多多色-多人伦交性欧美在线观看-多人伦精品一区二区三区视频-多色视频-免费黄色视屏网站-免费黄色在线

國(guó)內(nèi)最全I(xiàn)T社區(qū)平臺(tái) 聯(lián)系我們 | 收藏本站
阿里云優(yōu)惠2
您當(dāng)前位置:首頁(yè) > php開(kāi)源 > 綜合技術(shù) > 為什么 Android 截屏需要 root 權(quán)限

為什么 Android 截屏需要 root 權(quán)限

來(lái)源:程序員人生   發(fā)布時(shí)間:2015-01-23 08:22:24 閱讀次數(shù):4448次

Android 截屏問(wèn)題

看到很多朋友都有1個(gè)需求:那就是截取 Android 的全部屏幕,而且大家都遇到1個(gè)相同的問(wèn)題,沒(méi)有權(quán)限。這篇文章主要從代碼的角度分析,問(wèn)甚么需要權(quán)限,需要甚么樣的權(quán)限?對(duì)截屏方法也有1些分析,歡迎大家討論。


Android 截屏 -- 傳統(tǒng)方法

1般最開(kāi)始的 Android 截屏程序,都是來(lái)源于 Linux 的截屏方法,android 使用的 Linux 內(nèi)核,那末 Linux 下的截屏方法也就最早被 android 采取。Linux  使用了 framebuffer 管理顯示輸出,傳統(tǒng)的辦法就是讀取 framebuffer 的數(shù)據(jù),然后得到全部屏幕的數(shù)據(jù)。此方法在 Android3.0 版本之前是也唯1可行的方法。 但是 linux 采取了嚴(yán)格的權(quán)限控制 裝備文件,framebuffer 也是其控制之1,在 Android 中只有 root , 和 graphic 組用戶才有權(quán)限讀取:

ls -l /dev/graphics/fb0 crw-rw---- root graphics 29, 0 2015-01⑴6 03:26 fb0

所以要采取讀取 framebuffer 的方式實(shí)現(xiàn)截屏,利用必須取得 root 權(quán)限。

隨著 Android 顯示系統(tǒng)的變遷,自 Android 4.2 開(kāi)始, Android 自己增加截屏接口,而且更多的裝備采取了多個(gè) framebuffer 使用 overlay 的方式,更有采取硬件 composer 的裝備,使得單獨(dú)讀取 framebuffer 其實(shí)不能截取到,1個(gè)完全的屏幕。因而這個(gè)方法也漸漸被開(kāi)發(fā)者拋棄。



Android 截屏 -- SurfaceFlinger

在 Android 4.0 里,顯示系統(tǒng)采取了新的構(gòu)架,加入“黃油計(jì)劃”,同時(shí)也添加截屏接口:

status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display, sp<IMemoryHeap>* heap, uint32_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<IMemoryHeap>* heap, uint32_t* w, uint32_t* h, PixelFormat* f, uint32_t sw, uint32_t sh, uint32_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, minLayerZ, maxLayerZ); status_t res = postMessageSync(msg); if (res == NO_ERROR) { res = static_cast<MessageCaptureScreen*>( msg.get() )->getResult(); } return res; }

現(xiàn)在利用可以調(diào)用系統(tǒng)接口來(lái)截屏,最好的例子就是 screencap : frameworks/base/cmds/screencap/screencap.cpp

但是,系統(tǒng)仍然出于安全的斟酌,對(duì)權(quán)限的控制仍然嚴(yán)格:使用系統(tǒng)截屏接口需要 READ_FRAMEBUFFER 權(quán)限:

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; }

而且 READ_FRAMEBUFFER 屬于 system 級(jí)別的權(quán)限,非系統(tǒng)利用沒(méi)法取得,所以在利用程序中聲明了使用這個(gè)權(quán)限,利用程序如果不是 system 程序,仍然沒(méi)有權(quán)限。第3方程序要能截屏成功還是需要 root 。



Android 截屏 -- ddms

有的開(kāi)發(fā)者就會(huì)發(fā)現(xiàn),就算系統(tǒng)沒(méi)有 root,仍然可以通過(guò) ddms 截屏成功。 為何 ddms 可以在沒(méi)有 root 的裝備上截屏成功?

ddms 也是調(diào)用系統(tǒng)的截屏接口,而且他直接調(diào)用的是 screencap:

首先 ddms 通過(guò) adb 發(fā)送信號(hào)給裝備上的 adbd 守護(hù)進(jìn)程,adbd 里面的 framebuffer service (system/core/adb/framebuffer_service.c ) 負(fù)責(zé)全部截屏進(jìn)程:

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;

所以,實(shí)際上是 adbd 守護(hù)進(jìn)程啟動(dòng)了 screencap;以沒(méi)有root 的 mx3 為例:

shell@mx3:/ $ ps adbd ps adbd USER PID PPID VSIZE RSS WCHAN PC NAME shell 3008 1 4648 272 ffffffff 00000000 S /sbin/adbd shell@mx3:/ $ id shell id shell uid=2000(shell) gid=2000(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)

adbd 是以 shell 用戶履行的, 而系統(tǒng)為 shell 用戶分配 graphics 組,所以 shell 用戶是有權(quán)限調(diào)用 surfaceflinger 的接口的。



總結(jié)

以上幾種辦法,除 adb 不需要 root ,另外兩種都需要 root 才能截屏。固然還有 android 的版本差異,造成接口函數(shù)也不1樣,具體細(xì)節(jié)可以查看源代碼。要實(shí)現(xiàn)自己的截屏功能,提升權(quán)限是必須的,但是我們也看到有些程序可以在沒(méi)有 root 的裝備上履行。那末我們可以推測(cè),可以不要 root ,但是提升到 graphics 或?qū)⒗锰嵘?system 級(jí)別都是可行的。希望這篇文章可以幫助還在尋覓截屏方法的朋友。


生活不易,碼農(nóng)辛苦
如果您覺(jué)得本網(wǎng)站對(duì)您的學(xué)習(xí)有所幫助,可以手機(jī)掃描二維碼進(jìn)行捐贈(zèng)
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關(guān)閉
程序員人生
主站蜘蛛池模板: 亚洲丶国产丶欧美一区二区三区 | 国产亚洲精品资源在线26u | 亚洲春色在线观看 | 亚洲激情专区 | 国产一级淫片a视频免费观看 | 99视频精品免视3 | 国产高清国产精品国产k | 精品国产高清毛片 | 免费视频不卡一区二区三区 | 国产美女主播一级成人毛片 | 成人青草亚洲国产 | 国产成人一区二区三区在线视频 | 欧美另类精品一区二区三区 | h在线观看视频免费网站 | 五月天看片 | 欧美变态暴力交videos | 欧美精品一区二区三区免费播放 | h视频在线免费观看 | 狠狠干一区| 欧美日韩精品一区二区 | 小毛片网站 | 中文字幕在线精品视频入口一区 | 精品国产v无码大片在线观看 | 美女私人影院 | 美国一级毛片免费 | japanese国产高清麻豆 | 在线精品播放 | 日韩久久中文字幕 | 久久三级毛片 | 久久www免费人成_看片高清 | 日韩欧美极品 | 欧美一级高清免费a | 欧美成人精品福利在线视频 | 日韩免费福利视频 | 日产一一到六区网站免费 | 日韩欧美亚洲国产 | 日本无卡码一区二区三区 | 手机看片国产精品 | 国产精品一区二区三区四区 | 一级aaaaaa片毛片在线播放 | 99国产在线观看 |