前言

首先看一个Android界面的布局层次结构,最直观的看一下:

我们能清晰看到,这个界面分成了3部分:顶部状态栏(statusbar)、底部导航栏(navigationbar)、应用界面。

题外话:

查看布局的层次结构,工具或途径可以参考下面的。

Android Studio:Tools->Layout Inspector->选择要查看的进程;

SDK Tools:tools/hierarchyviewer.bat。 不过最新推荐用tools/monitor.bat代替单独的hierarchyviewer.bat;hierarchyviewer.bat在工程目录下也存在prebuilts/devtools/tools

该篇主要介绍Activity中窗口的创建过程 以及 添加到WMS的过程。

第二部分 综述总结,先将上述两个过程的内容做了比较简洁的总结。

第三部分 Activity窗口添加过程,跟踪源码详细 讲述了 Activity窗口的创建过程 以及 添加到WMS过程。

由于第三部分 跟踪源码,这个过程比较长,涉及比较多,相对枯燥。所以把总结先放到了第二部分。这样,如果了解过源码或这个过程的,可以只看第二部分。没了解过的,也可以通过第二部分有个大概了解,再查看第三部分,若遇到不太清楚的部分,可以再回到第二部分,对比理解。

该篇也是基于Android10的源码。

若有不对或不足,欢迎指点。

综述总结

前言已经介绍了为什么将总结放在了前面。下面具体看下。

第二部分,主要介绍了下面几个内容:

  • Window类型:窗口类型介绍
  • 几个重要类:窗口创建添加到WMS过程中常见的一些类,了解下他们之间的关系
  • Activity创建窗口添加到WMS综述:简单总结了下 Activity的创建过程 和 添加到WMS过程
  • Activity中的一些结构示意图:整个过程,Activity中关联的一些类/结构的 关系,理解这个个人觉得很有必要
  • Token传递到WMS:Token是很重要的参数,参与整个过程。这里将该篇涉及的过程中的 Token的传递过程单独总结了下

Window类型

//WindowManager.java
public static class LayoutParams extends ViewGroup.LayoutParams implements Parcelable {
public static final int FIRST_APPLICATION_WINDOW = 1;
public static final int LAST_APPLICATION_WINDOW = 99; public static final int FIRST_SUB_WINDOW = 1000;
public static final int LAST_SUB_WINDOW = 1999; public static final int FIRST_SYSTEM_WINDOW = 2000;
public static final int LAST_SYSTEM_WINDOW = 2999;
//状态栏
public static final int TYPE_STATUS_BAR = FIRST_SYSTEM_WINDOW;
//搜索栏
public static final int TYPE_SEARCH_BAR = FIRST_SYSTEM_WINDOW+1;
//来电显示
public static final int TYPE_PHONE = FIRST_SYSTEM_WINDOW+2;
//警告窗口,常见如:低电量警告
public static final int TYPE_SYSTEM_ALERT = FIRST_SYSTEM_WINDOW+3;
//锁屏
public static final int TYPE_KEYGUARD = FIRST_SYSTEM_WINDOW+4;
//toast
public static final int TYPE_TOAST = FIRST_SYSTEM_WINDOW+5;
public static final int TYPE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW+6;//显示在所有窗口之上,覆盖
//来电优先,即使锁屏状态下
public static final int TYPE_PRIORITY_PHONE = FIRST_SYSTEM_WINDOW+7;
//输入法窗口
public static final int TYPE_INPUT_METHOD = FIRST_SYSTEM_WINDOW+11;
//壁纸
public static final int TYPE_WALLPAPER = FIRST_SYSTEM_WINDOW+13;
}

应用窗口(1 ~ 99): FIRST_APPLICATION_WINDOW ~ LAST_APPLICATION_WINDOW。对应一个Activity,token需设置成Activity的token。 如:Activity。

子窗口(1000 ~ 1999): FIRST_SUB_WINDOW ~ LAST_SUB_WINDOW。必须要有一个父窗口,token需设置成父窗口的token。 如:PopupWindow,依附于Activity。

系统窗口(2000 ~ 2999): FIRST_SYSTEM_WINDOW ~ LAST_SYSTEM_WINDOW。系统级的 不需要对应Activity 也不需要有父窗口,应用进程一般没有权限创建,只有系统进程可以创建。如:上面列出了部分常见的系统窗口,状态栏、来电、toast、输入法等等。

几个重要类

下面几个类是后续经常看到的,这里主要看下他们直接的继承关系,后面看到比较容易理解。

public abstract class Window {}
public class PhoneWindow extends Window implements MenuBuilder.Callback {} public interface WindowManagerPolicy extends WindowManagerPolicyConstants {}
public class PhoneWindowManager implements WindowManagerPolicy {} public interface ViewManager {
public void addView(View view, ViewGroup.LayoutParams params);
public void updateViewLayout(View view, ViewGroup.LayoutParams params);
public void removeView(View view);
}
public interface WindowManager extends ViewManager {}
public final class WindowManagerImpl implements WindowManager {} /** A window in the window manager. */
class WindowState extends WindowContainer<WindowState> implements WindowManagerPolicy.WindowState {}
  1. Window是一个抽象类,Activity、Toast、Dialog等都是靠Window来呈现。

    PhoneWindow是Window的具体实现类(几乎是唯一实现类)。
  2. WindowManager是个接口,继承接口 ViewManager(ViewManager定义了3个操作:增加、更新、移除)。

    WindowManagerImpl是WindowManager的实现类。

    不过查看WindowManagerImpl中 关于ViewManager的3个操作可以看出,这3个实现 最终是交由WindowManagerGlobal完成的。
  3. WindowState维护着窗口的所有信息。WMS通过WindowState对窗口进行管理、保存状态等。

Activity创建窗口添加到WMS综述

这是跟踪的代码过程,这里汇总下 方便后续查看理解。 红色是比较主要的几个节点方法。

//attach()
-performLaunchActivity()
--activity.attach()//创建了PhoneWindow(mWindow)。mWindowManager保存的是 从mWindow处获取的 setWindowManager()创建的WindowManagerImpl
---mWindow.setWindowManager()//PhoneWindow内部 创建了WindowManagerImpl(mWindowManager),并保存了appToken、appName。 //onCreate()
-setContentView()
--installDecor()
---generateDecor()//创建了DecorView(mDecor)
---generateLayout()//将activity的布局作为子视图(ViewGroup)添加到mDecor中 //onResume()
-r.activity.makeVisible()//
--wm.addView(mDecor, ...)//wm即mWindowManager(WindowManagerImpl对象)
---WindowManagerGlobal.addView()//创建了ViewRootImpl。addView的view是mDecor,ViewRootImpl中创建了mWindow(这里是一个IBinder,而非attach()中创建的)
----ViewRootImpl.setView()//openSession()创建了Session(IWindowSession的代理类),view也是mDecor。mDecor传入到ViewRootImpl的mView
-----Session.addToDisplay()//通过Session进入system_server进程
------mService.addWindow()//进入WMS,执行addWindow()添加窗口

attach阶段:

一个Activity 创建了一个PhoneWindow对象 ,PhoneWindow通过setWindowManager() 创建了WindowManagerImpl

即Activity 对应一个PhoneWindow,并得到了一个WindowManager(WindowManagerImpl,Window创建的)。

onCreate阶段:

创建了DecorView ,并将 activity的布局添加到DecorView中

onResume阶段:

创建了ViewRootImpl,通过setView()最终由Session进入system_server进程。最终执行addWindow添加窗口到WMS。

Activity中的一些结构示意图

下面是我学习总结中 根据理解画的,方便自己查看时一眼可得。

(若有什么不对,多谢指点)

public final class WindowManagerImpl implements WindowManager {
private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
} public final class WindowManagerGlobal {
private static IWindowManager sWindowManagerService;//WMS客户端,
private static IWindowSession sWindowSession;//Session
private final ArrayList<View> mViews = new ArrayList<View>();
private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>();
private final ArrayList<WindowManager.LayoutParams> mParams = new ArrayList<WindowManager.LayoutParams>();
}
  1. 一个Activity对应了一个PhoneWindow对象。即 每个Activity对应一个Window (具体实现类是PhoneWindow)。
  2. 一个PhoneWindow 持有一个 DecorView 实例, DecorView实际是一个FrameLayout,它是Activity中所有View的根(最顶层的View)。
  3. 一个PhoneWindow有一个WindowManagerImpl。WindowManagerImpl持有一个单例WindowManagerGlobal。

Token传递到WMS

Activity启动时 AMS会为其创建一个ActivityRecord。可以参考:AMS之应用的第一次启动过程

下面先看下ActivityRecord中关于token的几处代码:

final class ActivityRecord extends ConfigurationContainer {
final IApplicationToken.Stub appToken; // window manager token
// TODO: Remove after unification
AppWindowToken mAppWindowToken; ActivityRecord(ActivityTaskManagerService _service, WindowProcessController _caller,...) {
appToken = new Token(this, _intent);
} void createAppWindowToken() {
mAppWindowToken = createAppWindow(mAtmService.mWindowManager, appToken,...);
} static class Token extends IApplicationToken.Stub {
Token(ActivityRecord activity, Intent intent) {
weakActivity = new WeakReference<>(activity);
name = intent.getComponent().flattenToShortString();
}
}
}

ActivityRecord中的成员变量 appToken ,这个很重要,后续很多地方会一直涉及到。

ActivityRecord中有个 appToken ,其是一个IBinder(内部类Token继承了IApplicationToken接口)。Token内部持有Activity的弱引用。

在ActivityRecord中会通过createAppWindow()创建并保存 AppWindowToken对象 到mAppWindowToken。

mAppWindowToken:这个appToken会被封装在其中。路径:ActivityStack.startActivityLocked()->ActivityRecord.createAppWindowToken()。AppWindowToken是WindowToken子类。WindowToken可以标志一个窗口。

这个appToken,会在Activity.attach()中作为参数传递到Activity。

Activity保存到mToken。

然后通过 Activity.attach()->mWindow.setWindowManager() 传入到Window(PhoneWindow)中。

Window保存到mAppToken。

WindowManagerGlobal.addView()->Window.adjustLayoutParamsForSubWindow()保存到WindowManager.LayoutParams中的token变量中。

最后WindowManager.LayoutParams(其中token即ActivityRecord中的appToken)作为参数传入ViewRootImpl.setView()。

ViewRootImpl中mWindowAttributes拷贝了WindowManager.LayoutParams,作为参数通过Session.addToDisplay()传入WMS中,进行后续操作。

这是整个添加窗口(到addWindow())过程 appToken参与的过程及传递过程。

appToken如何参与窗口的添加,这个在 “第三部分的2.8:mService.addWindow()” 注释中能大致看到,比较详细。


Activity窗口添加过程

这里主要介绍 Activity对应Window的创建 以及 Window添加到WMS的过程。

Activity窗口创建

AMS之应用的第一次启动过程 中,从点击应用图标到activity创建并执行onCreate()。 下面部分是后面部分的截取,不清楚可以参考下那篇文章。

1.1:handleLaunchActivity()

这里从handleLaunchActivity()开始。

