录屏流程 - 安卓R

根据安卓实现录屏app可知,安卓录屏时要创建一个VirtualDisplay。本文介绍安卓录屏的底层原理。

从frameworks/base/media/java/android/media/projection/MediaProjection.java的createVirtualDisplay方法继续看:

    /**
     * @hide
     */
    public VirtualDisplay createVirtualDisplay(@NonNull String name,
            int width, int height, int dpi, boolean isSecure, @Nullable Surface surface,
            @Nullable VirtualDisplay.Callback callback, @Nullable Handler handler) {
        DisplayManager dm = (DisplayManager) mContext.getSystemService(Context.DISPLAY_SERVICE);
        int flags = DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR
                | DisplayManager.VIRTUAL_DISPLAY_FLAG_PRESENTATION;
        if (isSecure) {
            flags |= DisplayManager.VIRTUAL_DISPLAY_FLAG_SECURE;
        }
        final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder(name, width,
                height, dpi);
        builder.setFlags(flags);
        if (surface != null) {
            builder.setSurface(surface);
        }
        return dm.createVirtualDisplay(this, builder.build(), callback, handler);
    }

调用了frameworks/base/core/java/android/hardware/display/DisplayManager.java的createVirtualDisplay方法:

    /** @hide */
    public VirtualDisplay createVirtualDisplay(@Nullable MediaProjection projection,
            @NonNull VirtualDisplayConfig virtualDisplayConfig,
            @Nullable VirtualDisplay.Callback callback, @Nullable Handler handler) {
        return mGlobal.createVirtualDisplay(mContext, projection, virtualDisplayConfig, callback,
                handler);
    }

直接调用了frameworks/base/core/java/android/hardware/display/DisplayManagerGlobal.java的createVirtualDisplay方法:

    public VirtualDisplay createVirtualDisplay(@NonNull Context context, MediaProjection projection,
            @NonNull VirtualDisplayConfig virtualDisplayConfig, VirtualDisplay.Callback callback,
            Handler handler) {
        VirtualDisplayCallback callbackWrapper = new VirtualDisplayCallback(callback, handler);
        IMediaProjection projectionToken = projection != null ? projection.getProjection() : null;
        int displayId;
        try {
            displayId = mDm.createVirtualDisplay(virtualDisplayConfig, callbackWrapper,
                    projectionToken, context.getPackageName());
        } catch (RemoteException ex) {
            throw ex.rethrowFromSystemServer();
        }
        if (displayId < 0) {
            Log.e(TAG, "Could not create virtual display: " + virtualDisplayConfig.getName());
            return null;
        }
        Display display = getRealDisplay(displayId);
        if (display == null) {
            Log.wtf(TAG, "Could not obtain display info for newly created "
                    + "virtual display: " + virtualDisplayConfig.getName());
            try {
                mDm.releaseVirtualDisplay(callbackWrapper);
            } catch (RemoteException ex) {
                throw ex.rethrowFromSystemServer();
            }
            return null;
        }
        return new VirtualDisplay(this, display, callbackWrapper,
                virtualDisplayConfig.getSurface());
    }

