Window, WindowManager, WindowManagerService 的简单梳理(二)- Window 的添加过程
Window, WindowManager, WindowManagerService 的简单梳理(三)- Activiy 的 Window 的创建过程
看完任玉刚的《Android 开发艺术探索》中关于Window 和 WindowManager 的章节,想大致上把 Window, WindowManager, WindowManagerService 的关系梳理一下。
这本书上讲的算是比较明白了,如果能够硬着头皮、逐字逐句、结合源码看下来,应该是可以看明白的。
不过看完以后,总少了一点通透的感觉,可能是因为这本书里对 WindowManagerService 本身的功能讲的不多。并且,几个概念绕来绕去,很容易互相混淆。
基本概念
-
Window : 在讲 WindowManagerService 的时候,这里的 Window 都不是指 android.view.Window 类,也不是它的子类 PhoneWindow。甚至于说,WindowManager 名字中的“Window”的含义,与 WindowManagerService 名字中的“Window”的含义是否相同?我不确定。非要下定义的话,可能林学森的《深入理解 Android 内核设计思想》一书中 WMS 部分的解释更接近真相一点。
“Window” 表明它是与窗口相关的,“Manager”指出它具有管理者的身份。。。“窗口”是一个抽象的概念,从用户的角度来讲,它是一个“界面”,如拨号面板;从 SurfaceFlinger 的角度来看,它是一个 Layer,承载着和“界面”有关的数据和属性;从 WMS 的角度来看,它是一个 WindowState,用于管理和“界面”有关的状态。
所以,这里的 Window 通常不是指具体的某个类,更多的是指一个抽象概念。
-
WindowManager :这个是有具体类和接口的。WindowManager 是一个接口,继承自 ViewManager 接口,具体实现是 WindowManagerImpl。WindowManager 并没有给 ViewManager 扩展多少方法,更多的意义可能是定义了一些静态接口和静态类,如 WindowManager.LayoutParams。所以我们有必要知道 ViewManager 的主要方法。
// ViewManager public interface ViewManager { /** * Assign the passed LayoutParams to the passed View and add the view to the window. * <p>Throws {@link android.view.WindowManager.BadTokenException} for certain programming * errors, such as adding a second view to a window without removing the first view. * <p>Throws {@link android.view.WindowManager.InvalidDisplayException} if the window is on a * secondary {@link Display} and the specified display can't be found * (see {@link android.app.Presentation}). * @param view The view to be added to this window. * @param params The LayoutParams to assign to view. */ public void addView(View view, ViewGroup.LayoutParams params); public void updateViewLayout(View view, ViewGroup.LayoutParams params); public void removeView(View view); }
以及 WindowManager.LayoutParams 的声明。
// WindowManager public static class LayoutParams extends ViewGroup.LayoutParams implements Parcelable { ... public int type; ... public int flags; ... }
-
WindowManagerService : 真正的 WindowManagerService 也是有对应的 WindowManagerService 类(/frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java)的;继承自 IWindowManager.Stub,当然,这是一个 aidl (/frameworks/base/core/java/android/view/IWindowManager.aidl),有一个实现 IWindowManagerImpl.java (/frameworks/base/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java),但是没发现这个实现对我们的分析有什么作用。
WindowManagerService 由 SystemServer 启动,代码如下。// SystemServe /** * Starts a miscellaneous grab bag of stuff that has yet to be refactored * and organized. */ private void startOtherServices() { ... WindowManagerService wm = null; ... //注意,这是 WindowManagerService wm = WindowManagerService.main(context, inputManager, mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL, !mFirstBoot, mOnlyCore); ServiceManager.addService(Context.WINDOW_SERVICE, wm); ... // Update the configuration for this context by hand, because we're going // to start using it before the config change done in wm.systemReady() will // propagate to it. Configuration config = wm.computeNewConfiguration(); DisplayMetrics metrics = new DisplayMetrics(); //注意,这是 WindowManager WindowManager w = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE); w.getDefaultDisplay().getMetrics(metrics); context.getResources().updateConfiguration(config, metrics); ... }
特意把 WindowManager 的部分也截出来,就是想说明 WindowManager 和 WindowManagerService 是不同的两个类和接口,职责也完全不一样。
WindowManagerService 是非常重要的一个系统服务,在SystemServer 中启动和注册,功能也复杂的多;WindowManager 则相对简单了很多。也可以看出,我们 通过getSystemService 得到的是 WindowManager,并不是 WindowManagerService。
WindowManagerService 实现的是 IWindowManager,一个 aidl 接口。WindowManager 本身就是一个接口,继承自 ViewManager。IWindowManager 接口本身也是巨复杂,跟 WindowManager 没有一毛钱关系。
在 Activity 中获取 WindowManager
我看的代码是 API 25。Activity 中提供了2种方法获取 WindowManager。
// Activity
/** Retrieve the window manager for showing custom windows. */
public WindowManager getWindowManager() {
return mWindowManager;
}
@Override
public Object getSystemService(@ServiceName @NonNull String name) {
if (getBaseContext() == null) {
throw new IllegalStateException(
"System services not available to Activities before onCreate()");
}
if (WINDOW_SERVICE.equals(name)) {
return mWindowManager;
} else if (SEARCH_SERVICE.equals(name)) {
ensureSearchManager();
return mSearchManager;
}
return super.getSystemService(name);
}
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) {
...
mWindow = new PhoneWindow(this, window);
mWindow.setWindowControllerCallback(this);
mWindow.setCallback(this);
...
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();
...
}
可见,Activity 的 WindowManager 是来自 mWindow。我们都知道,Activity 的 mWindow 其实就是 PhoneWindow;并且上面的代码中有 mWindow.setWindowManager() 的调用,那就看看 setWindowManager 是怎么实现的吧。
// android.view.Window
/**
* Set the window manager for use by this Window to, for example,
* display panels. This is <em>not</em> used for displaying the
* Window itself -- that must be done by the client.
*
* @param wm The window manager for adding new windows.
*/
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);
}
可见,setWindowManager 中,Window 并没有直接把入参的 WindowManager wm 作为自己的 mWindowManager ,而是重新创建了一个 WindowManagerImpl 对象。
那么如果直接用 mContext.getSystemService(Context.WINDOW_SERVICE),得到的又是什么呢?
从上面代码中的类型强转,已经可以看出来,是 WindowManager,不是 WindowManagerService。不过,我们还是看看代码吧。
// ContextImpl
@Override
public Object getSystemService(String name) {
return SystemServiceRegistry.getSystemService(this, name);
}
// SystemServiceRegistry
public static Object getSystemService(ContextImpl ctx, String name) {
ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);
return fetcher != null ? fetcher.getService(ctx) : null;
}
private static <T> void registerService(String serviceName, Class<T> serviceClass,
ServiceFetcher<T> serviceFetcher) {
SYSTEM_SERVICE_NAMES.put(serviceClass, serviceName);
SYSTEM_SERVICE_FETCHERS.put(serviceName, serviceFetcher);
}
static {
...
registerService(Context.WINDOW_SERVICE, WindowManager.class,
new CachedServiceFetcher<WindowManager>() {
@Override
public WindowManager createService(ContextImpl ctx) {
return new WindowManagerImpl(ctx);
}});
...
}
总之,我们能够从 Activity 或者 Context 拿到的,就是 WindowManager 的具体实现 WindowManagerImpl,不是 WindowManagerService。
因为这几个方法的名字,让我对 WindowManager 和 WindowManagerService 的关系纠结了很久。但是,他们俩真的就没有什么关系,只是名字很像而已。
以上内容参考了《Android 开发艺术探索》,也参考了《深入理解 Android 内核设计思想》,也参考了 Android 源码,如果有理解不对的地方,那一定是我学艺不精,与两位作者无关。