美文网首页SurfaceFlinger
Android P 图形显示系统(四) Android Virt

Android P 图形显示系统(四) Android Virt

作者: 夕月风 | 来源:发表于2018-10-11 10:34 被阅读1789次

    [TOC]

    Android VirtualDisplay解析

    Android支持多个屏幕:主显,外显,和虚显,虚显就是我们要说的VirtualDisplay。VirtualDisplay的使用场景很多,比如录屏,WFD显示等。其作用就是抓取屏幕上显示的内容。VirtualDisplay抓取屏幕内容,其实现方式有很多。在API中就提供了ImageReader进行读取VirtualDisplay里的内容。

    下面我们就结合ImageReader,来看看VirtualDisplay及其相关流程。

    ImageReader和VirtualDisplay使用示例

    我们以VirtualDisplayTest为示例:

    1.在测试setUp时,初始化 DisplayManager, ImageReader 和 ImageListener ,代码如下:

    * frameworks/base/core/tests/coretestssrc/android/hardware/display/VirtualDisplayTest.java
    
        protected void setUp() throws Exception {
            super.setUp();
    
            mDisplayManager = (DisplayManager)mContext.getSystemService(Context.DISPLAY_SERVICE);
            mHandler = new Handler(Looper.getMainLooper());
            mImageListener = new ImageListener();
    
            mImageReaderLock.lock();
            try {
                mImageReader = ImageReader.newInstance(WIDTH, HEIGHT, PixelFormat.RGBA_8888, 2);
                mImageReader.setOnImageAvailableListener(mImageListener, mHandler);
                mSurface = mImageReader.getSurface();
            } finally {
                mImageReaderLock.unlock();
            }
        }
    
    
    • DisplayManager 管理Display的,系统中有对应的DisplayManagerService。
    • ImageListener实现OnImageAvailableListener接口。
    • ImageReader是一个图片读取器,它是OnImageAvailableListener接口的触发者
    • 另外,注意这里的mSurface。

    2.以测试项目testPrivateVirtualDisplay为例

        public void testPrivateVirtualDisplay() throws Exception {
            VirtualDisplay virtualDisplay = mDisplayManager.createVirtualDisplay(NAME,
                    WIDTH, HEIGHT, DENSITY, mSurface, 0);
            assertNotNull("virtual display must not be null", virtualDisplay);
    
            Display display = virtualDisplay.getDisplay();
            try {
                assertDisplayRegistered(display, Display.FLAG_PRIVATE);
    
                // Show a private presentation on the display.
                assertDisplayCanShowPresentation("private presentation window",
                        display, BLUEISH,
                        WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION, 0);
            } finally {
                virtualDisplay.release();
            }
            assertDisplayUnregistered(display);
        }
    
    • 测试时,先通过mDisplayManager,创建一个虚拟显示。
    • 通过assertDisplayRegistered判断虚显是否已经注册
    • 通过assertDisplayCanShowPresentation判断是否能显示私有的Presentation
    • 将虚显释放后,通过assertDisplayUnregistered判断是否已经撤销注册。

    这里Presentation是Andorid的一个显示控件,能够实现将要显示的内容显示到制定的显示屏上。

    实例代码就这么多,接下来,我们来看具体的流程。

    ImageReader介绍

    ImageReader,简单来说,就是使应用能够以图片数据的形式读取绘制到Surface中的内容。图片数据用Image描述。

    1.ImageReader的定义
    ImageReader的定义如下:

    * frameworks/base/media/java/android/media/ImageReader.java
    
        public static ImageReader newInstance(int width, int height, int format, int maxImages) {
            return new ImageReader(width, height, format, maxImages, BUFFER_USAGE_UNKNOWN);
        }
    

    这里的参数maxImages表示,能同时访问的Image数量,这里概念上和BufferQueue中的maxnumber也是类似的。

    ImageReader关键代码如下:

        protected ImageReader(int width, int height, int format, int maxImages, long usage) {
            mWidth = width;
            mHeight = height;
            mFormat = format;
            mMaxImages = maxImages;
    
            .. ...
    
            mNumPlanes = ImageUtils.getNumPlanesForFormat(mFormat);
    
            nativeInit(new WeakReference<>(this), width, height, format, maxImages, usage);
    
            mSurface = nativeGetSurface();
    
            mIsReaderValid = true;
            // Estimate the native buffer allocation size and register it so it gets accounted for
            // during GC. Note that this doesn't include the buffers required by the buffer queue
            // itself and the buffers requested by the producer.
            // Only include memory for 1 buffer, since actually accounting for the memory used is
            // complex, and 1 buffer is enough for the VM to treat the ImageReader as being of some
            // size.
            mEstimatedNativeAllocBytes = ImageUtils.getEstimatedNativeAllocBytes(
                    width, height, format, /*buffer count*/ 1);
            VMRuntime.getRuntime().registerNativeAllocation(mEstimatedNativeAllocBytes);
        }
    
    • 我们的格式是PixelFormat.RGBA_8888,所以这里的mNumPlanes值为1
    • nativeInit,native方法,创建一个native的ImageReader实例。
    • nativeGetSurface,native方法,获取对应的Native实例的Surface,注意,我们的Surface是从哪儿来的。

    2.ImageReader的JNI实现
    ImageReader的JNI实现如下,这里包含了ImageReader的方法和SurfaceImage的方法。

    * frameworks/base/media/jni/android_media_ImageReader.cpp
    
    static const JNINativeMethod gImageReaderMethods[] = {
        {"nativeClassInit",        "()V",                        (void*)ImageReader_classInit },
        {"nativeInit",             "(Ljava/lang/Object;IIIIJ)V",  (void*)ImageReader_init },
        {"nativeClose",            "()V",                        (void*)ImageReader_close },
        {"nativeReleaseImage",     "(Landroid/media/Image;)V",   (void*)ImageReader_imageRelease },
        {"nativeImageSetup",       "(Landroid/media/Image;)I",   (void*)ImageReader_imageSetup },
        {"nativeGetSurface",       "()Landroid/view/Surface;",   (void*)ImageReader_getSurface },
        {"nativeDetachImage",      "(Landroid/media/Image;)I",   (void*)ImageReader_detachImage },
        {"nativeDiscardFreeBuffers", "()V",                      (void*)ImageReader_discardFreeBuffers }
    };
    
    static const JNINativeMethod gImageMethods[] = {
        {"nativeCreatePlanes",      "(II)[Landroid/media/ImageReader$SurfaceImage$SurfacePlane;",
                                                                  (void*)Image_createSurfacePlanes },
        {"nativeGetWidth",         "()I",                        (void*)Image_getWidth },
        {"nativeGetHeight",        "()I",                        (void*)Image_getHeight },
        {"nativeGetFormat",        "(I)I",                        (void*)Image_getFormat },
    };
    
    

    nativeInit对应的方法为ImageReader_init:

    static void ImageReader_init(JNIEnv* env, jobject thiz, jobject weakThiz, jint width, jint height,
                                 jint format, jint maxImages, jlong ndkUsage)
    {
        ... ...
        sp<JNIImageReaderContext> ctx(new JNIImageReaderContext(env, weakThiz, clazz, maxImages));
    
        sp<IGraphicBufferProducer> gbProducer;
        sp<IGraphicBufferConsumer> gbConsumer;
        BufferQueue::createBufferQueue(&gbProducer, &gbConsumer);
        sp<BufferItemConsumer> bufferConsumer;
        String8 consumerName = String8::format("ImageReader-%dx%df%xm%d-%d-%d",
                width, height, format, maxImages, getpid(),
                createProcessUniqueId());
        ... ...
        bufferConsumer = new BufferItemConsumer(gbConsumer, consumerUsage, maxImages,
                /*controlledByApp*/true);
        if (bufferConsumer == nullptr) {
            jniThrowExceptionFmt(env, "java/lang/RuntimeException",
                    "Failed to allocate native buffer consumer for format 0x%x and usage 0x%x",
                    nativeFormat, consumerUsage);
            return;
        }
        ctx->setBufferConsumer(bufferConsumer);
        bufferConsumer->setName(consumerName);
    
        ctx->setProducer(gbProducer);
        bufferConsumer->setFrameAvailableListener(ctx);
        ImageReader_setNativeContext(env, thiz, ctx);
        ctx->setBufferFormat(nativeFormat);
        ctx->setBufferDataspace(nativeDataspace);
        ctx->setBufferWidth(width);
        ctx->setBufferHeight(height);
    
        // Set the width/height/format/dataspace to the bufferConsumer.
        res = bufferConsumer->setDefaultBufferSize(width, height);
        if (res != OK) {
            jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
                              "Failed to set buffer consumer default size (%dx%d) for format 0x%x",
                              width, height, nativeFormat);
            return;
        }
        res = bufferConsumer->setDefaultBufferFormat(nativeFormat);
        if (res != OK) {
            jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
                              "Failed to set buffer consumer default format 0x%x", nativeFormat);
        }
        res = bufferConsumer->setDefaultBufferDataSpace(nativeDataspace);
        if (res != OK) {
            jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
                              "Failed to set buffer consumer default dataSpace 0x%x", nativeDataspace);
        }
    }
    
    • 创建了一个JNIImageReaderContext实例,这个就是ImageReader的Native对应的对象。
    JNIImageReaderContext::JNIImageReaderContext(JNIEnv* env,
            jobject weakThiz, jclass clazz, int maxImages) :
        mWeakThiz(env->NewGlobalRef(weakThiz)),
        mClazz((jclass)env->NewGlobalRef(clazz)),
        mFormat(0),
        mDataSpace(HAL_DATASPACE_UNKNOWN),
        mWidth(-1),
        mHeight(-1) {
        for (int i = 0; i < maxImages; i++) {
            BufferItem* buffer = new BufferItem;
            mBuffers.push_back(buffer);
        }
    }
    

    这里的mDataSpace是数据空间,用以描述格式的。native的Buffer用BufferItem描述,在mBuffers中。

    • 创建对应的BufferQueue,生产者gbProducer,消费者gbConsumer。
      这里用的还是BufferQueue,Consumer端用BufferItemConsumer进行了封装。还记得我们Androdi正常显示的时候,Consumer是什么吗?没错BufferLayerConsumer,需要注意这其间的差别。BufferItemConsumer中持有gbConsumer对象。

    • 创建完BufferQueue后,再设置到 JNIImageReaderContext 中。注意BufferItemConsumer的FrameAvailableListener为JNIImageReaderContext中实现的FrameAvailableListener。

    • 最后通过ImageReader_setNativeContext,将native对象和Java的对象关联。

    JNIImageReaderContext的类图


    ImageReaderContext的类图

    VirtualDisplay的创建

    通过DisplayManager创建VirtualDisplay。

    * frameworks/base/core/java/android/hardware/display/DisplayManager.java
    
        public VirtualDisplay createVirtualDisplay(@Nullable MediaProjection projection,
                @NonNull String name, int width, int height, int densityDpi, @Nullable Surface surface,
                int flags, @Nullable VirtualDisplay.Callback callback, @Nullable Handler handler,
                @Nullable String uniqueId) {
            return mGlobal.createVirtualDisplay(mContext, projection,
                    name, width, height, densityDpi, surface, flags, callback, handler, uniqueId);
        }
    

    DisplayManagerGlobal是一个单例,Android系统中就这么一个。

        public DisplayManager(Context context) {
            mContext = context;
            mGlobal = DisplayManagerGlobal.getInstance();
        }
    

    DisplayManagerGlobal的createVirtualDisplay方法实现如下:

    * frameworks/base/core/java/android/hardware/display/DisplayManagerGlobal.java
    
        public VirtualDisplay createVirtualDisplay(Context context, MediaProjection projection,
                String name, int width, int height, int densityDpi, Surface surface, int flags,
                VirtualDisplay.Callback callback, Handler handler, String uniqueId) {
            ... ...
            int displayId;
            try {
                displayId = mDm.createVirtualDisplay(callbackWrapper, projectionToken,
                        context.getPackageName(), name, width, height, densityDpi, surface, flags,
                        uniqueId);
            } catch (RemoteException ex) {
                throw ex.rethrowFromSystemServer();
            }
            if (displayId < 0) {
                Log.e(TAG, "Could not create virtual display: " + name);
                return null;
            }
            Display display = getRealDisplay(displayId);
            if (display == null) {
                Log.wtf(TAG, "Could not obtain display info for newly created "
                        + "virtual display: " + name);
                try {
                    mDm.releaseVirtualDisplay(callbackWrapper);
                } catch (RemoteException ex) {
                    throw ex.rethrowFromSystemServer();
                }
                return null;
            }
            return new VirtualDisplay(this, display, callbackWrapper, surface);
        }
    

    mDm是DisplayManagerservice(DMS)的Stub。mDm.createVirtualDisplay直接看DMS的实现:

    * frameworks/base/services/core/java/com/android/server/display/DisplayManagerService.java
    
            @Override // Binder call
            public int createVirtualDisplay(IVirtualDisplayCallback callback,
                    IMediaProjection projection, String packageName, String name,
                    int width, int height, int densityDpi, Surface surface, int flags,
                    String uniqueId) {
                ... ...
    
                if (projection != null) {
                    try {
                        if (!getProjectionService().isValidMediaProjection(projection)) {
                            throw new SecurityException("Invalid media projection");
                        }
                        flags = projection.applyVirtualDisplayFlags(flags);
                    } catch (RemoteException e) {
                        throw new SecurityException("unable to validate media projection or flags");
                    }
                }
    
                if (callingUid != Process.SYSTEM_UID &&
                        (flags & VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR) != 0) {
                    if (!canProjectVideo(projection)) {
                        throw new SecurityException("Requires CAPTURE_VIDEO_OUTPUT or "
                                + "CAPTURE_SECURE_VIDEO_OUTPUT permission, or an appropriate "
                                + "MediaProjection token in order to create a screen sharing virtual "
                                + "display.");
                    }
                }
                if ((flags & VIRTUAL_DISPLAY_FLAG_SECURE) != 0) {
                    if (!canProjectSecureVideo(projection)) {
                        throw new SecurityException("Requires CAPTURE_SECURE_VIDEO_OUTPUT "
                                + "or an appropriate MediaProjection token to create a "
                                + "secure virtual display.");
                    }
                }
    
                final long token = Binder.clearCallingIdentity();
                try {
                    return createVirtualDisplayInternal(callback, projection, callingUid, packageName,
                            name, width, height, densityDpi, surface, flags, uniqueId);
                } finally {
                    Binder.restoreCallingIdentity(token);
                }
            }
    

    在DMS的createVirtualDisplay函数中,做了一些参数的初始化,project和secure的处理等。然后通过createVirtualDisplayInternal方法来真正创建。

    createVirtualDisplayInternal函数

        private int createVirtualDisplayInternal(IVirtualDisplayCallback callback,
                IMediaProjection projection, int callingUid, String packageName, String name, int width,
                int height, int densityDpi, Surface surface, int flags, String uniqueId) {
            synchronized (mSyncRoot) {
                if (mVirtualDisplayAdapter == null) {
                    Slog.w(TAG, "Rejecting request to create private virtual display "
                            + "because the virtual display adapter is not available.");
                    return -1;
                }
    
                DisplayDevice device = mVirtualDisplayAdapter.createVirtualDisplayLocked(
                        callback, projection, callingUid, packageName, name, width, height, densityDpi,
                        surface, flags, uniqueId);
                if (device == null) {
                    return -1;
                }
    
                handleDisplayDeviceAddedLocked(device);
                LogicalDisplay display = findLogicalDisplayForDeviceLocked(device);
                if (display != null) {
                    return display.getDisplayIdLocked();
                }
    
                // Something weird happened and the logical display was not created.
                Slog.w(TAG, "Rejecting request to create virtual display "
                        + "because the logical display was not created.");
                mVirtualDisplayAdapter.releaseVirtualDisplayLocked(callback.asBinder());
                handleDisplayDeviceRemovedLocked(device);
            }
            return -1;
        }
    
    • mVirtualDisplayAdapter是DMS启动的时候初始化的
      启动时,用消息MSG_REGISTER_DEFAULT_DISPLAY_ADAPTERS注册的。
        private void registerDefaultDisplayAdapters() {
            // Register default display adapters.
            synchronized (mSyncRoot) {
                // main display adapter
                registerDisplayAdapterLocked(new LocalDisplayAdapter(
                        mSyncRoot, mContext, mHandler, mDisplayAdapterListener));
    
                mVirtualDisplayAdapter = mInjector.getVirtualDisplayAdapter(mSyncRoot, mContext,
                        mHandler, mDisplayAdapterListener);
                if (mVirtualDisplayAdapter != null) {
                    registerDisplayAdapterLocked(mVirtualDisplayAdapter);
                }
            }
        }
    
    • mVirtualDisplayAdapter创建完后,用handleDisplayDeviceAddedLocked处理
      这里告诉Android上层,一个新的Display被添加了。
        private void handleDisplayDeviceAddedLocked(DisplayDevice device) {
            DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
            if (mDisplayDevices.contains(device)) {
                Slog.w(TAG, "Attempted to add already added display device: " + info);
                return;
            }
    
            Slog.i(TAG, "Display device added: " + info);
            device.mDebugLastLoggedDeviceInfo = info;
    
            mDisplayDevices.add(device);
            LogicalDisplay display = addLogicalDisplayLocked(device);
            Runnable work = updateDisplayStateLocked(device);
            if (work != null) {
                work.run();
            }
            scheduleTraversalLocked(false);
        }
    

    一个Display被添加了,先拿到它的信息,DisplayDeviceInfo。再将添加的 设备加到mDisplayDevices中。
    最后,通过addLogicalDisplayLocked创建一个对应的逻辑显示屏,通过updateDisplayStateLocked更新 Display的信息,和Native的VirtualDisplay的信息保持同步。

    VirtualDisplayAdapter的createVirtualDisplayLocked方法:

    * frameworks/base/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
    
        public DisplayDevice createVirtualDisplayLocked(IVirtualDisplayCallback callback,
                IMediaProjection projection, int ownerUid, String ownerPackageName, String name,
                int width, int height, int densityDpi, Surface surface, int flags, String uniqueId) {
            boolean secure = (flags & VIRTUAL_DISPLAY_FLAG_SECURE) != 0;
            IBinder appToken = callback.asBinder();
            IBinder displayToken = mSurfaceControlDisplayFactory.createDisplay(name, secure);
            final String baseUniqueId =
                    UNIQUE_ID_PREFIX + ownerPackageName + "," + ownerUid + "," + name + ",";
            final int uniqueIndex = getNextUniqueIndex(baseUniqueId);
            if (uniqueId == null) {
                uniqueId = baseUniqueId + uniqueIndex;
            } else {
                uniqueId = UNIQUE_ID_PREFIX + ownerPackageName + ":" + uniqueId;
            }
            VirtualDisplayDevice device = new VirtualDisplayDevice(displayToken, appToken,
                    ownerUid, ownerPackageName, name, width, height, densityDpi, surface, flags,
                    new Callback(callback, mHandler), uniqueId, uniqueIndex);
    
            mVirtualDisplayDevices.put(appToken, device);
    
            try {
                if (projection != null) {
                    projection.registerCallback(new MediaProjectionCallback(appToken));
                }
                appToken.linkToDeath(device, 0);
            } catch (RemoteException ex) {
                mVirtualDisplayDevices.remove(appToken);
                device.destroyLocked(false);
                return null;
            }
    
            // Return the display device without actually sending the event indicating
            // that it was added.  The caller will handle it.
            return device;
        }
    
    • 首先通过mSurfaceControlDisplayFactory创建一个displayToken,这个displayToken实际上是native的VirtualDisplay的token。
    • 最后VirtualDisplayAdapter创建的是一个VirtualDisplayDevice。

    这里的mSurfaceControlDisplayFactory其实是对SurfaceControl调用的一个封装:

        public VirtualDisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
                Context context, Handler handler, Listener listener) {
            this(syncRoot, context, handler, listener,
                    (String name, boolean secure) -> SurfaceControl.createDisplay(name, secure));
        }
    

    SurfaceControl的createDisplay,主要的是调用native函数,创建native的VirtualDisplay。

    * frameworks/base/core/java/android/view/SurfaceControl.java
    
        public static IBinder createDisplay(String name, boolean secure) {
            if (name == null) {
                throw new IllegalArgumentException("name must not be null");
            }
            return nativeCreateDisplay(name, secure);
        }
    

    到此Java层的创建VirtualDisplay的流程完成。

    VirtualDisplay在Java层相关的类关系如下:


    VirtualDisplay关系类图

    简单梳理一下:

    • Android提供了DMS管理系统的Display
    • DisplayManagerGlobal是DMS的一个代理,唯一的代理。
    • 应用可以通过DisplayManager和DMS通信
    • 每个Display都有一个对应的LogcalDisplay进行描述。
    • 具体的显示屏用DisplayDevice进行描述,系统里面分为很多类型,VirtualDisplayDevice只是其中的一类。
    • 每种类型都有自己对应的Adapter,VirtualDisplayAdapter和VirtualDisplayDevice对应。

    看完Java层的流程,我们再来看一下Native层的流程。我们关系的主要问题,还是ImageReader是怎么获取到显示屏幕的显示数据,显然现在还没有我们要的答案。

    Native创建VirtualDisplay

    nativeCreateDisplay函数JNI实现,如下:

    * android_view_SurfaceControl.cpp
    
    static jobject nativeCreateDisplay(JNIEnv* env, jclass clazz, jstring nameObj,
            jboolean secure) {
        ScopedUtfChars name(env, nameObj);
        sp<IBinder> token(SurfaceComposerClient::createDisplay(
                String8(name.c_str()), bool(secure)));
        return javaObjectForIBinder(env, token);
    }
    

    最终还是通过SurfaceComposerClient来创建的

    sp<IBinder> SurfaceComposerClient::createDisplay(const String8& displayName, bool secure) {
        return ComposerService::getComposerService()->createDisplay(displayName,
                secure);
    }
    

    ComposerService的服务端实现,就是SurfaceFlinger。

    sp<IBinder> SurfaceFlinger::createDisplay(const String8& displayName,
            bool secure)
    {
        class DisplayToken : public BBinder {
            sp<SurfaceFlinger> flinger;
            virtual ~DisplayToken() {
                 // no more references, this display must be terminated
                 Mutex::Autolock _l(flinger->mStateLock);
                 flinger->mCurrentState.displays.removeItem(this);
                 flinger->setTransactionFlags(eDisplayTransactionNeeded);
             }
         public:
            explicit DisplayToken(const sp<SurfaceFlinger>& flinger)
                : flinger(flinger) {
            }
        };
    
        sp<BBinder> token = new DisplayToken(this);
    
        Mutex::Autolock _l(mStateLock);
        DisplayDeviceState info(DisplayDevice::DISPLAY_VIRTUAL, secure);
        info.displayName = displayName;
        mCurrentState.displays.add(token, info);
        mInterceptor.saveDisplayCreation(info);
        return token;
    }
    

    SurfaceFlinger在创建Display时,创建了一个DisplayToken。这个就是Java中我们说的那个token了。然后在将token添加到mCurrentState的displays中。创建的Display就保存在displays中。

    Native的流程很简单,但是我们还没有看到数据是怎么流转的。别急,看看我们的Surface去哪儿了。

    数据流分析

    DisplayManager创建Display时,有mSurface,这个是ImageReader那边获取过来的。

    static jobject ImageReader_getSurface(JNIEnv* env, jobject thiz)
    {
        ALOGV("%s: ", __FUNCTION__);
    
        IGraphicBufferProducer* gbp = ImageReader_getProducer(env, thiz);
        if (gbp == NULL) {
            jniThrowRuntimeException(env, "Buffer consumer is uninitialized");
            return NULL;
        }
    
        // Wrap the IGBP in a Java-language Surface.
        return android_view_Surface_createFromIGraphicBufferProducer(env, gbp);
    }
    

    包装了一个IGraphicBufferProducer。现在我们再来捋一遍创建VirtualDisplay的流程,只关系Surface的去向。是不是最后给到了VirtualDisplayDevice中的mSurface。那么又是什么时候调的呢?

    再看看DMS的handleDisplayDeviceAddedLocked方法,是不是有个scheduleTraversalLocked的调用?

    这Traversal,通知了WMS,然后又从WMS绕回DMS,调的是
    DMS的performTraversalInTransactionFromWindowManager,最后在performTraversalInTransactionLocked中,将调每个Device的performTraversalInTransactionLocked函数。

        private void performTraversalInTransactionLocked() {
            // Clear all viewports before configuring displays so that we can keep
            // track of which ones we have configured.
            clearViewportsLocked();
    
            // Configure each display device.
            final int count = mDisplayDevices.size();
            for (int i = 0; i < count; i++) {
                DisplayDevice device = mDisplayDevices.get(i);
                configureDisplayInTransactionLocked(device);
                device.performTraversalInTransactionLocked();
            }
    
            // Tell the input system about these new viewports.
            if (mInputManagerInternal != null) {
                mHandler.sendEmptyMessage(MSG_UPDATE_VIEWPORT);
            }
        }
    

    VirtualDisplayDevice的performTraversalInTransactionLocked函数如下:

            public void performTraversalInTransactionLocked() {
                if ((mPendingChanges & PENDING_RESIZE) != 0) {
                    SurfaceControl.setDisplaySize(getDisplayTokenLocked(), mWidth, mHeight);
                }
                if ((mPendingChanges & PENDING_SURFACE_CHANGE) != 0) {
                    setSurfaceInTransactionLocked(mSurface);
                }
                mPendingChanges = 0;
            }
    

    PENDING_SURFACE_CHANGE这个伏笔,在VirtualDisplayDevice创建的时候就已经埋下了。

            public VirtualDisplayDevice(IBinder displayToken, IBinder appToken,
                    int ownerUid, String ownerPackageName,
                    String name, int width, int height, int densityDpi, Surface surface, int flags,
                    Callback callback, String uniqueId, int uniqueIndex) {
                super(VirtualDisplayAdapter.this, displayToken, uniqueId);
                mAppToken = appToken;
                mOwnerUid = ownerUid;
                mOwnerPackageName = ownerPackageName;
                mName = name;
                mWidth = width;
                mHeight = height;
                mMode = createMode(width, height, REFRESH_RATE);
                mDensityDpi = densityDpi;
                mSurface = surface;
                mFlags = flags;
                mCallback = callback;
                mDisplayState = Display.STATE_UNKNOWN;
                mPendingChanges |= PENDING_SURFACE_CHANGE;
                mUniqueIndex = uniqueIndex;
            }
    

    没毛病~ 再通过setSurfaceInTransactionLocked函数,将Surface通过SurfaceControl,传给Native的VirtualDisplay。

        public final void setSurfaceInTransactionLocked(Surface surface) {
            if (mCurrentSurface != surface) {
                mCurrentSurface = surface;
                SurfaceControl.setDisplaySurface(mDisplayToken, surface);
            }
        }
    

    SurfaceControl中有个一个sGlobalTransaction,Surface被暂时保存到sGlobalTransaction中。

        public static void setDisplaySurface(IBinder displayToken, Surface surface) {
            synchronized (SurfaceControl.class) {
                sGlobalTransaction.setDisplaySurface(displayToken, surface);
            }
        }
    

    sGlobalTransaction生效是在closeTransaction时,这里是由WMS调的。openTransaction和closeTransaction成对出现,一个打开一个关闭。关闭时生效。

        private static void closeTransaction(boolean sync) {
            synchronized(SurfaceControl.class) {
                if (sTransactionNestCount == 0) {
                    Log.e(TAG, "Call to SurfaceControl.closeTransaction without matching openTransaction");
                } else if (--sTransactionNestCount > 0) {
                    return;
                }
                sGlobalTransaction.apply(sync);
            }
        }
    

    apply函数如下:

            public void apply(boolean sync) {
                applyResizedSurfaces();
                nativeApplyTransaction(mNativeObject, sync);
            }
    
    • 一些同步被保存到SurfaceControl中
    • 再通过nativeApplyTransaction给到底层。

    在JNI中将java的Transaction转换我们native的Transaction。

    static void nativeApplyTransaction(JNIEnv* env, jclass clazz, jlong transactionObj, jboolean sync) {
        auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
        transaction->apply(sync);
    }
    

    而我们的nativeSetDisplaySurface,最后如下:

    status_t SurfaceComposerClient::Transaction::setDisplaySurface(const sp<IBinder>& token,
            const sp<IGraphicBufferProducer>& bufferProducer) {
        if (bufferProducer.get() != nullptr) {
            // Make sure that composition can never be stalled by a virtual display
            // consumer that isn't processing buffers fast enough.
            status_t err = bufferProducer->setAsyncMode(true);
            if (err != NO_ERROR) {
                ALOGE("Composer::setDisplaySurface Failed to enable async mode on the "
                        "BufferQueue. This BufferQueue cannot be used for virtual "
                        "display. (%d)", err);
                return err;
            }
        }
        DisplayState& s(getDisplayStateLocked(token));
        s.surface = bufferProducer;
        s.what |= DisplayState::eSurfaceChanged;
        return NO_ERROR;
    }
    

    直接看SurfaceFlinger中的处理吧,注意我们这里what是DisplayState::eSurfaceChanged。

    void SurfaceFlinger::setTransactionState(
            const Vector<ComposerState>& state,
            const Vector<DisplayState>& displays,
            uint32_t flags)
    {
        ... ...
    
        size_t count = displays.size();
        for (size_t i=0 ; i<count ; i++) {
            const DisplayState& s(displays[i]);
            transactionFlags |= setDisplayStateLocked(s);
        }
        ... ...
    }
    

    SF在setTransactionState时,调用每Display的setDisplayStateLocked

    uint32_t SurfaceFlinger::setDisplayStateLocked(const DisplayState& s)
    {
        ssize_t dpyIdx = mCurrentState.displays.indexOfKey(s.token);
        if (dpyIdx < 0)
            return 0;
    
        uint32_t flags = 0;
        DisplayDeviceState& disp(mCurrentState.displays.editValueAt(dpyIdx));
        if (disp.isValid()) {
            const uint32_t what = s.what;
            if (what & DisplayState::eSurfaceChanged) {
                if (IInterface::asBinder(disp.surface) != IInterface::asBinder(s.surface)) {
                    disp.surface = s.surface;
                    flags |= eDisplayTransactionNeeded;
                }
            }
    

    前面我们创建的VirtualDisplay的token是不是Add到了mCurrentState.displays中,现在我们编辑它,将ImageReader那边给过来的Surface给到了disp.surface。

    Oops~ 记住,我们的Surface给给到了mCurrentState.displays的disp.surface。

    setTransactionState完成后,将通过setTransactionFlags出发SurfaceFlinger工作。SurfaceFlinger将处理Transaction。也就是会调用到handleTransaction函数。

    我们只看和处理 Display相关的流程,这里将有一个场大战。

    void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags)
    {
                ... ...
                // find displays that were added
                // (ie: in current state but not in drawing state)
                for (size_t i=0 ; i<cc ; i++) {
                    if (draw.indexOfKey(curr.keyAt(i)) < 0) {
                        const DisplayDeviceState& state(curr[i]);
    
                        sp<DisplaySurface> dispSurface;
                        sp<IGraphicBufferProducer> producer;
                        sp<IGraphicBufferProducer> bqProducer;
                        sp<IGraphicBufferConsumer> bqConsumer;
                        BufferQueue::createBufferQueue(&bqProducer, &bqConsumer);
    
                        int32_t hwcId = -1;
                        if (state.isVirtualDisplay()) {
                            // Virtual displays without a surface are dormant:
                            // they have external state (layer stack, projection,
                            // etc.) but no internal state (i.e. a DisplayDevice).
                            if (state.surface != NULL) {
    
                                // Allow VR composer to use virtual displays.
                                if (mUseHwcVirtualDisplays || getBE().mHwc->isUsingVrComposer()) {
                                    ... ...//这类的流程我们暂时走不到,先不看。
                                }
    
                                sp<VirtualDisplaySurface> vds =
                                        new VirtualDisplaySurface(*getBE().mHwc,
                                                hwcId, state.surface, bqProducer,
                                                bqConsumer, state.displayName);
    
                                dispSurface = vds;
                                producer = vds;
                            }
                        } else {
                            ... ...主显示,先不关心
                        }
    
                        const wp<IBinder>& display(curr.keyAt(i));
                        if (dispSurface != NULL) {
                            sp<DisplayDevice> hw =
                                    new DisplayDevice(this, state.type, hwcId, state.isSecure, display,
                                                      dispSurface, producer, hasWideColorDisplay);
                            hw->setLayerStack(state.layerStack);
                            hw->setProjection(state.orientation,
                                    state.viewport, state.frame);
                            hw->setDisplayName(state.displayName);
                            mDisplays.add(display, hw);
                            if (!state.isVirtualDisplay()) {
                                mEventThread->onHotplugReceived(state.type, true);
                            }
                        }
                    }
                }
    
    • 首先从DisplayDeviceState中拿出一个DisplayDeviceState
    • 创建一个createBufferQueue,注意区分这里的producer和bqProducer
    • 判断是不是虚显,如果是虚显,且state.surface不为空,将创建一个VirtualDisplaySurface,注意这里dispSurface和producer都是我们刚创建的VirtualDisplaySurface对象vds。
    • 最后创建DisplayDevice对象hw,初始化hw ,并添加到mDisplays中。
    • 另外,要注意的是,这里的 hwcId 为-1

    这里引出了两个重要的量级类DisplayDevice和VirtualDisplaySurface。

    我们先来看VirtualDisplaySurface

    class VirtualDisplaySurface : public DisplaySurface,
                                  public BnGraphicBufferProducer,
                                  private ConsumerBase {
    

    厉害了,我的VirtualDisplaySurface,继承了BnGraphicBufferProducer和ConsumerBase。这是即做Producer,也做Consumer。

    先来看VirtualDisplaySurface的构造函数:

    * frameworks/native/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
    
    VirtualDisplaySurface::VirtualDisplaySurface(HWComposer& hwc, int32_t dispId,
            const sp<IGraphicBufferProducer>& sink,
            const sp<IGraphicBufferProducer>& bqProducer,
            const sp<IGraphicBufferConsumer>& bqConsumer,
            const String8& name)
    :   ConsumerBase(bqConsumer),
        mHwc(hwc),
        mDisplayId(dispId),
        mDisplayName(name),
        mSource{},
        mDefaultOutputFormat(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED),
        mOutputFormat(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED),
        mOutputUsage(GRALLOC_USAGE_HW_COMPOSER),
        mProducerSlotSource(0),
        mProducerBuffers(),
        mQueueBufferOutput(),
        mSinkBufferWidth(0),
        mSinkBufferHeight(0),
        mCompositionType(COMPOSITION_UNKNOWN),
        mFbFence(Fence::NO_FENCE),
        mOutputFence(Fence::NO_FENCE),
        mFbProducerSlot(BufferQueue::INVALID_BUFFER_SLOT),
        mOutputProducerSlot(BufferQueue::INVALID_BUFFER_SLOT),
        mDbgState(DBG_STATE_IDLE),
        mDbgLastCompositionType(COMPOSITION_UNKNOWN),
        mMustRecompose(false),
        mForceHwcCopy(SurfaceFlinger::useHwcForRgbToYuv)
    {
        mSource[SOURCE_SINK] = sink;
        mSource[SOURCE_SCRATCH] = bqProducer;
    
        resetPerFrameState();
    
        int sinkWidth, sinkHeight;
        sink->query(NATIVE_WINDOW_WIDTH, &sinkWidth);
        sink->query(NATIVE_WINDOW_HEIGHT, &sinkHeight);
        mSinkBufferWidth = sinkWidth;
        mSinkBufferHeight = sinkHeight;
    
        // Pick the buffer format to request from the sink when not rendering to it
        // with GLES. If the consumer needs CPU access, use the default format
        // set by the consumer. Otherwise allow gralloc to decide the format based
        // on usage bits.
        int sinkUsage;
        sink->query(NATIVE_WINDOW_CONSUMER_USAGE_BITS, &sinkUsage);
        if (sinkUsage & (GRALLOC_USAGE_SW_READ_MASK | GRALLOC_USAGE_SW_WRITE_MASK)) {
            int sinkFormat;
            sink->query(NATIVE_WINDOW_FORMAT, &sinkFormat);
            mDefaultOutputFormat = sinkFormat;
        } else {
            mDefaultOutputFormat = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
        }
        mOutputFormat = mDefaultOutputFormat;
    
        ConsumerBase::mName = String8::format("VDS: %s", mDisplayName.string());
        mConsumer->setConsumerName(ConsumerBase::mName);
        mConsumer->setConsumerUsageBits(GRALLOC_USAGE_HW_COMPOSER);
        mConsumer->setDefaultBufferSize(sinkWidth, sinkHeight);
        sink->setAsyncMode(true);
        IGraphicBufferProducer::QueueBufferOutput output;
        mSource[SOURCE_SCRATCH]->connect(NULL, NATIVE_WINDOW_API_EGL, false, &output);
    }
    
    • ImageReader那边过来的Surface,被保存在mSource[SOURCE_SINK] 中
    • 新创建的BufferQueue的Producer保存在mSource[SOURCE_SCRATCH] 中
    • 新的BufferQueue的Consumer给到mConsumer。
    • mDisplayId为-1

    看明白了没有?这里主要点是的两个BufferQueue。一个是ImageReader的,另一个是VirtualDisplay的,也就是DisplayDevice的。

    DisplayDevice的BufferQueue,为了便于区分,我们私自命名一个DisplayBufferQueue,主要是用来GLES合成,合成后的数据就queue到这个BufferQueue中。

    ImageReader的BufferQueue,为了便于区分,我们私自命名一个ReaderBufferQueue,主要是用来读数据,合成完的数据,queue到DisplayBufferQueue中,再queue到ReaderBufferQueue。

    事实上,DisplayBufferQueue的Buffer,也是从ReaderBufferQueue中dequeue出来的。我们来看一下VirtualDisplaySurface的dequeueBuffer和queueBuffer方法就明白了。

    * frameworks/native/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
    
    status_t VirtualDisplaySurface::dequeueBuffer(int* pslot, sp<Fence>* fence, uint32_t w, uint32_t h,
                                                  PixelFormat format, uint64_t usage,
                                                  uint64_t* outBufferAge,
                                                  FrameEventHistoryDelta* outTimestamps) {
        if (mDisplayId < 0) {
            return mSource[SOURCE_SINK]->dequeueBuffer(pslot, fence, w, h, format, usage, outBufferAge,
                                                       outTimestamps);
        }
        ... ...
    }
    
    
    status_t VirtualDisplaySurface::queueBuffer(int pslot,
            const QueueBufferInput& input, QueueBufferOutput* output) {
        if (mDisplayId < 0)
            return mSource[SOURCE_SINK]->queueBuffer(pslot, input, output);
        ... ...
    }
    

    看到没有,因为ImageReader使用时,mDisplayId为-1,所以,这里直接走的SOURCE_SINK mSource,就ImageReader那边的BufferQueue。我们加一个栈看看dequeueBuffer和queueBuffer。

    VirtualDisplaySurface的dequeueBuffer栈

    01-03 13:53:16.709   265   265 D VirtualDisplaySurface_queueBuffer1: #00 pc 0006f6db  /system/lib/libsurfaceflinger.so
    01-03 13:53:16.710   265   265 D VirtualDisplaySurface_queueBuffer1: #01 pc 00054cb3  /system/lib/libgui.so (android::Surface::dequeueBuffer(ANativeWindowBuffer**, int*)+346)
    01-03 13:53:16.710   265   265 D VirtualDisplaySurface_queueBuffer1: #02 pc 0069e648  /vendor/lib/egl/libGLES_mali.so
    01-03 13:53:16.710   265   265 D VirtualDisplaySurface_queueBuffer1: #03 pc 00345970  /vendor/lib/egl/libGLES_mali.so
    01-03 13:53:16.710   265   265 D VirtualDisplaySurface_queueBuffer1: #04 pc 0034582c  /vendor/lib/egl/libGLES_mali.so
    01-03 13:53:16.710   265   265 D VirtualDisplaySurface_queueBuffer1: #05 pc 00633650  /vendor/lib/egl/libGLES_mali.so
    01-03 13:53:16.710   265   265 D VirtualDisplaySurface_queueBuffer1: #06 pc 0062b30c  /vendor/lib/egl/libGLES_mali.so
    01-03 13:53:16.710   265   265 D VirtualDisplaySurface_queueBuffer1: #07 pc 00633474  /vendor/lib/egl/libGLES_mali.so
    01-03 13:53:16.710   265   265 D VirtualDisplaySurface_queueBuffer1: #08 pc 00627d3c  /vendor/lib/egl/libGLES_mali.so
    01-03 13:53:16.710   265   265 D VirtualDisplaySurface_queueBuffer1: #09 pc 0062a820  /vendor/lib/egl/libGLES_mali.so
    01-03 13:53:16.710   265   265 D VirtualDisplaySurface_queueBuffer1: #10 pc 000737c9  /system/lib/libsurfaceflinger.so
    01-03 13:53:16.710   265   265 D VirtualDisplaySurface_queueBuffer1: #11 pc 000721b1  /system/lib/libsurfaceflinger.so
    01-03 13:53:16.711   265   265 D VirtualDisplaySurface_queueBuffer1: #12 pc 00079fad  /system/lib/libsurfaceflinger.so
    01-03 13:53:16.711   265   265 D VirtualDisplaySurface_queueBuffer1: #13 pc 0007ab59  /system/lib/libsurfaceflinger.so
    01-03 13:53:16.711   265   265 D VirtualDisplaySurface_queueBuffer1: #14 pc 000797cf  /system/lib/libsurfaceflinger.so
    01-03 13:53:16.711   265   265 D VirtualDisplaySurface_queueBuffer1: #15 pc 00078629  /system/lib/libsurfaceflinger.so
    01-03 13:53:16.711   265   265 D VirtualDisplaySurface_queueBuffer1: #16 pc 00078411  /system/lib/libsurfaceflinger.so
    01-03 13:53:16.711   265   265 D VirtualDisplaySurface_queueBuffer1: #17 pc 000100a3  /system/lib/libutils.so (android::Looper::pollInner(int)+294)
    01-03 13:53:16.711   265   265 D VirtualDisplaySurface_queueBuffer1: #18 pc 0000fee5  /system/lib/libutils.so (android::Looper::pollOnce(int, int*, int*, void**)+32)
    01-03 13:53:16.711   265   265 D VirtualDisplaySurface_queueBuffer1: #19 pc 00061ba7  /system/lib/libsurfaceflinger.so
    01-03 13:53:16.711   265   265 D VirtualDisplaySurface_queueBuffer1: #20 pc 000773d1  /system/lib/libsurfaceflinger.so (android::SurfaceFlinger::run()+8)
    01-03 13:53:16.711   265   265 D VirtualDisplaySurface_queueBuffer1: #21 pc 00002141  /system/bin/surfaceflinger
    01-03 13:53:16.711   265   265 D VirtualDisplaySurface_queueBuffer1: #22 pc 000774a9  /system/lib/libc.so (__libc_init+48)
    01-03 13:53:16.711   265   265 D VirtualDisplaySurface_queueBuffer1: #23 pc 00001df4  /system/bin/surfaceflinger
    

    VirtualDisplaySurface的queueBuffer栈

    01-03 13:53:16.774   265   265 D VirtualDisplaySurface_queueBuffer: #01 pc 00055423  /system/lib/libgui.so (android::Surface::queueBuffer(ANativeWindowBuffer*, int)+594)
    01-03 13:53:16.774   265   265 D VirtualDisplaySurface_queueBuffer: #02 pc 0069eb38  /vendor/lib/egl/libGLES_mali.so
    01-03 13:53:16.774   265   265 D VirtualDisplaySurface_queueBuffer: #03 pc 0034628c  /vendor/lib/egl/libGLES_mali.so
    01-03 13:53:16.774   265   265 D VirtualDisplaySurface_queueBuffer: #04 pc 00346f60  /vendor/lib/egl/libGLES_mali.so
    01-03 13:53:16.774   265   265 D VirtualDisplaySurface_queueBuffer: #05 pc 00346930  /vendor/lib/egl/libGLES_mali.so (eglp_swap_buffers+740)
    01-03 13:53:16.774   265   265 D VirtualDisplaySurface_queueBuffer: #06 pc 0000ca29  /system/lib/libEGL.so (eglSwapBuffersWithDamageKHR+236)
    01-03 13:53:16.774   265   265 D VirtualDisplaySurface_queueBuffer: #07 pc 0005135d  /system/lib/libsurfaceflinger.so
    01-03 13:53:16.774   265   265 D VirtualDisplaySurface_queueBuffer: #08 pc 0007ab71  /system/lib/libsurfaceflinger.so
    01-03 13:53:16.774   265   265 D VirtualDisplaySurface_queueBuffer: #09 pc 000797cf  /system/lib/libsurfaceflinger.so
    01-03 13:53:16.774   265   265 D VirtualDisplaySurface_queueBuffer: #10 pc 00078629  /system/lib/libsurfaceflinger.so
    01-03 13:53:16.775   265   265 D VirtualDisplaySurface_queueBuffer: #11 pc 00078411  /system/lib/libsurfaceflinger.so
    01-03 13:53:16.775   265   265 D VirtualDisplaySurface_queueBuffer: #12 pc 000100a3  /system/lib/libutils.so (android::Looper::pollInner(int)+294)
    01-03 13:53:16.775   265   265 D VirtualDisplaySurface_queueBuffer: #13 pc 0000fee5  /system/lib/libutils.so (android::Looper::pollOnce(int, int*, int*, void**)+32)
    01-03 13:53:16.775   265   265 D VirtualDisplaySurface_queueBuffer: #14 pc 00061ba7  /system/lib/libsurfaceflinger.so
    01-03 13:53:16.775   265   265 D VirtualDisplaySurface_queueBuffer: #15 pc 000773d1  /system/lib/libsurfaceflinger.so (android::SurfaceFlinger::run()+8)
    01-03 13:53:16.775   265   265 D VirtualDisplaySurface_queueBuffer: #16 pc 00002141  /system/bin/surfaceflinger
    01-03 13:53:16.775   265   265 D VirtualDisplaySurface_queueBuffer: #17 pc 000774a9  /system/lib/libc.so (__libc_init+48)
    01-03 13:53:16.775   265   265 D VirtualDisplaySurface_queueBuffer: #18 pc 00001df4  /system/bin/surfaceflinger
    

    合成的流程这里就不介绍了,只是这个数据流,大家再仔细体会。

    ImageReader获取数据

    我们再回到测试,看看ImageReader是怎么对到数据的。

    合成的数据queue过来后,将会调回调到JNIImageReaderContext的监听,onFrameAvailable。

    void JNIImageReaderContext::onFrameAvailable(const BufferItem& /*item*/)
    {
        ALOGV("%s: frame available", __FUNCTION__);
        bool needsDetach = false;
        JNIEnv* env = getJNIEnv(&needsDetach);
        if (env != NULL) {
            env->CallStaticVoidMethod(mClazz, gImageReaderClassInfo.postEventFromNative, mWeakThiz);
        } else {
            ALOGW("onFrameAvailable event will not posted");
        }
        if (needsDetach) {
            detachJNI();
        }
    }
    

    postEventFromNative是java的方法

        private static void postEventFromNative(Object selfRef) {
            @SuppressWarnings("unchecked")
            WeakReference<ImageReader> weakSelf = (WeakReference<ImageReader>)selfRef;
            final ImageReader ir = weakSelf.get();
            if (ir == null) {
                return;
            }
    
            final Handler handler;
            synchronized (ir.mListenerLock) {
                handler = ir.mListenerHandler;
            }
            if (handler != null) {
                handler.sendEmptyMessage(0);
            }
        }
    

    这里的handler是一个ListenerHandler。

        private final class ListenerHandler extends Handler {
            public ListenerHandler(Looper looper) {
                super(looper, null, true /*async*/);
            }
    
            @Override
            public void handleMessage(Message msg) {
                OnImageAvailableListener listener;
                synchronized (mListenerLock) {
                    listener = mListener;
                }
    
                // It's dangerous to fire onImageAvailable() callback when the ImageReader is being
                // closed, as application could acquire next image in the onImageAvailable() callback.
                boolean isReaderValid = false;
                synchronized (mCloseLock) {
                    isReaderValid = mIsReaderValid;
                }
                if (listener != null && isReaderValid) {
                    listener.onImageAvailable(ImageReader.this);
                }
            }
        }
    

    这里终于调回测试代码中onImageAvailable

            public void onImageAvailable(ImageReader reader) {
                mImageReaderLock.lock();
                try {
                    if (reader != mImageReader) {
                        return;
                    }
    
                    Log.d(TAG, "New image available from virtual display.");
    
                    // Get the latest buffer.
                    Image image = reader.acquireLatestImage();
                    if (image != null) {
                        try {
                            // Scan for colors.
                            int color = scanImage(image);
                            synchronized (this) {
                                if (mColor != color) {
                                    mColor = color;
                                    notifyAll();
                                }
                            }
                        } finally {
                            image.close();
                        }
                    }
                } finally {
                    mImageReaderLock.unlock();
                }
            }
    

    看到没有,这个和SurfaceFlinger中Layer的处理是不相似?通过ImageReader去acquireLatestImage。

        public Image acquireLatestImage() {
            Image image = acquireNextImage();
            if (image == null) {
                return null;
            }
            try {
                for (;;) {
                    Image next = acquireNextImageNoThrowISE();
                    if (next == null) {
                        Image result = image;
                        image = null;
                        return result;
                    }
                    image.close();
                    image = next;
                }
            } finally {
                if (image != null) {
                    image.close();
                }
            }
        }
    

    这里有一个循环,目的就是获取,最后一帧数据。acquireNextImage和acquireNextImageNoThrowISE是类似的,只是一个会抛出异常,一个不会。

        public Image acquireNextImage() {
            // Initialize with reader format, but can be overwritten by native if the image
            // format is different from the reader format.
            SurfaceImage si = new SurfaceImage(mFormat);
            int status = acquireNextSurfaceImage(si);
    
            switch (status) {
                case ACQUIRE_SUCCESS:
                    return si;
                case ACQUIRE_NO_BUFS:
                    return null;
                case ACQUIRE_MAX_IMAGES:
                    throw new IllegalStateException(
                            String.format(
                                    "maxImages (%d) has already been acquired, " +
                                    "call #close before acquiring more.", mMaxImages));
                default:
                    throw new AssertionError("Unknown nativeImageSetup return code " + status);
            }
        }
    

    acquireNextImage出错后,会抛一些异常。

        private int acquireNextSurfaceImage(SurfaceImage si) {
            synchronized (mCloseLock) {
                // A null image will eventually be returned if ImageReader is already closed.
                int status = ACQUIRE_NO_BUFS;
                if (mIsReaderValid) {
                    status = nativeImageSetup(si);
                }
    
                switch (status) {
                    case ACQUIRE_SUCCESS:
                        si.mIsImageValid = true;
                    case ACQUIRE_NO_BUFS:
                    case ACQUIRE_MAX_IMAGES:
                        break;
                    default:
                        throw new AssertionError("Unknown nativeImageSetup return code " + status);
                }
    
                // Only keep track the successfully acquired image, as the native buffer is only mapped
                // for such case.
                if (status == ACQUIRE_SUCCESS) {
                    mAcquiredImages.add(si);
                }
                return status;
            }
        }
    

    这类终于调到关键的了,nativeImageSetup函数。对应的JNI函数为ImageReader_imageSetup。

    ImageReader_imageSetup函数:

    static jint ImageReader_imageSetup(JNIEnv* env, jobject thiz, jobject image) {
        ALOGV("%s:", __FUNCTION__);
        JNIImageReaderContext* ctx = ImageReader_getContext(env, thiz);
        if (ctx == NULL) {
            jniThrowException(env, "java/lang/IllegalStateException",
                    "ImageReader is not initialized or was already closed");
            return -1;
        }
    
        BufferItemConsumer* bufferConsumer = ctx->getBufferConsumer();
        BufferItem* buffer = ctx->getBufferItem();
        if (buffer == NULL) {
            ALOGW("Unable to acquire a buffer item, very likely client tried to acquire more than"
                " maxImages buffers");
            return ACQUIRE_MAX_IMAGES;
        }
    
        status_t res = bufferConsumer->acquireBuffer(buffer, 0);
        if (res != OK) {
            ... ...
        }
    
        // Add some extra checks for non-opaque formats.
        if (!isFormatOpaque(ctx->getBufferFormat())) {
            ... ...
        }
    
        // Set SurfaceImage instance member variables
        Image_setBufferItem(env, image, buffer);
        env->SetLongField(image, gSurfaceImageClassInfo.mTimestamp,
                static_cast<jlong>(buffer->mTimestamp));
    
        return ACQUIRE_SUCCESS;
    }
    
    • 获取JNIImageReaderContext对象ctx
    • 从ctx中获取对应地Consumer BufferItemConsumer
    • 通过BufferItemConsumer的acquireBuffer接口去请求一块Buffer BufferItem
    • 将BufferItem和SurfaceImage关联
    static void Image_setBufferItem(JNIEnv* env, jobject thiz,
            const BufferItem* buffer)
    {
        env->SetLongField(thiz, gSurfaceImageClassInfo.mNativeBuffer, reinterpret_cast<jlong>(buffer));
    }
    
    • 设置SurfaceImage的timeStamp

    BufferItemConsumer的acquireBuffer函数如下:

    status_t BufferItemConsumer::acquireBuffer(BufferItem *item,
            nsecs_t presentWhen, bool waitForFence) {
        status_t err;
    
        if (!item) return BAD_VALUE;
    
        Mutex::Autolock _l(mMutex);
    
        err = acquireBufferLocked(item, presentWhen);
        if (err != OK) {
            if (err != NO_BUFFER_AVAILABLE) {
                BI_LOGE("Error acquiring buffer: %s (%d)", strerror(err), err);
            }
            return err;
        }
    
        if (waitForFence) {
            err = item->mFence->waitForever("BufferItemConsumer::acquireBuffer");
            if (err != OK) {
                BI_LOGE("Failed to wait for fence of acquired buffer: %s (%d)",
                        strerror(-err), err);
                return err;
            }
        }
    
        item->mGraphicBuffer = mSlots[item->mSlot].mGraphicBuffer;
    
        return OK;
    }
    

    这里waitForFence为0,这里不会去等Fence。

    最终还是通过ConsumerBase的acquireBufferLocked去获取的

    status_t ConsumerBase::acquireBufferLocked(BufferItem *item,
            nsecs_t presentWhen, uint64_t maxFrameNumber) {
        if (mAbandoned) {
            CB_LOGE("acquireBufferLocked: ConsumerBase is abandoned!");
            return NO_INIT;
        }
    
        status_t err = mConsumer->acquireBuffer(item, presentWhen, maxFrameNumber);
        if (err != NO_ERROR) {
            return err;
        }
    
        if (item->mGraphicBuffer != NULL) {
            if (mSlots[item->mSlot].mGraphicBuffer != NULL) {
                freeBufferLocked(item->mSlot);
            }
            mSlots[item->mSlot].mGraphicBuffer = item->mGraphicBuffer;
        }
    
        mSlots[item->mSlot].mFrameNumber = item->mFrameNumber;
        mSlots[item->mSlot].mFence = item->mFence;
    
        CB_LOGV("acquireBufferLocked: -> slot=%d/%" PRIu64,
                item->mSlot, item->mFrameNumber);
    
        return OK;
    }
    

    mConsumer为ImageReader的BufferQueue的Consumer。要是不记得了,回头去看看ImageReader_init。mConsumer通过acquireBuffer函数获取回来的,就是虚显合成后的数据。

    这里用了两个BufferQueue,千万不要混淆了。

    最后,测试代码中来扫描图时的处理,scanImage函数。

            private int scanImage(Image image) {
                final Image.Plane plane = image.getPlanes()[0];
                final ByteBuffer buffer = plane.getBuffer();
    

    getPlanes函数如下:

            public Plane[] getPlanes() {
                throwISEIfImageIsInvalid();
    
                if (mPlanes == null) {
                    mPlanes = nativeCreatePlanes(ImageReader.this.mNumPlanes, ImageReader.this.mFormat);
                }
                // Shallow copy is fine.
                return mPlanes.clone();
            }
    

    对应的JNI函数为Image_createSurfacePlanes:

    static jobjectArray Image_createSurfacePlanes(JNIEnv* env, jobject thiz,
            int numPlanes, int readerFormat)
    {
        ... ...
    
        jobjectArray surfacePlanes = env->NewObjectArray(numPlanes, gSurfacePlaneClassInfo.clazz,
                /*initial_element*/NULL);
        ... ...
    
        LockedImage lockedImg = LockedImage();
        Image_getLockedImage(env, thiz, &lockedImg);
        if (env->ExceptionCheck()) {
            return NULL;
        }
        // Create all SurfacePlanes
        for (int i = 0; i < numPlanes; i++) {
            Image_getLockedImageInfo(env, &lockedImg, i, halReaderFormat,
                    &pData, &dataSize, &pixelStride, &rowStride);
            byteBuffer = env->NewDirectByteBuffer(pData, dataSize);
            if ((byteBuffer == NULL) && (env->ExceptionCheck() == false)) {
                jniThrowException(env, "java/lang/IllegalStateException",
                        "Failed to allocate ByteBuffer");
                return NULL;
            }
    
            // Finally, create this SurfacePlane.
            jobject surfacePlane = env->NewObject(gSurfacePlaneClassInfo.clazz,
                        gSurfacePlaneClassInfo.ctor, thiz, rowStride, pixelStride, byteBuffer);
            env->SetObjectArrayElement(surfacePlanes, i, surfacePlane);
        }
    
        return surfacePlanes;
    }
    
    • 先通过Image_getLockedImage函数数,生成一个LockedImage。
    • 再通过Image_getLockedImageInfo获取生成的LockedImage数据,将数据保存在一个byteBuffer对象中。
    • 根据byteBuffer数据创建SurfacePlane
      这样,数据就传到Java层,SurfacePlane中,即mBuffer。

    LockedImage的生成,通过 Image_getLockedImage 函数:

    static void Image_getLockedImage(JNIEnv* env, jobject thiz, LockedImage *image) {
        ALOGV("%s", __FUNCTION__);
        BufferItem* buffer = Image_getBufferItem(env, thiz);
        if (buffer == NULL) {
            jniThrowException(env, "java/lang/IllegalStateException",
                    "Image is not initialized");
            return;
        }
    
        status_t res = lockImageFromBuffer(buffer,
                GRALLOC_USAGE_SW_READ_OFTEN, buffer->mFence->dup(), image);
        if (res != OK) {
            jniThrowExceptionFmt(env, "java/lang/RuntimeException",
                    "lock buffer failed for format 0x%x",
                    buffer->mGraphicBuffer->getPixelFormat());
            return;
        }
    
        // Carry over some fields from BufferItem.
        image->crop        = buffer->mCrop;
        image->transform   = buffer->mTransform;
        image->scalingMode = buffer->mScalingMode;
        image->timestamp   = buffer->mTimestamp;
        image->dataSpace   = buffer->mDataSpace;
        image->frameNumber = buffer->mFrameNumber;
    
        ALOGV("%s: Successfully locked the image", __FUNCTION__);
        // crop, transform, scalingMode, timestamp, and frameNumber should be set by producer,
        // and we don't set them here.
    }
    
    • 先获取到BufferItem,Image_getBufferItem
    • 从BufferItem中lock Image,lockImageFromBuffer

    lockImageFromBuffer函数如下;

    status_t lockImageFromBuffer(BufferItem* bufferItem, uint32_t inUsage,
            int fenceFd, LockedImage* outputImage) {
        ALOGV("%s: Try to lock the BufferItem", __FUNCTION__);
        if (bufferItem == nullptr || outputImage == nullptr) {
            ALOGE("Input BufferItem or output LockedImage is NULL!");
            return BAD_VALUE;
        }
    
        status_t res = lockImageFromBuffer(bufferItem->mGraphicBuffer, inUsage, bufferItem->mCrop,
                fenceFd, outputImage);
        if (res != OK) {
            ALOGE("%s: lock graphic buffer failed", __FUNCTION__);
            return res;
        }
    
        outputImage->crop        = bufferItem->mCrop;
        outputImage->transform   = bufferItem->mTransform;
        outputImage->scalingMode = bufferItem->mScalingMode;
        outputImage->timestamp   = bufferItem->mTimestamp;
        outputImage->dataSpace   = bufferItem->mDataSpace;
        outputImage->frameNumber = bufferItem->mFrameNumber;
        ALOGV("%s: Successfully locked the image from the BufferItem", __FUNCTION__);
        return OK;
    }
    
    • 通过lockImageFromBuffer函数,从GraphicBuffer中生成我们需要的outputImage。
    • 再同步对应的信息描述

    lockImageFromBuffer函数:

    status_t lockImageFromBuffer(sp<GraphicBuffer> buffer, uint32_t inUsage,
            const Rect& rect, int fenceFd, LockedImage* outputImage) {
        ... ...
    
        void* pData = NULL;
        android_ycbcr ycbcr = android_ycbcr();
        status_t res;
        int format = buffer->getPixelFormat();
        int flexFormat = format;
        if (isPossiblyYUV(format)) {
            res = buffer->lockAsyncYCbCr(inUsage, rect, &ycbcr, fenceFd);
            pData = ycbcr.y;
            flexFormat = HAL_PIXEL_FORMAT_YCbCr_420_888;
        }
    
        // lockAsyncYCbCr for YUV is unsuccessful.
        if (pData == NULL) {
            res = buffer->lockAsync(inUsage, rect, &pData, fenceFd);
            if (res != OK) {
                ALOGE("Lock buffer failed!");
                return res;
            }
        }
    
        outputImage->data = reinterpret_cast<uint8_t*>(pData);
        outputImage->width = buffer->getWidth();
        outputImage->height = buffer->getHeight();
        outputImage->format = format;
        outputImage->flexFormat = flexFormat;
        outputImage->stride =
                (ycbcr.y != NULL) ? static_cast<uint32_t>(ycbcr.ystride) : buffer->getStride();
    
        outputImage->dataCb = reinterpret_cast<uint8_t*>(ycbcr.cb);
        outputImage->dataCr = reinterpret_cast<uint8_t*>(ycbcr.cr);
        outputImage->chromaStride = static_cast<uint32_t>(ycbcr.cstride);
        outputImage->chromaStep = static_cast<uint32_t>(ycbcr.chroma_step);
        ALOGV("%s: Successfully locked the image from the GraphicBuffer", __FUNCTION__);
        // Crop, transform, scalingMode, timestamp, and frameNumber should be set by caller,
        // and cann't be set them here.
        return OK;
    }
    
    • 这里GraphicBuffer对象buffer就是VirtualDisplay合成后的数据,outputImage就是我们需要生成的数据。
    • 优先采用yuv的格式,通过GraphicBuffer的lockAsyncYCbCr接口去获取对应的数据地址。
    • 如果yuv获取失败,采用RGB的方式,lockAsync
    • outputImage->data就是数据的起始地址

    最后经过Image_getLockedImageInfo处理后,我们的数据就获取好了。最终我们的数据是保存在Image.Plane的mBuffer中,是一个ByteBuffer。此时,我们就可以做各种我们需要的处理了。

    相关文章

      网友评论

        本文标题:Android P 图形显示系统(四) Android Virt

        本文链接:https://www.haomeiwen.com/subject/ukovaftx.html