Android6.0 WMS(四) WMS中常用变量分析

来源:互联网 发布:清弓的老贾有淘宝店吗? 编辑:程序博客网 时间:2024/05/22 03:47

这篇博客我们分析WMS的一些常用变量,我们依然从主线addWindow开始分析,碰到一些常用的变量再进行分析。


DisplayContent

我们再来看如下DisplayContent 类

            final DisplayContent displayContent = getDisplayContentLocked(displayId);

我们再来看getDisplayContentLocked函数,当mDisplayContents没有对应displayId对应的DisplayContent,会调用newDisplayContentLocked函数创建一个DisplayContent 然后放入mDisplayContents。

    public DisplayContent getDisplayContentLocked(final int displayId) {        DisplayContent displayContent = mDisplayContents.get(displayId);        if (displayContent == null) {            final Display display = mDisplayManager.getDisplay(displayId);            if (display != null) {                displayContent = newDisplayContentLocked(display);            }        }        return displayContent;    }
DisplayContent 的mWindows放了该显示设备所有的window。


WindowManager.LayoutParams  token

我们看addWindow这个函数的一个参数WindowManager.LayoutParams attrs,这个参数有很多地方修改,最基本的是在Activity应用中调用setContentView的时候会初始化。

现在我们来看其中一个重要的成员变量token。

先看下面代码,当该窗口是一个子窗口时,会调用windowForClientLocked来查找主窗口的WindowState。这个WindowState也就是子窗口的attachedWindow。

            if (type >= FIRST_SUB_WINDOW && type <= LAST_SUB_WINDOW) {                attachedWindow = windowForClientLocked(null, attrs.token, false);                if (attachedWindow == null) {                    Slog.w(TAG, "Attempted to add window with token that is not a window: "                          + attrs.token + ".  Aborting.");                    return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN;                }                if (attachedWindow.mAttrs.type >= FIRST_SUB_WINDOW                        && attachedWindow.mAttrs.type <= LAST_SUB_WINDOW) {                    Slog.w(TAG, "Attempted to add window with token that is a sub-window: "                            + attrs.token + ".  Aborting.");                    return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN;                }            }

我们来看下windowForClientLocked函数,就是从mWindowMap中获取其attrs.token的WindowState,说明子窗口的attrs.token放的是其父窗口的token。

    final WindowState windowForClientLocked(Session session, IBinder client,            boolean throwOnError) {        WindowState win = mWindowMap.get(client);        ......        return win;    }

那我们先来看看这个token是从何而来,

