Android进阶知识树——理解系统服务WindowManagerService

1、WMS

  • WMS主要功能
  1. 窗口管理:WMS负责整个系统窗口的启动、添加、删除工作,系统中每个程序的显示都由WMS管理
  2. 窗口动画管理:WMS负责窗口添加或切换时动画效果的执行
  3. 窗口输入管理:WMS负责对窗口的触摸事件进行反馈和处理
  4. Surface管理:每个Window都有对应的Surface负责窗口的显示,而WMS负责所有Surface的管理调度
  • WMS属性介绍
public class WindowManagerService extends IWindowManager.Stub
        implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {

    final WindowManagerPolicy mPolicy;
    final ArraySet<Session> mSessions = new ArraySet<>();
    final WindowHashMap mWindowMap = new WindowHashMap();
    final ArrayList<AppWindowToken> mFinishedStarting = new ArrayList<>();
    final H mH = new H();
    final WindowAnimator mAnimator;
    final InputManagerService mInputManager;
    final IActivityManager mActivityManager;
}
  1. mPolicy:WindowManagerPolicy的实例,WindowManagerPolicy是窗口管理策略的接口类,它的具体实现类为PhoneWindowManager
  2. mSessions:ArraySet对象,保存元素类型为Session,主要用于应用程序与WMS间的进程通信,每个应用程序对应一个Session,WMS内部保存这些Session,用来记录所有像WMS提出窗口服务的客户端
  3. mWindowMap:WindowHashMap对象,它内部以IBinder为Key,WindowState为Value,所以mWindowMap中保存着WMS中所有窗口的集合,而WindowState中保存着每个窗口的所有信息;
  4. mFinishedStarting:ArrayList对象,内部保存着已经启动窗口的WindowToken,WindowToken为窗口令牌,当程序像WMS申请创建Window时需要出具Token,程序中的每个Activity对应一个AppWindowToken(WindowToken的子类),WindowToken会将统一Actiivty的窗口组合在一起进行管理;
  5. mAnimator:WindowAnimator的对象,用于窗口的动画管理
  6. mH:H的实例,负责将任务添加到主线程中
  7. mInputManager:InputManagerService对象负责输入系统的管理,对窗口的触摸事件反馈和处理
  8. mActivityManager:内部保存AMS的对象

2、创建过程

由Android进程的启动过程知道,程序会同过JNI调用ZygiteInit.main()进入Java层,在main()方法中完成启动工作,其中重要的一步就是调用startSystemServer()启动系统服务,WMS就是其中一个系统服务,startSystemServer()使用反射最终调用SystemServer.main()方法(本文源码参照Android P),

public static void main(String[] args) {
       new SystemServer().run();
   }
 private void run() {
 mSystemServiceManager = new SystemServiceManager(mSystemContext);
 startBootstrapServices();
 startCoreServices();
 startOtherServices();
 }

在main方法中直接调用SystemService的run(),在run中首先创建SystemServiceManager对象,然后利用SystemServiceManager分别启动引导服务、核心服务、其他服务,WMS的启动就在startOtherServices()过程中;

  • startOtherServices()
inputManager = new InputManagerService(context);
 wm = WindowManagerService.main(context, inputManager,
       mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,
       !mFirstBoot, mOnlyCore, new PhoneWindowManager());
 ServiceManager.addService(Context.WINDOW_SERVICE, wm, false,
       DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PROTO);
 ServiceManager.addService(Context.INPUT_SERVICE, inputManager,
       false, DUMP_FLAG_PRIORITY_CRITICAL);

在startOtherServices()中首先创建InputManagerService对象,然后调用WindowManagerService.main()创建WMS对象,此时最后一个参数就是前面讲的窗口策略类PhoneWindowManager,最后调用ServiceManager.addService()将WMS和InputManagerService保存在ServiceManager中;

  • WindowManagerService.main()
