一、WMS 的作用
WMS 在 Android 系统的地位,它作为中间层,连接了上层的 View 框架和下层的 SurfaceFingler。
- WMS 主要职责
- 窗口管理:负责启动、添加、删除窗口,管理窗口大小、层级,核心成员有:WindowContainer、RootWindowContainer、DisplayContent、TaskStack、Task、AppWindowToken、WindowState;
- 窗口动画:由其子系统 WindowAnimator 管理;
- 输入系统中转站:通过对窗口的触摸从而产生触摸事件,由 InputMethodService(IMS)对触摸事件进行处理,它会寻找一个最合适的窗口处理触摸反馈信息;
- Surface 管理:为每个窗口分配一块 Surface,用于绘制要显示的内容。
- WMS重要的类
- WMS继承于IWindowManager.Stub,作为Binder服务端
- 成员变量mSessions保存所有的Session对象,Session继承于IWindowSession.Stub,作为Binder服务端.Session的创建在 WindowState 的attach方法中:mSession.windowAddedLocked
- 成员变量mPolicy,实例是PhoneWindowManager,用于实现各种窗口相关的策略
- 成员变量mWindowMap,保存所有的WindowState对象;以IBinder为key, 是IWindow的Bp端;
- 每个窗口都对应一个WindowState对象, 该对象的成员变量mClient用于跟应用端交互,成员变量mToken用于跟AMS交互,WindowState的attach方法与SurfaceFlinger通信。
- WindowManager与WindowManagerService通过Session进行通信,具体的实现由WMS处理。
- WindowManager实现类是WindowManagerImpl ;
- WindowManagerImpl 中成员变量 mParentWindow (Window),mGlobal (WindowManagerGlobal)
AMS,WMS之间数据是对应的,通过token值可以在AMS,WMS,应用程序之后来唯一确定一组Window,token是关联着一组窗口的,可能有多个WindowState的token值是相同的.
二、WMS 的启动流程
wms 是运行在systemsever 系统进程的,在启动system 进程的时候,去初始化了 WMS
/frameworks/base/services/java/com/android/server/SystemServer.java
private void startOtherServices(@NonNull TimingsTraceAndSlog t) {t.traceBegin("startOtherServices");WindowManagerService wm = null;t.traceBegin("StartInputManagerService");// wms与 InputManagerService 息息相关,创建 InputManagerService 对象inputManager = new InputManagerService(context);t.traceEnd();t.traceBegin("StartWindowManagerService");// WMS needs sensor service readymSystemServiceManager.startBootPhase(t, SystemService.PHASE_WAIT_FOR_SENSOR_SERVICE);// 1. 创建 WindowManagerService 对象wm = WindowManagerService.main(context, inputManager, !mFirstBoot, mOnlyCore,new PhoneWindowManager(), mActivityManagerService.mActivityTaskManager);// 将 WindowManagerService 和 InputManagerService 添加到服务中ServiceManager.addService(Context.WINDOW_SERVICE, wm, /* allowIsolated= */ false,DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PROTO);ServiceManager.addService(Context.INPUT_SERVICE, inputManager,/* allowIsolated= */ false, DUMP_FLAG_PRIORITY_CRITICAL);// 2. wms 与 ams 关联mActivityManagerService.setWindowManager(wm);// 3. 初始化完成wm.onInitReady();// 4. InputManagerService 设置回调,并启动 InputManagerService inputManager.setWindowManagerCallbacks(wm.getInputManagerCallback());inputManager.start();// 5. 调用 displayReady 方法wm.displayReady();// 6. 系统准备完毕,调用 systemReadywm.systemReady();final Configuration config = wm.computeNewConfiguration(DEFAULT_DISPLAY);
1. 创建 WindowManagerService 对象
WindowManagerService.main(context, inputManager, !mFirstBoot, mOnlyCore,new PhoneWindowManager(), mActivityManagerService.mActivityTaskManager);public static WindowManagerService main(final Context context, final InputManagerService im,final boolean showBootMsgs, final boolean onlyCore, WindowManagerPolicy policy,ActivityTaskManagerService atm) {// policy 是值是 new PhoneWindowManager(),继承了 WindowManagerPolicyreturn main(context, im, showBootMsgs, onlyCore, policy, atm,// 一个Supplier可以通过lambda表达式、方法引用或默认构造函数来实例化。
// Supplier在Java 8中被引入,属于java.util.function包
// transactionFactory 为 SurfaceControl.Transaction::new,创建 Transaction 对象
// 通过get 可以获取到对象 Transactionnew DisplayWindowSettingsProvider(), SurfaceControl.Transaction::new, Surface::new,SurfaceControl.Builder::new);}==========@VisibleForTestingpublic static WindowManagerService main(final Context context, final InputManagerService im,final boolean showBootMsgs, final boolean onlyCore, WindowManagerPolicy policy,ActivityTaskManagerService atm, DisplayWindowSettingsProviderdisplayWindowSettingsProvider, Supplier<SurfaceControl.Transaction> transactionFactory,Supplier<Surface> surfaceFactory,Function<SurfaceSession, SurfaceControl.Builder> surfaceControlFactory) {// 在 android.display 实例化 wms,所以wms 跑在android.display线程中 DisplayThread.getHandler().runWithScissors(() ->sInstance = new WindowManagerService(context, im, showBootMsgs, onlyCore, policy,atm, displayWindowSettingsProvider, transactionFactory, surfaceFactory,surfaceControlFactory), 0);return sInstance;}
PhoneWindowManager,主要是负责窗口管理的各种策略。在 android.display 实例化 wms,所以wms 跑在android.display线程中
/frameworks/base/services/core/java/com/android/server/DisplayThread.java
// ServiceThread 继承了 HandlerThread public final class DisplayThread extends ServiceThread {private static DisplayThread sInstance;private static Handler sHandler;private DisplayThread() {// DisplayThread runs important stuff, but these are not as important as things running in// AnimationThread. Thus, set the priority to one lower.// 线程名字为 "android.display",优先级为 -3super("android.display", Process.THREAD_PRIORITY_DISPLAY + 1, false /*allowIo*/);}private static void ensureThreadLocked() {if (sInstance == null) {sInstance = new DisplayThread();sInstance.start();sInstance.getLooper().setTraceTag(Trace.TRACE_TAG_SYSTEM_SERVER);// 创建handler,looper 为 thread "android.display" 的loopersHandler = new Handler(sInstance.getLooper());}}// 获取到handlerpublic static Handler getHandler() {synchronized (DisplayThread.class) {ensureThreadLocked();return sHandler;}}
handler 执行 runWithScissors 方法
/frameworks/base/core/java/android/os/Handler.java
public final boolean runWithScissors(@NonNull Runnable r, long timeout) {if (r == null) {throw new IllegalArgumentException("runnable must not be null");}if (timeout < 0) {throw new IllegalArgumentException("timeout must be non-negative");}// 当前looper 不相等if (Looper.myLooper() == mLooper) {r.run();return true;}// 将其pos 到 BlockingRunnableBlockingRunnable br = new BlockingRunnable(r);return br.postAndWait(this, timeout);}===========public BlockingRunnable(Runnable task) {mTask = task;}@Overridepublic void run() {try {mTask.run();} finally {synchronized (this) {mDone = true;
// 执行完则唤醒系统主线程notifyAll();}}}public boolean postAndWait(Handler handler, long timeout) {
// 将其增加到消息队列中if (!handler.post(this)) {return false;}synchronized (this) {if (timeout > 0) {
。。} else {while (!mDone) {try {
// 阻塞systemserver 主线程wait();} catch (InterruptedException ex) {}}}}return true;}}
DisplayThread 给系统使用的共享单例前台线程类,线程名字为 android.display,专门提供给WindowManager, DisplayManager, and InputManager来执行快速响应的实时操作。
执行构造函数
private WindowManagerService(Context context, InputManagerService inputManager,boolean showBootMsgs, boolean onlyCore, WindowManagerPolicy policy,ActivityTaskManagerService atm, DisplayWindowSettingsProviderdisplayWindowSettingsProvider, Supplier<SurfaceControl.Transaction> transactionFactory,Supplier<Surface> surfaceFactory,Function<SurfaceSession, SurfaceControl.Builder> surfaceControlFactory) {installLock(this, INDEX_WINDOW);// 锁机制与 atm 一致mGlobalLock = atm.getGlobalLock();
// 缓存 AtmSmAtmService = atm;mContext = context;
。。。
// 是否允许在低电量开启动画mAllowAnimationsInLowPowerMode = context.getResources().getBoolean(com.android.internal.R.bool.config_allowAnimationsInLowPowerMode);// 缓存 inputManagermInputManager = inputManager; // Must be before createDisplayContentLocked.mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);mSurfaceControlFactory = surfaceControlFactory;mTransactionFactory = transactionFactory;mSurfaceFactory = surfaceFactory;
// 获取 Transaction 对象mTransaction = mTransactionFactory.get();// policy 为:PhoneWindowManagermPolicy = policy;
// 创建 WindowAnimator 对象mAnimator = new WindowAnimator(this);
// 创建 RootWindowContainer 对象mRoot = new RootWindowContainer(this);final ContentResolver resolver = context.getContentResolver();mUseBLAST = Settings.Global.getInt(resolver,Settings.Global.DEVELOPMENT_USE_BLAST_ADAPTER_VR, 1) == 1;mSyncEngine = new BLASTSyncEngine(this);mWindowPlacerLocked = new WindowSurfacePlacer(this);
// 任务快照控制类mTaskSnapshotController = new TaskSnapshotController(this);mWindowTracing = WindowTracing.createDefaultAndStartLooper(this,Choreographer.getInstance());LocalServices.addService(WindowManagerPolicy.class, mPolicy);mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);// mH 为 final H mH = new H();mKeyguardDisableHandler = KeyguardDisableHandler.create(mContext, mPolicy, mH);mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);// 注册低电量观察者if (mPowerManagerInternal != null) {mPowerManagerInternal.registerLowPowerModeObserver(new PowerManagerInternal.LowPowerModeListener() {@Overridepublic int getServiceType() {return ServiceType.ANIMATION;}@Overridepublic void onLowPowerModeChanged(PowerSaveState result) {synchronized (mGlobalLock) {final boolean enabled = result.batterySaverEnabled;if (mAnimationsDisabled != enabled && !mAllowAnimationsInLowPowerMode) {mAnimationsDisabled = enabled;dispatchNewAnimatorScaleLocked(null);}}}});mAnimationsDisabled = mPowerManagerInternal.getLowPowerState(ServiceType.ANIMATION).batterySaverEnabled;}mScreenFrozenLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "SCREEN_FROZEN");mScreenFrozenLock.setReferenceCounted(false);mDisplayNotificationController = new DisplayWindowListenerController(this);mActivityManager = ActivityManager.getService();mActivityTaskManager = ActivityTaskManager.getService();mAmInternal = LocalServices.getService(ActivityManagerInternal.class);mAtmInternal = LocalServices.getService(ActivityTaskManagerInternal.class);mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);AppOpsManager.OnOpChangedInternalListener opListener =new AppOpsManager.OnOpChangedInternalListener() {@Override public void onOpChanged(int op, String packageName) {updateAppOpsState();}};mAppOps.startWatchingMode(OP_SYSTEM_ALERT_WINDOW, null, opListener);mAppOps.startWatchingMode(AppOpsManager.OP_TOAST_WINDOW, null, opListener);mPmInternal = LocalServices.getService(PackageManagerInternal.class);mTestUtilityService = LocalServices.getService(TestUtilityService.class);final IntentFilter suspendPackagesFilter = new IntentFilter();suspendPackagesFilter.addAction(Intent.ACTION_PACKAGES_SUSPENDED);suspendPackagesFilter.addAction(Intent.ACTION_PACKAGES_UNSUSPENDED);context.registerReceiverAsUser(new BroadcastReceiver() {@Overridepublic void onReceive(Context context, Intent intent) {final String[] affectedPackages =intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);final boolean suspended =Intent.ACTION_PACKAGES_SUSPENDED.equals(intent.getAction());updateHiddenWhileSuspendedState(new ArraySet<>(Arrays.asList(affectedPackages)),suspended);}}, UserHandle.ALL, suspendPackagesFilter, null, null);// Get persisted window scale settingmWindowAnimationScaleSetting = Settings.Global.getFloat(resolver,Settings.Global.WINDOW_ANIMATION_SCALE, mWindowAnimationScaleSetting);mTransitionAnimationScaleSetting = Settings.Global.getFloat(resolver,Settings.Global.TRANSITION_ANIMATION_SCALE,context.getResources().getFloat(R.dimen.config_appTransitionAnimationDurationScaleDefault));setAnimatorDurationScale(Settings.Global.getFloat(resolver,Settings.Global.ANIMATOR_DURATION_SCALE, mAnimatorDurationScaleSetting));mForceDesktopModeOnExternalDisplays = Settings.Global.getInt(resolver,DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS, 0) != 0;final String displaySettingsPath = Settings.Global.getString(resolver,DEVELOPMENT_WM_DISPLAY_SETTINGS_PATH);mDisplayWindowSettingsProvider = displayWindowSettingsProvider;if (displaySettingsPath != null) {mDisplayWindowSettingsProvider.setBaseSettingsFilePath(displaySettingsPath);}mDisplayWindowSettings = new DisplayWindowSettings(this, mDisplayWindowSettingsProvider);IntentFilter filter = new IntentFilter();// Track changes to DevicePolicyManager state so we can enable/disable keyguard.filter.addAction(ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null);mLatencyTracker = LatencyTracker.getInstance(context);mSettingsObserver = new SettingsObserver();mHoldingScreenWakeLock = mPowerManager.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE, TAG_WM);mHoldingScreenWakeLock.setReferenceCounted(false);mSurfaceAnimationRunner = new SurfaceAnimationRunner(mTransactionFactory,mPowerManagerInternal);mAllowTheaterModeWakeFromLayout = context.getResources().getBoolean(com.android.internal.R.bool.config_allowTheaterModeWakeFromWindowLayout);mTaskPositioningController = new TaskPositioningController(this, mInputManager, mActivityTaskManager, mH.getLooper());mDragDropController = new DragDropController(this, mH.getLooper());mHighRefreshRateDenylist = HighRefreshRateDenylist.create(context.getResources());mConstants = new WindowManagerConstants(this, DeviceConfigInterface.REAL);mConstants.start(new HandlerExecutor(mH));LocalServices.addService(WindowManagerInternal.class, new LocalService());mEmbeddedWindowController = new EmbeddedWindowController(mAtmService);mDisplayAreaPolicyProvider = DisplayAreaPolicy.Provider.fromResources(mContext.getResources());mDisplayHashController = new DisplayHashController(mContext);setGlobalShadowSettings();// anr 控制类,无响应,无焦点等mAnrController = new AnrController(this);mStartingSurfaceController = new StartingSurfaceController(this);mBlurController = new BlurController(mContext, mPowerManager);}
mH 为 final H mH = new H()
成员变量,因此WMS后面的消息也是运行在 android.display
线程中的。
2. wms 与 ams 关联
mActivityManagerService.setWindowManager(wm);
/frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
973 public void setWindowManager(WindowManagerService wm) {
974 synchronized (mGlobalLock) {
975 mWindowManager = wm;
// 缓存 RootWindowContainer
976 mRootWindowContainer = wm.mRoot;
977 mTempConfig.setToDefaults();
978 mTempConfig.setLocales(LocaleList.getDefault());
979 mConfigurationSeq = mTempConfig.seq = 1;
980 mRootWindowContainer.onConfigurationChanged(mTempConfig);
981 mLockTaskController.setWindowManager(wm);
982 mTaskSupervisor.setWindowManager(wm);// RootWindowContainer 设置 WindowManager
983 mRootWindowContainer.setWindowManager(wm);
984 }
985 }
3. 初始化完成 onInitReady
wm.onInitReady();
/frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
public void onInitReady() {initPolicy();// Add ourself to the Watchdog monitors.Watchdog.getInstance().addMonitor(this);createWatermark();showEmulatorDisplayOverlayIfNeeded();}=========private void initPolicy() {// 在ui 线程执行下列函数,"android.ui"UiThread.getHandler().runWithScissors(new Runnable() {@Overridepublic void run() {WindowManagerPolicyThread.set(Thread.currentThread(), Looper.myLooper());// 初始化 PhoneWindowManagermPolicy.init(mContext, WindowManagerService.this, WindowManagerService.this);}}, 0);}
// 初始化 PhoneWindowManager
/frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java
public void init(Context context, IWindowManager windowManager,WindowManagerFuncs windowManagerFuncs) {mContext = context;mWindowManager = windowManager;mWindowManagerFuncs = windowManagerFuncs;mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);mActivityTaskManagerInternal = LocalServices.getService(ActivityTaskManagerInternal.class);mInputManagerInternal = LocalServices.getService(InputManagerInternal.class);mDreamManagerInternal = LocalServices.getService(DreamManagerInternal.class);mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);mAppOpsManager = mContext.getSystemService(AppOpsManager.class);mDisplayManager = mContext.getSystemService(DisplayManager.class);mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);mPackageManager = mContext.getPackageManager();mHasFeatureWatch = mPackageManager.hasSystemFeature(FEATURE_WATCH);mHasFeatureLeanback = mPackageManager.hasSystemFeature(FEATURE_LEANBACK);mHasFeatureAuto = mPackageManager.hasSystemFeature(FEATURE_AUTOMOTIVE);mHasFeatureHdmiCec = mPackageManager.hasSystemFeature(FEATURE_HDMI_CEC);mAccessibilityShortcutController =new AccessibilityShortcutController(mContext, new Handler(), mCurrentUserId);mLogger = new MetricsLogger();mScreenOffSleepTokenAcquirer = mActivityTaskManagerInternal.createSleepTokenAcquirer("ScreenOff");Resources res = mContext.getResources();mWakeOnDpadKeyPress =res.getBoolean(com.android.internal.R.bool.config_wakeOnDpadKeyPress);mWakeOnAssistKeyPress =res.getBoolean(com.android.internal.R.bool.config_wakeOnAssistKeyPress);mWakeOnBackKeyPress =res.getBoolean(com.android.internal.R.bool.config_wakeOnBackKeyPress);// Init display burn-in protectionboolean burnInProtectionEnabled = context.getResources().getBoolean(com.android.internal.R.bool.config_enableBurnInProtection);// Allow a system property to override this. Used by developer settings.boolean burnInProtectionDevMode =SystemProperties.getBoolean("persist.debug.force_burn_in", false);if (burnInProtectionEnabled || burnInProtectionDevMode) {final int minHorizontal;final int maxHorizontal;final int minVertical;final int maxVertical;final int maxRadius;if (burnInProtectionDevMode) {minHorizontal = -8;maxHorizontal = 8;minVertical = -8;maxVertical = -4;maxRadius = (isRoundWindow()) ? 6 : -1;} else {
....// handler是跑在ui 线程mHandler = new PolicyHandler();
4. InputManagerService 设置回调,并启动 InputManagerService
inputManager.setWindowManagerCallbacks(wm.getInputManagerCallback());
inputManager.start();
public InputManagerCallback getInputManagerCallback() {return mInputManagerCallback;}// mInputManagerCallback 的值为对象 InputManagerCallback(this)final InputManagerCallback mInputManagerCallback = new InputManagerCallback(this);
setWindowManagerCallbacks 设置回调
/frameworks/base/services/core/java/com/android/server/input/InputManagerService.java
public void setWindowManagerCallbacks(WindowManagerCallbacks callbacks) {// 保证只有一个 callbackif (mWindowManagerCallbacks != null) {unregisterLidSwitchCallbackInternal(mWindowManagerCallbacks);}mWindowManagerCallbacks = callbacks;registerLidSwitchCallbackInternal(mWindowManagerCallbacks);}========void registerLidSwitchCallbackInternal(@NonNull LidSwitchCallback callback) {synchronized (mLidSwitchLock) {// 将 callback 保存到 mLidSwitchCallbacksmLidSwitchCallbacks.add(callback);// Skip triggering the initial callback if the system is not yet ready as the switch// state will be reported as KEY_STATE_UNKNOWN. The callback will be triggered in// systemRunning().if (mSystemReady) {boolean lidOpen = getSwitchState(-1 /* deviceId */, InputDevice.SOURCE_ANY, SW_LID)== KEY_STATE_UP;callback.notifyLidSwitchChanged(0 /* whenNanos */, lidOpen);}}}
然后启动inputmanagerservice
public void start() {Slog.i(TAG, "Starting input manager");nativeStart(mPtr);
5. 调用 displayReady 方法
wm.displayReady();
public void displayReady() {synchronized (mGlobalLock) {if (mMaxUiWidth > 0) {mRoot.forAllDisplays(displayContent -> displayContent.setMaxUiWidth(mMaxUiWidth));}applyForcedPropertiesForDefaultDisplay();mAnimator.ready();mDisplayReady = true;// Reconfigure all displays to make sure that forced properties and// DisplayWindowSettings are applied.mRoot.forAllDisplays(DisplayContent::reconfigureDisplayLocked);mIsTouchDevice = mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN);mIsFakeTouchDevice = mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FAKETOUCH);}try {mActivityTaskManager.updateConfiguration(null);} catch (RemoteException e) {}}
6. 系统准备完毕,调用 systemReady
wm.systemReady();
public void systemReady() {mSystemReady = true;// 调用 PhoneWindowManager.java 的 systemReadymPolicy.systemReady();mRoot.forAllDisplayPolicies(DisplayPolicy::systemReady);
// 快照控制类mTaskSnapshotController.systemReady();mHasWideColorGamutSupport = queryWideColorGamutSupport();mHasHdrSupport = queryHdrSupport();
// ui线程执行 loadSettingsUiThread.getHandler().post(mSettingsObserver::loadSettings);
整个启动过程有3个线程,systemserver主线程,”android.display”,”android.ui”,整个过程采用阻塞的方式(利用runWithScissors)执行,WMS.mH的Looper运行在”android.display”进程。
参考:
WMS启动流程分析 | Skytoby
WMS—启动过程 - Gityuan博客 | 袁辉辉的技术博客
Android渲染(一)_系统服务WMS启动过程(基于Android10) - 掘金