Android应用程序窗口(Activity)与WindowManagerService服务的连接过程

Activity组件在其窗口对象和视图对象创建完成之后,就会请求与WindowManagerService建立一个连接,即请求WindowManagerService为其增加一个WindowState对象,用来描述它的窗口状态。

我们从两方面来看Activity组件与WindowManagerService服务之间的连接。一方面是从Activity组件到WindowManagerService服务的连接,另一方面是从WindowManagerService服务到Activity组件的连接。

从Activity组件到WindowManagerService服务的连接是以Activity组件所在的应用程序进程为单位来进行的。当一个应用程序进程在启动第一个Activity组件的时候,它便会打开一个到WindowManagerService服务的连接,这个连接以应用程序进程从WindowManagerService服务处获得一个实现了IWindowSession接口的Session代理对象来标志。

从WindowManagerService服务到Activity组件的连接是以Activity组件为单位来进行的。在应用程序进程这一侧,每一个Activity组件都关联一个实现了IWindow接口的W对象,这个W对象在Activity组件的视图对象创建完成之后,就会通过前面所获得一个Session代理对象来传递给WindowManagerService服务,而WindowManagerService服务接收到这个W对象之后,就会在内部创建一个WindowState对象来描述与该W对象所关联的Activity组件的窗口状态,并且以后就通过这个W对象来控制对应的Activity组件的窗口状态。

上述Activity组件与WindowManagerService服务之间的连接模型如图所示:

在这里插入图片描述
每一个Activity组件在ActivityManagerService服务内部,都对应有一个ActivityRecord对象,这个ActivityRecord对象是Activity组件启动的过程中创建的,用来描述Activity组件的运行状态。这样,每一个Activity组件在应用程序进程、WindowManagerService服务和ActivityManagerService服务三者之间就分别一一地建立了连接。

W类的实现:

在这里插入图片描述

Session类和WindowState类的实现:

在这里插入图片描述
W类实现了IWindow接口,它的类实例是一个Binder本地对象。一个Activity组件在启动的过程中,会创建一个关联的ViewRoot对象,用来配合WindowManagerService服务来管理该Activity组件的窗口状态。在这个ViewRoot对象内部,有一个类型为W的成员变量mWindow,它是在ViewRoot对象的创建过程中创建的。ViewRoot类有一个静态成员变量sWindowSession,它指向了一个实现了IWindowSession接口的Session代理对象。

当应用程序进程启动第一个Activity组件的时候,它就会请求WindowManagerService服务发送一个建立连接的Binder进程间通信请求。WindowManagerService服务接收到这个请求之后,就会在内部创建一个类型为Session的Binder本地对象,并且将这个Binder本地对象返回给应用程序进程,后者于是就会得到一个Session代理对象,并且保存在ViewRoot类的静态成员变量sWindowSession中。

有了这个Session代理对象之后,应用程序进程就可以在启动Activity组件的时候,调用它的成员函数add来将与该Activity组件所关联的一个W对象传递给WindowManagerService服务,后者于是就会得到一个W代理对象,并且会以这个W代理对象来创建一个WindowState对象,即将这个W代理对象保存在新创建的WindowState对象的成员变量mClient中。

Session类实现了IWindowSession接口,因此,应用程序进程就可以通过保存在ViewRoot类的静态成员变量sWindowSession所描述的一个Session代理对象所实现的IWindowSession接口来与WindowManagerService服务通信,例如:

  1. 在Activity组件的启动过程中,调用这个IWindowSession接口的成员函数add可以将一个关联的W对象传递到WindowManagerService服务,以便WindowManagerService服务可以为该Activity组件创建一个WindowState对象。
  2. 在Activity组件的销毁过程中,调用这个这个IWindowSession接口的成员函数remove来请求WindowManagerService服务之前为该Activity组件所创建的一个WindowState对象。
  3. 在Activity组件的运行过程中,调用这个这个IWindowSession接口的成员函数relayout来请求WindowManagerService服务来对该Activity组件的UI进行布局,以便该Activity组件的UI可以正确地显示在屏幕中。

W类实现了IWindow接口,因此,WindowManagerService服务就可以通过它在内部所创建的WindowState对象的成员变量mClient来要求运行在应用程序进程这一侧的Activity组件来配合管理窗口的状态,例如:

  1. 当一个Activity组件的窗口的大小发生改变后,WindowManagerService服务就会调用这个IWindow接口的成员函数resized来通知该Activity组件,它的大小发生改变了。
  2. 当一个Activity组件的窗口的可见性之后,WindowManagerService服务就会调用这个IWindow接口的成员函数dispatchAppVisibility来通知该Activity组件,它的可见性发生改变了。
  3. 当一个Activity组件的窗口获得或者失去焦点之后,WindowManagerService服务就会调用这个IWindow接口的成员函数windowFoucusChanged来通知该Activity组件,它的焦点发生改变了。