通过binder调用了frameworks/base/services/core/java/com/android/server/display/DisplayManagerService.java的内部类BinderService的createVirtualDisplay方法:

        @Override // Binder call
        public int createVirtualDisplay(VirtualDisplayConfig virtualDisplayConfig,
                IVirtualDisplayCallback callback, IMediaProjection projection, String packageName) {
            final int callingUid = Binder.getCallingUid();
            if (!validatePackageName(callingUid, packageName)) {
                throw new SecurityException("packageName must match the calling uid");
            }
            if (callback == null) {
                throw new IllegalArgumentException("appToken must not be null");
            }
            if (virtualDisplayConfig == null) {
                throw new IllegalArgumentException("virtualDisplayConfig must not be null");
            }
            final Surface surface = virtualDisplayConfig.getSurface();
            int flags = virtualDisplayConfig.getFlags();

            if (surface != null && surface.isSingleBuffered()) {
                throw new IllegalArgumentException("Surface can't be single-buffered");
            }

            if ((flags & VIRTUAL_DISPLAY_FLAG_PUBLIC) != 0) {
                flags |= VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR;

                // Public displays can't be allowed to show content when locked.
                if ((flags & VIRTUAL_DISPLAY_FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD) != 0) {
                    throw new IllegalArgumentException(
                            "Public display must not be marked as SHOW_WHEN_LOCKED_INSECURE");
                }
            }
            if ((flags & VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY) != 0) {
                flags &= ~VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR;
            }

            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 (callingUid != Process.SYSTEM_UID && (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.");
                }
            }

            if (callingUid != Process.SYSTEM_UID && (flags & VIRTUAL_DISPLAY_FLAG_TRUSTED) != 0) {
                if (!checkCallingPermission(ADD_TRUSTED_DISPLAY, "createVirtualDisplay()")) {
                    EventLog.writeEvent(0x534e4554, "162627132", callingUid,
                            "Attempt to create a trusted display without holding permission!");
                    throw new SecurityException("Requires ADD_TRUSTED_DISPLAY permission to "
                            + "create a trusted virtual display.");
                }
            }

            if ((flags & VIRTUAL_DISPLAY_FLAG_TRUSTED) == 0) {
                flags &= ~VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS;
            }

            // Sometimes users can have sensitive information in system decoration windows. An app
            // could create a virtual display with system decorations support and read the user info
            // from the surface.
            // We should only allow adding flag VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS
            // to trusted virtual displays.
            final int trustedDisplayWithSysDecorFlag =
                    (VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS
                            | VIRTUAL_DISPLAY_FLAG_TRUSTED);
            if ((flags & trustedDisplayWithSysDecorFlag)
                    == VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS
                    && !checkCallingPermission(INTERNAL_SYSTEM_WINDOW, "createVirtualDisplay()")) {
                    throw new SecurityException("Requires INTERNAL_SYSTEM_WINDOW permission");
            }

            final long token = Binder.clearCallingIdentity();
            try {
                return createVirtualDisplayInternal(callback, projection, callingUid, packageName,
                        surface, flags, virtualDisplayConfig);
            } finally {
                Binder.restoreCallingIdentity(token);
            }
        }

调用了DisplayManagerService的createVirtualDisplayInternal方法:

    private int createVirtualDisplayInternal(IVirtualDisplayCallback callback,
            IMediaProjection projection, int callingUid, String packageName, Surface surface,
            int flags, VirtualDisplayConfig virtualDisplayConfig) {
        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, surface, flags,
                    virtualDisplayConfig);
            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;
    }

其中调用了frameworks/base/services/core/java/com/android/server/display/VirtualDisplayAdapter.java的createVirtualDisplayLocked方法:

    public DisplayDevice createVirtualDisplayLocked(IVirtualDisplayCallback callback,
            IMediaProjection projection, int ownerUid, String ownerPackageName, Surface surface,
            int flags, VirtualDisplayConfig virtualDisplayConfig) {
        String name = virtualDisplayConfig.getName();
        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);
        String uniqueId = virtualDisplayConfig.getUniqueId();
        if (uniqueId == null) {
            uniqueId = baseUniqueId + uniqueIndex;
        } else {
            uniqueId = UNIQUE_ID_PREFIX + ownerPackageName + ":" + uniqueId;
        }
        VirtualDisplayDevice device = new VirtualDisplayDevice(displayToken, appToken,
                ownerUid, ownerPackageName, surface, flags, new Callback(callback, mHandler),
                uniqueId, uniqueIndex, virtualDisplayConfig);

        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;
    }

在这里创建了VirtualDisplayDevice对象

其中mSurfaceControlDisplayFactory是一个在VirtualDisplayAdapter的构造函数中定义的lambda:

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

    @VisibleForTesting
    VirtualDisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
            Context context, Handler handler, Listener listener,
            SurfaceControlDisplayFactory surfaceControlDisplayFactory) {
        super(syncRoot, context, handler, listener, TAG);
        mHandler = handler;
        mSurfaceControlDisplayFactory = surfaceControlDisplayFactory;
    }

其直接调用了frameworks/base/core/java/android/view/SurfaceControl.java的createDisplay方法:

    /**
     * @hide
     */
    @UnsupportedAppUsage
    public static IBinder createDisplay(String name, boolean secure) {
        if (name == null) {
            throw new IllegalArgumentException("name must not be null");
        }
        return nativeCreateDisplay(name, secure);
    }

调用了frameworks/base/core/jni/android_view_SurfaceControl.cpp的nativeCreateDisplay方法:

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);
}