//ActivityThread.java
@Override
public Activity handleLaunchActivity(ActivityClientRecord r,
PendingTransactionActions pendingActions, Intent customIntent) {
...
WindowManagerGlobal.initialize();
final Activity a = performLaunchActivity(r, customIntent);
...
} private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
...
try {
java.lang.ClassLoader cl = appContext.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
}
try {
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
if (activity != null) {
Window window = null;
...
//attach(),注意这个r.token。参考1.2
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,
r.assistToken);
if (r.isPersistable()) {
//callActivityOnCreate() 最终执行到的activity的onCreate()方法。
//参考1.4
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
} else {
mInstrumentation.callActivityOnCreate(activity, r.state);
}
}
}
...
return activity;
}

WindowManagerGlobal.initialize();是获取WMS的IBinder代理类,用于与WMS通信。这里不列出代码了。

接着要看的是activity.attach()。注意作为参数传入attach()的 r.token 是个IBinder,来自ActivityClientRecord,简单看标识了一个Activity。

1.2:activity.attach()

//Activity.java
final void attach(Context context, ActivityThread aThread,
Instrumentation instr, IBinder token, ...) {
...
//创建PhoneWindow
mWindow = new PhoneWindow(this, window, activityConfigCallback);//创建PhoneWindow
//设置软键盘
if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
mWindow.setSoftInputMode(info.softInputMode);
}
//token保存到mToken。
mToken = token;
...
//mToken传入到Window,参考1.3
mWindow.setWindowManager(
(WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
mToken, mComponent.flattenToString(),
(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
//mWindowManager即setWindowManager()中创建的WindowManagerImpl。
mWindowManager = mWindow.getWindowManager();
...
}

首先创建了Activityd对应的Window,是PhoneWindow-Window的实现类。 接着看mWindow.setWindowManager()

1.3:mWindow.setWindowManager()

//Window.java
public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
boolean hardwareAccelerated) {
//ActivityClientRecord.token
mAppToken = appToken;
mAppName = appName;
mHardwareAccelerated = hardwareAccelerated;
if (wm == null) {
wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
}
//创建了WindowManagerImpl,注意WindowManagerImpl中mParentWindow是this,非空
mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
}

这里创建了WindowManagerImpl对象,即WindowManager的实现类。并保存了appToken、appName、mWindowManager。

通过setWindowManager(),即为Window(或者PhoneWindow)设置创建了WindowManager(WindowManagerImpl)。

1.4:setContentView()

mInstrumentation.callActivityOnCreate()最终有调用到Activity的onCreate()。

自定义Activity,设置布局都执行了setContentView(),下面直接来看下这个方法。

//Activity.java
public void setContentView(@LayoutRes int layoutResID) {
getWindow().setContentView(layoutResID);//
initWindowDecorActionBar();
} public Window getWindow() {
return mWindow;//即PhoneWindow对象
} //PhoneWindow.java
// This is the top-level view of the window, containing the window decor.
private DecorView mDecor;
@Override
public void setContentView(int layoutResID) {
// Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window
// decor, when theme attributes and the like are crystalized. Do not check the feature
// before this happens.
if (mContentParent == null) {
installDecor();//
} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
mContentParent.removeAllViews();
}
if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
getContext());
transitionTo(newScene);
} else {
mLayoutInflater.inflate(layoutResID, mContentParent);
}
...
} private void installDecor() {
mForceDecorInstall = false;
if (mDecor == null) {
//生成DecorView,参考1.5
mDecor = generateDecor(-1);
...
} else {
mDecor.setWindow(this);
}
if (mContentParent == null) {
//布局添加到DecorView,参考1.5
mContentParent = generateLayout(mDecor); // Set up decor part of UI to ignore fitsSystemWindows if appropriate.
mDecor.makeOptionalFitsSystemWindows(); final DecorContentParent decorContentParent = (DecorContentParent) mDecor.findViewById(
R.id.decor_content_parent);
if (decorContentParent != null) {
} else {
mTitleView = findViewById(R.id.title);
}
...
}
}

这里主要关注下两个方法:mDecor = generateDecor(-1);mContentParent = generateLayout(mDecor);

先看下他们的相关代码:

1.5:generateDecor()和generateLayout()