Activity组件在WindowManagerService服务和ActivityManagerService服务之间的连接是通过一个AppWindowToken对象来描述的。

在这里插入图片描述
每一个Activity组件在启动的时候,ActivityManagerService服务都会内部为该Activity组件创建一个ActivityRecord对象,并且会以这个ActivityRecord对象所实现的一个IApplicationToken接口为参数,请求WindowManagerService服务为该Activity组件创建一个AppWindowToken对象,即将这个IApplicationToken接口保存在新创建的AppWindowToken对象的成员变量appToken中。

同时,这个ActivityRecord对象还会传递给它所描述的Activity组件所运行在应用程序进程,于是,应用程序进程就可以在启动完成该Activity组件之后,将这个ActivityRecord对象以及一个对应的W对象传递给WindowManagerService服务,后者接着就会做两件事情:

  1. 根据获得的ActivityRecord对象的IApplicationToken接口来找到与之对应的一个AppWindowToken对象;
  2. 根据获得的AppWindowToken对象以及前面传递过来的W代理对象来为正在启动的Activity组件创建一个WindowState对象,并且将该AppWindowToken对象保存在新创建的WindowState对象的成员变量mAppToken中。

AppWindowToken类是从WindowToken类继续下来的。WindowToken类也是用来标志一个窗口的,不过这个窗口类型除了是应用程序窗口,即Activity组件窗口之外,还可以是其它的,例如,输入法窗口或者壁纸窗口类型等,而AppWindowToken类只是用来描述Activity组件窗口。当WindowToken类是用来描述Activity组件窗口的时候,它的成员变量token指向的就是用来描述该Activity组件的一个ActivityRecord对象所实现的一个IBinder接口,而成员变量appWindowToken指向的就是其子类AppWindowToken对象。当另一方面,当WindowToken类是用来描述非Activity组件窗口的时候,它的成员变量appWindowToken的值就会等于null。这样,我们就可以通过WindowToken类的成员变量appWindowToken的值来判断一个WindowToken对象是否是用来描述一个Activity组件窗口的,即是否是用来描述一个应用程序窗口的。

上面所描述的Activity组件在ActivityManagerService服务和WindowManagerService服务之间以及应用程序进程和WindowManagerService服务之间的连接模型比较抽象,接下来,我们再通过三个过程来分析它们彼此之间的连接模型,如下所示:

  1. ActivityManagerService服务请求WindowManagerService服务为一个Activity组件创建一个AppWindowToken对象的过程;
  2. 应用程序进程请求WindowManagerService服务创建一个Session对象的过程;
  3. 应用程序进程请求WindowManagerService服务为一个Activity组件创建一个WindowState对象的过程。

一. AppWindowToken对象的创建过程

Activity组件在启动的过程中,会调用到ActivityStack类的成员函数startActivityLocked,该函数会请求WindowManagerService服务为当前正在启动的Activity组件创建一个AppWindowToken对象。

在这里插入图片描述

Step 1. ActivityStack.startActivityLocked

public class ActivityStack {
     
    ......  
  
    final ActivityManagerService mService;  
    ......  
  
    final ArrayList mHistory = new ArrayList();  
    ......  
  
    private final void startActivityLocked(ActivityRecord r, boolean newTask,  
            boolean doResume) {
     
        final int NH = mHistory.size();  
  
        int addPos = -1;  
  
        if (!newTask) {
     
            // If starting in an existing task, find where that is...  
            boolean startIt = true;  
            for (int i = NH-1; i >= 0; i--) {
     
                ActivityRecord p = (ActivityRecord)mHistory.get(i);  
                if (p.finishing) {
     
                    continue;  
                }  
                if (p.task == r.task) {
     
                    // Here it is!  Now, if this is not yet visible to the  
                    // user, then just add it without starting; it will  
                    // get started when the user navigates back to it.  
                    addPos = i+1;  
                    if (!startIt) {
     
                        mHistory.add(addPos, r);  
                        ......  
  
                        mService.mWindowManager.addAppToken(addPos, r, r.task.taskId,  
                                r.info.screenOrientation, r.fullscreen);  
                        ......  
                        return;  
                    }  
                    break;  
                }  
                if (p.fullscreen) {
     
                    startIt = false;  
                }  
            }  
        }  
  
        // Place a new activity at top of stack, so it is next to interact  
        // with the user.  
        if (addPos < 0) {
     
            addPos = NH;  
        }  
        ......  
  
        // Slot the activity into the history stack and proceed  
        mHistory.add(addPos, r);  
        ......  
  
        if (NH > 0) {
         
            ......  
  
            mService.mWindowManager.addAppToken(  
                    addPos, r, r.task.taskId, r.info.screenOrientation, r.fullscreen);  
            .....  
        } else {
     
            // If this is the first activity, don't do any fancy animations,  
            // because there is nothing for it to animate on top of.  
            mService.mWindowManager.addAppToken(addPos, r, r.task.taskId,  
                    r.info.screenOrientation, r.fullscreen);  
        }  
        ......  
  
        if (doResume) {
     
            resumeTopActivityLocked(null);  
        }  
    }  
  
