一、概述
当Activity启动后,是如何展现到屏幕上的呢 ? 带着这个问题,我们深入的学习下。
1.1 一些概念
如果之前没了解过,暂时可以先不关注,后续建立起概念了再来回顾~
-
WindowManagerService继承 IWindowManager.Stub,作为服务类提供了接口。 因此,IWindowManager就代表了 WMS。 -
WMS的成员变量
mSessions保存所有的session对象。 session是继承IWindowSession.Stub,作为服务端,提供给app层使用 。 疑问:IWindowSession和 IWindowManager 都提供给app使用,为啥要这样设计?答: 是为了减轻WMS的工作量,通过Session服务,没必要所有事情都直接通过WMS来完成。 -
mChoreographer 用来控制窗口动画、屏幕旋转等。
-
WMS的成员变量
mTokenMap,记录所有的 WindowToken 对象。以IBinder为key,可以是IAppWindowToken或者其他Binder的Bp端 (客户端Binder)。- 另一端的情况则是 ActivityRecord.Token extends IApplicationToken.Stub。IApplicationToken是 ActivityRecord的静态内部类,持有ActivityRecord的弱引用。保持跨进程的联系
-
成员变量
mWindowMap,保存所有WindowState对象(对应应用端的窗口概念),以IBinder为key,是IWindow接口定义的Bp端- 另一端情况: ViewRootImpl.W extends IWindow.Stub。
-
一般的,一个WindowState对应一个窗口。WindowState包含两个成员变量:
mClient:用于跟应用端交互。mToken跟AMS交互。
二、Activity的 launch 阶段
当启动一个Activity后,AMS会调用 app端的 handleLaunchActivity() 来完成最后的启动工作。
2.1 ActivityThread.handleLaunchActivity()
ActivityThread.java
public Activity handleLaunchActivity(ActivityClientRecord r,
PendingTransactionActions pendingActions, Intent customIntent) {
// ...
final Activity a = performLaunchActivity(r, customIntent);
// ...
}
2.2 ActivityThread.performLaunchActivity()
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
// 设置 ActivityClientRecord 一些信息
ActivityInfo aInfo = r.activityInfo;
if (r.packageInfo == null) {
// 创建 LoadApk对象,表示内存中已加载的apk信息
r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
Context.CONTEXT_INCLUDE_CODE);
}
ComponentName component = r.intent.getComponent();
if (component == null) {
component = r.intent.resolveActivity(
mInitialApplication.getPackageManager());
r.intent.setComponent(component);
}
if (r.activityInfo.targetActivity != null) {
// 设置 componentName
component = new ComponentName(r.activityInfo.packageName,
r.activityInfo.targetActivity);
}
// 2 创建activity的上下文,
ContextImpl appContext = createBaseContextForActivity(r);
// 3 通过反射,创建 Activity 对象
Activity activity = null;
try {
java.lang.ClassLoader cl = appContext.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
StrictMode.incrementExpectedActivityCount(activity.getClass());
r.intent.setExtrasClassLoader(cl);
r.intent.prepareToEnterProcess();
if (r.state != null) {
r.state.setClassLoader(cl);
}
} catch (Exception e) {
// 实例化activity失败
if (!mInstrumentation.onException(activity, e)) {
throw new RuntimeException(
"Unable to instantiate activity " + component
+ ": " + e.toString(), e);
}
}
// 4, 创建application 对象 ,但是这里不会真正的去创建,因为在拉起进程的阶段已经做过了。直接返回之前的对象即可
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
...
appContext.setOuterContext(activity);
// 5. attach window相关信息 ---重点关注的地方
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);
// 6, 设置主题
int theme = r.activityInfo.getThemeResource();
if (theme != 0) {
activity.setTheme(theme);
}
// 7, 回调onCreate() 方法 --重点
if (r.isPersistable()) {
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
} else {
mInstrumentation.callActivityOnCreate(activity, r.state);
}
// 8 ,存入键值对中 ArrayMap<IBinder, ActivityClientRecord> mActivities
synchronized (mResourcesManager) {
mActivities.put(r.token, r);
}
// ...
}
重点:
- Activity的
attach()方法 - Activity的 onCreate()方法
2.3 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) {
// 绑定context,因为activity是继承context的,所以mBase的赋值就在此处
attachBaseContext(context);
// fragments attach
mFragments.attachHost(null /*parent*/);
// 创建 PhoneWindow 对象。传入activity作为上下文,null,
mWindow = new PhoneWindow(this, window, activityConfigCallback);
mWindow.setWindowControllerCallback(this);
// 设置activity为 window的callback,当window有变化的时候就回调activity的方法
mWindow.setCallback(this); // 设置callback
mWindow.setOnWindowDismissedCallback(this);
mWindow.getLayoutInflater().setPrivateFactory(this);
// 4 一堆赋值
mInstrumentation = instr;
mToken = token; // ActivityRecord 的静态内部类对象
mAssistToken = assistToken;
mIdent = ident;
mApplication = application;
mIntent = intent;
mReferrer = referrer;
mComponent = intent.getComponent();
mActivityInfo = info;
mTitle = title;
mParent = parent;
mEmbeddedID = id;
// ....
// 给window设置 WMS引用
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());
}
// 获取windowManager对象
mWindowManager = mWindow.getWindowManager();
mCurrentConfig = config;
mWindow.setColorMode(info.colorMode);
}
重点:
- 创建mWindow成员变量,Window是一个抽象类,实际上是
PhoneWindow。传入了Activity作为context。 setWindowManager(), 传入了WMS服务的binder,Activity在AMS中的 token。- 获取mWindowManager 成员变量。这个windowManager对象是在
setWindowManager()时候创建的
Activity extends ContextThemeWrapper,同时ContextThemeWrapper extends ContextWrapper,同时ContextWrapper extends Context。 因此,Activity本身也是个context对象。
2.3.1 PhoneWindow 构造方法
PhoneWindow.java
public PhoneWindow(Context context) {
super(context);
mLayoutInflater = LayoutInflater.from(context);
}
/**
* Constructor for main window of an activity.
构造activity的主 window对象
*/
public PhoneWindow(Context context, Window preservedWindow,
ActivityConfigCallback activityConfigCallback) {
// 给父类 window的 context赋值。
this(context);
// Only main activity windows use decor context, all the other windows depend on whatever
// context that was given to them.
mUseDecorContext = true;
if (preservedWindow != null) {
mDecor = (DecorView) preservedWindow.getDecorView();
mElevation = preservedWindow.getElevation();
mLoadElevation = false;
mForceDecorInstall = true;
// If we're preserving window, carry over the app token from the preserved
// window, as we'll be skipping the addView in handleResumeActivity(), and
// the token will not be updated as for a new window.
getAttributes().token = preservedWindow.getAttributes().token;
}
// Even though the device doesn't support picture-in-picture mode,
// an user can force using it through developer options.
boolean forceResizable = Settings.Global.getInt(context.getContentResolver(),
DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES, 0) != 0;
mSupportsPictureInPicture = forceResizable || context.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_PICTURE_IN_PICTURE);
// 后续config变化回调用
mActivityConfigCallback = activityConfigCallback;
}
- 赋值Window类的
mContext成员,window类也有context的引用。 - 创建 mLayoutInflater
Window.java
public Window(Context context) {
mContext = context;
mFeatures = mLocalFeatures = getDefaultFeatures(context);
}
2.3.2 setWindowManager()
Window.java
public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
boolean hardwareAccelerated) {
mAppToken = appToken; // IApplicationToken.Stub 对象
mAppName = appName;
mHardwareAccelerated = hardwareAccelerated;
if (wm == null) {
// 这个 context是哪里赋值的? 其实就是activity
wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
}
// 创建本地的windowManager对象,其实是 WindowManagerImpl 对象。
mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
}
- 持有
IApplicationToken.Stub对象引用,它会弱引用了 ActivityRecord对象 - 如果vm为空,则再次赋值WMS
- 创建
本地 windowManager对象:WindowManagerImpl
public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
//
return new WindowManagerImpl(mContext, parentWindow);
}
parentWindow 对象为 PhoneWindow 对象。 因此,PhoneWindow 和 WindowManagerImpl 互相持有引用。
2.3.3 getWindowManager()
Window.java
public WindowManager getWindowManager() {
return mWindowManager;
}
返回上一步赋值的 本地windowManager对象。
2.4 小结
在activity的attach()方法中,我们可以知道:
- 一个activity与一个PhoneWindow对象绑定,称为 activity的主窗口。
- 此window 持有WMS的引用 vm,用来跨进程调用。
- activity持有 本地windowManagerImpl对象,内部会持有IWindowSession的引用。
至此,在activity启动阶段,完成了与window的绑定,初始化工作完成。后续系统会按顺序回调onStart()、onResume()等生命周期方法。我们继续看 handleResumeActivity()方法。
三、Activity的 resume 阶段
3.1 ActivityThread.handleResumeActivity()
ActivityThread.java
@Override
public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,
String reason) {
// If we are getting ready to gc after going to the background, well
// we are back active so skip it.
unscheduleGcIdler();
mSomeActivitiesChanged = true;
// TODO Push resumeArgs into the activity for consideration
// 1 执行activity的 onResume() 方法
final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason);
if (r == null) {
// 避免多次onResume() 执行
// We didn't actually resume the activity, so skipping any follow-up actions.
return;
}
// 如果该activity准备要destroy,那么久没必要去渲染UI了
if (mActivitiesToBeDestroyed.containsKey(token)) {
// Although the activity is resumed, it is going to be destroyed. So the following
// UI operations are unnecessary and also prevents exception because its token may
// be gone that window manager cannot recognize it. All necessary cleanup actions
// performed below will be done while handling destruction.
return;
}
final Activity a = r.activity;
//...
// r.window现在肯定是null,走该分支
if (r.window == null && !a.mFinished && willBeVisible) {
// 赋值 ActivityClientRecord的 window成员
r.window = r.activity.getWindow();
// 从window中 获取decorView
View decor = r.window.getDecorView();
// 设置decorView 可见
decor.setVisibility(View.INVISIBLE);
// 获取 本地 windowmanager
ViewManager wm = a.getWindowManager();
// 获取window的布局参数
WindowManager.LayoutParams l = r.window.getAttributes();
// 赋值activity的 mDecor对象
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添加到 window
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 the window has already been added, but during resume
// we started another activity, then don't yet make the
// window visible.
} else if (!willBeVisible) {
if (localLOGV) Slog.v(TAG, "Launch " + r + " mStartedActivity set");
r.hideForNow = true;
}
// Get rid of anything left hanging around.
cleanUpPendingRemoveWindows(r, false /* force */);
// 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) {
if (r.newConfig != null) {
performConfigurationChangedForActivity(r, r.newConfig);
if (DEBUG_CONFIGURATION) {
Slog.v(TAG, "Resuming activity " + r.activityInfo.name + " with newConfig "
+ r.activity.mCurrentConfig);
}
r.newConfig = null;
}
if (localLOGV) Slog.v(TAG, "Resuming " + r + " with isForward=" + isForward);
WindowManager.LayoutParams l = r.window.getAttributes();
if ((l.softInputMode
& WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION)
!= forwardBit) {
l.softInputMode = (l.softInputMode
& (~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION))
| forwardBit;
if (r.activity.mVisibleFromClient) {
ViewManager wm = a.getWindowManager();
View decor = r.window.getDecorView();
wm.updateViewLayout(decor, l);
}
}
r.activity.mVisibleFromServer = true;
mNumVisibleActivities++;
if (r.activity.mVisibleFromClient) {
r.activity.makeVisible();
}
}
r.nextIdle = mNewActivities;
mNewActivities = r;
if (localLOGV) Slog.v(TAG, "Scheduling idle handler for " + r);
Looper.myQueue().addIdleHandler(new Idler());
}
重点:
- 执行activity的onResume()
- 从window中
获取DecorView,然后调用本地的windowManager的addView()方法 - 调用 Activity的
makeVisible()
那么,window中的 decorView 是从哪里来的? ?
答:当Activity 调用 setContextView()时生成的。我们先看看 decorView的生成过程。
3.2 Activity.setContentView()
Activity.java
public void setContentView(@LayoutRes int layoutResID) {
getWindow().setContentView(layoutResID);
initWindowDecorActionBar();
}
调用了 window 的 setContentView()方法。
3.3 PhoneWindow.setContentView()
PhoneWindow.java
ViewGroup mContentParent;
@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.
// mContentParent 就是window用来存放view的父容器
// 第一次肯定是空。
if (mContentParent == null) {
// 初始化 decorView 和 contentParent 容器
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 {
// 把Activity的 布局文件 填充到 contentParent容器中
mLayoutInflater.inflate(layoutResID, mContentParent);
}
mContentParent.requestApplyInsets();
final Callback cb = getCallback();
if (cb != null && !isDestroyed()) {
// 回调activity的方法
cb.onContentChanged();
}
mContentParentExplicitlySet = true;
}
- 初始化
decorView和contentParent容器 - 把Activity的 布局文件 填充到 contentParent容器中
- 回调activity的onContentChanged() 方法
我们先看第一步怎么实现的。
3.3.1 installDecor()
PhoneWindow.java
private void installDecor() {
mForceDecorInstall = false;
if (mDecor == null) {
// 第一次为null,generateDecor 生成 mDecor
mDecor = generateDecor(-1);
mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
mDecor.setIsRootNamespace(true);
if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
}
} else {
// 不为null,则设置window引用
mDecor.setWindow(this);
}
if (mContentParent == null) {
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) {
mDecorContentParent = decorContentParent;
mDecorContentParent.setWindowCallback(getCallback());
if (mDecorContentParent.getTitle() == null) {
mDecorContentParent.setWindowTitle(mTitle);
}
final int localFeatures = getLocalFeatures();
for (int i = 0; i < FEATURE_MAX; i++) {
if ((localFeatures & (1 << i)) != 0) {
mDecorContentParent.initFeature(i);
}
}
mDecorContentParent.setUiOptions(mUiOptions);
if ((mResourcesSetFlags & FLAG_RESOURCE_SET_ICON) != 0 ||
(mIconRes != 0 && !mDecorContentParent.hasIcon())) {
mDecorContentParent.setIcon(mIconRes);
} else if ((mResourcesSetFlags & FLAG_RESOURCE_SET_ICON) == 0 &&
mIconRes == 0 && !mDecorContentParent.hasIcon()) {
mDecorContentParent.setIcon(
getContext().getPackageManager().getDefaultActivityIcon());
mResourcesSetFlags |= FLAG_RESOURCE_SET_ICON_FALLBACK;
}
if ((mResourcesSetFlags & FLAG_RESOURCE_SET_LOGO) != 0 ||
(mLogoRes != 0 && !mDecorContentParent.hasLogo())) {
mDecorContentParent.setLogo(mLogoRes);
}
// Invalidate if the panel menu hasn't been created before this.
// Panel menu invalidation is deferred avoiding application onCreateOptionsMenu
// being called in the middle of onCreate or similar.
// A pending invalidation will typically be resolved before the posted message
// would run normally in order to satisfy instance state restoration.
PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false);
if (!isDestroyed() && (st == null || st.menu == null) && !mIsStartingWindow) {
invalidatePanelMenu(FEATURE_ACTION_BAR);
}
} else {
mTitleView = findViewById(R.id.title);
if (mTitleView != null) {
if ((getLocalFeatures() & (1 << FEATURE_NO_TITLE)) != 0) {
final View titleContainer = findViewById(R.id.title_container);
if (titleContainer != null) {
titleContainer.setVisibility(View.GONE);
} else {
mTitleView.setVisibility(View.GONE);
}
mContentParent.setForeground(null);
} else {
mTitleView.setText(mTitle);
}
}
}
if (mDecor.getBackground() == null && mBackgroundFallbackDrawable != null) {
mDecor.setBackgroundFallback(mBackgroundFallbackDrawable);
}
// Only inflate or create a new TransitionManager if the caller hasn't
// already set a custom one.
if (hasFeature(FEATURE_ACTIVITY_TRANSITIONS)) {
if (mTransitionManager == null) {
final int transitionRes = getWindowStyle().getResourceId(
R.styleable.Window_windowContentTransitionManager,
0);
if (transitionRes != 0) {
final TransitionInflater inflater = TransitionInflater.from(getContext());
mTransitionManager = inflater.inflateTransitionManager(transitionRes,
mContentParent);
} else {
mTransitionManager = new TransitionManager();
}
}
//...
}
}
}
- 调用 generateDecor()生成 mDecor 容器
- 调用 generateLayout(mDecor) 生成 mContentParent 容器
3.3.2 generateDecor()
PhoneWindow.java
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;
if (mUseDecorContext) {
Context applicationContext = getContext().getApplicationContext();
if (applicationContext == null) {
context = getContext();
} else {
context = new DecorContext(applicationContext, getContext());
if (mTheme != -1) {
context.setTheme(mTheme);
}
}
} else {
context = getContext();
}
// 创建一个DecorView对象 ,this表示PhoneWindow
return new DecorView(context, featureId, this, getAttributes());
}
DecorView 继承了frameLayout,是一个容器类。
3.3.3 generateLayout()
PhoneWindow.java
protected ViewGroup generateLayout(DecorView decor) {
TypedArray a = getWindowStyle();
//根据 配置的xml属性,在代码中设置window的flag标记
mIsFloating = a.getBoolean(R.styleable.Window_windowIsFloating, false);
int flagsToUpdate = (FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR)
& (~getForcedWindowFlags());
if (mIsFloating) {
setLayout(WRAP_CONTENT, WRAP_CONTENT);
setFlags(0, flagsToUpdate);
} else {
setFlags(FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR, flagsToUpdate);
}
//...
if (a.getBoolean(R.styleable.Window_windowLightStatusBar, false)) {
decor.setSystemUiVisibility(
decor.getSystemUiVisibility() | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
}
if (a.getBoolean(R.styleable.Window_windowLightNavigationBar, false)) {
decor.setSystemUiVisibility(
decor.getSystemUiVisibility() | View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR);
}
//...
mDecor.startChanging();
// decoreView内部会inflate 这个layoutResource的布局,作为第一个子view添加到decorView中
layoutResource 会根据主题、系统不一样加载不同的布局(linearLayout垂直布局,上面为title区域,下面是framelayout内容区域)
,但不管如何变化,里面肯定会有R.id. content的控件
mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);
// 从decorView中 获取到 com.android.internal.R.id.content对应的控件,本质上是一个容器
ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
if (contentParent == null) {
throw new RuntimeException("Window couldn't find content container view");
}
//...
if (getContainer() == null) {
//设置window的背景
mDecor.setWindowBackground(mBackgroundDrawable);
final Drawable frame;
if (mFrameResource != 0) {
frame = getContext().getDrawable(mFrameResource);
} else {
frame = null;
}
mDecor.setWindowFrame(frame);
mDecor.setElevation(mElevation);
mDecor.setClipToOutline(mClipToOutline);
if (mTitle != null) {
setTitle(mTitle);
}
if (mTitleColor == 0) {
mTitleColor = mTextColor;
}
setTitleColor(mTitleColor);
}
mDecor.finishChanging();
return contentParent; // 返回 contentParent
}
- 对上一步生成的 decorView
加载布局文件,同时找到android.R.id.content的容器控件:contentParent,contentParent后面就用来加载Activity的布局内容。 - 设置 window 背景。
- 返回该 contextParent对象。
至此,经过在activity onCreate()方法中调用 setContentView()后,我们得到了 decorView对象,它是一个frameLayout容器,内部首先填充了一个LinearLayout(包含title区域和content区域)。然后在content区域再次填充了Activity对应的布局。
至此,整个decorView就包含了 Activity的整个布局。
但此时,还没有和windowManager 关联起来,继续看 handleResumeActivity() 中的 r.activity.makeVisible()方法。
3.4 Activity.makeVisible()
Activity.java
void makeVisible() {
if (!mWindowAdded) {
ViewManager wm = getWindowManager();
wm.addView(mDecor, getWindow().getAttributes());
mWindowAdded = true;
}
mDecor.setVisibility(View.VISIBLE);
}
调用了wm的 addView()方法。vm是 WindowManagerImpl 对象。
3.5 WindowManagerImpl.addView()
WindowManagerImpl.java
// WindowManagerImpl的成员变量, mGlobal是一个单例对象
private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
// 调用 mGlobal 的addView()
mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
}
- mParentWindow: 就是 PhoneWindow 对象
- Display 表示屏幕
继续调用 mGlobal 的addView()。WindowManagerGlobal 是一个单例对象。
3.6 mGlobal.addView()
WindowManagerGlobal.java
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow) {
if (view == null) {
throw new IllegalArgumentException("view must not be null");
}
if (display == null) {
throw new IllegalArgumentException("display must not be null");
}
if (!(params instanceof WindowManager.LayoutParams)) {
throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
}
// 转换为 WindowManager.LayoutParams
final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
if (parentWindow != null) {
// 为 子window 调整布局参数
parentWindow.adjustLayoutParamsForSubWindow(wparams);
} else {
// If there's no parent, then hardware acceleration for this view is
// set from the application's hardware acceleration setting.
final Context context = view.getContext();
if (context != null
&& (context.getApplicationInfo().flags
& ApplicationInfo.FLAG_HARDWARE_ACCELERATED) != 0) {
wparams.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
}
}
ViewRootImpl root;
View panelParentView = null;
// 上锁
synchronized (mLock) {
// Start watching for system property changes.
if (mSystemPropertyUpdater == null) {
mSystemPropertyUpdater = new Runnable() {
@Override public void run() {
synchronized (mLock) {
for (int i = mRoots.size() - 1; i >= 0; --i) {
mRoots.get(i).loadSystemProperties();
}
}
}
};
SystemProperties.addChangeCallback(mSystemPropertyUpdater);
}
// 找到当前view在 views列表中的 index
int index = findViewLocked(view, false);
if (index >= 0) {
// 表示之前添加过了
if (mDyingViews.contains(view)) {
// Don't wait for MSG_DIE to make it's way through root's queue.
// 如果已经在销毁列表,那么执行销毁动作
mRoots.get(index).doDie();
} else {
// 添加过,再次添加 则报错!不能重复添加!
throw new IllegalStateException("View " + view
+ " has already been added to the window manager.");
}
// The previous removeView() had not completed executing. Now it has.
}
// If this is a panel window, then find the window it is being
// attached to for future reference.
if (wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
final int count = mViews.size();
for (int i = 0; i < count; i++) {
if (mRoots.get(i).mWindow.asBinder() == wparams.token) {
panelParentView = mViews.get(i);
}
}
}
// 创建 ViewRootImpl对象
root = new ViewRootImpl(view.getContext(), display);
// 设置view的布局参数
view.setLayoutParams(wparams);
// 分别添加 三个列表中,整个应用的view、ViewRootImpl、params都加在这三个集合里
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
// do this last because it fires off messages to start doing things
try {
// 调用 setView
root.setView(view, wparams, panelParentView);
} catch (RuntimeException e) {
// BadTokenException or InvalidDisplayException, clean up.
if (index >= 0) {
// 异常,则移除views列表中的view
removeViewLocked(index, true);
}
throw e;
}
}
}
WindowManagerGlobal是单例对象,保存了应用的所有 views 和对应的 roots、params。
- 创建
ViewRootImpl对象 - 加入到三大列表中
mViews、mRoots、mParams - 调用 ViewRootImpl 的
setView()
在分析 setView()之前,我们先看看 ViewRootImpl的构造方法。
3.6.1 ViewRootImpl的构造方法
final IWindowSession mWindowSession;
public ViewRootImpl(Context context, Display display) {
mContext = context;
// IWindowSession 应用进程的代理对象,具体实现是system server进程的 Session extends IWindowSession.Stub
mWindowSession = WindowManagerGlobal.getWindowSession();
mDisplay = display;
mBasePackageName = context.getBasePackageName();
mThread = Thread.currentThread();
mLocation = new WindowLeaked(null);
mLocation.fillInStackTrace();
mWidth = -1;
mHeight = -1;
//重绘区域
mDirty = new Rect();
mTempRect = new Rect();
mVisRect = new Rect();
mWinFrame = new Rect();
// 创建 W binder对象,提供给系统回调应用时使用
mWindow = new W(this);
mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion;
mViewVisibility = View.GONE;
mTransparentRegion = new Region();
mPreviousTransparentRegion = new Region();
mFirst = true; // true for the first time the view is added
mAdded = false;
mAttachInfo = new View.AttachInfo(mWindowSession, mWindow, display, this, mHandler, this,
context);
mAccessibilityManager = AccessibilityManager.getInstance(context);
mAccessibilityManager.addAccessibilityStateChangeListener(
mAccessibilityInteractionConnectionManager, mHandler);
mHighContrastTextManager = new HighContrastTextManager();
mAccessibilityManager.addHighTextContrastStateChangeListener(
mHighContrastTextManager, mHandler);
mViewConfiguration = ViewConfiguration.get(context);
mDensity = context.getResources().getDisplayMetrics().densityDpi;
mNoncompatDensity = context.getResources().getDisplayMetrics().noncompatDensityDpi;
mFallbackEventHandler = new PhoneFallbackEventHandler(context);
// 持有 Choreographer 的引用
mChoreographer = Choreographer.getInstance();
// 获取 mDisplayManager 服务
mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
String processorOverrideName = context.getResources().getString(
R.string.config_inputEventCompatProcessorOverrideClassName);
if (processorOverrideName.isEmpty()) {
// No compatibility processor override, using default.
mInputCompatProcessor = new InputEventCompatProcessor(context);
} else {
// 输入事件处理
InputEventCompatProcessor compatProcessor = null;
try {
final Class<? extends InputEventCompatProcessor> klass =
(Class<? extends InputEventCompatProcessor>) Class.forName(
processorOverrideName);
compatProcessor = klass.getConstructor(Context.class).newInstance(context);
} catch (Exception e) {
Log.e(TAG, "Unable to create the InputEventCompatProcessor. ", e);
} finally {
mInputCompatProcessor = compatProcessor;
}
}
if (!sCompatibilityDone) {
sAlwaysAssignFocus = mTargetSdkVersion < Build.VERSION_CODES.P;
sCompatibilityDone = true;
}
loadSystemProperties();
}
- 通过 WindowManagerGlobal 静态方法 获取IWindowSession 代理Binder服务
- 创建
Wbinder对象,提供给系统回调应用时使用。W extends IWindow.Stub类,作为服务端。 - 持有
Choreographer的引用 - 获取 mDisplayManager 服务:(DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
- 输入事件处理
3.6.2 WindowManagerGlobal.getWindowSession()
WindowManagerGlobal.java
@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();
// 得到 WMS的代理Binder,
IWindowManager windowManager = getWindowManagerService();
// 调用 WMS的openSession()方法,返回一个IWindowSession 的 Binder对象
sWindowSession = windowManager.openSession(
// 这个callback作为应用的binder服务端,WMS用来回调给应用端
new IWindowSessionCallback.Stub() {
@Override
public void onAnimatorScaleChanged(float scale) {
ValueAnimator.setDurationScale(scale);
}
});
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
return sWindowSession;
}
}
上锁且判空,因此,一个应用程序只会在系统进程中创建一个 Session Binder服务对象。
3.6.2.1 WMS端 openSession()
WMS.java
@Override
public IWindowSession openSession(IWindowSessionCallback callback) {
//直接创建对象 Session
return new Session(this, callback);
}
3.6.3 ViewRootImpl的静态内部类 W
static class W extends IWindow.Stub {
// 持有ViewRootImpl的弱引用
private final WeakReference<ViewRootImpl> mViewAncestor;
// 持有 IWindowSession 引用
private final IWindowSession mWindowSession;
W(ViewRootImpl viewAncestor) {
mViewAncestor = new WeakReference<ViewRootImpl>(viewAncestor);
mWindowSession = viewAncestor.mWindowSession;
}
3.6.4 Choreographer 的getInstance()
Choreographer.java
public static Choreographer getInstance() {
return sThreadInstance.get();
}
sThreadInstance静态成员变量是一个 ThreadLocal对象。 用来存储线程私有的本地数据。
private static final ThreadLocal<Choreographer> sThreadInstance =
new ThreadLocal<Choreographer>() {
@Override
protected Choreographer initialValue() {
Looper looper = Looper.myLooper();
// 当前线程必须要looper才能创建 Choreographer
if (looper == null) {
throw new IllegalStateException("The current thread must have a looper!");
}
// 创建Choreographer, VSYNC_SOURCE_APP表示是app端。系统端也会用??
Choreographer choreographer = new Choreographer(looper, VSYNC_SOURCE_APP);
if (looper == Looper.getMainLooper()) {
// 如果是主线程,则赋值
mMainInstance = choreographer;
}
return choreographer;
}
};
因此,每个绑定了looper的线程,才可以创建 Choreographer 对象。 Choreographer详细工作流程后续单独分析。
大概作用是注册 onVsync接收,开始回调doFrame,在到doTraversal()方法。开始View的三大流程测量、布局、绘制。
各个角色的基本功能熟悉了,那么继续看 ViewRootImpl的 setView()是如何跟 WMS产生关系的?
3.7 ViewRootImpl.setView()
ViewRootImpl.java
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
synchronized (this) {
if (mView == null) {
mView = view;
mWindowAttributes.copyFrom(attrs);
if (mWindowAttributes.packageName == null) {
mWindowAttributes.packageName = mBasePackageName;
}
attrs = mWindowAttributes;
//...
mAdded = true;
//...
// 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()
requestLayout();
if ((mWindowAttributes.inputFeatures
& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
mInputChannel = new InputChannel();
}
mForceDecorViewVisibility = (mWindowAttributes.privateFlags
& PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY) != 0;
try {
mOrigWindowType = mWindowAttributes.type;
mAttachInfo.mRecomputeGlobalAttributes = true;
collectViewAttributes();
// 调用 addToDisplay()
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(), mTmpFrame,
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel,
mTempInsets);
setFrame(mTmpFrame);
} 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();
}
}
//...
}
}
}
- 调用 requestLayout()
- 调用
windowSession的addToDisplay()
3.7.1 ViewRootImpl.requestLayout()
ViewRootImpl.java
@Override
public void requestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
//检测创建view的线程和此时请求的线程是否一致: Only the original thread that created a view hierarchy can touch its views.
checkThread();
mLayoutRequested = true;
scheduleTraversals();
}
}
3.7.2 scheduleTraversals()
ViewRootImpl.java
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
// 发送一个同步屏障消息,也就是message的handler为null的消息 到消息队列中
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
// 往 mChoreographer 注册 runnable ,此消息是异步消息
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
if (!mUnbufferedInputDispatch) {
scheduleConsumeBatchedInput();
}
notifyRendererOfFramePending();
pokeDrawLockIfNeeded();
}
}
- 发送同步屏障消息,让后面的异步消息先执行,确保UI刷新优先处理。
- 往 mChoreographer 注册 CALLBACK_TRAVERSAL 异步消息 runnable。 当onVsync信号到来时候会优先执行该 runnable。
3.7.3 TraversalRunnable
final class TraversalRunnable implements Runnable {
@Override
public void run() {
doTraversal();
}
}
3.7.4 doTraversal()
void doTraversal() {
if (mTraversalScheduled) {
mTraversalScheduled = false;
mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
if (mProfile) {
Debug.startMethodTracing("ViewAncestor");
}
performTraversals();
if (mProfile) {
Debug.stopMethodTracing();
mProfile = false;
}
}
}
performTraversals() 内部会调用 view的三大流程。这里就不再深入了。
回过头来看 addToDisplay()方法。
四、 IWindowSession 端.addToDisplay()
4.1 Session.addToDisplay()
Session.java
@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) {
return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, outFrame,
outContentInsets, outStableInsets, outOutsets, outDisplayCutout, outInputChannel,
outInsetsState);
}
- this session 对象
- IWindow: 应用端的Binder服务,回调应用端用
- seq: 序号值,app端和WMS端 同步用
调用了 WMS的 addWindow()。
4.2 WMS.addWindow()
WMS.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) {
//...
synchronized (mGlobalLock) { // 上锁
if (!mDisplayReady) {
throw new IllegalStateException("Display has not been initialialized");
}
// 获取 DisplayContent
final DisplayContent displayContent = getDisplayContentOrCreate(displayId, attrs.token);
if (displayContent == null) {
// displayContent不存在,那么window就无法添加
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)) {
// 检查当前应用id的权限
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;
}
// mWindowMap key是客户端的IWindow 对象(也就是ViewRootImpl的W静态内部类对象),value是 WindowState
if (mWindowMap.containsKey(client.asBinder())) {
// 如果已经 WindowState已经存在,则返回。避免重复注册
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;
}
// 如果父窗口还是属于子窗口类型,那么报错。也就说只允许两级窗口的存在。子窗口不能再创建子窗口
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;
}
// WindowToken的子类,表示一个应用/activity的 token
AppWindowToken atoken = null;
final boolean hasParent = parentWindow != null;
// 内部从 mTokenMap 中获取。mTokenMap key是 IApplication.Stub的binder对象,value是 WindowToken
// 如果有父窗口则使用父窗口的token,如果没有父窗口就使用自己的layoutParams中的窗口的token
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.
// 如果有父窗口则使用父窗口的type,如果没有父窗口就使用自己的layoutParams中的窗口的type
final int rootType = hasParent ? parentWindow.mAttrs.type : type;
if (token == null) {
// 如果token为空且是属于下面的窗口类型,就返回错误,同时打印错误信息
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为空WMS也默认合法,就帮忙新建一个WindowToken对象
token = new WindowToken(this, binder, type, false, displayContent,
session.mCanAddInternalSystemWindow, isRoundedCornerOverlay);
} else if (rootType >= FIRST_APPLICATION_WINDOW && rootType <= LAST_APPLICATION_WINDOW) {
// token 此时不为null(表示之前已经注册过了)且窗口类型范围为[1,99]应用类型窗口。检查applicationToken
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) {
if (token.windowType != TYPE_INPUT_METHOD) {
Slog.w(TAG_WM, "Attempted to add input method window with bad token "
+ attrs.token + ". Aborting.");
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
}
} else if (rootType == TYPE_VOICE_INTERACTION) {
if (token.windowType != TYPE_VOICE_INTERACTION) {
Slog.w(TAG_WM, "Attempted to add voice interaction window with bad token "
+ attrs.token + ". Aborting.");
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
}
} else if (rootType == TYPE_WALLPAPER) {
if (token.windowType != TYPE_WALLPAPER) {
Slog.w(TAG_WM, "Attempted to add wallpaper window with bad token "
+ attrs.token + ". Aborting.");
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
}
} else if (rootType == TYPE_DREAM) {
if (token.windowType != TYPE_DREAM) {
Slog.w(TAG_WM, "Attempted to add Dream window with bad token "
+ attrs.token + ". Aborting.");
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
}
} else if (rootType == TYPE_ACCESSIBILITY_OVERLAY) {
if (token.windowType != TYPE_ACCESSIBILITY_OVERLAY) {
Slog.w(TAG_WM, "Attempted to add Accessibility overlay window with bad token "
+ attrs.token + ". Aborting.");
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
}
} else if (type == TYPE_TOAST) {
// Apps targeting SDK above N MR1 cannot arbitrary add toast windows.
// 对于type_tost类型的窗口,8.0后需要权限才可以弹出
addToastWindowRequiresToken = doesAddToastWindowRequireToken(attrs.packageName,
callingUid, parentWindow);
if (addToastWindowRequiresToken && token.windowType != TYPE_TOAST) {
Slog.w(TAG_WM, "Attempted to add a toast window with bad token "
+ attrs.token + ". Aborting.");
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
}
} else if (type == TYPE_QS_DIALOG) {
if (token.windowType != TYPE_QS_DIALOG) {
Slog.w(TAG_WM, "Attempted to add QS dialog window with bad token "
+ attrs.token + ". Aborting.");
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
}
} else if (token.asAppWindowToken() != null) {
Slog.w(TAG_WM, "Non-null appWindowToken for system window of rootType=" + rootType);
// It is not valid to use an app token with other system types; we will
// instead make a new token for it (as if null had been passed in for the token).
attrs.token = null;
token = new WindowToken(this, client.asBinder(), type, false, displayContent,
session.mCanAddInternalSystemWindow);
}
// 至此,toen不为null,且 WindowMap 中没有创建过WindowState。
// 那么就创建一个 WindowState对象
final WindowState win = new WindowState(this, session, client, token, parentWindow,
appOp[0], seq, attrs, viewVisibility, session.mUid,
session.mCanAddInternalSystemWindow);
final DisplayPolicy displayPolicy = displayContent.getDisplayPolicy();
// 调整窗口策略参数
displayPolicy.adjustWindowParamsLw(win, win.mAttrs, Binder.getCallingPid(),
Binder.getCallingUid());
//...
// 调用 win的 attach()
win.attach();
mWindowMap.put(client.asBinder(), win);
win.initAppOpsState();
//...
displayContent.getInputMonitor().setUpdateInputWindowsNeededLw();
boolean focusChanged = false;
if (win.canReceiveKeys()) {
// 如果该窗口可以接收事件,那么就更新当前获取焦点 窗口
focusChanged = updateFocusedWindowLocked(UPDATE_FOCUS_WILL_ASSIGN_LAYERS,
false /*updateInputWindows*/);
if (focusChanged) {
imMayMove = false;
}
}
//...
}
//...
}
- 首先确保 DisplayContent displayContent 对象的存在,即要显示到哪个屏幕上
- 判断
mWindowMap中是否已经添加过WindowState对象,若是则返回 - 从 displayContent 中获取 WindowToken 对象。一系列 ADD_BAD_APP_TOKEN 判断
- 创建新的 WindowState 对象,
- 调整窗口的策略
- 调用win 的 attach()方法。
创建SurfaceSession,用来与SurfaceFlinger的通信 - 存入到mWindowMap中,完成注册。
- 如果该窗口可以接收事件,那么就更新当前获取焦点窗口
4.2.1 WindowState 构造方法
WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token,
WindowState parentWindow, int appOp, int seq, WindowManager.LayoutParams a,
int viewVisibility, int ownerId, boolean ownerCanAddInternalSystemWindow,
PowerManagerWrapper powerManagerWrapper) {
super(service);
mSession = s; // session 代理
mClient = c; // IWindow代理
mAppOp = appOp;
mToken = token;
mAppToken = mToken.asAppWindowToken();
mOwnerUid = ownerId;
mOwnerCanAddInternalSystemWindow = ownerCanAddInternalSystemWindow;
mWindowId = new WindowId(this);
mAttrs.copyFrom(a);
mLastSurfaceInsets.set(mAttrs.surfaceInsets);
mViewVisibility = viewVisibility;
mPolicy = mWmService.mPolicy;
mContext = mWmService.mContext;
DeathRecipient deathRecipient = new DeathRecipient();
mSeq = seq;
mPowerManagerWrapper = powerManagerWrapper;
mForceSeamlesslyRotate = token.mRoundedCornerOverlay;
if (localLOGV) Slog.v(
TAG, "Window " + this + " client=" + c.asBinder()
+ " token=" + token + " (" + mAttrs.token + ")" + " params=" + a);
try {
// 注册客户端死亡监听
c.asBinder().linkToDeath(deathRecipient, 0);
} catch (RemoteException e) {
mDeathRecipient = null;
mIsChildWindow = false;
mLayoutAttached = false;
mIsImWindow = false;
mIsWallpaper = false;
mIsFloatingLayer = false;
mBaseLayer = 0;
mSubLayer = 0;
mInputWindowHandle = null;
mWinAnimator = null;
return;
}
mDeathRecipient = deathRecipient;
if (mAttrs.type >= FIRST_SUB_WINDOW && mAttrs.type <= LAST_SUB_WINDOW) {
// The multiplier here is to reserve space for multiple
// windows in the same type layer.
mBaseLayer = mPolicy.getWindowLayerLw(parentWindow)
* TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET;
mSubLayer = mPolicy.getSubWindowLayerFromTypeLw(a.type);
mIsChildWindow = true;
if (DEBUG_ADD_REMOVE) Slog.v(TAG, "Adding " + this + " to " + parentWindow);
parentWindow.addChild(this, sWindowSubLayerComparator);
mLayoutAttached = mAttrs.type !=
WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
mIsImWindow = parentWindow.mAttrs.type == TYPE_INPUT_METHOD
|| parentWindow.mAttrs.type == TYPE_INPUT_METHOD_DIALOG;
mIsWallpaper = parentWindow.mAttrs.type == TYPE_WALLPAPER;
} else {
// The multiplier here is to reserve space for multiple
// windows in the same type layer.
mBaseLayer = mPolicy.getWindowLayerLw(this)
* TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET;
mSubLayer = 0;
mIsChildWindow = false;
mLayoutAttached = false;
mIsImWindow = mAttrs.type == TYPE_INPUT_METHOD
|| mAttrs.type == TYPE_INPUT_METHOD_DIALOG;
mIsWallpaper = mAttrs.type == TYPE_WALLPAPER;
}
mIsFloatingLayer = mIsImWindow || mIsWallpaper;
if (mAppToken != null && mAppToken.mShowForAllUsers) {
// Windows for apps that can show for all users should also show when the device is
// locked.
mAttrs.flags |= FLAG_SHOW_WHEN_LOCKED;
}
// 窗口动画
mWinAnimator = new WindowStateAnimator(this);
mWinAnimator.mAlpha = a.alpha;
mRequestedWidth = 0;
mRequestedHeight = 0;
mLastRequestedWidth = 0;
mLastRequestedHeight = 0;
//
mLayer = 0;
mInputWindowHandle = new InputWindowHandle(
mAppToken != null ? mAppToken.mInputApplicationHandle : null, c,
getDisplayId());
}
4.2.2 WindowState.attach()
WindowState.java
void attach() {
if (localLOGV) Slog.v(TAG, "Attaching " + this + " token=" + mToken);
mSession.windowAddedLocked(mAttrs.packageName);
}
4.2.3 Session.windowAddedLocked
Session.java
SurfaceSession mSurfaceSession;
void windowAddedLocked(String packageName) {
mPackageName = packageName;
mRelayoutTag = "relayoutWindow: " + mPackageName;
if (mSurfaceSession == null) {
// 一个进程只有一个session,因此也只创建一次 SurfaceSession 对象
if (WindowManagerService.localLOGV) Slog.v(
TAG_WM, "First window added to " + this + ", creating SurfaceSession");
// 创建 SurfaceSession 对象
mSurfaceSession = new SurfaceSession();
if (SHOW_TRANSACTIONS) Slog.i(
TAG_WM, " NEW SURFACE SESSION " + mSurfaceSession);
// 每个session 都存入WMS中的
mService.mSessions.add(this);
if (mLastReportedAnimatorScale != mService.getCurrentAnimatorScale()) {
mService.dispatchNewAnimatorScaleLocked(this);
}
}
mNumWindow++; // 进程中所有窗口的数量
}
一个进程只有一个session,因此也只创建一次 SurfaceSession 对象。
4.3 SurfaceSession 构造方法
private long mNativeClient; // SurfaceComposerClient*
private static native long nativeCreate();
private static native void nativeDestroy(long ptr);
private static native void nativeKill(long ptr);
/** Create a new connection with the surface flinger. */
@UnsupportedAppUsage
public SurfaceSession() {
mNativeClient = nativeCreate();
}
mNativeClient 指向了native层的 SurfaceComposerClient 对象。用来跟 SurfaceFlinger 交互。
4.3.1 nativeCreate()
/frameworks/base/core/jni/android_view_SurfaceSession.cpp
static jlong nativeCreate(JNIEnv* env, jclass clazz) {
44 SurfaceComposerClient* client = new SurfaceComposerClient();
45 client->incStrong((void*)nativeCreate);
46 return reinterpret_cast<jlong>(client);
47 }
nativeCreate()创建了一个 SurfaceComposerClient 对象,并返回引用到java层。
总之,SurfaceSession 就是WMS用来跟SurfaceFlinger,建立联系的。至于具体怎么联系,后续继续分析。
五、总结
Activity的启动过程,也就是窗口的添加过程。总体分为两个部分:
-
App端
- 通过
PhoneWindow这个抽象的窗口概念,本质上就是个类。来封装了mDecorView对象。且与 WindowManagerImpl 绑定。 - 构造出 WindowManagerImpl 对象,调用
addView()方法。实际上调用 WindowManagerGlobal 单例对象 - WindowManagerGlobal单例对象内部 持有
mRoots、mViews、mParams三大数组用来存储整个应用的窗口信息。 - 新建 ViewRootImpl 对象,在构造方法中会 openSession()跨进程创建 Session 对象(系统进程中),一个应用只有一个。
- 关键点是在 ViewRootImpl的
setView()方法中 通过 IWindowSession 的addToDisplay(),把窗口信息注册到WMS中。
- 通过
-
WMS端
- 通过WMS提供的 openSession(),为每个进程创建 IWindowSession,具体实现为:Session对象。
- addToDisplay() 会继续调用 WMS的
addWindow()方法。 - 对应每一个窗口,创建 WindowState 与之对应。WindowState在 系统中就表示一个窗口。内部的 mClient对应 ViewRootImpl 的内部类 W。 mToken则表示AMS中 ActivityRecord.Token 内部类。
- WindowState 还会
创建 SurfaceSession,对应一块surface区域,实现与SurfaceFlinger通信 - WMS的职责就是负责每个进程中的 WindowState的创建、移除、管理显示层级。具体的绘制交给 SuerfaceFlinger。
总之, WMS其实是不关心 App层的window以及其中的view的。它只关心WindowState集合中元素的顺序。哪个进程的WindowState排在前面,哪个进程的
窗口排在后面。App通过windowLayoutParams lp把对应的窗口显示参数传递给WMS,让WMS来管理层级。
也就是说 WMS 负责窗口的创建与移除,以及显示状态的管理。具体绘制是由 SuerfaceFlinger 来负责的。
每个窗口都有一块自己的Surface,SurfaceFlinger 负责把这些 Surface 合成一块 FrameBuffer,最终上屏展示。
参考微信文章一个图: