前言
WindowManagerService是Android系统中重要的服务,它是WindowManager的管理者,WindowManagerService无论对于应用开发还是Framework开发都是重要的知识点,究其原因是因为WindowManagerService有很多职责,每个职责都会涉及重要且复杂的系统,这使得WindowManagerService就像一个十字路口的交通灯一样,没有了这个交通灯,十字路口就无法正常通车,WindowManagerService的职责只要有以下几点。
1)窗口管理
WindowManagerService是窗口的管理者,它负责窗口的启动、添加和删除,另外窗口的大小和层级也是由WMS进行管理的。窗口管理的核心成员由DisplayContent、WindowToken和WindowState。
2)窗口动画
窗口间进行切换时,使用窗口动画可以显得更炫一些,窗口动画由WMS的动画子系统来负责,动画子系统的管理者为WindowAnimator。
3)输入系统的中转站
通过对窗口的触摸从而产生触摸事件,InputManagerService(IMS)会对触摸事件进行处理,它会寻找一个最合适的窗口来处理触摸反馈信息,WindowManagerService是窗口的管理者,它作为输入系统的中转站再合适不过。
4)Surface管理
窗口并不具备绘制的功能,因此每个窗口都需要有一块Surface来供自己绘制,为每个窗口分配Surface时由WMS来完成的。
从上图可以看出WindowManagerService很复杂,与它关联的有窗口管理、窗口动画、输入系统和Surface,它们每一个都是重要且负责的系统,在具体讲述这些功能之前,我们需要先梳理一下WindowManagerService的启动流程,这样才能更好的理解这个服务。
一、SystemServer的启动WindowManagerService
1、系统启动后会启动JVM虚拟机,SystemServer 是虚拟机的第一个进程,由init 进程fork 产生。主要用来启动frameworks层中的服务。SystemServer进程里面有个main()方法,main 方法如下:
frameworks/base/service/java/com/android/server/SystemServer.java
public final class SystemServer {
public static void main(String[] args) {
new SystemServer().run();
}
}
2、main 方法里启动了 run() 方法,而在 run 方法中调用了startOtherServices() 方法:
public final class SystemServer {
private void run() {
...代码省略...
try {
traceBeginAndSlog("StartServices");
startBootstrapServices();//启动引导服务
startCoreServices();//启动核心服务
startOtherServices();//启动其他服务
SystemServerInitThreadPool.shutdown();
} catch (Throwable ex) {
Slog.e("System", "******************************************");
Slog.e("System", "************ Failure starting system services", ex);
throw ex;
} finally {
traceEnd();
}
...代码省略...
}
}
3、startOtherServices方法和WindowManagerService服务启动相关的代码如下所示。
public final class SystemServer {
private ActivityManagerService mActivityManagerService;
private boolean mOnlyCore;
private boolean mFirstBoot;
private void startOtherServices() {
...代码省略...
WindowManagerService wm = null;
InputManagerService inputManager = null;
...代码省略...
boolean isWatch = context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH);
...代码省略...
traceBeginAndSlog("StartInputManagerService");
inputManager = new InputManagerService(context);//创建InputManagerService
traceEnd();
traceBeginAndSlog("StartWindowManagerService");
// WMS needs sensor service ready
ConcurrentUtils.waitForFutureNoInterrupt(mSensorServiceStart, START_SENSOR_SERVICE);
mSensorServiceStart = null;
//执行WMS的main方法,其内部会创建WMS对象实例
wm = WindowManagerService.main(context, inputManager,
mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,
!mFirstBoot, mOnlyCore, new PhoneWindowManager());
//将WMS注册到服务管理器中
ServiceManager.addService(Context.WINDOW_SERVICE, wm, /* allowIsolated= */ false,
DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PROTO);
//将IMS注册到服务管理器中
ServiceManager.addService(Context.INPUT_SERVICE, inputManager,
/* allowIsolated= */ false, DUMP_FLAG_PRIORITY_CRITICAL);
traceEnd();
traceBeginAndSlog("SetWindowManagerService");
mActivityManagerService.setWindowManager(wm);
traceEnd();
traceBeginAndSlog("WindowManagerServiceOnInitReady");
wm.onInitReady();//调用WMS的onInitReady方法
traceEnd();
...代码省略...
try {
wm.displayReady();//初始化屏幕显示信息
} catch (Throwable e) {
reportWtf("making display ready", e);
}
...代码省略...
if (!isWatch) {
traceBeginAndSlog("StartStatusBarManagerService");
try {
//状态栏管理服务
statusBar = new StatusBarManagerService(context, wm);
ServiceManager.addService(Context.STATUS_BAR_SERVICE, statusBar);
} catch (Throwable e) {
reportWtf("starting StatusBarManagerService", e);
}
traceEnd();
}
...代码省略...
try {
wm.systemReady();//通知WMS,系统的初始化工作已经完成
} catch (Throwable e) {
reportWtf("making Window Manager Service ready", e);
}
...代码省略...
}
}
二、WindowManagerService的启动
1、WindowManagerService的main方法如下
frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
public class WindowManagerService extends IWindowManager.Stub
implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {
public static WindowManagerService main(final Context context, final InputManagerService im,
final boolean haveInputMethods, final boolean showBootMsgs, final boolean onlyCore,
WindowManagerPolicy policy) {
DisplayThread.getHandler().runWithScissors(() ->
//创建WMS对象实例
sInstance = new WindowManagerService(context, im, haveInputMethods, showBootMsgs,
onlyCore, policy), 0);
return sInstance;
}
}
DisplayThread的run方法中创建了WMS的实例,这就意味着WMS的创建是运行在android.display线程中的。
关于DisplayThread对象我们主要关注以下几点:
1)DisplayThread其实是一个名为android.display的单例前台线程。
frameworks/base/services/core/java/com/android/server/DisplayThread.java
public final class DisplayThread extends ServiceThread {
private static DisplayThread sInstance;
private static Handler sHandler;
private DisplayThread() {
super("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);
sHandler = new Handler(sInstance.getLooper());
}
}
public static DisplayThread get() {
synchronized (DisplayThread.class) {
ensureThreadLocked();
return sInstance;
}
}
public static Handler getHandler() {
synchronized (DisplayThread.class) {
ensureThreadLocked();
return sHandler;
}
}
}
DisplayThread线程主要用来处理需要低延时显示的相关操作,并只能由WindowManager、DisplayManager和InputManager实时执行快速操作。
2)DisplayThread调用静态方法getHandler返回一个Handler对象实例,并调用了该对象的runWithScissors方法。
frameworks/base/core/java/android/os/Handler.java
public class Handler {
public final boolean runWithScissors(final Runnable r, long timeout) {
if (r == null) {
throw new IllegalArgumentException("runnable must not be null");
}
//对传入的Runnable的timeout进行判断,如果Runnable为null或者timeout小于0则抛出异常。
if (timeout < 0) {
throw new IllegalArgumentException("timeout must be non-negative");
}
//根据每个线程只有一个Looper的原理来判断当前线程(system_server线程)是否是Handler所指向的线程(android.display线程),如果是则直接执行Runnable的run方法。
if (Looper.myLooper() == mLooper) {
r.run();
return true;
}
//否则调用BlockingRunnable的postAndWait方法,并将当前线程的Runnable作为参数传递进去。
BlockingRunnable br = new BlockingRunnable(r);
return br.postAndWait(this, timeout);
}
}
runWithScissors方法会对传入的Runnable的timeout进行判断,如果Runnable为null或者timeout小于0则抛出异常;并根据每个线程只有一个Looper的原理来判断当前线程(system_server线程)是否是Handler所指向的线程(android.display线程),如果是则直接执行Runnable的run方法;否则调用BlockingRunnable的postAndWait方法,并将当前线程的Runnable作为参数传递进去。
3)BlockingRunnable是Handler的内部类。
public class Handler {
private static final class BlockingRunnable implements Runnable {
private final Runnable mTask;
private boolean mDone;
public BlockingRunnable(Runnable task) {
mTask = task;
}
@Override
public void run() {
try {
//执行传入的Runnable的run方法,其实就是执行前面创建WindowManagerService对象实例的那段代码
mTask.run();
} finally {
synchronized (this) {
mDone = true;
notifyAll();
}
}
}
public boolean postAndWait(Handler handler, long timeout) {
//将当前自己发送给Handler
if (!handler.post(this)) {
return false;
}
synchronized (this) {
if (timeout > 0) {
final long expirationTime = SystemClock.uptimeMillis() + timeout;
while (!mDone) {
long delay = expirationTime - SystemClock.uptimeMillis();
if (delay <= 0) {
return false; // timeout
}
try {
wait(delay);
} catch (InterruptedException ex) {
}
}
} else {
while (!mDone) {
try {
//timeout为0,且mDone为false,则会将当前自己挂起
wait();
} catch (InterruptedException ex) {
}
}
}
}
return true;
}
}
}
- BlockingRunnable的postAndWait方法首先将当前的BlockingRunnable添加到Handler的任务队列中,前面第2步我们知道runWithScissors方法的第二个参数为0,因此timeout等于0,这样如果mDone为false的话会一直调用注释3处的wait方法使得当前线程(system_server线程)进入等待状态。
- 在BlockingRunnable将自身传给Handler之后,在合适的时机会执行传入的Runnable的run方法,其实就是创建WMS对象实例(运行在android.display线程中),执行完毕后finally代码块中将mDone设置为true,并调用noifyAll方法唤醒处于等待状态的线程,这样就不会继续调用注释3处的wait方法。
结合以上两点可以得出一个结论,system_server线程会一直等待android.display线程执行完毕才开始执行system_server线程,这是因为android.display线程内部执行了WMS的创建,而WMS的创建优先级要更高。
2、接下来我们来查看一下WMS的构造方法。
frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
private WindowManagerService(Context context, InputManagerService inputManager,
boolean haveInputMethods, boolean showBootMsgs, boolean onlyCore,
WindowManagerPolicy policy) {
private WindowManagerService(Context context, InputManagerService inputManager,
boolean haveInputMethods, boolean showBootMsgs, boolean onlyCore,
WindowManagerPolicy policy) {
installLock(this, INDEX_WINDOW);
mContext = context;
mHaveInputMethods = haveInputMethods;
mAllowBootMessages = showBootMsgs;
mOnlyCore = onlyCore;
mLimitedAlphaCompositing = context.getResources().getBoolean(
com.android.internal.R.bool.config_sf_limitedAlpha);
mHasPermanentDpad = context.getResources().getBoolean(
com.android.internal.R.bool.config_hasPermanentDpad);
mInTouchMode = context.getResources().getBoolean(
com.android.internal.R.bool.config_defaultInTouchMode);
mDrawLockTimeoutMillis = context.getResources().getInteger(
com.android.internal.R.integer.config_drawLockTimeoutMillis);
mAllowAnimationsInLowPowerMode = context.getResources().getBoolean(
com.android.internal.R.bool.config_allowAnimationsInLowPowerMode);
mMaxUiWidth = context.getResources().getInteger(
com.android.internal.R.integer.config_maxUiWidth);
mDisableTransitionAnimation = context.getResources().getBoolean(
com.android.internal.R.bool.config_disableTransitionAnimation);
//保存传递进来的InputManagerService,这样WMS就持有了IMS的引用。
mInputManager = inputManager; // Must be before createDisplayContentLocked.
mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
//读取显示设备的设置
mDisplaySettings = new DisplaySettings();
mDisplaySettings.readSettingsLocked();
//policy其实就是PhoneWindowManager的对象实例,将其赋值给mPolicy
mPolicy = policy;
//创建WindowAnimator对象实例,用于管理所有的窗口动画
mAnimator = new WindowAnimator(this);
mRoot = new RootWindowContainer(this);
mWindowPlacerLocked = new WindowSurfacePlacer(this);
mTaskSnapshotController = new TaskSnapshotController(this);
mWindowTracing = WindowTracing.createDefaultAndStartLooper(context);
LocalServices.addService(WindowManagerPolicy.class, mPolicy);
if(mInputManager != null) {
final InputChannel inputChannel = mInputManager.monitorInput(TAG_WM);
mPointerEventDispatcher = inputChannel != null
? new PointerEventDispatcher(inputChannel) : null;
} else {
mPointerEventDispatcher = null;
}
//获取显示设备管理服务实例对象
mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
mKeyguardDisableHandler = new KeyguardDisableHandler(mContext, mPolicy);
//获取电源管理服务实例对象
mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
if (mPowerManagerInternal != null) {
mPowerManagerInternal.registerLowPowerModeObserver(
new PowerManagerInternal.LowPowerModeListener() {
@Override
public int getServiceType() {
return ServiceType.ANIMATION;
}
@Override
public void onLowPowerModeChanged(PowerSaveState result) {
synchronized (mWindowMap) {
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);
mAppTransition = new AppTransition(context, this);
mAppTransition.registerListenerLocked(mActivityManagerAppTransitionNotifier);
final AnimationHandler animationHandler = new AnimationHandler();
animationHandler.setProvider(new SfVsyncFrameCallbackProvider());
mBoundsAnimationController = new BoundsAnimationController(context, mAppTransition,
AnimationThread.getHandler(), animationHandler);
//获得AMS实例对象,并赋值给mActivityManager。
mActivityManager = ActivityManager.getService();
mAmInternal = LocalServices.getService(ActivityManagerInternal.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);
final IntentFilter suspendPackagesFilter = new IntentFilter();
suspendPackagesFilter.addAction(Intent.ACTION_PACKAGES_SUSPENDED);
suspendPackagesFilter.addAction(Intent.ACTION_PACKAGES_UNSUSPENDED);
context.registerReceiverAsUser(new BroadcastReceiver() {
@Override
public 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 setting
mWindowAnimationScaleSetting = Settings.Global.getFloat(context.getContentResolver(),
Settings.Global.WINDOW_ANIMATION_SCALE, mWindowAnimationScaleSetting);
mTransitionAnimationScaleSetting = Settings.Global.getFloat(context.getContentResolver(),
Settings.Global.TRANSITION_ANIMATION_SCALE,
context.getResources().getFloat(
R.dimen.config_appTransitionAnimationDurationScaleDefault));
setAnimatorDurationScale(Settings.Global.getFloat(context.getContentResolver(),
Settings.Global.ANIMATOR_DURATION_SCALE, mAnimatorDurationScaleSetting));
IntentFilter filter = new IntentFilter();
// Track changes to DevicePolicyManager state so we can enable/disable keyguard.
filter.addAction(ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
mContext.registerReceiver(mBroadcastReceiver, filter);
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();
mAllowTheaterModeWakeFromLayout = context.getResources().getBoolean(
com.android.internal.R.bool.config_allowTheaterModeWakeFromWindowLayout);
mTaskPositioningController = new TaskPositioningController(
this, mInputManager, mInputMonitor, mActivityManager, mH.getLooper());
mDragDropController = new DragDropController(this, mH.getLooper());
LocalServices.addService(WindowManagerInternal.class, new LocalService());
}
}
对于WindowManagerService的构造方法主要提一下以下几点。
1)保存传递进来的IMS,这样WMS就持有了IMS的引用。
2)读取显示设备的设置。
3) 保存传递近来的policy,其实就是PhoneWindowManager的对象实例,将其赋值给mPolicy。
4)创建WindowAnimator对象实例,赋值给mAnimator,用于管理所有的窗口动画。
5)获取显示设备管理服务,并赋值给mDisplayManager。
6)获取电源管理服务,并复制给mPowerManager。
7)获得AMS实例对象,并赋值给mActivityManager。
3、结合SystemServer的startOtherServices方法,在创建WindowManagerService对象实例之后,会执行该对象的onInitReady方法。
private WindowManagerService(Context context, InputManagerService inputManager,
boolean haveInputMethods, boolean showBootMsgs, boolean onlyCore,
WindowManagerPolicy policy) {
public void onInitReady() {
//窗口管理策略的接口类WindowManagerPolicy(WMP),它用来定义一个窗口策略所要遵循的通用规范。
initPolicy();
// 调用addMonitor方法将自身添加到watchdog中,Watchdog用来监控系统的一些关键服务的运行状况,
// 这些被监控的服务都会实现Watchdog.Monitor接口。Watchdog每分钟都会对被监控的系统服务进行检查,
// 如果被监控的系统服务出现了死锁,就会杀死Watchdog所在的进程,也就是SystemServer进程。
Watchdog.getInstance().addMonitor(this);
openSurfaceTransaction();
try {
createWatermarkInTransaction();
} finally {
closeSurfaceTransaction("createWatermarkInTransaction");
}
showEmulatorDisplayOverlayIfNeeded();
}
}
调用initPolicy方法初始化窗口管理策略的接口类WindowManagerPolicy(WMP),它用来定义一个窗口策略所要遵循的通用规范。调用addMonitor方法将自身添加到watchdog中,Watchdog用来监控系统的一些关键服务的运行状况,这些被监控的服务都会实现Watchdog.Monitor接口。Watchdog每分钟都会对被监控的系统服务进行检查,如果被监控的系统服务出现了死锁,就会杀死Watchdog所在的进程,也就是SystemServer进程。
4、继续来看WindowManagerService的initPolicy方法。
private WindowManagerService(Context context, InputManagerService inputManager,
boolean haveInputMethods, boolean showBootMsgs, boolean onlyCore,
WindowManagerPolicy policy) {
private void initPolicy() {
UiThread.getHandler().runWithScissors(new Runnable() {
@Override
public void run() {
WindowManagerPolicyThread.set(Thread.currentThread(), Looper.myLooper());
//前面有提过,mPolicy其实就是PhoneWindowManager对象实例。
mPolicy.init(mContext, WindowManagerService.this, WindowManagerService.this);
}
}, 0);
}
}
WMS的initPolicy方法和前面讲的WMS的main方法的实现类似,调用UiThread的静态方法getHandler,然后执行runWithScissors方法,传入需要执行的Runnable对象。
1)UiThread其实是一个名为android.ui的前台线程。
frameworks/base/services/core/java/com/android/server/UiThread.java
public final class UiThread extends ServiceThread {
private static final long SLOW_DISPATCH_THRESHOLD_MS = 100;
private static final long SLOW_DELIVERY_THRESHOLD_MS = 200;
private static UiThread sInstance;
private static Handler sHandler;
private UiThread() {
super("android.ui", Process.THREAD_PRIORITY_FOREGROUND, false /*allowIo*/);
}
@Override
public void run() {
// Make sure UiThread is in the fg stune boost group
Process.setThreadGroup(Process.myTid(), Process.THREAD_GROUP_TOP_APP);
super.run();
}
private static void ensureThreadLocked() {
if (sInstance == null) {
sInstance = new UiThread();
sInstance.start();
final Looper looper = sInstance.getLooper();
looper.setTraceTag(Trace.TRACE_TAG_SYSTEM_SERVER);
looper.setSlowLogThresholdMs(
SLOW_DISPATCH_THRESHOLD_MS, SLOW_DELIVERY_THRESHOLD_MS);
sHandler = new Handler(sInstance.getLooper());
}
}
public static UiThread get() {
synchronized (UiThread.class) {
ensureThreadLocked();
return sInstance;
}
}
public static Handler getHandler() {
synchronized (UiThread.class) {
ensureThreadLocked();
return sHandler;
}
}
}
2)关于UiThread.getHandler().runWithScissors方法的调用流程这里不做具体分析了,请类比前面的DisplayThread.getHandler().runWithScissors。总之会执行Runnable的run方法,调用WMP的init方法,WMP是一个接口,具体实现类是PhoneWindowManager,这里调用的其实就是PhoneWindowManager的init方法。PhoneWindowManager的init方法运行在android.ui线程中,它的优先级要高于initPolicy方法所在的android.display线程,因此android.display线程要等PhoneWindowManager的init方法执行完毕后,处于等待状态的android.display线程才会被唤醒从而继续执行下面的代码。
三、WMS的创建过程的3个线程
上面WMS创建的过程中有提到3个线程,分别是system_server、android.display和android.ui,下图是关于这三个线程的三个步骤。
1、首先在system_server线程中执行了SystemServer的startOtherServices方法,在startOtherServices方法中会调用WMS的main方,main方法会创建WMS,创建的过程是在android.display线程中实现的,由于创建WMS的优先级更高,因此system_server线程要等WMS创建完成后,处于等待状态的system_server线程才会被唤醒从而继续执行下面的代码。
2、在WMS的构造方法中会调用WMS的initPolicy方法,在initPolicy方法中又会调用PWM的init方法,PWM的init方法在android.ui线程中运行,它的优先级要高于android.display线程,因此"android.display"线程要等PWM的init方法执行完毕后,处于等待状态的android.display线程才会被唤醒从而继续执行下面的代码。
3、PWM的init方法执行完毕后,android.display线程就完成了WMS的创建,等待的system_server线程被唤醒后继续执行WMS的main方法后的代码逻辑,比如在前面第二部分第2步的注释7的地方,WMS的displayReady方法用来初始化屏幕显示信息。