protected DecorView generateDecor(int featureId) {
// System process doesn't have application context and in that case we need to directly use
// the context we have. Otherwise we want the application context, so we don't cling to the
// activity.
Context context;
...
return new DecorView(context, featureId, this, getAttributes());//
} public class DecorView extends FrameLayout implements RootViewSurfaceTaker, WindowCallbacks {
} protected ViewGroup generateLayout(DecorView decor) {
...
mDecor.startChanging();
mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);
ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
...
mDecor.finishChanging();
return contentParent;
} //DecorView.java
void onResourcesLoaded(LayoutInflater inflater, int layoutResource) {
...
mDecorCaptionView = createDecorCaptionView(inflater);
final View root = inflater.inflate(layoutResource, null);
if (mDecorCaptionView != null) {
if (mDecorCaptionView.getParent() == null) {
addView(mDecorCaptionView,
new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
}
mDecorCaptionView.addView(root,
new ViewGroup.MarginLayoutParams(MATCH_PARENT, MATCH_PARENT));
} else { // Put it below the color views.
addView(root, 0, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
}
mContentRoot = (ViewGroup) root;
initializeElevation();
}

通过generateDecor()创建了一个DecorView。DecorView实际是一个FrameLayout。

然后通过generateLayout(),最终将activity的布局作为子视图(ViewGroup)添加到DecorView中。

上面可以看到,activity生成到执行onCreate(),这个过程,activity生成了关联的PhoneWindow,然后创建了WindowManagerImpl、DecorView。

下面看下Window添加到WMS的过程,看这些创建的对象之前如何联系 形成的一开始介绍的结构示意图。

Window添加到WMS过程

AMS之应用的第一次启动过程 中主要讲到onCreate,其实onResume也在其中在,这里不详细解释了,再次列出相关代码:

//ActivityStackSupervisor.java:
boolean realStartActivityLocked(ActivityRecord r, WindowProcessController proc,
boolean andResume, boolean checkConfig) throws RemoteException {
...
try {
...
try {
// Create activity launch transaction.
final ClientTransaction clientTransaction = ClientTransaction.obtain(
proc.getThread(), r.appToken); final DisplayContent dc = r.getDisplay().mDisplayContent;
clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent),
...
// Set desired final state.
final ActivityLifecycleItem lifecycleItem;
if (andResume) {
lifecycleItem = ResumeActivityItem.obtain(dc.isNextTransitionForward());
} else {
lifecycleItem = PauseActivityItem.obtain();
}
clientTransaction.setLifecycleStateRequest(lifecycleItem); // Schedule transaction.
mService.getLifecycleManager().scheduleTransaction(clientTransaction);
...
}
}
...
return true;
}

通过 LaunchActivityItem 关联 最终执行结果是创建了应用的Activity 并 执行了attach()和onCreate()。 andResume为true(传入的参数为true,可以参考那篇这段代码往前看), 通过 ResumeActivityItem 关联 最终执行到的是 ActivityThread.handleResumeActivity()。

这里从ActivityThread.handleResumeActivity()来看。

2.1:ActivityThread.handleResumeActivity()

//ActivityThread.java
@Override
public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,
String reason) {
...
// TODO Push resumeArgs into the activity for consideration
//执行onStart()->onResume()。参考2.2
final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason);
final Activity a = r.activity;
if (r.window == null && !a.mFinished && willBeVisible) {
r.window = r.activity.getWindow();
View decor = r.window.getDecorView();
decor.setVisibility(View.INVISIBLE);
ViewManager wm = a.getWindowManager();
WindowManager.LayoutParams l = r.window.getAttributes();
a.mDecor = decor;
l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
...
}
...
// The window is now visible if it has been added, we are not
// simply finishing, and we are not starting another activity.
if (!r.activity.mFinished && willBeVisible && r.activity.mDecor != null && !r.hideForNow) {
...
r.activity.mVisibleFromServer = true;
mNumVisibleActivities++;
if (r.activity.mVisibleFromClient) {
//参考2.3
r.activity.makeVisible();
}
}
...
}

注意 View decor = r.window.getDecorView(); 获取了DecorView对象,最后通过 a.mDecor = decor; 将DecorView赋到了Activity中。

这里关注两个:

performResumeActivity()

r.activity.makeVisible();

2.2:performResumeActivity()

//ActivityThread.java
@VisibleForTesting
public ActivityClientRecord performResumeActivity(IBinder token, boolean finalStateRequest,
String reason) {
final ActivityClientRecord r = mActivities.get(token);
...
try {
r.activity.onStateNotSaved();
r.activity.mFragments.noteStateNotSaved();
...
r.activity.performResume(r.startsNotResumed, reason); r.state = null;
r.persistentState = null;
r.setState(ON_RESUME); reportTopResumedActivityChanged(r, r.isTopResumedActivity, "topWhenResuming");
}
return r;
} //Activity.java
final void performResume(boolean followedByPause, String reason) {
performRestart(true /* start */, reason);
mInstrumentation.callActivityOnResume(this);
} final void performRestart(boolean start, String reason) {
mInstrumentation.callActivityOnRestart(this);
} //Instrumentation.java
public void callActivityOnRestart(Activity activity) {
activity.onRestart();
} public void callActivityOnResume(Activity activity) {
activity.mResumed = true;
activity.onResume();
...
}

performResumeActivity()中 r.activity.performResume()回调Activity的performResume()方法。最终执行了Activity的onResume()方法。

performResume()在执行onResume前,调用了performRestart(),最终调用的是activity的onStart()。这里可以看出 onStart()执行在onResume()之前。

2.3:r.activity.makeVisible()

//Activity.java
void makeVisible() {
if (!mWindowAdded) {
ViewManager wm = getWindowManager();
wm.addView(mDecor, getWindow().getAttributes());
mWindowAdded = true;
}
mDecor.setVisibility(View.VISIBLE);
} //WindowManagerImpl.java
public final class WindowManagerImpl implements WindowManager {
@UnsupportedAppUsage
private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
//mParentWindow即创建WindowManagerImpl是 传入的。参考2.4
mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
}
}

这里的getWindowManager()获取到的是前面讲到的 attach()时通过setWindowManager()创建的WindowManagerImpl对象。

前面也讲过,addView()等3个操作定义实现 最终在WindowManagerGlobal中,这里就可以看到。

2.4:WindowManagerGlobal.addView()