    ......  
} 

参数r是一个ActivityRecord对象,用来描述的是要启动的Activity组件,参数newTask是一个布尔变量,用来描述要启动的Activity组件是否是在新任务中启动的,参数doResume也是一个布尔变量,用来描述是否需要马上将Activity组件启动起来。

ActivityStack类的成员变量mService指向的是系统的ActivityManagerService,另外一个成员变量mHistory是一个数组列表,用来描述系统的Activity组件堆栈。

当参数newTask的值等于false时,就说明参数r所描述的Activity组件是在已有的一个任务中启动的,因此,这时候ActivityStack类的成员函数startActivityLocked就会从上到下遍历保存成员变量mHistory,找到一个已有的Activity组件,它与参数r所描述的Activity组件是属于同一个任务的,即它们的成员变量task的值相等。找到这样的一个Activity组件之后,如果位于它上面的其它Activity组件的窗口至少有一个全屏的,即变量startIt的值等于true,那么ActivityStack类的成员函数startActivityLocked就只是将参数r所描述的Activity组件加入到成员变量mHistory所描述的一个Activity组件堆栈中,以及调用成员变量mService所描述的ActivityManagerService服务的成员变量mWindowManager所描述的WindowManagerService服务的成员函数addAppToken来为它创建一个AppWindowToken对象,然后就返回了。这相当于是延迟到参数r所描述的Activity组件可见时,才将它启动起来。

当参数newTask的值等于true时,就说明参数r所描述的Activity组件是在一个任务中启动的,这时候ActivityStack类的成员函数startActivityLocked就会首先将它添加到成员变量mHistory所描述的一个Activity组件堆栈,接着再判断它是否是系统中第一个启动的Activity组件。如果是系统中第一个启动的Activity组件,那么ActivityStack类的成员函数startActivityLocked就只是简单地调用WindowManagerService服务的成员函数addAppToken来为它创建一个AppWindowToken对象就完事了。如果不是系统系统中第一个启动的Activity组件,那么ActivityStack类的成员函数startActivityLocked除了会调用WindowManagerService服务的成员函数addAppToken来为它创建一个AppWindowToken对象之外,还会为它创建一些启动动画等,我们忽略这些代码。

无论如何,ActivityStack类的成员函数startActivityLocked都会调用WindowManagerService服务的成员函数addAppToken为正在启动的Activity组件创建一个AppWindowToken对象。创建完成这个AppWindowToken对象之后,如果参数doResume的值等于true,那么ActivityStack类的成员函数startActivityLocked就会继续调用另外一个成员函数resumeTopActivityLocked来继续执行启动参数r所描述的一个Activity组件。


Step 2. WindowManagerService.addAppToken

public class WindowManagerService extends IWindowManager.Stub  
        implements Watchdog.Monitor {
     
    ......  
  
    /** 
     * Mapping from a token IBinder to a WindowToken object. 
     */  
    final HashMap<IBinder, WindowToken> mTokenMap =  
            new HashMap<IBinder, WindowToken>();  
  
    /** 
     * The same tokens as mTokenMap, stored in a list for efficient iteration 
     * over them. 
     */  
    final ArrayList<WindowToken> mTokenList = new ArrayList<WindowToken>();  
    ......  
  
    /** 
     * Z-ordered (bottom-most first) list of all application tokens, for 
     * controlling the ordering of windows in different applications.  This 
     * contains WindowToken objects. 
     */  
    final ArrayList<AppWindowToken> mAppTokens = new ArrayList<AppWindowToken>();  
    ......  
  
    public void addAppToken(int addPos, IApplicationToken token,  
            int groupId, int requestedOrientation, boolean fullscreen) {
     
        ......  
  
        long inputDispatchingTimeoutNanos;  
        try {
     
            inputDispatchingTimeoutNanos = token.getKeyDispatchingTimeout() * 1000000L;  
        } catch (RemoteException ex) {
     
            ......  
            inputDispatchingTimeoutNanos = DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;  
        }  
  
        synchronized(mWindowMap) {
     
            AppWindowToken wtoken = findAppWindowToken(token.asBinder());  
            if (wtoken != null) {
     
                ......  
                return;  
            }  
            wtoken = new AppWindowToken(token);  
            wtoken.inputDispatchingTimeoutNanos = inputDispatchingTimeoutNanos;  
            wtoken.groupId = groupId;  
            wtoken.appFullscreen = fullscreen;  
            wtoken.requestedOrientation = requestedOrientation;  
            mAppTokens.add(addPos, wtoken);  
            ......  
            mTokenMap.put(token.asBinder(), wtoken);  
            mTokenList.add(wtoken);  
  
            // Application tokens start out hidden.  
            wtoken.hidden = true;  
            wtoken.hiddenRequested = true;  
  
            //dump();  
        }  
    }
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值