Android启动Activity流程中的Token分析

以下分析基于Android4.3.

1. 从Activity到ActivityManagerService

通过Activity1的startActivity启动Activity2,调用流程如下

(Activity).startActivity(Intent, Bundle)

    --》(Activity).startActivityForResult(Intent, int)

        --》(Activity).startActivityForResult(Intent, int, Bundle)

            --》Instrumentation.execStartActivity(Context, IBinder, IBinder, Activity, Intent, int, Bundle) 

      Instrumentation.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.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;
    } 
ActivityManagerNative.getDefault().startActivity通过AIDL进程间通信机制调用ActivityManagerService的startActivity方法。
2. 从ActivityMnageService到Activity

调用流程如下:

ActivityManagerService.startActivity(IApplicationThread, String, Intent, String, IBinder, String, int, int, String, ParcelFileDescriptor, Bundle)   
 --》ActivityManagerService.startActivityAsUser(IApplicationThread, String, Intent, String, IBinder, String, int, int, String, ParcelFileDescriptor, Bundle, int)    
      --》ActivityStack.startActivityMayWait(IApplicationThread, int, String, Intent, String, IBinder, String, int, int, String, ParcelFileDescriptor, IActivityManager$WaitResult, Configuration, Bundle, int)
          --》ActivityStack.startActivityLocked(IApplicationThread, Intent, String, ActivityInfo, IBinder, String, int, int, int, String, int, Bundle, boolean, ActivityRecord[])

            ActivityStack.startActivityLocked,这个过程会创建ActivityRecord,ActivityRecord构造的时候会创建成员变量appToken = new Token(this),这个appToken用来与WindowManager通信。接着调用以下过程
              --》ActivityStack.startActivityUncheckedLocked(ActivityRecord, ActivityRecord, int, boolean, Bundle)    
                  --》ActivityStack.startActivityLocked(ActivityRecord, boolean, boolean, boolean, Bundle)
                      --》ActivityStack.startActivityUncheckedLocked(ActivityRecord, ActivityRecord, int, boolean, Bundle)

                          --》ActivityStack.startActivityLocked(ActivityRecord, boolean, boolean, boolean, Bundle)

  这次的startActivityLocked的参数不再是Intent而是ActivityRecord,

  主要的过程分3步:

   1. 将Activity2的ActivityRecord添加到mHistory中

   2. 通过mWindowManager.addAppToken建立activity与WindowManagerService之间的联系。

       mService.mWindowManager.addAppToken(
                    addPos, r.appToken, r.task.taskId, r.info.screenOrientation, r.fullscreen,
                    (r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0);

      在WindowManagerService的addAppToken的处理中,会创建atoken = new AppWindowToken(this, token);

       接着      mAppTokens.add(addPos, atoken); //将atoken加入到WindowManagerService的成员mAppTokens中
                     addAppTokenToAnimating(addPos, atoken);
                      mTokenMap.put(token.asBinder(), atoken); //建立appToken与AppWindowToken的映射关系

   3. 继续进行启动Activity2的流程

                  -->resumeTopActivityLocked(null);

                   这个过程分两步:

                   1)ActivityStack.startPausingLocked(boolean, boolean) ,使前一个Activity进行pause动作

                       调用  

                          prev.app.thread.schedulePauseActivity(prev.appToken, prev.finishing, userLeaving, prev.configChangeFlags);

                          取得前一个Activity,通过AIDL调用,向应用程序发送 SCHEDULE_PAUSE_ACTIVITY_TRANSACTION消息,

                          进而进入到应用程序侧的handlePauseActivity流程,这个流程中先进行activity的onPause回调,再通过AIDL调用ActivityManagerService的activityPaused方法。

                 2)启动下一个Activity

                               ActivityManagerService.activityPaused(IBinder)

                               --》ActivityStack.activityPaused(IBinder, boolean) 

                                    先进行前一个Activity的Pause流程,之后是completePauseLocked
                                    --》ActivityStack.completePauseLocked() line:
                                        --》ActivityStack.resumeTopActivityLocked(ActivityRecord)

                                            --》ActivityStack.resumeTopActivityLocked(ActivityRecord, Bundle)

                                                --》ActivityStack.startSpecificActivityLocked(ActivityRecord, boolean, boolean)

                           startSpecificActivityLocked的处理中会判断Activity2和Activity1是否是同一个进程。

                          如果不是,调用mService.startProcessLocked,启动一个新的进程。

                         如果是,调用startSpecificActivityLocked,这个函数中会调用app.thread.scheduleLaunchActivity进入Activity侧的处理流程。

        public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
                ActivityInfo info, Configuration curConfig, CompatibilityInfo compatInfo,
                Bundle state, List<ResultInfo> pendingResults,
                List<Intent> pendingNewIntents, boolean notResumed, boolean isForward,
                String profileName, ParcelFileDescriptor profileFd, boolean autoStopProfiler, int panelIndex) {
            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;
            r.mPanelIndex = panelIndex;

            updatePendingConfiguration(curConfig);

            queueOrSendMessage(H.LAUNCH_ACTIVITY, r);
        }
    注:这个过程会把 r.appToken传递给Activity侧的 ActivityClientRecord