//WindowManagerGlobal
@UnsupportedAppUsage
private final ArrayList<View> mViews = new ArrayList<View>();
@UnsupportedAppUsage
private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>();
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow) {
...
final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
if (parentWindow != null) {
//调整Window参数,这个过程将token设置其中了
//参考2.4.1
parentWindow.adjustLayoutParamsForSubWindow(wparams);
}
...
ViewRootImpl root;
View panelParentView = null;
synchronized (mLock) {
...
root = new ViewRootImpl(view.getContext(), display);
view.setLayoutParams(wparams);
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
try {
//将view及相关参数设置到ViewRootImpl中。ViewRootImpl会向WMS添加新窗口、申请Surface及绘制工作等。
//参考2.6
root.setView(view, wparams, panelParentView);
}
...
}
} //ViewRootImpl.java
@UnsupportedAppUsage
final IWindowSession mWindowSession;
public ViewRootImpl(Context context, Display display) {
mContext = context;
//创建了Session(),参考2.5
mWindowSession = WindowManagerGlobal.getWindowSession();
mDisplay = display;
mBasePackageName = context.getBasePackageName();
mThread = Thread.currentThread();
mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion;
//这里的mWindow不是前面Activity中的PhoneWindow,它是W extends IWindow.Stub
mWindow = new W(this);
mViewVisibility = View.GONE;
//创建AttachInfo
mAttachInfo = new View.AttachInfo(mWindowSession, mWindow, display, this, mHandler, this,
context);
...
} static class W extends IWindow.Stub {...} //ViewRootImpl.java
public final class ViewRootImpl implements ViewParent, //View.java
final static class AttachInfo {
AttachInfo(IWindowSession session, IWindow window, Display display,
ViewRootImpl viewRootImpl, Handler handler, Callbacks effectPlayer,
Context context) {
mSession = session;
mWindow = window;
mWindowToken = window.asBinder();
mDisplay = display;
mViewRootImpl = viewRootImpl;
mHandler = handler;
mRootCallbacks = effectPlayer;
mTreeObserver = new ViewTreeObserver(context);
}
}

这里主要看到,创建了ViewRootImpl对象。这个类实现了View与WindowManager之间必要的协议。

注意创建中的mWindow = new W(this);,这个W继承IWindow.Stub。

创建ViewRootImpl对象时 创建了一个mAttachInfo = View.AttachInfo(), AttachInfo是一系列绑定信息。mWindowSession、mWindow作为参数传入。AttachInfo创建时注意mWindowToken = window.asBinder();

mWindowSession在后续2.5/2.6/2.7中讲到,它是Session对象,它是IWindowSession的代理类,通过他可以与WMS通信的binder接口

mWindow这里是W对象,它是IWindow.Stub,通过new创建,后续能看到会传入WMS,它是WMS回调应用(与应用通信)的binder接口

mWindowToken,也就是W的IBinder对象,也是WMS与应用通信的接口

创建ViewRootImpl对象后,WindowManagerGlobal将View、ViewRootImpl、LayoutParams保存到相应的ArrayList中。前面也讲到过,WindowManagerGlobal是单例的,应用进程中只有一个。最后通过root.setView()将View(这里是DecorView)传入到ViewRootImpl中。

2.4.1:adjustLayoutParamsForSubWindow()

前面看到mAppToken是从Activity的传入的。

这里mAppToken被设置到WindowManager.LayoutParams里,后面可以看到最终传入到WMS参与处理。

//Window.java
void adjustLayoutParamsForSubWindow(WindowManager.LayoutParams wp) {
CharSequence curTitle = wp.getTitle();
//子窗口,该篇中是应用窗口,所以不走这,也了解下。
if (wp.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
wp.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
if (wp.token == null) {
View decor = peekDecorView();
if (decor != null) {
wp.token = decor.getWindowToken();
}
}
...
//系统窗口,也不走这
} else if (wp.type >= WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW &&
wp.type <= WindowManager.LayoutParams.LAST_SYSTEM_WINDOW) {
...
//应用窗口,该篇走这
} else {
if (wp.token == null) {
//设置到了WindowManager.LayoutParams中
wp.token = mContainer == null ? mAppToken : mContainer.mAppToken;
}
...
}
...
}

2.4.2:AttachInfo在其中了解下

ViewRootImpl与各个View。通过下面的过程,AttachInfo绑定信息被设置到各个View中了,即各个View能够获取到各种相关信息。

2.6执行到ViewRootImpl.setView()后,参考过程:setView()->requestLayout()->scheduleTraversals()->mTraversalRunnable->doTraversal()->performTraversals()->host.dispatchAttachedToWindow(mAttachInfo, 0)->View.dispatchAttachedToWindow()->ViewGroup.dispatchAttachedToWindow()。

属同个ViewGroup的 AttachInfo是一样的。

//ViewGroup.java
@Override
@UnsupportedAppUsage
void dispatchAttachedToWindow(AttachInfo info, int visibility) {
mGroupFlags |= FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW;
super.dispatchAttachedToWindow(info, visibility);
mGroupFlags &= ~FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW; final int count = mChildrenCount;
final View[] children = mChildren;
for (int i = 0; i < count; i++) {
final View child = children[i];
child.dispatchAttachedToWindow(info,
combineVisibility(visibility, child.getVisibility()));
}
final int transientCount = mTransientIndices == null ? 0 : mTransientIndices.size();
for (int i = 0; i < transientCount; ++i) {
View view = mTransientViews.get(i);
view.dispatchAttachedToWindow(info,
combineVisibility(visibility, view.getVisibility()));
}
}
}

上述过程 performTraversals() 大致了解下:从上而下遍历视图树,每个View绘制自己,ViewGroup通知子View进行绘制。测量performMeasure() 执行布局performLayout() 绘制performDraw()。

Android绘制 重要的部分就在这里,需要了解的可以仔细研究下这个方法(performTraversals()),这里不作关注。

2.5:WindowManagerGlobal.getWindowSession()