public class WindowManagerService extends IWindowManager.Stub{
 public static WindowManagerService main(final Context context, final InputManagerService im,
            final boolean haveInputMethods, final boolean showBootMsgs, final boolean onlyCore,
            WindowManagerPolicy policy) {
        DisplayThread.getHandler().runWithScissors(() ->
                sInstance = new WindowManagerService(context, im, haveInputMethods, showBootMsgs,
                        onlyCore, policy), 0);
        return sInstance;
    }
}

从上面代码中看出WindowManagerService是IWindowManager接口的代理类,在main()方法中调用DisplayThread.getHandler().runWithScissors()方法执行WindowManagerService的创建;

DisplayThread.getHandler().runWithScissors()其实就是发送一个事件消息,DisplayThread继承ServiceThread,而ServiceThread继承与HandlerThread,熟悉HandlerThread的同学都知道它是Android内部封装好的工具类,DisplayThread.getHandler()就是利用HandlerThread内部创建的Looper而创建的Handler,所以本质上执行的是Handler.runWithScissors()

  • Handler.runWithScissors()
 public final boolean runWithScissors(final Runnable r, long timeout) {
        if (Looper.myLooper() == mLooper) {
            r.run();
            return true;
        }
        BlockingRunnable br = new BlockingRunnable(r);
        return br.postAndWait(this, timeout);
    }

runWithScissors()中接收到事件runnable后,先判断当前线程是否为创建Looper的线程,如果是则直接在当前线程执行,否则创建BlockingRunnable封装事件并发送到创建线程的队列中,由上面的启动知道此时程序执行在systemserver线程,所以此处会创建BlockingRunnable对象

  • BlockingRunnable
 private static final class BlockingRunnable implements Runnable {
883        private final Runnable mTask;
884        private boolean mDone;
886        public BlockingRunnable(Runnable task) {
887            mTask = task;
888        }
889
890        @Override
891        public void run() {
892            try {
893                mTask.run();
894            } finally {
895                synchronized (this) {
896                    mDone = true;
897                    notifyAll();
898                }
899            }
900        }
901
902        public boolean postAndWait(Handler handler, long timeout) {
903            if (!handler.post(this)) {
904                return false;
905            }
906
907            synchronized (this) {
908                if (timeout > 0) {
909                    final long expirationTime = SystemClock.uptimeMillis() + timeout;
910                    while (!mDone) {
911                        long delay = expirationTime - SystemClock.uptimeMillis();
912                        if (delay <= 0) {
913                            return false; // timeout
914                        }
915                        try {
916                            wait(delay);
917                        } catch (InterruptedException ex) {
918                        }
919                    }
920                } else {
921                    while (!mDone) {
922                        try {
923                            wait();
924                        } catch (InterruptedException ex) {
925                        }
926                    }
927                }
928            }
929            return true;
930        }
931    }

BlockingRunnable是Handler的内部类,是专门用来处理线程安全的类,在postAndWait中首先使用Handler发送事件到当前队列,然后调用wait()方法使当前线程进入等待,然后在run()中执行传入的事件,在事件执行结束后调用notifyAll()方法唤醒线程,结合这里的启动过程总结一下:

  1. 在WindowManagerService.main()中即在system_service线程中,使用DisplayThread初始化的Handler发送事件,执行WMS的创建
  2. 在DisplayThread初始化的Handler中,首先会调用wait()使system_service线程执行等待,然后发送post发送事件到当前队列,即执行display线程
  3. 在display线程执行创建后,调用notify唤醒system_service线程继续执行
  • WindowManagerService
 private WindowManagerService(Context context, InputManagerService inputManager,
            boolean haveInputMethods, boolean showBootMsgs, boolean onlyCore,
            WindowManagerPolicy policy) {
 mAnimator = new WindowAnimator(this);
 mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
 mActivityManager = ActivityManager.getService();
}

在搞清楚上面的线程和执行的顺序后,下面进入到WMS的创建过程中,在WindowManagerService的构造函数中完成了WindowAnimator、mDisplayManager、mActivityManager的初始化,到此WMS启动已经完成

3、添加过程

