代码基于Android 9.0
1、wms的启动
SystemServer的main函数,启动了SystemServer线程,同时启动了各种服务,其中的startOtherServices启动了对应的AMS,IMS,WMS等系统服务。
SystemServer.java
traceBeginAndSlog("StartInputManagerService");
//新建IMS
inputManager = new InputManagerService(context);
traceEnd();
traceBeginAndSlog("StartWindowManagerService");
// WMS needs sensor service ready
ConcurrentUtils.waitForFutureNoInterrupt(mSensorServiceStart, START_SENSOR_SERVICE);
mSensorServiceStart = null;
//初始化WMS,绑定IMS
wm = WindowManagerService.main(context, inputManager,
mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,
!mFirstBoot, mOnlyCore, new PhoneWindowManager());
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);
traceEnd();
traceBeginAndSlog("SetWindowManagerService");
//关联AMS和WMS
mActivityManagerService.setWindowManager(wm);
traceEnd();
traceBeginAndSlog("WindowManagerServiceOnInitReady");
//初始化WMP
wm.onInitReady();
traceEnd();
WMS的main函数和InitPolicy函数都执行了handler的runWithScissors,该方法会执行新开的线程,然后阻塞当前线程,直到新开线程执行完毕。WMS单例的创建是在DisplayThread进行,WindowManagerPolicy(具体实现是PhoneWindowManager)的初始化是在UiThread进行。
WindowManagerService.java
public static WindowManagerService main(final Context context, final InputManagerService im,
final boolean haveInputMethods, final boolean showBootMsgs, final boolean onlyCore,
WindowManagerPolicy policy) {
//运行在DisplayThread
DisplayThread.getHandler().runWithScissors(() ->
sInstance = new WindowManagerService(context, im, haveInputMethods, showBootMsgs,
onlyCore, policy), 0);
return sInstance;
}
private void initPolicy() {
//运行在UiThread
UiThread.getHandler().runWithScissors(new Runnable() {
@Override
public void run() {
WindowManagerPolicyThread.set(Thread.currentThread(), Looper.myLooper());
mPolicy.init(mContext, WindowManagerService.this, WindowManagerService.this);
}
}, 0);
}
2、AMS和WMS关联
Activity启动的时候,ActivityStarter.StartActivity会创建一个ActivityRecord。
ActivityStarter.java
private int startActivity(IApplicationThread caller, Intent intent, Intent ephemeralIntent,
String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid,
String callingPackage, int realCallingPid, int realCallingUid, int startFlags,
SafeActivityOptions options,
boolean ignoreTargetSecurity, boolean componentSpecified, ActivityRecord[] outActivity,
TaskRecord inTask, boolean allowPendingRemoteAnimationRegistryLookup) {
...
ActivityRecord r = new ActivityRecord(mService, callerApp, callingPid, callingUid,
callingPackage, intent, resolvedType, aInfo, mService.getGlobalConfiguration(),
resultRecord, resultWho, requestCode, componentSpecified, voiceSession != null,
mSupervisor, checkedOptions, sourceRecord);
...
}
ActivityRecord创建的时候会创建一个appToken(IApplicationToken),通过该token创建AppWindowContainerController,创建时传入AppWindowContainerListener回调,WMS的单例,初始化mRoot。把ActivityRecord传过来的appToken转化成AppWindowToken,AppWindowToken继承WindowToken,会调用onDisplayChanged(dc),通过DisplayContent最终会调用WMS的addWindowToken方法。通过win.attach()保存Seesion和创建SurfaceSession。
Session.java
public SurfaceSession() {
mNativeClient = nativeCreate();
}
//这里创建的是SurfaceComposerClient,
static jlong nativeCreate(JNIEnv* env, jclass clazz) {
SurfaceComposerClient* client = new SurfaceComposerClient();
client->incStrong((void*)nativeCreate);
return reinterpret_cast<jlong>(client);
}
DisplayContent的tokenMap保存了ActivityRecord的token,key为token,value为WindowToken 。
AppWindowToken持有WMS,所以可以直接调用WMS的方法。
总结:ActivityRecord通过AppWindowContainerController持有的WMS直接执行方法(AppWindowContainerController和AppWindowToken都继承WindowContainer,持有WMS),实现AMS和WMS通讯。
ActivityRecord.java
public AppWindowContainerController(TaskWindowContainerController taskController,
IApplicationToken token, AppWindowContainerListener listener, int index,
int requestedOrientation, boolean fullscreen, boolean showForAllUsers, int configChanges,
boolean voiceInteraction, boolean launchTaskBehind, boolean alwaysFocusable,
int targetSdkVersion, int rotationAnimationHint, long inputDispatchingTimeoutNanos,
WindowManagerService service) {
//初始化mRoot
super(listener, service);
mHandler = new H(service.mH.getLooper());
mToken = token;
synchronized(mWindowMap) {
AppWindowToken atoken = mRoot.getAppWindowToken(mToken.asBinder());
if (atoken != null) {
// TODO: Should this throw an exception instead?
Slog.w(TAG_WM, "Attempted to add existing app token: " + mToken);
return;
}
final Task task = taskController.mContainer;
if (task == null) {
throw new IllegalArgumentException("AppWindowContainerController: invalid "
+ " controller=" + taskController);
}
//把IApplicationToken转化成AppWindowToken
atoken = createAppWindow(mService, token, voiceInteraction, task.getDisplayContent(),
inputDispatchingTimeoutNanos, fullscreen, showForAllUsers, targetSdkVersion,
requestedOrientation, rotationAnimationHint, configChanges, launchTaskBehind,
alwaysFocusable, this);
if (DEBUG_TOKEN_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "addAppToken: " + atoken
+ " controller=" + taskController + " at " + index);
//添加token到task里面,task也是WindwContainer
task.addChild(atoken, index);
}
}
3、Activity与WMS关联
启动Activity的时候,ActivityThread执行到performLaunchActivity时,创建activity对象,调用Activity.attach方法,这里创建了一个PhoneWindow和关联了WindowManager。
ActivityThread.java
/** Core implementation of activity launch. */
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
...
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config,
r.referrer, r.voiceInteractor, window, r.configCallback);
...
}
handleResumeActivity时把PhoneWindow里面的DecorView设置成不可见,最后调用Activity的makevisible。
ActivityThread.java
@Override
public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,
String reason) {
...
if (r.window == null && !a.mFinished && willBeVisible) {
r.window = r.activity.getWindow();
View decor = r.window.getDecorView();
//设置DecorView不可见
decor.setVisibility(View.INVISIBLE);
ViewManager wm = a.getWindowManager();
WindowManager.LayoutParams l = r.window.getAttributes();
a.mDecor = decor;
l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
l.softInputMode |= forwardBit;
if (r.mPreserveWindow) {
a.mWindowAdded = true;
r.mPreserveWindow = false;
// Normally the ViewRoot sets up callbacks with the Activity
// in addView->ViewRootImpl#setView. If we are instead reusing
// the decor view we have to notify the view root that the
// callbacks may have changed.
ViewRootImpl impl = decor.getViewRootImpl();
if (impl != null) {
impl.notifyChildRebuilt();
}
}
if (a.mVisibleFromClient) {
if (!a.mWindowAdded) {
a.mWindowAdded = true;
//把decorview添加到wm,具体实现是在WindowManagerImpl里
wm.addView(decor, l);
} else {
// The activity will get a callback for this {@link LayoutParams} change
// earlier. However, at that time the decor will not be set (this is set
// in this method), so no action will be taken. This call ensures the
// callback occurs with the decor set.
a.onWindowAttributesChanged(l);
}
}
...
if (r.activity.mVisibleFromClient) {
//activity设置成可见的
r.activity.makeVisible();
}
...
}
WindowManager(WindowManagerImpl)添加DecorView,实际是调用了WindowManagerGolbal的addView。
WindowManagerGlobal.java
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow) {
...
ViewRootImpl root;
View panelParentView = null;
...
root = new ViewRootImpl(view.getContext(), display);
view.setLayoutParams(wparams);
//所有的view对象
mViews.add(view);
//viewrootimpl
mRoots.add(root);
//对应view的参数
mParams.add(wparams);
// do this last because it fires off messages to start doing things
try {
//viewRootImpl关联DecorView
root.setView(view, wparams, panelParentView);
} catch (RuntimeException e) {
// BadTokenException or InvalidDisplayException, clean up.
if (index >= 0) {
removeViewLocked(index, true);
}
throw e;
}
}
}
这里创建了ViewRootImpl,其初始化创建Session,mWindow,attachInfo等,然后通过ViewRootImpl的setView把DecorView添加上去,setView会调用addToDisplay,传递了Session和Window(IWindow),InputChanel。
ViewRootImpl.java
public ViewRootImpl(Context context, Display display) {
mContext = context;
//进程单例
mWindowSession = WindowManagerGlobal.getWindowSession();
mDisplay = display;
...
//IWindow的binder对象,属于ViewRootImpl
mWindow = new W(this);
...
//AttachInfo比较重要的
mAttachInfo = new View.AttachInfo(mWindowSession, mWindow, display, this, mHandler, this,
context);
...
}
/**
* We have one child
*/
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
....
try {
mOrigWindowType = mWindowAttributes.type;
mAttachInfo.mRecomputeGlobalAttributes = true;
collectViewAttributes();
//此处最终调用了WindowManagerService的addWindow方法
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(), mWinFrame,
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel);
} catch (RemoteException e) {
mAdded = false;
mView = null;
mAttachInfo.mRootView = null;
mInputChannel = null;
mFallbackEventHandler.setView(null);
unscheduleTraversals();
setAccessibilityFocus(null, null);
throw new RuntimeException("Adding window failed", e);
} finally {
if (restore) {
attrs.restore();
}
}
...
}
这里最后是调用了WindowManagerService的addWindow(通过Session的IPC),同时传递了Session和mWindow。这里的Session由于是WindowManagerGolbal单例来的,所以对应的是app的,mWindow对应的是ViewRootImpl的。这里还创建了相应的token。
WindowManagerService.java
public int addWindow(Session session, IWindow client, int seq,
LayoutParams attrs, int viewVisibility, int displayId, Rect outFrame,
Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel) {
...
//省略部分通过各种逻辑创建对应的token
//创建对应的WindowState
final WindowState win = new WindowState(this, session, client, token, parentWindow,
appOp[0], seq, attrs, viewVisibility, session.mUid,
session.mCanAddInternalSystemWindow);
...
//这里调用了mSession.put(session)
win.attach();
mWindowMap.put(client.asBinder(), win);
....
}
WMS里面的windowMap保存的是key为mWindow,value为生成的WindowState,也就是间接的ViewRootImpl。WMS同时也保存了Session在数组里。
app和WMS的关系图
想到几个问题,后续再研究解决
1、status bar,wallpaper,dialog,popupwindow,Navigation等窗口的显示流程逻辑。
2、Activity切换动画过程。
3、输入事件和window的交互,位置大小变化。
4、多任务上滑的是否为多窗口。
5、窗口的移除。
网友评论