这里通过binder调用了frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp的createDisplay方法:

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);
    // Display ID is assigned when virtual display is allocated by HWC.
    DisplayDeviceState state;
    state.isSecure = secure;
    state.displayName = displayName;
    mCurrentState.displays.add(token, state);
    mInterceptor->saveDisplayCreation(state);
    return token;
}

创建了DisplayToken并保存到了SurfaceFlinger.mCurrentState.displays的key中。

回到DisplayManagerService的createVirtualDisplayInternal方法中,此方法接下来还调用了DisplayManagerService的handleDisplayDeviceAddedLocked方法:

    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);
    }

其中调用了DisplayManagerService的addLogicalDisplayLocked方法:

    // Adds a new logical display based on the given display device.
    // Sends notifications if needed.
    private LogicalDisplay addLogicalDisplayLocked(DisplayDevice device) {
        DisplayDeviceInfo deviceInfo = device.getDisplayDeviceInfoLocked();
        boolean isDefault = (deviceInfo.flags
                & DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY) != 0;
        if (isDefault && mLogicalDisplays.get(Display.DEFAULT_DISPLAY) != null) {
            Slog.w(TAG, "Ignoring attempt to add a second default display: " + deviceInfo);
            isDefault = false;
        }

        if (!isDefault && mSingleDisplayDemoMode) {
            Slog.i(TAG, "Not creating a logical display for a secondary display "
                    + " because single display demo mode is enabled: " + deviceInfo);
            return null;
        }

        final int displayId = assignDisplayIdLocked(isDefault);
        final int layerStack = assignLayerStackLocked(displayId);

        LogicalDisplay display = new LogicalDisplay(displayId, layerStack, device);
        display.updateLocked(mDisplayDevices);
        if (!display.isValidLocked()) {
            // This should never happen currently.
            Slog.w(TAG, "Ignoring display device because the logical display "
                    + "created from it was not considered valid: " + deviceInfo);
            return null;
        }

        configureColorModeLocked(display, device);
        if (isDefault) {
            recordStableDisplayStatsIfNeededLocked(display);
            recordTopInsetLocked(display);
        }

        mLogicalDisplays.put(displayId, display);
        DisplayManagerGlobal.invalidateLocalDisplayInfoCaches();

        // Wake up waitForDefaultDisplay.
        if (isDefault) {
            mSyncRoot.notifyAll();
        }

        sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_ADDED);
        return display;
    }

这里创建了LogicalDisplay对象。

回到handleDisplayDeviceAddedLocked方法最后还调用了DisplayManagerService的scheduleTraversalLocked方法:

    // Requests that performTraversals be called at a
    // later time to apply changes to surfaces and displays.
    private void scheduleTraversalLocked(boolean inTraversal) {
        if (!mPendingTraversal && mWindowManagerInternal != null) {
            mPendingTraversal = true;
            if (!inTraversal) {
                mHandler.sendEmptyMessage(MSG_REQUEST_TRAVERSAL);
            }
        }
    }

接下来会进入WindowManagerService的窗口布局流程,在其中会调用DisplayManagerService的performTraversalLocked方法:

    private void performTraversalLocked(SurfaceControl.Transaction t) {
        // 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);
            configureDisplayLocked(t, device);
            device.performTraversalLocked(t);
        }

        // Tell the input system about these new viewports.
        if (mInputManagerInternal != null) {
            mHandler.sendEmptyMessage(MSG_UPDATE_VIEWPORT);
        }
    }

调用了每个DisplayDevice的performTraversalLocked方法,这其中当然包括刚刚创建的VirtualDisplayDevice的performTraversalLocked方法(frameworks/base/services/core/java/com/android/server/display/VirtualDisplayAdapter.java):

        @Override
        public void performTraversalLocked(SurfaceControl.Transaction t) {
            if ((mPendingChanges & PENDING_RESIZE) != 0) {
                t.setDisplaySize(getDisplayTokenLocked(), mWidth, mHeight);
            }
            if ((mPendingChanges & PENDING_SURFACE_CHANGE) != 0) {
                setSurfaceLocked(t, mSurface);
            }
            mPendingChanges = 0;
        }

