Android Surface 跨进程传递原理?
- Surface
- Activity 的 Surface 是怎么跨进程传递的
- 问题
Surface
public class Surface implements Parcelable {
// ....
long mNativeObject;
private final Canvas mCanvas = new CompatibleCanvas();
// ....
}
首先,Surface 实现了 Parcelable,所以它是可以跨进程传递的。
Parcelable 关键的函数就是 readFromParcel(Parcel source) 和 writeToParcel(Parcel dest, int flags)
- writeToParcel()
@Override
public void writeToParcel(Parcel dest, int flags) {
// ...
synchronized (mLock) {
// 写了个 mName
dest.writeString(mName);
dest.writeInt(mIsSingleBuffered ? 1 : 0);
// 调用了 native 方法 nativeWriteToParcel 写入了一个 mNativeObject 对象
nativeWriteToParcel(mNativeObject, dest);
}
}
writeToParcel 方法写入了一个 mName 变量,然后调用 nativeWriteToParcel 函数写入了 mNativeObject 对象。long mNativeObject; 是一个 native对象的指针。
private static native void nativeWriteToParcel(long nativeObject, Parcel dest);
- readFromParcel 函数
public void readFromParcel(Parcel source) {
synchronized (mLock) {
mName = source.readString();
mIsSingleBuffered = source.readInt() != 0;
setNativeObjectLocked(nativeReadFromParcel(mNativeObject, source));
}
}
private static native long nativeReadFromParcel(long nativeObject, Parcel source);
readFromParcel 和 writeToParcel 相比,他是反过来读取一个 mName 值,然后通过 mNativeObject 传入nativeReadFromParcel 中,在调用 setNativeObjectLocked() 函数。设置了一些属性。
- setNativeObjectLocked()
private void setNativeObjectLocked(long ptr) {
if (mNativeObject != ptr) {
// 。。。
mNativeObject = ptr;
}
}
setNativeObjectLocked 函数把传入的 long 类型的地址赋值给了 mNativeObject 。
-
目前java层来看的话就是操作了一个 long 类型的mNativeObject 变量和一个 mName 属性。接下来看一下 native 层的实现
frameworks/base/core/jni/android_view_Surface.cpp
-
先看一下 nativeWriteToParcel() 函数
static void nativeWriteToParcel(JNIEnv* env, jclass clazz,
jlong nativeObject, jobject parcelObj) {
// 通过 parcelForJavaObject 函数获得了一个 native 层的 Parcel 对象
Parcel* parcel = parcelForJavaObject(env, parcelObj);
// nativeObject 就是 surface 在 native 层的指针
// 所以通过该指针获得 surface 的对象
sp<Surface> self(reinterpret_cast<Surface *>(nativeObject));
android::view::Surface surfaceShim;
if (self != nullptr) {
// 获取一个 GraphicBuffer
surfaceShim.graphicBufferProducer = self->getIGraphicBufferProducer();
}
// 将 GraphicBuffer 对象写到 parcel
surfaceShim.writeToParcel(parcel, /*nameAlreadyWritten*/true);
}
- parcelForJavaObject()
Parcel* parcelForJavaObject(JNIEnv* env, jobject obj)
{
if (obj) {
// 通过 jni ,从Java层的 Parcel 对象获得了一个 native 层的 Parcel 对象。
Parcel* p = (Parcel*)env->GetLongField(obj, gParcelOffsets.mNativePtr);
if (p != NULL) {
return p;
}
}
return NULL;
}
上面方法通过 jni ,从Java层的 Parcel 对象获得了一个 native 层的 Parcel 对象。因为Java层对象中保存了一个 native 层对象的指针。
- nativeReadFromParcel
static jlong nativeReadFromParcel(JNIEnv* env, jclass clazz,
jlong nativeObject, jobject parcelObj) {
// 先 parcel 对象拿到 native 的 Parcel 对象
Parcel* parcel = parcelForJavaObject(env, parcelObj);
// 定义 surfaceShim 指定是 android view surface
android::view::Surface surfaceShim;
surfaceShim.readFromParcel(parcel, /*nameAlreadyRead*/true);
sp<Surface> self(reinterpret_cast<Surface *>(nativeObject));
// 只有当底层的IGraphicBufferProducer发生变化时才更新Surface。
if (self != nullptr
&& (IInterface::asBinder(self->getIGraphicBufferProducer()) ==
IInterface::asBinder(surfaceShim.graphicBufferProducer))) {
// same IGraphicBufferProducer, return ourselves
return jlong(self.get());
}
sp<Surface> sur;
if (surfaceShim.graphicBufferProducer != nullptr) {
// 创建一个 surface 对象,传入 IGraphicBufferProducer
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);
}
// 返回新创建的 surface 对象给 Java 层
return jlong(sur.get());
}
- Java层的surface 在于 native 层的 surface,而 native 层的 surface 在于 graphicBufferProducer 对象,它是可以申请 buffer 的存在。
Activity 的 Surface 是怎么跨进程传递的
performTraversals() 是准备绘制的时候,当第一次绘制的时候代码如下
private void performTraversals() {
if(mFirst){
int relayoutResult = 0;
relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
}
}
- relayoutWindow()
private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
boolean insetsPending) throws RemoteException {
int relayoutResult = mWindowSession.relayout(mWindow, mSeq, params,
(int) (mView.getMeasuredWidth() * appScale + 0.5f),
(int) (mView.getMeasuredHeight() * appScale + 0.5f), viewVisibility,
insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0, frameNumber,
mWinFrame, mPendingOverscanInsets, mPendingContentInsets, mPendingVisibleInsets,
mPendingStableInsets, mPendingOutsets, mPendingBackDropFrame, mPendingDisplayCutout,
mPendingMergedConfiguration, mSurface);
return relayoutResult;
}
mWindowSession binder 对象会给 wms 申请 relayout 调用,这里面会申请surface。传入的 mSurface 只是一个空壳。
relayout() 是一个 aidl 接口源码中是这样描述它的,总之就是调用这个方法,可以返回一个 surface 对象,你可以用它展示内容。mWindowSession 实际上就是 Java 层和 wms 交流的桥梁
* Change the parameters of a window. You supply the
* new parameters, it returns the new frame of the window on screen (the
* position should be ignored) and surface of the window. The surface
* will be invalid if the window is currently hidden, else you can use it
* to draw the window's contents.
调用该这个 aidl 方法执行 framework 中 Session.java
@Override
public int relayout(IWindow window, int seq, WindowManager.LayoutParams attrs,
int requestedWidth, int requestedHeight, int viewFlags, int flags, long frameNumber,
Rect outFrame, Rect outOverscanInsets, Rect outContentInsets, Rect outVisibleInsets,
Rect outStableInsets, Rect outsets, Rect outBackdropFrame,
DisplayCutout.ParcelableWrapper cutout, MergedConfiguration mergedConfiguration,
Surface outSurface) {
int res = mService.relayoutWindow(this, window, seq, attrs,
requestedWidth, requestedHeight, viewFlags, flags, frameNumber,
outFrame, outOverscanInsets, outContentInsets, outVisibleInsets,
outStableInsets, outsets, outBackdropFrame, cutout,
mergedConfiguration, outSurface);
return res;
}
- mService.relayoutWindow()
public int relayoutWindow(Session session, IWindow client, int seq, LayoutParams attr...{
// 调用了 createSurfaceControl() 方法中有下面代码
WindowSurfaceController surfaceController;
surfaceController = winAnimator.createSurfaceLocked(win.mAttrs.type, win.mOwnerUid);
// getSurface 里面调用了 outSurface.copyFrom(mSurfaceControl);
surfaceController.getSurface(outSurface);
}
- surface 从 surfaceController 中 copy 了一些东西
public void copyFrom(SurfaceControl other) {
// SurfaceControl 也保存了 native 层的对象
long surfaceControlPtr = other.mNativeObject;
// 根据 native 层的SurfaceControl对象创建一个native层的 surface 对象
long newNativeObject = nativeGetFromSurfaceControl(surfaceControlPtr);
synchronized (mLock) {
if (mNativeObject != 0) {
nativeRelease(mNativeObject);
}
// 然后将 native层的 surface 对象 和 java层的 surface 对象绑定到一起
setNativeObjectLocked(newNativeObject);
}
}
上面方法创建了 native 层的 surface 对象 并且和Java层的surface 层对象绑定一起,在创建对象的时候,
long newNativeObject = nativeGetFromSurfaceControl(surfaceControlPtr); 创建了一个 Surface对象,并且传入了 mGraphicBufferProducer 。也就是 SurfaceControl 中有一个 mGraphicBufferProducer 然后根据 mGraphicBufferProducer 创建了一个native 层 Surface 对象,然后将 native 层的 Surface 对象的指针,保存到 Java 层 Surface 对象中。
问题
-
怎么理解 surface 它是一块 buffer 么?
所以 surface 实际上有作用的是 GraphicBufferProducer 对象,它可以生成 buffer 。
-
如果是 buffer ,surface 如何跨进程携带它的?
所以它不是 buffer 它携带的是 GraphicBufferProducer ,GraphicBufferProducer 是一个 binder 对象。