之前在分析Activity的时候,我们分析过Surface创建。这个系列的博客是讲述显示系统,这里再系统的分析下Surface创建过程。
之前我们分析在Activity在调用attach方法时,建立ViewRootImpl,以及创建其Surface过程,还有在WMS中创建Surface的过程。
这篇博客我们通过另外一个方式分析,但是其实质是一样的。
一、应用层创建Surface
应用开发中很少直接使用Surface,因为每个Activity中已经创建好了各自的Surface对象(就是之前博客分析的在ViewRootImpl通过WMS创建的),通常只有一些特殊应用才需要在Activity之外创建Surface,例如照相机、视频播放应用。通常这些应用也是通过创建SurfaceView来使用Surface。在应用中不直接创建一个可用的Surface对象,或者说直接创建出来的Surface对象也没用,因为这样的Surface不能和SurfaceFlinger之间有关联。
下面我们就来看下SurfaceView是如何创建Surface的,在SurfaceView有两个Surface一个mSurface表示正在用的,另一个mNewSurface代表我们要切换的。
final Surface mSurface = new Surface(); // Current surface in use
final Surface mNewSurface = new Surface(); // New surface we are switching to
至于Surface的构造函数没什么代码,我们就不看了。
我们再来看SurfaceView的updateWindow函数,也是调用了WindowSession的relayout函数,和之前Activity创建Surface的流程一样,这里获取到mNewSurface,再把mNewSurface的数据复制到mSurface中。
protected void updateWindow(boolean force, boolean redrawNeeded) {
......
relayoutResult = mSession.relayout(mWindow, mWindow.mSeq, mLayout, mWidth, mHeight,
visible ? VISIBLE : GONE,
WindowManagerGlobal.RELAYOUT_DEFER_SURFACE_DESTROY,
mWinFrame, mOverscanInsets, mContentInsets,
mVisibleInsets, mStableInsets, mOutsets, mConfiguration,
mNewSurface);
......
mSurface.transferFrom(mNewSurface);
......
}
mSession对象是IWindowSession,它是WMS中Session的代理对象。下面这是IWindowSession.aidl文件中relayout函数的定义,我们可以看到outSurface的参数前面有一个out代表这是一个返回参数,从WMS获取这个对象的。而返回数据都是通过Parcel来传递的。那下面我们来看看Surface的readFromParcel函数。
int relayout(IWindow window, int seq, in WindowManager.LayoutParams attrs,
int requestedWidth, int requestedHeight, int viewVisibility,
int flags, out Rect outFrame, out Rect outOverscanInsets,
out Rect outContentInsets, out Rect outVisibleInsets, out Rect outStableInsets,
out Rect outOutsets, out Configuration outConfig, out Surface outSurface);
我们来看下Surface的readFromParcel函数,前面是参数检查,后面先是调用了nativeReadFromParcel函数来重新创建一个native层的Surface,然后调用setNativeObjectLocked来保存这个native层的Surface到mNativeObject对象
public void readFromParcel(Parcel source) {
if (source == null) {
throw new IllegalArgumentException("source must not be null");
}
synchronized (mLock) {
// nativeReadFromParcel() will either return mNativeObject, or
// create a new native Surface and return it after reducing
// the reference count on mNativeObject. Either way, it is
// not necessary to call nativeRelease() here.
mName = source.readString();
setNativeObjectLocked(nativeReadFromParcel(mNativeObject, source));
}
}
我们来看JNI层的nativeReadFromParcel函数,这个函数在android_view_Surface.cpp中,会将Parcel对象中读取一个Binder对象,并且用它创建一个c层的Surface,并且返回。这里我们还不清楚这个Binder是什么。
static jlong nativeReadFromParcel(JNIEnv* env, jclass clazz,
jlong nativeObject, jobject parcelObj) {
Parcel* parcel = parcelForJavaObject(env, parcelObj);//将数据解析成parcel
if (parcel == NULL) {
doThrowNPE(env);
return 0;
}
sp<Surface> self(reinterpret_cast<Surface *>(nativ