对与Window添加过程的前半部分见Android进阶知识树—— 理解WindowManager,本文只分析WMS执行的部分,上一文章中知道添加过程最终调用到WMS中的addWindow(),下面分步骤阅读源码;

  • 对添加窗口的检查
public int addWindow(){
  int res = mPolicy.checkAddPermission(attrs, appOp);//1
  final DisplayContent displayContent = getDisplayContentOrCreate(displayId);//2
  if (type >= FIRST_SUB_WINDOW && type <= LAST_SUB_WINDOW) {
                parentWindow = windowForClientLocked(null, attrs.token, false);
                if (parentWindow == null) {
                    return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN;
                }
                if (parentWindow.mAttrs.type >= FIRST_SUB_WINDOW
                        && parentWindow.mAttrs.type <= LAST_SUB_WINDOW) {
                    return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN;
                }
           }
}

在addWindow()中具体执行如下:

  1. 首先调用传入的窗口策略对窗口进行权限检查,具体执行在PhoneWindowManager中,
  2. 根据displayId获取要添加到对应的DisplayContent
  3. 根据添加的Type确定添加窗口的类型
  4. 调用windowForClientLocked根据窗口令牌token查找窗口是否已添加过
  • 创建WindowToken
    WindowToken token = displayContent.getWindowToken(
1191                    hasParent ? parentWindow.mAttrs.token : attrs.token);//1
final int rootType = hasParent ? parentWindow.mAttrs.type : type;
token = new WindowToken(this, binder, type, false, displayContent,
1247                        session.mCanAddInternalSystemWindow, isRoundedCornerOverlay);//2
atoken = token.asAppWindowToken();

总结:

  1. 调用displayContent.getWindowToken()获取WindowToken,然后判断是否有父窗口和父窗口的Type类型
  2. 创建窗口令牌WindowToken
  3. 将WindowToken转换为程序窗口令牌AppWindowToken
  • 窗口添加和数据保存
final WindowState win = new WindowState(this, session, client, token, parentWindow,appOp[0], seq, attrs, viewVisibility, session.mUid,
                    session.mCanAddInternalSystemWindow);// 1

 mPolicy.adjustWindowParamsLw(win, win.mAttrs, hasStatusBarServicePermission);//2

 res = mPolicy.prepareAddWindowLw(win, attrs);//3
 mWindowMap.put(client.asBinder(), win);//4
 win.mToken.addWindow(win);//5

addWindow()最后部分执行以下步骤:

  1. 创建WidowState保存Window的全部信息
  2. 调用mPolicy.adjustWindowParamsLw()根据窗口Type修改Window的LayoutParam
  3. 调用prepareAddWindowLw()执行Window的添加
  4. 以Binder为Key将WindowState对象保存在mWindowMap中
  5. 将WindowState保存在窗口的Token中

4、删除过程

关于Window的删除过程见Android进阶知识树—— 理解WindowManager,程序最终调用WMS的removeWindow(),在removeWindow()中首先获取到保存Window所有信息的WidowState对象,然后调用WindowState.removeIfPossible()方法,removeIfPossible中直接调用重载的方法,最终调用 removeImmediately();

void removeWindow(Session session, IWindow client) {
        synchronized(mWindowMap) {
            WindowState win = windowForClientLocked(session, client, false);
            if (win == null) {
                return;
            }
            win.removeIfPos();
        }
    }

  • removeImmediately()
@Override
void removeImmediately() {
     super.removeImmediately();
            mPolicy.removeWindowLw(this); 
1921        disposeInputChannel();
1923        mWinAnimator.destroyDeferredSurfaceLocked();
1924        mWinAnimator.destroySurfaceLocked();
1925        mSession.windowRemovedLocked();
1927        mClient.asBinder().unlinkToDeath(mDeathRecipient, 0);
1933        mService.postWindowRemoveCleanupLocked(this);
}

removeImmediately中主要做一些清理工作,移除当前Widow、通知当前窗口动画、移除mSession等;

到此这对WMS的介绍和窗口的添加就介绍完毕了,希望有所帮助,后面会继续整理相关内容!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章