Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> android6.0 Activity(三) Activity與WMS通信過程

android6.0 Activity(三) Activity與WMS通信過程

編輯:關於Android編程

Activity在窗口和ViewRootImpl創建後會請求WMS創建一個連接,請求WMS為其創建一個WindowState對象用來描述窗口狀態。Activity與WMS的連接分為2方面,

一方面是從Activity組件到WindowManagerService服務的連接,另一方面是從WindowManagerService服務到Activity組件的連接。從Activity組件到WindowManagerService服務的連接是以Activity組件所在的應用程序進程為單位來進行的。當一個應用程序進程在啟動第一個Activity組件的時候,它便會打開一個到WindowManagerService服務的連接,這個連接以應用程序進程從WindowManagerService服務處獲得一個實現了IWindowSession接口的Session代理對象來標志。從WindowManagerService服務到Activity組件的連接是以Activity組件為單位來進行的。在應用程序進程這一側,每一個Activity組件都關聯一個實現了IWindow接口的W對象,這個W對象在Activity組件的視圖對象創建完成之後,就會通過前面所獲得一個Session代理對象來傳遞給WindowManagerService服務,而WindowManagerService服務接收到這個W對象之後,就會在內部創建一個WindowState對象來描述與該W對象所關聯的Activity組件的窗口狀態,並且以後就通過這個W對象來控制對應的Activity組件的窗口狀態。

上述Activity組件與WindowManagerService服務之間的連接模型如圖

\

從圖還可以看出,每一個Activity組件在ActivityManagerService服務內部,都對應有一個ActivityRecord對象,這個ActivityRecord對象是Activity組件啟動的過程中創建的,用來描述Activity組件的運行狀態。這樣,每一個Activity組件在應用程序進程、WindowManagerService服務和ActivityManagerService服務三者之間就分別一一地建立了連接。在本文中,我們主要關注Activity組件在應用程序進程和WindowManagerService服務之間以及在WindowManagerService服務和ActivityManagerService服務之間的連接。

 

W類實現了IWindow接口,它的類實例是一個Binder本地對象。一個Activity組件在啟動的過程中,會創建一個關聯的ViewRootImpl對象,用來配合WindowManagerService服務來管理該Activity組件的窗口狀態。在這個ViewRoot對象內部,有一個類型為W的成員變量mWindow,它是在ViewRootImpl對象的創建過程中創建的。

ViewRootImpl類有一個靜態成員變量sWindowSession,它指向了一個實現了IWindowSession接口的Session代理對象。當應用程序進程啟動第一個Activity組件的時候,它就會請求WindowManagerService服務發送一個建立連接的Binder進程間通信請求。WindowManagerService服務接收到這個請求之後,就會在內部創建一個類型為Session的Binder本地對象,並且將這個Binder本地對象返回給應用程序進程,後者於是就會得到一個Session代理對象,並且保存在ViewRootImpl類的靜態成員變量sWindowSession中。

有了這個Session代理對象之後,應用程序進程就可以在啟動Activity組件的時候,調用它的成員函數add來將與該Activity組件所關聯的一個W對象傳遞給WindowManagerService服務,後者於是就會得到一個W代理對象,並且會以這個W代理對象來創建一個WindowState對象,即將這個W代理對象保存在新創建的WindowState對象的成員變量mClient中。

應用程序進程就可以通過保存在ViewRootImpl類的靜態成員變量sWindowSession所描述的一個Session代理對象所實現的IWindowSession接口來與WindowManagerService服務通信,例如:

1. 在Activity組件的啟動過程中,調用這個IWindowSession接口的成員函數add可以將一個關聯的W對象傳遞到WindowManagerService服務,以便WindowManagerService服務可以為該Activity組件創建一個WindowState對象。

2. 在Activity組件的銷毀過程中,調用這個這個IWindowSession接口的成員函數remove來請求WindowManagerService服務之前為該Activity組件所創建的一個WindowState對象。

3. 在Activity組件的運行過程中,調用這個這個IWindowSession接口的成員函數relayout來請求WindowManagerService服務來對該Activity組件的UI進行布局,以便該Activity組件的UI可以正確地顯示在屏幕中。

 

我們再來看W類的作用。W類實現了IWindow接口,因此,WindowManagerService服務就可以通過它在內部所創建的WindowState對象的成員變量mClient來要求運行在應用程序進程這一側的Activity組件來配合管理窗口的狀態,例如:

1. 當一個Activity組件的窗口的大小發生改變後,WindowManagerService服務就會調用這個IWindow接口的成員函數resized來通知該Activity組件,它的大小發生改變了。

2. 當一個Activity組件的窗口的可見性之後,WindowManagerService服務就會調用這個IWindow接口的成員函數dispatchAppVisibility來通知該Activity組件,它的可見性發生改變了。

3. 當一個Activity組件的窗口獲得或者失去焦點之後,WindowManagerService服務就會調用這個IWindow接口的成員函數windowFoucusChanged來通知該Activity組件,它的焦點發生改變了。

理解了Activity組件在應用程序進程和WindowManagerService服務之間的連接模型之後,接下來我們再通過簡要分析Activity組件在WindowManagerService服務和ActivityManagerService服務之間的連接。

Activity組件在WindowManagerService服務和ActivityManagerService服務之間的連接是通過一個AppWindowToken對象來描述的。AppWindowToken類的實現如圖所示:

\

每一個Activity組件在啟動的時候,ActivityManagerService服務都會內部為該Activity組件創建一個ActivityRecord對象,並且會以這個ActivityRecord對象所實現的一個IApplicationToken接口為參數,請求WindowManagerService服務為該Activity組件創建一個AppWindowToken對象,即將這個IApplicationToken接口保存在新創建的AppWindowToken對象的成員變量appToken中。同時,這個ActivityRecord對象還會傳遞給它所描述的Activity組件所運行在應用程序進程,於是,應用程序進程就可以在啟動完成該Activity組件之後,將這個ActivityRecord對象以及一個對應的W對象傳遞給WindowManagerService服務,後者接著就會做兩件事情:

1. 根據獲得的ActivityRecord對象的IApplicationToken接口來找到與之對應的一個AppWindowToken對象;

2. 根據獲得的AppWindowToken對象以及前面傳遞過來的W代理對象來為正在啟動的Activity組件創建一個WindowState對象,並且將該AppWindowToken對象保存在新創建的WindowState對象的成員變量mAppToken中。

順便提一下,AppWindowToken類是從WindowToken類繼續下來的。WindowToken類也是用來標志一個窗口的,不過這個窗口類型除了是應用程序窗口,即Activity組件窗口之外,還可以是其它的,例如,輸入法窗口或者壁紙窗口類型等,而AppWindowToken類只是用來描述Activity組件窗口。當WindowToken類是用來描述Activity組件窗口的時候,它的成員變量token指向的就是用來描述該Activity組件的一個ActivityRecord對象所實現的一個IBinder接口,而成員變量appWindowToken指向的就是其子類AppWindowToken對象。當另一方面,當WindowToken類是用來描述非Activity組件窗口的時候,它的成員變量appWindowToken的值就會等於null。這樣,我們就可以通過WindowToken類的成員變量appWindowToken的值來判斷一個WindowToken對象是否是用來描述一個Activity組件窗口的,即是否是用來描述一個應用程序窗口的。

上面所描述的Activity組件在ActivityManagerService服務和WindowManagerService服務之間以及應用程序進程和WindowManagerService服務之間的連接模型比較抽象,接下來,我們再通過三個過程來分析它們彼此之間的連接模型,如下所示:

1. ActivityManagerService服務請求WindowManagerService服務為一個Activity組件創建一個AppWindowToken對象的過程;

2. 應用程序進程請求WindowManagerService服務創建一個Session對象的過程;

3. 應用程序進程請求WindowManagerService服務為一個Activity組件創建一個WindowState對象的過程。

通過這三個過程的分析,我們就可以對應用程序進程、ActivityManagerService服務和WindowManagerService服務的關系有一個深刻的認識了。

 

 

一、APPWindowToken創建過程

Activity組件在啟動的過程中,會調用到ActivityStack類的成員函數startActivityLocked,該函數會請求WindowManagerService服務為當前正在啟動的Activity組件創建一個AppWindowToken對象。接下來,我們就從ActivityStack類的成員函數startActivityLocked開始分析一個AppWindowToken對象的創建過程,如圖所示:

\

