Activity启动分析(二)

226 阅读12分钟

在Activity启动流程分析一篇中,我们介绍了从Launcher启动桌面应用的大体流程,本篇将是这一篇的补充,主要分析在Activity准备启动到显示过程中的详细内容,探讨关于WindowManager,Activity以及Window之间的联系。从而更进一步了解Android GUI 子系统。

应用进程创建

Activity启动是在ActivityThread中进行的,通过Zygote创建完应用进程后,首先会通过ActivityThread的main方法初始化UI线程,然后会通知ActivityManager进行attachApplication,这里AMS(ActivityManagerService)会看栈顶是否有等待启动的Activity,如果有的话就通过IApplicationThread通知应用Launch这个Activity。关于这个IApplication它实际是一个Binder,它负责AMS和应用进程之间的通信,在ActivityThread中的一系列schedulexxx方法都是通过这个Binder对象通知的。它的服务端是在应用进程一端,客户端是在AMS所在进程即SystemServer进程中。这个Binder是随着ActivityThread的创建而生成的,并在AMS进行attachApplication时将其传递给AMS。

frameworks/base/core/java/android/app/ActivityThread.java
private void attach(boolean system) {
    ……
    IActivityManager mgr = ActivityManagerNative.getDefault();
    try {
        //将该ApplicationThread attach到AMS上 因为AMS正是通过这个对象来和应用程序进行binder调用的
        mgr.attachApplication(mAppThread); 
    } catch (RemoteException ex) {
        // Ignore
    }
    ……
}
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) {//启动activity

    updateProcessState(procState, false);

    ActivityClientRecord r = new ActivityClientRecord();
    r.token = token;
    r.ident = ident;
    r.intent = intent;
    r.activityInfo = info;
    ……

    sendMessage(H.LAUNCH_ACTIVITY, r);
}

AMS通过IApplicationThread的scheduleLaunchActivityl来启动一个Activity,启动过程会对应的创建一个ActivityClientRecord实例,这个和AMS中的ActivityRecord是对应的。这里最为重要的是token参数,它也是一个Binder对象,这个token实际上就是ActivityRecord中的appToken,在ActivityRecord构造时创建,它被AMS用来标记ActivityRecord对应的Activity。在AMS启动过程中会通过WMS调用addAppToken为该Activity添加一个AppWindowToken,appToken作为一个标识被传递给WMS。这样无论是应用进程还是WMS都可以通过这个Token来识别是否为同一个对象。

注:在Android Framework中一个Binder Token通常被用于进行binder通信或者唯一标记一个对象。

frameworks/base/core/java/android/app/ActivityThread.java
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    ……
    Activity a = performLaunchActivity(r, customIntent);

    if (a != null) {
        ……
        handleResumeActivity(r.token, false, r.isForward,
                !r.activity.mFinished && !r.startsNotResumed);activity显示出来 并回调OnResume 
    } 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
        }
    }
}

scheduleLaunchActivity 通过H,实际上是个Handler通知调用handleLaunchActivity启动Activity,这个方法首先调用performLaunchActivity创建Activity,然后通过handleResumeActivity显示activity。这两个方法做了Activity启动过程中的绝大部分事情。后面的内容主要据此展开。

Activity的创建

frameworks/base/core/java/android/app/ActivityThread.java
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    ActivityInfo aInfo = r.activityInfo;
    ……
    Activity activity = null;
    try {
        java.lang.ClassLoader cl = r.packageInfo.getClassLoader();//加载ClassLoader
        activity = mInstrumentation.newActivity(
                cl, component.getClassName(), r.intent);//创建activity
        StrictMode.incrementExpectedActivityCount(activity.getClass());
        r.intent.setExtrasClassLoader(cl);
        if (r.state != null) {
            r.state.setClassLoader(cl);
        }
    } catch (Exception e) {}

    try {
        Application app = r.packageInfo.makeApplication(false, mInstrumentation);//创建Application
        if (activity != null) {
            Context appContext = createBaseContextForActivity(r, activity);//为activity 创建ContextImpl对象
            CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
            Configuration config = new Configuration(mCompatConfiguration);
            //调用activity的attach 将context设置到activity中 保存token
            activity.attach(appContext, this, getInstrumentation(), r.token,
                    r.ident, app, r.intent, r.activityInfo, title, r.parent,
                    r.embeddedID, r.lastNonConfigurationInstances, config);

            if (customIntent != null) {
                activity.mIntent = customIntent;
            }
            r.lastNonConfigurationInstances = null;
            activity.mStartedActivity = false;
            int theme = r.activityInfo.getThemeResource();//获取activity主题 
            if (theme != 0) {
                activity.setTheme(theme);//将主题将应用到activity
            }

            activity.mCalled = false;
            mInstrumentation.callActivityOnCreate(activity, r.state);//调用activity的onCreate
            if (!activity.mCalled) {
                throw new SuperNotCalledException(
                    "Activity " + r.intent.getComponent().toShortString() +
                    " did not call through to super.onCreate()");
            }
            r.activity = activity;
            r.stopped = true;
            if (!r.activity.mFinished) {
                activity.performStart();//调用activity的onstart
                r.stopped = false;
            }
            ……
        }
        r.paused = true;

        mActivities.put(r.token, r);//保存这个ActivityClientRecord 这在应用端代表了activity

    }
    ……
    return activity;
}

在performLaunchActivity中主要做以下事情:

  1. 根据r中的Activity信息创建Activity实例,这个是Instrumention通过反射来完成的。
  2. 为应用创建Application,当然这个Application只会创建一次,如果已经创建了就直接返回
  3. 为Activity创建Context,这里具体为ContextImpl
  4. 将activity attach到上下文Context
  5. 调用onCreate onStart等生命周期回调

接下来我们分步介绍以上几个步骤:

创建Activity实例

创建Activity实例的过程比较简单,因为Activity没有提供任何构造方法,这里通过反射默认构造一个实例。

创建Application

//为应用创建application
public Application makeApplication(boolean forceDefaultAppClass,
        Instrumentation instrumentation) {
    if (mApplication != null) {//Application已经创建就就直接返回
        return mApplication;
    }

    Application app = null;

    String appClass = mApplicationInfo.className;//应用设置的application
    if (forceDefaultAppClass || (appClass == null)) {//如果应用未设置application或者未强制使用默认的application
        appClass = "android.app.Application";//使用默认的application对象
    }

    try {
        java.lang.ClassLoader cl = getClassLoader();
        ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);//创建application context
        app = mActivityThread.mInstrumentation.newApplication(
                cl, appClass, appContext);//创建application
        appContext.setOuterContext(app);
    } catch (Exception e) {}
    mActivityThread.mAllApplications.add(app);
    mApplication = app;
    ……
    instrumentation.callApplicationOnCreate(app);
    ……
    
    return app;
}

makeApplication主要为应用创建Application实例,在创建之前会先通过createAppContext创建AppcliationContext,然后调用onCreate回调。

创建contextImpl

 private Context createBaseContextForActivity(ActivityClientRecord r,
        final Activity activity) {
    //每个Activity启动时都需要创建一个ContextImpl
    ContextImpl appContext = ContextImpl.createActivityContext(this, r.packageInfo, r.token);//创建ContextImpl实例
    appContext.setOuterContext(activity);//outerContext实际上为activity
    Context baseContext = appContext;
    ……
    return baseContext;
}

每个Acitivty启动都需要为其创建一个Context,这里通过ContextImpl.createActivityContext创建

Activity的attach过程

