Android P WindowManager (三) window添加时主要参数的分析(2) client(IWindow)。

在WindowManagerService.addWindow每次的client(IWindow)是不同的,而client是什么呢?这个要从这个client在应用的创建开始了

(1)应用端client的初始化和传递

frameworks/base/core/java/android/view/ViewRootImpl.java

    //在ViewRootImpl的构造器中创建了client在应用端的实现mWindow
    public ViewRootImpl(Context context, Display display) {
        /*......*/
        mWindow = new W(this);
        /*......*/
    }
    //在ViewRootImpl.setView中调用到了session传给WindowManagerService去处理
    public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
                    /*......*/
                    res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                            getHostVisibility(), mDisplay.getDisplayId(), mWinFrame,
                            mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                            mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel);
                    /*......*/
    }

    //client在应用中的是一个AIDL的服务端实现,那就说明WindowManagerService端的话就是一个客户端的实现了.
    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;
        }
        /*......*/
    }

client在应用端的创建可以看到,应用端的client就是一个IWindow.Stub的实现,依附与ViewRootImpl,通过session.addToDisplay传递给服务端要在服务端生成一个AIDL的客户端,也就是说在WindowManagerService,它就是一个client.

(2)服务端的client(IWindow)

frameworks/base/base/services/core/java/com/android/server/wm/WindowManagerService.java

    //在addWindow中吧这个client添加到mWindowMap中
    public int addWindow(Session session, IWindow client, int seq,
            WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
            Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
            InputChannel outInputChannel) {
            /*......*/
            final WindowState win = new WindowState(this, session, client, token, parentWindow,
                    appOp[0], seq, attrs, viewVisibility, session.mUid,
                    session.mCanAddInternalSystemWindow);
            /*......*/
            mWindowMap.put(client.asBinder(), win);
            /*......*/
    }

/*************************************************/下面是client的几个作用我用万能分割符分开下
mWindowMap是WindowHashMap类型的变量,WindowHashMap继承了HashMap,它限制了HashMap的key值的类型为IBinder,value值的类型为WindowState。也就是说在WindowManagerService中保存Window信息的存储器了.而且也可以发现的是client就是WindowManagerService区分Window的key,只要知道了client那么对应的Window也就能获取到了.
/*************************************************/
另外在上面的代码中WindowState初始化时也用到了client,这里就真正用到client的AIDL的作用了,通过WindowState获取client,然后回调应用端的”class W extends IWindow.Stub”.

frameworks/base/base/services/core/java/com/android/server/wm/WindowState.java

    final IWindow mClient;
    private void dispatchResized(Rect frame, Rect overscanInsets, Rect contentInsets,
            Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
            MergedConfiguration mergedConfiguration, boolean reportOrientation, int displayId,
            DisplayCutout displayCutout)
            throws RemoteException {
        final boolean forceRelayout = isDragResizeChanged() || reportOrientation;

        mClient.resized(frame, overscanInsets, contentInsets, visibleInsets, stableInsets, outsets,
                reportDraw, mergedConfiguration, getBackdropFrame(frame), forceRelayout,
                mPolicy.isNavBarForcedShownLw(this), displayId,
                new DisplayCutout.ParcelableWrapper(displayCutout));
        mDragResizingChangeReported = true;
    }

这里很有意思的是IWindow.aidl是oneway模式,这是由于在WindowManagerService中我们拿到的是一个client的客户端,client操作是会通过Binder调用到应用端的”class W extends IWindow.Stub”,但是说到底WindowManagerService是一个管理者,管理者可以通过client这个喇叭通知应用端要做什么,但不能等着应用端做完之后给我们回复了我们再去通知下一个,否则的话工作的效率就太低了.

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 {
}

还有一处有意思的是当服务端的client是一个”class W extends IWindow.Stub”时,说明这个时候添加的Window是由system_server创建的,因为是同一个进程,所以client传递过程没有经过Binder化的跨进程处理.例如在<<Android P WindowManager (二) window添加时主要参数的分析(1) WindowSession。>>中点击设置应用启动时,会先添加一个Window{ba4a949 u0 Splash Screen com.android.settings},而这个Window就是由system_server创建的.

02-27 11:45:04.600  2590  2691 V lishuo  : *** ADD session :Session{e5dc9ec 2590:1000}
02-27 11:45:04.600  2590  2691 V lishuo  : *** ADD client.asBinder :android.view.ViewRootImpl$W@f957350
02-27 11:45:04.600  2590  2691 V lishuo  : *** ADD windowState :Window{ba4a949 u0 Splash Screen com.android.settings}

