Android進階 - 應用啟動分析

yangxi_001發表於2017-03-02

Andorid系統啟動後,就可以使用系統中的應用程式了,Android的應用程式的字尾是:apk,分為系統應用和使用者應用,系統應用可在編譯原始碼時,打包發行,使用者應用則可以通過應用市場等來下載安裝。Launcher本身也是一個系統應用,上一篇文章(Android入門-系統啟動簡介)提到,SystemServer是通過:ActivityStackSupervisor.startActivityLocked()來啟動主螢幕應用的。其實,所有的Android應用都可以通過這種方法啟動。
1、回顧Home啟動

Android入門-系統啟動簡介已經分析了,Home的啟動是通過ActivityManagerService.startHomeActivityLocked啟動的:

startHomeActivityLocked:
frameworks/base/services/java/com/android/server/am/ActivityManagerService.java:

//獲取主螢幕Intent
Intent getHomeIntent() {
    Intent intent = new Intent(mTopAction, mTopData != null ? Uri.parse(mTopData) : null);
    intent.setComponent(mTopComponent);
    if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
        intent.addCategory(Intent.CATEGORY_HOME);
    }
    return intent;
}
boolean startHomeActivityLocked(int userId) {
    ...
    // 獲取主螢幕的Intent
    Intent intent = getHomeIntent();
    // 獲取主螢幕的Activity資訊(如:包名,Activity名,應用資訊,程式名等)
    ActivityInfo aInfo =
        resolveActivityInfo(intent, STOCK_PM_FLAGS, userId);
    if (aInfo != null) {
        // 設定主螢幕Intent的元件資訊
        intent.setComponent(new ComponentName(
                aInfo.applicationInfo.packageName, aInfo.name));
        // Don't do this if the home app is currently being
        // instrumented.
        aInfo = new ActivityInfo(aInfo);
        aInfo.applicationInfo = getAppInfoForUser(aInfo.applicationInfo, userId);
        // 獲取主螢幕應用的程式資訊
        ProcessRecord app = getProcessRecordLocked(aInfo.processName,
                aInfo.applicationInfo.uid, true);
        if (app == null || app.instrumentationClass == null) {
        	// 假如主螢幕應用程式未啟動,則啟動
            intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
            mStackSupervisor.startHomeActivity(intent, aInfo);
        }
    }

    return true;
}
startActivityLocked:

frameworks/base/services/java/com/android/server/am/ActivityStackSupervisor.java:

void startHomeActivity(Intent intent, ActivityInfo aInfo) {
    moveHomeToTop();
    startActivityLocked(null, intent, null, aInfo, null, null, 0, 0, 0, null, 0,
            null, false, null);
}

可以看出,SystemServer程式通過呼叫ActivityStackSupervisor.startActivityLocked()來啟動主螢幕應用。

2、考查一個簡單的應用啟動例子

這裡,我們建立一個HelloAndroid的應用,再建立一個TestCallApp的應用,嘗試在TestCallApp裡,啟動HelloAndroid應用。

2.1、建立HelloAndroid應用

在Eclipse裡,NewProject->AndroidApplicationProject,取名:HelloAndroid,package名為:com.helloandroid。按嚮導一直Next,最後點選finish。

開啟AndroidManifest.xml:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.helloandroid" android:versioncode="1" android:versionname="1.0">

    <uses-sdk android:minsdkversion="19" android:targetsdkversion="19">

    <application android:allowbackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme">
        <activity android:name="com.helloandroid.MainActivity" android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN">
                <action android:name="com.helloandroid.HELLO">
                <category android:name="android.intent.category.DEFAULT">
                <category android:name="android.intent.category.LAUNCHER">
            </category></category></action></action></intent-filter>
        </activity>
    </application>
</uses-sdk></manifest>

intent-filter下面已經有一個名為“android.intent.action.MAIN”的action和一個名為“android.intent.category.LAUNCHER”的category,這是用於在Launcher裡點選使用者圖示來啟動應用的。我們在intent-filter下新增一個名為“com.helloandroid.HELLO”的action和一個名為“android.intent.category.DEFAULT”的category,這樣做是為了方便其他程式呼叫。本章暫不詳細討論Intent。

點選Run,安裝並執行HelloAndroid應用。

2.2、建立TestCallApp應用

建立應用的方法同上,名稱用:TestCallApp,包名為:com.testcallapp。開啟fragment_main.xml,轉至GraphicalLayout,拖一個Button放到介面上,ID為call_button。

轉至MainActivity.java:

...
/**
 * A placeholder fragment containing a simple view.
 */
public static class PlaceholderFragment extends Fragment {

    public PlaceholderFragment() {
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.fragment_main, container, false);
        // 加入下面程式碼
        Button b = (Button) rootView.findViewById(R.id.call_button);
        if (b != null)
            b.setOnClickListener(new OnClickListener() {

                @Override
                public void onClick(View v) {
                    Intent intent = new Intent();
                    intent.setAction("com.helloandroid.HELLO");
                    startActivity(intent);
                }
            });
        return rootView;
    }
}
...
上面是在Activity裡內嵌了一個Fragment碎片,如果沒用Fragment,可以在Activity.OnCreate裡寫上面的程式碼。

點選Run,執行並安裝此程式。點選”Call“按鈕,即可啟動HelloAndroid應用。

此案例說明了如何從一個應用裡啟動另一個應用,也是用Intent,通過Activity.startActivity()函式來呼叫。

2.3、啟動過程分析

