recovery图片资源的再分析

1. 概述

为了进一步分析recovery系统使用资源png文件的过程,我们把相关代码剥离出来,作成小例子进行分析。


2. 正向分析的代码

这个小例子的第一步是能够遍历出png中所有locale的图片信息。


2.1 代码

代码如下:

/*
 * gcc png_example.c -Iinclude -lpng
 *
 * The original code is based android_4.4.2_r2 branch.
 */

#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <png.h>
#include <pixelflinger/pixelflinger.h> // android/system/core/include/pixelfligner/pixelflinger.h

// copy from minui.h
typedef struct {
    int width;
    int height;
    int row_bytes;
    int pixel_bytes;
    unsigned char* data;
} GRSurface;

typedef GRSurface* gr_surface;

#define SURFACE_DATA_ALIGNMENT 8

static gr_surface malloc_surface(size_t data_size) {
    unsigned char* temp = malloc(sizeof(GRSurface) + data_size + SURFACE_DATA_ALIGNMENT);
    if (temp == NULL) return NULL;
    gr_surface surface = (gr_surface) temp;
    surface->data = temp + sizeof(GRSurface) +
        (SURFACE_DATA_ALIGNMENT - (sizeof(GRSurface) % SURFACE_DATA_ALIGNMENT));
    return surface;
}


static int open_png(const char* file_name, png_structp* png_ptr, png_infop* info_ptr,
                    png_uint_32* width, png_uint_32* height, png_byte* channels) {
    unsigned char header[8];
    int result = 0;

    FILE* fp = fopen(file_name, "rb");
    if (fp == NULL) {
        result = -1;
        goto exit;
    }

    size_t bytesRead = fread(header, 1, sizeof(header), fp);
    if (bytesRead != sizeof(header)) {
        result = -2;
        goto exit;
    }

    if (png_sig_cmp(header, 0, sizeof(header))) {
        result = -3;
        goto exit;
    }

    *png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    if (!*png_ptr) {
        result = -4;
        goto exit;
    }

    *info_ptr = png_create_info_struct(*png_ptr);
    if (!*info_ptr) {
        result = -5;
        goto exit;
    }

    if (setjmp(png_jmpbuf(*png_ptr))) {
        result = -6;
        goto exit;
    }

    png_init_io(*png_ptr, fp);
    png_set_sig_bytes(*png_ptr, sizeof(header));
    png_read_info(*png_ptr, *info_ptr);

    int color_type, bit_depth;
    png_get_IHDR(*png_ptr, *info_ptr, width, height, &bit_depth,
            &color_type, NULL, NULL, NULL);

    *channels = png_get_channels(*png_ptr, *info_ptr);

    if (bit_depth == 8 && *channels == 3 && color_type == PNG_COLOR_TYPE_RGB) {
        // 8-bit RGB images: great, nothing to do.
    } else if (bit_depth <= 8 && *channels == 1 && color_type == PNG_COLOR_TYPE_GRAY) {
        // 1-, 2-, 4-, or 8-bit gray images: expand to 8-bit gray.
        png_set_expand_gray_1_2_4_to_8(*png_ptr);
    } else if (bit_depth <= 8 && *channels == 1 && color_type == PNG_COLOR_TYPE_PALETTE) {
        // paletted images: expand to 8-bit RGB.  Note that we DON'T
        // currently expand the tRNS chunk (if any) to an alpha
        // channel, because minui doesn't support alpha channels in
        // general.
        png_set_palette_to_rgb(*png_ptr);
        *channels = 3;
    } else {
        fprintf(stderr, "minui doesn't support PNG depth %d channels %d color_type %d\n",
                bit_depth, *channels, color_type);
        result = -7;
        goto exit;
    }

    return result;

  exit:
    if (result < 0) {
        png_destroy_read_struct(png_ptr, info_ptr, NULL);
    }
    if (fp != NULL) {
        fclose(fp);
    }

    return result;
}

static int matches_locale(const char* loc, const char* locale) {
    if (locale == NULL) return 0;

    if (strcmp(loc, locale) == 0) return 1;

    // if loc does *not* have an underscore, and it matches the start
    // of locale, and the next character in locale *is* an underscore,
    // that's a match.  For instance, loc == "en" matches locale ==
    // "en_US".

    int i;
    for (i = 0; loc[i] != 0 && loc[i] != '_'; ++i);
    if (loc[i] == '_') return 0;

    return (strncmp(locale, loc, i) == 0 && locale[i] == '_');
}


