Android screenshot problem
See a lot of friends have a need: that is to intercept the entire Android screen, and everyone has encountered a similar problem, no permissions. This article is mainly from the point of view of the code analysis, ask what needs permissions, what kind of permissions required? We also have some analysis on the screen cutting method, and we welcome the discussion.
Android screenshot--traditional method
Generally the first Android screenshot is from the Linux screenshot method, Android uses the Linux kernel, then the Linux screenshot method is the first to be used by Android. Linux uses the Framebuffer management display output, the traditional way is to read the framebuffer data, and then get the entire screen of data. This method is also the only viable method before the Android3.0 version. However, Linux employs strict permissions control device files, Framebuffer is also one of its controls, only root in Android, and graphic group users have access to read:
Ls-l/dev/graphics/fb0 crw-rw----root graphics , 0 2015-01-16 03:26 fb0
Therefore, to use the Read framebuffer way to achieve the screenshot, the application must be root permissions.
With the evolution of Android display system, since Android 4.2, Android has added a screenshot interface, and more devices using multiple framebuffer use overlay, more hardware composer devices, so that the separate read F Ramebuffer is not able to intercept a complete screen. So this method is also gradually abandoned by the developers.
Android screenshot--Surfaceflinger
In Android 4.0, the display system uses a new architecture, adding a "butter plan", as well as a screenshot interface:
status_t Surfaceflinger::capturescreen (const sp<ibinder>& Display, sp<imemoryheap>* heap, UI nt32_t* width, uint32_t* height, pixelformat* format, uint32_t SW, uint32_t sh, uint32_t Minlayerz, uint32_t Maxlayerz) {if (cc_unlikely (display = = 0)) return bad_value; if (! Glextensions::getinstance (). Haveframebufferobject ()) return invalid_operation; Class Messagecapturescreen:public Messagebase {surfaceflinger* flinger; sp<ibinder> display; sp<imemoryheap>* Heap; uint32_t* W; uint32_t* h; pixelformat* F; uint32_t SW; uint32_t sh; uint32_t Minlayerz; uint32_t Maxlayerz; status_t result; Public:messagecapturescreen (surfaceflinger* flinger, const sp<ibinder>& display, Sp<im emoryheap>* Heap, uint32_t* W, uint32_t* H, pixelformat* F, uint32_t SW, uint32_t sh, UIn t32_t mInlayerz, uint32_t Maxlayerz): Flinger (Flinger), display (display), Heap (heap), W (W), H (h), F (f), SW (SW), SH (SH), Minlayerz (Minlayerz), Maxlayerz (Maxlayerz), result (permission_denied) { } status_t GetResult () const {return result; } virtual bool Handler () {Mutex::autolock _l (flinger->mstatelock); result = flinger->capturescreenimpllocked (display, Heap, W, H, F, SW, SH, Minlayerz, Maxlayerz); return true; } }; sp<messagebase> msg = new Messagecapturescreen (this, display, heap, width, height, format, SW, SH, minlay ErZ, Maxlayerz); status_t res = Postmessagesync (msg); if (res = = No_error) {res = static_cast<messagecapturescreen*> (Msg.get ())->getresult (); } return res;
Now the application can call the system interface to intercept the screen, the best example is Screencap:frameworks/base/cmds/screencap/screencap.cpp
However, the system is still for security reasons, the control of permissions is still strict: the use of the system screenshot interface requires Read_framebuffer permissions:
Case Capture_screen: { //codes that require permission check ipcthreadstate* IPC = Ipcthreadstate::self (); const int PID = Ipc->getcallingpid (); const int UID = IPC->GETCALLINGUID (); if (uid! = aid_graphics) && ! Permissioncache::checkpermission (Sreadframebuffer, PID, uid)) { Aloge ("Permission denial:" "can ' t read Framebuffer pid=%d, uid=%d ", PID, UID); return permission_denied; } break; }
And Read_framebuffer belong to the system level of permissions, non-systems application is not available, so in the application to declare the use of this permission, the application if not the system program, still do not have permissions. Third-party programs to be able to intercept the success or need root.
Android screenshot--DDMS
Some developers will find that even if the system does not have root, it can still be successfully ddms by the screenshot. Why is DDMS able to screen successfully on a device without root?
DDMS is also the Intercept interface of the calling system, and he calls the Screencap directly:
First DDMS sends a signal through ADB to the ADBD daemon on the device, ADBD inside the framebuffer service (SYSTEM/CORE/ADB/FRAMEBUFFER_SERVICE.C) is responsible for the entire screenshot process:
void Framebuffer_service (int fd, void *cookie) { struct fbinfo fbinfo; unsigned int i; Char buf[640]; int fd_screencap; int W, h, F; int fds[2]; if (pipe (FDS) < 0) goto done; pid_t pid = fork (); if (PID < 0) goto done; if (PID = = 0) { dup2 (fds[1], Stdout_fileno); Close (Fds[0]); Close (fds[1]); Const char* Command = "screencap"; const char *args[2] = {command, NULL}; EXECVP (command, (char**) args); Exit (1); } Fd_screencap = fds[0]; /* Read W, H & Format * /if (READX (Fd_screencap, &w, 4)) goto done; if (READX (Fd_screencap, &h, 4)) goto done; if (READX (Fd_screencap, &f, 4)) goto done;
So, in fact, the ADBD daemon started the screencap; take mx3 without Root as an example:
[Email protected]:/$ ps Adbdps adbduser PID PPID vsize RSS wchan PC Nameshell 3008 1 4648 272 Ffffffff 00000000 S/sbin/adbd[email protected]:/$ id shellid shelluid=2000 (shell) gid= (shell) groups=1003 (graphics), 1004 (input), 1007 (log), 1009 (Mount), 1011 (ADB), 1015 (SDCARD_RW), 1028 (Sdcard_r), 3001 (Net_bt_admin), 3002 (NET_BT), 3003 (inet), 3006 (net_bw_stats)
The ADBD is executed as a shell user, and the system assigns a graphics group to the shell user, so the shell user has permission to invoke the Surfaceflinger interface.
Summarize
The above methods, in addition to the ADB does not need root, the other two require root to intercept the screen. Of course there are Android version differences, resulting in interface functions are not the same, specific details can view the source code. To implement your screenshots, it is necessary to elevate permissions, but we also see that some programs can be executed on a device without root. Then we can speculate that it is possible not to root, but it is possible to ascend to the graphics or to elevate the application to the system level. Hopefully this article will help friends who are still looking for screenshots.
Why Android screenshots require root access