在VirtualDisplayDevice的构造函数中会执行mPendingChanges |= PENDING_SURFACE_CHANGE,因此此时会调用父类frameworks/base/services/core/java/com/android/server/display/DisplayDevice.java的setSurfaceLocked方法:

    /**
     * Sets the display surface while in a transaction.
     */
    public final void setSurfaceLocked(SurfaceControl.Transaction t, Surface surface) {
        if (mCurrentSurface != surface) {
            mCurrentSurface = surface;
            t.setDisplaySurface(mDisplayToken, surface);
        }
    }

这个Transaction会在关闭时到SurfaceFlinger中处理,因此接下来看frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp的applyTransactionState方法:

void SurfaceFlinger::applyTransactionState(
        const Vector<ComposerState>& states, const Vector<DisplayState>& displays, uint32_t flags,
        const InputWindowCommands& inputWindowCommands, const int64_t desiredPresentTime,
        const client_cache_t& uncacheBuffer, const int64_t postTime, bool privileged,
        bool hasListenerCallbacks, const std::vector<ListenerCallbacks>& listenerCallbacks,
        bool isMainThread) {
    ......
    for (const DisplayState& display : displays) {
        transactionFlags |= setDisplayStateLocked(display);
    }
    ......
}

其中对每个DisplayState调用了setDisplayStateLocked方法:

uint32_t SurfaceFlinger::setDisplayStateLocked(const DisplayState& s) {
    const ssize_t index = mCurrentState.displays.indexOfKey(s.token);
    if (index < 0) return 0;

    uint32_t flags = 0;
    DisplayDeviceState& state = mCurrentState.displays.editValueAt(index);

    const uint32_t what = s.what;
    if (what & DisplayState::eSurfaceChanged) {
        if (IInterface::asBinder(state.surface) != IInterface::asBinder(s.surface)) {
            state.surface = s.surface;
            flags |= eDisplayTransactionNeeded;
        }
    }
    ......
    return flags;
}

就这样我们的surface给到了SurfaceFlinger.mCurrentState.displays中key为之前创建的DisplayToken所对应的value中。

在处理Transaction的流程中接下来还会调用SurfaceFlinger的handleTransactionLocked方法:

void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags)
{
    ......

    /*
     * Perform display own transactions if needed
     */

    if (transactionFlags & eDisplayTransactionNeeded) {
        processDisplayChangesLocked();
        processDisplayHotplugEventsLocked();
    }

    ......
}

调用了SurfaceFlinger的processDisplayChangesLocked方法:

void SurfaceFlinger::processDisplayChangesLocked() {
    // here we take advantage of Vector's copy-on-write semantics to
    // improve performance by skipping the transaction entirely when
    // know that the lists are identical
    const KeyedVector<wp<IBinder>, DisplayDeviceState>& curr(mCurrentState.displays);
    const KeyedVector<wp<IBinder>, DisplayDeviceState>& draw(mDrawingState.displays);
    if (!curr.isIdenticalTo(draw)) {
        mVisibleRegionsDirty = true;

        // find the displays that were removed
        // (ie: in drawing state but not in current state)
        // also handle displays that changed
        // (ie: displays that are in both lists)
        for (size_t i = 0; i < draw.size(); i++) {
            const wp<IBinder>& displayToken = draw.keyAt(i);
            const ssize_t j = curr.indexOfKey(displayToken);
            if (j < 0) {
                // in drawing state but not in current state
                processDisplayRemoved(displayToken);
            } else {
                // this display is in both lists. see if something changed.
                const DisplayDeviceState& currentState = curr[j];
                const DisplayDeviceState& drawingState = draw[i];
                processDisplayChanged(displayToken, currentState, drawingState);
            }
        }

        // find displays that were added
        // (ie: in current state but not in drawing state)
        for (size_t i = 0; i < curr.size(); i++) {
            const wp<IBinder>& displayToken = curr.keyAt(i);
            if (draw.indexOfKey(displayToken) < 0) {
                processDisplayAdded(displayToken, curr[i]);
            }
        }
    }

    mDrawingState.displays = mCurrentState.displays;
}

由于我们的虚拟屏幕是新来的,因此会调用SurfaceFlinger的processDisplayAdded方法:

