Android P WindowManager (二) window添加时主要参数的分析(1) WindowSession。

《Android P 系统界面 (一) 直观感受每个window的添加》中我们可以看到每次的添加一个window时有以下的规律:

1.每次的(IWindow)client是不同的
2.每个window添加时都会生成一个WindowState

另外我在之前添加的log的基础上又添加了对session的观察,发现了第三条规律:

/base/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -1424,7 +1424,14 @@ public class WindowManagerService extends IWindowManager.Stub
     public int addWindow(Session session, IWindow client, int seq,
            LayoutParams attrs, int viewVisibility, int displayId, Rect outFrame,
            Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
            DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel) {
            /********************************/
             win.attach();
             mWindowMap.put(client.asBinder(), win);
-
+            android.util.Log.v("lishuo","*** ADD session :" + session.toString());
+            android.util.Log.v("lishuo","*** ADD client.asBinder :" + client.asBinder().toString());
+            android.util.Log.v("lishuo","*** ADD windowState :" + win.toString());
+            for(IBinder key:mWindowMap.keySet())
+            {
+                android.util.Log.v("lishuo","client.asBinder :" + key.toString());
+                android.util.Log.v("lishuo","windowState :" + mWindowMap.get(key).toString());
+            }
             win.initAppOpsState();

3.当添加的Window的应用是同一个时,这些Window的session是相同的。

 

那对于从log里面发现的3个规律,就要针对三个参数分别做分析了,这三个分别是WindowManagerService函数addWindow的前两个参数session,client,以及中间新创建的WindowState。

 

一,session
从WindowManagerService中看到session是Session类,这个类的位置是在framework/base/services/core/java/com/android/server/wm/Session.java.

/**
 * This class represents an active client session.  There is generally one
 * Session object per process that is interacting with the window manager.
 */
/**
 * 此类代表一个活跃的客户端。每个进程通常有一个session与WindowManagerService交互。
 */
class Session extends IWindowSession.Stub implements IBinder.DeathRecipient{


从这里就能看到session是一个使用AIDL进行进程通信的一个服务端的具体实现,session可以看做注册在WindowManagerService中的一个应用端操作的接受器。

一. session的应用端创建

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

    public ViewRootImpl(Context context, Display display) {
        mContext = context;
        mWindowSession = WindowManagerGlobal.getWindowSession();
        /* ...... */
    }


session应用端的创建是在WindowManagerGlobal.getWindowSession创建的sWindowSession开始的,sWindowSession是静态属性,而且创建的过程也可以看到是一个标准的单例模式的创建过程,这符合了一个进程只有一个session与WindowManagerService交互的要求了.

session在应用端的实现就是sWindowSession.sWindowSession是一个IWindowSession(IWindowSession.aidl)类型的属性,即只是一个客户端的实现,真正的工作是在服务端中处理的,而服务端的创建是WindowManagerService.openSession中处理的,这个后续要说明一下.

而我也在生产的时候添加了log以观察session生成之前的操作:


    private static IWindowSession sWindowSession;
    public static IWindowSession getWindowSession() {
        synchronized (WindowManagerGlobal.class) {
            if (sWindowSession == null) {
                try {
+                    Log.e(TAG + "_lishuo", "new WindowSession", new Exception("lishuo"));
                    InputMethodManager imm = InputMethodManager.getInstance();
                    IWindowManager windowManager = getWindowManagerService();
                    sWindowSession = windowManager.openSession(
                            new IWindowSessionCallback.Stub() {
                                @Override
                                public void onAnimatorScaleChanged(float scale) {
                                    ValueAnimator.setDurationScale(scale);
                                }
                            },
                            /*添加输入法的客户端为了判断当前的窗口的输入法是否有焦点,好像也关联了InputMethodManagerService 有需要的话可以来追下*/
                            imm.getClient(), imm.getInputContext());
                } catch (RemoteException e) {
                    throw e.rethrowFromSystemServer();
                }
            }
            return sWindowSession;
        }
    }

 

(1)开机时SystemUI的session创建.

SystemUI的session是在第一次添加Window{7802e91 u0 DockedStackDivider}的时候创建的,后续的添加Window{5ecd386 u0 NavigationBar}等窗口都是使用的已经创建的session.

02-27 10:31:35.616  3534  3534 E WindowManager_lishuo: new WindowSession
02-27 10:31:35.616  3534  3534 E WindowManager_lishuo: java.lang.Exception: lishuo
02-27 10:31:35.616  3534  3534 E WindowManager_lishuo: 	at android.view.WindowManagerGlobal.getWindowSession(WindowManagerGlobal.java:186)
02-27 10:31:35.616  3534  3534 E WindowManager_lishuo: 	at android.view.ViewRootImpl.<init>(ViewRootImpl.java:520)
02-27 10:31:35.616  3534  3534 E WindowManager_lishuo: 	at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:347)
02-27 10:31:35.616  3534  3534 E WindowManager_lishuo: 	at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:93)
02-27 10:31:35.616  3534  3534 E WindowManager_lishuo: 	at com.android.systemui.stackdivider.DividerWindowManager.add(DividerWindowManager.java:63)
02-27 10:31:35.616  3534  3534 E WindowManager_lishuo: 	at com.android.systemui.stackdivider.Divider.addDivider(Divider.java:93)
02-27 10:31:35.616  3534  3534 E WindowManager_lishuo: 	at com.android.systemui.stackdivider.Divider.update(Divider.java:105)
02-27 10:31:35.616  3534  3534 E WindowManager_lishuo: 	at com.android.systemui.stackdivider.Divider.start(Divider.java:55)
02-27 10:31:35.616  3534  3534 E WindowManager_lishuo: 	at com.android.systemui.SystemUIApplication.startServicesIfNeeded(SystemUIApplication.java:195)
02-27 10:31:35.616  3534  3534 E WindowManager_lishuo: 	at com.android.systemui.SystemUIApplication.startServicesIfNeeded(SystemUIApplication.java:139)
02-27 10:31:35.616  3534  3534 E WindowManager_lishuo: 	at com.android.systemui.SystemUIService.onCreate(SystemUIService.java:39)
02-27 10:31:35.616  3534  3534 E WindowManager_lishuo: 	at android.app.ActivityThread.handleCreateService(ActivityThread.java:3563)
02-27 10:31:35.616  3534  3534 E WindowManager_lishuo: 	at android.app.ActivityThread.access$1400(ActivityThread.java:206)
02-27 10:31:35.616  3534  3534 E WindowManager_lishuo: 	at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1694)
02-27 10:31:35.616  3534  3534 E WindowManager_lishuo: 	at android.os.Handler.dispatchMessage(Handler.java:106)
02-27 10:31:35.616  3534  3534 E WindowManager_lishuo: 	at android.os.Looper.loop(Looper.java:193)
02-27 10:31:35.616  3534  3534 E WindowManager_lishuo: 	at android.app.ActivityThread.main(ActivityThread.java:6702)
02-27 10:31:35.616  3534  3534 E WindowManager_lishuo: 	at java.lang.reflect.Method.invoke(Native Method)
02-27 10:31:35.616  3534  3534 E WindowManager_lishuo: 	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
02-27 10:31:35.616  3534  3534 E WindowManager_lishuo: 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:911)
02-27 10:31:35.650  2590  2647 V lishuo  : *** ADD session :Session{47993cc 3534:u0a10045}
02-27 10:31:35.650  2590  2647 V lishuo  : *** ADD client.asBinder :android.os.BinderProxy@bba6d2a
02-27 10:31:35.650  2590  2647 V lishuo  : *** ADD windowState :Window{7802e91 u0 DockedStackDivider}
......
02-27 10:31:36.669  2590  2648 V lishuo  : *** ADD session :Session{47993cc 3534:u0a10045}
02-27 10:31:36.669  2590  2648 V lishuo  : *** ADD client.asBinder :android.os.BinderProxy@c3b1c6b
02-27 10:31:36.669  2590  2648 V lishuo  : *** ADD windowState :Window{5ecd386 u0 NavigationBar}