我們接著來分析此函式的原碼:

  1. Activity.startActivity:

    frameworks/base/core/java/android/app/Activity.java:

    ...
    	public void startActivity(Intent intent) {
    	    startActivity(intent, null);
    	}
    	...
    	public void startActivity(Intent intent, 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);
            }
        }
    	...
    	public void startActivityForResult(Intent intent, int requestCode, Bundle options) {
            if (mParent == null) {
                Instrumentation.ActivityResult ar =
                    mInstrumentation.execStartActivity(
                        this, mMainThread.getApplicationThread(), mToken, this,
                        intent, requestCode, options);
                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;
                }
    
                final View decor = mWindow != null ? mWindow.peekDecorView() : null;
                if (decor != null) {
                    decor.cancelPendingInputEvents();
                }
                // TODO Consider clearing/flushing other event sources and events for child windows.
            } else {
            	// 從子Activity中啟動,從下面的程式碼可以看出,事實上也是呼叫execStartActivity,與mParent==null的流程差不多。
                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);
                }
            }
        }
        ...
        public void startActivityFromChild(Activity child, Intent intent, 
                int requestCode, Bundle options) {
            Instrumentation.ActivityResult ar =
                mInstrumentation.execStartActivity(
                    this, mMainThread.getApplicationThread(), mToken, child,
                    intent, requestCode, options);
            if (ar != null) {
                mMainThread.sendActivityResult(
                    mToken, child.mEmbeddedID, requestCode,
                    ar.getResultCode(), ar.getResultData());
            }
        }
    從上面的原始碼可以看出呼叫過程:startActivity(intent)->startActivity(intent,options)->startActivityForResult(intent,-1,options);最終都走到了Instrumentation.execStartActivity()函式裡。
  2. Instrumentation.execStartActivity:

    frameworks/base/core/java/android/app/Instrumentation.java

    ...
        public ActivityResult execStartActivity(
                Context who, IBinder contextThread, IBinder token, Activity target,
                Intent intent, int requestCode, Bundle options) {
            ...
            try {
                intent.migrateExtraStreamToClipData();
                intent.prepareToLeaveProcess();
                int result = ActivityManagerNative.getDefault()
                    .startActivity(whoThread, who.getBasePackageName(), intent,
                            intent.resolveTypeIfNeeded(who.getContentResolver()),
                            token, target != null ? target.mEmbeddedID : null,
                            requestCode, 0, null, null, options);
                checkStartActivityResult(result, intent);
            } catch (RemoteException e) {
            }
            return null;
        }
        ...
    流程走到這裡,突然看不到原始碼了,因為IActivityManager是一個介面,通過呼叫IActivityManager.startActivity函式,來啟動Activity。那麼,IActivityManager的實現類在哪?先來看看ActivityManagerNative.getDefault()幹了什麼:frameworks/base/core/java/android/app/ActivityManagerNative.java
  3. 獲取ActivityManagerService服務呼叫代理:

    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);
        }
    	...
        static public IActivityManager getDefault() {
            return gDefault.get();
        }
        ...
        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;
            }
        };
    ActivityManagerNative.gDefault是一個私有的單例模式執行的成員變數,儲存當前預設的IActivityManager,從create程式碼可以看出,gDefault是"activity"服務的一個通訊代理,即:ActivityManagerProxy,通過IBinder與ActivityManagerService通訊。這裡不分析IBinder及Android程式間通訊機制,這屬於另一篇文章的範疇了。這裡簡單講述如何流程如何到ActivityManagerService服務中的。
  4. ActivityManagerService服務呼叫:

    IBinder有一個非常關鍵的方法transact,對應的Binder就會有一個onTransact與之對應,即通過IBinder.transact發出指令後,會觸發遠端的onTransact函式執行。

    • 呼叫端:ActivityManagerProxy.startActivity

      frameworks/base/core/java/android/app/ActivityManagerNative.java

      class ActivityManagerProxy implements IActivityManager
      {
          ...
          public int startActivity(IApplicationThread caller, String callingPackage, Intent intent,
                  String resolvedType, IBinder resultTo, String resultWho, int requestCode,
                  int startFlags, String profileFile,
                  ParcelFileDescriptor profileFd, 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);
              data.writeString(profileFile);
              if (profileFd != null) {
                  data.writeInt(1);
                  profileFd.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);
              }
              // 通過IBinder.transact(),呼叫服務端
              mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);
              reply.readException();
              int result = reply.readInt();
              reply.recycle();
              data.recycle();
              return result;
          }
          ...
      }
      通過呼叫IBinder.transact(START_ACTIVITY_TRANSACTION,...)來呼叫遠端服務
    • 服務端:ActivityManagerService.onTransact,是由其父類ActivityManagerNative實現的:

      frameworks/base/core/java/android/app/ActivityManagerNative.java

      public abstract class ActivityManagerNative extends Binder implements IActivityManager{
      ...
          @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();
                  String profileFile = data.readString();
                  ParcelFileDescriptor profileFd = data.readInt() != 0
                          ? data.readFileDescriptor() : null;
                  Bundle options = data.readInt() != 0
                          ? Bundle.CREATOR.createFromParcel(data) : null;
                  // 啟動Activity
                  int result = startActivity(app, callingPackage, intent, resolvedType,
                          resultTo, resultWho, requestCode, startFlags,
                          profileFile, profileFd, options);
                  reply.writeNoException();
                  reply.writeInt(result);
                  return true;
              }
              ...
          }
          ...
      }
    現在我們知道了,流程最終是通過ActivityManagerService.startActivity來啟動Activity的。
  5. ActivityManagerService.startActivity:

    frameworks/base/services/java/com/android/server/am/ActivityManagerService.java

    ...
        @Override
        public final int startActivity(IApplicationThread caller, String callingPackage,
                Intent intent, String resolvedType, IBinder resultTo,
                String resultWho, int requestCode, int startFlags,
                String profileFile, ParcelFileDescriptor profileFd, Bundle options) {
            return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
                    resultWho, requestCode,
                    startFlags, profileFile, profileFd, options, UserHandle.getCallingUserId());
        }
    
        @Override
        public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
                Intent intent, String resolvedType, IBinder resultTo,
                String resultWho, int requestCode, int startFlags,
                String profileFile, ParcelFileDescriptor profileFd, Bundle options, int userId) {
            enforceNotIsolatedCaller("startActivity");
            userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId,
                    false, true, "startActivity", null);
            // TODO: Switch to user app stacks here.
            return mStackSupervisor.startActivityMayWait(caller, -1, callingPackage, intent, resolvedType,
                    resultTo, resultWho, requestCode, startFlags, profileFile, profileFd,
                    null, null, options, userId);
        }
        ...
  6. ActivityStackSupervisor.startActivityMayWait:

    frameworks/base/services/java/com/android/server/am/ActivityStackSupervisor.java

    ...
        final int startActivityMayWait(IApplicationThread caller, int callingUid,
                String callingPackage, Intent intent, String resolvedType, IBinder resultTo,
                String resultWho, int requestCode, int startFlags, String profileFile,
                ParcelFileDescriptor profileFd, WaitResult outResult, Configuration config,
                Bundle options, int userId) {
            ...
            synchronized (mService) {
                ...
                int res = startActivityLocked(caller, intent, resolvedType,
                        aInfo, resultTo, resultWho, requestCode, callingPid, callingUid,
                        callingPackage, startFlags, options, componentSpecified, null);
    
                ...
                if (outResult != null) {
                	// 回傳結果
                    ...
                }
    
                return res;
            }
        }

又到了ActivityStackSupervisor.startActivityLocked函式了。

