WindowManagerService添加窗口流程简析---应用窗口的创建

    Android系统中的窗体是屏幕上的一块用于绘制各种UI元素并能够响应应用户输入的一个矩形区域。从原理上来讲,窗体的概念是独自占有一个Surface实例的显示区域。比如Dialog、Activity的界面、壁纸、状态栏以及Toast等都是窗体。 


 一、Android窗口类型

  在WindowManager类的内部类LayoutParams中定义了三种窗口类型(Application windows,Sub-windows和System windows),所以Android系统中窗口分为三大类型:

  • 应用窗口:该窗口对应一个Activity,因此,要创建应用窗口就必须在Activity中完成了。
  • 子窗口:必须依附在某个父窗口之上。
  • 系统窗口:由系统进程创建,不依赖于任何应用或者不依附在任何父窗口之上。

    

二、Activity应用窗口的创

    

    1、Activity创建Window并与WindowManager进行绑定

    在Activity启动过程中会调用ActivityThread的performLaunchActivity方法,performLaunchActivity方法中又会调用Activity的attach方法。下面从Activity的attach方法开始入手,如下所示:

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, String referrer, 
            IVoiceInteractor voiceInteractor, Window window, ActivityConfigCallback activityConfigCallback) {

        .......
       //创建PhoneWindow,Window的实现类 ,一个Activity对应着一个Window也就是应用窗口。
        mWindow = new PhoneWindow(this, window, activityConfigCallback); 
        ......
       //调用PhoneWindow的setWindowManager方法,
       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(); //WindowManagerImpl对象
        ......
   }

    调用了PhoneWindow的setWindowManager方法,这个方法的具体的实现在PhoneWindow的父类Window中。

public void setWindowManager(WindowManager wm, IBinder appToken, String appName, boolean hardwareAccelerated) {
        mAppToken = appToken;
        mAppName = appName;
        mHardwareAccelerated = hardwareAccelerated
                || SystemProperties.getBoolean(PROPERTY_HARDWARE_UI, false);
        if (wm == null) {

            //mContext.getSystemService(Context.WINDOW_SERVICE);返回的是WindowManagerImpl对象
            wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);

         }

        //创建WindowManagerImpl并将window和WindowManagerImpl关联
        mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
    }


    经过上面的setWindowManager方法,Window就和WindowManagerImpl进行了关联,这样WindowManagerImpl就持有了Window的引用,就可以对Window进行操作。

    2、Activity给Window添加View

    每个Activity都会调用setContextView方法来加载布局视图,而这其实就是视图View添加到Activity窗口上的一个过程。加载布局视图代码如下Activity#setContentView:

public void setContentView(int layoutResID) {
        getWindow().setContentView(layoutResID); //getWindow()返回Activity的成员变量mWindow即PhoneWindow
        initWindowDecorActionBar(); //初始化ActionBarView
    }

2.1 查看PhoneWindow的SetContentView方法

public void setContentView(int layoutResID) {
        if (mContentParent == null) {
            installDecor();  //1----创建顶层视图DecorView,整个应用窗口的根View
        } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
            mContentParent.removeAllViews();
        }
        if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
            final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
                    getContext());
            transitionTo(newScene);
        } else {
            mLayoutInflater.inflate(layoutResID, mContentParent);  //加载xml布局视图内容到视图容器mContentParent中
        }
    }

2.1.1 PhoneWindow的installDecor()的具体内容:

 private void installDecor() {
        if (mDecor == null) {  
            mDecor = generateDecor(-1); //1---生成DecorView对象,DecorView继承自FrameLayout
            mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
            mDecor.setIsRootNamespace(true);
            if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
                mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
            }
        }

        //2---mContentParent是id为android.R.id.content的FrameLayout,setContentView就是将布局设置在这里
        if (mContentParent == null) {  
            mContentParent = generateLayout(mDecor);
            .......
         } else {  //设置title
               mTitleView = findViewById(R.id.title);
                if (mTitleView != null) {
                    if ((getLocalFeatures() & (1 << FEATURE_NO_TITLE)) != 0) {
                        final View titleContainer = findViewById(R.id.title_container);
                        if (titleContainer != null) {
                            titleContainer.setVisibility(View.GONE);
                        } else {
                            mTitleView.setVisibility(View.GONE);
                        }
                        mContentParent.setForeground(null);
                   } else {
                        mTitleView.setText(mTitle);
                    }
                }
           }
}

    注释1中generateDecor方法通过new DecorView创建对象,在DecorView的构造方法中,传入了PhoneWindow对象,即将PhoneWindow和DecorView进行了关联。下面看下注释2中generateLayout主要内容:

