我们都知道在android中所有的界面显示相关的,都是通过WindowManager.addView方法来将当前需要显示的View添加到window中。

Window与WindowManager之间的关系

WindowManager的实现类就是WindowManagerImpl:

@Overridepublic void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {        // 每一个window都又一个唯一标识的token,这里如果没有,则设置系统默认的        applyDefaultToken(params);        // mGlobal是WindowManagerGlobal类型        mGlobal.addView(view, params, mDisplay, mParentWindow);}

然后通过,ViewRootImpl进一步实现当前需要显示的View的绘制,具体可以参考setContentView那些事
可以看到,在framework中Window和PhoneWindow构成了窗口的抽象部分,其中Window为抽象接口,PhoneWindow为具体实现,同样的WindowManager是实现部分的父类

WindowManagerImpl为具体实现逻辑,在WindowManagerImpl中使用WindowManagerGlobal通过IWindowManager接口与WindowManagerService进行交互,并由WMS完成具体的窗口管理工作

public final class WindowManagerGlobal {    private static IWindowManager sWindowManagerService;    public static IWindowManager getWindowManagerService() {        synchronized (WindowManagerGlobal.class) {            if (sWindowManagerService == null) {                sWindowManagerService = IWindowManager.Stub.asInterface(                        ServiceManager.getService("window"));                try {                    sWindowManagerService = getWindowManagerService();                    ValueAnimator.setDurationScale(sWindowManagerService.getCurrentAnimatorScale());                } catch (RemoteException e) {                    Log.e(TAG, "Failed to get WindowManagerService, cannot set animator scale", e);                }            }            return sWindowManagerService;        }    }}

Window与WindowManager建立连接

在Window中维护了一个mWindowManager属性,可以通过 方法设置一个mWindowManager,来和WindowManager建立连接

public abstract class Window {    private WindowManager mWindowManager;    public void setWindowManager(WindowManager wm, IBinder appToken, String appName) {        setWindowManager(wm, appToken, appName, false);    }    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) {            wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);        }        mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);    }    ....}

关于WindowManagerService

WindowManagerService(WMS),和其他系统服务一样也是在SystemServer中启动的。

