之前讲过Android中recovery的基本知识。
在工作中,需要做的经常是对标准recovery做一些定制化,所以这篇文章,记录下这段时间的一些心得:
在源码根目录下自行make otapackage 会生成升级包,两次编译后包用下面工具:
./build/tools/releasetools/ota_from_target_files -n -i <旧包> <新包> <差分包名> ,可以制作增量升级包。这里必须用中间生成的包才行。
改进方法:
前面说的可以自己写一个简单的Linux脚本,把修改后的升级脚本和文件进行打包签名,这样可以比源码中直接make otapackage效率要高一些,同时也更灵活。
有时你这个版本只是多了一两个APK,就可以在脚本用mount挂在system分区->package_extract_file直接将APK解压到制定的目录。
例如,现在这个版本是想要减掉上一个版本的一个system/app/下的一个APK,如果我们可以自己给脚本解析器增加一个delete的命令。
例如,增加设置命令的接口来给fastboot发送命令,让recovery系统去告诉fastboot去完成一些只能在fastboot中完成的工作。遇到两次需要这样做:(1)当时,有一个工作是要求在recovery中增加重新划分分区的功能,因为这个工作只能在fastboot中完成,所以我就是这样做的。
(2)还有一次是恢复出厂设置后,有些fastboot中的env需要重新设置,才能算是真正的恢复出厂,就也是让recovery去告诉fastboot重新设置下env。
这个基本每次都要做的,如果只是使用安卓原本的recovery来做的话,就只要去源码下bootable/recovery/res/images把图片换换,然后修改下位置和一些简单的细节就可以了。
不过了解下它的实现也好:
Recovery UI 在recovery源代码recovery.cpp中main有
Device* device = make_device();
ui = device->GetUI();
gCurrentUI = ui;
ui->Init();
ui->SetLocale(locale);
ui->SetBackground(RecoveryUI::NONE);
if(show_text) ui->ShowText(true);
(1)首先新建了一个Device类的对象, Device类封装了一些操作,包括UI的操作
(2)调用Device类的GetUI()返回一个DefaultUI对象,recovery中涉及到三个UI类,三个类之间为继承关系,分别为DefaultUI、 ScreenRecoveryUI、RecoveryUI
(3)调用DefaultUI类的Init(), DefaultUI类没有Init()方法,因此将调用它的父类ScreenRecoveryUI的Init()
(4)同理,调用ScreenRecoveryUI类的SetLocale()来标识几个比较特别的区域
(5)同理,调用ScreenRecoveryUI类的SetBackground()设置初始状态的背景图
(6)显示recovery的主界面,即一个选择菜单
graphics.c给出一些接口,这些接口会调用Pixelflinger的源代码给出的接口,以下是部分接口。
Pixelflinger库来进行渲染。 附上minui部分接口的说明,供参考
int gr_init(void); /* 初始化图形显示,主要是打开设备、分配内存、初始化一些参数 */
void gr_exit(void); /* 注销图形显示,关闭设备并释放内存 */
int gr_fb_width(void); /* 获取屏幕的宽度 */
int gr_fb_height(void); /* 获取屏幕的高度 */
gr_pixel *gr_fb_data(void); /* 获取显示数据缓存的地址 */
void gr_flip(void); /* 刷新显示内容 */
void gr_fb_blank(bool blank); /* 清屏 */
void gr_color(unsignedcharr, unsignedcharg, unsignedcharb, unsignedchara); /* 设置颜色 */
void gr_fill(intx,inty,intw,inth); /* 填充矩形区域,参数分别代表起始坐标、矩形区域大小 */
int gr_text(intx,inty,constchar*s); /* 显示字符串 */
int gr_measure(constchar*s); /* 获取字符串在默认字库中占用的像素长度 */
void gr_font_size(int*x,int*y); /* 获取当前字库一个字符所占的长宽 */
void gr_blit(gr_surface source,intsx,intsy,intw,inth,intdx,intdy); /* 填充由source指定的图片 */
unsigned int gr_get_width(gr_surface surface); /* 获取图片宽度 */
Unsigned int gr_get_height(gr_surface surface); /* 获取图片高度 */
/* 根据图片创建显示资源数据,name为图片在mk文件指定的相对路径 */
int res_create_surface(constchar* name, gr_surface* pSurface);
void res_free_surface(gr_surface surface); /* 释放资源数据 */
screen_ui.cpp给出了设置的流程,跟踪这个代码可以知道显示的方法,要注意的是,显示文字的界面必须在showtext为TRUE的时候才会显示,所以用此方法来实现进程界面和选择界面的变换。
字体比较麻烦吧,我记得我修改字体的时候,觉得很麻烦,不清楚有没有比较好的方法。
我的方法:先在graphics.c文件中修改字体头文件。然后:
(1)在recovery/miniui中有制作头文件的源码mkfont.c,在/recovery/font中有字体图片,需用gimp工具得到mkfont.c编译所要的结构体。注意gimp输出.c文件时,全部选项都不要选。
(2)制作的字体文件.h存在的不足是底色和字体色的问题。修改mkfont.c文件让其相反输出即可。
(3)在graphics.c文件中的static void gr_init_font(void)//字体函数是对字体的初始化,在这里是判断字体头文件中的字体,根据阈值0x80来选择透明度,源码默认是255,所以无论怎么调色,最后都是黑色
(4)对颜色的修改就要先修改第3点所述部分,再在int gr_text(int x, int y, const char *s)增加想要的字体颜色即可 ,如:gr_color(255,255,255,252);
有时,机器给不同国家,recovery也就要求显示不同语言,那就用这个函数:
SetLocale, 该函数根据locale判断所用的字体是否属于阿拉伯语系,阿拉伯语的书写习惯是从右到左,如果是阿拉伯语系的话,就设置一个标志,后面根据这个标志决定从右到左显示文字或进度条。 SetLocale的参数locale赋值逻辑是这样的,先从command文件中读取, command文件中设置locale的命令如”–locale=zh_CN“,如果没有传入locale,初始化过程中会尝试从/cache/recovery/last_locale中读取locale, 如果该文件也没有,则locale不会被赋值,就默认用English.
这个其实也是在setting中设置的,会设置为env保持在fastboot中。(我用的方案是这样,不清楚是不是安卓原本的)