由于服务端调用client时没有办法通过oneway模式,所以WindowManagerService就要对一些耗时的操作做了些处理.
frameworks/base/base/services/core/java/com/android/server/wm/WindowState.java

    final IWindow mClient;
    void reportResized() {
            /*......*/
            if (mAttrs.type != WindowManager.LayoutParams.TYPE_APPLICATION_STARTING
                    && mClient instanceof IWindow.Stub) {
                // To prevent deadlock simulate one-way call if win.mClient is a local object.
                // 为了防止死锁,如果win.mclient是本地对象,则模拟单向调用。
                mService.mH.post(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            dispatchResized(frame, overscanInsets, contentInsets, visibleInsets,
                                    stableInsets, outsets, reportDraw, mergedConfiguration,
                                    reportOrientation, displayId, displayCutout);
                        } catch (RemoteException e) {
                            // Not a remote call, RemoteException won't be raised.
                        }
                    }
                });
            } else {
                dispatchResized(frame, overscanInsets, contentInsets, visibleInsets, stableInsets,
                        outsets, reportDraw, mergedConfiguration, reportOrientation, displayId,
                        displayCutout);
            }
            /*......*/
    }

/*************************************************/

client在WindowManagerService中的另外一个作用也在WindowManagerService.addWindow:

    public int addWindow(Session session, IWindow client, int seq,
            WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
            Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
            InputChannel outInputChannel) {
            /*......*/
            WindowToken token = displayContent.getWindowToken(
                    hasParent ? parentWindow.mAttrs.token : attrs.token);
            if (token == null) {
                if (rootType >= FIRST_APPLICATION_WINDOW && rootType <= LAST_APPLICATION_WINDOW) {
                    Slog.w(TAG_WM, "Attempted to add application window with unknown token "
                          + attrs.token + ".  Aborting.");
                    return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                }
                if (rootType == TYPE_INPUT_METHOD) {
                    Slog.w(TAG_WM, "Attempted to add input method window with unknown token "
                          + attrs.token + ".  Aborting.");
                    return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                }
                if (rootType == TYPE_VOICE_INTERACTION) {
                    Slog.w(TAG_WM, "Attempted to add voice interaction window with unknown token "
                          + attrs.token + ".  Aborting.");
                    return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                }
                if (rootType == TYPE_WALLPAPER) {
                    Slog.w(TAG_WM, "Attempted to add wallpaper window with unknown token "
                          + attrs.token + ".  Aborting.");
                    return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                }
                if (rootType == TYPE_DREAM) {
                    Slog.w(TAG_WM, "Attempted to add Dream window with unknown token "
                          + attrs.token + ".  Aborting.");
                    return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                }
                if (rootType == TYPE_QS_DIALOG) {
                    Slog.w(TAG_WM, "Attempted to add QS dialog window with unknown token "
                          + attrs.token + ".  Aborting.");
                    return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                }
                if (rootType == TYPE_ACCESSIBILITY_OVERLAY) {
                    Slog.w(TAG_WM, "Attempted to add Accessibility overlay window with unknown token "
                            + attrs.token + ".  Aborting.");
                    return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                }
                if (type == TYPE_TOAST) {
                    // Apps targeting SDK above N MR1 cannot arbitrary add toast windows.
                    if (doesAddToastWindowRequireToken(attrs.packageName, callingUid,
                            parentWindow)) {
                        Slog.w(TAG_WM, "Attempted to add a toast window with unknown token "
                                + attrs.token + ".  Aborting.");
                        return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                    }
                }
                final IBinder binder = attrs.token != null ? attrs.token : client.asBinder();
                token = new WindowToken(this, binder, type, false, displayContent,
                        session.mCanAddInternalSystemWindow);
            }else{
            /*......*/
    }

此处就用来作为binder来生成WindowToken了,WindowToken就是用来同步AM和WM的操作了(AppWindowToken)等.这个地方可以参考下老罗的<<Android窗口管理服务WindowManagerService对窗口的组织方式分析>>,这个是讲的很详细的,后面我也尽量简单的写写.

总结
client(IWindow)主要有以下几点:

(1)每个Window有不同的client,所以client被WindowManagerService用作了识别Window的key.
(2)client(IWindow)就同WindowSession相反了,WindowSession是从应用指向了服务,而client是从服务指向了应用,处理一些从WindowManagerService发到应用的操作.
(3)对于一些特殊的Window,也被用来生成WindowToken,例如一些自定义的悬浮窗等.

    原文作者:lishuo710307
    原文地址: https://blog.csdn.net/qq_26825819/article/details/88026363
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