Android中APP、AMS、WMS的Binder IPC
APP、AMS、WMS的IPC是一个极其值得深入研究的过程。下面通过非常常见的startActivity来解析APP、AMS、WMS进程之间的通信过程。
1.startActivity Binder IPC流程图
ServiceManager,AMS,WMS,SurfaceFlinger都是android系统服务,在前面《从底层看android5.0启动过程》一文中已经解析过,不清楚的可先浏览该文章。在android系统启动完毕后,这些系统服务也随之开启了。
2.APP与AMS间的Binder IPC
2.1.APP启动Activity
当APP内部Activity.startActivity(),当启动一个Activity,APP需要和AMS通信,所以APP需要向ServiceManager查询AMS的Binder引用。下面分析关键源码体会该过程,Activity.startActivity()主线程经过辗转最终调用Instrumentation.execStartActivity(),其关键源码如下
public ActivityResult execStartActivity( Context who, IBinder contextThread, IBinder token, Activity target, Intent intent, int requestCode, Bundle options) { //获取AMS引用并调用AMS.startActiviy() int result = ActivityManagerNative.getDefault() .startActivity(whoThread, who.getBasePackageName(), intent, intent.resolveTypeIfNeeded(who.getContentResolver()), token, target != null ? target.mEmbeddedID : null, requestCode, 0, null, options); checkStartActivityResult(result, intent); } catch (RemoteException e) { } return null; }
2.2.APP获取AMS的Binder引用
APP主线程执行ActivityManagerNative.getDefault()获取的就是一个AMS的Binder引用,其关键源码如下
public abstract class ActivityManagerNative extends Binder implements IActivityManager {//... private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() { protected IActivityManager create() { //向ServiceManager获取AMS的Binder引用 IBinder b = ServiceManager.getService("activity"); if (false) { Log.v("ActivityManager", "default service binder = " + b); } //类型转换,如果是本进程的其他类获取Binder引用,则不需要通过Binder Driver可直 //接获得Binder引用,得到的IActivityManager是AMS //如果是其他进程,得到的IActivityManager是ActivityManagerProxy,双方 //通过Binder Driver通信 IActivityManager am = asInterface(b); if (false) { Log.v("ActivityManager", "default service = " + am); } return am; } };//...}
ActivityManagerNative只是一个抽象类,IActivityManager接口实际上是由ActivityManagerNative子类AMS实现的。
上一篇文章《AMS管理四大组件》已经解析过AMS向ServiceManager登记了“域名”为“activity”的Binder。因此上述的逻辑主要是获取AMS的Binder引用,由于是不同进程间通信,asInterface转化为ActivityManagerProxy类型,ActivityManagerProxy.startActvity通过Binder Driver作为中介,最终调用的是AMS.startActvity.
2.3.AMS启动Activity
接下来由AMS线程执行AMS.startActivity(),其主要源码如下
public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback { public final int startActivity(...) { return startActivityAsUser(...); }}
2.4.APP的ActivityThread启动Activity
最终辗转执行ActivityThread.startActivity()。Activity分别经历onCreate->onStart->onResume三个状态迁移。其中onResume是当界面即将可见时才调用。
3.APP与WMS间的Binder IPC
3.1.应用窗口添加到系统
在handleResumeActivity阶段会把应用窗口添加到系统,首先会对窗口设置一系列的属性,最终调用WindowMangerImpl.addView()把DecorView添加到系统中,主要源码如下
final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward, boolean reallyResume) { // If we are getting ready to gc after going to the background, well // we are back active so skip it. unscheduleGcIdler(); mSomeActivitiesChanged = true; // 这个函数最终将调用Activity.onResume ActivityClientRecord r = performResumeActivity(token, clearHide); //... if (r.window == null && !a.mFinished && willBeVisible) { r.window = r.activity.getWindow(); //DecorView是Activity整棵View树的最外围 View decor = r.window.getDecorView(); decor.setVisibility(View.INVISIBLE); //得到的是WindowMangerImpl对象 ViewManager wm = a.getWindowManager(); //获取窗口属性 WindowManager.LayoutParams l = r.window.getAttributes(); a.mDecor = decor; //窗口类型 l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION; l.softInputMode |= forwardBit; if (a.mVisibleFromClient) { a.mWindowAdded = true; wm.addView(decor, l);//将窗口添加到WMS中 } //...
主线程ActivityThread执行WindowMangerImpl.addView(),这个过程肯定也会涉及到Binder IPC,下面重点分析。
3.2.ViewRootImpl是整棵View树和WMS的中介
WindowMangerImpl其实仅仅是WindowManagerGlobal的一个代理类,而且WindowManagerGlobal是一个全局单例对象存在着,UI主线程执行WindowManagerGlobal.addView()方法,会创建一个ViewRootImpl对象作为中介,ViewRootImpl就是应用程序和WMS 的Binder IPC关键,其源码如下
public void addView(View view, ViewGroup.LayoutParams params, Display display, Window parentWindow) { ViewRootImpl root; View panelParentView = null; //... 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); //... }
3.3.追踪APP主线程获取的WMS的引用
ViewRootImpl构造函数会调用getWindowSession(),getWindowSession()通过getWindowManagerService()获取到了WMS对象,因此可以确定APP主线程获取的WMS的Binder引用是在getWindowManagerService()方法中,在该方法中,调用ServiceManager.getService(“window”),来获取域名为“window”的Bindr引用,也就是WMS的引用。获取到WMS的引用后,会打开一个Seesion连接,用于APP进程和WMS进程之间的通信。在其关键源码如下
public ViewRootImpl(Context context, Display display) { mContext = context; //打开一个Seesion,用于于WMS连接 mWindowSession = WindowManagerGlobal.getWindowSession(); } public static IWindowSession getWindowSession() { synchronized (WindowManagerGlobal.class) { if (sWindowSession == null) { try { InputMethodManager imm = InputMethodManager.getInstance(); //获取WindowManagerService IWindowManager windowManager = getWindowManagerService(); //打开一个Session连接,用于与WMS连接 sWindowSession = windowManager.openSession( new IWindowSessionCallback.Stub() { @Override public void onAnimatorScaleChanged(float scale) { ValueAnimator.setDurationScale(scale); } }, imm.getClient(), imm.getInputContext()); ValueAnimator.setDurationScale(windowManager.getCurrentAnimatorScale()); } catch (RemoteException e) { Log.e(TAG, "Failed to open window session", e); } } return sWindowSession; } }public static IWindowManager getWindowManagerService() { synchronized (WindowManagerGlobal.class) { if (sWindowManagerService == null) { sWindowManagerService = IWindowManager.Stub.asInterface( ServiceManager.getService("window")); } return sWindowManagerService; } }
4.4.session会话addWindow
ViewRootImpl.setView利用Session来发起一个添加窗口的服务,在Session的addToDisplay方法中,通过AMS.addWindow正式发起添加窗口的服务请求。其源码如下
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) { //调用Session接口 res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes, getHostVisibility(), mDisplay.getDisplayId(), mAttachInfo.mContentInsets, mInputChannel); }
final class Session extends IWindowSession.Stub implements IBinder.DeathRecipient { public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs, int viewVisibility, int displayId, Rect outContentInsets, InputChannel outInputChannel) { return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, outContentInsets, outInputChannel); }}
addWindow会对该窗口进行权限检查,判断窗口类型,调整窗口属性以及分配层机值等操作,最终由“摄像机”SurfaceFlinger捕抓当前画面,然后真实地呈现给观众。
更多相关文章
- 自定义圆形进度条的实现方式
- Android(安卓)屏幕窗口Log日志调试库 LogcatViewer
- Android中通过GPS或NetWork获取当前位置的经纬度
- Android异步加载获取网络数据(图片)
- Android(安卓)SharedPreferences详解
- Android(安卓)LruCache原理及使用(对象软引用不行,使用LRU算法)
- Android重学之查漏补缺——Context引起的内存泄露
- Android获取CPU,内存,磁盘使用率
- Android中接口(Interface)的简单使用