frameworks/base/core/java/android/app/Activity.java
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);//context为ContextImpl

    mFragments.attachActivity(this, mContainer, null);
    
    mWindow = PolicyManager.makeNewWindow(this);//为其创建窗口 Window为抽象类,这里实际上是创建了PhoneWindow
    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;//token赋值 这个token实际上就是在ActivityRecord创建的appToken 它是一个 IApplicationToken.Stub
    mIdent = ident;
    mApplication = application;
    mIntent = intent;
    mComponent = intent.getComponent();
    mActivityInfo = info;
    mTitle = title;
    mParent = parent;
    mEmbeddedID = id;
    mLastNonConfigurationInstances = lastNonConfigurationInstances;
    //这里传给window 使用同样的token,这里为window设置一个管理对象,实际是为其创建一个新的WindowManagerImpl    
    mWindow.setWindowManager(
            (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
            mToken, mComponent.flattenToString(),
            (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);//设置WindowManager
    if (mParent != null) {
        mWindow.setContainer(mParent.getWindow());
    }
    mWindowManager = mWindow.getWindowManager();//取到WindowManager
    mCurrentConfig = config;
}

为Activity创建好context后接下来需要调用Activity的attach方法做以下事情:

  1. 设置context,将其保存在ContextWrapper中
  2. 保存token,这个token为ActivityRecord中的appToken
  3. 为Activity创建Window,即PhoneWindow
  4. 为Window设置WindowManager,这个WindowManager实际为WindowManagerImpl。
frameworks/base/core/java/android/app/ContextImpl.java
class ContextImpl extends Context {
    static {
        ……
        registerService(WINDOW_SERVICE, new ServiceFetcher() {
        Display mDefaultDisplay;
        public Object getService(ContextImpl ctx) {
            ……
            return new WindowManagerImpl(display);
        }});
        ……
    }

    private static void registerService(String serviceName, ServiceFetcher fetcher) {
        ……
        SYSTEM_SERVICE_MAP.put(serviceName, fetcher);
    }

    private static final HashMap<String, ServiceFetcher> SYSTEM_SERVICE_MAP =
                new HashMap<String, ServiceFetcher>();

    @Override
    public Object getSystemService(String name) {
        ServiceFetcher fetcher = SYSTEM_SERVICE_MAP.get(name);
        return fetcher == null ? null : fetcher.getService(this);
    }
}

这里需要注意的是contextImpl在getSystemServer(Context.WINDOW_SERVICE)时会创建一个新的实例WindowManagerImpl,所以对于每个Window,都会有一个新的这样的实例。这个WindowManagerImpl并不是WMS的本地代理,这里不要混淆。接下来我们看看在setWindowManager中会做些什么事情

public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
        boolean hardwareAccelerated) {
    mAppToken = appToken;//保存appToken
    mAppName = appName;
    mHardwareAccelerated = hardwareAccelerated
            || SystemProperties.getBoolean(PROPERTY_HARDWARE_UI, false);
    if (wm == null) {
        wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
    }
    //这里的wm实际上是WMS的本地代理,它是在ComtextImpl的getSystemService的ServiceFetcher中注册的
    //这里会创建一个新的WindowManagerImpl返回 
    mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
}
public final class WindowManagerImpl implements WindowManager {
    //单例 事实上所有的接口都是通过WindowManagerGlobal对象完成的
    //真正的代理任务是交给WindowManagerGlobal,这个对象是个单例,在一个进程中只有一个
    private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
    private final Display mDisplay;
    private final Window mParentWindow;

    public WindowManagerImpl(Display display) {
        this(display, null);
    }

    private WindowManagerImpl(Display display, Window parentWindow) {
        mDisplay = display;
        mParentWindow = parentWindow;
    }
    //这个在Window的setWindowManager中调用 parentWindow为activity对应的window对象
    public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
        return new WindowManagerImpl(mDisplay, parentWindow);
    }

    public WindowManagerImpl createPresentationWindowManager(Display display) {
        return new WindowManagerImpl(display, mParentWindow);
    }

    @Override
    public void addView(View view, ViewGroup.LayoutParams params) {
        mGlobal.addView(view, params, mDisplay, mParentWindow);
    }

    @Override
    public void updateViewLayout(View view, ViewGroup.LayoutParams params) {
        mGlobal.updateViewLayout(view, params);
    }

    @Override
    public void removeView(View view) {
        mGlobal.removeView(view, false);
    }

    @Override
    public void removeViewImmediate(View view) {
        mGlobal.removeView(view, true);
    }

    @Override
    public Display getDefaultDisplay() {
        return mDisplay;
    }
}

setWindowManager为该window保存了Activity的appToken,同时通过createLocalWindowManager又创建了一个WindowManagerImpl。这次创建的实例中mParentWindow不为null,而是当前window,需要注意的是它内部持有一个 WindowManagerGlobal单例,这个WindowManagerGlobal是用来和WMS通信的,它内部就持有WMS的Binder本地代理接口对象。

生命周期的回调

Activity完成attach后就已经有对应的PhoneWindow对象了,同时将context保存在activity中了,这时候先回调onCreate,在onCreate中我们通过setContentView设置内容视图,其实是通过PhoneWindow对象的setContentView来完成的。

