public static final int VIRTUAL_DISPLAY_FLAG_PUBLIC = 1 << 0;
public static final int VIRTUAL_DISPLAY_FLAG_PRESENTATION = 1 << 1;
public static final int VIRTUAL_DISPLAY_FLAG_SECURE = 1 << 2;
public static final int VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY = 1 << 3;
public static final int VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR = 1 << 4;
public static final int VIRTUAL_DISPLAY_FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD = 1 << 5;
public static final int VIRTUAL_DISPLAY_FLAG_SUPPORTS_TOUCH = 1 << 6;
public static final int VIRTUAL_DISPLAY_FLAG_ROTATES_WITH_CONTENT = 1 << 7;
public static final int VIRTUAL_DISPLAY_FLAG_DESTROY_CONTENT_ON_REMOVAL = 1 << 8;
public static final int VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS = 1 << 9;
public static final int VIRTUAL_DISPLAY_FLAG_TRUSTED = 1 << 10;
public static final int VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP = 1 << 11;
public static abstract class Callback {
/**
* Called when the virtual display video projection has been
* paused by the system or when the surface has been detached
* by the application by calling setSurface(null).
* The surface will not receive any more buffers while paused.
*/
public void onPaused() { }
/**
* Called when the virtual display video projection has been
* resumed after having been paused.
*/
public void onResumed() { }
/**
* Called when the virtual display video projection has been
* stopped by the system. It will no longer receive frames
* and it will never be resumed. It is still the responsibility
* of the application to release() the virtual display.
*/
public void onStopped() { }
}
VirtualDisplay原理
关于VirtualDisplay的实现原理,主要从AndroidFramework角度进行分析。
java复制代码
// /frameworks/base/core/java/android/hardware/display/DisplayManager.java
public VirtualDisplay createVirtualDisplay(@NonNull String name,
int width, int height, int densityDpi, @Nullable Surface surface, int flags) {
return createVirtualDisplay(name, width, height, densityDpi, surface, flags, null, null);
}
public VirtualDisplay createVirtualDisplay(@NonNull String name,
int width, int height, int densityDpi, @Nullable Surface surface, int flags,
@Nullable VirtualDisplay.Callback callback, @Nullable Handler handler) {
final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder(name, width,
height, densityDpi);
builder.setFlags(flags);
if (surface != null) {
builder.setSurface(surface);
}
return createVirtualDisplay(null /* projection */, builder.build(), callback, handler);
}
// TODO : Remove this hidden API after remove all callers. (Refer to MultiDisplayService)
/** @hide */
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) {
final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder(name, width,
height, densityDpi);
builder.setFlags(flags);
if (uniqueId != null) {
builder.setUniqueId(uniqueId);
}
if (surface != null) {
builder.setSurface(surface);
}
return createVirtualDisplay(projection, builder.build(), callback, handler);
}
/** @hide */
public VirtualDisplay createVirtualDisplay(@Nullable MediaProjection projection,
@NonNull VirtualDisplayConfig virtualDisplayConfig,
@Nullable VirtualDisplay.Callback callback, @Nullable Handler handler) {
// 走的这里,会调用到DisplayManagerGlobal中。
return mGlobal.createVirtualDisplay(mContext, projection, virtualDisplayConfig, callback,
handler);
}
// /frameworks/base/services/core/java/com/android/server/display/DisplayManagerService.java
@Override // Binder call
public int createVirtualDisplay(VirtualDisplayConfig virtualDisplayConfig,
IVirtualDisplayCallback callback, IMediaProjection projection, String packageName) {
// 检查uid与包名,是否相符。
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");
}
// 拿到client端传过来的surface对象
final Surface surface = virtualDisplayConfig.getSurface();
int flags = virtualDisplayConfig.getFlags();
if (surface != null && surface.isSingleBuffered()) {
throw new IllegalArgumentException("Surface can't be single-buffered");
}
// 下面开始针对Flag,做一些逻辑判断。
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 ((flags & VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR) != 0) {
flags &= ~VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP;
}
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 (callingUid != Process.SYSTEM_UID
&& (flags & VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP) != 0) {
if (!checkCallingPermission(ADD_TRUSTED_DISPLAY, "createVirtualDisplay()")) {
throw new SecurityException("Requires ADD_TRUSTED_DISPLAY permission to "
+ "create a virtual display which is not in the default DisplayGroup.");
}
}
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);
}
}
// /frameworks/base/services/core/java/com/android/server/display/DisplayManagerService.java
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;
}
// 为虚拟屏创建Device(告知surfaceflinger创建Display)
DisplayDevice device = mVirtualDisplayAdapter.createVirtualDisplayLocked(
callback, projection, callingUid, packageName, surface, flags,
virtualDisplayConfig);
if (device == null) {
return -1;
}
// 发送添加Device通知,这里比较重要
mDisplayDeviceRepo.onDisplayDeviceEvent(device,
DisplayAdapter.DISPLAY_DEVICE_EVENT_ADDED);
// 检查Display是否创建成功
final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(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());
mDisplayDeviceRepo.onDisplayDeviceEvent(device,
DisplayAdapter.DISPLAY_DEVICE_EVENT_REMOVED);
}
return -1;
}