3. Launcher裡啟動應用

由於Launcher本身也是一個應用,所以,原理上來講,Launcher裡啟動應用,應該和在其他應用裡啟動一個應用沒有什麼區別。我們來看看Launcher3的Launcher原始碼:
packages/apps/Launcher3/src/com/android/launcher3/Launcher.java

public class Launcher extends Activity
        implements View.OnClickListener, OnLongClickListener, LauncherModel.Callbacks,
                   View.OnTouchListener {
    ...
    public void onClick(View v) {
        ...
        Object tag = v.getTag();
        if (tag instanceof ShortcutInfo) {
        	//如果是快捷方式
            ...

            // Start activities
            int[] pos = new int[2];
            v.getLocationOnScreen(pos);
            intent.setSourceBounds(new Rect(pos[0], pos[1],
                    pos[0] + v.getWidth(), pos[1] + v.getHeight()));
			// 啟動Activity
            boolean success = startActivitySafely(v, intent, tag);

            mStats.recordLaunch(intent, shortcut);

            if (success && v instanceof BubbleTextView) {
                mWaitingForResume = (BubbleTextView) v;
                mWaitingForResume.setStayPressed(true);
            }
        } 
		...
    }
    ...
    
    boolean startActivitySafely(View v, Intent intent, Object tag) {
        boolean success = false;
        try {
        	// 啟動Activity
            success = startActivity(v, intent, tag);
        } catch (ActivityNotFoundException e) {
            Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
            Log.e(TAG, "Unable to launch. tag=" + tag + " intent=" + intent, e);
        }
        return success;
    }
    ...
}
Launcher判斷點選一個快捷方式後,會呼叫startActivitySafely啟動Activity,而startActivitySafely裡,則是呼叫Activity.startActivity來啟動,與我們之前的預測完全相同。

4. 應用程式啟動

前面幾節說了幾種型別的應用啟動方式,最終都是用ActivityStackSupervisor.startActivityLocked來啟動一個應用。現在,我們沿著這個流程,繼續往下分析,應用的程式是如何啟動的。由於startActivityLocked函式的作用不僅僅是新啟動一個應用,還可以啟動程式內部的Activity,所以,函式寫的較為複雜,邏輯較多,本文將略去與新應用啟動無關的邏輯,簡單分析新應用的啟動流程。

4.1 startActivity

  1. ActivityStackSupervisor.startActivityLocked:

    frameworks/base/services/java/com/android/server/am/ActivityStackSupervisor.java

    final int startActivityLocked(IApplicationThread caller,
            Intent intent, String resolvedType, ActivityInfo aInfo, IBinder resultTo,
            String resultWho, int requestCode,
            int callingPid, int callingUid, String callingPackage, int startFlags, Bundle options,
            boolean componentSpecified, ActivityRecord[] outActivity) {
        ...
        err = startActivityUncheckedLocked(r, sourceRecord, startFlags, true, options);
    
        if (allPausedActivitiesComplete()) {
            // If someone asked to have the keyguard dismissed on the next
            // activity start, but we are not actually doing an activity
            // switch...  just dismiss the keyguard now, because we
            // probably want to see whatever is behind it.
            dismissKeyguard();
        }
        return err;
    }
    final int startActivityUncheckedLocked(ActivityRecord r,
                ActivityRecord sourceRecord, int startFlags, boolean doResume,
                Bundle options) {
        ...
        boolean newTask = false;
        boolean keepCurTransition = false;
        ...
        if (newTask) {
            EventLog.writeEvent(EventLogTags.AM_CREATE_TASK, r.userId, r.task.taskId);
        }
        ActivityStack.logStartActivity(EventLogTags.AM_CREATE_ACTIVITY, r, r.task);
        targetStack.mLastPausedActivity = null;
        targetStack.startActivityLocked(r, newTask, doResume, keepCurTransition, options);
        mService.setFocusedActivityLocked(r);
        return ActivityManager.START_SUCCESS;
    }
    到了ActivityStack.startActivityLocked,函式名稱相同,類不同。Android的程式碼寫的真的不怎麼樣。
  2. ActivityStack.startActivityLocked:

    frameworks/base/services/java/com/android/server/am/ActivityStack.java

    final void startActivityLocked(ActivityRecord r, boolean newTask,
            boolean doResume, boolean keepCurTransition, Bundle options) {
        TaskRecord rTask = r.task;
        final int taskId = rTask.taskId;
        if (taskForIdLocked(taskId) == null || newTask) {
        	// 如果是新任務,則將任務插入到任務列表頂端
            // Last activity in task had been removed or ActivityManagerService is reusing task.
            // Insert or replace.
            // Might not even be in.
            insertTaskAtTop(rTask);
            mWindowManager.moveTaskToTop(taskId);
        }
        TaskRecord task = null;
        if (!newTask) {
            ...
        }
        ...
    
        task = r.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());
        // 將Activity插到任務的Activities頂端,一個任務可以有多個Activities
        task.addActivityToTop(r);
    	// 標記Activity已經在歷史記錄中
        r.putInHistory();
        r.frontOfTask = newTask;
        if (!isHomeStack() || numActivities() > 0) {
            // 非home下的視窗處理,略
            ...
        } else {
            // home下的視窗處理,涉及鎖屏等,略
            ...
        }
        if (VALIDATE_TOKENS) {
            validateAppTokensLocked();
        }
    
        if (doResume) {
        	// 恢復或啟動頂層的Activity,本函式之前已經將Activity置入頂層
            mStackSupervisor.resumeTopActivitiesLocked();
        }
    }
  3. ActivityStackSupervisor.resumeTopActivitiesLocked:

    這段程式碼在上一篇(Android入門 - 系統啟動簡介)的Launcher啟動已經有描述,本文再次描述,因為後續流程不一樣。
    frameworks/base/services/java/com/android/server/am/ActivityStackSupervisor.java

    boolean resumeTopActivitiesLocked() {
        return resumeTopActivitiesLocked(null, null, null);
    }
    
    boolean resumeTopActivitiesLocked(ActivityStack targetStack, ActivityRecord target,
            Bundle targetOptions) {
        if (targetStack == null) {
            targetStack = getFocusedStack();
        }
        boolean result = false;
        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
            final ActivityStack stack = mStacks.get(stackNdx);
            if (isFrontStack(stack)) {
                if (stack == targetStack) {
                    result = stack.resumeTopActivityLocked(target, targetOptions);
                } else {
                    stack.resumeTopActivityLocked(null);
                }
            }
        }
        return result;
    }
  4. ActivityStack.resumeTopActivityLocked:

    frameworks/base/services/java/com/android/server/am/ActivityStack.java

    final boolean resumeTopActivityLocked(ActivityRecord prev) {
        return resumeTopActivityLocked(prev, null);
    }
    final boolean resumeTopActivityLocked(ActivityRecord prev, Bundle options) {
        if (ActivityManagerService.DEBUG_LOCKSCREEN) mService.logLockScreen("");
    	// 找到頂層的ActivityRecord
        // 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 = mStackSupervisor.mUserLeaving;
        mStackSupervisor.mUserLeaving = false;
    
        if (next == null) {
        	// 此處啟動Launcher,在上一篇文章有描述,不過,經過一翻流轉,最終還是會回到本函式,但此時next不是null了。Android原始碼,哎。。。
            ...
        }
    	...
        if (next.app != null && next.app.thread != null) {
        	// 應用已經啟動情況,有可能會重啟動應用,此處不分析
            ...
    
        } else {
            ...
            mStackSupervisor.startSpecificActivityLocked(next, true, true);
        }
        if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
        return true;
    }
    上面的函式邏輯非常複雜,有許多的return語句,這些return之後,經過一翻流轉有可能又進入此函式,進入另一個判斷分支。本文不詳細分析Activity的各種複雜管理,只討論如何啟動,所以,略去了這許多程式碼,我是服了Android的程式碼設計者,一些這麼複雜的函式,怎麼也應該分多個函式來實現。
  5. ActivityStackSupervisor.startSpecificActivityLocked:

    frameworks/base/services/java/com/android/server/am/ActivityStackSupervisor.java

    void startSpecificActivityLocked(ActivityRecord r,
            boolean andResume, boolean checkConfig) {
        // Is this activity's application already running?
        ProcessRecord app = mService.getProcessRecordLocked(r.processName,
                r.info.applicationInfo.uid, true);
    
        r.task.stack.setLaunchTime(r);
    
        if (app != null && app.thread != null) {
            // 如果程式已經執行。。。
            ...
        }
    
        mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
                "activity", r.intent.getComponent(), false, false, true);
    }
    終於到了啟動程式的一步了。