// WindowManagerGlobal.java
@UnsupportedAppUsage
public static IWindowSession getWindowSession() {
synchronized (WindowManagerGlobal.class) {
if (sWindowSession == null) {
try {
InputMethodManager.ensureDefaultInstanceForDefaultDisplayIfNecessary();
IWindowManager windowManager = getWindowManagerService();
//创建Session对象
sWindowSession = windowManager.openSession(
new IWindowSessionCallback.Stub() {
@Override
public void onAnimatorScaleChanged(float scale) {
ValueAnimator.setDurationScale(scale);
}
});
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
return sWindowSession;
}
} //WindowManagerService.java
@Override
public IWindowSession openSession(IWindowSessionCallback callback) {
return new Session(this, callback);
}

获取Sessiond对象,如果没有则通过 windowManager.openSession() 创建。Session是IWindowSession的代理类,然后返回给ViewRootImpl中的mWindowSession。

2.6:ViewRootImpl.setView()

//ViewRootImpl.java
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
synchronized (this) {
if (mView == null) {
mView = view;
mWindowAttributes.copyFrom(attrs);
...
// Schedule the first layout -before- adding to the window
// manager, to make sure we do the relayout before receiving
// any other events from the system.
requestLayout();//TODO
try {
mOrigWindowType = mWindowAttributes.type;
mAttachInfo.mRecomputeGlobalAttributes = true;
collectViewAttributes();
//参考2.7,进入system_server进程
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(), mTmpFrame,
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel,
mTempInsets);
setFrame(mTmpFrame);
}
...
}
}
}

res = mWindowSession.addToDisplay():mWindowSession是上面返回的创建的Session,mWindowSession.addToDisplay()即通过binder进入system_server进程,执行的Session.addToDisplay()。

mView即DecorView。

这里的mWindow是2.4中讲到的,是 W 继承IWindow.Stub。这是一个IBinder对象,在应用进程创建ViewRootImpl时被创建。

这里mWindowSession.addToDisplay()往后可以看到被传入到WMS。

2.7:Session.addToDisplay()

//Session.java
class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
final WindowManagerService mService;
public Session(WindowManagerService service, IWindowSessionCallback callback) {
mService = service;
...
} @Override
public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
int viewVisibility, int displayId, Rect outFrame, Rect outContentInsets,
Rect outStableInsets, Rect outOutsets,
DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel,
InsetsState outInsetsState) {
//参考2.8
return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, outFrame,
outContentInsets, outStableInsets, outOutsets, outDisplayCutout, outInputChannel,
outInsetsState);
}
}

进入WMS,添加Window。

2.8:mService.addWindow()

终于到最后WMS.addWindow(),这里完成窗口添加。可以仔细看下下面源码及注释,这个方法即使缩减了很多还是比较长,需要耐心。

