APP、AMS、WMS的IPC是一个极其值得深入研究的过程。下面通过非常常见的startActivity来解析APP、AMS、WMS进程之间的通信过程。
ServiceManager,AMS,WMS,SurfaceFlinger都是android系统服务,在前面《从底层看android5.0启动过程》一文中已经解析过,不清楚的可先浏览该文章。在android系统启动完毕后,这些系统服务也随之开启了。
当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;
}
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.
接下来由AMS线程执行AMS.startActivity(),其主要源码如下
public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
public final int startActivity(...) {
return startActivityAsUser(...);
}
}
最终辗转执行ActivityThread.startActivity()。Activity分别经历onCreate->onStart->onResume三个状态迁移。其中onResume是当界面即将可见时才调用。
在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,下面重点分析。
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);
//...
}
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;
}
}
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捕抓当前画面,然后真实地呈现给观众。