android后台截屏实现(2)--screencap源码修改

来源:互联网 发布:手机淘宝不能分享链接 编辑:程序博客网 时间:2024/06/07 05:07

        首先找到screencap类在Android源码中的位置,/442/frameworks/base/cmds/screencap/screencap.cpp。

源码如下:

[cpp] view plain copy
  1. /* 
  2.  * Copyright (C) 2010 The Android Open Source Project 
  3.  * 
  4.  * Licensed under the Apache License, Version 2.0 (the "License"); 
  5.  * you may not use this file except in compliance with the License. 
  6.  * You may obtain a copy of the License at 
  7.  * 
  8.  *      http://www.apache.org/licenses/LICENSE-2.0 
  9.  * 
  10.  * Unless required by applicable law or agreed to in writing, software 
  11.  * distributed under the License is distributed on an "AS IS" BASIS, 
  12.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
  13.  * See the License for the specific language governing permissions and 
  14.  * limitations under the License. 
  15.  */  
  16.   
  17. #include <errno.h>  
  18. #include <unistd.h>  
  19. #include <stdio.h>  
  20. #include <fcntl.h>  
  21.   
  22. #include <linux/fb.h>  
  23. #include <sys/ioctl.h>  
  24. #include <sys/mman.h>  
  25.   
  26. #include <binder/ProcessState.h>  
  27.   
  28. #include <gui/SurfaceComposerClient.h>  
  29. #include <gui/ISurfaceComposer.h>  
  30.   
  31. #include <ui/PixelFormat.h>  
  32.   
  33. #include <SkImageEncoder.h>  
  34. #include <SkBitmap.h>  
  35. #include <SkData.h>  
  36. #include <SkStream.h>  
  37.   
  38. using namespace android;  
  39.   
  40. static uint32_t DEFAULT_DISPLAY_ID = ISurfaceComposer::eDisplayIdMain;  
  41.   
  42. static void usage(const char* pname)  
  43. {  
  44.     fprintf(stderr,  
  45.             "usage: %s [-hp] [-d display-id] [FILENAME]\n"  
  46.             "   -h: this message\n"  
  47.             "   -p: save the file as a png.\n"  
  48.             "   -d: specify the display id to capture, default %d.\n"  
  49.             "If FILENAME ends with .png it will be saved as a png.\n"  
  50.             "If FILENAME is not given, the results will be printed to stdout.\n",  
  51.             pname, DEFAULT_DISPLAY_ID  
  52.     );  
  53. }  
  54.   
  55. static SkBitmap::Config flinger2skia(PixelFormat f)  
  56. {  
  57.     switch (f) {  
  58.         case PIXEL_FORMAT_RGB_565:  
  59.             return SkBitmap::kRGB_565_Config;  
  60.         default:  
  61.             return SkBitmap::kARGB_8888_Config;  
  62.     }  
  63. }  
  64.   
  65. static status_t vinfoToPixelFormat(const fb_var_screeninfo& vinfo,  
  66.         uint32_t* bytespp, uint32_t* f)  
  67. {  
  68.   
  69.     switch (vinfo.bits_per_pixel) {  
  70.         case 16:  
  71.             *f = PIXEL_FORMAT_RGB_565;  
  72.             *bytespp = 2;  
  73.             break;  
  74.         case 24:  
  75.             *f = PIXEL_FORMAT_RGB_888;  
  76.             *bytespp = 3;  
  77.             break;  
  78.         case 32:  
  79.             // TODO: do better decoding of vinfo here  
  80.             *f = PIXEL_FORMAT_RGBX_8888;  
  81.             *bytespp = 4;  
  82.             break;  
  83.         default:  
  84.             return BAD_VALUE;  
  85.     }  
  86.     return NO_ERROR;  
  87. }  
  88.   
  89. int main(int argc, char** argv)  
  90. {  
  91.     ProcessState::self()->startThreadPool();  
  92.   
  93.     const char* pname = argv[0];  
  94.     bool png = false;  
  95.     int32_t displayId = DEFAULT_DISPLAY_ID;  
  96.     int c;  
  97.     while ((c = getopt(argc, argv, "phd:")) != -1) {  
  98.         switch (c) {  
  99.             case 'p':  
  100.                 png = true;  
  101.                 break;  
  102.             case 'd':  
  103.                 displayId = atoi(optarg);  
  104.                 break;  
  105.             case '?':  
  106.             case 'h':  
  107.                 usage(pname);  
  108.                 return 1;  
  109.         }  
  110.     }  
  111.     argc -= optind;  
  112.     argv += optind;  
  113.   
  114.     int fd = -1;  
  115.     if (argc == 0) {  
  116.         fd = dup(STDOUT_FILENO);  
  117.     } else if (argc == 1) {  
  118.         const char* fn = argv[0];  
  119.         fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0664);  
  120.         if (fd == -1) {  
  121.             fprintf(stderr, "Error opening file: %s (%s)\n", fn, strerror(errno));  
  122.             return 1;  
  123.         }  
  124.         const int len = strlen(fn);  
  125.         if (len >= 4 && 0 == strcmp(fn+len-4, ".png")) {  
  126.             png = true;  
  127.         }  
  128.     }  
  129.   
  130.     if (fd == -1) {  
  131.         usage(pname);  
  132.         return 1;  
  133.     }  
  134.   
  135.     void const* mapbase = MAP_FAILED;  
  136.     ssize_t mapsize = -1;  
  137.   
  138.     void const* base = 0;  
  139.     uint32_t w, s, h, f;  
  140.     size_t size = 0;  
  141.   
  142.     ScreenshotClient screenshot;  
  143.     sp<IBinder> display = SurfaceComposerClient::getBuiltInDisplay(displayId);  
  144.     if (display != NULL && screenshot.update(display) == NO_ERROR) {  
  145.         base = screenshot.getPixels();  
  146.         w = screenshot.getWidth();  
  147.         h = screenshot.getHeight();  
  148.         s = screenshot.getStride();  
  149.         f = screenshot.getFormat();  
  150.         size = screenshot.getSize();  
  151.     } else {  
  152.         const char* fbpath = "/dev/graphics/fb0";  
  153.         int fb = open(fbpath, O_RDONLY);  
  154.         if (fb >= 0) {  
  155.             struct fb_var_screeninfo vinfo;  
  156.             if (ioctl(fb, FBIOGET_VSCREENINFO, &vinfo) == 0) {  
  157.                 uint32_t bytespp;  
  158.                 if (vinfoToPixelFormat(vinfo, &bytespp, &f) == NO_ERROR) {  
  159.                     size_t offset = (vinfo.xoffset + vinfo.yoffset*vinfo.xres) * bytespp;  
  160.                     w = vinfo.xres;  
  161.                     h = vinfo.yres;  
  162.                     s = vinfo.xres;  
  163.                     size = w*h*bytespp;  
  164.                     mapsize = offset + size;  
  165.                     mapbase = mmap(0, mapsize, PROT_READ, MAP_PRIVATE, fb, 0);  
  166.                     if (mapbase != MAP_FAILED) {  
  167.                         base = (void const *)((char const *)mapbase + offset);  
  168.                     }  
  169.                 }  
  170.             }  
  171.             close(fb);  
  172.         }  
  173.     }  
  174.   
  175.     if (base) {  
  176.         if (png) {  
  177.             SkBitmap b;  
  178.             b.setConfig(flinger2skia(f), w, h, s*bytesPerPixel(f));  
  179.             b.setPixels((void*)base);  
  180.             SkDynamicMemoryWStream stream;  
  181.             SkImageEncoder::EncodeStream(&stream, b,  
  182.                     SkImageEncoder::kPNG_Type, SkImageEncoder::kDefaultQuality);  
  183.             SkData* streamData = stream.copyToData();  
  184.             write(fd, streamData->data(), streamData->size());  
  185.             streamData->unref();  
  186.         } else {  
  187.             write(fd, &w, 4);  
  188.             write(fd, &h, 4);  
  189.             write(fd, &f, 4);  
  190.             size_t Bpp = bytesPerPixel(f);  
  191.             for (size_t y=0 ; y<h ; y++) {  
  192.                 write(fd, base, w*Bpp);  
  193.                 base = (void *)((char *)base + s*Bpp);  
  194.             }  
  195.         }  
  196.     }  
  197.     close(fd);  
  198.     if (mapbase != MAP_FAILED) {  
  199.         munmap((void *)mapbase, mapsize);  
  200.     }  
  201.     return 0;  
  202. }  

        由源码可以看出,screencap的入口main方法是从命令行获取参数,通过分析后执行相应的操作。我们要想在java层调用这个类,就要把它的入口改成native方法的接口,修改后的代码如下:

[cpp] view plain copy
  1. #include <jni.h>  
  2. #include "com_android_servicescreencap_ScreenCap.h"  
  3.   
  4. #include <errno.h>  
  5. #include <unistd.h>  
  6. #include <stdio.h>  
  7. #include <fcntl.h>  
  8.   
  9. #include <linux/fb.h>  
  10. #include <sys/ioctl.h>  
  11. #include <sys/mman.h>  
  12.   
  13. #include <binder/ProcessState.h>  
  14.   
  15. #include <gui/SurfaceComposerClient.h>  
  16. #include <gui/ISurfaceComposer.h>  
  17.   
  18. #include <ui/PixelFormat.h>  
  19.   
  20. #include <SkImageEncoder.h>  
  21. #include <SkBitmap.h>  
  22. #include <SkData.h>  
  23. #include <SkStream.h>  
  24.   
  25. #include <android/log.h>  
  26. #define LOG_TAG "ServiceScreenCap"  
  27. #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)  
  28. #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)  
  29. #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)  
  30.   
  31. using namespace android;  
  32.   
  33. static uint32_t DEFAULT_DISPLAY_ID = ISurfaceComposer::eDisplayIdMain;  
  34.   
  35.   
  36. static status_t vinfoToPixelFormat(const fb_var_screeninfo& vinfo,  
  37.         uint32_t* bytespp, uint32_t* f)  
  38. {  
  39.   
  40.     switch (vinfo.bits_per_pixel) {  
  41.         case 16:  
  42.             *f = PIXEL_FORMAT_RGB_565;  
  43.             *bytespp = 2;  
  44.             break;  
  45.         case 24:  
  46.             *f = PIXEL_FORMAT_RGB_888;  
  47.             *bytespp = 3;  
  48.             break;  
  49.         case 32:  
  50.             // TODO: do better decoding of vinfo here  
  51.             *f = PIXEL_FORMAT_RGBX_8888;  
  52.             *bytespp = 4;  
  53.             break;  
  54.         default:  
  55.             return BAD_VALUE;  
  56.     }  
  57.     return NO_ERROR;  
  58. }  
  59.   
  60. static SkBitmap::Config flinger2skia(PixelFormat f)  
  61. {  
  62.     switch (f) {  
  63.         case PIXEL_FORMAT_RGB_565:  
  64.             return SkBitmap::kRGB_565_Config;  
  65.         default:  
  66.             return SkBitmap::kARGB_8888_Config;  
  67.     }  
  68. }  
  69.   
  70.   
  71. /* 
  72.  * Class:     com_android_servicescreencap_ScreenCap 
  73.  * Method:    currentscreen 
  74.  * Signature: (Ljava/lang/String;)I 
  75.  */  
  76. JNIEXPORT jint  
  77. JNICALL ScreenCap_currentscreen(JNIEnv *env,  
  78.         jclass clazz, jstring jpath) {  
  79.   
  80.     ProcessState::self()->startThreadPool();  
  81.   
  82.     int32_t displayId = DEFAULT_DISPLAY_ID;  
  83.   
  84.     const char* fn = env->GetStringUTFChars(jpath,NULL);  
  85.     LOGI("=====jpath:%s \n", fn);  
  86.   
  87.     if (fn == NULL) {  
  88.         LOGE("=====path = %s \n =====err: %s \n",fn, strerror(errno));  
  89.         return 1;  
  90.     }  
  91.     int fd = -1;  
  92.     fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0664);  
  93.     LOGI("=====after open ,fd:%d \n",fd);  
  94.     if (fd == -1) {  
  95.         LOGE("=====err: %s \n", strerror(errno));  
  96.         return 2;  
  97.     }  
  98.   
  99.     void const* mapbase = MAP_FAILED;  
  100.     ssize_t mapsize = -1;  
  101.   
  102.     void const* base = 0;  
  103.     uint32_t w, s, h, f;  
  104.     size_t size = 0;  
  105.   
  106.     ScreenshotClient screenshot;  
  107.     sp < IBinder > display = SurfaceComposerClient::getBuiltInDisplay(displayId);  
  108.     if (display != NULL && screenshot.update(display) == NO_ERROR) {  
  109.         base = screenshot.getPixels();  
  110.         w = screenshot.getWidth();  
  111.         h = screenshot.getHeight();  
  112.         s = screenshot.getStride();  
  113.         f = screenshot.getFormat();  
  114.         size = screenshot.getSize();  
  115.     } else {  
  116.         const char* fbpath = "/dev/graphics/fb0";  
  117.         int fb = open(fbpath, O_RDONLY);  
  118.         LOGI("=====read framebuffer, fb:%d \n", fb);  
  119.         if (fb >= 0) {  
  120.             struct fb_var_screeninfo vinfo;  
  121.             if (ioctl(fb, FBIOGET_VSCREENINFO, &vinfo) == 0) {  
  122.                 uint32_t bytespp;  
  123.                 if (vinfoToPixelFormat(vinfo, &bytespp, &f) == NO_ERROR) {  
  124.                     size_t offset = (vinfo.xoffset + vinfo.yoffset * vinfo.xres)  
  125.                             * bytespp;  
  126.                     w = vinfo.xres;  
  127.                     h = vinfo.yres;  
  128.                     s = vinfo.xres;  
  129.                     size = w * h * bytespp;  
  130.                     mapsize = offset + size;  
  131.                     mapbase = mmap(0, mapsize, PROT_READ, MAP_PRIVATE, fb, 0);  
  132.                     if (mapbase != MAP_FAILED) {  
  133.                         base = (void const *) ((char const *) mapbase + offset);  
  134.                     }  
  135.                 }  
  136.             }  
  137.             close(fb);  
  138.         }else{  
  139.             LOGE("=====fb = %d , err: %s \n",fb, strerror(errno));  
  140.             return 3;  
  141.         }  
  142.     }  
  143.   
  144.     if (base) {  
  145.         SkBitmap b;  
  146.         b.setConfig(flinger2skia(f), w, h, s * bytesPerPixel(f));  
  147.         b.setPixels((void*) base);  
  148.         SkDynamicMemoryWStream stream;  
  149.         SkImageEncoder::EncodeStream(&stream, b, SkImageEncoder::kPNG_Type,  
  150.                 SkImageEncoder::kDefaultQuality);  
  151.         SkData* streamData = stream.copyToData();  
  152.         write(fd, streamData->data(), streamData->size());  
  153.         streamData->unref();  
  154.     }  
  155.     close (fd);  
  156.     if (mapbase != MAP_FAILED) {  
  157.         munmap((void *) mapbase, mapsize);  
  158.     }  
  159.     return 0;  
  160. }  
  161.   
  162.   
  163. static JNINativeMethod methods[] = {  
  164.         {"currentscreen","(Ljava/lang/String;)I",(void*)ScreenCap_currentscreen},  
  165. };  
  166.   
  167. static int registerNativeMethods(JNIEnv* env,const char* classname,JNINativeMethod* gMethods,int numMethods ){  
  168.     jclass clazz;  
  169.     clazz = env->FindClass(classname);  
  170.     if(clazz == NULL){  
  171.         return JNI_FALSE;  
  172.     }  
  173.     if(env->RegisterNatives(clazz,gMethods,numMethods) <0 ){  
  174.         return JNI_FALSE;  
  175.     }  
  176.     return JNI_TRUE;  
  177. }  
  178.   
  179.   
  180.   
  181. static int registerNatives(JNIEnv* env)  
  182. {  
  183.   if (!registerNativeMethods(env, "com/android/servicescreencap/ScreenCap",  
  184.                  methods, sizeof(methods) / sizeof(methods[0]))) {  
  185.     return JNI_FALSE;  
  186.   }  
  187.   
  188.   return JNI_TRUE;  
  189. }  
  190.   
  191.   
  192. typedef union {  
  193.     JNIEnv* env;  
  194.     void* venv;  
  195. } UnionJNIEnvToVoid;  
  196.   
  197. jint JNI_OnLoad(JavaVM* vm, void* reserved)  
  198. {  
  199.     UnionJNIEnvToVoid uenv;  
  200.     uenv.venv = NULL;  
  201.     jint result = -1;  
  202.     JNIEnv* env = NULL;  
  203.   
  204.   
  205.     if (vm->GetEnv(&uenv.venv, JNI_VERSION_1_6) != JNI_OK) {  
  206.          return result;  
  207.     }  
  208.     env = uenv.env;  
  209.   
  210.     if (registerNatives(env) != JNI_TRUE) {  
  211.          return result;  
  212.     }  
  213.   
  214.     result = JNI_VERSION_1_6;  
  215.   
  216.     return result;  
  217. }  

        修改后的代码入口是ScreenCap_currentscreen,该方法接收一个地址,将当前屏幕截取到该地址下。代码中加入了日志,可以打印native层的错误信息。


此处需采用动态方式注册本地方法,静态方式好像会有问题。



参考链接: 

Android: How to Capture Screen in Gingerbread(2.3中实现截屏)

Android: How to Capture Screen in Gingerbread(2.3中实现截屏)(续)

Android系统截屏的实现(附代码)


原文地址: http://blog.csdn.net/lingfengxu/article/details/43487793

原创粉丝点击