//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,
InsetsState outInsetsState) {
int[] appOp = new int[1];
//检查权限,无权限不能添加窗口
int res = mPolicy.checkAddPermission(attrs, appOp);
if (res != WindowManagerGlobal.ADD_OKAY) {
return res;
} boolean reportNewConfig = false;
WindowState parentWindow = null;
...
final int type = attrs.type;
synchronized (mGlobalLock) {
...
//获取窗口要添加到的DisplayContent。即显示在哪个屏幕上
final DisplayContent displayContent = getDisplayContentOrCreate(displayId, attrs.token); if (displayContent == null) {
Slog.w(TAG_WM, "Attempted to add window to a display that does not exist: "
+ displayId + ". Aborting.");
return WindowManagerGlobal.ADD_INVALID_DISPLAY;
}
if (!displayContent.hasAccess(session.mUid)) {
Slog.w(TAG_WM, "Attempted to add window to a display for which the application "
+ "does not have access: " + displayId + ". Aborting.");
return WindowManagerGlobal.ADD_INVALID_DISPLAY;
} if (mWindowMap.containsKey(client.asBinder())) {
Slog.w(TAG_WM, "Window " + client + " is already added");
return WindowManagerGlobal.ADD_DUPLICATE_ADD;
}
//添加子窗口,父窗口必须存在。
if (type >= FIRST_SUB_WINDOW && type <= LAST_SUB_WINDOW) {
parentWindow = windowForClientLocked(null, attrs.token, false);
if (parentWindow == null) {
Slog.w(TAG_WM, "Attempted to add window with token that is not a window: "
+ attrs.token + ". Aborting.");
return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN;
}
//这里可以看出WMS要求 窗口的层级 最多为两层
if (parentWindow.mAttrs.type >= FIRST_SUB_WINDOW
&& parentWindow.mAttrs.type <= LAST_SUB_WINDOW) {
Slog.w(TAG_WM, "Attempted to add window with token that is a sub-window: "
+ attrs.token + ". Aborting.");
return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN;
}
}
if (type == TYPE_PRIVATE_PRESENTATION && !displayContent.isPrivate()) {
Slog.w(TAG_WM, "Attempted to add private presentation window to a non-private display. Aborting.");
return WindowManagerGlobal.ADD_PERMISSION_DENIED;
} AppWindowToken atoken = null;
final boolean hasParent = parentWindow != null;
//获取WindowToken,对于子窗口使用父窗口的token。
//通过attrs.token从mTokenMap取出:private final HashMap<IBinder, WindowToken> mTokenMap = new HashMap();
//关于Activity窗口:WindowToken,前面讲过ActivityRecord 创建时会创建AppWindowToken,这个过程中appToken和AppWindowToken被保存到mTokenMap中
WindowToken token = displayContent.getWindowToken(
hasParent ? parentWindow.mAttrs.token : attrs.token); // If this is a child window, we want to apply the same type checking rules as the
// parent window type.
final int rootType = hasParent ? parentWindow.mAttrs.type : type;
boolean addToastWindowRequiresToken = false;
//以下是WindowToken和窗口之间的关系
if (token == null) {
//以下窗口类型,WindowToken不能为空
if (rootType >= FIRST_APPLICATION_WINDOW && rootType <= LAST_APPLICATION_WINDOW) {
Slog.w(TAG_WM, "Attempted to add application window with unknown token "
+ attrs.token + ". Aborting.");
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
}
if (rootType == TYPE_INPUT_METHOD) {
Slog.w(TAG_WM, "Attempted to add input method window with unknown token "
+ attrs.token + ". Aborting.");
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
}
if (rootType == TYPE_VOICE_INTERACTION) {
Slog.w(TAG_WM, "Attempted to add voice interaction window with unknown token "
+ attrs.token + ". Aborting.");
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
}
if (rootType == TYPE_WALLPAPER) {
Slog.w(TAG_WM, "Attempted to add wallpaper window with unknown token "
+ attrs.token + ". Aborting.");
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
}
if (rootType == TYPE_DREAM) {
Slog.w(TAG_WM, "Attempted to add Dream window with unknown token "
+ attrs.token + ". Aborting.");
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
}
if (rootType == TYPE_QS_DIALOG) {
Slog.w(TAG_WM, "Attempted to add QS dialog window with unknown token "
+ attrs.token + ". Aborting.");
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
}
if (rootType == TYPE_ACCESSIBILITY_OVERLAY) {
Slog.w(TAG_WM, "Attempted to add Accessibility overlay window with unknown token "
+ attrs.token + ". Aborting.");
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
}
if (type == TYPE_TOAST) {
// Apps targeting SDK above N MR1 cannot arbitrary add toast windows.
if (doesAddToastWindowRequireToken(attrs.packageName, callingUid,
parentWindow)) {
Slog.w(TAG_WM, "Attempted to add a toast window with unknown token "
+ attrs.token + ". Aborting.");
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
}
}
final IBinder binder = attrs.token != null ? attrs.token : client.asBinder();
final boolean isRoundedCornerOverlay =
(attrs.privateFlags & PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY) != 0;
//token为空,除上述窗口类型,其他是允许的。此时新建WindowToken
token = new WindowToken(this, binder, type, false, displayContent,
session.mCanAddInternalSystemWindow, isRoundedCornerOverlay);
//token不为空,且是应用窗口类型,token需要时AppWindowToken类型
} else if (rootType >= FIRST_APPLICATION_WINDOW && rootType <= LAST_APPLICATION_WINDOW) {
//判断token是否是AppWindowToken类型
//前面知道,Activity创建的是AppWindowToken,即获得的atoken非空
atoken = token.asAppWindowToken();
if (atoken == null) {
Slog.w(TAG_WM, "Attempted to add window with non-application token "
+ token + ". Aborting.");
return WindowManagerGlobal.ADD_NOT_APP_TOKEN;
} else if (atoken.removed) {
Slog.w(TAG_WM, "Attempted to add window with exiting application token "
+ token + ". Aborting.");
return WindowManagerGlobal.ADD_APP_EXITING;
} else if (type == TYPE_APPLICATION_STARTING && atoken.startingWindow != null) {
Slog.w(TAG_WM, "Attempted to add starting window to token with already existing"
+ " starting window");
return WindowManagerGlobal.ADD_DUPLICATE_ADD;
}
//其他各种窗口类型处理
} else if (rootType == TYPE_INPUT_METHOD) {
...
}...
//WindowState维护了所有窗口的信息,它是WMS实际管理的“窗口”
//它与Z-Order密切相关(多个Window层叠布局),其属性mLayer 越大,窗口越靠前。
final WindowState win = new WindowState(this, session, client, token, parentWindow,
appOp[0], seq, attrs, viewVisibility, session.mUid,
session.mCanAddInternalSystemWindow);
if (win.mDeathRecipient == null) {
// Client has apparently died, so there is no reason to
// continue.
Slog.w(TAG_WM, "Adding window client " + client.asBinder()
+ " that is dead, aborting.");
return WindowManagerGlobal.ADD_APP_EXITING;
}
...
origId = Binder.clearCallingIdentity();
//创建SurfaceSession,实现与SurfaceFlinger通信。参考2.9 简单说明下
win.attach();
//将WindowState对象加入到mWindowMap中
mWindowMap.put(client.asBinder(), win);
win.initAppOpsState();
...
final AppWindowToken aToken = token.asAppWindowToken();
win.mToken.addWindow(win);
win.applyAdjustForImeIfNeeded();
...
}
...
return res;
}

WMS通过WindowState对窗口进行管理、保存状态等。

添加窗口都需要指明其WindowToken;同时窗口需指明其DisplayContent 以确定显示到哪个屏幕设备。

具体请看上面注释,比较详细了。

看完,大致能明白窗口类型、WindowToken在窗口添加中的作用。了解到token的作用。

比如:若添加的时子窗口,则必须有父窗口,且窗口的层级最多为两层。WindowToken为null,可以明显看出那些情况不允许添加。添加的窗口时应用窗口时,WindowToken要是AppWindowToken。等等。

addWindow()暂时就说这些。

这个添加后的结果,通过res 最终反回到了 2.6:ViewRootImpl.setView() 中,根据结果 继续处理。

2.9:win.attach()

为什么win.attach()是创建与SurfaceFlinger通信的?简单了解下。

跟踪下去是创建了SurfaceSession对象,这个创建进入native,最终创建了一个与SurfaceFlinger通信的 SurfaceComposerClient。 因此,可以与SurfaceFlinger进行通信。

ViewRootImpl创建时 就创建的mSurface,mSurface是ViewRootImpl的成员变量,此时创建的Surface什么都没有,最后通过relayoutWindow()进入WMS 一步步向SurfaceFlinger发出请求。

这时几处相关代码。