int read_png(const char* file_name, const char* locale/*,
                                    gr_surface* pSurface*/) {
    gr_surface surface = NULL;
    int result = 0;
    png_structp png_ptr = NULL;
    png_infop info_ptr = NULL;
    png_uint_32 width, height;
    png_byte channels;

    //*pSurface = NULL;

    if (locale == NULL) {
        surface = malloc_surface(0);
        surface->width = 0;
        surface->height = 0;
        surface->row_bytes = 0;
        surface->pixel_bytes = 1;
        goto exit;
    }

    result = open_png(file_name, &png_ptr, &info_ptr, &width, &height, &channels);
    if (result < 0) return result;

    if (channels != 1) {
        result = -7;
        goto exit;
    }

    unsigned char* row = malloc(width);
    png_uint_32 y;
    for (y = 0; y < height; ++y) {
        png_read_row(png_ptr, row, NULL);
        int w = (row[1] << 8) | row[0];
        int h = (row[3] << 8) | row[2];
        int len = row[4];
        char* loc = (char*)row+5;

        printf("  %20s: %s (%d x %d @ %lu)\n", file_name, loc, w, h, y);
        if (y+1+h >= height || matches_locale(loc, locale)) {
            surface = malloc_surface(w*h);
            if (surface == NULL) {
                result = -8;
                goto exit;
            }
            surface->width = w;
            surface->height = h;
            surface->row_bytes = w;
            surface->pixel_bytes = 1;

            int i;
            for (i = 0; i < h; ++i, ++y) {
                png_read_row(png_ptr, row, NULL);
                memcpy(surface->data + i*w, row, w);
            }

            //*pSurface = (gr_surface) surface;
            break;
        } else {
            int i;
            for (i = 0; i < h; ++i, ++y) {
                png_read_row(png_ptr, row, NULL);
            }
        }
    }

exit:
    png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
    if (result < 0 && surface != NULL) free(surface);
    return result;
}

int main(int argc, const char* argv[]) {
	if (argc != 3) {
		printf("Usage: ./a.out file_name locale\n");
		exit(1);
	}

	read_png(argv[1], argv[2]);
	return 0;
}

2.2 运行结果

如果机器上还没有安装png库,则需要先做这个准备工作。其实这一步只需要一条命令即可:

sudo apt-get install libpng-dev

因为是小例子,就没有makefile,直接用gcc命令来完成编译&链接的事情。命令在代码一开始的注释中给出了,下面是运行的效果:

flying-bird@flyingbird:~/examples/png$ gcc png_example.c -Iinclude -lpng
flying-bird@flyingbird:~/examples/png$ ./a.out ./res/installing_text.png en_GB
  ./res/installing_text.png: ar (305 x 38 @ 0)
  ./res/installing_text.png: bg (384 x 71 @ 39)
  ./res/installing_text.png: ca (429 x 71 @ 111)
  ./res/installing_text.png: cs (398 x 38 @ 183)
  ./res/installing_text.png: da (414 x 38 @ 222)
  ./res/installing_text.png: de (382 x 38 @ 261)
  ./res/installing_text.png: el (338 x 71 @ 300)
  ./res/installing_text.png: en_GB (324 x 38 @ 372)
flying-bird@flyingbird:~/examples/png$ ./a.out ./res/installing_text.png en
  ./res/installing_text.png: ar (305 x 38 @ 0)
  ./res/installing_text.png: bg (384 x 71 @ 39)
  ./res/installing_text.png: ca (429 x 71 @ 111)
  ./res/installing_text.png: cs (398 x 38 @ 183)
  ./res/installing_text.png: da (414 x 38 @ 222)
  ./res/installing_text.png: de (382 x 38 @ 261)
  ./res/installing_text.png: el (338 x 71 @ 300)
  ./res/installing_text.png: en_GB (324 x 38 @ 372)
  ./res/installing_text.png: en (324 x 38 @ 411)
flying-bird@flyingbird:~/examples/png$ ./a.out ./res/installing_text.png xy_GB
  ./res/installing_text.png: ar (305 x 38 @ 0)
  ./res/installing_text.png: bg (384 x 71 @ 39)
  ./res/installing_text.png: ca (429 x 71 @ 111)
  ./res/installing_text.png: cs (398 x 38 @ 183)
  ./res/installing_text.png: da (414 x 38 @ 222)
  ./res/installing_text.png: de (382 x 38 @ 261)
  ./res/installing_text.png: el (338 x 71 @ 300)
  ./res/installing_text.png: en_GB (324 x 38 @ 372)
  ./res/installing_text.png: en (324 x 38 @ 411)
  ./res/installing_text.png: es_ES (474 x 38 @ 450)
  ./res/installing_text.png: es (474 x 38 @ 489)
  ./res/installing_text.png: fa (416 x 38 @ 528)
  ./res/installing_text.png: fi (438 x 38 @ 567)
  ./res/installing_text.png: fr (388 x 71 @ 606)
  ./res/installing_text.png: hr (393 x 38 @ 678)
  ./res/installing_text.png: hu (370 x 38 @ 717)
  ./res/installing_text.png: in (397 x 38 @ 756)
  ./res/installing_text.png: it (384 x 71 @ 795)
  ./res/installing_text.png: iw (245 x 38 @ 867)
  ./res/installing_text.png: ja (474 x 71 @ 906)
  ./res/installing_text.png: ko (317 x 38 @ 978)
  ./res/installing_text.png: lt (384 x 38 @ 1017)
  ./res/installing_text.png: lv (385 x 71 @ 1056)
  ./res/installing_text.png: nb (434 x 38 @ 1128)
  ./res/installing_text.png: nl (350 x 38 @ 1167)
  ./res/installing_text.png: pl (394 x 38 @ 1206)
  ./res/installing_text.png: pt_BR (449 x 38 @ 1245)
  ./res/installing_text.png: pt (459 x 38 @ 1284)
  ./res/installing_text.png: ro (472 x 38 @ 1323)
  ./res/installing_text.png: ru (446 x 38 @ 1362)
  ./res/installing_text.png: sk (392 x 71 @ 1401)
  ./res/installing_text.png: sl (439 x 38 @ 1473)
  ./res/installing_text.png: sr (336 x 71 @ 1512)
  ./res/installing_text.png: sv (404 x 38 @ 1584)
  ./res/installing_text.png: th (334 x 38 @ 1623)
  ./res/installing_text.png: tl (419 x 38 @ 1662)
  ./res/installing_text.png: tr (414 x 38 @ 1701)
  ./res/installing_text.png: uk (471 x 38 @ 1740)
  ./res/installing_text.png: vi (462 x 38 @ 1779)
  ./res/installing_text.png: zh_CN (240 x 38 @ 1818)
  ./res/installing_text.png: zh (240 x 38 @ 1857)
  ./res/installing_text.png:  (1 x 1 @ 1896)