4.2 啟動程式

  1. ActivityManagerService.startProcessLocked:

    frameworks/base/services/java/com/android/server/am/ActivityManagerService.java

    final ProcessRecord startProcessLocked(String processName,
            ApplicationInfo info, boolean knownToBeDead, int intentFlags,
            String hostingType, ComponentName hostingName, boolean allowWhileBooting,
            boolean isolated, boolean keepIfLarge) {
        ProcessRecord app;
        if (!isolated) {
            app = getProcessRecordLocked(processName, info.uid, keepIfLarge);
        } else {
            // If this is an isolated process, it can't re-use an existing process.
            app = null;
        }
        ...
        if (app != null && app.pid > 0) {
            // 已經執行
            ...
        }
        ...
    
        if (app == null) {
        	// 建立程式資訊
            app = newProcessRecordLocked(info, processName, isolated);
            if (app == null) {
                Slog.w(TAG, "Failed making new process record for "
                        + processName + "/" + info.uid + " isolated=" + isolated);
                return null;
            }
            mProcessNames.put(processName, app.uid, app);
            if (isolated) {
                mIsolatedProcesses.put(app.uid, app);
            }
        } else {
            // If this is a new package in the process, add the package to the list
            app.addPackage(info.packageName, mProcessStats);
        }
    
        // If the system is not ready yet, then hold off on starting this
        // process until it is.
        if (!mProcessesReady
                && !isAllowedWhileBooting(info)
                && !allowWhileBooting) {
            // 如果系統未準備好,則加入Hold佇列...
            if (!mProcessesOnHold.contains(app)) {
                mProcessesOnHold.add(app);
            }
            if (DEBUG_PROCESSES) Slog.v(TAG, "System not ready, putting on hold: " + app);
            return app;
        }
    	// 啟動程式,見下面的函式
        startProcessLocked(app, hostingType, hostingNameStr);
        return (app.pid != 0) ? app : null;
    }
    ...
    private final void startProcessLocked(ProcessRecord app,
            String hostingType, String hostingNameStr) {
        ...
        // 從Hold佇列中移除
        mProcessesOnHold.remove(app);
    
        updateCpuStats();
    
        try {
            int uid = app.uid;
    
            int[] gids = null;
            int mountExternal = Zygote.MOUNT_EXTERNAL_NONE;
            ...
            // 啟動程式
            Process.ProcessStartResult startResult = Process.start("android.app.ActivityThread",
                    app.processName, uid, uid, gids, debugFlags, mountExternal,
                    app.info.targetSdkVersion, app.info.seinfo, null);
    		...
    		// 設定app的pid
    		app.setPid(startResult.pid);
    		app.usingWrapper = startResult.usingWrapper;
            app.removed = false;
            synchronized (mPidsSelfLocked) {
            	// 非常關鍵,儲存應用的資訊,將來ActivityThread.attach啟動Application時,要依據pid找到app的資訊
                this.mPidsSelfLocked.put(startResult.pid, app);
                Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
                msg.obj = app;
                mHandler.sendMessageDelayed(msg, startResult.usingWrapper
                        ? PROC_START_TIMEOUT_WITH_WRAPPER : PROC_START_TIMEOUT);
            }
            ...
        } catch (RuntimeException e) {
            // XXX do better error recovery.
            app.setPid(0);
            Slog.e(TAG, "Failure starting process " + app.processName, e);
        }
    }
    準備啟動程式了。
  2. Process.start:

    frameworks/base/core/java/android/os/Process.java

    public static final ProcessStartResult start(final String processClass,
                                  final String niceName,
                                  int uid, int gid, int[] gids,
                                  int debugFlags, int mountExternal,
                                  int targetSdkVersion,
                                  String seInfo,
                                  String[] zygoteArgs) {
        try {
            return startViaZygote(processClass, niceName, uid, gid, gids,
                    debugFlags, mountExternal, targetSdkVersion, seInfo, zygoteArgs);
        } catch (ZygoteStartFailedEx ex) {
            Log.e(LOG_TAG,
                    "Starting VM process through Zygote failed");
            throw new RuntimeException(
                    "Starting VM process through Zygote failed", ex);
        }
    }
    private static ProcessStartResult startViaZygote(final String processClass,
                                  final String niceName,
                                  final int uid, final int gid,
                                  final int[] gids,
                                  int debugFlags, int mountExternal,
                                  int targetSdkVersion,
                                  String seInfo,
                                  String[] extraArgs)
                                  throws ZygoteStartFailedEx {
        synchronized(Process.class) {
            // 組織一些程式啟動引數,略去
    		...
            return zygoteSendArgsAndGetResult(argsForZygote);
        }
    }
    private static ProcessStartResult zygoteSendArgsAndGetResult(ArrayList<String> args)
            throws ZygoteStartFailedEx {
        // 連線Zygote伺服器,在上一篇中,已經說明,Zygote啟動後,會建立Socket伺服器,等待客戶端連線,處理Fork新程式
        openZygoteSocketIfNeeded();
    
        try {
        	// 向Zygote傳送Fork程式的請求
            ...
            sZygoteWriter.write(Integer.toString(args.size()));
            sZygoteWriter.newLine();
    
            int sz = args.size();
            for (int i = 0; i < sz; i++) {
                String arg = args.get(i);
                if (arg.indexOf('\n') >= 0) {
                    throw new ZygoteStartFailedEx(
                            "embedded newlines not allowed");
                }
                sZygoteWriter.write(arg);
                sZygoteWriter.newLine();
            }
    
            sZygoteWriter.flush();
    	    // 接收來自Zygote的回覆
            // Should there be a timeout on this?
            ProcessStartResult result = new ProcessStartResult();
            // Fork的程式ID,很重要
            result.pid = sZygoteInputStream.readInt();
            if (result.pid < 0) {
                throw new ZygoteStartFailedEx("fork() failed");
            }
            result.usingWrapper = sZygoteInputStream.readBoolean();
            return result;
        } catch (IOException ex) {
            try {
                if (sZygoteSocket != null) {
                    sZygoteSocket.close();
                }
            } catch (IOException ex2) {
                // we're going to fail anyway
                Log.e(LOG_TAG,"I/O exception on routine close", ex2);
            }
    
            sZygoteSocket = null;
    
            throw new ZygoteStartFailedEx(ex);
        }
    }
    上面的過程就簡單了,開啟與Zygote伺服器的套接字連線,並往套接字裡傳送請求,再接收回復,真正的程式建立過程在Zygote中。