//WindowState.java
void attach() {
if (localLOGV) Slog.v(TAG, "Attaching " + this + " token=" + mToken);
mSession.windowAddedLocked(mAttrs.packageName);
} //Session.java
void windowAddedLocked(String packageName) {
mPackageName = packageName;
mRelayoutTag = "relayoutWindow: " + mPackageName;
if (mSurfaceSession == null) {
mSurfaceSession = new SurfaceSession();
...
}
mNumWindow++;
} //ViewRootImpl.java
// These can be accessed by any thread, must be protected with a lock.
// Surface can never be reassigned or cleared (use Surface.clear()).
@UnsupportedAppUsage
public final Surface mSurface = new Surface();
private final SurfaceControl mSurfaceControl = new SurfaceControl();

这里只说到添加窗口到WMS,关于窗口添加后的处理、界面的计算显示更新等等,以后再总结。

Android10_原理机制系列_Activity窗口添加到WMS过程的更多相关文章

  1. Android10_原理机制系列_事件传递机制

    前言和概述 Android的输入设备,最常用的就是 触摸屏和按键 了.当然还有其他方式,比如游戏手柄,比如支持OTG设备,则可以链接鼠标.键盘等. 那么这些设备的操作 是如何传递到系统 并 控制界面的 ...

  2. Android10_原理机制系列_Window介绍及WMS的启动过程

    简介 Window简介 Android中,Window是一个重要部分,用户看到的界面.触摸显示界面进行一系列操作都涉及到Window.但实际上,Window本身并不具备绘制功能. 该篇简单介绍下Win ...

  3. Android10_原理机制系列_AMS(ATMS)之应用的第一次启动的过程

    概述 该篇基于Android 10的代码.在 AMS之AMS的启动---Android Framework(Android 10) 中已经介绍了,在Android 10中,activity的调度和管理 ...

  4. Android10_原理机制系列_AMS之AMS的启动

    概述 该篇基于AndroidQ,主要介绍系统启动中的 AMS(ActivityManagerService)的启动过程. AMS对四大组件(AndroidQ将activity移到了ActivityTa ...

  5. Android10_原理机制系列_Binder机制

    前言 Binder 从java到c++到kernel,涉及的内容很多,很难在一篇文章中说清楚.这篇主要是自我记录,方便后续查询并拆分总结的. 因为涉及的的确非常多,不能面面俱到,所以可能一些地方感觉比 ...

  6. Android10_原理机制系列_Android消息机制(Handler)详述

    概述 在Android中的多进程.多线程中提过,只有主线程(UI线程)可以更新UI,其他线程不可以,所以一般耗时操作放到子线程.子线程可以通过Handler将相关信息通知到主线程. Android的消 ...

  7. Android10_原理机制系列_PMS的启动及应用的安装过程

    概述 这里主要介绍 PackageManagerService(简称PMS)的启动 和 一个应用的安装过程.这里只是大致总结,供参考,不少地方同样需要进一步深入了解学习的. 该篇相关代码也是基于And ...

  8. Java的多线程机制系列:(三)synchronized的同步原理

    synchronized关键字是JDK5之实现锁(包括互斥性和可见性)的唯一途径(volatile关键字能保证可见性,但不能保证互斥性,详细参见后文关于vloatile的详述章节),其在字节码上编译为 ...

  9. Java的多线程机制系列:不得不提的volatile及指令重排序(happen-before)

    一.不得不提的volatile volatile是个很老的关键字,几乎伴随着JDK的诞生而诞生,我们都知道这个关键字,但又不太清楚什么时候会使用它:我们在JDK及开源框架中随处可见这个关键字,但并发专 ...

随机推荐

  1. 插件下载地址 ext

    ext2.2.0  http://files.cnblogs.com/files/chenghu/ext-2.2.zip http://files.cnblogs.com/files/chenghu/ ...

  2. SQL 查询当天,本月,本周的记录 sql 查询日期

    SELECT * FROM 表 WHERE CONVERT(Nvarchar, dateandtime, 111) = CONVERT(Nvarchar, GETDATE(), 111)   ORDE ...

  3. 第十一章 LNMP架构基础介绍

    一.LNMP架构 1.简介 oLNMP是一套技术的组合,L=Linux.N=Nginx.M~=MySQL.P~=PHP不仅仅包含这些,还有redis/ELK/zabbix/git/jenkins/ka ...

  4. 修改apt,pip,npm为国内镜像源

    apt 原文件备份 sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak 编辑源列表文件 sudo vim /etc/apt/sources. ...

  5. 通过命令行上传ipa到appstore

    搞持续集成自动化打包上传到appstore遇到这个问题,记录一下. 其实主要就一条到命令: xcrun altool --upload-app -f xxxx.ipa -u "yanqizh ...

  6. 抽空学学KVM(六)qemu-img命令使用

    通过KVM创建虚拟机,用到的命令不多,而且可以通过qemu-img -help查看到非常详细的解释,常用的主要有以下几种: 1.qemu-img info  查看磁盘信息     #info [-f ...

  7. Docker启动Mysql镜像

    date: 2020-03-14 17:00:00 updated: 2020-03-14 18:00:00 Docker启动Mysql镜像 管理员权限!!! docker run -p 3306:3 ...

  8. Mybatis---01Mybatis动态代理过程分析

    1.通过调试,session调用的getMapper是其实现类DefaultSQLSession中的 //1.读取配置文件 InputStream in = Resources.getResource ...

  9. Mysql优化建议

    Mysql优化建议: (1)CPU要更快,而不是更多.因为mysql不支持多个处理器并发处理一条sql,所以正常情况下不需要考虑更多的CPU.当然,你的系统中的对mysql的并发很高时,多核可以解决一 ...

  10. 免费申请HTTPS通配符证书

    前言 在阿里云买了一个域名giantliu.cn 部署了自己的博客系统 https://www.giantliu.cn/ 所有用https证书是Let's Encrypt免费申请的 因为申请的免费证书 ...