flying-bird@flyingbird:~/examples/png$  ./a.out ./res/installing_text.png en_ES
  ./res/installing_text.png: ar (305 x 38 @ 0)
  ./res/installing_text.png: bg (384 x 71 @ 39)
  ./res/installing_text.png: ca (429 x 71 @ 111)
  ./res/installing_text.png: cs (398 x 38 @ 183)
  ./res/installing_text.png: da (414 x 38 @ 222)
  ./res/installing_text.png: de (382 x 38 @ 261)
  ./res/installing_text.png: el (338 x 71 @ 300)
  ./res/installing_text.png: en_GB (324 x 38 @ 372)
  ./res/installing_text.png: en (324 x 38 @ 411)
flying-bird@flyingbird:~/examples/png$ 


2.3 locale匹配规则

locale匹配的规则在Android源代码中有详细的说明(下面代码中间的一段注释),另外通过代码也可以分析出来。为了阅读方便,再copy&paste这个函数:

static int matches_locale(const char* loc, const char* locale) {
    if (locale == NULL) return 0;

    if (strcmp(loc, locale) == 0) return 1;

    // if loc does *not* have an underscore, and it matches the start
    // of locale, and the next character in locale *is* an underscore,
    // that's a match.  For instance, loc == "en" matches locale ==
    // "en_US".

    int i;
    for (i = 0; loc[i] != 0 && loc[i] != '_'; ++i);
    if (loc[i] == '_') return 0;

    return (strncmp(locale, loc, i) == 0 && locale[i] == '_');
}

参数中第一个loc是从png文件中读取出来的字符串,第二个locale是目标字符串。运行时输入了几种参数进行对比运行,其中最后一个en_ES是非法代码,并没有西班牙英语 微笑



3. 图片规则

3.1 每个图片的width & height

进一步地,通过打印信息,可以看出每种locale的图片高度和宽度并不一样。——@ xxx这个数据无需关注,通常仅用于调试用,验证是否地区某个locale的图片at实现放置的位置。(此仅为猜测微笑


3.2 色彩深度等

通过Android的各个分支代码的对比分析,可以看到Android准备支持越来越多的图片格式。至于目前,我们仅关注如下规则:

  1. bit_depth == 8
  2. channels == 1
  3. color_type == PNG_COLOR_TYPE_GRAY



  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
DB2的crash recovery是指在数据库系统发生故障导致系统崩溃时,通过一定的恢复机制来恢复数据库系统的过程。下面是对DB2 crash recovery分析: 1. Crash recovery的原理 DB2的crash recovery是基于日志记录和回放的原理实现的。当DB2发生故障时,系统会将当前的数据库状态记录到日志文件中。在系统恢复时,DB2会分析日志文件中记录的操作,重新执行这些操作,以恢复数据库到故障前的状态。 2. Crash recovery的流程 DB2的crash recovery流程大致分为以下几个步骤: (1)确定crash recovery的起点:DB2系统会检查日志文件,以确定crash recovery的起点。通常情况下,起点是最后一个提交的事务。 (2)执行redo操作:DB2系统会执行redo操作,即重放所有未提交的操作,以使数据库恢复到crash recovery起点之前的状态。 (3)执行undo操作:DB2系统会执行undo操作,即回滚所有已提交的操作,以消除因为crash recovery而造成的数据不一致问题。 (4)更新数据结构:DB2系统会更新数据结构,以反映数据库的最新状态。 (5)完成crash recovery:当DB2系统执行完以上步骤后,crash recovery就完成了。此时,数据库已经恢复到了故障前的状态。 3. Crash recovery的优化 为了加速crash recovery的速度,DB2提供了一些优化技术。例如,DB2可以通过使用多线程来并行执行redo和undo操作,以加快恢复速度。此外,DB2还可以通过启用log buffer来减少日志写入到磁盘的次数,从而提高性能。 总之,DB2的crash recovery是一个重要的恢复机制,它可以保证数据库在发生故障时能够及时恢复到正常状态。了解crash recovery的原理和流程,对于DB2的管理和维护是非常重要的。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值