void SurfaceFlinger::processDisplayAdded(const wp<IBinder>& displayToken,
                                         const DisplayDeviceState& state) {
    int width = 0;
    int height = 0;
    ui::PixelFormat pixelFormat = static_cast<ui::PixelFormat>(PIXEL_FORMAT_UNKNOWN);
    if (state.physical) {
        const auto& activeConfig =
                getCompositionEngine().getHwComposer().getActiveConfig(state.physical->id);
        width = activeConfig->getWidth();
        height = activeConfig->getHeight();
        pixelFormat = static_cast<ui::PixelFormat>(PIXEL_FORMAT_RGBA_8888);
    } else if (state.surface != nullptr) {
        int status = state.surface->query(NATIVE_WINDOW_WIDTH, &width);
        ALOGE_IF(status != NO_ERROR, "Unable to query width (%d)", status);
        status = state.surface->query(NATIVE_WINDOW_HEIGHT, &height);
        ALOGE_IF(status != NO_ERROR, "Unable to query height (%d)", status);
        int intPixelFormat;
        status = state.surface->query(NATIVE_WINDOW_FORMAT, &intPixelFormat);
        ALOGE_IF(status != NO_ERROR, "Unable to query format (%d)", status);
        pixelFormat = static_cast<ui::PixelFormat>(intPixelFormat);
    } else {
        // Virtual displays without a surface are dormant:
        // they have external state (layer stack, projection,
        // etc.) but no internal state (i.e. a DisplayDevice).
        return;
    }

    compositionengine::DisplayCreationArgsBuilder builder;
    if (const auto& physical = state.physical) {
        builder.setPhysical({physical->id, physical->type});
    }
    builder.setPixels(ui::Size(width, height));
    builder.setPixelFormat(pixelFormat);
    builder.setIsSecure(state.isSecure);
    builder.setLayerStackId(state.layerStack);
    builder.setPowerAdvisor(&mPowerAdvisor);
    builder.setUseHwcVirtualDisplays(mUseHwcVirtualDisplays);
    builder.setName(state.displayName);
    const auto compositionDisplay = getCompositionEngine().createDisplay(builder.build());

    sp<compositionengine::DisplaySurface> displaySurface;
    sp<IGraphicBufferProducer> producer;
    sp<IGraphicBufferProducer> bqProducer;
    sp<IGraphicBufferConsumer> bqConsumer;
    getFactory().createBufferQueue(&bqProducer, &bqConsumer, /*consumerIsSurfaceFlinger =*/false);

    std::optional<DisplayId> displayId = compositionDisplay->getId();

    if (state.isVirtual()) {
        sp<VirtualDisplaySurface> vds =
                new VirtualDisplaySurface(getHwComposer(), displayId, state.surface, bqProducer,
                                          bqConsumer, state.displayName);

        displaySurface = vds;
        producer = vds;
    } else {
        ALOGE_IF(state.surface != nullptr,
                 "adding a supported display, but rendering "
                 "surface is provided (%p), ignoring it",
                 state.surface.get());

        LOG_ALWAYS_FATAL_IF(!displayId);
        displaySurface = new FramebufferSurface(getHwComposer(), *displayId, bqConsumer,
                                                maxGraphicsWidth, maxGraphicsHeight);
        producer = bqProducer;
    }

    LOG_FATAL_IF(!displaySurface);
    const auto display = setupNewDisplayDeviceInternal(displayToken, compositionDisplay, state,
                                                       displaySurface, producer);
    mDisplays.emplace(displayToken, display);
    if (!state.isVirtual()) {
        LOG_FATAL_IF(!displayId);
        dispatchDisplayHotplugEvent(displayId->value, true);
    }

    if (display->isPrimary()) {
        mScheduler->onPrimaryDisplayAreaChanged(display->getWidth() * display->getHeight());
    }
}

在这里创建了一个BufferQueue并生成了一对生产者和消费者(见BufferQueue机制),然后还创建了VirtualDisplaySurface对象,首先来看一下其定义(frameworks/native/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h):

