WindowManagerService(WMS)服务是重要的Android系统服务,它负责管理Android窗口系统。包含的功能有窗口的增加和删除,窗口的大小和位置,窗口动画等。WMS需要和应用程序进行双向通信才能实现相关的功能。那么本节就先讨论一下,应用进程和WMS双向通信建立的代码实现过程。后续我们再讨论窗口的添加和删除源码逻辑。
1. 总览图
2. 应用到WMS的通信建立
首先来看应用程序到WMS的通信建立过程 在Activity中有个变量mWindow,它是Window类型。Window类型是抽象类。它提供了标准的UI策略,如背景,标题,区域,默认键处理等。它的实例类被用做顶层View添加到window manager中。在attach方法中创建对应的实例PhoneWindow。 创建完成Window实例对象后调用了mWindow.setWindowManager方法。这个方法的实现在Window类中。而在mWindow.setWindowManager方法中有创建了WindowManager的实例对象WindowManagerImpl,这个WindowManagerImpl提供和系统 window manager的底层通信能力。 如下代码:
@UiContext
public class Activity extends ContextThemeWrapper
implements LayoutInflater.Factory2,
Window.Callback, KeyEvent.Callback,
OnCreateContextMenuListener, ComponentCallbacks2,
Window.OnWindowDismissedCallback,
ContentCaptureManager.ContentCaptureClient {
...
private Window mWindow;
//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, IBinder assistToken,
IBinder shareableActivityToken) {
attachBaseContext(context);
mFragments.attachHost(null /*parent*/);
//创建 Winodw类的实例
mWindow = new PhoneWindow(this, window, activityConfigCallback);
mWindow.setWindowControllerCallback(mWindowControllerCallback);
mWindow.setCallback(this);
mWindow.setOnWindowDismissedCallback(this);
mWindow.getLayoutInflater().setPrivateFactory(this);
...
//设置WindowManager
mWindow.setWindowManager(
(WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
mToken, mComponent.flattenToString(),
(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
...
}
...
}
//Window类的setWindowManager方法实现
public void setWindowManager(WindowManager wm, IBinder appToken, String appName,boolean hardwareAccelerated) {
mAppToken = appToken;
mAppName = appName;
mHardwareAccelerated = hardwareAccelerated;
if (wm == null) {
wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
}
//通过WindowManagerImpl创建WindowManager实例对象
mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
}
//WindowManagerImpl类的createLocalWindowManager方法
//直接创建WindowManagerImpl对象并返回
public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
return new WindowManagerImpl(mContext, parentWindow, mWindowContextToken);
}
再看看WindowManagerImpl类,其中定义了变量mGlobal,类型为WindowManagerGlobal。通过WindowManagerGlobal.getInstance()创建实例。通过这种调用方式我们知道,这个类是个单例,全局应用进程中只有一个实例。 WindowManagerGlobal也是提供与系统window manager的底层通信能力。但它和任何特定的context无关,而WindowManager是绑定了context的。
public final class WindowManagerImpl implements WindowManager {
//创建单例对象WindowManagerGlobal
@UnsupportedAppUsage
private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
...
}
//WindowManagerGlobal类定义
public final class WindowManagerGlobal {
...
//mViews 保存应用中的所有顶层View(DecorView)
@UnsupportedAppUsage
private final ArrayList<View> mViews = new ArrayList<View>();
//mRoots保存顶层View关联的ViewRootImpl对象
@UnsupportedAppUsage
private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>();
//mParams保存创建顶层View的layout数据
@UnsupportedAppUsage
private final ArrayList<WindowManager.LayoutParams> mParams =
new ArrayList<WindowManager.LayoutParams>();
...
//WindowManagerGlobal类的getInstance方法
//创建全局唯一的WindowManagerGlobal实例对象
@UnsupportedAppUsage
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, int userId) {
...
// 创建ViewRootImpl对象
if (windowlessSession == null) {
root = new ViewRootImpl(view.getContext(), display);
} else {
root = new ViewRootImpl(view.getContext(), display,
windowlessSession, new WindowlessWindowLayout());
}
view.setLayoutParams(wparams);
mViews.add(view);
//添加创建的ViewRootImpl对象到列表中
mRoots.add(root);
mParams.add(wparams);
// do this last because it fires off messages to start doing things
try {
//将要添加的View设置到创建的ViewRootImpl中。
root.setView(view, wparams, panelParentView, userId);
} catch (RuntimeException e) {
final int viewIndex = (index >= 0) ? index : (mViews.size() - 1);
// BadTokenException or InvalidDisplayException, clean up.
if (viewIndex >= 0) {
removeViewLocked(viewIndex, true);
}
throw e;
}
}
....
}
当应用程序需要向屏幕上添加一个新的View时,WindowManagerGlobal的addView方法会被调用。在这个方法中,创建了ViewRootImpl对象,并将其添加到mRoots列表中,同时将ViewRootImpl与要添加的View绑定在一起。 ViewRootImpl的构造函数中可以看到,调用了WindowManagerGlobal.getWindowSession()来获取需要的IWindowSession对象。
//ViewRootImpl的构造函数
public ViewRootImpl(Context context, Display display) {
this(context, display, WindowManagerGlobal.getWindowSession(), new WindowLayout());
}
回到WindowManagerGlobal类,看看getWindowSession方法。 其通过获取IWindowManager类的实例windowManager,并调用其openSession方法获取IWindowSession对象,并赋值给sWindowSession变量然后返回sWindowSession。所以ViewRootImpl得到的IWindowSession对象就是WindowManagerGlobal.getWindowSession方法返回的。sWindowSession是静态变量,所以它也是全局进程唯一的。 getWindowManagerService方法获取的是系统的WindowManagerService服务在应用进程的代理对象。了解Binder机制对这种方法调用就很熟悉。也就是说windowManager.openSession调用的实际是WindowManagerService服务的openSession方法。
// WindowManagerGlobal.getWindowSession方法
@UnsupportedAppUsage
public static IWindowSession getWindowSession() {
synchronized (WindowManagerGlobal.class) {
if (sWindowSession == null) {
try {
// Emulate the legacy behavior. The global instance of InputMethodManager
// was instantiated here.
// TODO(b/116157766): Remove this hack after cleaning up @UnsupportedAppUsage
InputMethodManager.ensureDefaultInstanceForDefaultDisplayIfNecessary();
//获取系统服务WindowManagerService的代理对象
IWindowManager windowManager = getWindowManagerService();
//代理对象调用openSession方法,通过Binder进程通信,获取服务端的openSession方法调用,这属于远程Binder调用
sWindowSession = windowManager.openSession(
new IWindowSessionCallback.Stub() {
@Override
public void onAnimatorScaleChanged(float scale) {
ValueAnimator.setDurationScale(scale);
}
});
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
return sWindowSession;
}
}
进入WindowManagerService类可以看到openSession的方法实现。直接new了一个Session对象返回。从Session类的定义可以看到,Session继承了IWindowSession.Stub,表明,这是个Binder服务对象。windowManager.openSession返回给应用进程的对象就是这个服务对象的代理对象。应用就可以通过代理对象来调用服务提供的方法,实现用户进程到WMS服务的通信过程。
// -------------------------------------------------------------
// IWindowManager API
// -------------------------------------------------------------
@Override
public IWindowSession openSession(IWindowSessionCallback callback) {
return new Session(this, callback);
}
//Session类的定义
class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
...
}
这里应用到WMS服务的通信就建立完成,后续应用就可以通过WindowManagerGlobal类中的sWindowSession变量来实现对WMS的方法调用。实际上这个变量也被同时绑定在ViewRootImpl对像的mWindowSession变量中。
总结一下各变量引用关系:
时序图:
3. WMS到应用的通信建立
回到上节WindowManagerGlobal中的addView代码中,我们可以看到创建完成ViewRootImpl后调用了ViewRootImpl的setView方法。该方法较长,看看部分代码:
/**
* We have one child
*/
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView,
int userId) {
...
Rect attachedFrame = new Rect();
final float[] compatScale = { 1f };
res = mWindowSession.addToDisplayAsUser(mWindow, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(), userId,
mInsetsController.getRequestedVisibilities(), inputChannel, mTempInsets, mTempControls, attachedFrame, compatScale);
...
}
mWindowSession即上节中分析的与WMS通信的Binder通信类。addToDisplayAsUser中传入了mWindow变量。mWindow变量是W类的实例变量。从W类的定义我们可以看到W类是静态内部类,它继承了IWindow.Stub,说明它是一个用于Binder通信的类。W类的创建在ViewRootImpl构造函数中,mWindow变量指向W对象。
public ViewRootImpl(@UiContext Context context, Display display, IWindowSession session,
WindowLayout windowLayout) {
...
//创建W对象
mWindow = new W(this);
...
}
在mWindowSession.addToDisplayAsUser中将mWindow作为第一个参数传入。在上节代码中我们知道mWindowSession是Session对象在用户进程中的代理。mWindowSession.addToDisplayAsUser即最终调用的是WMS中Session对象的addToDisplayAsUser方法。
//Sessionl类的addToDisplayAsUser方法
@Override
public int addToDisplayAsUser(IWindow window, WindowManager.LayoutParams attrs, int viewVisibility, int displayId, int userId, InsetsVisibilities requestedVisibilities, InputChannel outInputChannel, InsetsState outInsetsState, InsetsSourceControl[] outActiveControls, Rect outAttachedFrame, float[] outSizeCompatScale) {
return mService.addWindow(this, window, attrs, viewVisibility, displayId, userId, requestedVisibilities, outInputChannel, outInsetsState, outActiveControls, outAttachedFrame, outSizeCompatScale);
}
Session对象的addToDisplayAsUser方法又直接调用mService.addWindow方法,并把window参数变量出入其中。mService即是WindowManagerService服务对象。
//WindowManagerService类addWindow方法
public int addWindow(Session session, IWindow client, LayoutParams attrs, int viewVisibility, int displayId, int requestUserId, InsetsVisibilities requestedVisibilities, InputChannel outInputChannel, InsetsState outInsetsState, InsetsSourceControl[] outActiveControls, Rect outAttachedFrame, float[] outSizeCompatScale) {
...
final WindowState win = new WindowState(this, session, client, token, parentWindow, appOp[0], attrs, viewVisibility, session.mUid, userId, session.mCanAddInternalSystemWindow);
...
win.attach();
mWindowMap.put(client.asBinder(), win);
...
}
WMS的addWindow方法将参数client变量传入到WindowState构造方法中。WindowState代表一个窗口,它的构造函数中将client赋给mClient变量,供WindowState使用。 从以上过程可以看出,即将W对象通过之前建立的从用户进程到WMS的通信通道mWindowSession,传入到WMS中。这样WMS就可以通过W的代理对象与用户进程通信。 W继承至IWindow.Stub,如果我们了解Binder机制的话应该知道IWindow.Stub继承android.os.Binder类,而android.os.Binder实现了IBinder接口。而进程通信用到的Parcel除了可以传递基础类型外,还可以传递IBinder对象。所以W类可以通过上述方式被传到WMS中。进程通信Binder机制相关知识有机会再介绍。
总结流程图
通过以上步骤,应用进程和WMS服务端就建立了双向通信的能力。
源码路径:
Activity.java: frameworks/base/core/java/android/app/Activity.java Window.java:frameworks/base/core/java/android/view/Window.java WindowManagerImpl.java: frameworks/base/core/java/android/view/WindowManagerImpl.java WindowManagerGlobal.java:frameworks/base/core/java/android/view/WindowManagerGlobal.java ViewRootImpl.java:frameworks/base/core/java/android/view/ViewRootImpl.java WindowManagerService.java: frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java WindowState.java:frameworks/base/services/core/java/com/android/server/wm/WindowState.java Session.java:frameworks/base/services/core/java/com/android/server/wm/Session.java