Android 如何在没有 root 权限的情况下以编程方式截取其他应用程序的屏幕截图,例如 Screenshot UX Trial?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12462944/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to take a screenshot of other app programmatically without root permission, like Screenshot UX Trial?
提问by Victor Chang
How to take a screenshot of other app programmatically without root permission, like Screenshot UX Trial?
如何在没有 root 权限的情况下以编程方式截取其他应用程序的屏幕截图,例如 Screenshot UX Trial?
I know I can capture the bitmap of the root view in my app. But I can't get the root view of the other app when my app is running in background
bitmap = Bitmap.createBitmap(rootview.getDrawingCache());
There is a permission for capturing current frame buffer in Manifest:
android.permission.READ_FRAME_BUFFER
. But some website says it's for signature app only.
我知道我可以在我的应用程序中捕获根视图的位图。但是当我的应用程序在后台运行时,我无法获得其他应用程序的根视图
bitmap = Bitmap.createBitmap(rootview.getDrawingCache());
在 Manifest: 中有捕获当前帧缓冲区的权限
android.permission.READ_FRAME_BUFFER
。但是有些网站说它仅适用于签名应用程序。
After trying Screenshot UX Trial, I read the permission:
在尝试 Screenshot UX Trial 后,我阅读了权限:
- INTERNET: for connect to localhost screenshot server for rooted phone.
- SYSTEM_ALERT_WINDOW: for topmost camera button.
- VIBRATE: for vibrate feedback.
- WRITE_EXTERNAL_STORAGE: to save the screenshot.
- GET_TASKS: for detect foreground Develoment setting activity for non rooted&non preloaded capture method.
- 互联网:用于连接到 localhost 屏幕截图服务器以获取 root 手机。
- SYSTEM_ALERT_WINDOW:用于最顶部的相机按钮。
- VIBRATE:用于振动反馈。
- WRITE_EXTERNAL_STORAGE:保存截图。
- GET_TASKS:用于检测非 root 和非预加载捕获方法的前景开发设置活动。
It seems either SYSTEM_ALERT_WINDOW
or GET_TASKS
allow the app to take screenshot.
I have two guess of how it works:
似乎SYSTEM_ALERT_WINDOW
或GET_TASKS
允许应用程序截取屏幕截图。我有两个猜测它是如何工作的:
- It may be able to access the
Activity
of the foreground activity, it gets the root view of theActivity
, capture its screenshot. - Calling
glreadpixels
- 它可能能够访问
Activity
前台活动的 ,它获取 的根视图Activity
,捕获其屏幕截图。 - 打电话
glreadpixels
If you try one of my guess, please let me know the result.
如果您尝试我的猜测之一,请告诉我结果。
回答by Adrian Taylor
This is extremely difficult. I spent several years trying to do it. I eventually succeeded, but any solution will involve commercial as well as technical effort.
这是极其困难的。我花了几年的时间试图做到这一点。我最终成功了,但任何解决方案都将涉及商业和技术方面的努力。
Update March 2015
2015 年 3 月更新
Most of the stuff below is no longer up-to-date. There's now, after all these years, an android.media.projection
package
https://developer.android.com/reference/android/media/projection/package-summary.htmlwhich finally allows what you need!
下面的大部分内容不再是最新的。这么多年过去了,现在有了一个android.media.projection
包
https://developer.android.com/reference/android/media/projection/package-summary.html终于可以满足你的需求了!
Capturing the screen image of your own application
捕获您自己的应用程序的屏幕图像
For completeness, I want to include your own comment that you can capture an image of your own application using Bitmap.createBitmap(rootview.getDrawingCache());
and similar mechanisms.
为了完整起见,我想包括您自己的评论,您可以使用Bitmap.createBitmap(rootview.getDrawingCache());
类似的机制捕获自己的应用程序的图像。
Capturing the screen of another application whilst you're in the background
在后台捕获另一个应用程序的屏幕
Using the READ_FRAMEBUFFER
permission
使用READ_FRAMEBUFFER
权限
Firstly, you're right that a normal application can't make use of the READ_FRAMEBUFFER
permission, because it's "signature"-level. That means you must be signed by the same key as the Android system ROM in order to be able to take such a screenshot.
首先,普通应用程序不能使用READ_FRAMEBUFFER
权限是对的,因为它是“签名”级别的。这意味着您必须使用与 Android 系统 ROM 相同的密钥签名才能截取此类屏幕截图。
I thought this was a bit sad, so back in 2009 I made an Android open-source project submission to ask that it be opened up1. The response from Dianne Hackborn, the Android architect was:
我觉得这有点悲哀,所以早在 2009 年我就提交了一个 Android 开源项目,要求将其开放1。Android 架构师 Dianne Hackborn 的回应是:
Um, no. Absolutely positively not.
不。绝对肯定没有。
So, that went well, then! Hence this permission is still signature
-level to this day.
那么,一切顺利!因此,该权限signature
直到今天仍然是级别的。
If you had this permission, however, you could call the captureScreen
member of ISurfaceComposer
2. You'd need to write some native code to access this function, using the Android NDK and also some undocumented APIs. However, it's possible.
但是,如果您拥有此权限,则可以调用2的captureScreen
成员。您需要使用 Android NDK 和一些未公开的 API 编写一些本机代码来访问此功能。然而,这是可能的。ISurfaceComposer
Internally within the Android graphics subsystem, this uses a glReadPixels
call to retrieve the pixels from the GPU back to the CPU. (The GPU is used for most of the compositing on Android. In fact Android 4.0+ supports extra hardware compositors, and the Surface Flinger has to do even more work to pull those pixels back to the CPU.)
在 Android 图形子系统内部,它使用glReadPixels
调用将像素从 GPU 检索回 CPU。(GPU 用于 Android 上的大部分合成。实际上,Android 4.0+ 支持额外的硬件合成器,而 Surface Flinger 必须做更多的工作才能将这些像素拉回 CPU。)
This call works beautifully, except for a few small problems:
除了一些小问题外,这个调用效果很好:
- The risk of using an unsupported API which might break at any moment;
- The hassle of calling it in C++
- It causes the GPU pipelines to stall, which can upset the GPU designers but doesn't really cause problems in reality
- It relies on a large bandwidth from the GPU backto the CPU. This is sometimes problematic because memory architectures are designed to send data in the opposite direction. However, I seem to recall that all modern Android chipset architectures directly share memory between the GPU and CPU, except for one (it may be Broadcom? - I can't remember) where this may cause this mechanism to be very slow.
- 使用不受支持的 API 的风险,该 API 可能随时中断;
- 在 C++ 中调用它的麻烦
- 它会导致 GPU 流水线停滞,这会让 GPU 设计者感到不安,但实际上并不会真正引起问题
- 它依赖于从 GPU返回到 CPU的大带宽。这有时是有问题的,因为内存架构旨在以相反的方向发送数据。但是,我似乎记得所有现代 Android 芯片组架构都直接在 GPU 和 CPU 之间共享内存,除了一个(可能是博通? - 我不记得了)这可能会导致此机制非常慢。
... and one large problem ...
......还有一个大问题......
- Most importantly, as a normal application writer, you can't even call this API due to the signature-level permissions required.
- 最重要的是,作为普通的应用程序编写者,由于需要签名级权限,您甚至无法调用此 API。
Still, on most Android devices, you can get 10 frames per second out of this. Better still, this API actually supports scaling the resulting image in hardware on the GPU, so if you're clever you can pre-scale the image to just the size you need, before the pixels even hit the CPU. So it can be extremely high performance.
尽管如此,在大多数 Android 设备上,您可以每秒获得 10 帧。更好的是,这个 API 实际上支持在 GPU 上的硬件中缩放生成的图像,所以如果你很聪明,你可以在像素到达 CPU 之前将图像预先缩放到你需要的大小。所以它可以是非常高性能的。
Note, of course, that you as an application writer can't call glReadPixels
because you don't have access to the relevant OpenGL context. It's owned by the surface flinger.
请注意,当然,您作为应用程序编写者无法调用,glReadPixels
因为您无权访问相关的 OpenGL 上下文。它由表面抛油环拥有。
Using /dev/graphics/fb0
and similar
使用/dev/graphics/fb0
和类似
Some are tempted to try to read these Linux device files which represent the framebuffer. However, there are three problems:
有些人试图读取这些代表帧缓冲区的 Linux 设备文件。但是,存在三个问题:
- You need root.
- Sometimes they're not even there.
- Often, they don't represent the real screen image. Remember on Android that the graphics are composited on the GPU. So there's no reason why the CPU should have access to a copy of the full composited screen image, and it often doesn't. This file sometimes contains tearing (at best) and a garbage image (at worst). Interestingly, some of the tools for rooted phones do use this method, which I think is a mistake. If you've got root, you by definition have all Android permissions and can therefore call the above
captureScreen
API to get a correct image.
- 你需要root。
- 有时他们甚至不在那里。
- 通常,它们并不代表真实的屏幕图像。请记住,在 Android 上,图形是在 GPU 上合成的。因此,CPU 没有理由访问完整的合成屏幕图像的副本,而且通常不会。该文件有时包含撕裂(最好)和垃圾图像(最坏)。有趣的是,一些root手机的工具确实使用了这种方法,我认为这是一个错误。如果您有 root 用户,根据定义,您拥有所有 Android 权限,因此可以调用上述
captureScreen
API 来获取正确的图像。
Using hardware partners
使用硬件合作伙伴
Now we get into the solutions which require commercial action.
现在我们进入需要商业行动的解决方案。
Talking to the Android chipset makers often presents a solution. Since they design the hardware, they have access to the framebuffer - and they often are able to provide libraries which entirely avoid the Android permissions model by simply accessing their custom kernel drivers directly.
与 Android 芯片组制造商交谈通常会提供解决方案。由于他们设计了硬件,因此他们可以访问帧缓冲区——并且他们通常能够通过直接访问他们的自定义内核驱动程序来提供完全避免 Android 权限模型的库。
If you're aiming at a specific phone model, this is often a good way forward. Of course, the odds are you'll need to cooperate with the phone maker as well as the silicon manufacturer.
如果您的目标是特定的手机型号,这通常是一个很好的前进方向。当然,您可能需要与手机制造商以及芯片制造商合作。
Sometimes this can provide outstandingresults. For example I have heard it's possible on some hardware to pipe the phone hardware framebuffer directly into the phone hardware H.264 video encoder, and retrieve a pre-encoded video stream of whatever is on the phone screen. Outstanding. (Unfortunately, I only knowthis is possible on TI OMAP chips, which are gradually withdrawing from the phone market3).
有时,这可以提供出色的结果。例如,我听说在某些硬件上可以将电话硬件帧缓冲区直接通过管道传输到电话硬件 H.264 视频编码器,并检索电话屏幕上任何内容的预编码视频流。杰出的。(不幸的是,我只知道这在逐渐退出手机市场的 TI OMAP 芯片上是可能的3)。
Using security holes
使用安全漏洞
Android rigidly enforces its permission model, and has few security holes. However the Android OEMs can sometimes be more careless.
Android 严格执行其权限模型,并且几乎没有安全漏洞。然而,Android OEM 有时会更加粗心。
For example a major OEM whose name begins with S has implemented a way to capture the screen using a keystroke. It saves it to a world-readable file on the SD card. Hypothetically you might be able to find what intercepts those keys and see how it works. Perhaps you could do something similar.
例如,名称以 S 开头的主要 OEM 实施了一种使用按键捕获屏幕的方法。它将它保存到 SD 卡上的一个世界可读的文件中。假设您可以找到拦截这些键的内容并查看它是如何工作的。也许你可以做一些类似的事情。
And perhaps there's a way for another major OEM whose name also begins with S.
也许还有一种方法可以让另一家名称也以 S 开头的主要 OEM 厂商。
No, I'm not going to go into any more detail on this section. To work out how to do those things, I'd need to have reverse-engineered software, and that might be illegal. Good luck, though.
不,我不打算详细介绍这一部分。为了弄清楚如何做这些事情,我需要有逆向工程软件,这可能是非法的。不过祝你好运。
Working with the phone makers
与手机制造商合作
As described previously, the phone makers have ready access to an API which does work. And the phone makers have the signature
-level permissions required.
如前所述,手机制造商必须在其API随时访问不工作。并且手机制造商拥有signature
所需的级别权限。
So, all you need to do is to arrange to get your software signed by the phone maker.
因此,您需要做的就是安排让手机制造商对您的软件进行签名。
This is, however, hard. By signing the software, the phone maker is guaranteeing its quality - so they should want to audit your source code. Also, due to the nature of Android - if they sign the software, they need to be the ones distributing it. You can't put it on the Market if it is signed by someone else's signature.
然而,这很难。通过签署软件,手机制造商保证了它的质量——所以他们应该审核你的源代码。此外,由于 Android 的性质 - 如果他们签署软件,他们需要成为分发它的人。如果它是由其他人签名的,则您不能将其投放市场。
However, the OEM need not include it on the ROM - they can still distribute it on the Android market. But you can't.
但是,OEM 不需要将它包含在 ROM 中——他们仍然可以在 Android 市场上分发它。但你不能。
A good solution would be if each vendor signed a small library which then could be accessed by a common SDK. Which leads me onto...
一个好的解决方案是,如果每个供应商都签署了一个小型库,然后可以通过通用 SDK 访问该库。这让我...
Work with software partners who have solved this already
与已经解决了这个问题的软件合作伙伴合作
I know a lot about this because I used to work at RealVNC. We worked with all the major Android phone vendors to get access to these signature-level APIs. I cannot overemphasise the many, many man-years of effort (commercially and technically) required to achieve this. Some of the OEMs have publicised this work - for example 4.
我对此非常了解,因为我曾经在 RealVNC 工作过。我们与所有主要的 Android 手机供应商合作,以访问这些签名级 API。为实现这一目标需要付出很多很多人年的努力(商业和技术上),我再怎么强调也不为过。一些 OEM 已经公布了这项工作——例如4。
I do not workat RealVNC any more, so I have nothing to gain from advertising their software. But if you really reallywant to be able to capture the screen on multiple Android devices, you may wish to approach them about re-using their Remote Control Service or Android VNC SDK 5. It is not open-source so you should expect to pay, and believe me this is fair enough given the epic effort involved in working with all these Android OEMs.
我不再在 RealVNC工作,所以我从他们的软件广告中没有任何好处。但是,如果您真的希望能够在多个 Android 设备上捕获屏幕,您可能希望与他们联系以重新使用他们的远程控制服务或 Android VNC SDK 5。它不是开源的,所以你应该期望付费,相信我,考虑到与所有这些 Android OEM 合作所付出的巨大努力,这已经足够公平了。
In the interests of balance I should point out that other vendors have also worked with the phone makers on this - e.g. Soti. But I believe they all offer specific device management solutions, rather than a general remote control/event injection SDK.
为平衡起见,我应该指出,其他供应商也在这方面与手机制造商合作——例如 Soti。但我相信他们都提供特定的设备管理解决方案,而不是通用的远程控制/事件注入 SDK。
Over USB
通过 USB
Another option - the adb
daemon which listens for debugging connections over USB has slightly more privileges than a normal application, which is why it's able to grab the screen (you can see its image using the ddms
tool). If you're able to run any command using adb
then you too can gain those privileges (as per the android-screenshot-library linked previously).
另一种选择 -adb
通过 USB 侦听调试连接的守护程序具有比普通应用程序稍多的权限,这就是它能够抓取屏幕的原因(您可以使用该ddms
工具查看其图像)。如果您能够使用任何命令运行,adb
那么您也可以获得这些权限(根据之前链接的 android-screenshot-library)。
Contribute to the Android open-source project
为 Android 开源项目做贡献
Eventually this problem reduced me to dust, and I left for greener pastures which didn't involve trying to squeeze pixels out of Android phones.
最终,这个问题让我尘埃落定,我离开了更绿色的牧场,这不涉及试图从 Android 手机中挤出像素。
Before I left RealVNC though, we tried again to contribute these APIs to the Android open-source project. This time we got a more positive reaction6. In short, it was suggested that our security approach was almost right, but that the graphics system was in too much turmoil to accept our patches. Well, the great news is that the graphics system is no longer in turmoil - in fact it now has that captureScreen
API which means no graphics system changes are needed whatsoever. It may therefore be possible to submit a new security mechanism to AOSP around this API which finally solves this problem.
在我离开 RealVNC 之前,我们再次尝试将这些 API 贡献给 Android 开源项目。这次我们得到了更积极的反应6。简而言之,有人认为我们的安全方法几乎是正确的,但图形系统太混乱而无法接受我们的补丁。好吧,好消息是图形系统不再处于混乱状态 - 事实上它现在有了captureScreen
API,这意味着不需要任何图形系统更改。因此,有可能围绕这个 API 向 AOSP 提交新的安全机制,最终解决这个问题。
Best of luck!
祝你好运!
回答by DNax
Maybe the android-screenshot-librarycan help. But well in their Usage page it says that it needs a native service started with adb (from the android sdk).
也许android-screenshot-library可以提供帮助。但是在他们的使用页面中,它说它需要一个以 adb 启动的本机服务(来自 android sdk)。
PS: Remember that Screenshot UX does not work for every unrooted phone.
PS:请记住,Screenshot UX 不适用于所有无根电话。
回答by Diederik
I don't think Android will allow you to access another app's frame buffer. This is just part of the security of Android. Each app should keep to its own resources.
我认为 Android 不会允许您访问另一个应用程序的帧缓冲区。这只是 Android 安全性的一部分。每个应用程序都应该保留自己的资源。
If you really need to get a screen capture of any app, I would suggest using the native screen grab "gesture". For the the Nexus 7for example, simply "... hold the power button and the volume down button at the same time for approximately 2 seconds."
如果您确实需要获取任何应用程序的屏幕截图,我建议您使用本机屏幕抓取“手势”。例如,对于Nexus 7,只需“...同时按住电源按钮和音量降低按钮大约 2 秒钟。”
A Google search will usually find the trick with your device.
Google 搜索通常会在您的设备上找到窍门。