在
https://blog.csdn.net/aaajj/article/details/93653074
https://blog.csdn.net/aaajj/article/details/102537628
https://blog.csdn.net/aaajj/article/details/113076275
里面讨论了从SurfaceFlinger中获取layer图像的一个试验
采用的方法是直接获取GraphicBuffer,进而找到数据地址来获取图片进行保存,
这样的操作可以加深对GrapicBuffer的理解,其实获取layer,系统里已经提供了相应的方法,在查看截图程序screencap关注SurfaceFlinger程序的时候,注意到里面有方法
4727 status_t SurfaceFlinger::captureLayers(const sp<IBinder>& layerHandleBinder
在里SurfaceControl.java也有方法
1323 public static GraphicBuffer captureLayers(IBinder layerHandleToken, Rect sourceCrop,
我们来找一下系统中有没有调用,
找到了2个调用的地方
268 final GraphicBuffer buffer = SurfaceControl.captureLayers( | ||
719 GraphicBuffer wallpaperBuffer = SurfaceControl.captureLayers( |
695 /**
696 * Take a screenshot of the wallpaper if it's visible.
697 *
698 * @return Bitmap of the wallpaper
699 */
700 Bitmap screenshotWallpaperLocked() {
701 if (!mService.mPolicy.isScreenOn()) {
702 if (DEBUG_SCREENSHOT) {
703 Slog.i(TAG_WM, "Attempted to take screenshot while display was off.");
704 }
705 return null;
706 }
707
…
715
716 final Rect bounds = wallpaperWindowState.getBounds();
717 bounds.offsetTo(0, 0);
718
719 GraphicBuffer wallpaperBuffer = SurfaceControl.captureLayers(
720 wallpaperWindowState.getSurfaceControl().getHandle(), bounds, 1 /* frameScale */);
721
722 if (wallpaperBuffer == null) {
723 Slog.w(TAG_WM, "Failed to screenshot wallpaper");
724 return null;
725 }
726 return Bitmap.createHardwareBitmap(wallpaperBuffer);
727 }
这个方法里获取到了wallpaper的layer的GraphicBuffer对象,Bitmap里面竟然还有方法可以把GraphicBuffer转换为Bitmap对象,看起来很强大。
我们再看看哪里调用的screenshotWallpaperLocked方法
如果我们调用这个方法,就可以获取这个Bitmap对象来保存图片,这样就可以查看这个方法的实际效果。
3689 public Bitmap screenshotWallpaper() {
3690 if (!checkCallingPermission(READ_FRAME_BUFFER, "screenshotWallpaper()")) {
3691 throw new SecurityException("Requires READ_FRAME_BUFFER permission");
3692 }
3693 try {
3694 Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "screenshotWallpaper");
3695 synchronized (mWindowMap) {
3696 return mRoot.mWallpaperController.screenshotWallpaperLocked();
3697 }
3698 } finally {
3699 Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
3700 }
3701 }
这个方法没有提供对外的接口,我们不方便在app里调用这个方法,
我们可以在WMS的dump方法里来进行调用测试,
获取到Bitmap对象后,调用其compress方法来保存图片,注意,由于wms所在的进程system_server的用户名是 system,不能写/sdcard目录,我们需要保存文件到/data/anr 这样user是system的路径下,当然,手机最好root下,便于我们查看/data里各目录的信息
通过dumpsys window命令来进行调用触发
我们可以看到,图片被获取保存了,pull到电脑上查看,就是wallpaper图片
通过这个试验,我们可以了解到cartureLaryers方法的使用,其参数IBinder handle,看起来是对应的surfaceControl对象,这个需要我们继续探索了解。