`
zzu_007
  • 浏览: 22520 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Activity与WindowManagerService连接的过程(一)

阅读更多
page1
    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组件在ActivityManagerServices服务内部, 都对应有一个ActivityRecord对象.这样, 每一个Activity组件在应用程序进程, WindowManagerService服务和ActivityManagerService服务三者之间就分别建立了一对一的连接.
    第一, 我们首先分析一下ActivityManagerService服务请求WindowManagerService服务为一个Activity组件创建一个AppWindowToken对象的过程, 关于这部分的内容可以参考page2文件.
    经过上面的分析, 我们知道了每一个Activity组件在ActivityManagerService服务内部都有一个对应的ActivityRecord对象, 并且在WindowManagerService服务内部关联有一个AppWindowToken对象.
    第二, 我们分析一下Activity与WindowManagerService建立连接的过程, 本质上是Session对象的创建过程,关于这部分的内容可以参考page5文件.
    第三, 我们分析一下应用程序进程请求WindowManagerService服务为一个Activity组件创建一个WindowState对象的过程, 关于这部分的内容可以参考page9文件.

    经过上面的分析, 我们了解了如下的事实:
    为了显示一个Activity, 应用程序进程为它创建一个窗口(Window)对象, 一个视图(View)对象, 一个ViewRoot对象、一个W对象.
    WindowManagerService服务为它创建一个AppWindowToken对象和一个WindowState对象,  一个SurfaceSession对象.
    此外,WindowManagerService服务还为一个Activity组件所运行在的应用程序进程创建了一个Session对象.
page2
在这篇文章里,我们分析一下ActivityManagerService服务请求WindowManagerService服务为一个Activity组件创建一个AppWindowToken对象的过程, 我们从ActivityStack的startActivityLocked函数作为入口来分析, startActivityLocked函数的定义如下:
1     private final void startActivityLocked(ActivityRecord r, boolean newTask,
2             boolean doResume, boolean keepCurTransition, Bundle options) {
3         final int NH = mHistory.size();
4
5         int addPos = -1;
6        
7         if (!newTask) {
8             // If starting in an existing task, find where that is...
9             boolean startIt = true;
10             for (int i = NH-1; i >= 0; i--) {
11                 ActivityRecord p = mHistory.get(i);
12                 if (p.finishing) {
13                     continue;
14                 }
15                 if (p.task == r.task) {
16                     // Here it is!  Now, if this is not yet visible to the
17                     // user, then just add it without starting; it will
18                     // get started when the user navigates back to it.
19                     addPos = i+1;
20                     if (!startIt) {
21                         if (DEBUG_ADD_REMOVE) {
22                             RuntimeException here = new RuntimeException("here");
23                             here.fillInStackTrace();
24                             Slog.i(TAG, "Adding activity " + r + " to stack at " + addPos,
25                                     here);
26                         }
27                         mHistory.add(addPos, r);
28                         r.putInHistory();
29                         mService.mWindowManager.addAppToken(addPos, r.appToken, r.task.taskId,
30                                 r.info.screenOrientation, r.fullscreen,
31                                 (r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0);
32                         if (VALIDATE_TOKENS) {
33                             validateAppTokensLocked();
34                         }
35                         ActivityOptions.abort(options);
36                         return;
37                     }
38                     break;
39                 }
40                 if (p.fullscreen) {
41                     startIt = false;
42                 }
43             }
44         }
45
46         // Place a new activity at top of stack, so it is next to interact
47         // with the user.
48         if (addPos < 0) {
49             addPos = NH;
50         }
51        
52         // If we are not placing the new activity frontmost, we do not want
53         // to deliver the onUserLeaving callback to the actual frontmost
54         // activity
55         if (addPos < NH) {
56             mUserLeaving = false;
57             if (DEBUG_USER_LEAVING) Slog.v(TAG, "startActivity() behind front, mUserLeaving=false");
58         }
59        
60         // Slot the activity into the history stack and proceed
61         if (DEBUG_ADD_REMOVE) {
62             RuntimeException here = new RuntimeException("here");
63             here.fillInStackTrace();
64             Slog.i(TAG, "Adding activity " + r + " to stack at " + addPos, here);
65         }
66         mHistory.add(addPos, r);
67         r.putInHistory();
68         r.frontOfTask = newTask;
69         if (NH > 0) {
70             // We want to show the starting preview window if we are
71             // switching to a new task, or the next activity's process is
72             // not currently running.
73             boolean showStartingIcon = newTask;
74             ProcessRecord proc = r.app;
75             if (proc == null) {
76                 proc = mService.mProcessNames.get(r.processName, r.info.applicationInfo.uid);
77             }
78             if (proc == null || proc.thread == null) {
79                 showStartingIcon = true;
80             }
81             if (DEBUG_TRANSITION) Slog.v(TAG,
82                     "Prepare open transition: starting " + r);
83             if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
84                 mService.mWindowManager.prepareAppTransition(
85                         WindowManagerPolicy.TRANSIT_NONE, keepCurTransition);
86                 mNoAnimActivities.add(r);
87             } else {
88                 mService.mWindowManager.prepareAppTransition(newTask
89                         ? WindowManagerPolicy.TRANSIT_TASK_OPEN
90                         : WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN, keepCurTransition);
91                 mNoAnimActivities.remove(r);
92             }
93             r.updateOptionsLocked(options);
94             mService.mWindowManager.addAppToken(
95                     addPos, r.appToken, r.task.taskId, r.info.screenOrientation, r.fullscreen,
96                     (r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0);
97             boolean doShow = true;
98             if (newTask) {
99                 // Even though this activity is starting fresh, we still need
100                 // to reset it to make sure we apply affinities to move any
101                 // existing activities from other tasks in to it.
102                 // If the caller has requested that the target task be
103                 // reset, then do so.
104                 if ((r.intent.getFlags()
105                         &Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
106                     resetTaskIfNeededLocked(r, r);
107                     doShow = topRunningNonDelayedActivityLocked(null) == r;
108                 }
109             }
110             if (SHOW_APP_STARTING_PREVIEW && doShow) {
111                 // Figure out if we are transitioning from another activity that is
112                 // "has the same starting icon" as the next one.  This allows the
113                 // window manager to keep the previous window it had previously
114                 // created, if it still had one.
115                 ActivityRecord prev = mResumedActivity;
116                 if (prev != null) {
117                     // We don't want to reuse the previous starting preview if:
118                     // (1) The current activity is in a different task.
119                     if (prev.task != r.task) prev = null;
120                     // (2) The current activity is already displayed.
121                     else if (prev.nowVisible) prev = null;
122                 }
123                 mService.mWindowManager.setAppStartingWindow(
124                         r.appToken, r.packageName, r.theme,
125                         mService.compatibilityInfoForPackageLocked(
126                                 r.info.applicationInfo), r.nonLocalizedLabel,
127                         r.labelRes, r.icon, r.windowFlags,
128                         prev != null ? prev.appToken : null, showStartingIcon);
129             }
130         } else {
131             // If this is the first activity, don't do any fancy animations,
132             // because there is nothing for it to animate on top of.
133             mService.mWindowManager.addAppToken(addPos, r.appToken, r.task.taskId,
134                     r.info.screenOrientation, r.fullscreen,
135                     (r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0);
136             ActivityOptions.abort(options);
137         }
138         if (VALIDATE_TOKENS) {
139             validateAppTokensLocked();
140         }
141
142         if (doResume) {
143             resumeTopActivityLocked(null);
144         }
145     }
在这里我们主要关注addAppToken函数的实现, 关于WindowManagerService的addAppToken函数的详细分析可以参考page3文件.
page3
在这里我们分析一下WindowManagerService的addAppToken函数的实现, addAppToken函数的定义如下:
    1     public void addAppToken(int addPos, IApplicationToken token,
    2             int groupId, int requestedOrientation, boolean fullscreen, boolean showWhenLocked) {
    3         if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
    4                 "addAppToken()")) {
    5             throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
    6         }
    7
    8         // Get the dispatching timeout here while we are not holding any locks so that it
    9         // can be cached by the AppWindowToken.  The timeout value is used later by the
    10         // input dispatcher in code that does hold locks.  If we did not cache the value
    11         // here we would run the chance of introducing a deadlock between the window manager
    12         // (which holds locks while updating the input dispatcher state) and the activity manager
    13         // (which holds locks while querying the application token).
    14         long inputDispatchingTimeoutNanos;
    15         try {
    16             inputDispatchingTimeoutNanos = token.getKeyDispatchingTimeout() * 1000000L;
    17         } catch (RemoteException ex) {
    18             Slog.w(TAG, "Could not get dispatching timeout.", ex);
    19             inputDispatchingTimeoutNanos = DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
    20         }
    21
    22         synchronized(mWindowMap) {
    23             AppWindowToken atoken = findAppWindowToken(token.asBinder());
    24             if (atoken != null) {
    25                 Slog.w(TAG, "Attempted to add existing app token: " + token);
    26                 return;
    27             }
    28             atoken = new AppWindowToken(this, token);
    29             atoken.inputDispatchingTimeoutNanos = inputDispatchingTimeoutNanos;
    30             atoken.groupId = groupId;
    31             atoken.appFullscreen = fullscreen;
    32             atoken.showWhenLocked = showWhenLocked;
    33             atoken.requestedOrientation = requestedOrientation;
    34             if (DEBUG_TOKEN_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG, "addAppToken: " + atoken
    35                     + " at " + addPos);
    36             mAppTokens.add(addPos, atoken);
    37             addAppTokenToAnimating(addPos, atoken);
    38             mTokenMap.put(token.asBinder(), atoken);
    39
    40             // Application tokens start out hidden.
    41             atoken.hidden = true;
    42             atoken.hiddenRequested = true;
    43
    44             //dump();
    45         }
    46     }
    第3-6行(WindowManagerService->addAppToken)会进行权限检查, 当发现没有权限时,就抛出异常.
    第14-20行(WindowManagerService->addAppToken)会得到ApplicationToken的inputDispatchingTimeout的时间, 这个值是会保存到AppWindowToken中去的.
    第22行(WindowManagerService->addAppToken)会在mWindowMap上加锁, 为的是保护对mTokenMap的访问.
    第23-27行(WindowManagerService->addAppToken)会调用findAppWindowToken函数来查找该Activity是否已经创建过AppWindowToken, 如果AppWindowToken已经存在就直接返回了. AppWindowToken的定义如下:
    AppWindowToken findAppWindowToken(IBinder token) {
        WindowToken wtoken = mTokenMap.get(token);
        if (wtoken == null) {
            return null;
        }
        return wtoken.appWindowToken;
    }
    findAppWindowToken函数的逻辑还是很简单的, 就是在mTokenMap中根据IApplicationToken来查找.
    第28行(WindowManagerService->addAppToken)会new一个AppWindowToken对象, 而传入的参数是WindowManagerService和IApplicationToken. 关于AppWindowToken的创建过程可以参考page4文件.
page4
在这篇文章里我们分析一下AppWindowToken的创建过程,我们先来分析一下AppWindowToken类的继承层次.
class AppWindowToken extends WindowToken
AppWindowToken的构造函数的定义如下:
1     AppWindowToken(WindowManagerService _service, IApplicationToken _token) {
2         super(_service, _token.asBinder(),
3                 WindowManager.LayoutParams.TYPE_APPLICATION, true);
4         appWindowToken = this;
5         appToken = _token;
6         mInputApplicationHandle = new InputApplicationHandle(this);
7         mAnimator = service.mAnimator;
8         mAppAnimator = new AppWindowAnimator(this);
9     }

第2-3行(AppWindowToken->AppWindowToken)会调用父类WindowToken的构造函数, 注意这里传入的参数type为WindowManager.LayoutParams.TYPE_APPLICATION.
WindowToken的构造函数的定义如下:
WindowToken(WindowManagerService _service, IBinder _token, int type, boolean _explicit) {
service = _service;
token = _token;
windowType = type;
explicit = _explicit;
    }

第4-5行(AppWindowToken->AppWindowToken)会将IApplicationToken保存到appToken成员变量中. 由此可见, AppWindowToken其实是拿着IApplicationToken对象的.
page5
    我们这里分析一下Activity与WindowManagerService建立连接的过程.
    应用程序进程在启动第一个Activity组件的时候, 就会请求与WindowManagerService服务建立一个连接,以便可以配合WindowManagerService服务来管理系统中的所有窗口.
    具体来说,就是应用程序进程在为它里面启动的第一个Activity组件的视图对象创建一个关联的ViewRoot对象的时候,就会向WindowManagerService服务请求返回一个类型为Session的Binder本地对象,这样应用程序进程就可以获得一个类型为Session的Binder代理对象, 以后就可以通过这个Binder代理对象和WindowManagerService服务进行通信了.
    在ViewRoot对象的创建过程中,会尝试建立和WindowManagerService服务建立连接.那我们就从ViewRoot类的构造函数作为入口来分析:
        ViewRootImpl类的构造函数的定义如下:
    1     public ViewRootImpl(Context context, Display display) {
        2         super();
        3
        4         if (MEASURE_LATENCY) {
        5             if (lt == null) {
        6                 lt = new LatencyTimer(100, 1000);
        7             }
        8         }
        9
        10         // Initialize the statics when this class is first instantiated. This is
        11         // done here instead of in the static block because Zygote does not
        12         // allow the spawning of threads.
        13         mWindowSession = WindowManagerGlobal.getWindowSession(context.getMainLooper());
        14         mDisplay = display;
        15
        16         CompatibilityInfoHolder cih = display.getCompatibilityInfo();
        17         mCompatibilityInfo = cih != null ? cih : new CompatibilityInfoHolder();
        18
        19         mThread = Thread.currentThread();
        20         mLocation = new WindowLeaked(null);
        21         mLocation.fillInStackTrace();
        22         mWidth = -1;
        23         mHeight = -1;
        24         mDirty = new Rect();
        25         mTempRect = new Rect();
        26         mVisRect = new Rect();
        27         mWinFrame = new Rect();
        28         mWindow = new W(this);
        29         mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion;
        30         mInputMethodCallback = new InputMethodCallback(this);
        31         mViewVisibility = View.GONE;
        32         mTransparentRegion = new Region();
        33         mPreviousTransparentRegion = new Region();
        34         mFirst = true; // true for the first time the view is added
        35         mAdded = false;
        36         mAccessibilityManager = AccessibilityManager.getInstance(context);
        37         mAccessibilityInteractionConnectionManager =
        38             new AccessibilityInteractionConnectionManager();
        39         mAccessibilityManager.addAccessibilityStateChangeListener(
        40                 mAccessibilityInteractionConnectionManager);
        41         mAttachInfo = new View.AttachInfo(mWindowSession, mWindow, display, this, mHandler, this);
        42         mViewConfiguration = ViewConfiguration.get(context);
        43         mDensity = context.getResources().getDisplayMetrics().densityDpi;
        44         mNoncompatDensity = context.getResources().getDisplayMetrics().noncompatDensityDpi;
        45         mFallbackEventHandler = PolicyManager.makeNewFallbackEventHandler(context);
        46         mProfileRendering = Boolean.parseBoolean(
        47                 SystemProperties.get(PROPERTY_PROFILE_RENDERING, "false"));
        48         mChoreographer = Choreographer.getInstance();
        49
        50         PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
        51         mAttachInfo.mScreenOn = powerManager.isScreenOn();
        52         loadSystemProperties();
        53     }
        第13行(ViewRootImpl->ViewRootImpl)会调用WindowManagerGlobal的getWindowSession函数, 关于getWindowSession函数的详细分析可以参考page6文件.

分享到:
评论

相关推荐

    WindowManagerService详解图

    WindowManagerService详解图

    animations in WindowManagerService翻译的结果

    animations in WindowManagerService翻译的结果

    WindowManagerService相关类图.eddx

    Activity,Window,DecorView,ViewRootImpl,WindowManager,WindowManagerImpl,WindowManagerGlobal,WindowManagerService相关类图

    深入理解WindowManagerService笔记

    深入理解WindowManagerService笔记

    WindowManagerService服务是如何以堆栈的形式来组织窗口

    我们知道,在Android系统中,Activity是以堆栈的形式组织...从前面Android应用程序启动过程源代码分析一文可以知道,应用程序进程中的每一个Activity组件在Activity管理服务ActivityManagerService中都对应有一个Activi

    Android应用程序UI架构 高清PTT

    Android系统采用一种称为Surface的UI架构为应用程序提供用户...这个PPT讲Android应用程序的Surface机制,阐述Activity、Window和View的关系,以及应用程序、WindowManagerService和SurfaceFlinger协作完成UI渲染的过程

    Android窗口机制

    DecorView通过PhoneWindow与WindowManagerService通信原理图 每个Activity都有一个Window对象,这个对象是PhoneWindow类型的。 每个Window对象里面都维护着一个WindowManager对象。 Activity里面添加一个View是通过...

    android4.0按键处理

    有关4.0按键的处理流程,包括windowmanagerservice的激动启动等

    Android应用程序进程管理

    这个PPT讲Android应用程序进程的启动和回收,主要涉及到Zygote进程、System Server进程,以及组件管理服务ActivityManagerService、窗口服务WindowManagerService,还有专用驱动Low Memory Killer。通过了解Android...

    Android应用内悬浮窗的实现方案示例

    悬浮窗,大家应该也不陌生,凌驾于应用之上的一个小弹窗,实现上很简单,就是添加一个系统级别的窗口,Android中通过WindowManagerService( WMS)来管理所有的窗口,对于WMS来说,管你是Activity、Toast、Dialog,...

    深入理解Android中的Window和WindowManager

    创建一个Window,需要通过WindowManager即可完成,WindowManager是外界访问Window的入口,Window具体实现位于WindowManagerService中,WindowManager和WindowManagerService的交互是一个IPC的过程。Android中,所有...

    Android input系统.pdf

     WindowManagerService.java : 作为应用与IMS的通信桥梁, 也作为InputDispatcher向AMS报告ANR的通信桥梁.  ActivityManagerService.java :ANR 处理.  Activity & Views :接收输入事件并处理.

    Android 添加系统服务的方法详解

    系统服务是Android中非常重要的一部分, 像ActivityManagerService, PackageManagerService, WindowManagerService, 这些系统服务都是Framework层的关键服务, 本篇文章主要讲一下如何基于Android源码添加一个系统服务...

    Android控件TextView的实现原理分析

    Android控件TextView的实现...实际上,每一个视图都是一个控件,这些控制可以将自己的UI绘制在窗口的绘图表面上,同时还可以与用户进行交互,即获得用户的键盘或者触摸屏输入。在本文中,我们就详细分析窗口控件的上

    Android-Event-driver.zip_Looper_android_android Handler_event

    Android 事件捕捉和处理流程分析 ,在Android系统中,键盘按键事件是由WindowManagerService服务来管理的,然后再以消息的形式来分发给应用程序处理,不过和普通消息不一样,它是由硬件中断触发的;在上一篇文章...

    Android中View绘制流程详细介绍

    创建Window Window即窗口,这个概念在AndroidFramework中的实现为android...在Android系统中,窗口是独占一个Surface实例的显示区域,每个窗口的Surface由WindowManagerService分配。我们可以把Surface看作一块画布,应

Global site tag (gtag.js) - Google Analytics