/* This DisplaySurface implementation supports virtual displays, where GPU
 * and/or HWC compose into a buffer that is then passed to an arbitrary
 * consumer (the sink) running in another process.
 *
 * The simplest case is when the virtual display will never use the h/w
 * composer -- either the h/w composer doesn't support writing to buffers, or
 * there are more virtual displays than it supports simultaneously. In this
 * case, the GPU driver works directly with the output buffer queue, and
 * calls to the VirtualDisplay from SurfaceFlinger and DisplayHardware do
 * nothing.
 *
 * If h/w composer might be used, then each frame will fall into one of three
 * configurations: GPU-only, HWC-only, and MIXED composition. In all of these,
 * we must provide a FB target buffer and output buffer for the HWC set() call.
 *
 * In GPU-only composition, the GPU driver is given a buffer from the sink to
 * render into. When the GPU driver queues the buffer to the
 * VirtualDisplaySurface, the VirtualDisplaySurface holds onto it instead of
 * immediately queueing it to the sink. The buffer is used as both the FB
 * target and output buffer for HWC, though on these frames the HWC doesn't
 * do any work for this display and doesn't write to the output buffer. After
 * composition is complete, the buffer is queued to the sink.
 *
 * In HWC-only composition, the VirtualDisplaySurface dequeues a buffer from
 * the sink and passes it to HWC as both the FB target buffer and output
 * buffer. The HWC doesn't need to read from the FB target buffer, but does
 * write to the output buffer. After composition is complete, the buffer is
 * queued to the sink.
 *
 * On MIXED frames, things become more complicated, since some h/w composer
 * implementations can't read from and write to the same buffer. This class has
 * an internal BufferQueue that it uses as a scratch buffer pool. The GPU
 * driver is given a scratch buffer to render into. When it finishes rendering,
 * the buffer is queued and then immediately acquired by the
 * VirtualDisplaySurface. The scratch buffer is then used as the FB target
 * buffer for HWC, and a separate buffer is dequeued from the sink and used as
 * the HWC output buffer. When HWC composition is complete, the scratch buffer
 * is released and the output buffer is queued to the sink.
 */
class VirtualDisplaySurface : public compositionengine::DisplaySurface,
                              public BnGraphicBufferProducer,
                              private ConsumerBase {

VirtualDisplaySurface既是生产者又是消费者。

接下来看VirtualDisplaySurface的构造器(frameworks/native/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp):

VirtualDisplaySurface::VirtualDisplaySurface(HWComposer& hwc,
                                             const std::optional<DisplayId>& displayId,
                                             const sp<IGraphicBufferProducer>& sink,
                                             const sp<IGraphicBufferProducer>& bqProducer,
                                             const sp<IGraphicBufferConsumer>& bqConsumer,
                                             const std::string& name)
      : ConsumerBase(bqConsumer),
        mHwc(hwc),
        mDisplayId(displayId),
        mDisplayName(name),
        mSource{},
        mDefaultOutputFormat(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED),
        mOutputFormat(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED),
        mOutputUsage(GRALLOC_USAGE_HW_COMPOSER),
        mProducerSlotSource(0),
        mProducerBuffers(),
        mProducerSlotNeedReallocation(0),
        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 GPU. 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.c_str());
    mConsumer->setConsumerName(ConsumerBase::mName);
    mConsumer->setConsumerUsageBits(GRALLOC_USAGE_HW_COMPOSER);
    mConsumer->setDefaultBufferSize(sinkWidth, sinkHeight);
    sink->setAsyncMode(true);
    IGraphicBufferProducer::QueueBufferOutput output;
    mSource[SOURCE_SCRATCH]->connect(nullptr, NATIVE_WINDOW_API_EGL, false, &output);
}

mSource[SOURCE_SINK]存放了原surface,mSource[SOURCE_SCRATCH]存放了新创建的生产者,mConsumer存放了新创建的消费者。

VirtualDisplay创建好了后,在SurfaceFlinger中Layer的合成流程中,会有相应的Output对象。也就是说在outputs列表中,除了手机的默认屏幕外,还会有我们创建的虚拟屏幕。这样SurfaceFlinger对于每帧都会进行一次额外的合成,每帧都会产生虚拟屏的合成后的图像,给MediaRecorder进行消费,从而生成录制的视频。

总结

1 录屏时SurfaceFlinger对每帧图像会进行至少2次合成。

2 在录屏的BufferQueue中,SurfaceFlinger是生产者,消费者可以是MediaRecorder或其它。

3 录屏的buffer一定是gpu合成的。

4 录屏时,如果某个layer的mPrimaryDisplayOnly为true,则录屏的视频不包括这个layer。

5 录屏时,如果有visible的layer是secure的,则视频中这个layer是黑的。

  • 4
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

SSSxCCC

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值