我们知道WMS的addWindow,是用ActivityThread的handleResumeActivity函数调用如下代码发起的,我们先来看看WindowManagerImpl的addView函数

            if (r.window == null && !a.mFinished && willBeVisible) {                r.window = r.activity.getWindow();                View decor = r.window.getDecorView();                decor.setVisibility(View.INVISIBLE);                ViewManager wm = a.getWindowManager();                WindowManager.LayoutParams l = r.window.getAttributes();                a.mDecor = decor;                l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;                l.softInputMode |= forwardBit;                if (a.mVisibleFromClient) {                    a.mWindowAdded = true;                    wm.addView(decor, l);                }

WindowManagerImpl的addView函数,直接调用了WindowMangerGlobal的addView函数

    @Override    public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {        applyDefaultToken(params);        mGlobal.addView(view, params, mDisplay, mParentWindow);    }

WindowMangerGlobal的addView函数先调用了其parentWindow的adjustLayoutParamsForSubWindow函数,然后就是创建ViewRooImpl对象,再调用其setView函数,就是在这个函数中通过Binder调用了WMS的addWindow函数。

    public void addView(View view, ViewGroup.LayoutParams params,            Display display, Window parentWindow) {        if (view == null) {            throw new IllegalArgumentException("view must not be null");        }        if (display == null) {            throw new IllegalArgumentException("display must not be null");        }        if (!(params instanceof WindowManager.LayoutParams)) {            throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");        }        final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;        if (parentWindow != null) {            parentWindow.adjustLayoutParamsForSubWindow(wparams);        }        ......                    root = new ViewRootImpl(view.getContext(), display);            view.setLayoutParams(wparams);            mViews.add(view);            mRoots.add(root);            mParams.add(wparams);        }        // do this last because it fires off messages to start doing things        try {            root.setView(view, wparams, panelParentView);        }         ......    }

那我们先要看这个parentWindow是谁,这个parentWindow是在创建WindowManagerImpl 时传进来的。

    public WindowManagerImpl createLocalWindowManager(Window parentWindow) {        return new WindowManagerImpl(mDisplay, parentWindow);    }

这个函数是在Activity的attach中调用的,代码如下:

        mWindow.setWindowManager(                (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),                mToken, mComponent.flattenToString(),                (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);

最后我们看传参是this,就是代表Activity中创建的PhoneWindow对象。

    public void setWindowManager(WindowManager wm, IBinder appToken, String appName,            boolean hardwareAccelerated) {        mAppToken = appToken;        mAppName = appName;        mHardwareAccelerated = hardwareAccelerated                || SystemProperties.getBoolean(PROPERTY_HARDWARE_UI, false);        if (wm == null) {            wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);        }        mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);    }

Window的adjustLayoutParamsForSubWindow函数如下,会把wp的token改成mAppToken。

    void adjustLayoutParamsForSubWindow(WindowManager.LayoutParams wp) {        CharSequence curTitle = wp.getTitle();        if (wp.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&           ......        } else if (wp.type >= WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW &&           .......        } else {            if (wp.token == null) {                wp.token = mContainer == null ? mAppToken : mContainer.mAppToken;            }            if ((curTitle == null || curTitle.length() == 0)                    && mAppName != null) {                wp.setTitle(mAppName);            }        }        if (wp.packageName == null) {            wp.packageName = mContext.getPackageName();        }        if (mHardwareAccelerated) {            wp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;        }    }

而这个mAppToken就是在setWindowManager时赋值的,因此这个token就是Activity的mToken。就是每一个Activity的全局唯一性。

    public void setWindowManager(WindowManager wm, IBinder appToken, String appName,            boolean hardwareAccelerated) {        mAppToken = appToken;        mAppName = appName;        mHardwareAccelerated = hardwareAccelerated                || SystemProperties.getBoolean(PROPERTY_HARDWARE_UI, false);        if (wm == null) {            wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);        }        mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);    }


mTokenMap

我们再回想之前分析的博客,每个Activity启动的时候会在ActivityStack中调用mWindowManager.addAppToken函数,WMS的addAppToken函数如下,就是放入mTokenMap中,key就是appToken,Value就是APPWindowToken。

    @Override    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);            ......            mTokenMap.put(token.asBinder(), atoken);            // Application tokens start out hidden.            atoken.hidden = true;            atoken.hiddenRequested = true;        }    }