4.3 在Zygote裡啟動程式

Zygote是所有Java的孵化器,Zygote啟動時會自動啟動SystemServer程式,並註冊Socket伺服器,監聽客戶端的請求,來Fork新的程式。

  1. Zygote啟動,我們再來回顧一下ZygoteInit.main()函式:

    frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

    public static void main(String argv[]) {
        try {
            // Start profiling the zygote initialization.
            SamplingProfilerIntegration.start();
    		// 註冊套接字伺服器
            registerZygoteSocket();
            ...
    		// 啟動SystemServer
            if (argv[1].equals("start-system-server")) {
                startSystemServer();
            } else if (!argv[1].equals("")) {
                throw new RuntimeException(argv[0] + USAGE_STRING);
            }
    
            Log.i(TAG, "Accepting command socket connections");
    		// 迴圈監聽Socket請求
            runSelectLoop();
    
            closeServerSocket();
        } catch (MethodAndArgsCaller caller) {
            caller.run();
        } catch (RuntimeException ex) {
            Log.e(TAG, "Zygote died with exception", ex);
            closeServerSocket();
            throw ex;
        }
    }
  2. 監聽請求:ZygoteInit.runSelectLoop()

    private static void runSelectLoop() throws MethodAndArgsCaller {
        ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
        ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
        FileDescriptor[] fdArray = new FileDescriptor[4];
    	// server socket的index為0,由於不是client,所以,放peers裡往一個null,保持index索引的同步。
    	// 其實,這個沒有必要,後面的peers.get(index-1)就行。再次看不慣Android原始碼。
        fds.add(sServerSocket.getFileDescriptor());
        peers.add(null);
    
        int loopCount = GC_LOOP_COUNT;
        while (true) {
            int index;
    		...
            try {
                fdArray = fds.toArray(fdArray);
                index = selectReadable(fdArray); // 阻塞等待所有的套接字
            } catch (IOException ex) {
                throw new RuntimeException("Error in select()", ex);
            }
    
            if (index < 0) {
                throw new RuntimeException("Error in select()");
            } else if (index == 0) {
            	// 如果索引為0,表示有新的client請求連線,建立一個新的ZygoteConnection,並加入peers和fds列表中
                ZygoteConnection newPeer = acceptCommandPeer();
                peers.add(newPeer);
                fds.add(newPeer.getFileDesciptor());
            } else {
            	// 如果是客戶端Socket有資料,則執行一次操作
                boolean done;
                done = peers.get(index).runOnce();
    
                if (done) {
                    peers.remove(index);
                    fds.remove(index);
                }
            }
        }
    }
    上面原始碼中的註釋,已對說明了Zygote伺服器的簡單處理過程。每一個新的連線請求後,會執行runOnce,來處理請求。
  3. 處理請求:

    frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java

    boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {
        String args[];
        Arguments parsedArgs = null;
        FileDescriptor[] descriptors;
    
        try {
        	// 讀取引數列表
            args = readArgumentList();
            descriptors = mSocket.getAncillaryFileDescriptors();
        } catch (IOException ex) {
            Log.w(TAG, "IOException on command socket " + ex.getMessage());
            closeSocket();
            return true;
        }
    	...
        try {
            ...
            // fork程式
            pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
                    parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
                    parsedArgs.niceName);
        } catch (IOException ex) {
            logAndPrintError(newStderr, "Exception creating pipe", ex);
        } catch (ErrnoException ex) {
            logAndPrintError(newStderr, "Exception creating pipe", ex);
        } catch (IllegalArgumentException ex) {
            logAndPrintError(newStderr, "Invalid zygote arguments", ex);
        } catch (ZygoteSecurityException ex) {
            logAndPrintError(newStderr,
                    "Zygote security policy prevents request: ", ex);
        }
        try {
            if (pid == 0) {
                // in child
                IoUtils.closeQuietly(serverPipeFd);
                serverPipeFd = null;
                handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);
    
                // should never get here, the child is expected to either
                // throw ZygoteInit.MethodAndArgsCaller or exec().
                return true;
            } else {
                // in parent...pid of < 0 means failure
                IoUtils.closeQuietly(childPipeFd);
                childPipeFd = null;
                return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs);
            }
        } finally {
            IoUtils.closeQuietly(childPipeFd);
            IoUtils.closeQuietly(serverPipeFd);
        }
    }
    先readArgumentList()讀取Socket中的資料引數,再通過Zygote.forkAndSpecialize建立一個新程式,最後是處理程式:handleChildProc。
  4. Fork程式:

    libcore/dalvik/src/main/java/dalvik/system/Zygote.java

    public static int forkAndSpecialize(int uid, int gid, int[] gids, int debugFlags,
            int[][] rlimits, int mountExternal, String seInfo, String niceName) {
        preFork();
        int pid = nativeForkAndSpecialize(
                uid, gid, gids, debugFlags, rlimits, mountExternal, seInfo, niceName);
        postFork();
        return pid;
    }
    nativeForkAndSpecialize()是一個JNI呼叫,函式在art/runtime/native/dalvik_system_Zygote.cc中。

    static jint Zygote_nativeForkAndSpecialize(JNIEnv* env, jclass, jint uid, jint gid, jintArray gids,
                                               jint debug_flags, jobjectArray rlimits, jint mount_external,
                                               jstring se_info, jstring se_name) {
        return ForkAndSpecializeCommon(env, uid, gid, gids, debug_flags, rlimits, 0, 0, mount_external, se_info, se_name, false);
    }
    和SystemServer程式啟動一樣,都到了ForkAndSpecializeCommon函式這裡,本文不準備繼續往下分析,有興趣的朋友可以繼續研究。這就完成了新程式的啟動。
  5. 子程式處理(handleChildProc):

    frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java

    private void handleChildProc(Arguments parsedArgs,
                FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr)
                throws ZygoteInit.MethodAndArgsCaller {
    	...
        if (parsedArgs.runtimeInit) {
            ...
        } else {
            String className;
            try {
            	// className類名,來自client的請求資料,即:android.app.ActivityThread,可看前面的程式碼分析
                className = parsedArgs.remainingArgs[0];
            } catch (ArrayIndexOutOfBoundsException ex) {
                logAndPrintError(newStderr,
                        "Missing required class name argument", null);
                return;
            }
    
            String[] mainArgs = new String[parsedArgs.remainingArgs.length - 1];
            System.arraycopy(parsedArgs.remainingArgs, 1,
                    mainArgs, 0, mainArgs.length);
    
            if (parsedArgs.invokeWith != null) {
                WrapperInit.execStandalone(parsedArgs.invokeWith,
                        parsedArgs.classpath, className, mainArgs);
            } else {
            	// 裝入class
                ClassLoader cloader;
                if (parsedArgs.classpath != null) {
                    cloader = new PathClassLoader(parsedArgs.classpath,
                            ClassLoader.getSystemClassLoader());
                } else {
                    cloader = ClassLoader.getSystemClassLoader();
                }
    
                try {
                	// 執行class的main函式
                    ZygoteInit.invokeStaticMain(cloader, className, mainArgs);
                } catch (RuntimeException ex) {
                    logAndPrintError(newStderr, "Error starting.", ex);
                }
            }
        }
    }
    子程式裝入android.app.ActivityThread類,並執行android.app.ActivityThread.main函式,應用啟動完成。

