一、WindowManagerService 窗口管理员
窗口的概念,直观的看,是一个界面,比如桌面、打开的一张照片。
从SurfaceFlinger的角度看,它是一个layer,当向surfaceflinger申请一个surface时,实际是创建了一个layer,承载着跟窗口有关的数据。
从WindowManagerService的角度看,它是windowState,管理着窗口有关的状态。
WindowManagerService除了管理着系统中所有的窗口外,还有一个重要功能就是负责事件的分发。因为它管理着系统的所有窗口,所以当有一个事件到来时,WMS最有可能知道哪个窗口适合处理这个事件。
1. WindowManagerService的启动。
WMS是由systemServer启动的系统服务的一种。
SystemServer.java
/**
* Starts a miscellaneous grab bag of stuff that has yet to be refactored and organized.
*/
private void startOtherServices() {
final Context context = mSystemContext;
...
WindowManagerService wm = null;
//先实例化一个InputManagerService对象,作为WindowManagerService 的参数,InputManagerService负责事件的接收分发。
inputManager = new InputManagerService(context);
...
wm = WindowManagerService.main(context, inputManager, !mFirstBoot, mOnlyCore,
(WindowManagerPolicy)OpPhoneWindowManagerInjector.getInstance(), mActivityManagerService.mActivityTaskManager);
//注册到ServiceManager中。
ServiceManager.addService(Context.WINDOW_SERVICE, wm, /* allowIsolated= */ false,
DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PROTO);
ServiceManager.addService(Context.INPUT_SERVICE, inputManager,
/* allowIsolated= */ false, DUMP_FLAG_PRIORITY_CRITICAL);
...
}
WindowManagerService是在一个单独的线程中运行的,而且是以同步(runWithScissors)的方式启动的这个线程,所以在WindowManagerService启动完成之后,SystemServer才能继续往下走。
WindowManagerService.java
public static WindowManagerService main(final Context context, final InputManagerService im,
final boolean showBootMsgs, final boolean onlyCore, WindowManagerPolicy policy,
ActivityTaskManagerService atm) {
return main(context, im, showBootMsgs, onlyCore, policy, atm,
SurfaceControl.Transaction::new);
}
/**
* Creates and returns an instance of the WindowManagerService. This call allows the caller
* to override the {@link TransactionFactory} to stub functionality under test.
*/
@VisibleForTesting
public static WindowManagerService main(final Context context, final InputManagerService im,
final boolean showBootMsgs, final boolean onlyCore, WindowManagerPolicy policy,
ActivityTaskManagerService atm, TransactionFactory transactionFactory) {
DisplayThread.getHandler().runWithScissors(() ->
sInstance = new WindowManagerService(context, im, showBootMsgs, onlyCore, policy,
atm, transactionFactory), 0);
return sInstance;
}
// -------------------------------------------------------------
// Async Handler
// -------------------------------------------------------------
final class H extends android.os.Handler {
...
}
WMS所在的线程就是DisplayThread这个显示线程,这个线程不仅被WMS使用,DisplayManagerService、InputManagerService也会使用。当实例化WindowManagerService时,它的成员变量mH就与DisplayThread产生了关联,后期可以通过mH这个handler投递事件到DisplayThread的looper队列中。mH是WMS的内部类H。
2. 应用程序、WMS、AMS之间的关系
应用程序的启动,通常是Activity的启动,因为Activity是主要用于UI显示的组件,所以必然跟WMS产生关联。
1)Activity到AMS,未完待续。
2)应用程序到WMS,参见android P View 框架1---概述
3)前面提到接口多数是基于AIDL实现的BinderServer,用于应用进程跟系统进程间跨进程交互。
WMS和AMS都在SystemServer进程,是可以直接进行函数调用的,比如在SystemServer.java中:
SystemServer.java
private void startOtherServices() {
...
mActivityManagerService.setWindowManager(wm);
...
}
AMS通过setWindowManager把WMS的句柄wm设置给了AMS中的成员mWindowManager。
ActivityManagerService.java
public void setWindowManager(WindowManagerService wm) {
synchronized (this) {
mWindowManager = wm;
mActivityTaskManager.setWindowManager(wm);
...
}
}
WMS中有一个AppWindowToken对应了AMS中的ActivityRecord,
/**
* Version of WindowToken that is specifically for a particular application (or
* really activity) that is displaying windows.
*/
class AppWindowToken extends WindowToken implements WindowManagerService.AppFreezeListener,
ConfigurationContainerListener {
...
// Non-null only for application tokens.
final IApplicationToken appToken;
...
// TODO: Remove after unification
ActivityRecord mActivityRecord;
}
/**
* An entry in the history stack, representing an activity.
*/
public final class ActivityRecord extends ConfigurationContainer {
...
final IApplicationToken.Stub appToken; // window manager token
// TODO: Remove after unification
AppWindowToken mAppWindowToken;
...
}
这个AppWindowToken是在startActivity的过程中添加的,具体过程如下:
ActivityStack.java
void startActivityLocked(ActivityRecord r, ActivityRecord focusedTopActivity,
boolean newTask, boolean keepCurTransition, ActivityOptions options) {
TaskRecord rTask = r.getTaskRecord();
final int taskId = rTask.taskId;
// mLaunchTaskBehind tasks get placed at the back of the task stack.
if (!r.mLaunchTaskBehind && (taskForIdLocked(taskId) == null || newTask)) {
// Last activity in task had been removed or ActivityManagerService is reusing task.
// Insert or replace.
// Might not even be in.
insertTaskAtTop(rTask, r);
}
TaskRecord task = null;
if (!newTask) {
// If starting in an existing task, find where that is...
boolean startIt = true;
for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
task = mTaskHistory.get(taskNdx);
if (task.getTopActivity() == null) {
// All activities in task are finishing.
continue;
}
if (task == rTask) {
// Here it is! Now, if this is not yet visible to the
// user, then just add it without starting; it will
// get started when the user navigates back to it.
if (!startIt) {
if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Adding activity " + r + " to task "
+ task, new RuntimeException("here").fillInStackTrace());
//创建AppWindowToken对象
r.createAppWindowToken();
ActivityOptions.abort(options);
return;
}
break;
} else if (task.numFullscreen > 0) {
startIt = false;
}
}
}
...
}
ActivityRecord.java
void createAppWindowToken() {
...
// TODO: remove after unification
mAppWindowToken = mAtmService.mWindowManager.mRoot.getAppWindowToken(appToken.asBinder());
if (mAppWindowToken != null) {
// TODO: Should this throw an exception instead?
Slog.w(TAG, "Attempted to add existing app token: " + appToken);
} else {
//获取或创建相应的Task
final Task container = task.getTask();
if (container == null) {
throw new IllegalArgumentException("createAppWindowToken: invalid task =" + task);
}
mAppWindowToken = createAppWindow(mAtmService.mWindowManager, appToken,
task.voiceSession != null, container.getDisplayContent(),
ActivityTaskManagerService.getInputDispatchingTimeoutLocked(this)
* 1000000L, fullscreen,
(info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0, appInfo.targetSdkVersion,
info.screenOrientation, mRotationAnimationHint,
mLaunchTaskBehind, isAlwaysFocusable());
...
//将该Token添加到对应的Task中。
container.addChild(mAppWindowToken, Integer.MAX_VALUE /* add on top */);
}
task.addActivityToTop(this);
...
}
Task.java
class Task extends WindowContainer<AppWindowToken> implements ConfigurationContainerListener{
...
@Override
void addChild(AppWindowToken wtoken, int position) {
position = getAdjustedAddPosition(position);
super.addChild(wtoken, position);
mDeferRemoval = false;
}
...
}
WindowContainer.java
/**
* Defines common functionality for classes that can hold windows directly or through their
* children in a hierarchy form.
* The test class is {@link WindowContainerTests} which must be kept up-to-date and ran anytime
* changes are made to this class.
*/
class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<E>
implements Comparable<WindowContainer>, Animatable {
...
// List of children for this window container. List is in z-order as the children appear on
// screen with the top-most window container at the tail of the list.
protected final WindowList<E> mChildren = new WindowList<E>();
...
/**
* Adds the input window container has a child of this container in order based on the input
* comparator.
* @param child The window container to add as a child of this window container.
* @param comparator Comparator to use in determining the position the child should be added to.
* If null, the child will be added to the top.
*/
@CallSuper
protected void addChild(E child, Comparator<E> comparator) {
...
int positionToAdd = -1;
if (comparator != null) {
final int count = mChildren.size();
for (int i = 0; i < count; i++) {
if (comparator.compare(child, mChildren.get(i)) < 0) {
positionToAdd = i;
break;
}
}
}
if (positionToAdd == -1) {
mChildren.add(child);
} else {
mChildren.add(positionToAdd, child);
}
onChildAdded(child);
// Set the parent after we've actually added a child in case a subclass depends on this.
child.setParent(this);
}
}
RootWindowContainer.java
/** Root {@link WindowContainer} for the device. */
class RootWindowContainer extends WindowContainer<DisplayContent>
implements ConfigurationContainerListener {
...
/**
* Returns the app window token for the input binder if it exist in the system.
* NOTE: Only one AppWindowToken is allowed to exist in the system for a binder token, since
* AppWindowToken represents an activity which can only exist on one display.
*/
AppWindowToken getAppWindowToken(IBinder binder) {
for (int i = mChildren.size() - 1; i >= 0; --i) {
final DisplayContent dc = mChildren.get(i);
final AppWindowToken atoken = dc.getAppWindowToken(binder);
if (atoken != null) {
return atoken;
}
}
return null;
}
/** Returns the window token for the input binder if it exist in the system. */
WindowToken getWindowToken(IBinder binder) {
for (int i = mChildren.size() - 1; i >= 0; --i) {
final DisplayContent dc = mChildren.get(i);
final WindowToken wtoken = dc.getWindowToken(binder);
if (wtoken != null) {
return wtoken;
}
}
return null;
}
...
}
WindowManagerService.java
// The root of the device window hierarchy.
RootWindowContainer mRoot;
/**
* Hint to a token that its activity will relaunch, which will trigger removal and addition of
* a window.
* @param token Application token for which the activity will be relaunched.
*/
public void setWillReplaceWindow(IBinder token, boolean animate) {
synchronized (mGlobalLock) {
final AppWindowToken appWindowToken = mRoot.getAppWindowToken(token);
...
appWindowToken.setWillReplaceWindows(animate);
}
}
4)在把一个窗口通过addView注册到WMS后,wms会请surfaceflinger申请一个surface承载UI数据,使窗口内容可以显示到屏幕上。窗口的拥有者通过WindowManagerImpl.java,进一步通过WindowManagerGlobal.java管理名下所有的窗口,具体就是mViews,mRoots,mParams三个列表。
来源:CSDN
作者:小人物梦想大世界
链接:https://blog.csdn.net/qq2234385378/article/details/102482493