frameworks/base/policy/src/com/android/internal/policy/impl/PhoneWindow.java
 @Override
public void setContentView(int layoutResID) {
    if (mContentParent == null) {
        installDecor();//创建decorview
    } else {
        mContentParent.removeAllViews();
    }
    mLayoutInflater.inflate(layoutResID, mContentParent);
    final Callback cb = getCallback();
    if (cb != null && !isDestroyed()) {
        cb.onContentChanged();
    }
}

setContentView为当前window生成一个DecorView,它是整个view树的根view节点。

Activity的显示

通过上面的一系列工作,Activity已经准备好显示前的工作了,接下来就是开始handleResumeActivity了。

final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward,
            boolean reallyResume) {
    ……
    ActivityClientRecord r = performResumeActivity(token, clearHide);//回调OnResume

    if (r != null) {
        final Activity a = r.activity;
        …… 
        if (r.window == null && !a.mFinished && willBeVisible) {//还未被添加到WMS且也没有finish
            r.window = r.activity.getWindow();
            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;//调整Z主序为TYPE_BASE_APPLICATION 因为默认为TYPE_APPLICATION
            l.softInputMode |= forwardBit;
            if (a.mVisibleFromClient) {
                a.mWindowAdded = true;
                wm.addView(decor, l);//添加view decorView是在onCreate中调用setContentView设置的
            }
        } 
        ……
        r.activity.makeVisible();
    }
    ……
}

在这个方法中我们主要看activity是如何被显示出来的。首先获取已经inflate好的DecorView,将其设置为不可见,随后从Activity取到WindowManager(WindowManager是ViewManager的父类,它们都是接口),它实际就是之前通过createLocalWindowManager创建的WindowManagerImpl.随后通过wm.addView添加decorView到window中,这里最终会将window添加到WMS中去。前面我们知道和WMS的通信是由WindowManagerImpl内部的WindowManagerGlobal完成的,它是一个单例。

@Override
public void addView(View view, ViewGroup.LayoutParams params) {
    mGlobal.addView(view, params, mDisplay, mParentWindow);
}

这里的mParentWindow就是activity对应的window,mDisplay代表显示终端对象。params为view的布局参数。


//具体完成addView接口方法的事务 
public void addView(View view, ViewGroup.LayoutParams params,
        Display display, Window parentWindow) {
    ……
    ViewRootImpl root;
    View panelParentView = null;
    synchronized (mLock) {
        ……

        final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams)params;
        if (parentWindow != null) {
            parentWindow.adjustLayoutParamsForSubWindow(wparams);//设置LayoutParams的token
        }
        ……

        root = new ViewRootImpl(view.getContext(), display);//创建ViewRootImpl对象

        view.setLayoutParams(wparams);

        mViews.add(view);//添加到view列表
        mRoots.add(root);//添加到root列表
        mParams.add(wparams);//添加到参数列表
    }

    try {
        root.setView(view, wparams, panelParentView);//将view树和viewRoot关联
    } catch (RuntimeException e) {}
}

