MyException - 我的异常网
当前位置:我的异常网» 移动开发 » Activity与WindowManagerService连接的进程(一)

Activity与WindowManagerService连接的进程(一)

www.MyException.Cn  网友分享于:2018-04-18  浏览:0次
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文件.

文章评论

写给自己也写给你 自己到底该何去何从
写给自己也写给你 自己到底该何去何从
程序员眼里IE浏览器是什么样的
程序员眼里IE浏览器是什么样的
科技史上最臭名昭著的13大罪犯
科技史上最臭名昭著的13大罪犯
为啥Android手机总会越用越慢?
为啥Android手机总会越用越慢?
当下全球最炙手可热的八位少年创业者
当下全球最炙手可热的八位少年创业者
Web开发者需具备的8个好习惯
Web开发者需具备的8个好习惯
亲爱的项目经理,我恨你
亲爱的项目经理,我恨你
程序员最害怕的5件事 你中招了吗?
程序员最害怕的5件事 你中招了吗?
5款最佳正则表达式编辑调试器
5款最佳正则表达式编辑调试器
那些性感的让人尖叫的程序员
那些性感的让人尖叫的程序员
Web开发人员为什么越来越懒了?
Web开发人员为什么越来越懒了?
那些争议最大的编程观点
那些争议最大的编程观点
中美印日四国程序员比较
中美印日四国程序员比较
旅行,写作,编程
旅行,写作,编程
“懒”出效率是程序员的美德
“懒”出效率是程序员的美德
团队中“技术大拿”并非越多越好
团队中“技术大拿”并非越多越好
60个开发者不容错过的免费资源库
60个开发者不容错过的免费资源库
 程序员的样子
程序员的样子
我的丈夫是个程序员
我的丈夫是个程序员
鲜为人知的编程真相
鲜为人知的编程真相
老程序员的下场
老程序员的下场
做程序猿的老婆应该注意的一些事情
做程序猿的老婆应该注意的一些事情
总结2014中国互联网十大段子
总结2014中国互联网十大段子
程序猿的崛起——Growth Hacker
程序猿的崛起——Growth Hacker
十大编程算法助程序员走上高手之路
十大编程算法助程序员走上高手之路
Java程序员必看电影
Java程序员必看电影
Java 与 .NET 的平台发展之争
Java 与 .NET 的平台发展之争
看13位CEO、创始人和高管如何提高工作效率
看13位CEO、创始人和高管如何提高工作效率
我是如何打败拖延症的
我是如何打败拖延症的
初级 vs 高级开发者 哪个性价比更高?
初级 vs 高级开发者 哪个性价比更高?
代码女神横空出世
代码女神横空出世
程序员都该阅读的书
程序员都该阅读的书
不懂技术不要对懂技术的人说这很容易实现
不懂技术不要对懂技术的人说这很容易实现
如何成为一名黑客
如何成为一名黑客
要嫁就嫁程序猿—钱多话少死的早
要嫁就嫁程序猿—钱多话少死的早
如何区分一个程序员是“老手“还是“新手“?
如何区分一个程序员是“老手“还是“新手“?
程序员的鄙视链
程序员的鄙视链
什么才是优秀的用户界面设计
什么才是优秀的用户界面设计
Google伦敦新总部 犹如星级庄园
Google伦敦新总部 犹如星级庄园
2013年中国软件开发者薪资调查报告
2013年中国软件开发者薪资调查报告
一个程序员的时间管理
一个程序员的时间管理
程序员必看的十大电影
程序员必看的十大电影
程序员和编码员之间的区别
程序员和编码员之间的区别
聊聊HTTPS和SSL/TLS协议
聊聊HTTPS和SSL/TLS协议
编程语言是女人
编程语言是女人
“肮脏的”IT工作排行榜
“肮脏的”IT工作排行榜
程序员周末都喜欢做什么?
程序员周末都喜欢做什么?
10个帮程序员减压放松的网站
10个帮程序员减压放松的网站
程序员的一天:一寸光阴一寸金
程序员的一天:一寸光阴一寸金
软件开发程序错误异常ExceptionCopyright © 2009-2015 MyException 版权所有