到此為止,Android的應用程式啟動完成,最終是Fork了一個新程式,並在新程式裡載入了android.app.ActivityThread類,這樣,我們也知道了,所有Android應用程式啟動,都會用到android.app.ActivityThread類的。

5. 應用執行

應用程式啟動後,就進入了訊息迴圈,到程式退出。訊息迴圈是在android.app.ActivityThread實現的。但到現在為止,還與我們的Activity沒什麼關係。接下來,我們看看,我們的Activity是怎麼載入的。
前面已經分析了startProcessLocked()函式會請求Zygote伺服器Fork一個程式,Zygote建立新程式後,會將程式id(pid)返回,startProcessLocked()會將pid儲存ProcessRecord中,而ProcessRecord包含了我們要啟動的應用的詳細資訊(如:Activity類名,包名等)。由於新程式與新ActivityThread之間,沒有任何引數傳遞,唯一知道的是,ActivityThread在新程式裡執行,能獲取該程式的pid。所以,我們可以通過pid來得到ProcessRecord,進而得到要啟動的應用的所有資訊。

frameworks/base/core/java/android/app/ActivityThread.java

public static void main(String[] args) {
    ...
    ActivityThread thread = new ActivityThread();
    thread.attach(false);

    if (sMainThreadHandler == null) {
        sMainThreadHandler = thread.getHandler();
    }

    AsyncTask.init();

    if (false) {
        Looper.myLooper().setMessageLogging(new
                LogPrinter(Log.DEBUG, "ActivityThread"));
    }
	// 處理訊息
    Looper.loop();

    throw new RuntimeException("Main thread loop unexpectedly exited");
}
上面這段程式碼很簡單,沒有什麼地方用到了我們的Activity引數,Looper.loop()是迴圈處理訊息的,此時,我們的Activity應該已經啟動了,怎麼啟動的,我們還是不知道。看來,thread.attach(false),這句就非常關鍵了。我們來分析一下:

  1. ActivityThread.attach:

    frameworks/base/core/java/android/app/ActivityThread.java

    private void attach(boolean system) {
        sCurrentActivityThread = this;
        mSystemThread = system;
        if (!system) {
            ...
            RuntimeInit.setApplicationObject(mAppThread.asBinder());
            // 前面已經分析過: ActivityManagerNative.getDefault()。mrg實際上就是ActivityManagerProxy的例項,是一個ActivityManagerService的Binder通訊代理
            IActivityManager mgr = ActivityManagerNative.getDefault();
            try {
            	// 傳入mAppThread,後面要用到
                mgr.attachApplication(mAppThread);
            } catch (RemoteException ex) {
                // Ignore
            }
        } else {
            ...
        }
        ...
    }
    這裡不再分析ActivityManagerProxy是如何到ActivityManagerService的了,請看前面的分析。mgr.attachApplication最終會進入ActivityManagerService.attachApplication函式。
  2. ActivityManagerService.attachApplication:

    frameworks/base/services/java/com/android/server/am/ActivityManagerService.java

    @Override
    public final void attachApplication(IApplicationThread thread) {
        synchronized (this) {
        	// call程式的pid
            int callingPid = Binder.getCallingPid();
            final long origId = Binder.clearCallingIdentity();
            // 線上程中附上Application
            attachApplicationLocked(thread, callingPid);
            Binder.restoreCallingIdentity(origId);
        }
    }
    ...
    private final boolean attachApplicationLocked(IApplicationThread thread,
            int pid) {
    	...
        ProcessRecord app;
        if (pid != MY_PID && pid >= 0) {
            synchronized (mPidsSelfLocked) {
            	// 找到pid對應的app,儲存的程式碼在startActivityLocked中。
            	// 疑問?由於startActivityLocked是在一個程式中呼叫,而attachApplicationLocked是經由Zygote建立的新程式中觸發呼叫。怎麼保證attachApplicationLocked呼叫之前,startActivityLocked程式碼已經執行至儲存程式資訊這一步呢?
                // synchronized程式碼似乎不能保證在get之前,一定會先put,只能保證mPidsSelfLocked不會被同時訪問。萬一套接字返回較慢,而ActivityThread的快速執行至本程式碼處,豈不是找不到app了?
                app = mPidsSelfLocked.get(pid);
            }
        } else {
            app = null;
        }
        if (app == null) {
        	// 此段程式碼算是對我上述疑問的一個錯誤處理,但應該在之前儘量避免此種情況發生。
            Slog.w(TAG, "No pending application record for pid " + pid
                    + " (IApplicationThread " + thread + "); dropping process");
            EventLog.writeEvent(EventLogTags.AM_DROP_PROCESS, pid);
            if (pid > 0 && pid != MY_PID) {
                Process.killProcessQuiet(pid);
            } else {
                try {
                    thread.scheduleExit();
                } catch (Exception e) {
                    // Ignore exceptions.
                }
            }
            return false;
        }
    	...
    	// 會設定app.thread=thread,後面會呼叫thread.scheduleLaunchActivity來啟動Activity
        app.makeActive(thread, mProcessStats);
        ...
        // See if the top visible activity is waiting to run in this process...
        if (normalMode) {
            try {
                if (mStackSupervisor.attachApplicationLocked(app, mHeadless)) {
                    didSomething = true;
                }
            } catch (Exception e) {
                badApp = true;
            }
        }
        ...
        return true;
    }
  3. ActivityManagerService.attachApplication:

    frameworks/base/services/java/com/android/server/am/ActivityStackSupervisor.java

    boolean attachApplicationLocked(ProcessRecord app, boolean headless) throws Exception {
        boolean didSomething = false;
        final String processName = app.processName;
        // 找到app對應的ActivityRecord,並呼叫realStartActivityLocked啟動Activity。
        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
            final ActivityStack stack = mStacks.get(stackNdx);
            if (!isFrontStack(stack)) {
                continue;
            }
            ActivityRecord hr = stack.topRunningActivityLocked(null);
            if (hr != null) {
                if (hr.app == null && app.uid == hr.info.applicationInfo.uid
                        && processName.equals(hr.processName)) {
                    try {
                        if (headless) {
                            Slog.e(TAG, "Starting activities not supported on headless device: "
                                    + hr);
                        } else if (realStartActivityLocked(hr, app, true, true)) {
                            didSomething = true;
                        }
                    } catch (Exception e) {
                        Slog.w(TAG, "Exception in new application when starting activity "
                              + hr.intent.getComponent().flattenToShortString(), e);
                        throw e;
                    }
                }
            }
        }
        if (!didSomething) {
            ensureActivitiesVisibleLocked(null, 0);
        }
        return didSomething;
    }
    ...
    final boolean realStartActivityLocked(ActivityRecord r,
            ProcessRecord app, boolean andResume, boolean checkConfig)
            throws RemoteException {
    	...
    
        r.app = app;
        app.waitingToKill = null;
        r.launchCount++;
        r.lastLaunchTime = SystemClock.uptimeMillis();
    	...
        final ActivityStack stack = r.task.stack;
        try {
            if (app.thread == null) {
                throw new RemoteException();
            }
            ...
            // 啟動Activity
            app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
                    System.identityHashCode(r), r.info,
                    new Configuration(mService.mConfiguration), r.compat,
                    app.repProcState, r.icicle, results, newIntents, !andResume,
                    mService.isNextTransitionForward(), profileFile, profileFd,
                    profileAutoStop);
    		...
    
        } catch (RemoteException e) {
            ...
            throw e;
        }
    	...
    
        return true;
    }
    app.thread是一個ApplicationThread例項,ApplicationThread是定義在ActivityThread裡的一個私有類,繼承自ApplicationThreadNative。而ApplicationThreadNative繼承自Binder,並實現了IApplicationThread介面,可以作為Binder服務端。儘管是從Binder繼承,但ApplicationThread.scheduleLaunchActivity並未走Binder通訊通道,是直接的服務端函式呼叫。網上有資料說是走的ApplicationThreadProxy,再走IBinder.transact,最終才進入ApplicationThread.scheduleLaunchActivity,這種說法不正確,或者Android4.4有修改,因為Android4.4中ActivityThread.mAppThread並不是繼承自ApplicationThreadProxy的類例項,而是繼承自ApplicationThreadNative。
  4. ApplicationThread.scheduleLaunchActivity:

    frameworks/base/core/java/android/app/ActivityThread.java

    public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
            ActivityInfo info, Configuration curConfig, CompatibilityInfo compatInfo,
            int procState, Bundle state, List<ResultInfo> pendingResults,
            List<Intent> pendingNewIntents, boolean notResumed, boolean isForward,
            String profileName, ParcelFileDescriptor profileFd, boolean autoStopProfiler) {
    
        updateProcessState(procState, false);
    
        ActivityClientRecord r = new ActivityClientRecord();
    
        r.token = token;
        r.ident = ident;
        r.intent = intent;
        r.activityInfo = info;
        r.compatInfo = compatInfo;
        r.state = state;
    
        r.pendingResults = pendingResults;
        r.pendingIntents = pendingNewIntents;
    
        r.startsNotResumed = notResumed;
        r.isForward = isForward;
    
        r.profileFile = profileName;
        r.profileFd = profileFd;
        r.autoStopProfiler = autoStopProfiler;
    
        updatePendingConfiguration(curConfig);
    
        sendMessage(H.LAUNCH_ACTIVITY, r);
    }
    本函式流程比較簡單,建立一個ActivityClientRecord,然後,傳送LAUNCH_ACTIVITY訊息,啟動一個Activity。sendMessage是個啥玩意?在Win32程式裡,這很常見,Java程式裡,基本看不到。
  5. ActivityThread.sendMessage:

    frameworks/base/core/java/android/app/ActivityThread.java

    private void sendMessage(int what, Object obj) {
        sendMessage(what, obj, 0, 0, false);
    }
    ...
    private void sendMessage(int what, Object obj, int arg1, int arg2, boolean async) {
        if (DEBUG_MESSAGES) Slog.v(
            TAG, "SCHEDULE " + what + " " + mH.codeToString(what)
            + ": " + arg1 + " / " + obj);
        Message msg = Message.obtain();
        msg.what = what;
        msg.obj = obj;
        msg.arg1 = arg1;
        msg.arg2 = arg2;
        if (async) {
            msg.setAsynchronous(true);
        }
        // 一個成員變數,類為H,H類派生自Hander。
        mH.sendMessage(msg);
    }
  6. Handler.sendMessage:

    frameworks/base/core/java/android/os/Handler.java

    public final boolean sendMessage(Message msg)
    {
        return sendMessageDelayed(msg, 0);
    }
    ...
    public final boolean sendMessageDelayed(Message msg, long delayMillis)
    {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }
    ...
    public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
        MessageQueue queue = mQueue;
        if (queue == null) {
            RuntimeException e = new RuntimeException(
                    this + " sendMessageAtTime() called with no mQueue");
            Log.w("Looper", e.getMessage(), e);
            return false;
        }
        return enqueueMessage(queue, msg, uptimeMillis);
    }
    ...
    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
    	// 很重要,儲存msg的target為this,即H類的例項
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }
    上面的程式碼,其實是將msg放入到mQueue佇列中。既然是訊息佇列機制,則是非同步處理,流程走到這算是完成了。但我們還是不知道從什麼地方啟動Activity的,所以,我們必須找到讀取訊息佇列並處理訊息的程式碼。

6. Activity執行

上面我們已經知道,Activity的啟動msg已經放到mQueue佇列中,我們現在需要知道,什麼時候從佇列中取出訊息,並加入處理,啟動Activity。
先回顧一下ActivityThread.main()函式。

frameworks/base/core/java/android/app/ActivityThread.java

public static void main(String[] args) {
    ...
	// 初始化Lopper,Looper存有前面說的重要變數:mQueue訊息佇列。這是靜態的,可供全域性使用。
    Looper.prepareMainLooper();
    
    ActivityThread thread = new ActivityThread();
    thread.attach(false);

    if (sMainThreadHandler == null) {
        sMainThreadHandler = thread.getHandler();
    }
	// 強制建立AsyncTask.sHandler例項
    AsyncTask.init();

    if (false) {
        Looper.myLooper().setMessageLogging(new
                LogPrinter(Log.DEBUG, "ActivityThread"));
    }
	// 處理訊息
    Looper.loop();

    throw new RuntimeException("Main thread loop unexpectedly exited");
}
由上面可以看到Looper類至關重要,我們來看看prepareMainLooper()做了什麼?

frameworks/base/core/java/android/os/Looper.java

public final class Looper {
	...
    private static void prepare(boolean quitAllowed) {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper(quitAllowed));
    }
	...
    public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }
    ...
    public static Looper myLooper() {
        return sThreadLocal.get();
    }
}
先初始化sThreadLocal,並設定sThreadLocal為一個新建立的Looper。這樣的話,sThreadLocal.get()就能得到這個Looper。Looper函式全域性都用的是sThreadLocal.get()得到的Looper。