在addView中为当前decorview创建ViewRootImpl,这个是用来管理view树的,对应的将view,root,params分别添加到三个对应的数组中,最后通过ViewRootImpl的setView将当前view和ViewRootImpl关联起来。

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {//关联子视图
    synchronized (this) {
        if (mView == null) {//未设置view
            mView = view;
            mViewLayoutDirectionInitial = mView.getRawLayoutDirection();
            mFallbackEventHandler.setView(view);
            mWindowAttributes.copyFrom(attrs);
            ……
            if ((mWindowAttributes.inputFeatures
                    & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {//没有设置InputChannel
                mInputChannel = new InputChannel();//输入通道 这个是用来接收事件的 会通过native层设置
            }
            try {
                mOrigWindowType = mWindowAttributes.type;
                mAttachInfo.mRecomputeGlobalAttributes = true;
                collectViewAttributes();
                //将窗口添加到到显示队列中 这个mInputChannel是socketpair的客户端的channel,
                res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                        getHostVisibility(), mDisplay.getDisplayId(),
                        mAttachInfo.mContentInsets, mInputChannel);
            } 
            ……
            if (mInputChannel != null) {
                if (mInputQueueCallback != null) {
                    mInputQueue = new InputQueue();
                    mInputQueueCallback.onInputQueueCreated(mInputQueue);
                }
                mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
                        Looper.myLooper());//创建窗口事件输入接收者 mInputChannel用来接收事件的接口
            }
            ……
            // Set up the input pipeline.
            //建立输入事件的处理职责链
            CharSequence counterSuffix = attrs.getTitle();
            InputStage syntheticInputStage = new SyntheticInputStage();
            InputStage viewPostImeStage = new ViewPostImeInputStage(syntheticInputStage);
            InputStage nativePostImeStage = new NativePostImeInputStage(viewPostImeStage,
                    "aq:native-post-ime:" + counterSuffix);
            InputStage earlyPostImeStage = new EarlyPostImeInputStage(nativePostImeStage);
            InputStage imeStage = new ImeInputStage(earlyPostImeStage,
                    "aq:ime:" + counterSuffix);
            InputStage viewPreImeStage = new ViewPreImeInputStage(imeStage);
            InputStage nativePreImeStage = new NativePreImeInputStage(viewPreImeStage,
                    "aq:native-pre-ime:" + counterSuffix);

            mFirstInputStage = nativePreImeStage;
            mFirstPostImeInputStage = earlyPostImeStage;
            mPendingInputEventQueueLengthCounterName = "aq:pending:" + counterSuffix;
        }
    }
}

ViewRootImpl作为view树的管理者负责view树的绘制和输入事件的管理。其中最重要的工作是通过mWindowSession将当前window添加到WMS中去。这里需要注意mWindow是一个W对象,它是一个Binder对象,WMS使用它和应用进程通信,当窗口状态发生变化需要通过这个Binder通知应用端。

 //获取windowsession进行会话 也是一个单例 可见一个应用也只会有一个session
public static IWindowSession getWindowSession() {
    synchronized (WindowManagerGlobal.class) {
        if (sWindowSession == null) {
            try {
                InputMethodManager imm = InputMethodManager.getInstance();
                IWindowManager windowManager = getWindowManagerService();
                sWindowSession = windowManager.openSession(
                        imm.getClient(), imm.getInputContext());//打开会话 
                float animatorScale = windowManager.getAnimationScale(2);
                ValueAnimator.setDurationScale(animatorScale);
            } catch (RemoteException e) {
                Log.e(TAG, "Failed to open window session", e);
            }
        }
        return sWindowSession;
    }
}

mWindowSession是在创建ViewRootImpl通过WindowManagerGlobal的getWindowSession得到的。它返回一个IWindowSession是一个匿名binder,用来和WMS进行会话,在WindowManagerGlobal中它是这样打开一个会话的,它同样是一个单例,即一个应用进程只需要一个会话就可以了。

frameworks/base/services/java/com/android/server/wm/Session.java
 //添加window到WMS 应用端通过session来和WMS交互
@Override
public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
        int viewVisibility, int displayId, Rect outContentInsets,
        InputChannel outInputChannel) {
    return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
            outContentInsets, outInputChannel);
}

得到该会话就可以通过addToDisplay将window添加到WMS了,它实际是和Session交互的,Session是IWindowSession匿名binder的服务端,mService是WMS服务。

