在 Android Framework 中增加 Native 库

OS: Android 4.4.2

在framework层使用Native lib和在application层的使用有所不同,主要集中在如何正确书写Android.mk和各种依赖关系,要比直接ndk-build麻烦一些。

场景: 在SystemUI包中添加一个Native库,假设名字为libxx.so

处理步骤:

  1. 进到frameworks/base/packages/SystemUI下创建JNI文件夹,这里存放所有libxx.so需要的文件。

    假设源文件名为xx.c。建立Android.mk文件,文件内容如下:

    LOCAL_PATH := $(call my-dir)
    include $(CLEAR_VARS)
    
    LOCAL_LDFLAGS := -llog -ljnigraphics
    LOCAL_MODULE    := libxx
    LOCAL_SRC_FILES := xx.c
    LOCAL_CFLAGS    =  -ffast-math -O3 -funroll-loops
    
    ifeq ($(TARGET_ARCH), arm)
            LOCAL_SDK_VERSION := 9
    endif
    
    ifeq ($(TARGET_ARCH), x86)
            LOCAL_SDK_VERSION := 9
    endif
    
    ifeq ($(TARGET_ARCH), mips)
            LOCAL_SDK_VERSION := 9
    endif
    
    include $(BUILD_SHARED_LIBRARY)
    

    注意,如果要将libxx.so文件编译到system image,需要修改LOCAL_MODULE_TAGS(如果有),这个值必须为user,而不是samples,或者干脆去掉这个变量 。因为如果没有指定LOCAL_MODULE_TAGS,该项默认为user

  2. 为了能在编译SystemUI的时候自动编译libxx.so,需要在SystemUI的Android.mk文件中加入如下内容:

    ifneq (,$(TARGET_BUILD_APPS))
      LOCAL_JNI_SHARED_LIBRARIES := libxx
    else
      LOCAL_REQUIRED_MODULES := libxx
    endif
    

    Android对上面语句的解释如下:

    If this is an unbundled build (to install seprately) then include
    the libraries in the APK, otherwise just put them in /system/lib and
    leave them out of the APK
    
  3. 可以用make systemimage和mm SystemUI来测试效果。

Android 获取历史 Application 的截图

Android Framework中的WindowManagerService提供了获取历史Application截图的方法getTaskTopThumbnail,下面演示的只获取了最近一个app的Thumbnail。需要注意的是framework只提供了缩略图,没有提供完整的截图,但是我们可以通过在WindowManagerService中修改getTaskTopThumbnail来提供完整的Application截图。 另:这个方法只能截取Window属性为TYPE_APPLICATION的窗口,对于像属性为TYPE_KEYGUARD等窗口不能使用这个方法,可以通过Surface来截图。 这种方法的意义在于: 你可以获取一个处于pause或stop(可能被另一个窗口遮挡)状态的avtivity的截图,而使用Surface截图只能获取当前显示的画面(也就是framebuffer中的内容)。

 ActivityManager am = (ActivityManager) getContext().getSystemService(
                Context.ACTIVITY_SERVICE);

    private Bitmap takeScreenshot() {
        Bitmap bmp = null;

        final List<ActivityManager.RecentTaskInfo> recentTasks = am.getRecentTasksForUser(
                1, ActivityManager.RECENT_IGNORE_UNAVAILABLE,
                UserHandle.CURRENT.getIdentifier());
        if (recentTasks.size() > 0) {
            ActivityManager.RecentTaskInfo recentInfo = recentTasks.get(0);
            bmp = am.getTaskTopThumbnail(recentInfo.persistentId);
        }

        return bmp;
    }

ref: frameworks/base/services/java/com/android/server/wm/WindowManagerService.java

使用 jpeglib 压缩图片

#include <jpeglib.h>
void writeJPEG(unsigned char* pixs, int  width, int height, char* file) {
    struct jpeg_compress_struct jcs;
    struct jpeg_error_mgr jem;
    jcs.err = jpeg_std_error(&jem);
    jpeg_create_compress(&jcs);
    FILE* fp = fopen(file, "wb");
    if(fp == NULL) {
        perror("writeJPEG");
        return;
    }

    jpeg_stdio_dest(&jcs, fp);
    jcs.image_width = width;
    jcs.image_height = height;
    jcs.input_components = 3; //RGB
    jcs.in_color_space = JCS_RGB;
    jpeg_set_defaults(&jcs);
    jpeg_set_quality(&jcs, 100, TRUE); //输出图片质量

    jpeg_start_compress(&jcs, TRUE);
    JSAMPROW row_pointer[1];
    int row_stride;
    row_stride = jcs.image_width * 3; //RGB

    while(jcs.next_scanline < jcs.image_height) {
        row_pointer[0] = &pixs[jcs.next_scanline * row_stride];
        jpeg_write_scanlines(&jcs, row_pointer, 1);
    }
    
    jpeg_finish_compress(&jcs);
    jpeg_destroy_compress(&jcs);
    fclose(fp);
}

Android NDK 中的 LOCAL_LDLIBS and LOCAL_SHARED_LIBRARIES

  • LOCAL_LDLIBS : 不会重新编译所依赖的库
  • LOCAL_SHARED_LIBRARIES : 如果所依赖的库代码有更新,会重新编译该依赖库

Git RPC faild 解决方法

在git pull一个很大的库时发生了如下的错误:

macbookpro:Experiments sss$ git pull
remote: Counting objects: 3466, done.
remote: Compressing objects: 100% (2172/2172), done.
error: RPC failed; result=56, HTTP code = 200B | 17.00 KiB/s    
fatal: The remote end hung up unexpectedly
fatal: early EOF
fatal: index-pack failed

解决方法 增加git的post缓存大小:

git config --global http.postBuffer 500000000 #增加到约500MB