继续回到addWindow函数,下面是一些出错处理。首先就是传来的appToken一定要在mTokenMap有对应的WindowToken。

            WindowToken token = mTokenMap.get(attrs.token);            if (token == null) {                if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {                    Slog.w(TAG, "Attempted to add application window with unknown token "                          + attrs.token + ".  Aborting.");                    return WindowManagerGlobal.ADD_BAD_APP_TOKEN;                }                if (type == TYPE_INPUT_METHOD) {                    Slog.w(TAG, "Attempted to add input method window with unknown token "                          + attrs.token + ".  Aborting.");                    return WindowManagerGlobal.ADD_BAD_APP_TOKEN;                }                if (type == TYPE_VOICE_INTERACTION) {                    Slog.w(TAG, "Attempted to add voice interaction window with unknown token "                          + attrs.token + ".  Aborting.");                    return WindowManagerGlobal.ADD_BAD_APP_TOKEN;                }                if (type == TYPE_WALLPAPER) {                    Slog.w(TAG, "Attempted to add wallpaper window with unknown token "                          + attrs.token + ".  Aborting.");                    return WindowManagerGlobal.ADD_BAD_APP_TOKEN;                }                if (type == TYPE_DREAM) {                    Slog.w(TAG, "Attempted to add Dream window with unknown token "                          + attrs.token + ".  Aborting.");                    return WindowManagerGlobal.ADD_BAD_APP_TOKEN;                }                if (type == TYPE_ACCESSIBILITY_OVERLAY) {                    Slog.w(TAG, "Attempted to add Accessibility overlay window with unknown token "                            + attrs.token + ".  Aborting.");                    return WindowManagerGlobal.ADD_BAD_APP_TOKEN;                }                token = new WindowToken(this, attrs.token, -1, false);                addToken = true;            } else if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {                AppWindowToken atoken = token.appWindowToken;                if (atoken == null) {                    Slog.w(TAG, "Attempted to add window with non-application token "                          + token + ".  Aborting.");                    return WindowManagerGlobal.ADD_NOT_APP_TOKEN;                } else if (atoken.removed) {                    Slog.w(TAG, "Attempted to add window with exiting application token "                          + token + ".  Aborting.");                    return WindowManagerGlobal.ADD_APP_EXITING;                }                if (type == TYPE_APPLICATION_STARTING && atoken.firstWindowDrawn) {                    // No need for this guy!                    if (localLOGV) Slog.v(                            TAG, "**** NO NEED TO START: " + attrs.getTitle());                    return WindowManagerGlobal.ADD_STARTING_NOT_NEEDED;                }            } else if (type == TYPE_INPUT_METHOD) {                if (token.windowType != TYPE_INPUT_METHOD) {                    Slog.w(TAG, "Attempted to add input method window with bad token "                            + attrs.token + ".  Aborting.");                      return WindowManagerGlobal.ADD_BAD_APP_TOKEN;                }            } else if (type == TYPE_VOICE_INTERACTION) {                if (token.windowType != TYPE_VOICE_INTERACTION) {                    Slog.w(TAG, "Attempted to add voice interaction window with bad token "                            + attrs.token + ".  Aborting.");                      return WindowManagerGlobal.ADD_BAD_APP_TOKEN;                }            } else if (type == TYPE_WALLPAPER) {                if (token.windowType != TYPE_WALLPAPER) {                    Slog.w(TAG, "Attempted to add wallpaper window with bad token "                            + attrs.token + ".  Aborting.");                      return WindowManagerGlobal.ADD_BAD_APP_TOKEN;                }            } else if (type == TYPE_DREAM) {                if (token.windowType != TYPE_DREAM) {                    Slog.w(TAG, "Attempted to add Dream window with bad token "                            + attrs.token + ".  Aborting.");                      return WindowManagerGlobal.ADD_BAD_APP_TOKEN;                }            } else if (type == TYPE_ACCESSIBILITY_OVERLAY) {                if (token.windowType != TYPE_ACCESSIBILITY_OVERLAY) {                    Slog.w(TAG, "Attempted to add Accessibility overlay window with bad token "                            + attrs.token + ".  Aborting.");                    return WindowManagerGlobal.ADD_BAD_APP_TOKEN;                }            } else if (token.appWindowToken != null) {                Slog.w(TAG, "Non-null appWindowToken for system window of type=" + type);                // It is not valid to use an app token with other system types; we will                // instead make a new token for it (as if null had been passed in for the token).                attrs.token = null;                token = new WindowToken(this, null, -1, false);                addToken = true;            }


mWindowMap

然后就新建一个WindowState对象,加入到mWindowMap中,注意这里的key是client.asBinder

            WindowState win = new WindowState(this, session, client, token,                    attachedWindow, appOp[0], seq, attrs, viewVisibility, displayContent);            ......            win.attach();            mWindowMap.put(client.asBinder(), win);

这里的client,是ViewRootImpl的mWindow 对象用来和WMS通信的,一个ViewRootImpl一个mWindow对象。

        mWindow = new W(this);


token.windows

再回到addWindow函数,下面是关于新窗口确定插入的位置的相关代码:

            if (type == TYPE_INPUT_METHOD) {                win.mGivenInsetsPending = true;                mInputMethodWindow = win;                addInputMethodWindowToListLocked(win);                imMayMove = false;            } else if (type == TYPE_INPUT_METHOD_DIALOG) {                mInputMethodDialogs.add(win);                addWindowToListInOrderLocked(win, true);                moveInputMethodDialogsLocked(findDesiredInputMethodWindowIndexLocked(true));                imMayMove = false;            } else {                addWindowToListInOrderLocked(win, true);                if (type == TYPE_WALLPAPER) {                    mLastWallpaperTimeoutTime = 0;                    displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;                } else if ((attrs.flags&FLAG_SHOW_WALLPAPER) != 0) {                    displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;                } else if (mWallpaperTarget != null                        && mWallpaperTarget.mLayer >= win.mBaseLayer) {                    // If there is currently a wallpaper being shown, and                    // the base layer of the new window is below the current                    // layer of the target window, then adjust the wallpaper.                    // This is to avoid a new window being placed between the                    // wallpaper and its target.                    displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;                }            }

我们主要看下addWindowToListInOrderLocked函数,这个函数分有附属窗口和没有附属窗口,我们先看下有附属窗口的处理。

    private void addWindowToListInOrderLocked(final WindowState win, boolean addToToken) {        if (DEBUG_FOCUS_LIGHT) Slog.d(TAG, "addWindowToListInOrderLocked: win=" + win +                " Callers=" + Debug.getCallers(4));        if (win.mAttachedWindow == null) {            final WindowToken token = win.mToken;            int tokenWindowsPos = 0;            if (token.appWindowToken != null) {                tokenWindowsPos = addAppWindowToListLocked(win);            } else {                addFreeWindowToListLocked(win);            }            if (addToToken) {                if (DEBUG_ADD_REMOVE) Slog.v(TAG, "Adding " + win + " to " + token);                token.windows.add(tokenWindowsPos, win);            }        } else {            addAttachedWindowToListLocked(win, addToToken);        }        if (win.mAppToken != null && addToToken) {            win.mAppToken.allAppWindows.add(win);        }    }

addAttachedWindowToListLocked函数,先调用getTokenWindowsOnDisplay函数,来得到所有这个WindowToken的WindowState,然后根据这个WindowState插入合适位置。并且把要插入的windowState,也放入token.windows。

    private void addAttachedWindowToListLocked(final WindowState win, boolean addToToken) {        final WindowToken token = win.mToken;        final DisplayContent displayContent = win.getDisplayContent();        if (displayContent == null) {            return;        }        final WindowState attached = win.mAttachedWindow;        WindowList tokenWindowList = getTokenWindowsOnDisplay(token, displayContent);        // Figure out this window's ordering relative to the window        // it is attached to.        final int NA = tokenWindowList.size();        final int sublayer = win.mSubLayer;        int largestSublayer = Integer.MIN_VALUE;        WindowState windowWithLargestSublayer = null;        int i;        for (i = 0; i < NA; i++) {            WindowState w = tokenWindowList.get(i);            final int wSublayer = w.mSubLayer;            if (wSublayer >= largestSublayer) {                largestSublayer = wSublayer;                windowWithLargestSublayer = w;            }            if (sublayer < 0) {                // For negative sublayers, we go below all windows                // in the same sublayer.                if (wSublayer >= sublayer) {                    if (addToToken) {                        if (DEBUG_ADD_REMOVE) Slog.v(TAG, "Adding " + win + " to " + token);                        token.windows.add(i, win);//放入WindowToken的windows                    }                    placeWindowBefore(wSublayer >= 0 ? attached : w, win);//插入合适位置                    break;                }            } else {                // For positive sublayers, we go above all windows                // in the same sublayer.                if (wSublayer > sublayer) {                    if (addToToken) {                        if (DEBUG_ADD_REMOVE) Slog.v(TAG, "Adding " + win + " to " + token);                        token.windows.add(i, win);                    }                    placeWindowBefore(w, win);                    break;                }            }        }        if (i >= NA) {            if (addToToken) {                if (DEBUG_ADD_REMOVE) Slog.v(TAG, "Adding " + win + " to " + token);                token.windows.add(win);            }            if (sublayer < 0) {                placeWindowBefore(attached, win);            } else {                placeWindowAfter(largestSublayer >= 0                                 ? windowWithLargestSublayer                                 : attached,                                 win);            }        }    }

我们先看下getTokenWindowsOnDisplay函数,就是遍历WindowToken的windows,是得同一个DisplayContent对象。

    WindowList getTokenWindowsOnDisplay(WindowToken token, DisplayContent displayContent) {        final WindowList windowList = new WindowList();        final int count = token.windows.size();        for (int i = 0; i < count; i++) {            final WindowState win = token.windows.get(i);            if (win.getDisplayContent() == displayContent) {                windowList.add(win);            }        }        return windowList;    }


DisplayContent的mWindows

再来看placeWindowBefore函数,插入到windows的pos位置

    private void placeWindowBefore(WindowState pos, WindowState window) {        final WindowList windows = pos.getWindowList();        int i = windows.indexOf(pos);        if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(            TAG, "Adding window " + window + " at "            + i + " of " + windows.size() + " (before " + pos + ")");        if (i < 0) {            Slog.w(TAG, "placeWindowBefore: Unable to find " + pos + " in " + windows);            i = 0;        }        windows.add(i, window);        mWindowsChanged = true;    }

getWindowList就是返回DisplayContent 得到mWindows,所以在placeWindowBefore插入window,最终也都是插入DisplayContent的mWindows

    WindowList getWindowList() {        final DisplayContent displayContent = getDisplayContent();        return displayContent == null ? null : displayContent.getWindowList();    }



继续看addWindowToListInOrderLocked函数,对没有附属窗口的调用addAppWindowToListLocked,就是调用WindowState的getWindowList来获取displayContent.getWindowList,然后调用placeWindowBefore插入合适的位置。

    private int addAppWindowToListLocked(final WindowState win) {        final IWindow client = win.mClient;        final WindowToken token = win.mToken;        final DisplayContent displayContent = win.getDisplayContent();        if (displayContent == null) {            // It doesn't matter this display is going away.            return 0;        }        final WindowList windows = win.getWindowList();        final int N = windows.size();        WindowList tokenWindowList = getTokenWindowsOnDisplay(token, displayContent);        int tokenWindowsPos = 0;        int windowListPos = tokenWindowList.size();        if (!tokenWindowList.isEmpty()) {            // If this application has existing windows, we            // simply place the new window on top of them... but            // keep the starting window on top.            if (win.mAttrs.type == TYPE_BASE_APPLICATION) {                // Base windows go behind everything else.                WindowState lowestWindow = tokenWindowList.get(0);                placeWindowBefore(lowestWindow, win);                ......            }        }    }


Task TaskStack

我们再来看看WMS的addAppToken函数,这个函数中新建了APPWindowToken之后,会看mTaskIdToTask是否有这个taskId,没有会调用createTaskLocked根据AMS传进来的taskId和stackId创建Task和TaskStack。

            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);            ......            Task task = mTaskIdToTask.get(taskId);            if (task == null) {                task = createTaskLocked(taskId, stackId, userId, atoken);            }            task.addAppToken(addPos, atoken);            mTokenMap.put(token.asBinder(), atoken);
createTaskLocked函数如下,TaskStack会在ActivityStackSupervisor中调用WMS的attachStack函数创建,这里然后创建Task,再把task放入mTaskIdToTask中。再把task加入到TaskStack中。
    private Task createTaskLocked(int taskId, int stackId, int userId, AppWindowToken atoken) {        if (DEBUG_STACK) Slog.i(TAG, "createTaskLocked: taskId=" + taskId + " stackId=" + stackId                + " atoken=" + atoken);        final TaskStack stack = mStackIdToStack.get(stackId);        if (stack == null) {            throw new IllegalArgumentException("addAppToken: invalid stackId=" + stackId);        }        EventLog.writeEvent(EventLogTags.WM_TASK_CREATED, taskId, stackId);        Task task = new Task(taskId, stack, userId, this);        mTaskIdToTask.put(taskId, task);        stack.addTask(task, !atoken.mLaunchTaskBehind /* toTop */, atoken.showForAllUsers);        return task;    }
WMS的attachStack函数如下,当mStackIdToStack没有这个stackId,这个时候新建TaskStack,然后加入到mStackIdToStack。

    public void attachStack(int stackId, int displayId) {        final long origId = Binder.clearCallingIdentity();        try {            synchronized (mWindowMap) {                final DisplayContent displayContent = mDisplayContents.get(displayId);                if (displayContent != null) {                    TaskStack stack = mStackIdToStack.get(stackId);                    if (stack == null) {                        if (DEBUG_STACK) Slog.d(TAG, "attachStack: stackId=" + stackId);                        stack = new TaskStack(this, stackId);//新建TaskStack                        mStackIdToStack.put(stackId, stack);//加入到mStackIdToStack                    }                    stack.attachDisplayContent(displayContent);                    displayContent.attachStack(stack);                    moveStackWindowsLocked(displayContent);                    final WindowList windows = displayContent.getWindowList();                    for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {                        windows.get(winNdx).reportResized();                    }                }            }


AppWindowToken 的mTask

我们再回到WMS的addAppToken函数,创建完task,之后调用了Task的addAppToken函数

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

Task的addAppToken把AppWindowToken 放入到Task的mAppTokens中,并且赋值AppWindowToken 的mTask

    void addAppToken(int addPos, AppWindowToken wtoken) {        final int lastPos = mAppTokens.size();        if (addPos >= lastPos) {            addPos = lastPos;        } else {            for (int pos = 0; pos < lastPos && pos < addPos; ++pos) {                if (mAppTokens.get(pos).removed) {                    // addPos assumes removed tokens are actually gone.                    ++addPos;                }            }        }        mAppTokens.add(addPos, wtoken);        wtoken.mTask = this;        mDeferRemoval = false;    }






1 0
原创粉丝点击