//添加window到WMS 
public int addWindow(Session session, IWindow client, int seq,
        WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
        Rect outContentInsets, InputChannel outInputChannel) {
   
    boolean reportNewConfig = false;
    WindowState attachedWindow = null;//Window在WMS是通过WindowState体现的
    WindowState win = null;

    synchronized(mWindowMap) {
        
        if (mWindowMap.containsKey(client.asBinder())) {
            Slog.w(TAG, "Window " + client + " is already added");
            return WindowManagerGlobal.ADD_DUPLICATE_ADD;
        }

        boolean addToken = false;
        WindowToken token = mTokenMap.get(attrs.token);//获取到对应的appWindowToken
        if (token == null) {
            
            token = new WindowToken(this, attrs.token, -1, false);
            addToken = true;
        } 

        win = new WindowState(this, session, client, token,
                attachedWindow, appOp[0], seq, attrs, viewVisibility, displayContent);
       
        mPolicy.adjustWindowParamsLw(win.mAttrs);
        win.setShowToOwnerOnlyLocked(mPolicy.checkShowToOwnerOnly(attrs));

        res = mPolicy.prepareAddWindowLw(win, attrs);
        if (res != WindowManagerGlobal.ADD_OKAY) {
            return res;
        }

        if (outInputChannel != null && (attrs.inputFeatures
                & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
            String name = win.makeInputChannelName();
            //创建一对输入通道,其中第一个为服务端的channel位于WindowManagerService中,另外一个通过outInputChannel参数返回到应用程序中
            InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
            win.setInputChannel(inputChannels[0]);
            inputChannels[1].transferTo(outInputChannel);//第二个channel是作为outInputChannel返回给客户端的
            //向InputDispatcher注册服务端的channel,这样当Disaptcher收到事件后可以通过该channel分发事件给客户端
            mInputManager.registerInputChannel(win.mInputChannel, win.mInputWindowHandle);
        }
        ……
        if (addToken) {
            mTokenMap.put(attrs.token, token);
        }
        win.attach();
        mWindowMap.put(client.asBinder(), win);

        if (type == TYPE_INPUT_METHOD) {
            win.mGivenInsetsPending = true;
            mInputMethodWindow = win;
            addInputMethodWindowToListLocked(win);
            imMayMove = false;
        } else if (type == TYPE_INPUT_METHOD_DIALOG) {
            mInputMethodDialogs.add(win);
            addWindowToListInOrderLocked(win, true);
            moveInputMethodDialogsLocked(findDesiredInputMethodWindowIndexLocked(true));
            imMayMove = false;
        } else {
            addWindowToListInOrderLocked(win, true);
            if (type == TYPE_WALLPAPER) {
                mLastWallpaperTimeoutTime = 0;
                displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
            } else if ((attrs.flags&FLAG_SHOW_WALLPAPER) != 0) {
                displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
            } else if (mWallpaperTarget != null
                    && mWallpaperTarget.mLayer >= win.mBaseLayer) {
                // If there is currently a wallpaper being shown, and
                // the base layer of the new window is below the current
                // layer of the target window, then adjust the wallpaper.
                // This is to avoid a new window being placed between the
                // wallpaper and its target.
                displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
            }
        }

        assignLayersLocked(displayContent.getWindowList());
        
    }

    return res;
}

首先我们注意到两个map

final HashMap<IBinder, WindowState> mWindowMap = new HashMap<IBinder, WindowState>();
final HashMap<IBinder, WindowToken> mTokenMap = new HashMap<IBinder, WindowToken>();

mWindowMap是IWindow和服务端Window的映射,这里WindowState即代表了服务端的Window,而IWindow是ViewRootImpl中的W对象。

mTokenMap是token和WindowToken的映射,这里的token为appToken,windowToken为我们在启动activity之前通过addApptoken添加的。

在addWindow中主要完成以下事情:

  1. 通过token取到WindowToken,这个token来自 WindowManager.LayoutParams,它是在WindowManagerGlobal的addView中通过adjustLayoutParamsForSubWindows设置的,它会根据不同的窗口类型和属性设置该token.
  2. 如果未取到WindowToken需要为其创建一个。
  3. 随后为该窗口创建WindowState,它代表了应用端的Window。同时将其添加到mWindowMap中
  4. 根据不同的窗口类型设置窗口的Z序。

关于添加窗口的具体细节,这里就不详述,我会在后面的文章后介绍。

显示的时机

在handleResumeActivity通过addView添加view,将window加入到WMS后,会通过updateViewLayout更新视图

frameworks/base/core/java/android/view/WindowManagerGlobal.java
 //更新视图
public void updateViewLayout(View view, ViewGroup.LayoutParams params) {
    if (view == null) {
        throw new IllegalArgumentException("view must not be null");
    }
    if (!(params instanceof WindowManager.LayoutParams)) {
        throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
    }

    final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams)params;

    view.setLayoutParams(wparams);//设置view布局参数

    synchronized (mLock) {
        int index = findViewLocked(view, true);
        ViewRootImpl root = mRoots.get(index);//找到对应的viewroot
        mParams.remove(index);//移除之前的params
        mParams.add(index, wparams);//添加新的params
        root.setLayoutParams(wparams, false);//通过root设置参数 false代表view已经添加过 这里会对view树重新绘制
    }
}

在root.setLayoutParams中会通过scheduleTraversals()绘制view。