上一篇文章講到了Client端窗口添加流程,本文接著上文往下講,講一下Server端的窗口添加流程。
1. WindowManagerService#grantInputChannel
? ? ? ? 由grantInputChannel我們可以看到,Client端傳入了session對象, 發起者Uid-callingUid,發起者pid-callingPid, 要顯示屏幕的displayId, 要顯示的圖層surface,用于返回到客戶端窗口,讓WMS使用它來通知客戶端的IWindow對象window,窗口的flags, 窗口的privateFlags,窗口的inputFeatures以及窗口類型,windowToken,以及InputChannel,用戶應用端和WMS端雙方互相通信的通路已經鋪好了。
/**
將 InputChannel 分配給 SurfaceControl,并將其配置為根據其屏幕上的幾何圖形接收觸摸輸入。
由 WindowlessWindowManager 用于啟用 SurfaceControl 嵌入視圖的輸入。*/void grantInputChannel(Session session, int callingUid, int callingPid,int displayId, SurfaceControl surface, IWindow window, IBinder hostInputToken,int flags, int privateFlags, int inputFeatures, int type, IBinder windowToken,IBinder focusGrantToken, String inputHandleName, InputChannel outInputChannel) {final int sanitizedType = sanitizeWindowType(session, displayId, windowToken, type);final InputApplicationHandle applicationHandle;final String name;final InputChannel clientChannel;synchronized (mGlobalLock) {
//EmbeddedWindowController是用于跟蹤嵌入式窗口。
// 如果嵌入的窗口沒有收到輸入,則窗口管理器不會跟蹤它。但是,如果他們確實收到輸入,我們會跟蹤調用 PID 以歸咎于正確的應用和主機窗口以發送 pointerDownOutsideFocus。EmbeddedWindowController.EmbeddedWindow win =new EmbeddedWindowController.EmbeddedWindow(session, this, window,mInputToWindowMap.get(hostInputToken), callingUid, callingPid,sanitizedType, displayId, focusGrantToken, inputHandleName,(flags & FLAG_NOT_FOCUSABLE) == 0);
//client輸入通道確認clientChannel = win.openInputChannel();
//增加一個新的嵌入窗口mEmbeddedWindowController.add(clientChannel.getToken(), win);applicationHandle = win.getApplicationHandle();name = win.toString();}
//updateInputChannelupdateInputChannel(clientChannel.getToken(), callingUid, callingPid, displayId, surface, name, applicationHandle, flags, privateFlags, inputFeatures, sanitizedType, null /* region */, window);clientChannel.copyTo(outInputChannel);}
這里有個很重要的IWindow,官方介紹是API back to a client window that the Window Manager uses to inform it of?interesting things happening. 也就是說是是用于WMS回調客戶端的,當窗口有一些改變時,WMS及時調用客戶端接口,讓客戶端窗口立即更新。
IWindow.aidl - OpenGrok cross reference for /frameworks/base/core/java/android/view/IWindow.aidl
/*** API back to a client window that the Window Manager uses to inform it of* interesting things happening.** {@hide}*/
oneway interface IWindow {/*** ===== NOTICE =====* The first method must remain the first method. Scripts* and tools rely on their transaction number to work properly.*//*** Invoked by the view server to tell a window to execute the specified* command. Any response from the receiver must be sent through the* specified file descriptor.*/void executeCommand(String command, String parameters, in ParcelFileDescriptor descriptor);void resized(in ClientWindowFrames frames, boolean reportDraw,in MergedConfiguration newMergedConfiguration, in InsetsState insetsState,boolean forceLayout, boolean alwaysConsumeSystemBars, int displayId,int syncSeqId, boolean dragResizing);/*** Called when this window retrieved control over a specified set of insets sources.*/void insetsControlChanged(in InsetsState insetsState, in InsetsSourceControl[] activeControls);/*** Called when a set of insets source window should be shown by policy.** @param types internal insets types (WindowInsets.Type.InsetsType) to show* @param fromIme true if this request originated from IME (InputMethodService).* @param statsToken the token tracking the current IME show request or {@code null} otherwise.*/void showInsets(int types, boolean fromIme, in @nullable ImeTracker.Token statsToken);/*** Called when a set of insets source window should be hidden by policy.** @param types internal insets types (WindowInsets.Type.InsetsType) to hide* @param fromIme true if this request originated from IME (InputMethodService).* @param statsToken the token tracking the current IME hide request or {@code null} otherwise.*/void hideInsets(int types, boolean fromIme, in @nullable ImeTracker.Token statsToken);void moved(int newX, int newY);void dispatchAppVisibility(boolean visible);void dispatchGetNewSurface();void closeSystemDialogs(String reason);/*** Called for wallpaper windows when their offsets or zoom level change.*/void dispatchWallpaperOffsets(float x, float y, float xStep, float yStep, float zoom, boolean sync);void dispatchWallpaperCommand(String action, int x, int y,int z, in Bundle extras, boolean sync);/*** Drag/drop events*/void dispatchDragEvent(in DragEvent event);/*** Pointer icon events*/void updatePointerIcon(float x, float y);/*** Called for non-application windows when the enter animation has completed.*/void dispatchWindowShown();/*** Called when Keyboard Shortcuts are requested for the window.*/void requestAppKeyboardShortcuts(IResultReceiver receiver, int deviceId);/*** Called when Scroll Capture support is requested for a window.** @param callbacks to receive responses*/void requestScrollCapture(in IScrollCaptureResponseListener callbacks);
}
IWindow是怎么賦值并一步步傳入WMS端的呢,由下面代碼可以看出,它是在ViewRootImpl中進行賦值的
//定義
? final W mWindow;
...public ViewRootImpl(@UiContext Context context, Display display, IWindowSession session, WindowLayout windowLayout) {...mWindow = new W(this);... }W如下static class W extends IWindow.Stub {private final WeakReference<ViewRootImpl> mViewAncestor;private final IWindowSession mWindowSession;W(ViewRootImpl viewAncestor) {mViewAncestor = new WeakReference<ViewRootImpl>(viewAncestor);mWindowSession = viewAncestor.mWindowSession;}
...public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView, int userId) {
//此時將mWindow傳入res = mWindowSession.addToDisplayAsUser(mWindow, mWindowAttributes,getHostVisibility(), mDisplay.getDisplayId(), userId,mInsetsController.getRequestedVisibleTypes(), inputChannel, mTempInsets, mTempControls, attachedFrame, compatScale);
?