上節講到,訊息是通過Handler.sendMessage函式傳送,其實就是放到Handler.mQueue成員儲存的佇列,Handler.mQueue來自哪裡呢?

public final class ActivityThread {
	...
	final H mH = new H();
	...
	private class H extends Handler {
	...
	}
}

上面的H類無建構函式,new的時候執行的是Handler的預設建構函式。
frameworks/base/core/java/android/os/Handler.java

public class Handler {
...
	public Handler() {
	        this(null, false);
	}
	public Handler(Callback callback, boolean async) {
	    if (FIND_POTENTIAL_LEAKS) {
	        final Class<? extends Handler> klass = getClass();
	        if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
	                (klass.getModifiers() & Modifier.STATIC) == 0) {
	            Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
	                klass.getCanonicalName());
	        }
	    }
		// mLooper為Looper.myLooper(),此函式前面已經有分析
	    mLooper = Looper.myLooper();
	    if (mLooper == null) {
	        throw new RuntimeException(
	            "Can't create handler inside thread that has not called Looper.prepare()");
	    }
	    // 這裡指定mQueue,來自mLooper.mQueue。
	    mQueue = mLooper.mQueue;
	    mCallback = callback;
	    mAsynchronous = async;
	}
...
}
經過上面的分析,我們知道,通過Handler.sendMessage傳送的訊息,其實是放在:Looper.myLooper().mQueue佇列中,訊息佇列的變數來源已經確定。

下面來看,看到ActivityThread.main函式中,Looper.loop()是如何處理訊息的。
frameworks/base/core/java/android/os/Looper.java

public final class Looper {
	...
    public static void loop() {
    	// 也是通過myLooper()獲取Looper
        final Looper me = myLooper();
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        // 獲取訊息佇列,顯然,與Handler.sendMessage用的是同一佇列。
        final MessageQueue queue = me.mQueue;
		...
        for (;;) {
            Message msg = queue.next(); // might block
            
            ...
			// 訊息排程
            msg.target.dispatchMessage(msg);
			
			...
        }
    }
    ...
}
msg.target是在傳送訊息時,由上節的程式碼ActivityThread.enqueueMessage中指定的,是ActivityThead的私有類H的例項。

frameworks/base/core/java/android/os/Handler.java

public class Handler{
	...
	public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }
    ...
}
上面的msg.callback和mCallback都為null,所以,會進入handleMessage,即進入H.handleMessage中。

frameworks/base/core/java/android/os/Handler.java

public final class ActivityThread {...

final H mH = new H();

...

private class H extends 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");

ActivityClientRecord r = (ActivityClientRecord)msg.obj;

r.packageInfo = getPackageInfoNoCheck(

r.activityInfo.applicationInfo, r.compatInfo);

handleLaunchActivity(r, null);

Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

} break;

...

}

...

}

}

...

private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {

...

Activity a = performLaunchActivity(r, customIntent);

if (a != null) {

r.createdConfig = new Configuration(mConfiguration);

Bundle oldState = r.state;

handleResumeActivity(r.token, false, r.isForward,

!r.activity.mFinished && !r.startsNotResumed);

...

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

} catch (RemoteException ex) {

// Ignore

}

}

}

...

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {

// System.out.println("##### [" + System.currentTimeMillis() + "] ActivityThread.performLaunchActivity(" + r + ")");

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;

try {

java.lang.ClassLoader cl = r.packageInfo.getClassLoader();

activity = mInstrumentation.newActivity(

cl, component.getClassName(), r.intent);

StrictMode.incrementExpectedActivityCount(activity.getClass());

r.intent.setExtrasClassLoader(cl);

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="

相關文章