視窗管理是ANDROID架構一個重要部分,主要包括如下功能:
(1)Z-ordered的維護
(2)視窗的建立、銷毀
(3)視窗的繪製、布局
(4)Token管理,AppToken
(5)使用中視窗管理(FocusWindow)
(6)活動應用管理(FocusAPP)
(7)IME管理
(8)系統訊息收集與分發
這些功能主要有一個視窗管理服務和相應的用戶端來實現,實現機制是標準的ANDROID系統服務實現機制--基於代理模式和CORBA模式的實現機制:用戶端通過遠程代理使用BINDER驅動與服務進行互動.
視窗管理的整個類圖如下:
整個類圖包括用戶端和服務端兩大部分,服務端的類主要有WindowManagerService、WindowState、Session、SurfaceSession、Surface等主要類。WindowManagerService、Session派生自各自的本地樁(STUB)。而這些樁和連同遠端存取代理都是通過AIDL 檔案自動產生的,STUB提供了服務管理介面的本地IPC樁實現,且派生自Binder類,遠端存取代理Proxy提供了服務管理介面的遠端實現,代理根據本地服務的引用訪問本地服務,實現遠端訪問本地服務的目的。因此藉助STUB
提供IPC本地服務提供者,Proxy提供遠端提供者,可以實現用戶端訪問服務的目標。
如下是根據AIDL檔案自動產生的IWindowManager.java和IWindowSession.java代碼片斷。
public interface IWindowManager extends android.os.IInterface
{
public static abstract class Stub extends android.os.Binder implements android.view.IWindowManager
{
private static final java.lang.String DESCRIPTOR = "android.view.IWindowManager";
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
public static android.view.IWindowManager asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = (android.os.IInterface)obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof android.view.IWindowManager))) {
return ((android.view.IWindowManager)iin);
}
return new android.view.IWindowManager.Stub.Proxy(obj);
}
public android.os.IBinder asBinder()
{
return this;
}
@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
{
switch (code)
{
}
}
Proxy(android.os.IBinder remote)
{
mRemote = remote;
}
public android.os.IBinder asBinder()
{
return mRemote;
}
public boolean startViewServer(int port) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(port);
mRemote.transact(Stub.TRANSACTION_startViewServer, _data, _reply, 0);//通過服務的遠端引用發出訪問請求。
}
}
用戶端都通過如下介面獲得視窗管理服務遠端代理對象,該介面首先通過ServiceManager(0號服務)的getService介面使用視窗管理服務在ServiceManager中登記時使用的服務名字獲得視窗管理服務的引用,並傳進IWindowManager.Stub.asInterface 獲得一個視窗管理服務遠端代理對象,然後使用該遠端代理對象訪問視窗管理服務。
static IWindowManager getWindowManager() {
synchronized (sStaticInit) {
if (sWindowManager == null) {
sWindowManager = IWindowManager.Stub.asInterface(
ServiceManager.getService("window"));
}
return sWindowManager;
}
}
Session對象也是服務端提供的供用戶端可以訪問的對象,服務端使用Session對象指示一個用戶端與視窗管理服務互動實現視窗操作的會話,通常為每個與視窗管理互動的進程開啟一個Session對象,在服務端維護一個Session對象列表管理每一個Session,在Session會話期間,用戶端可以通過該Session對象與視窗管理服務實現視窗互動,如視窗的建立、銷毀、繪製、布局等,保證一個Session期間視窗狀態的一致。
Session對象在一個進程建立第一個視窗時使用視窗管理介面的openSession介面建立,第一個視窗建立期間也建立一個SurfaceSession對象用來實現視窗和視圖繪製操作。SurfaceSession對象用來與SurfaceFliger 服務建立串連,實現視窗和視圖在顯示硬體上的實際輸出工作。
服務端的Surface類是一個處理視窗輸出的對象,視窗和視圖使用Surface類進行實際的繪製.
服務端為每個視窗建立一個Surface對象,並在該對象中通過JNI建立一個C++層負責繪製的SurfaceControl對象,並把該Surface對象建立的SurfaceControl對象的引用傳給用戶端的Surface對象中,因此用戶端的Surface對象就可以使用和服務端Surface對象一樣的SurfaceControl對象進行繪製控制了.
服務端使用WindowState對象代表每一個視窗,每一個視窗的WindowState對象依據視窗的Z-ordered 放在mWindows數組中,也根據用戶端視窗對應的W類對象放到mWindowMap中。
final ArrayList<WindowState> mWindows;
mWindowMap.put(client.asBinder(), win);
每個視窗都對應一個WindowToken標記和AppWindowToken標記,服務端使用WindowToken唯一標識每一個視窗,並在addWindow函數中根據標示用戶端視窗的attrs.token為索引值儲存到視窗服務的HashMap 變數中mTokenMap.
mTokenMap.put(attrs.token, token);
attrs.token 是視窗布局參數中LayoutParams的一個binder 對象,在用戶端LocalWindowManager建立視窗addView時賦值,主視窗類型對應ACTIVITY的AppToken,子視窗類型對應主視圖的WindowToken。
public static class LayoutParams extends ViewGroup.LayoutParams
implements Parcelable {
public IBinder token = null;
}
使用AppWindowToken對象標識與視窗綁定的ACTIVITY, 在ACTIVITY啟動時賦值,並也依據對應視窗的Z-ordered放在mAppTokens數組中.
final ArrayList<AppWindowToken> mAppTokens = new ArrayList<AppWindowToken>();
用戶端負責視窗操作的主要有四個類 :
ViewRootImpl 視圖處理類,繼承自Handler,實現用戶端視窗及VIEW與視窗管理服務的互動和事件處理,因此ViewRootImpl是一個中介模式的採用。內部也有一個W類對象mWindow,派生自IWindow.Stub,是代表用戶端視窗的一個樁對象,視窗管理服務通過該對象與用戶端互動。用戶端與視窗服務開啟的會話儲存在sWindowSession變數中,因此用戶端使用sWindowSession與視窗管理服務發送請求,視窗管理服務使用mWindow向用戶端回送應答,藉助ViewRootImpl的兩個BINDER對象實現用戶端與視窗服務服務的雙向互動。
WindowManagerImpl是用戶端WindowManager管理介面的實現,用來通過ViewRootImpl發送視窗的建立、銷毀和布局請求等。
VIEW類是視圖的基類,視圖的主 View通過AttachInfo對象藉助ViewRootImpl綁定到視窗,ViewRootImpl也作為主視圖的ViewParent。AttachInfo是視圖的內部類
下面是一個開啟一個視窗的順序圖表:
1 )用戶端在建立視窗時調用getWindowManager獲得本地視窗管理對象,並調用其addView函數,在這裡為視窗的布局參數賦值,如視窗標題、包名字、token值、flag值等;
2)接著調用本地視窗管理對象的超類CompatModeWrapper的addView函數;
3)CompatModeWrapper是WindowManagerImpl的封裝類,採用了橋接模式,達到實現和抽象的分離目的. 因此CompatModeWrapper函數addView轉而調用WindowManagerImpl的addView函數;
4)WindowManagerImpl的addView函數首先查看要add的視圖是否已經存在,若不存在時執行個體化一個ViewRootImpl對象,並把view和ViewRootImpl對象及布局參數儲存到本地數組中,接著調用ViewRootImpl對象的setView函數;
5)ViewRootImpl對象的setView函數首先請求進行視窗的第一次布局(調用requestLayout),然後根據視窗屬性是否支援輸入執行個體化一個InputChannel,然後通過服務端遠程代理對象sWindowSession向服務端發出建立視窗的請求(調用其add介面);最後還要registerInputChannel和把視圖assignParent;
6)服務端的Session對象收到addwindow的請求,就調用視窗管理服務的addWindow函數來完成建立視窗的任務,完成實際建立視窗的工作。首先執行個體化一個WindowState對象代表建立的視窗,接著使用用戶端視窗的BINDER對象(W對象)為索引值把WindowState對象放入mWindowMap中,並根據Z-ORDER放入WindowState的數組中,還要調用WindowState對象的attach函數與Session完成綁定,並在SurfaceSession沒有建立時完成建立;然後建立或獲得WindowToken,並使用傳進來的用戶端視窗布局參數中的token值把WindowToken放入mTokenMap中;最後根據視窗能否能夠接收索引值更新焦點視窗。
歡迎轉載,轉載時請尊重原創註明出處。