3. Activity侧的处理流程

通过message会进入以下过程

ActivityThread.handleLaunchActivity(ActivityThread$ActivityClientRecord, Intent)

 --》ActivityThread.performLaunchActivity(ActivityThread$ActivityClientRecord, Intent)
     --》(Activity).attach(Context, ActivityThread, Instrumentation, IBinder, int, Application, Intent, ActivityInfo, CharSequence, Activity, String,          Activity$NonConfigurationInstances, Configuration, int)
          -->(Activity).attach(Context, ActivityThread, Instrumentation, IBinder, int, Application, Intent, ActivityInfo, CharSequence, Activity, String,    
Activity$NonConfigurationInstances, Configuration) 

final void attach(Context context, ActivityThread aThread,
            Instrumentation instr, IBinder token, int ident,
            Application application, Intent intent, ActivityInfo info,
            CharSequence title, Activity parent, String id,
            NonConfigurationInstances lastNonConfigurationInstances,
            Configuration config) {
        attachBaseContext(context);

        mFragments.attachActivity(this, mContainer, null);

        mWindow = PolicyManager.makeNewWindow(this);
        mWindow.setWindowPanelIndex(mPanelIndex);
        String deviveName = (String)intent.getExtra("devicename");
        if(deviveName!=null){
            mWindow.setWindowTitle(deviveName);
        }
        mWindow.setCallback(this);
        mWindow.getLayoutInflater().setPrivateFactory(this);
        if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
            mWindow.setSoftInputMode(info.softInputMode);
        }
        if (info.uiOptions != 0) {
            mWindow.setUiOptions(info.uiOptions);
        }
        mUiThread = Thread.currentThread();

        mMainThread = aThread;
        mInstrumentation = instr;
        mToken = token; 
        mIdent = ident;
        mApplication = application;
        mIntent = intent;
        mComponent = intent.getComponent();
        mActivityInfo = info;
        mTitle = title;
        mParent = parent;
        mEmbeddedID = id;
        mLastNonConfigurationInstances = lastNonConfigurationInstances;

        mWindow.setWindowManager(
                (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
                mToken, mComponent.flattenToString(),
                (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
        if (mParent != null) {
            mWindow.setContainer(mParent.getWindow());
        }
        mWindowManager = mWindow.getWindowManager();
        mCurrentConfig = config;
    }

  attach处理:把token赋值给Activity的成员变量mToken,mWindow是一个PhoneWindow.(继承自Window),是Activity的成员。通过调用mWindow.setWindowManager将mToken赋值给Window的mAppToken成员变量。

attach之后,performLaunchActivity会间接调用Activity的onCreate,进而调用setContentView,生成decorView。

  接着

           ActivityThread.handleLaunchActivity(ActivityThread$ActivityClientRecord, Intent)

                   --》ActivityThread.handleResumeActivity(ActivityThread$ActivityClientRecord, Intent)

    如下是部分代码:

            if (r.window == null && !a.mFinished && willBeVisible) {
                r.window = r.activity.getWindow();//取得Activity的window
                View decor = r.window.getDecorView();
                decor.setVisibility(View.INVISIBLE);
                ViewManager wm = a.getWindowManager();
                WindowManager.LayoutParams l = r.window.getAttributes();
                a.mDecor = decor;
                l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
                l.softInputMode |= forwardBit;
                if (a.mVisibleFromClient) {
                    a.mWindowAdded = true;
                    wm.addView(decor, l);
                }

            // If the window has already been added, but during resume
            // we started another activity, then don't yet make the
            // window visible.
            } else if (!willBeVisible) {
                if (localLOGV) Slog.v(
                    TAG, "Launch " + r + " mStartedActivity set");
                r.hideForNow = true;
            }
4. addView的处理流程

WindowManagerImpl.addView(View, ViewGroup$LayoutParams)
--》WindowManagerGlobal.addView(View, ViewGroup$LayoutParams, Display, Window)
addView传入的第二个参数是LayoutParams,是Activity对应的window的mWindowAttributes属性。

public void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow) {
        if (view == null) {
            throw new IllegalArgumentException("view must not be null");
        }
        if (display == null) {
            throw new IllegalArgumentException("display must not be null");
        }
        if (!(params instanceof WindowManager.LayoutParams)) {
            throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
        }

        final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams)params;
        if (parentWindow != null) {
            parentWindow.adjustLayoutParamsForSubWindow(wparams);
        }

        ViewRootImpl root;
        View panelParentView = null;

        synchronized (mLock) {
            // Start watching for system property changes.
            if (mSystemPropertyUpdater == null) {
                mSystemPropertyUpdater = new Runnable() {
                    @Override public void run() {
                        synchronized (mLock) {
                            for (ViewRootImpl viewRoot : mRoots) {
                                viewRoot.loadSystemProperties();
                            }
                        }
                    }
                };
                SystemProperties.addChangeCallback(mSystemPropertyUpdater);
            }

            int index = findViewLocked(view, false);
            if (index >= 0) {
                throw new IllegalStateException("View " + view
                        + " has already been added to the window manager.");
            }

            // If this is a panel window, then find the window it is being
            // attached to for future reference.
            if (wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
                    wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
                final int count = mViews != null ? mViews.length : 0;
                for (int i=0; i<count; i++) {
                    if (mRoots[i].mWindow.asBinder() == wparams.token) {
                        panelParentView = mViews[i];
                    }
                }
            }

            root = new ViewRootImpl(view.getContext(), display);

            view.setLayoutParams(wparams);

            if (mViews == null) {
                index = 1;
                mViews = new View[1];
                mRoots = new ViewRootImpl[1];
                mParams = new WindowManager.LayoutParams[1];
            } else {
                index = mViews.length + 1;
                Object[] old = mViews;
                mViews = new View[index];
                System.arraycopy(old, 0, mViews, 0, index-1);
                old = mRoots;
                mRoots = new ViewRootImpl[index];
                System.arraycopy(old, 0, mRoots, 0, index-1);
                old = mParams;
                mParams = new WindowManager.LayoutParams[index];
                System.arraycopy(old, 0, mParams, 0, index-1);
            }
            index--;

            mViews[index] = view;
            mRoots[index] = root;
            mParams[index] = wparams;
        }

        // do this last because it fires off messages to start doing things
        try {
            root.setView(view, wparams, panelParentView);
        } catch (RuntimeException e) {
            // BadTokenException or InvalidDisplayException, clean up.
            synchronized (mLock) {
                final int index = findViewLocked(view, false);
                if (index >= 0) {
                    removeViewLocked(index, true);
                }
            }
            throw e;
        }
    }

 1)通过调用adjustLayoutParamsForSubWindow将LayoutParams的token成员变量。

 2)ViewRootImpl的构造

 public ViewRootImpl(Context context, Display display) {
        mContext = context;
        mWindowSession = WindowManagerGlobal.getWindowSession();
        mDisplay = display;
        mBasePackageName = context.getBasePackageName();

        CompatibilityInfoHolder cih = display.getCompatibilityInfo();
        mCompatibilityInfo = cih != null ? cih : new CompatibilityInfoHolder();

        mThread = Thread.currentThread();
        mLocation = new WindowLeaked(null);
        mLocation.fillInStackTrace();
        mWidth = -1;
        mHeight = -1;
        mDirty = new Rect();
        mTempRect = new Rect();
        mVisRect = new Rect();
        mWinFrame = new Rect();
        mWindow = new W(this);
        mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion;
        mViewVisibility = View.GONE;
        mTransparentRegion = new Region();
        mPreviousTransparentRegion = new Region();
        mFirst = true; // true for the first time the view is added
        mAdded = false;
        mAccessibilityManager = AccessibilityManager.getInstance(context);
        mAccessibilityInteractionConnectionManager =
            new AccessibilityInteractionConnectionManager();
        mAccessibilityManager.addAccessibilityStateChangeListener(
                mAccessibilityInteractionConnectionManager);
        mAttachInfo = new View.AttachInfo(mWindowSession, mWindow, display, this, mHandler, this);
        mViewConfiguration = ViewConfiguration.get(context);
        mDensity = context.getResources().getDisplayMetrics().densityDpi;
        mNoncompatDensity = context.getResources().getDisplayMetrics().noncompatDensityDpi;
        mFallbackEventHandler = PolicyManager.makeNewFallbackEventHandler(context);
        mChoreographer = Choreographer.getInstance();

        PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
        mAttachInfo.mScreenOn = powerManager.isScreenOn();
        loadSystemProperties();
    }

  3)设定decorView的LayoutParams
  4)ViewRootImpl.setView部分处理  

                // Schedule the first layout -before- adding to the window
                // manager, to make sure we do the relayout before receiving
                // any other events from the system.
                requestLayout();
                if ((mWindowAttributes.inputFeatures
                        & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
                    mInputChannel = new InputChannel();
                }
                try {
                    mOrigWindowType = mWindowAttributes.type;
                    mAttachInfo.mRecomputeGlobalAttributes = true;
                    collectViewAttributes();
                    res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                            getHostVisibility(), mDisplay.getDisplayId(),
                            mAttachInfo.mContentInsets, mInputChannel);
                }

说明: 1.requestLayout将遍历布局的处理放入UI主线程的工作队列中。
             2. mWindowSession.addToDisplay,最后会调用WindwoMangerService的addWindow处理。

             3. addWindow之后会执行requestLayout放入工作队列中的处理过程,会调用WindwoMangerService的relayoutWindow。

5. 各组件间关系



  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值