我們啟動一個Activity的時候會調用ActivityStack的startActivityLocked函數,而在這個函數中最後在哪個會調用WMS的addAppToken來創建一個APPWindowToken

    final void startActivityLocked(ActivityRecord r, boolean newTask,
            boolean doResume, boolean keepCurTransition, Bundle options) {
        TaskRecord rTask = r.task;
        final int taskId = rTask.taskId;
        // mLaunchTaskBehind tasks get placed at the back of the task stack.
        if (!r.mLaunchTaskBehind && (taskForIdLocked(taskId) == null || newTask)) {
            // Last activity in task had been removed or ActivityManagerService is reusing task.
            // Insert or replace.
            // Might not even be in.
            insertTaskAtTop(rTask, r);
            mWindowManager.moveTaskToTop(taskId);
        }
        TaskRecord task = null;
        if (!newTask) {
            // If starting in an existing task, find where that is...
            boolean startIt = true;
            for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
                task = mTaskHistory.get(taskNdx);
                if (task.getTopActivity() == null) {
                    // All activities in task are finishing.
                    continue;
                }
                if (task == r.task) {
                    // Here it is!  Now, if this is not yet visible to the
                    // user, then just add it without starting; it will
                    // get started when the user navigates back to it.
                    if (!startIt) {
                        if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Adding activity " + r + " to task "
                                + task, new RuntimeException("here").fillInStackTrace());
                        task.addActivityToTop(r);
                        r.putInHistory();
                        mWindowManager.addAppToken(task.mActivities.indexOf(r), r.appToken,
                                r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,
                                (r.info.flags & ActivityInfo.FLAG_SHOW_FOR_ALL_USERS) != 0,
                                r.userId, r.info.configChanges, task.voiceSession != null,
                                r.mLaunchTaskBehind);

我們再來看看WMS的addAppToken函數,在WMS中創建了APPWindowToken然後保存在mTokenMap中。

    public void addAppToken(int addPos, IApplicationToken token, int taskId, int stackId,
            int requestedOrientation, boolean fullscreen, boolean showForAllUsers, int userId,
            int configChanges, boolean voiceInteraction, boolean launchTaskBehind) {
        ......
        synchronized(mWindowMap) {
            AppWindowToken atoken = findAppWindowToken(token.asBinder());//如果已經有了直接退出
            if (atoken != null) {
                Slog.w(TAG, "Attempted to add existing app token: " + token);
                return;
            }
            atoken = new AppWindowToken(this, token, voiceInteraction);//新建一個APPWindowToken
            atoken.inputDispatchingTimeoutNanos = inputDispatchingTimeoutNanos;
            atoken.appFullscreen = fullscreen;
            atoken.showForAllUsers = showForAllUsers;
            atoken.requestedOrientation = requestedOrientation;
            atoken.layoutConfigChanges = (configChanges &
                    (ActivityInfo.CONFIG_SCREEN_SIZE | ActivityInfo.CONFIG_ORIENTATION)) != 0;
            atoken.mLaunchTaskBehind = launchTaskBehind;
            if (DEBUG_TOKEN_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG, "addAppToken: " + atoken
                    + " to stack=" + stackId + " task=" + taskId + " at " + addPos);

            Task task = mTaskIdToTask.get(taskId);
            if (task == null) {
                task = createTaskLocked(taskId, stackId, userId, atoken);
            }
            task.addAppToken(addPos, atoken);

            mTokenMap.put(token.asBinder(), atoken);//保存在mTokenMap中 token為key(Activity的binder對象)

            // Application tokens start out hidden.
            atoken.hidden = true;
            atoken.hiddenRequested = true;
        }
    }

再來看看AppWindowToken的構造函數,它是WindowToken的子類,再調用父類構造函數的時候說明了自己是TYPE_APPLICATION類型的。參數_token指向的是一個ActivityRecord對象的IBinder接口,因此,AppWindowToken類的成員變量appToken描述的就是一個ActivityRecord對象。

    AppWindowToken(WindowManagerService _service, IApplicationToken _token,
            boolean _voiceInteraction) {
        super(_service, _token.asBinder(),
                WindowManager.LayoutParams.TYPE_APPLICATION, true);
        appWindowToken = this;
        appToken = _token;
        voiceInteraction = _voiceInteraction;
        mInputApplicationHandle = new InputApplicationHandle(this);
        mAnimator = service.mAnimator;
        mAppAnimator = new AppWindowAnimator(this);
    }

 

二、 Session的創建過程

應用程序進程在啟動第一個Activity組件的時候,就會請求與WindowManagerService服務建立一個連接,以便可以配合WindowManagerService服務來管理系統中的所有窗口。具體來說,就是應用程序進程在為它裡面啟動的第一個Activity組件的視圖對象創建一個關聯的ViewRootImpl對象的時候,就會向WindowManagerService服務請求返回一個類型為Session的Binder本地對象,這樣應用程序進程就可以獲得一個類型為Session的Binder代理對象,以後就可以通過這個Binder代理對象來和WindowManagerService服務進行通信了。

之前我們再分析WindowManagerGlobal的時候,先是新建了一個ViewRootImpl,然後才是調用其setView函數。

我們先看下構造函數,先是通過WindowManagerGlobal.getWindowSession獲取mWindowSession,然後新建了mWindow對象。

    public ViewRootImpl(Context context, Display display) {
        mContext = context;
        mWindowSession = WindowManagerGlobal.getWindowSession();
        mDisplay = display;
        mBasePackageName = context.getBasePackageName();

        mDisplayAdjustments = display.getDisplayAdjustments();

        mThread = Thread.currentThread();
        mLocation = new WindowLeaked(null);
        mLocation.fillInStackTrace();
        mWidth = -1;
        mHeight = -1;
        mDirty = new Rect();
        mTempRect = new Rect();
        mVisRect = new Rect();
        mWinFrame = new Rect();
        mWindow = new W(this);

我們來看下WindowManagerGlobal.getWindowSession函數,還是通過WMS獲取IWindowSession。

    public static IWindowSession getWindowSession() {
        synchronized (WindowManagerGlobal.class) {
            if (sWindowSession == null) {
                try {
                    InputMethodManager imm = InputMethodManager.getInstance();
                    IWindowManager windowManager = getWindowManagerService();
                    sWindowSession = windowManager.openSession(
                            new IWindowSessionCallback.Stub() {
                                @Override
                                public void onAnimatorScaleChanged(float scale) {
                                    ValueAnimator.setDurationScale(scale);
                                }
                            },
                            imm.getClient(), imm.getInputContext());
                } catch (RemoteException e) {
                    Log.e(TAG, "Failed to open window session", e);
                }
            }
            return sWindowSession;
        }
    }

WMS的openSession函數為每個Activity創建一個Session。

    @Override
    public IWindowSession openSession(IWindowSessionCallback callback, IInputMethodClient client,
            IInputContext inputContext) {
        if (client == null) throw new IllegalArgumentException("null client");
        if (inputContext == null) throw new IllegalArgumentException("null inputContext");
        Session session = new Session(this, callback, client, inputContext);
        return session;
    }

而這個Session也是一個Binder服務,這樣每個Activity都能找到屬於它的Session和WMS通信。

final class Session extends IWindowSession.Stub
        implements IBinder.DeathRecipient {

 

三、WindowState的創建過程

在Android系統中,WindowManagerService服務負責統一管理系統中的所有窗口,因此,當運行在應用程序進程這一側的Activity組件在啟動完成之後,需要與WindowManagerService服務建立一個連接,以便WindowManagerService服務可以管理它的窗口。具體來說,就是應用程序進程將一個Activitty組件的視圖對象設置到與它所關聯的一個ViewRootImpl對象的內部的時候,就會將一個實現了IWindow接口的Binder本地對象傳遞WindowManagerService服務。這個實現了IWindow接口的Binder本地對象唯一地標識了一個Activity組件,WindowManagerService服務接收到了這個Binder本地對象之後,就會將它保存在一個新創建的WindowState對象的內部,這樣WindowManagerService服務以後就可以通過它來和Activity組件通信,以便可以要求Activity組件配合來管理系系統中的所有窗口。

應用程序進程將一個Activity組件的視圖對象設置到與它所關聯的一個ViewRootImpl對象的內部是通過調用ViewRootImpl類的成員函數setView來實現的,因此,接下來我們就從ViewRootImpl類的成員函數setView開始分析Activity組件與WindowManagerService服務的連接過程,即一個WindowState對象的創建過程,如圖所示:

\

下面我們分析下ViewRootImpl的setView函數,在這個函數中調用了IWindowSession的addToDisplay函數

 

                    res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                            getHostVisibility(), mDisplay.getDisplayId(),
                            mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                            mAttachInfo.mOutsets, mInputChannel);
然後在實現函數中直接是調用了WMS的addWindow函數。

 

 

    @Override
    public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
            int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets,
            Rect outOutsets, InputChannel outInputChannel) {
        return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
                outContentInsets, outStableInsets, outOutsets, outInputChannel);
    }

 

WMS的addWindow我在Activity WMS ViewRootImpl三者關系(Activity創建窗口 按鍵分發等) 的WMS一節中比較詳細的分析過了。

3.1 創建WindowState對象

在addWindow會新建WindowState對象,下面我們來看下這個對象和它的構造函數。

mSession是WMS對應Activity的一個Binder服務對象

mClient是Activity的IWindow服務對象,用來和Activity通信

mToken指向一個WindowToken對象,通過它唯一的標識一個窗口

mAttrs:指向一個WindowManager.LayoutParams對象,使用參數a來初始化,通過它就可以知道當前當前所創建的WindowState對象所描述的窗口的布局參數。

mViewVisibility:這是一個整型變量,使用參數viewVisibility來初始化,表示當前所創建的WindowState對象所描述的窗口視圖的可見性。

mAlpha:這是一個浮點數,使用參數a所描述的一WindowManager.LayoutParams對象的成員變量alpha來初始化,表示當前所創建的WindowState對象所描述的窗口的Alpha通道。

    WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token,
           WindowState attachedWindow, int appOp, int seq, WindowManager.LayoutParams a,
           int viewVisibility, final DisplayContent displayContent) {
        mService = service;
        mSession = s;
        mClient = c;
        mAppOp = appOp;
        mToken = token;
        mOwnerUid = s.mUid;
        mWindowId = new IWindowId.Stub() {
            @Override
            public void registerFocusObserver(IWindowFocusObserver observer) {
                WindowState.this.registerFocusObserver(observer);
            }
            @Override
            public void unregisterFocusObserver(IWindowFocusObserver observer) {
                WindowState.this.unregisterFocusObserver(observer);
            }
            @Override
            public boolean isFocused() {
                return WindowState.this.isFocused();
            }
        };
        mAttrs.copyFrom(a);
        mViewVisibility = viewVisibility;

我們繼續看構造函數:

        if ((mAttrs.type >= FIRST_SUB_WINDOW &&
                mAttrs.type <= LAST_SUB_WINDOW)) {
            // The multiplier here is to reserve space for multiple
            // windows in the same type layer.
            mBaseLayer = mPolicy.windowTypeToLayerLw(
                    attachedWindow.mAttrs.type) * WindowManagerService.TYPE_LAYER_MULTIPLIER
                    + WindowManagerService.TYPE_LAYER_OFFSET;
            mSubLayer = mPolicy.subWindowTypeToLayerLw(a.type);
            mAttachedWindow = attachedWindow;
            if (WindowManagerService.DEBUG_ADD_REMOVE) Slog.v(TAG, "Adding " + this + " to " + mAttachedWindow);

            final WindowList childWindows = mAttachedWindow.mChildWindows;
            final int numChildWindows = childWindows.size();
            if (numChildWindows == 0) {
                childWindows.add(this);
            } else {
                boolean added = false;
                for (int i = 0; i < numChildWindows; i++) {
                    final int childSubLayer = childWindows.get(i).mSubLayer;
                    if (mSubLayer < childSubLayer
                            || (mSubLayer == childSubLayer && childSubLayer < 0)) {
                        // We insert the child window into the list ordered by the sub-layer. For
                        // same sub-layers, the negative one should go below others; the positive
                        // one should go above others.
                        childWindows.add(i, this);
                        added = true;
                        break;
                    }
                }
                if (!added) {
                    childWindows.add(this);
                }
            }

            mLayoutAttached = mAttrs.type !=
                    WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
            mIsImWindow = attachedWindow.mAttrs.type == TYPE_INPUT_METHOD
                    || attachedWindow.mAttrs.type == TYPE_INPUT_METHOD_DIALOG;
            mIsWallpaper = attachedWindow.mAttrs.type == TYPE_WALLPAPER;
            mIsFloatingLayer = mIsImWindow || mIsWallpaper;
        } else {
            // The multiplier here is to reserve space for multiple
            // windows in the same type layer.
            mBaseLayer = mPolicy.windowTypeToLayerLw(a.type)
                    * WindowManagerService.TYPE_LAYER_MULTIPLIER
                    + WindowManagerService.TYPE_LAYER_OFFSET;
            mSubLayer = 0;
            mAttachedWindow = null;
            mLayoutAttached = false;
            mIsImWindow = mAttrs.type == TYPE_INPUT_METHOD
                    || mAttrs.type == TYPE_INPUT_METHOD_DIALOG;
            mIsWallpaper = mAttrs.type == TYPE_WALLPAPER;
            mIsFloatingLayer = mIsImWindow || mIsWallpaper;
        }

這段代碼初始化WindowState類的以下七個成員變量:
-mBaseLayer:這是一個整型變量,用來描述一個窗口的基礎Z軸位置值,這個值是與窗口類型相關的。對於子窗口來說,它的值由父窗口的基礎Z軸位置值乘以常量TYPE_LAYER_MULTIPLIER再加固定偏移量TYPE_LAYER_OFFSET得到;對於非子窗口來說,它的值就是由窗口的類型來決定的。一個窗口的基礎Z軸位置值是通過調用WindowManagerService類的成員變量mPolicy所描述的一個窗口管理策略器的成員函數windowTypeToLayerLw來獲得的,而窗口管理策略器的成員函數windowTypeToLayerLw主要是根據窗口的類型來決定它的基礎Z軸位置值的。

-mSubLayer:這是一個整型變量,用來描述一個子窗口相對其父窗口的Z軸偏移值。對於非子窗口來說,這個值固定為0;對於子窗口來說,這個值是由WindowManagerService類的成員變量mPolicy所描述的一個窗口管理策略器的成員函數subWindowTypeToLayerLw來獲得的,而窗口管理策略器的成員函數subWindowTypeToLayerLw主要是根據子窗口的類型來決定它相對其父窗口的Z軸偏移值的。

-mAttachedWindow:指向一個WindowState對象,用來描述一個子窗口的父窗口。對於非子窗口來說,這個值固定為null;對於子窗口來說, 這個值使用參數attachedWindow來初始化。如果當前所創建的WindowState對象所描述的窗口是一個子窗口,那麼這個子窗口還會被添加用來描述它的父窗口的一WindowState對象的成員變量mChildWindows所描述的一個子窗口列表中去。

-mLayoutAttached:這是一個布爾變量,用來描述一個子窗口的視圖是否是嵌入在父窗口的視圖裡面的。對於非子窗口來說,這個值固定為false;對於子窗口來說,這個值只有子窗口的類型是非對話框時,它的值才會等於true,否則都等於false。

-mIsImWindow:這是一個布爾變量,表示當前所創建的WindowState對象所描述的窗口是否是一個輸入法窗口或者一個輸入法對話框。

-mIsWallpaper :這是一個布爾變量,表示當前所創建的WindowState對象所描述的窗口是否是一個壁紙窗口。

-mIsFloatingLayer :這是一個布爾變量,表示當前所創建的WindowState對象所描述的窗口是否是一個浮動窗口。當一個窗口是一個輸入法窗口、輸入法對話框口或者壁紙窗口時,它才是一個浮動窗口。

我們繼續向前看代碼:

        WindowState appWin = this;
        while (appWin.mAttachedWindow != null) {
            appWin = appWin.mAttachedWindow;
        }
        WindowToken appToken = appWin.mToken;
        while (appToken.appWindowToken == null) {
            WindowToken parent = mService.mTokenMap.get(appToken.token);
            if (parent == null || appToken == parent) {
                break;
            }
            appToken = parent;
        }
        mRootToken = appToken;
        mAppToken = appToken.appWindowToken;

這段代碼主要用來初始化成員變量mRootToken和mAppToken。
成員變量mRootToken的類型為WindowToken,用來描述當前所創建的WindowState對象所描述的窗口的根窗口。如果當前所創建的WindowState對象所描述的窗口是一個子窗口,那麼就先找到它的父窗口,然後再找到它的父窗口所屬的應用程序窗口,即Activity組件窗口,這時候找到的Activity組件窗口就是一個根窗口。如果當前所創建的WindowState對象所描述的窗口是一個子窗口,但是它不屬於任何一個應用程序窗口的,那麼它的父窗口就是一個根窗口。如果當前所創建的WindowState對象所描述的窗口不是一個子窗口,並且它也不屬於一個應用程序窗口的,那麼它本身就是一個根窗口。

成員變量mAppToken的類型為AppWindowToken,只有當成員變量mRootToken所描述的一個根窗口是一個應用程序窗口時,它的值才不等於null。

我們繼續向前看最後一段代碼:

        if (mAppToken != null) {
            final DisplayContent appDisplay = getDisplayContent();
            mNotOnAppsDisplay = displayContent != appDisplay;

            if (mAppToken.showForAllUsers) {
                // Windows for apps that can show for all users should also show when the
                // device is locked.
                mAttrs.flags |= FLAG_SHOW_WHEN_LOCKED;
            }
        }

        mWinAnimator = new WindowStateAnimator(this);
        mWinAnimator.mAlpha = a.alpha;

        mRequestedWidth = 0;
        mRequestedHeight = 0;
        mLastRequestedWidth = 0;
        mLastRequestedHeight = 0;
        mXOffset = 0;
        mYOffset = 0;
        mLayer = 0;
        mInputWindowHandle = new InputWindowHandle(
                mAppToken != null ? mAppToken.mInpu

這段代碼將以下十個成員變量的值設置為null或者0:
-mSurface:指向一個mSurface對象,用來描述窗口的繪圖表面。

-mRequestedWidth:這是一個整型變量,用來描述應用程序進程所請求的窗口寬度。

-mRequestedHeight:這是一個整型變量,用來描述應用程序進程所請求的窗口高度。

-mLastRequestedWidth:這是一個整型變量,用來描述應用程序進程上一次所請求的窗口寬度。
-mLastRequestedHeight:這是一個整型變量,用來描述應用程序進程上一次所請求的窗口高度。
-mXOffset:這是一個整型變量,用來描述壁紙窗口相對屏幕在X軸上的偏移量,對其它類型的窗口為說,這個值等於0。
-mYOffset:這是一個整型變量,用來描述壁紙窗口相對屏幕在Y軸上的偏移量,對其它類型的窗口為說,這個值等於0。
-mLayer:這是一個整型變量,用來描述窗口的Z軸位置值。
-mAnimLayer:這是一個整型變量,用來描述窗口的Z軸位置值,它的值可能等於mLayer的值,但是在以下四種情況中不相等。當一個窗口關聯有一個目標窗口的時候,那麼它的值就等於mLayer的值加上目標窗口指定的一個動畫層調整值;當一個窗口的根窗口是一個應用程序窗口時,那麼它的值就等於mLayer的值加上根窗口指定的一個動畫層調整值;當一個窗口是一個輸入法窗口時,那麼它的值就等於mLayer的值加上系統設置的輸入法動畫層調整值;當一個窗口是壁紙窗口時,那麼它的值就等於mLayer的值加上系統設置的壁紙動畫層調整值。
-mLastLayer:這是一個整型變量,用描述窗口上一次所使用的mAnimLayer的值。
至此,我們就分析完成WindowState的構造函數的實現了。

 

3.2 WindowState的attach函數

返回之前WindowManagerService類的成員函數addWindow中,接下來就會繼續調用前面所創建的一個WindowState對象的成員函數attach函數。我們先來看看這個函數在addWindow的調用的地方:

 

            WindowState win = new WindowState(this, session, client, token,
                    attachedWindow, appOp[0], seq, attrs, viewVisibility, displayContent);
            if (win.mDeathRecipient == null) {
                // Client has apparently died, so there is no reason to
                // continue.
                Slog.w(TAG, "Adding window client " + client.asBinder()
                        + " that is dead, aborting.");
                return WindowManagerGlobal.ADD_APP_EXITING;
            }

            if (win.getDisplayContent() == null) {
                Slog.w(TAG, "Adding window to Display that has been removed.");
                return WindowManagerGlobal.ADD_INVALID_DISPLAY;
            }

            mPolicy.adjustWindowParamsLw(win.mAttrs);
            win.setShowToOwnerOnlyLocked(mPolicy.checkShowToOwnerOnly(attrs));

            res = mPolicy.prepareAddWindowLw(win, attrs);
            if (res != WindowManagerGlobal.ADD_OKAY) {
                return res;
            }

            if (outInputChannel != null && (attrs.inputFeatures
                    & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
                String name = win.makeInputChannelName();
                InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
                win.setInputChannel(inputChannels[0]);
                inputChannels[1].transferTo(outInputChannel);

                mInputManager.registerInputChannel(win.mInputChannel, win.mInputWindowHandle);
            }

            // From now on, no exceptions or errors allowed!

            res = WindowManagerGlobal.ADD_OKAY;

            origId = Binder.clearCallingIdentity();

            if (addToken) {
                mTokenMap.put(attrs.token, token);
            }
            win.attach();

 

WindowState的attach函數會創建一個關聯的SurfaceSession對象,以便可以用來和SurfaceFlinger服務通信。下面看下這個函數:

    void attach() {
        if (WindowManagerService.localLOGV) Slog.v(
            TAG, "Attaching " + this + " token=" + mToken
            + ", list=" + mToken.windows);
        mSession.windowAddedLocked();
    }

在Session的windowAddedLocked函數中,直接新建了一個SurfaceSession對象。

    void windowAddedLocked() {
        if (mSurfaceSession == null) {
            mSurfaceSession = new SurfaceSession();
            mService.mSessions.add(this);
            if (mLastReportedAnimatorScale != mService.getCurrentAnimatorScale()) {
                mService.dispatchNewAnimatorScaleLocked(this);
            }
        }
        mNumWindow++;
    }

Session類的成員變量mSurfaceSession指向的是一個SurfaceSession對象,這個SurfaceSession對象是WindowManagerService服務用來與SurfaceSession服務建立連接的。Session類的成員函數windowAddedLocked首先檢查這個成員變量的值是否等於null。如果等於null的話,那麼就說明WindowManagerService服務尚未為當前正在請求增加窗口的應用程序進程創建一個用來連接SurfaceSession服務的SurfaceSession對象,因此,Session類的成員函數windowAddedLocked就會創建一個SurfaceSession對象,並且保存在成員變量mSurfaceSession中,並且將正在處理的Session對象添加WindowManagerService類的成員變量mSession所描述的一個HashSet中去,表示WindowManagerService服務又多了一個激活的應用程序進程連接。

Session類的另外一個成員變量mNumWindow是一個整型變量,用來描述當前正在處理的Session對象內部包含有多少個窗口,即運行在引用了當前正在處理的Session對象的應用程序進程的內部的窗口的數量。每當運行在應用程序進程中的窗口銷毀時,該應用程序進程就會通知WindowManagerService服務移除用來描述該窗口狀態的一個WindowState對象,並且通知它所引用的Session對象減少其成員變量mNumWindow的值。當一個Session對象的成員變量mNumWindow的值減少為0時,就說明該Session對象所描述的應用程序進程連接已經不需要了,因此,該Session對象就可以殺掉其成員變量mSurfaceSession所描述的一個SurfaceSession對象,以便可以斷開和SurfaceSession服務的連接。

接下來,我們就繼續分析SurfaceSession類的構造函數的實現,以便可以了解一個SurfaceSession對象是如何與SurfaceSession服務建立連接的。

    public SurfaceSession() {
        mNativeClient = nativeCreate();
    }

我們再來看下這個JNI函數,發現這塊和surfacefligner相關,SurfaceComposerClient類主要就是用來在應用程序進程和SurfaceFlinger服務之間建立連接的,以便應用程序進程可以為運行在它裡面的應用程序窗口請求SurfaceComposerClient創建繪制表面(Surface)的操作等。

static jlong nativeCreate(JNIEnv* env, jclass clazz) {
    SurfaceComposerClient* client = new SurfaceComposerClient();
    client->incStrong((void*)nativeCreate);
    return reinterpret_cast(client);
}


這樣,每一個Java層的SurfaceSession對象在C++層就都有一個對應的SurfaceComposerClient對象,因此,Java層的應用程序就可以通過SurfaceSession類來和SurfaceFlinger服務建立連接。

雖然到目前為止,我們已經為Android應用程序窗口創建了很多對象,但是我們仍然還有一個最重要的對象還沒有創建,那就是Android應用程序窗口的繪圖表面,即用來渲染UI的Surface還沒有創建。這個Surface是要請求SurfaceFlinger服務來創建的,我們將在下篇博客中分析。

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved