【源码解读】Screencap源码分析-基础篇

由于工作的关联关系,本文将针对Android screencap的源码进行分析,此文是基础篇,为后续对源码的修改做知识储备。


本文期望达到的目的:

  1. 了解screencap使用
  2. 了解screencap实现基础原理
  3. 为后续screencap源码修改和其他应用做准备

 

源码位置:

android4.0之后内置了截图工具screencap,一般位于/system/bin/screencap

源码路径:frameworks/base/cmds/screencap/

 

使用介绍:

usage: screencap [-hp] [-d display-id] [FILENAME]
   -h: this message
   -p: save the file as a png.
   -d: specify the display id to capture, default 0.
If FILENAME ends with .png it will be saved as a png.
If FILENAME is not given, the results will be printed to stdout.


使用相当简单:

adb shell screencap -p/sdcard/testscreen.png


备注:

  1. -d 参数为支持扩展的display设备
  2. 如果文件名以.png结尾时,它将保存为png文件,如果文件名没有给出,则结果被会被输出到stdout(导出会相当的卡)


如果手机没有连接adb,我们也可以用以下代码去完成调用:

public Boolean DoScreenShot(){
	Process process = null;
	DataOutputStream os = null;
	try {
	}
	catch (Exception e){
		return false;
	}finally {
		Try {
			process = Runtime.getRuntime().exec(“su”);
			os = new DataOutputStream(process.getOutputStream());
			os.writeBytes(“serccncap –p ” + strFileFullPath);
			os.flush();
			process.waitFor();
			If (os != null) {
				os.close();
			}
			process.destroy();
		}
		catch (Exception e){
		}
	}
	return true;
}

源码分析:

核心代码:

【源码解读】Screencap源码分析-基础篇_第1张图片

整个程序最核心的代码就是上图。


获取截图信息的流程是通过ScreenshotClient对象,如果发现ScreenshotClient获取失败则读取/dev/graphics/fb0文件。


不知道/dev/graphics/fb0是什么文件,可以google下。

1、 fb0读取比较容易看懂:(如果有兴趣的话可以继续去看linux内核文件中的显示文件)   

  1. 直接open()打开文件
  2. 通过fb_var_screeninfo结构体来定位fb0的文件头格式
  3. 根据偏移地址把一贞的数据读到一个mmap中,
  4. base = (void const *)((char const *)mapbase + offset);

2、ScreenshotClient:

  1. 创建ScreenshotClient screenshot
  2. 直接调用screenshot.update()
  3. base = screenshot.getPixels();


后续我们再继续阅读ScreenshotClient类,了解它是如何显示屏幕显示获取的:

ScreenshotClient类位于frameworks/native/libs/gui/SurfaceComposerClient.cpp中。

这个类提供了updata()函数:

【源码解读】Screencap源码分析-基础篇_第2张图片

从567行来看,该函数是直接调用了SurfaceFlinger服务的代理对象中的captureScreen()函数。

其中getComposerService()函数的源码:

【源码解读】Screencap源码分析-基础篇_第3张图片

从代码上可以看出,instance.mComposerService是SurfaceFlinger服务的代理对象。


如果有兴趣的话可以继续跟进去里面的代码,会发现上面的第5行代码就是通过getService("SurfaceFlinger", &mComposerService)获取服务代理对象。

说到“SurfaceFlinger”服务,这个服务器是比较庞大的架构。主要的作用是进行UI绘制。(后续可以深入分析)


所以:

    Screencap的实现就是通过访问“SurfaceFlinger”服务或者读取fb0文件进行截屏的。


最后我们看看Screencap保存图片的代码:

【源码解读】Screencap源码分析-基础篇_第4张图片

程序只提供了png后缀的图片格式,如果想要返回其他的图片格式,需要要进行类型type的修改。


图片格式:

1、SkImageEncoder 中的Type 枚举(注意有些android版本是没有完全实现的)

enum Type{
	kUnknown_Type,
	kBMP_Type,
	kGIF_Type,
	kICO_Type,
	kJPEG_Type,
	kPNG_Type,
	kWBMP_Type,
	kWEBP_Type,
	kKTX_Type,
};


2、kDefaultQuality默认值为80 图片的清晰度

如果想提高这个工具的截屏效率,可以通过选择图片格式或者选择图片的质量。


总结:

  1. 经实际测试,1s 不到10帧,screencap效率是相当差的(包含保存为jpeg等格式)。
  2. 如果需要修改保存图片的格式,需要修改源码重新编译。

你可能感兴趣的:(源码,效率,性能优化,截屏,screencap)