这是极其困难的。我花了几年的时间试图做到这一点。我最终成功了,但任何解决方案都将涉及商业和技术工作。
2015 年 3 月更新
下面的大部分内容不再是最新的。经过这么多年,现在有一个android.media.projection
包
https://developer.android.com/reference/android/media/projection/package-summary.html
终于可以满足您的需求了!
捕获您自己的应用程序的屏幕图像
为了完整起见,我想包含您自己的评论,您可以使用Bitmap.createBitmap(rootview.getDrawingCache());
类似机制捕获您自己的应用程序的图像。
在后台捕获另一个应用程序的屏幕
使用READ_FRAMEBUFFER
权限
首先,您是对的,普通应用程序无法使用该READ_FRAMEBUFFER
权限,因为它是“签名”级别的。这意味着您必须使用与 Android 系统 ROM 相同的密钥进行签名,才能截取这样的屏幕截图。
我觉得这有点难过,所以早在 2009 年,我提交了一个 Android 开源项目,要求将其开放1。Android 架构师 Dianne Hackborn 的回应是:
不。绝对不会。
那么,事情进展顺利!因此,此权限至今仍为signature
- 级别。
但是,如果您有此权限,则可以调用2captureScreen
的成员。您需要使用 Android NDK 和一些未记录的 API 编写一些本机代码来访问此功能。但是,这是可能的。ISurfaceComposer
在 Android 图形子系统内部,它使用glReadPixels
调用将像素从 GPU 检索回 CPU。(GPU 用于 Android 上的大部分合成。事实上,Android 4.0+ 支持额外的硬件合成器,Surface Flinger 必须做更多的工作才能将这些像素拉回 CPU。)
这个调用很好用,除了一些小问题:
- 使用可能随时中断的不受支持的 API 的风险;
- 在 C++ 中调用它的麻烦
- 它会导致 GPU 流水线停止,这可能会让 GPU 设计人员感到不安,但实际上并不会真正造成问题
- 它依赖于从 GPU 到 CPU 的大带宽。这有时是有问题的,因为内存架构被设计为以相反的方向发送数据。但是,我似乎记得所有现代 Android 芯片组架构都直接在 GPU 和 CPU 之间共享内存,除了一个(可能是 Broadcom? - 我不记得了),这可能会导致这种机制非常缓慢。
...还有一个大问题...
- 最重要的是,作为一个普通的应用程序编写者,由于需要签名级别的权限,您甚至无法调用此 API。
尽管如此,在大多数 Android 设备上,您仍然可以获得每秒 10 帧的速度。更好的是,这个 API 实际上支持在 GPU 上的硬件中缩放生成的图像,所以如果你很聪明,你可以在像素到达 CPU 之前将图像预缩放到你需要的大小。所以它可以是极高的性能。
当然,请注意,您作为应用程序编写者无法调用glReadPixels
,因为您无权访问相关的 OpenGL 上下文。它归表面抛油环所有。
使用/dev/graphics/fb0
和类似
有些人很想尝试读取这些代表帧缓冲区的 Linux 设备文件。但是,存在三个问题:
- 你需要根。
- 有时他们甚至都不在那里。
- 通常,它们并不代表真实的屏幕图像。请记住,在 Android 上,图形是在 GPU 上合成的。因此,CPU 没有理由访问完整合成屏幕图像的副本,而且通常没有。该文件有时包含撕裂(最好的情况)和垃圾图像(最坏的情况)。有趣的是,一些root手机的工具确实使用了这种方法,我认为这是一个错误。如果你有 root 权限,那么根据定义,你拥有所有 Android 权限,因此可以调用上述
captureScreen
API 来获取正确的图像。
使用硬件合作伙伴
现在我们进入需要商业行动的解决方案。
与 Android 芯片组制造商交谈通常会提供解决方案。由于他们设计了硬件,因此他们可以访问帧缓冲区——而且他们通常能够通过直接访问他们的自定义内核驱动程序来提供完全避免 Android 权限模型的库。
如果您针对特定的手机型号,这通常是一个很好的前进方向。当然,您可能需要与手机制造商以及硅制造商合作。
有时这可以提供出色的结果。例如,我听说在某些硬件上可以将电话硬件帧缓冲区直接传送到电话硬件 H.264 视频编码器中,并检索电话屏幕上任何内容的预编码视频流。杰出的。(不幸的是,我只知道这在 TI OMAP 芯片上是可能的,它正在逐渐退出手机市场3)。
使用安全漏洞
Android 严格执行其权限模型,并且几乎没有安全漏洞。然而,Android OEM 有时可能会更加粗心。
例如,一家名称以 S 开头的主要 OEM 实施了一种使用击键来捕获屏幕的方法。它将它保存到 SD 卡上的世界可读文件中。假设您可能能够找到拦截这些密钥的内容并查看它是如何工作的。也许你可以做类似的事情。
也许对于另一个名称也以 S 开头的主要 OEM 来说,还有一种方法。
不,我不会在本节中详细介绍。要弄清楚如何做这些事情,我需要有逆向工程软件,这可能是非法的。不过,祝你好运。
与手机制造商合作
如前所述,电话制造商可以随时访问有效的API。并且电话制造商具有signature
所需的级别权限。
因此,您需要做的就是安排让手机制造商对您的软件进行签名。
然而,这很难。通过签署软件,手机制造商可以保证其质量——因此他们应该审核您的源代码。此外,由于 Android 的性质 - 如果他们签署了软件,他们需要成为分发它的人。如果它是由其他人签名的,则不能将其投放市场。
但是,OEM 不需要将其包含在 ROM 中 - 他们仍然可以在 Android 市场上分发它。但你不能。
一个好的解决方案是,如果每个供应商都签署一个小型库,然后可以通过通用 SDK 访问该库。这导致我...
与已经解决此问题的软件合作伙伴合作
我对此了解很多,因为我曾经在 RealVNC 工作过。我们与所有主要的 Android 手机供应商合作,以访问这些签名级 API。我不能过分强调实现这一目标所需的许多人年的努力(商业上和技术上)。一些原始设备制造商已经宣传了这项工作,例如4 .
我不再在 RealVNC 工作,所以我从宣传他们的软件中得不到任何好处。但是,如果您真的希望能够在多个 Android 设备上捕获屏幕,您可能希望与他们联系以重新使用他们的 Remote Control Service 或 Android VNC SDK 5。它不是开源的,因此您应该期望付费,并且相信我,考虑到与所有这些 Android OEM 合作所涉及的巨大努力,这已经足够公平了。
为了平衡起见,我应该指出其他供应商也在这方面与手机制造商合作 - 例如 Soti。但我相信它们都提供特定的设备管理解决方案,而不是通用的远程控制/事件注入 SDK。
通过 USB
另一种选择 -adb
通过 USB 侦听调试连接的守护程序比普通应用程序具有稍多的特权,这就是它能够抓取屏幕的原因(您可以使用该ddms
工具查看其图像)。如果您能够运行任何命令,adb
那么您也可以获得这些权限(根据之前链接的 android-screenshot-library)。
为 Android 开源项目做出贡献
最终,这个问题让我化为尘土,我去了更绿色的牧场,这并不涉及试图从 Android 手机中挤出像素。
不过,在我离开 RealVNC 之前,我们再次尝试将这些 API 贡献给 Android 开源项目。这次我们得到了更积极的反应6。简而言之,有人认为我们的安全方法几乎是正确的,但图形系统太混乱了,无法接受我们的补丁。好消息是图形系统不再处于混乱状态——事实上它现在有了captureScreen
API,这意味着不需要对图形系统进行任何更改。因此,可以围绕这个 API 向 AOSP 提交一个新的安全机制,最终解决这个问题。
祝你好运!