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的介紹和窗口的添加就介紹完畢了,希望有所幫助,後面會繼續整理相關內容!

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