我们都知道在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. Unity 调用 Android Native 方法(一) 获得Android系统音量
  2. Android 4.2 BT系统之蓝牙关闭过程全跟踪
  3. Mac 下面,添加android adb命令(一般环境变量的添加方法)
  4. Android软键盘挡住输入框的问题及解决方法
  5. Android 系统服务的两种注册方式

随机推荐

  1. Android(安卓)-- TypedArray
  2. Android控件开发之一----TextView
  3. Android(安卓)不支持 SYSV IPC (SYSV IPC)
  4. Android短信欺诈(Smishing)漏洞
  5. Android(安卓)开发在Eclipse提示信息 Thi
  6. Android+Eclipse环境
  7. Android(安卓)Volley.jar包下载
  8. 我对IT的一点了解
  9. generateDefaultLayoutParams()
  10. Android多进程加载资源失败问题分析:andr