一、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一文一起閱讀。