根据安卓实现录屏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是黑的。