Android窗口与Token对应策略

概念

Android窗口分为三种类型,应用窗口,子窗口,系统窗口
每种类型窗口必须对应有一个身份标识Token,Token一般是一个binder对象

主要来看三种窗口的Token是如何分配的

addView

任何窗口的添加都会到这个方法,该方法会设置Window对应的Token,并且创建三个ArrayList,每一个Window的View,ViewRootImpl,LayoutParams会一一对应
/frameworks/base/core/java/android/view/WindowManagerGlobal.java

public void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow) {
        ......
        final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
        if (parentWindow != null) {
            //此方法会设置不同窗口的Token
            parentWindow.adjustLayoutParamsForSubWindow(wparams);
        } else {
           ......
        }

        ViewRootImpl root;
        View panelParentView = null;

        synchronized (mLock) {
            ......
            if (wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
                    wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
                final int count = mViews.size();
                for (int i = 0; i < count; i++) {
                    if (mRoots.get(i).mWindow.asBinder() == wparams.token) {
                        panelParentView = mViews.get(i);
                    }
                }
            }

            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);
            } catch (RuntimeException e) {
                // BadTokenException or InvalidDisplayException, clean up.
                if (index >= 0) {
                    removeViewLocked(index, true);
                }
                throw e;
            }
        }
    }

adjustLayoutParamsForSubWindow

我们看此方中中刚好有三条分支,对应三种类型窗口的处理,type是窗口的类型,FIRST_SUB_WINDOW代表第一个子窗口,LAST_SUB_WINDOW代表最后一个子窗口,FIRST_SYSTEM_WINDOW代表第一个系统窗口,LAST_SYSTEM_WINDOW代表最后一个系统窗口
/frameworks/base/core/java/android/view/Window.java

void adjustLayoutParamsForSubWindow(WindowManager.LayoutParams wp) {
        ......
        //子窗口
        if (wp.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
                wp.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
            if (wp.token == null) {
                View decor = peekDecorView();
                if (decor != null) {
                    wp.token = decor.getWindowToken();
                }
            }
            ......
            //系统窗口
        } else if (wp.type >= WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW &&
                wp.type <= WindowManager.LayoutParams.LAST_SYSTEM_WINDOW) {
            // We don't set the app token to this system window because the life cycles should be
            // independent. If an app creates a system window and then the app goes to the stopped
            // state, the system window should not be affected (can still show and receive input
            // events)
            ......
        } else {
           //应用窗口
            if (wp.token == null) {
                wp.token = mContainer == null ? mAppToken : mContainer.mAppToken;
            }
            ....
        }
    }

子窗口分支:子窗口通过的token通过getWindowToken赋值

getWindowToken

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

   public IBinder getWindowToken() {
        return mAttachInfo != null ? mAttachInfo.mWindowToken : null;
    }
    AttachInfo(IWindowSession session, IWindow window, Display display,
                ViewRootImpl viewRootImpl, Handler handler, Callbacks effectPlayer,
                Context context) {
            ......
            mWindow = window;
            mWindowToken = window.asBinder();
            ......
        }
    }

mAttachInfo.mWindowToken是在ViewRootImpl的构造方法中赋值的
/frameworks/base/core/java/android/view/ViewRootImpl.java

public ViewRootImpl(Context context, Display display) {
     ......
     mWindow = new W(this);
     mAttachInfo = new View.AttachInfo(mWindowSession, mWindow, display, this, mHandler, this,
                context);
     ......
}

其实子窗口的token就是父窗口的W对象,并且从开始addView方法中看到,ViewRootImpl的创建是在给窗口设置token之后,所以如果一开始创建的窗口就是一个子窗口是不行的,没有token

系统窗口分支:部分系统窗口的token不会在这里设置,也不需要开发者干预,系统会自动创建,注释直译:
系统窗口生命周期应该是独立的,因此我们没有将应用令牌设置给系统窗口。 如果某个应用创建了系统窗口,然后该应用进入停止状态,则该系统窗口不应受到影响(仍可以显示和接收输入事件)

应用窗口分支:mContainer是Window类型的,mAppToken和mContainer.mAppToken都一样都是Window中的mAppToken

 wp.token = mContainer == null ? mAppToken : mContainer.mAppToken;

看下mAppToken哪里来的

setWindowManager

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

setWindowManager方法是由Activity创建时调用自身attach方法中调用的
/frameworks/base/core/java/android/app/ActivityThread.java

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
	......
	activity.attach(appContext, this, getInstrumentation(), r.token,
                          r.ident, app, r.intent, r.activityInfo, title, r.parent,
                          r.embeddedID, r.lastNonConfigurationInstances, config,
                          r.referrer, r.voiceInteractor, window, r.configCallback,
                          r.assistToken);
	......
}

attach

/frameworks/base/core/java/android/app/Activity.java

 final void attach(Context context, ActivityThread aThread,
            Instrumentation instr, IBinder token, int ident,
            Application application, Intent intent, ActivityInfo info,
            CharSequence title, Activity parent, String id,
            NonConfigurationInstances lastNonConfigurationInstances,
            Configuration config, String referrer, IVoiceInteractor voiceInteractor,
            Window window, ActivityConfigCallback activityConfigCallback, IBinder assistToken) {
	......
	mToken = token;
	mWindow.setWindowManager(
                (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
                mToken, mComponent.flattenToString(),
                (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
	......

}

其实mAppToken就是ActivityClientRecord.token,ActivityClientRecord是app与AMS中ActivityRecord对应的,ActivityClientRecord.token就是ActivityRecord.appToken,

看下ActivityRecord构造函数,直接new的一个Token,代表了Activity的专属令牌

final IApplicationToken.Stub appToken; // window manager token

ActivityRecord(ActivityTaskManagerService _service, WindowProcessController _caller,
              int _launchedFromPid, int _launchedFromUid, String _launchedFromPackage, Intent _intent,
              String _resolvedType, ActivityInfo aInfo, Configuration _configuration,
              ActivityRecord _resultTo, String _resultWho, int _reqCode, boolean _componentSpecified,
              boolean _rootVoiceInteraction, ActivityStackSupervisor supervisor,ActivityOptions options, ActivityRecord sourceRecord) {
	......
	appToken = new Token(this, _intent);
	......
}

总结:子窗口用的父窗口的W对象,应用窗口由应用内部创建的token对象,部分系统窗口由系统自动创建专属token

发布了28 篇原创文章 · 获赞 40 · 访问量 4810

猜你喜欢

转载自blog.csdn.net/qq_34211365/article/details/103627993