2.1.2 PhoneWindow的generateLayout(mDecor)

protected ViewGroup generateLayout(DecorView decor) {
  /*应用当前主题数据,加载的是 
    *TypedArray  mWindowStyle = mContext.obtainStyledAttributes(com.android.internal.R.styleable.Window);
    */
  TypedArray a = getWindowStyle();
  ......
  //加载DecorView布局,这些xml文件位于frameworks/base/core/res/res/layout下
  int layoutResource;
  int features = getLocalFeatures();
  if ((features & ((1 << FEATURE_LEFT_ICON) | (1 << FEATURE_RIGHT_ICON))) != 0) {
    if (mIsFloating) {
      TypedValue res = new TypedValue();
      getContext().getTheme().resolveAttribute(com.android.internal.R.attr.dialogTitleIconsDecorLayout, res, true);
      layoutResource = res.resourceId;
    } else {
      layoutResource = com.android.internal.R.layout.screen_title_icons;
  }
  removeFeature(FEATURE_ACTION_BAR);
  } else if ((features & ((1 << FEATURE_PROGRESS) | (1 << FEATURE_INDETERMINATE_PROGRESS))) != 0 && (features & (1 << FEATURE_ACTION_BAR)) == 0) {
  layoutResource = com.android.internal.R.layout.screen_progress;
  ......
  
  mDecor.startChanging();
  //inflate View,并添加到decorView中
  View in = mLayoutInflater.inflate(layoutResource, null);
  decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
  //id="@android:id/content"的View赋值给mContentParent
  ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
  if (contentParent == null) {
    throw new RuntimeException("Window couldn't find content container view");
  }

2.2 initWindowDecorActionBar(); 

private void initWindowDecorActionBar() {
       Window window = getWindow();
        window.getDecorView();  //若DecorView为null,则创建DecorView
        if (isChild() || !window.hasFeature(Window.FEATURE_ACTION_BAR) || mActionBar != null) {
            return;
        }

        mActionBar = new WindowDecorActionBar(this); //创建ActionBar
        mActionBar.setDefaultDisplayHomeAsUpEnabled(mEnableDefaultActionBarUp);

        mWindow.setDefaultIcon(mActivityInfo.getIconResource());
        mWindow.setDefaultLogo(mActivityInfo.getLogoResource());
    }

三、Activity添加窗口Window的过程

    在setContentView中只是将需要添加的View的结构添加到DecorView中,此时DecorView并无显示内容,View还未进行绘制,所以在onCreate方法中是无法获取View的宽高等信息。

    在Activity创建完成之后,Ams利用Bindler进程间的通信机制通知客户端调用ActivityThread类中的handleResumeActivity方法来启动Activity。代码如下:

final void handleResumeActivity(IBinder token,
            boolean clearHide, boolean isForward, boolean reallyResume) {
        ........
        ActivityClientRecord r = performResumeActivity(token, clearHide);

        if (r != null) {
            final Activity a = r.activity;
            final int forwardBit = isForward ?
                    WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION : 0;
            boolean willBeVisible = !a.mStartedActivity;
            if (!willBeVisible) {
                try {
                    willBeVisible = ActivityManagerNative.getDefault().willActivityBeVisible(
                            a.getActivityToken());
                } catch (RemoteException e) {
                }
            }
            if (r.window == null && !a.mFinished && willBeVisible) { //参数设置
                r.window = r.activity.getWindow();//PhoneWindow
                View decor = r.window.getDecorView(); //窗口顶层视图DecorView
                decor.setVisibility(View.INVISIBLE);
                ViewManager wm = a.getWindowManager(); //Activity窗口的窗口管理器对象WindowManager
                WindowManager.LayoutParams l = r.window.getAttributes();//窗口参数

                a.mDecor = decor;

                //窗口的类型为基础应用窗口
                l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
                //窗口的软输入法模式
                l.softInputMode |= forwardBit;
                if (a.mVisibleFromClient) {
                    //标记客户端Activity添加窗口成功
                    a.mWindowAdded = true;
                    //添加窗口
                    wm.addView(decor, l);
                }
    ........
        }
    }

    在这个过程中最主要的操作就是调用了WindowManager.addView方法,而WindowManager是个接口类,继承自ViewManager。ViewManager源码如下:

public interface ViewManager{

    public void addView(View view, ViewGroup.LayoutParams params);
    public void updateViewLayout(View view, ViewGroup.LayoutParams params);
    public void removeView(View view);
}

    WindowManager继承自ViewManager,WindowManager窗口管理其实就是对窗口的视图View进行管理。WindowManager 源码如下:

public interface WindowManager extends ViewManager {
    ........
     public Display getDefaultDisplay();
     public void removeViewImmediate(View view);
     public static class LayoutParams extends ViewGroup.LayoutParams
            implements Parcelable {
    ........
    }
}

    WindowManager 的实现类WindowManagerImpl,其源码如下:

public final class WindowManagerImpl implements WindowManager {
    private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
    private final Display mDisplay;

    private IBinder mDefaultToken;

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

    private WindowManagerImpl(Display display, Window parentWindow) {
        mDisplay = display;
        mParentWindow = parentWindow;
    }

    public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
        return new WindowManagerImpl(mDisplay, parentWindow);
    }

   @Override
    public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        applyDefaultToken(params);  //如果params.token为null,则token设置为系统默认的
        mGlobal.addView(view, params, mDisplay, mParentWindow);
    }

    @Override
    public void updateViewLayout(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        applyDefaultToken(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;
    }
}

    从源码中可以看出,WindowManagerImpl中并没有做实质性的操作,而是将具体操作全部交给了WindowManagerGlobal去处理,这里到了设计模式中的桥接模式,可以看出WindowManagerGlobal是一个单例,说明在一个进程中只有一个WindowManagerGlobal实例。下面查看WindowManagerGlobal的addView()方法。

public final class WindowManagerGlobal {
    private final ArrayList<View> mViews = new ArrayList<View>(); //保存当前应用所有窗口的DecorView
    private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>(); //保存当前应用所有ViewRootImpl
    private final ArrayList<WindowManager.LayoutParams> mParams =
            new ArrayList<WindowManager.LayoutParams>(); //保存当前应用所有窗口的布局参数
    ........
    //单例模式构造方法
    public static WindowManagerGlobal getInstance() {
        synchronized (WindowManagerGlobal.class) {
            if (sDefaultWindowManager == null) {
                sDefaultWindowManager = new WindowManagerGlobal();
            }
            return sDefaultWindowManager;
        }
    }

//添加view
 public void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow) {
     ......
        final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
        if (parentWindow != null) {
           parentWindow.adjustLayoutParamsForSubWindow(wparams);
        } else {
            // 如果没有父级,那么此视图的硬件加速从应用程序的硬件加速设置中设置。
           final Context context = view.getContext();
            if (context != null
                    && (context.getApplicationInfo().flags
                            & ApplicationInfo.FLAG_HARDWARE_ACCELERATED) != 0) {
                wparams.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
           }
       }

        ViewRootImpl root;
        View panelParentView = null;

        synchronized (mLock) {
            // 监听系统属性变更
            if (mSystemPropertyUpdater == null) {
                mSystemPropertyUpdater = new Runnable() {
                    @Override public void run() {
                        synchronized (mLock) {
                            for (int i = mRoots.size() - 1; i >= 0; --i) {
                                mRoots.get(i).loadSystemProperties();
                            }
                        }
                    }
                };
                SystemProperties.addChangeCallback(mSystemPropertyUpdater);
            }

            int index = findViewLocked(view, false);
            if (index >= 0) {
                if (mDyingViews.contains(view)) { //如果该view处于正在删除中,则直接删除
                    // Don't wait for MSG_DIE to make it's way through root's queue.
                    mRoots.get(index).doDie();
                } else { //不能重复添加同一个view对象
                    throw new IllegalStateException("View " + view
                            + " has already been added to the window manager.");
                }
                // The previous removeView() had not completed executing. Now it has.
            }

            // 如果是子Window,则根据token获取对应的父窗口Window
            if (wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
                    wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
                final int count = mViews.size();
                for (int i = 0; i < count; i++) {
                    if (mRoots.get(i).mWindow.asBinder() == wparams.token) {
                        panelParentView = mViews.get(i);
                    }
                }
            }

            root = new ViewRootImpl(view.getContext(), display); //每一个窗口对应一个ViewRootImpl

            view.setLayoutParams(wparams);

            mViews.add(view);
            mRoots.add(root);
            mParams.add(wparams);

            // do this last because it fires off messages to start doing things
            try {
                root.setView(view, wparams, panelParentView);  //ViewRootImpl 完成绘制view操作
           } catch (RuntimeException e) {
               // 出现异常,则清除该View
               if (index >= 0) {
                   removeViewLocked(index, true);
                }
                throw e;
           }
        }
   }
//主要更新当前窗口的参数LayoutParams
 public void updateViewLayout(View view, ViewGroup.LayoutParams params) {

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

        view.setLayoutParams(wparams);

        synchronized (mLock) {
            int index = findViewLocked(view, true);
            ViewRootImpl root = mRoots.get(index);
            mParams.remove(index);
            mParams.add(index, wparams);
            root.setLayoutParams(wparams, false); //绘制操作由ViewRootImpl完成
        }
    }
    //从三个数组里面分别移除DecorView对象,ViewRootIpl对象,WindowManager.LayoutParams对象
    public void removeView(View view, boolean immediate) { 
        synchronized (mLock) {
            int index = findViewLocked(view, true);
            View curView = mRoots.get(index).getView();
            removeViewLocked(index, immediate);
            if (curView == view) {
                return;
            }
        }
    }

    在WindowManagerGlobal的方法中最终调用ViewRootImpl的setView来完成View的添加和绘制,ViewRootImpl是一个视图层次结构的顶部,它实现了View与WindowManager之间所需要的协议,作为WindowManagerGlobal中大部分的内部实现。这个好理解,在WindowManagerGlobal中实现方法中,都可以见到ViewRootImpl,也就说WindowManagerGlobal方法最后还是调用到了ViewRootImpl。addView,removeView,update调用顺序

WindowManagerImpl -> WindowManagerGlobal -> ViewRootImpl 

    下面查看ViewRootImpl的setView的主要内容:

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
                ...
                // 在添加到WindowManager中之前,先进行绘制view操作,绘制完毕后才能接受事件
                requestLayout();
                ......
                try {
                ......
                    res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                            getHostVisibility(), mDisplay.getDisplayId(),
                            mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                            mAttachInfo.mOutsets, mInputChannel);  
                } 
    }

