1. 程式人生 > >根Acitivity的啟動過程(1) Launcher 向ActivityManagerService傳送一個啟動MainActivity的程序間通訊請求

根Acitivity的啟動過程(1) Launcher 向ActivityManagerService傳送一個啟動MainActivity的程序間通訊請求

Activity有兩種

  • 由Launcher啟動的根actvity
  • 由activity啟動的子activity

根activity在配置檔案中宣告

<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />

根Activity的啟動過程

  • 首先PackageManagerService負責應用程式的安裝
    1 對manifest配置檔案解析,儲存各個元件資訊
    2 Launcher(也是一個Activity)在啟動過程中向PackageManageService查詢所有action=”action.Main” category = intent.CATEGORY_LAUNCHER 的activity
    3 為符合條件的每個activity建立快捷圖示,並將資訊和圖示繫結起來

  • 在點選圖示的時候執行Launcher的startActivitySafely方法

    boolean startActivitySafely(View v, Intent intent, Object tag) {
        boolean success = false;
        try {
            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; }
  • 接著執行startActivity(View v, Intent intent, Object tag)
    boolean startActivity(View v, Intent intent, Object tag) {
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);//
啟動標誌位設定為1,在新的任務中啟動 try { // Only launch using the new animation if the shortcut has not opted out (this is a // private contract between launcher and may be ignored in the future). boolean useLaunchAnimation = (v != null) && !intent.hasExtra(INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION); if (useLaunchAnimation) { ActivityOptions opts = ActivityOptions.makeScaleUpAnimation(v, 0, 0, v.getMeasuredWidth(), v.getMeasuredHeight()); startActivity(intent, opts.toBundle());// 帶啟動動畫(縮放和彈出動畫) } else { startActivity(intent); } return true; } catch (SecurityException e) { Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show(); Log.e(TAG, "Launcher does not have the permission to launch " + intent + ". Make sure to create a MAIN intent-filter for the corresponding activity " + "or use the exported attribute for this activity. " + "tag="+ tag + " intent=" + intent, e); } return false; }
  • 執行startActivity(intent)
public void startActivity(Intent intent){
    startActivityForResult(intent,-1);//不需要知道返回結果
}
  • 接著看一下startActivityForResult
    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;
            }
        } else {
            if (options != null) {
                mParent.startActivityFromChild(this, intent, requestCode, options);
            } else {
                // Note we want to go through this method for compatibility with
                // existing applications that may have overridden it.
                mParent.startActivityFromChild(this, intent, requestCode);
            }
        }
    }

mInstrumentation是Activity的成員變數,用來監控應用程式與系統之間的互動操作。

mInstrumentation.execStartActivity 有個ApplicationThread引數是ActivityThread的內部型別weiApplicationThread的Binder本地物件,mInstrumentation最終將這個ApplicationThread傳遞給ActivityManagerService,AMS通過它通知Launcher進入pause狀態。
mToken(IBinder)是一個Binder代理物件,指向了AMS中ActivityRecord的Binder本地物件,ActivityRecord用來維護組建的執行狀態和資訊,這樣AMS就可以獲得Launcher元件的資訊了。
- 接著看mInstrumentation.execStartActivity

    public ActivityResult execStartActivity(
            Context who, IBinder contextThread, IBinder token, Activity target,
            Intent intent, int requestCode, Bundle options) {
        IApplicationThread whoThread = (IApplicationThread) contextThread;
        if (mActivityMonitors != null) {
            synchronized (mSync) {
                final int N = mActivityMonitors.size();
                for (int i=0; i<N; i++) {
                    final ActivityMonitor am = mActivityMonitors.get(i);
                    if (am.match(who, null, intent)) {
                        am.mHits++;
                        if (am.isBlocking()) {
                            return requestCode >= 0 ? am.getResult() : null;
                        }
                        break;
                    }
                }
            }
        }
        try {
            intent.setAllowFds(false);
            intent.migrateExtraStreamToClipData();
            int result = ActivityManagerNative.getDefault()
                .startActivity(whoThread, intent,
                        intent.resolveTypeIfNeeded(who.getContentResolver()),
                        token, target != null ? target.mEmbeddedID : null,
                        requestCode, 0, null, null, options);
            checkStartActivityResult(result, intent);
        } catch (RemoteException e) {
        }
        return null;
    }

ActivityManagerNative.getDefault().startActivity 獲得一個AMS代理,最終呼叫ActivityManagerProxy.startActivity

   public int startActivity(IApplicationThread caller, 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);
        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);
        }
        mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);// 向AMS傳送程序間通訊
        reply.readException();
        int result = reply.readInt();
        reply.recycle();
        data.recycle();
        return result;
    }

這樣通過ActivityManagerProxy向AMS傳送一個程序間通訊請求,啟動activity。