// frameworks/base/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarButtonTest.javaprivateDisplaycreateVirtualDisplay(){finalString displayName ="NavVirtualDisplay";finalDisplayInfo displayInfo =newDisplayInfo();mContext.getDisplay().getDisplayInfo(displayInfo);finalDisplayManager displayManager = mContext.getSystemService(DisplayManager.class);// 创建ImageReader,通过它得到一张SurfacemReader =ImageReader.newInstance(displayInfo.logicalWidth,displayInfo.logicalHeight,PixelFormat.RGBA_8888,2);assertNotNull("ImageReader must not be null", mReader);// 创建虚拟屏,传入Surface。mVirtualDisplay = displayManager.createVirtualDisplay(displayName, displayInfo.logicalWidth,displayInfo.logicalHeight, displayInfo.logicalDensityDpi, mReader.getSurface(),0/*flags*/);assertNotNull("virtual display must not be null", mVirtualDisplay);waitForDisplayReady(mVirtualDisplay.getDisplay().getDisplayId());return mVirtualDisplay.getDisplay();}
publicstaticabstractclassCallback{/*** 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.*/publicvoidonPaused(){}/*** Called when the virtual display video projection has been* resumed after having been paused.*/publicvoidonResumed(){}/*** 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.*/publicvoidonStopped(){}}
// /frameworks/base/services/core/java/com/android/server/display/DisplayManagerService.java@Override// Binder callpublicintcreateVirtualDisplay(VirtualDisplayConfig virtualDisplayConfig,IVirtualDisplayCallback callback,IMediaProjection projection,String packageName){// 检查uid与包名,是否相符。finalint callingUid =Binder.getCallingUid();if(!validatePackageName(callingUid, packageName)){thrownewSecurityException("packageName must match the calling uid");}if(callback ==null){thrownewIllegalArgumentException("appToken must not be null");}if(virtualDisplayConfig ==null){thrownewIllegalArgumentException("virtualDisplayConfig must not be null");}// 拿到client端传过来的surface对象finalSurface surface = virtualDisplayConfig.getSurface();int flags = virtualDisplayConfig.getFlags();if(surface !=null&& surface.isSingleBuffered()){thrownewIllegalArgumentException("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){thrownewIllegalArgumentException("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)){thrownewSecurityException("Invalid media projection");}flags = projection.applyVirtualDisplayFlags(flags);}catch(RemoteException e){thrownewSecurityException("unable to validate media projection or flags");}}if(callingUid !=Process.SYSTEM_UID&&(flags &VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR)!=0){if(!canProjectVideo(projection)){thrownewSecurityException("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)){thrownewSecurityException("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!");thrownewSecurityException("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()")){thrownewSecurityException("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.finalint 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()")){thrownewSecurityException("Requires INTERNAL_SYSTEM_WINDOW permission");}finallong token =Binder.clearCallingIdentity();try{// 调用内部实现returncreateVirtualDisplayInternal(callback, projection, callingUid, packageName,surface, flags, virtualDisplayConfig);}finally{Binder.restoreCallingIdentity(token);}}// /frameworks/base/services/core/java/com/android/server/display/DisplayManagerService.javaprivateintcreateVirtualDisplayInternal(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是否创建成功finalLogicalDisplay 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;}
// /frameworks/base/services/core/java/com/android/server/display/VirtualDisplayAdapter.javapublicDisplayDevicecreateVirtualDisplayLocked(IVirtualDisplayCallback callback,IMediaProjection projection,int ownerUid,String ownerPackageName,Surface surface,int flags,VirtualDisplayConfig virtualDisplayConfig){String name = virtualDisplayConfig.getName();// VIRTUAL_DISPLAY_FLAG_SECURE 的用途,是判断是否为安全的Display,这个参数会告知SurfaceFlingerboolean secure =(flags &VIRTUAL_DISPLAY_FLAG_SECURE)!=0;IBinder appToken = callback.asBinder();// 调用SurfaceFligner创建Display(Display的type是virtual)IBinder displayToken = mSurfaceControlDisplayFactory.createDisplay(name, secure);finalString baseUniqueId =UNIQUE_ID_PREFIX+ ownerPackageName +","+ ownerUid +","+ name +",";finalint uniqueIndex =getNextUniqueIndex(baseUniqueId);String uniqueId = virtualDisplayConfig.getUniqueId();if(uniqueId ==null){uniqueId = baseUniqueId + uniqueIndex;}else{uniqueId =UNIQUE_ID_PREFIX+ ownerPackageName +":"+ uniqueId;}// 通过SurfaceFligner返回的displayToken,创建Device对象VirtualDisplayDevice device =newVirtualDisplayDevice(displayToken, appToken,ownerUid, ownerPackageName, surface, flags,newCallback(callback, mHandler),uniqueId, uniqueIndex, virtualDisplayConfig);// 放到虚拟屏的List中管理。mVirtualDisplayDevices.put(appToken, device);try{if(projection !=null){projection.registerCallback(newMediaProjectionCallback(appToken));}appToken.linkToDeath(device,0);}catch(RemoteException ex){mVirtualDisplayDevices.remove(appToken);device.destroyLocked(false);returnnull;}// Return the display device without actually sending the event indicating// that it was added. The caller will handle it.return device;}// /frameworks/base/services/core/java/com/android/server/display/DisplayDeviceRepository.java// mDisplayDeviceRepo.onDisplayDeviceEvent(device,// DisplayAdapter.DISPLAY_DEVICE_EVENT_ADDED); // 这段代码,会调用到下面的函数中。privatevoidhandleDisplayDeviceAdded(DisplayDevice device){synchronized(mSyncRoot){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;// 需要是将Device(就是上面创建的虚拟屏幕Device)放入到DMS的管理listmDisplayDevices.add(device);// 通知Device添加,会调用到LogicalDisplayMappe的handleDisplayDeviceAddedLocked中。sendEventLocked(device,DISPLAY_DEVICE_EVENT_ADDED);}}// /frameworks/base/services/core/java/com/android/server/display/LogicalDisplayMapper.javaprivatevoidhandleDisplayDeviceAddedLocked(DisplayDevice device){DisplayDeviceInfo deviceInfo = device.getDisplayDeviceInfoLocked();// Internal Displays need to have additional initialization.// This initializes a default dynamic display layout for INTERNAL// devices, which is used as a fallback in case no static layout definitions// exist or cannot be loaded.if(deviceInfo.type ==Display.TYPE_INTERNAL){initializeInternalDisplayDeviceLocked(device);}// Create a logical display for the new display deviceLogicalDisplay display =createNewLogicalDisplayLocked(device,Layout.assignDisplayIdLocked(false/*isDefault*/));// 刷新布局和display配置applyLayoutLocked();updateLogicalDisplaysLocked();}