前言html
轉載請聲明,轉自【http://www.javashuo.com/article/p-srtoulvf-e.html】,多謝!java
目光所及,皆有Window!Window,顧名思義,窗口,它是應用與用戶交互的一個窗口,咱們所見到視圖,都對應着一個Window。好比屏幕上方的狀態欄、下方的導航欄、按音量鍵調出來音量控制欄、充電時的充電界面、屏幕中間的應用顯示區域(Activity)、Dialog、Toast、PopWindow、菜單等,都依附於對應的Window。能夠認爲Window是View的實際直接管理者,因此理解Window相關的知識,對理解Android的視圖機制有很大的幫助。android
本文將介紹Window相關的基礎知識,以及從源碼的角度分析WindowManager是如何將View呈如今界面的。本文主要包含以下內容:session
1、一個懸浮按鈕的demo架構
本demo實現了在屏幕上顯示一個懸浮的Button,並能夠跟隨手指的移動而移動。代碼以下:app
1 public void drawFloatButton() { 2 requestWindowPermission(); 3 final WindowManager windowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE); 4 final Button button = new Button(this); 5 button.setText("button"); 6 final WindowManager.LayoutParams params = new WindowManager.LayoutParams( 7 WindowManager.LayoutParams.WRAP_CONTENT, 8 WindowManager.LayoutParams.WRAP_CONTENT, 9 0, 10 0, 11 PixelFormat.TRANSPARENT); 12 params.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL 13 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE 14 | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED; 15 params.gravity = Gravity.LEFT | Gravity.TOP; 16 params.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; 17 params.x = 500; 18 params.y = 500; 19 windowManager.addView(button, params); 20 button.setOnTouchListener(new View.OnTouchListener() { 21 @Override 22 public boolean onTouch(View v, MotionEvent event) { 23 int rawX = (int) event.getRawX(); 24 int rawY = (int) event.getRawY(); 25 switch (event.getAction()) { 26 case MotionEvent.ACTION_MOVE: 27 params.x = rawX; 28 params.y = rawY; 29 windowManager.updateViewLayout(button, params); 30 break; 31 default: 32 break; 33 } 34 return false; 35 } 36 }); 37 }
若是是在Android6.0及以上,須要處理權限問題,在AndroidManifest.xml中聲明權限:ide
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
並在代碼中動態申請佈局
1 private void requestWindowPermission() { 2 //android 6.0或者以後的版本須要發一個intent讓用戶受權 3 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 4 if (!Settings.canDrawOverlays(getApplicationContext())) { 5 Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, 6 Uri.parse("package:" + getPackageName())); 7 startActivityForResult(intent, 100); 8 } 9 } 10 }
因爲該權限是一個敏感權限,因此啓動時系統還會彈出一個界面讓用戶手動開啓該權限:post
演示效果以下所示:學習
該Button是個懸浮按鈕,它並非經過在xml佈局文件中加入,而後經過Activity的setContentView方法將其顯示在界面中的,而是經過第19行的WindowManager.addView方法實現的。gif中能夠看到,該Button能夠顯示到Title區域,也能夠在app退出後(不殺死進程)獨立顯示在桌面上。手指滑動過程當中,經過第29行WindowManager.updateViewLayout更新Button的LayoutParams的座標參數,不斷更新該Button的位置。後續咱們會對這兩個方法作詳細分析。
2、Window相關特性
經過上述的demo,咱們能夠看到設置了LayoutParams的flags、type變量值,它們都是用來定義Window的特性的。
一、flag
flag變量用於設置window的屬性,控制其顯示特性,好比設置爲不獲取焦點、不接受觸屏事件、顯示在鎖屏之上等。在WindowManager.LayoutParams類中定義了不少的flag常量,來豐富Window的功能及屬性。
二、type
type變量用於表示Window的類型。系統規定了Window有三種類型,按取值由小到大依次爲:
(1)應用Window:對應着一個Activity,要建立應用窗口就必須在Activity中完成。層級範圍:1~99
(2)子Window:不能獨立存在,須要依附於特定的父Window。好比Dialog,PopWindow,菜單等。層級範圍:1000~1999
(3)系統Window:擁有系統權限才能建立的Window。好比Toast、系統狀態欄、導航欄、手機低電量提示、輸入法Window、搜索條、來電顯示等。系統Window是獨立於應用程序的,理論上講應用程序沒有權限建立系統Window,只有系統進程纔有。層級範圍:2000~2999
type的值越大,在Window體系中顯示的層級就越高。爲了理解這一點,咱們瞭解一下窗口的Z-Order管理。
手機上採用的是層疊式的佈局,它是一個三維空間,將手機水平方向做爲X軸,豎直方向做爲Y軸,垂直於屏幕由裏向外的方向爲Z軸,全部窗口就按照type值的順序排列在Z軸上,type值越大Z值也就越大。以下圖所示,因此係統Window每每會在上層顯示:
3、WindowManager關係網
WindowManager在系統架構中的位置
這裏必定要捋清楚ViewManager、WindowManager、WindowManagerImpl、WindowManagerGlobal之間的關係。下面先把關鍵代碼擺出來:
1 public interface ViewManager 2 { 3 public void addView(View view, ViewGroup.LayoutParams params); 4 public void updateViewLayout(View view, ViewGroup.LayoutParams params); 5 public void removeView(View view); 6 } 7 8 public interface WindowManager extends ViewManager{ 9 ...... 10 } 11 12 public final class WindowManagerImpl implements WindowManager { 13 private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance(); 14 @override 15 public void addView(view,params){ 16 mGlobal.addView(...); 17 } 18 public void updateViewLayout(view,params){ 19 mGlobal.updateViewLayout(...); 20 } 21 public void remove(view){ 22 mGlobal.remove(...); 23 } 24 } 25 26 public final class WindowManagerGlobal { 27 public void addView(...){ 28 ...... 29 } 30 public void updateViewLayout(...) { 31 ...... 32 } 33 public void removeView(...) { 34 ...... 35 } 36 }
看到上述這段代碼,相信你必定已經清楚了它們之間的關係了。ViewManager是個接口,其中定義了三個方法,在Window體系中添加、更新、移除View的過程看起來比較複雜,但其實都是圍繞着這三個方法展開的。WindowManager是個接口,繼承了ViewManager,擴展了功能。WindowManagerImpl是個實現類,其中包含了WindowManagerGlobal實例。WindowManagerGlobal則真正完成了addView、updateViewLayout、removeView過程。因此,在demo中咱們在使用WindowManager的實例調用addView,updateViewLayout方法時,實際上都是WindowManagerGlobal來完成的。這種方式稱爲橋接模式,這在系統源碼種很常見,Context機制中也是這種方式,橋接模式這裏就不展開講了。
第13行中經過WindowManagerGlobal.getInstance()來獲取的實例,這裏看看其實現:
1 //=========WindowManagerGlobal.java======== 2 private static WindowManagerGlobal sDefaultWindowManager; 3 public static WindowManagerGlobal getInstance() { 4 synchronized (WindowManagerGlobal.class) { 5 if (sDefaultWindowManager == null) { 6 sDefaultWindowManager = new WindowManagerGlobal(); 7 } 8 return sDefaultWindowManager; 9 } 10 }
可見,它是經過單例模式的方式對外提供的實例。若是對單例模式比較瞭解的話,就能看出這種實現方式是有問題的(對比DCL方式),但不明白系統源碼爲何要這樣實現,多是系統中調用該實例方法的場景比較簡單吧,我們本身在設計單例模式的時候可不能這樣作。
在WindowMangerGlobal.java中維護着四個很是重要的list:
1 //=========WindowManagerGlobal.java========= 2 //全部Window對應的View 3 private final ArrayList<View> mViews = new ArrayList<View>(); 4 //全部Window對應的ViewRootImpl 5 private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>(); 6 //全部Window對應的LayoutParams 7 private final ArrayList<WindowManager.LayoutParams> mParams = new ArrayList<WindowManager.LayoutParams>; 8 //正在被刪除的View,或者已經執行了removeView方法但尚未完成刪除操做的View 9 private final ArraySet<View> mDyingViews = new ArraySet<View>;
這四個list在addView、updateViewLayout、removeView的過程當中都會頻頻出現,理清楚這四個list和這三個方法,理解WindowManager工做機制時會清晰不少。
在下面的源碼中會詳細講到。
4、addView機制
1 //=========WindowManagerGlobal========= 2 public void addView(View view, ViewGroup.LayoutParams params, 3 Display display, Window parentWindow) { 4 ...... 5 final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params; 6 ...... 7 ViewRootImpl root; 8 View panelParentView = null; 9 synchronized (mLock) { 10 ...... 11 //view不能重複添加,若是要添加須要先removeView,不然拋異常 12 int index = findViewLocked(view, false); 13 if (index >= 0) { 14 if (mDyingViews.contains(view)) { 15 // Don't wait for MSG_DIE to make it's way through root's queue. 16 mRoots.get(index).doDie(); 17 } else { 18 throw new IllegalStateException("View " + view 19 + " has already been added to the window manager."); 20 } 21 // The previous removeView() had not completed executing. Now it has. 22 } 23 //子window 24 // If this is a panel window, then find the window it is being 25 // attached to for future reference. 26 if (wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW && 27 wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) { 28 final int count = mViews.size(); 29 for (int i = 0; i < count; i++) { 30 if (mRoots.get(i).mWindow.asBinder() == wparams.token) { 31 panelParentView = mViews.get(i); 32 } 33 } 34 } 35 root = new ViewRootImpl(view.getContext(), display); 36 view.setLayoutParams(wparams); 37 mViews.add(view); 38 mRoots.add(root);8 39 mParams.add(wparams); 40 // do this last because it fires off messages to start doing things 41 try { 42 root.setView(view, wparams, panelParentView); 43 } catch (RuntimeException e) { 44 // BadTokenException or InvalidDisplayException, clean up. 45 if (index >= 0) { 46 removeViewLocked(index, true); 47 } 48 throw e; 49 } 50 } 51 }
上述代碼中除了關鍵方法外,注意留意mViews、mRoots、mParams集合的操做。
1 //=========ViewRootImpl.java========== 2 /** 3 * We have one child 4 */ 5 public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) { 6 synchronized (this) { 7 if (mView == null) { 8 mView = view; 9 ...... 10 mAdded = true; 11 int res; /* = WindowManagerImpl.ADD_OKAY; */ 12 // Schedule the first layout -before- adding to the window 13 // manager, to make sure we do the relayout before receiving 14 // any other events from the system. 15 requestLayout(); 16 ...... 17 try { 18 ...... 19 res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes, 20 getHostVisibility(), mDisplay.getDisplayId(), 21 mAttachInfo.mContentInsets, mAttachInfo.mStableInsets, 22 mAttachInfo.mOutsets, mInputChannel); 23 } catch (RemoteException e) { 24 mAdded = false; 25 mView = null; 26 ...... 27 throw new RuntimeException("Adding window failed", e); 28 } finally { 29 ...... 30 } 31 ...... 32 } 33 } 34 }
第15行requestLayout()方法會執行View的繪製流程,在我以前的博文【朝花夕拾】Android自定義View篇之(一)View繪製流程中第三節有相關介紹。這裏簡單截取了一段UML圖,讀者明白其做用就能夠了,想深刻研究的能夠去這篇文章看看。
第19行的mWindowSession.addToDisplay(...)方法,addView的實際邏輯處理就在這裏面。咱們繼續分析mWindowSession和addToDisplay(...)的邏輯:
1 //========ViewRootImpl.java========= 2 public final class ViewRootImpl{ 3 final IWindowSession mWindowSession; 4 public ViewRootImpl(...){ 5 ...... 6 mWindowSession = WindowManagerGlobal.getWindowSession(); 7 ...... 8 } 9 } 10 11 //=======WindowManagerGlobal.java========== 12 public static IWindowSession getWindowSession() { 13 synchronized (WindowManagerGlobal.class) { 14 if (sWindowSession == null) { 15 try { 16 ...... 17 IWindowManager windowManager = getWindowManagerService(); 18 sWindowSession = windowManager.openSession( 19 new IWindowSessionCallback.Stub() { 20 @Override 21 public void onAnimatorScaleChanged(float scale) { 22 ValueAnimator.setDurationScale(scale); 23 } 24 }, 25 ...... 26 } catch (RemoteException e) { 27 throw e.rethrowFromSystemServer(); 28 } 29 } 30 return sWindowSession; 31 } 32 } 33 34 public static IWindowManager getWindowManagerService() { 35 synchronized (WindowManagerGlobal.class) { 36 if (sWindowManagerService == null) { 37 sWindowManagerService = IWindowManager.Stub.asInterface( 38 ServiceManager.getService("window")); 39 ...... 40 } 41 return sWindowManagerService; 42 } 43 } 44 45 //============WindowManagerService.java======= 46 @Override 47 public IWindowSession openSession(IWindowSessionCallback callback, IInputMethodClient client, 48 IInputContext inputContext) { 49 if (client == null) throw new IllegalArgumentException("null client"); 50 if (inputContext == null) throw new IllegalArgumentException("null inputContext"); 51 Session session = new Session(this, callback, client, inputContext); 52 return session; 53 } 54 55 public int addWindow(Session session, IWindow client, int seq, 56 WindowManager.LayoutParams attrs, int viewVisibility, int displayId, 57 Rect outContentInsets, Rect outStableInsets, Rect outOutsets, 58 InputChannel outInputChannel) { 59 //在wms中真正實現 60 ...... 61 } 62 63 //===========Session.java========= 64 final WindowManagerService mService; 65 public Session(WindowManagerService service, ......) { 66 mService = service; 67 ...... 68 } 69 70 @Override 71 public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs, 72 int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets, 73 Rect outOutsets, InputChannel outInputChannel) { 74 return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, 75 outContentInsets, outStableInsets, outOutsets, outInputChannel); 76 }
這裏面的代碼邏輯很容易理解,最後是把addView的工做交給了WMS的addWindow方法,因此真正添加view的邏輯是在WMS中完成的。這裏面邏輯比較複雜繁瑣,就不繼續深刻了,當目前爲止就已經清楚整個流程了。
5、updateViewLayout更新機制
1 //============WindowManagerGlobal.java========== 2 public void updateViewLayout(View view, ViewGroup.LayoutParams params) { 3 ...... 4 final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams)params; 5 view.setLayoutParams(wparams); 6 synchronized (mLock) { 7 int index = findViewLocked(view, true); 8 ViewRootImpl root = mRoots.get(index); 9 mParams.remove(index); 10 mParams.add(index, wparams); 11 root.setLayoutParams(wparams, false); 12 } 13 }
這裏面對mParams進行了操做,將舊有的LayoutParams進行了替換。第11行執行了更新邏輯:
1 //=============ViewRootImpl.java========== 2 void setLayoutParams(WindowManager.LayoutParams attrs, boolean newView) { 3 ...... //對新的LayoutParams參數作一些操做 4 scheduleTraversals(); //調用繪製流程 5 }
從上述過程能夠發現更新過程相對比較簡單,更新view的過程簡單來講就是,將新的LayoutParams替換掉舊的,並啓用繪製流程。
6、removeView移除機制
1 //============WindowManagerImpl.java========== 2 @Override 3 public void removeView(View view) { 4 mGlobal.removeView(view, false); 5 } 6 @Override 7 public void removeViewImmediate(View view) { 8 mGlobal.removeView(view, true); 9 }
WindowManagerImpl類中提供了兩個方法用於移除view,從方法名稱能夠推測其差異在於Immediate,也就是是否當即移除的意思。
1 //==========WindowManagerGlobal.java========= 2 public void removeView(View view, boolean immediate) { 3 ...... 4 synchronized (mLock) { 5 int index = findViewLocked(view, true); 6 View curView = mRoots.get(index).getView(); 7 removeViewLocked(index, immediate); 8 ...... 9 } 10 } 11 12 private void removeViewLocked(int index, boolean immediate) { 13 ViewRootImpl root = mRoots.get(index); 14 View view = root.getView(); 15 ...... 16 boolean deferred = root.die(immediate); 17 if (view != null) { 18 view.assignParent(null); 19 if (deferred) { 20 mDyingViews.add(view); 21 } 22 } 23 } 24 25 //========ViewRootImpl.java========= 26 private final static int MSG_DIE = 3; 27 final ViewRootHandler mHandler = new ViewRootHandler(); 28 /** 29 * @param immediate True, do now if not in traversal. False, put on queue and do later. 30 * @return True, request has been queued. False, request has been completed. 31 */ 32 boolean die(boolean immediate) { 33 // Make sure we do execute immediately if we are in the middle of a traversal or the damage 34 // done by dispatchDetachedFromWindow will cause havoc on return. 35 if (immediate && !mIsInTraversal) { 36 doDie(); 37 return false; 38 } 39 ...... 40 mHandler.sendEmptyMessage(MSG_DIE); 41 return true; 42 } 43 44 final class ViewRootHandler extends Handler { 45 ...... 46 @Override 47 public void handleMessage(Message msg) { 48 switch (msg.what) { 49 case MSG_DIE: 50 doDie(); 51 break; 52 ...... 53 } 54 } 55 }
如上代碼驗證了以前的猜測,removeView(View)和removeViewImmediate(View)的區別確實就在因而否當即移除。若是調用removeView,會經過handler來調用doDie(),而咱們知道handler對應了一個MessageQueue的,須要排隊等待執行的,這樣就實現了延後執行。而若是調用removeViewImmediate,若是當前沒有執行view的遍歷,那就直接調用doDie()了。
1 //==========ViewRootImpl.java======== 2 void doDie() { 3 ...... 4 synchronized (this) { 5 if (mRemoved) { 6 return; 7 } 8 mRemoved = true; 9 if (mAdded) { 10 dispatchDetachedFromWindow(); 11 } 12 ...... 13 mAdded = false; 14 } 15 WindowManagerGlobal.getInstance().doRemoveView(this); 16 } 17 //移除的主要邏輯都在該方法內完成 18 void dispatchDetachedFromWindow() { 19 mView.dispatchDetachedFromWindow(); 20 ...... 21 try { 22 mWindowSession.remove(mWindow); 23 } catch (RemoteException e) { 24 } 25 ...... 26 unscheduleTraversals();//中止繪製View 27 } 28 29 //======View.java====== 30 void dispatchDetachedFromWindow() { 31 ...... 32 onDetachedFromWindow(); 33 ...... 34 } 35 36 @CallSuper 37 protected void onDetachedFromWindow() { 38 //在view從window移除後會回調該方法,能夠在其中作一些資源回收的操做,如終止動畫、中止線程等。 39 } 40 41 //========WindowManagerGlobal.java======= 42 //該方法主要用於刷新數據 43 void doRemoveView(ViewRootImpl root) { 44 synchronized (mLock) { 45 final int index = mRoots.indexOf(root); 46 if (index >= 0) { 47 mRoots.remove(index); 48 mParams.remove(index); 49 final View view = mViews.remove(index); 50 mDyingViews.remove(view); 51 } 52 } 53 ...... 54 } 55 56 //==========Session.java======= 57 @Override 58 public void remove(IWindow window) { 59 mService.removeWindow(this, window); 60 } 61 62 //==========WindowManagerService.java======= 63 void removeWindow(Session session, IWindow client) { 64 synchronized(mWindowMap) { 65 WindowState win = windowForClientLocked(session, client, false); 66 if (win == null) { 67 return; 68 } 69 win.removeIfPossible(); 70 } 71 }
上述doDie()過程比較容易理解,第22行,參考addView中的邏輯分析可知,這裏也是IPC方式,流程最終進入到了WMS中的removeWindow方法,一樣到這裏我們不繼續往下深刻了。上述流程中,mRoots、mParams、mViews、mDyingViews四個集合也作了相應的操做。
上面講到的三個主要方法中,能夠看到它們都對mRoots、mParams、mViews、mDyingViews進行了刷新。
7、WMS簡介
在前面的addView和removeView機制中,咱們會發現具體的處理邏輯都交給了WMS(即WindowManagerService的簡寫)中,那WMS是什麼呢?
WMS是一個很是重要的系統服務。它支撐着視圖相關的各項業務,這很是符合軟件設計的單一職責原則,其業務和ActivityManagerService(簡稱AMS)一塊兒幾乎佔據了framework業務的半壁江山,可見其重要性。關於WMS的內容實在太多了,這裏只簡單介紹其大體功能以及啓動流程。
一、WMS功能介紹
WMS的大概功能以下圖所示:
這裏先簡單描述一下各項功能:
窗口管理:WMS是窗口管理者,結合WindowManager實現窗口的啓動、添加、刪除,以及管理窗口的大小、層級等。
窗口動畫:在窗口切換時,使用窗口動畫可使這個過程看起來更炫更生動,這個窗口動畫就是由WMS的動畫子系統來負責的,動畫子系統的管理者即是WindowAnimator。
輸入系統的中轉站: 觸摸設備屏幕上的窗口時會產生觸摸事件,InputManagerService(IMS)會對觸摸事件進行處理,找到最合適的窗口來反饋事件。而WMS是這些窗口的管理者,那天然而然就成爲了輸入系統的中轉站了。
Surface管理:窗口並不具有繪製功能,因此每一個窗口都須要一個Surface來供本身繪製,WMS就是這個Surface的管理者。
該部分參考:Android解析WindowManagerService(一)WMS的誕生
二、WMS的啓動流程
在我以前的文章:【系統之音】Android系統啓動篇 中有介紹過系統的啓動過程,其中提到過WMS的啓動時機,這裏從源碼入手再稍微詳細闡述一下:
1 //===========SystemServer.java========== 2 /** 3 * The main entry point from zygote. 4 */ 5 public static void main(String[] args) { 6 new SystemServer().run(); 7 } 8 9 private void run() { 10 ...... 11 startBootstrapServices(); 12 startCoreServices(); 13 startOtherServices(); 14 ...... 15 } 16 17 private void startOtherServices() { 18 ...... 19 WindowManagerService wm = null; 20 ...... 21 wm = WindowManagerService.main(context, inputManager, 22 mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL, 23 !mFirstBoot, mOnlyCore, new PhoneWindowManager()); 24 ServiceManager.addService(Context.WINDOW_SERVICE, wm); 25 ...... 26 }
在第21行中獲得了WMS的實例:
1 //=========WindowManagerService.java======= 2 private static WindowManagerService sInstance; 3 ...... 4 public static WindowManagerService main(final Context context, final InputManagerService im, 5 final boolean haveInputMethods, final boolean showBootMsgs, final boolean onlyCore, 6 WindowManagerPolicy policy) { 7 DisplayThread.getHandler().runWithScissors(() -> 8 sInstance = new WindowManagerService(context, im, haveInputMethods, showBootMsgs, 9 onlyCore, policy), 0); 10 return sInstance; 11 }
第7行調用了Handler的runWithScissors方法,該方法的做用是執行一個同步的task,即執行完第8行後纔會執行第10行,因此main方法返回的是一個WMS實例。
第24行就是一個將WMS加入到系統服務的過程:
1 //============ServiceManager.java========= 2 /** 3 * Place a new @a service called @a name into the service 4 * manager. 5 * 6 * @param name the name of the new service 7 * @param service the service object 8 */ 9 public static void addService(String name, IBinder service) { 10 try { 11 getIServiceManager().addService(name, service, false); 12 } catch (RemoteException e) { 13 Log.e(TAG, "error in addService", e); 14 } 15 } 16 17 private static IServiceManager sServiceManager; 18 private static IServiceManager getIServiceManager() { 19 if (sServiceManager != null) { 20 return sServiceManager; 21 } 22 // Find the service manager 23 sServiceManager = ServiceManagerNative 24 .asInterface(Binder.allowBlocking(BinderInternal.getContextObject())); 25 return sServiceManager; 26 }
這裏調用的addService就是一個IPC過程,若是有閱讀過AIDL實現Binder時編譯生成的代碼,看到ServiceManagerNative類後就會很是眼熟,它就是實現Binder的中間類。至於提供addService功能實現的Server是誰,筆者目前還未找到,因此先研究到這裏,後續研究透徹了再補上。
到這裏咱們就清楚了,在SystemServer進程啓動過程當中,WMS啓動,並經過ServiceManager中的addServie方法添加到系統中,供其它進程調用。
結語
關於Window、WindowManager、WMS等的內容很是多,這裏只寫了一些筆者在學習過程當中作的一些研究。 因爲筆者水平有限,若是有些地方描述不妥或者不許確的地方,請讀者不吝賜教。
本文參考資料有:
【朝花夕拾】Android自定義View篇之(一)View繪製流程
Android解析WindowManagerService(一)WMS的誕生
《Android開發藝術探索》