Systemui的session的创建最关键的地方为DividerWindowManager.java:

    public void add(View view, int width, int height) {
        mLp = new WindowManager.LayoutParams(
                width, height, TYPE_DOCK_DIVIDER,
                FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCH_MODAL
                        | FLAG_WATCH_OUTSIDE_TOUCH | FLAG_SPLIT_TOUCH | FLAG_SLIPPERY,
                PixelFormat.TRANSLUCENT);
        mLp.token = new Binder();//这是在应用端随意new了一个token,服务端会重新赋值的
        mLp.setTitle(WINDOW_TITLE);
        mLp.privateFlags |= PRIVATE_FLAG_NO_MOVE_ANIMATION;
        mLp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
        view.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
        mWindowManager.addView(view, mLp);//此处为session的创建的起因
        mView = view;
    }

(2)桌面点击设置后的session创建.

在之前观察Window添加的log时我们已经知道点击进入设置会有两次的Window添加,但是从下面的log来看第一次添加Window{ba4a949 u0 Splash Screen com.android.settings}竟然没有创建session,而是在第二次添加Window{21a4d5b u0 com.android.settings/com.android.settings.Settings}之前才创建的.这是因为Window{ba4a949 u0 Splash Screen com.android.settings}并不是设置进程添加的Window,他是由system_server创建的,这里就不往下找原因了,主要是看session的创建过程.

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}

02-27 11:45:05.562  9207  9207 E WindowManager_lishuo: java.lang.Exception: lishuo
02-27 11:45:05.562  9207  9207 E WindowManager_lishuo: 	at android.view.WindowManagerGlobal.getWindowSession(WindowManagerGlobal.java:186)
02-27 11:45:05.562  9207  9207 E WindowManager_lishuo: 	at android.view.ViewRootImpl.<init>(ViewRootImpl.java:520)
02-27 11:45:05.562  9207  9207 E WindowManager_lishuo: 	at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:347)
02-27 11:45:05.562  9207  9207 E WindowManager_lishuo: 	at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:93)
02-27 11:45:05.562  9207  9207 E WindowManager_lishuo: 	at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:3899)
02-27 11:45:05.562  9207  9207 E WindowManager_lishuo: 	at android.app.servertransaction.ResumeActivityItem.execute(ResumeActivityItem.java:51)
02-27 11:45:05.562  9207  9207 E WindowManager_lishuo: 	at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:145)
02-27 11:45:05.562  9207  9207 E WindowManager_lishuo: 	at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:70)
02-27 11:45:05.562  9207  9207 E WindowManager_lishuo: 	at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1836)
02-27 11:45:05.562  9207  9207 E WindowManager_lishuo: 	at android.os.Handler.dispatchMessage(Handler.java:106)
02-27 11:45:05.562  9207  9207 E WindowManager_lishuo: 	at android.os.Looper.loop(Looper.java:193)
02-27 11:45:05.562  9207  9207 E WindowManager_lishuo: 	at android.app.ActivityThread.main(ActivityThread.java:6702)
02-27 11:45:05.562  9207  9207 E WindowManager_lishuo: 	at java.lang.reflect.Method.invoke(Native Method)
02-27 11:45:05.562  9207  9207 E WindowManager_lishuo: 	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
02-27 11:45:05.562  9207  9207 E WindowManager_lishuo: 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:911)

02-27 11:45:05.585  2590  6961 V lishuo  : *** ADD session :Session{699390c 9207:1000}
02-27 11:45:05.586  2590  6961 V lishuo  : *** ADD client.asBinder :android.os.BinderProxy@69db46a
02-27 11:45:05.586  2590  6961 V lishuo  : *** ADD windowState :Window{21a4d5b u0 com.android.settings/com.android.settings.Settings}

设置应用的session的创建最关键的地方为ActivityThread.java:

    @Override
    public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,
            String reason) {
    /****/
        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 (r.mPreserveWindow) {
                a.mWindowAdded = true;
                r.mPreserveWindow = false;
                // Normally the ViewRoot sets up callbacks with the Activity
                // in addView->ViewRootImpl#setView. If we are instead reusing
                // the decor view we have to notify the view root that the
                // callbacks may have changed.
                ViewRootImpl impl = decor.getViewRootImpl();
                if (impl != null) {
                    impl.notifyChildRebuilt();
                }
            }
            if (a.mVisibleFromClient) {
                if (!a.mWindowAdded) {
                    a.mWindowAdded = true;
                    wm.addView(decor, l);
                } else {
                    // The activity will get a callback for this {@link LayoutParams} change
                    // earlier. However, at that time the decor will not be set (this is set
                    // in this method), so no action will be taken. This call ensures the
                    // callback occurs with the decor set.
                    a.onWindowAttributesChanged(l);
                }
            }

            // If the window has already been added, but during resume
            // we started another activity, then don't yet make the
            // window visible.
        }
    /****/
    }

从以上两个应用创建session的过程可以看到,session的应用端的创建是在当前进程第一个ViewRootImpl初始化的时候开始的,通过调用WindowManagerService.openSession创建服务端的实例并且绑定,而两个session之间则使用AIDL通过Binder进行跨进程的通信.
此处要注意的是WindowManagerService端的session是一个接收器,一直在监听着应用端的session调用.

 

二, 服务器端session的创建

WindowManagerService端session的创建就简单多了,WindowManagerService.java:

    @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;
    }

在openSession创建了一个session,然后返回这个session.这里就很简单了剩下的就看Session.java.

 

三, frameworks/base/services/core/java/com/android/server/wm/Session.java

Session.java是对IWindowSession.aidl的实现,它对IWindowSession的方法都一一做了实现,但是在这个类里面我们大部分看到的是很简单的函数:

    @Override
    public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
            int viewVisibility, int displayId, Rect outFrame, Rect outContentInsets,
            Rect outStableInsets, Rect outOutsets,
            DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel) {
        //扔给Service
        return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, outFrame,
                outContentInsets, outStableInsets, outOutsets, outDisplayCutout, outInputChannel);
    }

    @Override
    public int addToDisplayWithoutInputChannel(IWindow window, int seq, WindowManager.LayoutParams attrs,
            int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets) {
        //扔给Service
        return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
                new Rect() /* outFrame */, outContentInsets, outStableInsets, null /* outOutsets */,
                new DisplayCutout.ParcelableWrapper() /* cutout */, null /* outInputChannel */);
    }


    @Override
    public void prepareToReplaceWindows(IBinder appToken, boolean childrenOnly) {
        //还是扔给Service
        mService.setWillReplaceWindows(appToken, childrenOnly);
    }

总结

从以上的内容来看,这个session就是个很纯粹的Binder,它就像是一个管道一样横跨在应用端和WindowManagerService之间.当应用调用客户端session的函数时会把携带着client(IWindow)的一堆数据扔进这个管道中,然后服务端session这个家伙接到后连带着自己(this)又把这个数据送给了WindowManagerService.所以session这个类很简单,就是一个用来跨进程通信的工具.

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值