Android10原理机制系列之Activity窗口添加到WMS过程

移动开发 Android
首先看一个Android界面的布局层次结构,我们能清晰看到,这个界面分成了3部分:顶部状态栏(statusbar)、底部导航栏(navigationbar)、应用界面。

前言

首先看一个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类型 

  1. //WindowManager.java 
  2. public static class LayoutParams extends ViewGroup.LayoutParams implements Parcelable { 
  3.     public static final int FIRST_APPLICATION_WINDOW = 1; 
  4.     public static final int LAST_APPLICATION_WINDOW = 99; 
  5.      
  6.     public static final int FIRST_SUB_WINDOW = 1000; 
  7.     public static final int LAST_SUB_WINDOW = 1999; 
  8.      
  9.     public static final int FIRST_SYSTEM_WINDOW = 2000; 
  10.     public static final int LAST_SYSTEM_WINDOW = 2999; 
  11.     //状态栏 
  12.     public static final int TYPE_STATUS_BAR         = FIRST_SYSTEM_WINDOW; 
  13.     //搜索栏 
  14.     public static final int TYPE_SEARCH_BAR         = FIRST_SYSTEM_WINDOW+1; 
  15.     //来电显示 
  16.     public static final int TYPE_PHONE              = FIRST_SYSTEM_WINDOW+2; 
  17.     //警告窗口,常见如:低电量警告 
  18.     public static final int TYPE_SYSTEM_ALERT       = FIRST_SYSTEM_WINDOW+3; 
  19.     //锁屏 
  20.     public static final int TYPE_KEYGUARD           = FIRST_SYSTEM_WINDOW+4; 
  21.     //toast 
  22.     public static final int TYPE_TOAST              = FIRST_SYSTEM_WINDOW+5; 
  23.     public static final int TYPE_SYSTEM_OVERLAY     = FIRST_SYSTEM_WINDOW+6;//显示在所有窗口之上,覆盖 
  24.     //来电优先,即使锁屏状态下 
  25.     public static final int TYPE_PRIORITY_PHONE     = FIRST_SYSTEM_WINDOW+7; 
  26.     //输入法窗口 
  27.     public static final int TYPE_INPUT_METHOD       = FIRST_SYSTEM_WINDOW+11; 
  28.     //壁纸 
  29.     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、输入法等等。

几个重要类

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

  1. public abstract class Window {} 
  2. public class PhoneWindow extends Window implements MenuBuilder.Callback {} 
  3.  
  4. public interface WindowManagerPolicy extends WindowManagerPolicyConstants {} 
  5. public class PhoneWindowManager implements WindowManagerPolicy {} 
  6.  
  7. public interface ViewManager { 
  8.     public void addView(View view, ViewGroup.LayoutParams params); 
  9.     public void updateViewLayout(View view, ViewGroup.LayoutParams params); 
  10.     public void removeView(View view); 
  11. public interface WindowManager extends ViewManager {} 
  12. public final class WindowManagerImpl implements WindowManager {} 
  13.  
  14. /** A window in the window manager. */ 
  15. class WindowState extends WindowContainer<WindowState> implements WindowManagerPolicy.WindowState {} 

Window是一个抽象类,Activity、Toast、Dialog等都是靠Window来呈现。

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

不过查看WindowManagerImpl中 关于ViewManager的3个操作可以看出,这3个实现 最终是交由WindowManagerGlobal完成的。

WindowState维护着窗口的所有信息。WMS通过WindowState对窗口进行管理、保存状态等。

Activity创建窗口添加到WMS综述

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

  1. //attach() 
  2. -performLaunchActivity() 
  3. --activity.attach()//创建了PhoneWindow(mWindow)。mWindowManager保存的是 从mWindow处获取的 setWindowManager()创建的WindowManagerImpl 
  4. ---mWindow.setWindowManager()//PhoneWindow内部 创建了WindowManagerImpl(mWindowManager),并保存了appToken、appName。 
  5.  
  6. //onCreate() 
  7. -setContentView() 
  8. --installDecor() 
  9. ---generateDecor()//创建了DecorView(mDecor) 
  10. ---generateLayout()//将activity的布局作为子视图(ViewGroup)添加到mDecor中 
  11.  
  12. //onResume() 
  13. -r.activity.makeVisible()// 
  14. --wm.addView(mDecor, ...)//wm即mWindowManager(WindowManagerImpl对象) 
  15. ---WindowManagerGlobal.addView()//创建了ViewRootImpl。addView的view是mDecor,ViewRootImpl中创建了mWindow(这里是一个IBinder,而非attach()中创建的) 
  16. ----ViewRootImpl.setView()//openSession()创建了Session(IWindowSession的代理类),view也是mDecor。mDecor传入到ViewRootImpl的mView 
  17. -----Session.addToDisplay()//通过Session进入system_server进程 
  18. ------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中的一些结构示意图

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

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

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

Token传递到WMS

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

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

  1. final class ActivityRecord extends ConfigurationContainer { 
  2.     final IApplicationToken.Stub appToken; // window manager token 
  3.     // TODO: Remove after unification 
  4.     AppWindowToken mAppWindowToken; 
  5.          
  6.     ActivityRecord(ActivityTaskManagerService _service, WindowProcessController _caller,...) { 
  7.         appToken = new Token(this, _intent); 
  8.     } 
  9.      
  10.     void createAppWindowToken() { 
  11.         mAppWindowToken = createAppWindow(mAtmService.mWindowManager, appToken,...); 
  12.     } 
  13.      
  14.     static class Token extends IApplicationToken.Stub { 
  15.         Token(ActivityRecord activity, Intent intent) { 
  16.             weakActivity = new WeakReference<>(activity); 
  17.             name = intent.getComponent().flattenToShortString(); 
  18.         } 
  19.     } 

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()开始。 

  1. //ActivityThread.java 
  2. @Override 
  3. public Activity handleLaunchActivity(ActivityClientRecord r, 
  4.         PendingTransactionActions pendingActions, Intent customIntent) { 
  5.     ... 
  6.     WindowManagerGlobal.initialize(); 
  7.     final Activity a = performLaunchActivity(r, customIntent); 
  8.     ... 
  9.  
  10. private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) { 
  11.     ... 
  12.     try { 
  13.         java.lang.ClassLoader cl = appContext.getClassLoader(); 
  14.         activity = mInstrumentation.newActivity( 
  15.                 cl, component.getClassName(), r.intent); 
  16.     } 
  17.     try { 
  18.         Application app = r.packageInfo.makeApplication(false, mInstrumentation); 
  19.         if (activity != null) { 
  20.             Window window = null
  21.             ... 
  22.             //attach(),注意这个r.token。参考1.2 
  23.             activity.attach(appContext, this, getInstrumentation(), r.token, 
  24.                     r.ident, app, r.intent, r.activityInfo, title, r.parent, 
  25.                     r.embeddedID, r.lastNonConfigurationInstances, config, 
  26.                     r.referrer, r.voiceInteractor, window, r.configCallback, 
  27.                     r.assistToken); 
  28.             if (r.isPersistable()) { 
  29.                 //callActivityOnCreate() 最终执行到的activity的onCreate()方法。   
  30.                 //参考1.4 
  31.                 mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState); 
  32.             } else { 
  33.                 mInstrumentation.callActivityOnCreate(activity, r.state); 
  34.             } 
  35.         } 
  36.     } 
  37.     ... 
  38.     return activity; 

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

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

1.2:activity.attach() 

  1. //Activity.java 
  2. final void attach(Context context, ActivityThread aThread, 
  3.        Instrumentation instr, IBinder token, ...) { 
  4.     ... 
  5.     //创建PhoneWindow 
  6.     mWindow = new PhoneWindow(this, window, activityConfigCallback);//创建PhoneWindow  
  7.     //设置软键盘 
  8.     if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) { 
  9.         mWindow.setSoftInputMode(info.softInputMode); 
  10.     } 
  11.     //token保存到mToken。         
  12.     mToken = token; 
  13.     ... 
  14.     //mToken传入到Window,参考1.3 
  15.     mWindow.setWindowManager( 
  16.             (WindowManager)context.getSystemService(Context.WINDOW_SERVICE), 
  17.             mToken, mComponent.flattenToString(), 
  18.             (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0); 
  19.     //mWindowManager即setWindowManager()中创建的WindowManagerImpl。 
  20.     mWindowManager = mWindow.getWindowManager(); 
  21.     ... 

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

1.3:mWindow.setWindowManager() 

  1. //Window.java 
  2. public void setWindowManager(WindowManager wm, IBinder appToken, String appName, 
  3.         boolean hardwareAccelerated) { 
  4.     //ActivityClientRecord.token 
  5.     mAppToken = appToken; 
  6.     mAppName = appName; 
  7.     mHardwareAccelerated = hardwareAccelerated; 
  8.     if (wm == null) { 
  9.         wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE); 
  10.     } 
  11.     //创建了WindowManagerImpl,注意WindowManagerImpl中mParentWindow是this,非空 
  12.     mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this); 

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

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

1.4:setContentView()

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

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

  1. //Activity.java 
  2. public void setContentView(@LayoutRes int layoutResID) { 
  3.     getWindow().setContentView(layoutResID);// 
  4.     initWindowDecorActionBar(); 
  5.  
  6.  
  7. public Window getWindow() { 
  8.     return mWindow;//即PhoneWindow对象 
  9.  
  10. //PhoneWindow.java 
  11. // This is the top-level view of the window, containing the window decor. 
  12. private DecorView mDecor; 
  13. @Override 
  14. public void setContentView(int layoutResID) { 
  15.     // Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window 
  16.     // decor, when theme attributes and the like are crystalized. Do not check the feature 
  17.     // before this happens. 
  18.     if (mContentParent == null) { 
  19.         installDecor();// 
  20.     } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) { 
  21.         mContentParent.removeAllViews(); 
  22.     } 
  23.     if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) { 
  24.         final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID, 
  25.                 getContext()); 
  26.         transitionTo(newScene); 
  27.     } else { 
  28.         mLayoutInflater.inflate(layoutResID, mContentParent); 
  29.     } 
  30.     ... 
  31.  
  32. private void installDecor() { 
  33.     mForceDecorInstall = false
  34.     if (mDecor == null) { 
  35.         //生成DecorView,参考1.5 
  36.         mDecor = generateDecor(-1); 
  37.         ... 
  38.     } else { 
  39.         mDecor.setWindow(this); 
  40.     } 
  41.     if (mContentParent == null) { 
  42.         //布局添加到DecorView,参考1.5 
  43.         mContentParent = generateLayout(mDecor); 
  44.  
  45.         // Set up decor part of UI to ignore fitsSystemWindows if appropriate. 
  46.         mDecor.makeOptionalFitsSystemWindows(); 
  47.  
  48.         final DecorContentParent decorContentParent = (DecorContentParent) mDecor.findViewById( 
  49.                 R.id.decor_content_parent); 
  50.         if (decorContentParent != null) { 
  51.         } else { 
  52.             mTitleView = findViewById(R.id.title); 
  53.         } 
  54.         ... 
  55.     } 

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

先看下他们的相关代码:

1.5:generateDecor()和generateLayout() 

  1. protected DecorView generateDecor(int featureId) { 
  2.     // System process doesn't have application context and in that case we need to directly use 
  3.     // the context we have. Otherwise we want the application context, so we don't cling to the 
  4.     // activity. 
  5.     Context context; 
  6.     ... 
  7.     return new DecorView(context, featureId, this, getAttributes());// 
  8.  
  9. public class DecorView extends FrameLayout implements RootViewSurfaceTaker, WindowCallbacks { 
  10.  
  11. protected ViewGroup generateLayout(DecorView decor) { 
  12.     ... 
  13.     mDecor.startChanging(); 
  14.     mDecor.onResourcesLoaded(mLayoutInflater, layoutResource); 
  15.     ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT); 
  16.     ... 
  17.     mDecor.finishChanging(); 
  18.     return contentParent; 
  19.  
  20. //DecorView.java 
  21. void onResourcesLoaded(LayoutInflater inflater, int layoutResource) { 
  22.     ... 
  23.     mDecorCaptionView = createDecorCaptionView(inflater); 
  24.     final View root = inflater.inflate(layoutResource, null); 
  25.     if (mDecorCaptionView != null) { 
  26.         if (mDecorCaptionView.getParent() == null) { 
  27.             addView(mDecorCaptionView, 
  28.                     new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT)); 
  29.         } 
  30.         mDecorCaptionView.addView(root, 
  31.                 new ViewGroup.MarginLayoutParams(MATCH_PARENT, MATCH_PARENT)); 
  32.     } else { 
  33.  
  34.         // Put it below the color views. 
  35.         addView(root, 0, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT)); 
  36.     } 
  37.     mContentRoot = (ViewGroup) root; 
  38.     initializeElevation(); 

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

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

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

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

Window添加到WMS过程

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

  1. //ActivityStackSupervisor.java: 
  2. boolean realStartActivityLocked(ActivityRecord r, WindowProcessController proc, 
  3.         boolean andResume, boolean checkConfig) throws RemoteException { 
  4.     ... 
  5.     try { 
  6.         ... 
  7.         try { 
  8.             // Create activity launch transaction
  9.             final ClientTransaction clientTransaction = ClientTransaction.obtain( 
  10.                     proc.getThread(), r.appToken); 
  11.  
  12.             final DisplayContent dc = r.getDisplay().mDisplayContent; 
  13.             clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent), 
  14.             ... 
  15.             // Set desired final state. 
  16.             final ActivityLifecycleItem lifecycleItem; 
  17.             if (andResume) { 
  18.                 lifecycleItem = ResumeActivityItem.obtain(dc.isNextTransitionForward()); 
  19.             } else { 
  20.                 lifecycleItem = PauseActivityItem.obtain(); 
  21.             } 
  22.             clientTransaction.setLifecycleStateRequest(lifecycleItem); 
  23.  
  24.             // Schedule transaction
  25.             mService.getLifecycleManager().scheduleTransaction(clientTransaction); 
  26.             ... 
  27.         }  
  28.     } 
  29.     ... 
  30.     return true

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

这里从ActivityThread.handleResumeActivity()来看。

2.1:ActivityThread.handleResumeActivity() 

  1. //ActivityThread.java 
  2. @Override 
  3. public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward, 
  4.         String reason) { 
  5.     ... 
  6.     // TODO Push resumeArgs into the activity for consideration 
  7.     //执行onStart()->onResume()。参考2.2 
  8.     final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason); 
  9.     final Activity a = r.activity; 
  10.     if (r.window == null && !a.mFinished && willBeVisible) { 
  11.         r.window = r.activity.getWindow(); 
  12.         View decor = r.window.getDecorView(); 
  13.         decor.setVisibility(View.INVISIBLE); 
  14.         ViewManager wm = a.getWindowManager(); 
  15.         WindowManager.LayoutParams l = r.window.getAttributes(); 
  16.         a.mDecor = decor; 
  17.         l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION; 
  18.         ... 
  19.     }  
  20.     ... 
  21.     // The window is now visible if it has been added, we are not 
  22.     // simply finishing, and we are not starting another activity. 
  23.     if (!r.activity.mFinished && willBeVisible && r.activity.mDecor != null && !r.hideForNow) { 
  24.         ... 
  25.         r.activity.mVisibleFromServer = true
  26.         mNumVisibleActivities++; 
  27.         if (r.activity.mVisibleFromClient) { 
  28.             //参考2.3 
  29.             r.activity.makeVisible(); 
  30.         } 
  31.     } 
  32.     ... 

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

这里关注两个: 

  1. performResumeActivity()  
  2. r.activity.makeVisible(); 

2.2:performResumeActivity() 

  1. //ActivityThread.java 
  2. @VisibleForTesting 
  3. public ActivityClientRecord performResumeActivity(IBinder token, boolean finalStateRequest, 
  4.         String reason) { 
  5.     final ActivityClientRecord r = mActivities.get(token); 
  6.     ... 
  7.     try { 
  8.         r.activity.onStateNotSaved(); 
  9.         r.activity.mFragments.noteStateNotSaved(); 
  10.         ... 
  11.         r.activity.performResume(r.startsNotResumed, reason); 
  12.  
  13.         r.state = null
  14.         r.persistentState = null
  15.         r.setState(ON_RESUME); 
  16.  
  17.         reportTopResumedActivityChanged(r, r.isTopResumedActivity, "topWhenResuming"); 
  18.     }  
  19.     return r; 
  20.  
  21. //Activity.java 
  22. final void performResume(boolean followedByPause, String reason) { 
  23.     performRestart(true /* start */, reason); 
  24.     mInstrumentation.callActivityOnResume(this); 
  25.  
  26. final void performRestart(boolean start, String reason) { 
  27.     mInstrumentation.callActivityOnRestart(this); 
  28.  
  29. //Instrumentation.java 
  30. public void callActivityOnRestart(Activity activity) { 
  31.     activity.onRestart(); 
  32.  
  33. public void callActivityOnResume(Activity activity) { 
  34.     activity.mResumed = true
  35.     activity.onResume(); 
  36.     ... 

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

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

2.3:r.activity.makeVisible() 

  1. //Activity.java 
  2. void makeVisible() { 
  3.     if (!mWindowAdded) { 
  4.         ViewManager wm = getWindowManager(); 
  5.         wm.addView(mDecor, getWindow().getAttributes()); 
  6.         mWindowAdded = true
  7.     } 
  8.     mDecor.setVisibility(View.VISIBLE); 
  9.  
  10. //WindowManagerImpl.java 
  11. public final class WindowManagerImpl implements WindowManager { 
  12.     @UnsupportedAppUsage 
  13.     private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance(); 
  14.     @Override 
  15.     public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) { 
  16.         applyDefaultToken(params); 
  17.         //mParentWindow即创建WindowManagerImpl是 传入的。参考2.4 
  18.         mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow); 
  19.     } 

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

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

2.4:WindowManagerGlobal.addView() 

  1. //WindowManagerGlobal 
  2. @UnsupportedAppUsage 
  3. private final ArrayList<View> mViews = new ArrayList<View>(); 
  4. @UnsupportedAppUsage 
  5. private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>(); 
  6. public void addView(View view, ViewGroup.LayoutParams params, 
  7.         Display display, Window parentWindow) { 
  8.     ... 
  9.     final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params; 
  10.     if (parentWindow != null) { 
  11.         //调整Window参数,这个过程将token设置其中了 
  12.         //参考2.4.1 
  13.         parentWindow.adjustLayoutParamsForSubWindow(wparams); 
  14.     }  
  15.     ... 
  16.     ViewRootImpl root; 
  17.     View panelParentView = null
  18.     synchronized (mLock) { 
  19.         ... 
  20.         root = new ViewRootImpl(view.getContext(), display); 
  21.         view.setLayoutParams(wparams); 
  22.         mViews.add(view); 
  23.         mRoots.add(root); 
  24.         mParams.add(wparams); 
  25.         try { 
  26.             //将view及相关参数设置到ViewRootImpl中。ViewRootImpl会向WMS添加新窗口、申请Surface及绘制工作等。 
  27.             //参考2.6 
  28.             root.setView(view, wparams, panelParentView); 
  29.         }  
  30.         ... 
  31.     } 
  32.  
  33. //ViewRootImpl.java 
  34. @UnsupportedAppUsage 
  35. final IWindowSession mWindowSession; 
  36. public ViewRootImpl(Context context, Display display) { 
  37.     mContext = context; 
  38.     //创建了Session(),参考2.5 
  39.     mWindowSession = WindowManagerGlobal.getWindowSession(); 
  40.     mDisplay = display; 
  41.     mBasePackageName = context.getBasePackageName(); 
  42.     mThread = Thread.currentThread(); 
  43.     mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion; 
  44.     //这里的mWindow不是前面Activity中的PhoneWindow,它是W extends IWindow.Stub 
  45.     mWindow = new W(this); 
  46.     mViewVisibility = View.GONE; 
  47.     //创建AttachInfo 
  48.     mAttachInfo = new View.AttachInfo(mWindowSession, mWindow, display, this, mHandler, this, 
  49.                 context); 
  50.     ... 
  51.  
  52. static class W extends IWindow.Stub {...} 
  53.  
  54. //ViewRootImpl.java 
  55. public final class ViewRootImpl implements ViewParent, 
  56.  
  57. //View.java 
  58. final static class AttachInfo { 
  59.     AttachInfo(IWindowSession session, IWindow window, Display display, 
  60.             ViewRootImpl viewRootImpl, Handler handler, Callbacks effectPlayer, 
  61.             Context context) { 
  62.         mSession = session; 
  63.         mWindow = window; 
  64.         mWindowToken = window.asBinder(); 
  65.         mDisplay = display; 
  66.         mViewRootImpl = viewRootImpl; 
  67.         mHandler = handler; 
  68.         mRootCallbacks = effectPlayer; 
  69.         mTreeObserver = new ViewTreeObserver(context); 
  70.     } 

这里主要看到,创建了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参与处理。 

  1. //Window.java 
  2. void adjustLayoutParamsForSubWindow(WindowManager.LayoutParams wp) { 
  3.     CharSequence curTitle = wp.getTitle(); 
  4.     //子窗口,该篇中是应用窗口,所以不走这,也了解下。        
  5.     if (wp.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW && 
  6.             wp.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) { 
  7.         if (wp.token == null) { 
  8.             View decor = peekDecorView(); 
  9.             if (decor != null) { 
  10.                 wp.token = decor.getWindowToken(); 
  11.             } 
  12.         } 
  13.         ... 
  14.     //系统窗口,也不走这 
  15.     } else if (wp.type >= WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW && 
  16.             wp.type <= WindowManager.LayoutParams.LAST_SYSTEM_WINDOW) { 
  17.         ... 
  18.     //应用窗口,该篇走这 
  19.     } else { 
  20.         if (wp.token == null) { 
  21.             //设置到了WindowManager.LayoutParams中 
  22.             wp.token = mContainer == null ? mAppToken : mContainer.mAppToken; 
  23.         } 
  24.         ... 
  25.     } 
  26.     ... 

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是一样的。 

  1. //ViewGroup.java 
  2. @Override 
  3. @UnsupportedAppUsage 
  4. void dispatchAttachedToWindow(AttachInfo info, int visibility) { 
  5.     mGroupFlags |= FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW; 
  6.     super.dispatchAttachedToWindow(info, visibility); 
  7.     mGroupFlags &= ~FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW; 
  8.  
  9.     final int count = mChildrenCount; 
  10.     final View[] children = mChildren; 
  11.     for (int i = 0; i < count; i++) { 
  12.         final View child = children[i]; 
  13.         child.dispatchAttachedToWindow(info, 
  14.                 combineVisibility(visibility, child.getVisibility())); 
  15.     } 
  16.     final int transientCount = mTransientIndices == null ? 0 : mTransientIndices.size(); 
  17.     for (int i = 0; i < transientCount; ++i) { 
  18.         View view = mTransientViews.get(i); 
  19.         view.dispatchAttachedToWindow(info, 
  20.                 combineVisibility(visibility, view.getVisibility())); 
  21.     } 

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

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

2.5:WindowManagerGlobal.getWindowSession() 

  1. // WindowManagerGlobal.java    
  2. @UnsupportedAppUsage 
  3. public static IWindowSession getWindowSession() { 
  4.     synchronized (WindowManagerGlobal.class) { 
  5.         if (sWindowSession == null) { 
  6.             try { 
  7.                 InputMethodManager.ensureDefaultInstanceForDefaultDisplayIfNecessary(); 
  8.                 IWindowManager windowManager = getWindowManagerService(); 
  9.                 //创建Session对象 
  10.                 sWindowSession = windowManager.openSession( 
  11.                         new IWindowSessionCallback.Stub() { 
  12.                             @Override 
  13.                             public void onAnimatorScaleChanged(float scale) { 
  14.                                 ValueAnimator.setDurationScale(scale); 
  15.                             } 
  16.                         }); 
  17.             } catch (RemoteException e) { 
  18.                 throw e.rethrowFromSystemServer(); 
  19.             } 
  20.         } 
  21.         return sWindowSession; 
  22.     } 
  23.  
  24. //WindowManagerService.java 
  25. @Override 
  26. public IWindowSession openSession(IWindowSessionCallback callback) { 
  27.     return new Session(this, callback); 

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

2.6:ViewRootImpl.setView() 

  1. //ViewRootImpl.java 
  2. public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) { 
  3.     synchronized (this) { 
  4.         if (mView == null) { 
  5.             mView = view
  6.             mWindowAttributes.copyFrom(attrs); 
  7.             ... 
  8.             // Schedule the first layout -before- adding to the window 
  9.             // manager, to make sure we do the relayout before receiving 
  10.             // any other events from the system. 
  11.             requestLayout();//TODO 
  12.             try { 
  13.                 mOrigWindowType = mWindowAttributes.type; 
  14.                 mAttachInfo.mRecomputeGlobalAttributes = true
  15.                 collectViewAttributes(); 
  16.                 //参考2.7,进入system_server进程 
  17.                 res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes, 
  18.                         getHostVisibility(), mDisplay.getDisplayId(), mTmpFrame, 
  19.                         mAttachInfo.mContentInsets, mAttachInfo.mStableInsets, 
  20.                         mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel, 
  21.                         mTempInsets); 
  22.                 setFrame(mTmpFrame); 
  23.             } 
  24.             ... 
  25.         } 
  26.     } 

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()

  1. //Session.java 
  2. class Session extends IWindowSession.Stub implements IBinder.DeathRecipient { 
  3.     final WindowManagerService mService; 
  4.     public Session(WindowManagerService service, IWindowSessionCallback callback) { 
  5.         mService = service; 
  6.         ... 
  7.     } 
  8.  
  9.     @Override 
  10.     public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs, 
  11.             int viewVisibility, int displayId, Rect outFrame, Rect outContentInsets, 
  12.             Rect outStableInsets, Rect outOutsets, 
  13.             DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel, 
  14.             InsetsState outInsetsState) { 
  15.         //参考2.8 
  16.         return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, outFrame, 
  17.                 outContentInsets, outStableInsets, outOutsets, outDisplayCutout, outInputChannel, 
  18.                 outInsetsState); 
  19.     } 

进入WMS,添加Window。

2.8:mService.addWindow()

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

  1. //WindowManagerService.java 
  2. public int addWindow(Session session, IWindow client, int seq, 
  3.         LayoutParams attrs, int viewVisibility, int displayId, Rect outFrame, 
  4.         Rect outContentInsets, Rect outStableInsets, Rect outOutsets, 
  5.         DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel, 
  6.         InsetsState outInsetsState) { 
  7.     int[] appOp = new int[1]; 
  8.     //检查权限,无权限不能添加窗口 
  9.     int res = mPolicy.checkAddPermission(attrs, appOp); 
  10.     if (res != WindowManagerGlobal.ADD_OKAY) { 
  11.         return res; 
  12.     } 
  13.  
  14.     boolean reportNewConfig = false
  15.     WindowState parentWindow = null
  16.     ... 
  17.     final int type = attrs.type; 
  18.     synchronized (mGlobalLock) { 
  19.         ... 
  20.         //获取窗口要添加到的DisplayContent。即显示在哪个屏幕上 
  21.         final DisplayContent displayContent = getDisplayContentOrCreate(displayId, attrs.token); 
  22.          
  23.         if (displayContent == null) { 
  24.             Slog.w(TAG_WM, "Attempted to add window to a display that does not exist: " 
  25.                     + displayId + ".  Aborting."); 
  26.             return WindowManagerGlobal.ADD_INVALID_DISPLAY; 
  27.         } 
  28.         if (!displayContent.hasAccess(session.mUid)) { 
  29.             Slog.w(TAG_WM, "Attempted to add window to a display for which the application " 
  30.                     + "does not have access: " + displayId + ".  Aborting."); 
  31.             return WindowManagerGlobal.ADD_INVALID_DISPLAY; 
  32.         } 
  33.  
  34.         if (mWindowMap.containsKey(client.asBinder())) { 
  35.             Slog.w(TAG_WM, "Window " + client + " is already added"); 
  36.             return WindowManagerGlobal.ADD_DUPLICATE_ADD; 
  37.         } 
  38.         //添加子窗口,父窗口必须存在。 
  39.         if (type >= FIRST_SUB_WINDOW && type <= LAST_SUB_WINDOW) { 
  40.             parentWindow = windowForClientLocked(null, attrs.token, false); 
  41.             if (parentWindow == null) { 
  42.                 Slog.w(TAG_WM, "Attempted to add window with token that is not a window: " 
  43.                       + attrs.token + ".  Aborting."); 
  44.                 return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN; 
  45.             } 
  46.             //这里可以看出WMS要求 窗口的层级 最多为两层 
  47.             if (parentWindow.mAttrs.type >= FIRST_SUB_WINDOW 
  48.                     && parentWindow.mAttrs.type <= LAST_SUB_WINDOW) { 
  49.                 Slog.w(TAG_WM, "Attempted to add window with token that is a sub-window: " 
  50.                         + attrs.token + ".  Aborting."); 
  51.                 return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN; 
  52.             } 
  53.         } 
  54.         if (type == TYPE_PRIVATE_PRESENTATION && !displayContent.isPrivate()) { 
  55.             Slog.w(TAG_WM, "Attempted to add private presentation window to a non-private display.  Aborting."); 
  56.             return WindowManagerGlobal.ADD_PERMISSION_DENIED; 
  57.         } 
  58.  
  59.         AppWindowToken atoken = null
  60.         final boolean hasParent = parentWindow != null
  61.         //获取WindowToken,对于子窗口使用父窗口的token。 
  62.         //通过attrs.token从mTokenMap取出:private final HashMap<IBinder, WindowToken> mTokenMap = new HashMap(); 
  63.         //关于Activity窗口:WindowToken,前面讲过ActivityRecord 创建时会创建AppWindowToken,这个过程中appToken和AppWindowToken被保存到mTokenMap中 
  64.         WindowToken token = displayContent.getWindowToken( 
  65.                 hasParent ? parentWindow.mAttrs.token : attrs.token); 
  66.  
  67.         // If this is a child window, we want to apply the same type checking rules as the 
  68.         // parent window type. 
  69.         final int rootType = hasParent ? parentWindow.mAttrs.type : type; 
  70.         boolean addToastWindowRequiresToken = false
  71.         //以下是WindowToken和窗口之间的关系 
  72.         if (token == null) { 
  73.             //以下窗口类型,WindowToken不能为空 
  74.             if (rootType >= FIRST_APPLICATION_WINDOW && rootType <= LAST_APPLICATION_WINDOW) { 
  75.                 Slog.w(TAG_WM, "Attempted to add application window with unknown token " 
  76.                       + attrs.token + ".  Aborting."); 
  77.                 return WindowManagerGlobal.ADD_BAD_APP_TOKEN; 
  78.             } 
  79.             if (rootType == TYPE_INPUT_METHOD) { 
  80.                 Slog.w(TAG_WM, "Attempted to add input method window with unknown token " 
  81.                       + attrs.token + ".  Aborting."); 
  82.                 return WindowManagerGlobal.ADD_BAD_APP_TOKEN; 
  83.             } 
  84.             if (rootType == TYPE_VOICE_INTERACTION) { 
  85.                 Slog.w(TAG_WM, "Attempted to add voice interaction window with unknown token " 
  86.                       + attrs.token + ".  Aborting."); 
  87.                 return WindowManagerGlobal.ADD_BAD_APP_TOKEN; 
  88.             } 
  89.             if (rootType == TYPE_WALLPAPER) { 
  90.                 Slog.w(TAG_WM, "Attempted to add wallpaper window with unknown token " 
  91.                       + attrs.token + ".  Aborting."); 
  92.                 return WindowManagerGlobal.ADD_BAD_APP_TOKEN; 
  93.             } 
  94.             if (rootType == TYPE_DREAM) { 
  95.                 Slog.w(TAG_WM, "Attempted to add Dream window with unknown token " 
  96.                       + attrs.token + ".  Aborting."); 
  97.                 return WindowManagerGlobal.ADD_BAD_APP_TOKEN; 
  98.             } 
  99.             if (rootType == TYPE_QS_DIALOG) { 
  100.                 Slog.w(TAG_WM, "Attempted to add QS dialog window with unknown token " 
  101.                       + attrs.token + ".  Aborting."); 
  102.                 return WindowManagerGlobal.ADD_BAD_APP_TOKEN; 
  103.             } 
  104.             if (rootType == TYPE_ACCESSIBILITY_OVERLAY) { 
  105.                 Slog.w(TAG_WM, "Attempted to add Accessibility overlay window with unknown token " 
  106.                         + attrs.token + ".  Aborting."); 
  107.                 return WindowManagerGlobal.ADD_BAD_APP_TOKEN; 
  108.             } 
  109.             if (type == TYPE_TOAST) { 
  110.                 // Apps targeting SDK above N MR1 cannot arbitrary add toast windows. 
  111.                 if (doesAddToastWindowRequireToken(attrs.packageName, callingUid, 
  112.                         parentWindow)) { 
  113.                     Slog.w(TAG_WM, "Attempted to add a toast window with unknown token " 
  114.                             + attrs.token + ".  Aborting."); 
  115.                     return WindowManagerGlobal.ADD_BAD_APP_TOKEN; 
  116.                 } 
  117.             } 
  118.             final IBinder binder = attrs.token != null ? attrs.token : client.asBinder(); 
  119.             final boolean isRoundedCornerOverlay = 
  120.                     (attrs.privateFlags & PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY) != 0; 
  121.             //token为空,除上述窗口类型,其他是允许的。此时新建WindowToken 
  122.             token = new WindowToken(this, binder, type, false, displayContent, 
  123.                     session.mCanAddInternalSystemWindow, isRoundedCornerOverlay); 
  124.         //token不为空,且是应用窗口类型,token需要时AppWindowToken类型 
  125.         } else if (rootType >= FIRST_APPLICATION_WINDOW && rootType <= LAST_APPLICATION_WINDOW) { 
  126.             //判断token是否是AppWindowToken类型 
  127.             //前面知道,Activity创建的是AppWindowToken,即获得的atoken非空 
  128.             atoken = token.asAppWindowToken(); 
  129.             if (atoken == null) { 
  130.                 Slog.w(TAG_WM, "Attempted to add window with non-application token " 
  131.                       + token + ".  Aborting."); 
  132.                 return WindowManagerGlobal.ADD_NOT_APP_TOKEN; 
  133.             } else if (atoken.removed) { 
  134.                 Slog.w(TAG_WM, "Attempted to add window with exiting application token " 
  135.                       + token + ".  Aborting."); 
  136.                 return WindowManagerGlobal.ADD_APP_EXITING; 
  137.             } else if (type == TYPE_APPLICATION_STARTING && atoken.startingWindow != null) { 
  138.                 Slog.w(TAG_WM, "Attempted to add starting window to token with already existing" 
  139.                         + " starting window"); 
  140.                 return WindowManagerGlobal.ADD_DUPLICATE_ADD; 
  141.             } 
  142.         //其他各种窗口类型处理 
  143.         } else if (rootType == TYPE_INPUT_METHOD) { 
  144.             ... 
  145.         }... 
  146.         //WindowState维护了所有窗口的信息,它是WMS实际管理的“窗口” 
  147.         //它与Z-Order密切相关(多个Window层叠布局),其属性mLayer 越大,窗口越靠前。 
  148.         final WindowState win = new WindowState(this, session, client, token, parentWindow, 
  149.                 appOp[0], seq, attrs, viewVisibility, session.mUid, 
  150.                 session.mCanAddInternalSystemWindow); 
  151.         if (win.mDeathRecipient == null) { 
  152.             // Client has apparently died, so there is no reason to 
  153.             // continue
  154.             Slog.w(TAG_WM, "Adding window client " + client.asBinder() 
  155.                     + " that is dead, aborting."); 
  156.             return WindowManagerGlobal.ADD_APP_EXITING; 
  157.         } 
  158.         ... 
  159.         origId = Binder.clearCallingIdentity(); 
  160.         //创建SurfaceSession,实现与SurfaceFlinger通信。参考2.9 简单说明下 
  161.         win.attach(); 
  162.         //将WindowState对象加入到mWindowMap中 
  163.         mWindowMap.put(client.asBinder(), win); 
  164.         win.initAppOpsState(); 
  165.         ... 
  166.         final AppWindowToken aToken = token.asAppWindowToken(); 
  167.         win.mToken.addWindow(win); 
  168.         win.applyAdjustForImeIfNeeded(); 
  169.         ... 
  170.     } 
  171.     ... 
  172.     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发出请求。

这时几处相关代码。 

  1. //WindowState.java 
  2. void attach() { 
  3.     if (localLOGV) Slog.v(TAG, "Attaching " + this + " token=" + mToken); 
  4.     mSession.windowAddedLocked(mAttrs.packageName); 
  5.  
  6. //Session.java 
  7. void windowAddedLocked(String packageName) { 
  8.     mPackageName = packageName; 
  9.     mRelayoutTag = "relayoutWindow: " + mPackageName; 
  10.     if (mSurfaceSession == null) { 
  11.         mSurfaceSession = new SurfaceSession(); 
  12.         ... 
  13.     } 
  14.     mNumWindow++; 
  15.  
  16. //ViewRootImpl.java     
  17. // These can be accessed by any thread, must be protected with a lock. 
  18. // Surface can never be reassigned or cleared (use Surface.clear()). 
  19. @UnsupportedAppUsage 
  20. public final Surface mSurface = new Surface(); 
  21. private final SurfaceControl mSurfaceControl = new SurfaceControl(); 

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

 

责任编辑:未丽燕 来源: 博客园精华区
相关推荐

2011-07-27 17:45:29

iPhone 模拟器 图片

2011-11-15 14:52:39

Mac OSWindows域

2021-05-26 14:39:27

FedoraLinux企业域

2019-11-07 09:20:36

Windows 10联系人Outlook

2015-12-01 09:23:14

Windows 10开始菜单网站

2011-07-18 10:32:39

域控制器

2019-04-17 14:32:39

加密文件Windows 10搜索结果

2018-08-15 14:56:51

windows 10引导菜单安全模式

2020-02-11 12:54:34

Linux日志文件消息

2018-08-10 09:22:20

Windows 10Windows照片

2019-03-06 15:02:56

应用程序Windows 10 右键单击菜单

2020-11-17 11:18:31

Docker

2021-05-31 08:59:22

Fuse.js动态搜索React

2021-01-11 12:50:07

Windows 10Windows操作系统

2020-10-13 10:43:09

Windows 10Windows操作系统

2023-06-08 15:17:13

iOSChatGPT

2023-05-24 10:04:36

微软ChatGPT人工智能

2022-03-14 08:54:04

NetlifyHTMLReact

2021-06-15 05:45:56

Linkerd annotations网络技术

2017-05-09 14:00:00

SambaWinbindUbuntu
点赞
收藏

51CTO技术栈公众号