public final class SystemServer {    private void startOtherServices() {       ....        // 通过WindowManagerService的静态main方法获取一个WindowManagerService实例        wm = WindowManagerService.main(context, inputManager,                    mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,                    !mFirstBoot, mOnlyCore);        // 将WMS添加到ServiceManager中        ServiceManager.addService(Context.WINDOW_SERVICE, wm);        ServiceManager.addService(Context.INPUT_SERVICE, inputManager);        mActivityManagerService.setWindowManager(wm);    }}

在startOtherServices中,获取WindowManagerService实例,然后添加到ServiceManager中,之后我们就可以通过ServiceManager#getService获取WMS了.

WindowManagerService.main方法

通过WindowManagerService.main方法获取WMS实例,其实就是在main方法内部通过异步方法new了一个WindowManagerService实例。

public static WindowManagerService main(final Context context,            final InputManagerService im,            final boolean haveInputMethods, final boolean showBootMsgs,            final boolean onlyCore) {        final WindowManagerService[] holder = new WindowManagerService[1];        DisplayThread.getHandler().runWithScissors(new Runnable() {            @Override            public void run() {                // 通过异步方法创建一个WindowManagerService实例                holder[0] = new WindowManagerService(context, im,                        haveInputMethods, showBootMsgs, onlyCore);            }        }, 0);        return holder[0];}

WindowManagerService构造方法

private WindowManagerService(Context context, InputManagerService inputManager,                                 boolean haveInputMethods, boolean showBootMsgs, boolean onlyCore) {        // 完成一些初始化工作        mContext = context;        mHaveInputMethods = haveInputMethods;        mAllowBootMessages = showBootMsgs;        mOnlyCore = onlyCore;        // 省略代码        // 获取显示服务        mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);        // 为每一个display分配一个content        mDisplays = mDisplayManager.getDisplays();        for (Display display : mDisplays) {            createDisplayContentLocked(display);        }        mKeyguardDisableHandler = new KeyguardDisableHandler(mContext, mPolicy);        // 获取PowerManager服务,并且注册LowPowerModeObserver        mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);        mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);        mPowerManagerInternal.registerLowPowerModeObserver(                new PowerManagerInternal.LowPowerModeListener() {                    @Override                    public void onLowPowerModeChanged(boolean enabled) {                        synchronized (mWindowMap) {                            if (mAnimationsDisabled != enabled && !mAllowAnimationsInLowPowerMode) {                                mAnimationsDisabled = enabled;                                dispatchNewAnimatorScaleLocked(null);                            }                        }                    }                });        // 省略代码        // 获取IActivityManager        mActivityManager = ActivityManagerNative.getDefault();        mBatteryStats = BatteryStatsService.getService();        mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);        AppOpsManager.OnOpChangedInternalListener opListener =                new AppOpsManager.OnOpChangedInternalListener() {                    @Override public void onOpChanged(int op, String packageName) {                        updateAppOpsState();                    }                };        .....        // 构建窗口动画        mAnimator = new WindowAnimator(this);        // 初始化窗口管理策略        initPolicy();        // 开启绘制SurfaceView事务        SurfaceControl.openTransaction();        ....}

深入理解WindowManagerService

WMS主要用来管理当前窗口和对事件的管理和分发,在IWindowManager.aidl文件中定义了大部分WMS的功能方法,另外作为窗口的管理者,WMS里也定义了各种不同的窗口

public class WindowManagerService extends IWindowManager.Stub        implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {    // 已经启动完成的应用    final ArrayList mFinishedStarting = new ArrayList<>();    // 尺寸正在改变的窗口    final ArrayList mResizingWindows = new ArrayList<>();    // 动画结束的窗口    final ArrayList mPendingRemove = new ArrayList<>();    // 即将释放Surface的窗口    final ArrayList mDestroySurface = new ArrayList<>();    // 失去焦点的窗口    ArrayList mLosingFocus = new ArrayList<>();    // 为了释放内存,需要强制关闭的窗口    final ArrayList mForceRemoves = new ArrayList<>();    // 等待绘制的窗口    ArrayList mWaitingForDrawn = new ArrayList<>();    // 正在打开的应用    final ArraySet mOpeningApps = new ArraySet<>();    // 正在关闭的应用    final ArraySet mClosingApps = new ArraySet<>();    // 当前获得焦点的窗口    WindowState mCurrentFocus = null;    // 上一个获得焦点的窗口    WindowState mLastFocus = null;    // 输入发窗口下方的窗口    WindowState mInputMethodTarget = null;    // 输入法窗口    WindowState mInputMethodWindow = null;    // 得到焦点的应用    AppWindowToken mFocusedApp = null;}

可以看到在WMS中维护的成员变量大都用到了线性表,不同窗口或者同一个窗口在不同阶段可能位于不同的线性表中,对于窗口,主要分为应用窗口和系统窗口

  • 应用窗口

应用窗口中,我们常见的activity所处的窗口,应用对话窗口,应用弹出窗口都属于该类,与应用窗口相关的主要是Window和PhoneWindow类
PhoneWindow继承自Window,应用窗口的添加主要通过WindowManager.addView方法将一个DecorView添加到WindowManager中,具体可以参考setContentView那些事

  • 系统窗口

我们平时常见的状态栏,导航栏等都是系统窗口,对于系统窗口,不像activity那样使用setContentView来设置布局,它没有专门的封装类,而是直接使用WindowManager.addView方法
将一个View添加到WindowManager中,下面看下PhoneStatusBar的显示过程。

PhoneStatusBar的显示

对于PhoneStatusBar,其主要的是在addStatusBarWindow中添加当前statusbar到WindowManager中的.

private void addStatusBarWindow() {    // 加载并创建StatusBarWindowView,StatusBarWindowView继承自FrameLayout    makeStatusBarView();    mStatusBarWindowManager = new StatusBarWindowManager(mContext);    // 将StatusBarWindowView添加到WindowManager中    mStatusBarWindowManager.add(mStatusBarWindow, getStatusBarHeight());}

加载并创建StatusBarWindowView

protected PhoneStatusBarView makeStatusBarView() {        final Context context = mContext;        Resources res = context.getResources();        updateDisplaySize(); // populates mDisplayMetrics        updateResources();        // 加载布局文件,并初始化mStatusBarWindow对象        mStatusBarWindow = (StatusBarWindowView) View.inflate(context,                R.layout.super_status_bar, null);        ....        return mStatusBarView;}

将StatusBarWindowView添加到WindowManager

在StatusBarWindowManager中将StatusBarWindowView添加到WindowManager中的:

public void add(View statusBarView, int barHeight) {        mLp = new WindowManager.LayoutParams(                ViewGroup.LayoutParams.MATCH_PARENT,                barHeight,                WindowManager.LayoutParams.TYPE_STATUS_BAR,                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE                        | WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING                        | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH                        | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH                        | WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,                PixelFormat.TRANSLUCENT);        mLp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;        mLp.gravity = Gravity.TOP;        mLp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;        mLp.setTitle("StatusBar");        mLp.packageName = mContext.getPackageName();        mStatusBarView = statusBarView;        mBarHeight = barHeight;        mWindowManager.addView(mStatusBarView, mLp);        mLpChanged = new WindowManager.LayoutParams();        mLpChanged.copyFrom(mLp);}

WindowManager.addView流程分析

上述代码通过WindowManager.addView将当前View显示到屏幕,那么当前View具体是怎么被显示到屏幕的,下面就是我们要讨论的:
我们知道WindowManager是一个接口,其具体的实现类是WindowManagerImpl

public interface WindowManager extends ViewManager

看下WindowManagerImpl#addView方法:

public final class WindowManagerImpl implements WindowManager {    private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();    @Override    public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {        android.util.SeempLog.record_vg_layout(383,params);        applyDefaultToken(params);        // mGlobal是WindowManagerGlobal类的实例        mGlobal.addView(view, params, mDisplay, mParentWindow);    }}

可以看到,上述最终实质上是通过WindowManagerGlobal#addView实现具体的逻辑

public void addView(View view, ViewGroup.LayoutParams params,            Display display, Window parentWindow) {        ....                try {            // root是ViewRootImpl的实例            root.setView(view, wparams, panelParentView);        } catch (RuntimeException e) {           ....        }}

继续分析ViewRootImpl#setView的逻辑实现:

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {        synchronized (this) {            if (mView == null) {                mView = view;                ....                int res; /* = WindowManagerImpl.ADD_OKAY; */                // 实现具体的绘制操作                requestLayout();                try {                    mOrigWindowType = mWindowAttributes.type;                    mAttachInfo.mRecomputeGlobalAttributes = true;                    collectViewAttributes();                    // 通过addToDisplay方法向WMS发起一个Session请求,这里最终会调用Session中对应的方法                    res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,                            getHostVisibility(), mDisplay.getDisplayId(),                            mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,                            mAttachInfo.mOutsets, mInputChannel);                } catch (RemoteException e) {                    ....                    throw new RuntimeException("Adding window failed", e);                } finally {                    if (restore) {                        attrs.restore();                    }                }            }        }}

上面的方法主要做了下面的操作:
1. requestLayout(); // 进行具体的绘制操作
2. 调用了Session.addToDisplay方法:

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

最终还是回到了WMS中与其建立连接,并且上述addToDisplay调用最终返回WMS中的addWindow的返回结果。

final WindowManagerPolicy mPolicy = new PhoneWindowManager();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];        // mPolicy实际上是一个PhoneWindowManager类型,在checkAddPermission方法中,首先判断窗口类型是否是系统级别的,        // 如果不是系统级别的窗口,则返回一个ADD_OKAY,否则需要SYSTEM_ALERT_WINDOW或者INTERNAL_SYSTEM_WINDOW权限        int res = mPolicy.checkAddPermission(attrs, appOp);        if (res != WindowManagerGlobal.ADD_OKAY) {            return res;        }        ....        synchronized(mWindowMap) {            ....            boolean addToken = false;            WindowToken token = mTokenMap.get(attrs.token);            if (token == null) {                // 如果窗口是子窗口                if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {                    return WindowManagerGlobal.ADD_BAD_APP_TOKEN;                }                // 如果是输入法窗口                if (type == TYPE_INPUT_METHOD) {                    return WindowManagerGlobal.ADD_BAD_APP_TOKEN;                }                // 如果是墙纸窗口                if (type == TYPE_WALLPAPER) {                    return WindowManagerGlobal.ADD_BAD_APP_TOKEN;                }                // 如果是DayDream窗口,即互动屏保                if (type == TYPE_DREAM) {                    return WindowManagerGlobal.ADD_BAD_APP_TOKEN;                }                // 构造WindowToken对象                token = new WindowToken(this, attrs.token, -1, false);                addToken = true;            } else if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {                // 获取应用的AppWindowToken                AppWindowToken atoken = token.appWindowToken;                if (atoken == null) {                    return WindowManagerGlobal.ADD_NOT_APP_TOKEN;                } else if (atoken.removed) {                    return WindowManagerGlobal.ADD_APP_EXITING;                }                if (type == TYPE_APPLICATION_STARTING && atoken.firstWindowDrawn) {                    // No need for this guy!                    if (localLOGV) Slog.v(                            TAG, "**** NO NEED TO START: " + attrs.getTitle());                    return WindowManagerGlobal.ADD_STARTING_NOT_NEEDED;                }            } else if (type == TYPE_INPUT_METHOD) {                if (token.windowType != TYPE_INPUT_METHOD) {                      // 如果是输入法窗口,token的windowType必须是ADD_BAD_APP_TOKEN类型                      return WindowManagerGlobal.ADD_BAD_APP_TOKEN;                }            }             ....           // 在窗口的有效性检查完成之后,为当前窗口创建一个WindowState对象,来维护窗口的状态以及根据适当的机制来调整窗口的状态           WindowState win = new WindowState(this, session, client, token,                    attachedWindow, appOp[0], seq, attrs, viewVisibility, displayContent);           // 如果客户端已经被销毁            if (win.mDeathRecipient == null) {                return WindowManagerGlobal.ADD_APP_EXITING;            }                                   if (outInputChannel != null && (attrs.inputFeatures                    & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {                // 如果输出Channel的读通道为空,则创建通道                String name = win.makeInputChannelName();                InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);                win.setInputChannel(inputChannels[0]);                inputChannels[1].transferTo(outInputChannel);                // 向InputManager中注册通道,以便当前窗口可以接收到事件                mInputManager.registerInputChannel(win.mInputChannel, win.mInputWindowHandle);            }           .....        }}

到现在为止,使用WindowManager.addView方法显示对应的View解析就完成了,重点总结一下:
1. WindowManager#addView—>WindowManagerGlobal#addView—>ViewRootImpl#setView
2. 在ViewRootImpl#setView中的requestLayout();实现具体的绘制操作
3. 在ViewRootImpl#setView中调用Session#addToDisplay
4. 在Session#addToDisplay中最终还是回到了WMS中与其建立连接,并且最终调用WMS的addWindow
5. 在WMS的addWindow方法中,主要做了下面几件事:

  • 检查当前窗口的权限,如果不是系统级别的窗口,则返回一个ADD_OKAY,否则需要SYSTEM_ALERT_WINDOW或者INTERNAL_SYSTEM_WINDOW权限

  • 根据当前窗口类型,返回对应的token值

  • 当前窗口创建一个WindowState对象,来维护窗口的状态以及根据适当的机制来调整窗口的状态,并且通过registerInputChannel,以便当前窗口可以接收输入事件

更多相关文章

  1. 36个Android开发常用经典代码大全
  2. Unity 调用 Android(安卓)Native 方法(一) 获得Android系统音量
  3. 「抄底 Android(安卓)内存优化 3」 —— JVM 内存管理
  4. Android中的Handler、Looper、Message简要分析
  5. Android(安卓)实现联网——在线程中联网
  6. Android(安卓)手动显示和隐藏软键盘 android 隐藏显示输入法键盘
  7. Android(安卓)Studio ADB响应失败解决方法
  8. 浅谈Java中Collections.sort对List排序的两种方法
  9. Python list sort方法的具体使用

随机推荐

  1. Android(安卓)RadioButton 图片位置和大
  2. Android(安卓)设置View背景图网络url
  3. Android(安卓)AudioTrack实时播放
  4. eclipse 新建 android 项目时,问题汇总
  5. Android(安卓)同时监听多个Button事件
  6. 第一章:初入Android大门(通过Button设置T
  7. Android(安卓)SD卡,文件,文件夹工具
  8. Android(安卓)log简化
  9. android开发框架汇总
  10. Android(安卓)SharedPreferences的使用