Android之Surface
一、Surface是什么
Handle onto a raw buffer that is being managed by the screen compositor.
大概意思是处理由屏幕合成器管理的原理缓存区。
二、Surface实现原理
在Surface类里有一个Canvas对象,在Canvas里有一个Bitmap,Bitmap是真正的画布。
Bitmap是什么
Bitmap缩写是BMP,是一种存储像素的数据结构。
三、Surface跨进程间传递
源码:frameworks/base/core/java/android/view/Surface.java
/** * Handle onto a raw buffer that is being managed by the screen compositor. * * <p>A Surface is generally created by or from a consumer of image buffers (such as a * {@link android.graphics.SurfaceTexture}, {@link android.media.MediaRecorder}, or * {@link android.renderscript.Allocation}), and is handed to some kind of producer (such as * {@link android.opengl.EGL14#eglCreateWindowSurface(android.opengl.EGLDisplay,android.opengl.EGLConfig,java.lang.Object,int[],int) OpenGL}, * {@link android.media.MediaPlayer#setSurface MediaPlayer}, or * {@link android.hardware.camera2.CameraDevice#createCaptureSession CameraDevice}) to draw * into.</p> * * <p><strong>Note:</strong> A Surface acts like a * {@link java.lang.ref.WeakReference weak reference} to the consumer it is associated with. By * itself it will not keep its parent consumer from being reclaimed.</p> */ public class Surface implements Parcelable { …… }
Surface继承自Parcelable,Parcelable是一个序列化接口,将对象转化为二进制流(二进制序列)的过程。二进制流可以通过Socket传输或者保存到本地。
在Android中Surface是怎么在进程间传递的,应用如何将Surface传递给SurfaceFlinger进程绘制的。
Java层实现:
在Parcelable中有两个关键函数:
/** * 将数据写入Parcel对象 */ public void writeToParcel(Parcel dest, int flags) {} /** * 从Parcel对象中读取数据 */ public void readFromParcel(Parcel source) {}
先看Parcelable.writeToParcel()函数:
@Override public void writeToParcel(Parcel dest, int flags) { synchronized (mLock) { // NOTE: This must be kept synchronized with the native parceling code // in frameworks/native/libs/Surface.cpp dest.writeString(mName); dest.writeInt(mIsSingleBuffered ? 1 : 0); nativeWriteToParcel(mNativeObject, dest); } }
dest是一个Parcel对象,将name写入Parcel对象dest,再调用nativeWriteToParcel()函数,将mNativeObject写入到Parcel对象。
mNativeObject是什么?
long mNativeObject; // package scope only for SurfaceControl access
mNativeObject是Long型变量,存储Native层的对象指针。
nativeWriteToParcel()函数定义:
private static native void nativeWriteToParcel(long nativeObject, Parcel dest);
nativeWriteToParcel()函数是Native层函数。
下面看看readFromParcel()函数:
public void readFromParcel(Parcel source) { 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. // NOTE: This must be kept synchronized with the native parceling code // in frameworks/native/libs/Surface.cpp mName = source.readString(); mIsSingleBuffered = source.readInt() != 0; setNativeObjectLocked(nativeReadFromParcel(mNativeObject, source)); } }
从Surface对象中读取name数据,再调用nativeReadFromParcel()函数,通过setNativeObjectLocked()函数将nativeReadFromParcel()函数返回的数据保存起来。
nativeReadFromParcel()函数定义:
private static native long nativeReadFromParcel(long nativeObject, Parcel source);
setNativeObjectLocked()函数实现:
private void setNativeObjectLocked(long ptr) { if (mNativeObject != ptr) { mNativeObject = ptr; } }
将nativeReadFromParcel()函数返回值赋值给mNativeObject变量。
Native层:
源码:frameworks/base/core/jni/android_view_Surface.cpp
nativeWriteToParcel()函数实现:
static void nativeWriteToParcel(JNIEnv* env, jclass clazz, jlong nativeObject, jobject parcelObj) { // (1) 获取parcel对象,从Java层 Parcel* parcel = parcelForJavaObject(env, parcelObj); if (parcel == NULL) { jniThrowNullPointerException(env, NULL); return; } // (2) Native层的Surface对象 sp<Surface> self(reinterpret_cast<Surface *>(nativeObject)); android::view::Surface surfaceShim; if (self != nullptr) { // (3) surfaceShim.graphicBufferProducer = self->getIGraphicBufferProducer(); } // Calling code in Surface.java has already written the name of the Surface // to the Parcel surfaceShim.writeToParcel(parcel, /*nameAlreadyWritten*/true); } // (3) sp<IGraphicBufferProducer> GraphicBufferSource::getIGraphicBufferProducer() const { return mProducer; }
(1) 通过parcelFroJavaOjbect()获取Parcel对象:
Parcel* parcelForJavaObject(JNIEnv* env, jobject obj) { if (obj) { Parcel* p = (Parcel*)env->GetLongField(obj, gParcelOffsets.mNativePtr); if (p != NULL) { return p; } jniThrowException(env, "java/lang/IllegalStateException", "Parcel has been finalized!"); } return NULL; }
(1) 通过JNI调用,在Native层通过Native层保存的Java层Parcel指针获取Native层对应Java层的Parcel对象。
(2) 通过Native层保存的Java层Surface对象指针,在Native层恢复Surface对象。
(3) 将Native层的IGraphicBufferProducer对象传递给Java层的Surface.graphicBufferProducer变量。
nativeReadFromParcel()函数实现:
static jlong nativeReadFromParcel(JNIEnv* env, jclass clazz, jlong nativeObject, jobject parcelObj) { // (1) Parcel* parcel = parcelForJavaObject(env, parcelObj); android::view::Surface surfaceShim; // (2) sp<Surface> self(reinterpret_cast<Surface *>(nativeObject)); // update the Surface only if the underlying IGraphicBufferProducer // has changed. // (3) if (self != nullptr && (IInterface::asBinder(self->getIGraphicBufferProducer()) == IInterface::asBinder(surfaceShim.graphicBufferProducer))) { // same IGraphicBufferProducer, return ourselves return jlong(self.get()); } // (4) sp<Surface> sur; if (surfaceShim.graphicBufferProducer != nullptr) { // we have a new IGraphicBufferProducer, create a new Surface for it sur = new Surface(surfaceShim.graphicBufferProducer, true); // and keep a reference before passing to java sur->incStrong(&sRefBaseOwner); } if (self != NULL) { // and loose the java reference to ourselves self->decStrong(&sRefBaseOwner); } // (5) return jlong(sur.get()); }
(1) 获取Native层对应Java层的Parcel对象。
(2) 获取Native层对应Java层的Surface对象。
(3) 获取IGraphicBufferProducer对象,一个Binder对象。
(4) 通过IGraphicBufferProducer对象创建一个新的Surface对象。
(5) 将Native层的新Surface对象通过JNI调用传递给Java层。
对象Java层的Surface对应Native层的Surface对象,对于Native层的Surface对应Native层的IGraphicBufferProducer对象。
四、总结
Android App中,一个Window对应一个Surface对象,应用与绘制服务SurfaceFlinger服务的通信是基于共享内存实现的,应用中在Java层将Surface对象通过Parcel转化为二进制流,并且二进制流存储在共享内存。
Android每个应用都有在共享内存中都会有一个SharedClicent,再应用的Window对应一个Surface,而每个Surface对应共享内存的SharedBufferStack。
Surface中Buffer是没有进程跨进程传递的,应用与SurfaceFlinger服务通信传递的是共享内存的物理地址,应用将Surface的Buffer写入到SharedClient中,再将SharedClient中的SharedBufferStack的地址通过Binder通信传递给SurfaceFlinger。SurfaceFlinger服务通过共享内存的物理地址到SharedClicent读取SharedBufferStack数据。
在SharedBufferStack中分为双缓冲与三级缓冲,在Android 4.1版本前是双缓冲机制,在4.1版本后是三级缓冲机制。
SharedBufferStack分为:
-
- FontBuffer:在屏幕中显示。
- BackBuffer:绘制Buffer。
- Triple Buffer:是Android对绘制优化,Vsync垂直同步提供的机制。Triple Buffer是CPU/GPU在空闲时提前准备数据的Buffer。
PS:可以配合SurfaceFlinger一文一起阅读。