requestlayout()进行布局的绘制,绘制结束后调用mWindowSession.addToDisplay添加和显示view。mWindowSession是Session对象,继承自IWindowSession.Stub(是一个Binder对象),也就是说这其实是一次IPC过程,远程调用了Session中的addToDisPlay方法。下面查看下Session中的addToDisPlay方法:

@Override
    public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
            int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets,
            Rect outOutsets, InputChannel outInputChannel) {
        return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
                outContentInsets, outStableInsets, outOutsets, outInputChannel);
    }

    其中mService就是WindowManagerService,也就是说Window的添加请求,最终是通过WindowManagerService来添加的。下面查看下WindowManagerService的具体方法。

四、WindowManagerService的addWindow方法

public int addWindow(Session session, IWindow client, int seq,
            WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
            Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
            InputChannel outInputChannel) {
        int[] appOp = new int[1];
        int res = mPolicy.checkAddPermission(attrs, appOp); //检查权限,系统窗口需要对应的系统权限
        if (res != WindowManagerGlobal.ADD_OKAY) {
            return res;
        }

        boolean reportNewConfig = false;
        WindowState parentWindow = null;
        long origId;
        final int callingUid = Binder.getCallingUid();
        final int type = attrs.type; //窗体的类型

        synchronized(mWindowMap) {
            if (!mDisplayReady) {
                throw new IllegalStateException("Display has not been initialialized");
            }
	    //通过displayId參数指定加入到哪一个DisplayContent,默认是DEFAULT_DISPLAY手机屏幕
            final DisplayContent displayContent = mRoot.getDisplayContentOrCreate(displayId);
            if (displayContent == null) {
                Slog.w(TAG_WM, "Attempted to add window to a display that does not exist: "
                        + displayId + ".  Aborting.");
                return WindowManagerGlobal.ADD_INVALID_DISPLAY;
            }
            if (!displayContent.hasAccess(session.mUid)
                    && !mDisplayManagerInternal.isUidPresentOnDisplay(session.mUid, displayId)) {
                Slog.w(TAG_WM, "Attempted to add window to a display for which the application "
                        + "does not have access: " + displayId + ".  Aborting.");
                return WindowManagerGlobal.ADD_INVALID_DISPLAY;
            }

            if (mWindowMap.containsKey(client.asBinder())) { //判断是否重复添加Window
                Slog.w(TAG_WM, "Window " + client + " is already added");
                return WindowManagerGlobal.ADD_DUPLICATE_ADD;
            }

	    //子窗口必须依附于父窗口,对于子窗体来说,attrs.token表示了父窗体
            if (type >= FIRST_SUB_WINDOW && type <= LAST_SUB_WINDOW) {
                parentWindow = windowForClientLocked(null, attrs.token, false);
                if (parentWindow == null) {
                    Slog.w(TAG_WM, "Attempted to add window with token that is not a window: "
                          + attrs.token + ".  Aborting.");
                    return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN;
                }
                if (parentWindow.mAttrs.type >= FIRST_SUB_WINDOW
                        && parentWindow.mAttrs.type <= LAST_SUB_WINDOW) { //窗体嵌套只能是两层,子窗口是不能在添加窗口的
                    Slog.w(TAG_WM, "Attempted to add window with token that is a sub-window: "
                            + attrs.token + ".  Aborting.");
                    return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN;
                }
            }

            if (type == TYPE_PRIVATE_PRESENTATION && !displayContent.isPrivate()) {
                Slog.w(TAG_WM, "Attempted to add private presentation window to a non-private display.  Aborting.");
                return WindowManagerGlobal.ADD_PERMISSION_DENIED;
            }

            AppWindowToken atoken = null; //应用窗口token
            final boolean hasParent = parentWindow != null;
            // 子窗口使用父窗口策略
            WindowToken token = displayContent.getWindowToken(
                    hasParent ? parentWindow.mAttrs.token : attrs.token);
            // If this is a child window, we want to apply the same type checking rules as the
            // parent window type.
            final int rootType = hasParent ? parentWindow.mAttrs.type : type;

            boolean addToastWindowRequiresToken = false;

            if (token == null) { //token异常判断
               ......
                final IBinder binder = attrs.token != null ? attrs.token : client.asBinder();
                token = new WindowToken(this, binder, type, false, displayContent,
                        session.mCanAddInternalSystemWindow); //创建系统WindowToken
            } else if (rootType >= FIRST_APPLICATION_WINDOW && rootType <= LAST_APPLICATION_WINDOW) { //应用窗口类型
                atoken = token.asAppWindowToken();
                ......
            } else if (rootType == TYPE_INPUT_METHOD) {
                if (token.windowType != TYPE_INPUT_METHOD) {
                    Slog.w(TAG_WM, "Attempted to add input method window with bad token "
                            + attrs.token + ".  Aborting.");
                      return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                }
            } else if (rootType == TYPE_VOICE_INTERACTION) {
                if (token.windowType != TYPE_VOICE_INTERACTION) {
                    Slog.w(TAG_WM, "Attempted to add voice interaction window with bad token "
                            + attrs.token + ".  Aborting.");
                      return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                }
            } else if (rootType == TYPE_WALLPAPER) {
                if (token.windowType != TYPE_WALLPAPER) {
                    Slog.w(TAG_WM, "Attempted to add wallpaper window with bad token "
                            + attrs.token + ".  Aborting.");
                      return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                }
            } else if (rootType == TYPE_DREAM) {
                if (token.windowType != TYPE_DREAM) {
                    Slog.w(TAG_WM, "Attempted to add Dream window with bad token "
                            + attrs.token + ".  Aborting.");
                      return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                }
            } else if (rootType == TYPE_ACCESSIBILITY_OVERLAY) {
                if (token.windowType != TYPE_ACCESSIBILITY_OVERLAY) {
                    Slog.w(TAG_WM, "Attempted to add Accessibility overlay window with bad token "
                            + attrs.token + ".  Aborting.");
                    return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                }
            } else if (type == TYPE_TOAST) {
                // Apps targeting SDK above N MR1 cannot arbitrary add toast windows.
                addToastWindowRequiresToken = doesAddToastWindowRequireToken(attrs.packageName,
                        callingUid, parentWindow);
                if (addToastWindowRequiresToken && token.windowType != TYPE_TOAST) {
                    Slog.w(TAG_WM, "Attempted to add a toast window with bad token "
                            + attrs.token + ".  Aborting.");
                    return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                }
            } else if (type == TYPE_QS_DIALOG) {
                if (token.windowType != TYPE_QS_DIALOG) {
                    Slog.w(TAG_WM, "Attempted to add QS dialog window with bad token "
                            + attrs.token + ".  Aborting.");
                    return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                }
            } else if (token.asAppWindowToken() != null) {
                Slog.w(TAG_WM, "Non-null appWindowToken for system window of rootType=" + rootType);
                // It is not valid to use an app token with other system types; we will
                // instead make a new token for it (as if null had been passed in for the token).
                attrs.token = null;
                token = new WindowToken(this, client.asBinder(), type, false, displayContent,
                        session.mCanAddInternalSystemWindow);//创建系统窗口类型的token
            }
	    //WMS为要加入的窗体创建了一个WindowState对象,这个对象维护了一个窗体的全部状态信息
            final WindowState win = new WindowState(this, session, client, token, parentWindow,
                    appOp[0], seq, attrs, viewVisibility, session.mUid,
                    session.mCanAddInternalSystemWindow);
            if (win.mDeathRecipient == null) {
                // Client has apparently died, so there is no reason to
                // continue.
                Slog.w(TAG_WM, "Adding window client " + client.asBinder()
                        + " that is dead, aborting.");
                return WindowManagerGlobal.ADD_APP_EXITING;
            }

            if (win.getDisplayContent() == null) {
                Slog.w(TAG_WM, "Adding window to Display that has been removed.");
                return WindowManagerGlobal.ADD_INVALID_DISPLAY;
            }

	    //WindowManagerPolicy(实现类PhoneWindowManager),这个函数的调用会调整LayoutParams的一些成员的取值
            mPolicy.adjustWindowParamsLw(win.mAttrs); 
            win.setShowToOwnerOnlyLocked(mPolicy.checkShowToOwnerOnly(attrs));

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

            final boolean openInputChannels = (outInputChannel != null
                    && (attrs.inputFeatures & INPUT_FEATURE_NO_INPUT_CHANNEL) == 0);
            if  (openInputChannels) {
                win.openInputChannel(outInputChannel);
            }
	    ......

            win.attach();
	    // 然后将WindowState对象加入到mWindowMap中
            mWindowMap.put(client.asBinder(), win);
            if (win.mAppOp != AppOpsManager.OP_NONE) {
                int startOpResult = mAppOps.startOpNoThrow(win.mAppOp, win.getOwningUid(),
                        win.getOwningPackage());
                if ((startOpResult != AppOpsManager.MODE_ALLOWED) &&
                        (startOpResult != AppOpsManager.MODE_DEFAULT)) {
                    win.setAppOpVisibilityLw(false);
                }
            }

            final AppWindowToken aToken = token.asAppWindowToken(); //应用窗口windowToken
            if (type == TYPE_APPLICATION_STARTING && aToken != null) {
                aToken.startingWindow = win;
                if (DEBUG_STARTING_WINDOW) Slog.v (TAG_WM, "addWindow: " + aToken
                        + " startingWindow=" + win);
            }

            boolean imMayMove = true;

            win.mToken.addWindow(win);
            if (type == TYPE_INPUT_METHOD) {
                win.mGivenInsetsPending = true;
                setInputMethodWindowLocked(win);
                imMayMove = false;
            } else if (type == TYPE_INPUT_METHOD_DIALOG) {
                displayContent.computeImeTarget(true /* updateImeTarget */);
                imMayMove = false;
            } else {
                if (type == TYPE_WALLPAPER) {
                    displayContent.mWallpaperController.clearLastWallpaperTimeoutTime();
                    displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
                } else if ((attrs.flags&FLAG_SHOW_WALLPAPER) != 0) {
                    displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
                } else if (displayContent.mWallpaperController.isBelowWallpaperTarget(win)) {
                    // 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;
                }
            }

            // If the window is being added to a stack that's currently adjusted for IME,
            // make sure to apply the same adjust to this new window.
            win.applyAdjustForImeIfNeeded();

            if (type == TYPE_DOCK_DIVIDER) {
                mRoot.getDisplayContent(displayId).getDockedDividerController().setWindow(win);
            }

            final WindowStateAnimator winAnimator = win.mWinAnimator;
            winAnimator.mEnterAnimationPending = true;
            winAnimator.mEnteringAnimation = true;
            // Check if we need to prepare a transition for replacing window first.
            if (atoken != null && atoken.isVisible()
                    && !prepareWindowReplacementTransition(atoken)) {
                // If not, check if need to set up a dummy transition during display freeze
                // so that the unfreeze wait for the apps to draw. This might be needed if
                // the app is relaunching.
                prepareNoneTransitionForRelaunching(atoken);
            }

            if (displayContent.isDefaultDisplay) {
                final DisplayInfo displayInfo = displayContent.getDisplayInfo();
                final Rect taskBounds;
                if (atoken != null && atoken.getTask() != null) {
                    taskBounds = mTmpRect;
                    atoken.getTask().getBounds(mTmpRect);
                } else {
                    taskBounds = null;
                }
                if (mPolicy.getInsetHintLw(win.mAttrs, taskBounds, displayInfo.rotation,
                        displayInfo.logicalWidth, displayInfo.logicalHeight, outContentInsets,
                        outStableInsets, outOutsets)) {
                    res |= WindowManagerGlobal.ADD_FLAG_ALWAYS_CONSUME_NAV_BAR;
                }
            } else {
                outContentInsets.setEmpty();
                outStableInsets.setEmpty();
            }

            if (mInTouchMode) {
                res |= WindowManagerGlobal.ADD_FLAG_IN_TOUCH_MODE;
            }
            if (win.mAppToken == null || !win.mAppToken.isClientHidden()) { //设置应用窗体可见
                res |= WindowManagerGlobal.ADD_FLAG_APP_VISIBLE;
            }

            mInputMonitor.setUpdateInputWindowsNeededLw(); //以下和输入法窗体有关

            boolean focusChanged = false;
            if (win.canReceiveKeys()) {
                focusChanged = updateFocusedWindowLocked(UPDATE_FOCUS_WILL_ASSIGN_LAYERS,
                        false /*updateInputWindows*/);
                if (focusChanged) {
                    imMayMove = false;
                }
            }

            if (imMayMove) {
                displayContent.computeImeTarget(true /* updateImeTarget */);
            }

            // Don't do layout here, the window must call
            // relayout to be displayed, so we'll do it there.
            displayContent.assignWindowLayers(false /* setLayoutNeeded */);

            if (focusChanged) {
                mInputMonitor.setInputFocusLw(mCurrentFocus, false /*updateInputWindows*/);
            }
            mInputMonitor.updateInputWindowsLw(false /*force*/);

            if (localLOGV || DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "addWindow: New client "
                    + client.asBinder() + ": window=" + win + " Callers=" + Debug.getCallers(5));

            if (win.isVisibleOrAdding() && updateOrientationFromAppTokensLocked(false, displayId)) {
                reportNewConfig = true;
            }
        }

        if (reportNewConfig) {
            sendNewConfiguration(displayId);
        }

        Binder.restoreCallingIdentity(origId);

        return res;
    }

总结:以上是添加应用窗口的简析,从代码中可以看到还是有点复杂的,这里只是简单介绍添加流程,希望有所帮助。






    原文作者:white_wt
    原文地址: https://blog.csdn.net/white_wt/article/details/79831773
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