Android Recovery Ui 分析

简介:
Android   recovery和android本质上是两个独立的rootfs, 仅仅是recovery这个rootfs存在的意义就是为android这个rootfs服务,因此被解释为Android系统的一部分。

recovery作为一个简单的rootfs, 提供了很有限的几个功能,仅仅包括了几个简单的库。UI的显示採用的是直接刷framebuffer的形式。作为android framework及app层的码农。对这样的形式相对陌生,特抽点时间梳理了一番。 首先,浏览一下reocvery的main函数代码中UI相关的语句

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
main( int  argc, char  **argv) {
 
     ......
 
     Device* device = make_device();       
     ui = device->GetUI();
     gCurrentUI = ui;
 
     ui->Init();
     ui->SetLocale(locale);
     ui->SetBackground(RecoveryUI::NONE);
     if  (show_text) ui->ShowText( true );
 
     ......
 
     if  (status != INSTALL_SUCCESS || ui->IsTextVisible()) {
         prompt_and_wait(device, status);
     }
 
     ......
}
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的主界面,即一个选择菜单


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
void  ScreenRecoveryUI::Init()
{
     gr_init();
 
     gr_font_size(&char_width, &char_height);
 
     text_col = text_row = 0 ;
     text_rows = gr_fb_height() / char_height;
     if  (text_rows > kMaxRows) text_rows = kMaxRows;
     text_top = 1 ;
 
     text_cols = gr_fb_width() / char_width;
     if  (text_cols > kMaxCols - 1 ) text_cols = kMaxCols - 1 ;
 
     LoadBitmap( "icon_installing" , &backgroundIcon[INSTALLING_UPDATE]);
     backgroundIcon[ERASING] = backgroundIcon[INSTALLING_UPDATE];
     LoadBitmap( "icon_error" , &backgroundIcon[ERROR]);
     backgroundIcon[NO_COMMAND] = backgroundIcon[ERROR];
 
     LoadBitmap( "progress_empty" , &progressBarEmpty);
     LoadBitmap( "progress_fill" , &progressBarFill);
 
     LoadLocalizedBitmap( "installing_text" , &backgroundText[INSTALLING_UPDATE]);
     LoadLocalizedBitmap( "erasing_text" , &backgroundText[ERASING]);
     LoadLocalizedBitmap( "no_command_text" , &backgroundText[NO_COMMAND]);
     LoadLocalizedBitmap( "error_text" , &backgroundText[ERROR]);
 
     int  i;
 
     progressBarIndeterminate = (gr_surface*)malloc(indeterminate_frames *
                                                     sizeof(gr_surface));
     for  (i = 0 ; i  0 ) {
         installationOverlay = (gr_surface*)malloc(installing_frames *
                                                    sizeof(gr_surface));
         for  (i = 0 ; i
<p style= "margin-top:0px; margin-bottom:0px; padding:5px" >
</p>
<p style= "margin-top:0px; margin-bottom:0px; padding:5px" > </p>
<p style= "margin-top:0px; margin-bottom:0px; padding:5px" > 1 、gr_init()  初始化图形设备,分配Pixelflinger库渲染的内存</p>
<p style= "margin-top:0px; margin-bottom:0px; padding:5px" > 2 、gr_font_size()  将字体相应的surface长宽赋值给char_width和char_height</p>
 
3 、LoadBitmap()  将png生成surface, 每一个png图片相应一个surface, 全部surface存放在一个数组中
4 、LoadLocalizedBitmap()  将区域文字所在的图片中的text信息依据当前的locale提取出来,生成相应的surface, 所以
    surface也存放在一个数组中
6 、pthread_create(&progress_t, NULL, progress_thread, NULL)
创建一个线程,该线程的任务是一个死循环。在该循环中不停
    地检測currentIcon以及progressBarType来决定是不是要更新进度条。
7 、调用RecoveryUI的Init(),初始化输入事件处理。
 
<p style= "margin-top:0px; margin-bottom:0px; padding:5px" > </p>
 
<pre class = "brush:java;" > void  ScreenRecoveryUI::SetLocale( const  char * locale) {
     if  (locale) {
         char * lang = strdup(locale);
         for  ( char * p = lang; *p; ++p) {
             if  (*p == '_' ) {
                 *p = '\0' ;
                 break ;
             }
         }
 
         // A bit cheesy: keep an explicit list of supported languages
         // that are RTL.
         if  (strcmp(lang, "ar" ) == 0  ||   // Arabic
             strcmp(lang, "fa" ) == 0  ||   // Persian (Farsi)
             strcmp(lang, "he" ) == 0  ||   // Hebrew (new language code)
             strcmp(lang, "iw" ) == 0  ||   // Hebrew (old language code)
             strcmp(lang, "ur" ) == 0 ) {   // Urdu
             rtl_locale = true ;
         }
         free(lang);
     }
}
 
</pre><br> ScreenRecoveryUI类的SetLocale, 该函数依据locale推断所用的字体是否属于阿拉伯语系,阿拉伯语的书写习惯是从右到左,假设是阿拉伯语系的话,就设置一个标志。后面依据这个标志决定从右到左显示文字或进度条。SetLocale的參数locale赋值逻辑是这种,先从command文件里读取, command文件里设置locale的命令如 "--<em>locale</em>=zh_CN“,假设没有传入locale,初始化过程中会尝试从/cache/recovery/last_locale中读取locale, 假设该文件也没有,则locale不会被赋值,就默认用English.  <pre class=" brush:java;"> void  ScreenRecoveryUI::SetBackground(Icon icon)
{
     pthread_mutex_lock(&updateMutex);
 
     // Adjust the offset to account for the positioning of the
     // base image on the screen.
     if  (backgroundIcon[icon] != NULL) {
         gr_surface bg = backgroundIcon[icon];
         gr_surface text = backgroundText[icon];
         overlay_offset_x = install_overlay_offset_x + (gr_fb_width() - gr_get_width(bg)) / 2 ;
         overlay_offset_y = install_overlay_offset_y +
             (gr_fb_height() - (gr_get_height(bg) + gr_get_height(text) + 40 )) / 2 ;
     }
 
     currentIcon = icon;
     update_screen_locked();
 
     pthread_mutex_unlock(&updateMutex);
}
 
</pre> SetBackground函数比較简洁,关键部分在update_screen_locked。以下我们重点分析一下。<p></p><p> update_screen_locked和update_progress_locked是recovery的UI部分的关键函数,update_screen_locked用来更新背景, update_progress_locked用来更新进度条。由于显示的画面会一直在更新,所以这两个函数会在不同的地方被重复调用<br></p><pre class = "brush:java;" > void  ScreenRecoveryUI::update_screen_locked()
{
     draw_screen_locked();
     gr_flip();
}
</pre> update_screen_locked包括两个操作。一是更新screen, 二是切换前后buffer。 <pre class = "brush:java;" > void  ScreenRecoveryUI::draw_screen_locked()
{
     draw_background_locked(currentIcon);
     draw_progress_locked();
 
     if  (show_text) {
         SetColor(TEXT_FILL);
         gr_fill( 0 , 0 , gr_fb_width(), gr_fb_height());
 
         int  y = 0 ;
         int  i = 0 ;
         if  (show_menu) {
             SetColor(HEADER);
 
             for  (; i  y+ 2  && count
 
 
  
 
 
draw_background_locked函数的实现代码中又出现了几个以gr_开头的函数,以gr_开头的函数来自minui库。minui库的代码在recovery源代码下的minui文件夹下。minui提供的接口实现了图形的描绘以及固定大小的文字显示。
 
 
 
gr_color(unsigned char  r, unsigned char  g, unsigned char  b, unsigned char  a);  /* 设置字体颜色 */ 
gr_fill( int  x, int  y, int  w, int  h);  /* 填充矩形区域,參数分别代表起始坐标、矩形区域大小 */ 
gr_blit(gr_surface source, int  sx, int  sy, int  w, int  h, int  dx, int  dy);  /* 填充由source指定的图片 */ 
 
 
 
draw_background_locked函数先将整个渲染buffer填充为黑色,然后计算背景surface的长宽。文字surface的长宽。再结合fb的长宽计算出背景surface以及文字surface显示的坐标,有长宽和坐标就能够调用Pixelflinger的接口在渲染buffer上进行渲染。
  
<pre class = "brush:java;" > void  ScreenRecoveryUI::draw_progress_locked()
{
     if  (currentIcon == ERROR) return ;
 
     if  (currentIcon == INSTALLING_UPDATE || currentIcon == ERASING) {
         draw_install_overlay_locked(installingFrame);
     }
 
     if  (progressBarType != EMPTY) {
         int  iconHeight = gr_get_height(backgroundIcon[INSTALLING_UPDATE]);
         int  width = gr_get_width(progressBarEmpty);
         int  height = gr_get_height(progressBarEmpty);
 
         int  dx = (gr_fb_width() - width)/ 2 ;
         int  dy = ( 3 *gr_fb_height() + iconHeight - 2 *height)/ 4 ;
 
         // Erase behind the progress bar (in case this was a progress-only update)
         gr_color( 0 , 0 , 0 , 255 );
         gr_fill(dx, dy, width, height);
 
         if  (progressBarType == DETERMINATE) {
             float  p = progressScopeStart + progress * progressScopeSize;
             int  pos = ( int ) (p * width);
 
             if  (rtl_locale) {
                 // Fill the progress bar from right to left.
                 if  (pos > 0 ) {
                     gr_blit(progressBarFill, width-pos, 0 , pos, height, dx+width-pos, dy);
                 }
                 if  (pos  0 ) {
                     gr_blit(progressBarFill, 0 , 0 , pos, height, dx, dy);
                 }
                 if  (pos
 
 
  
draw_progress_locked函数的原理与 update_screen_locked函数类似, 终于是将进度条的surface输出到渲染buffer,
recovery中各个场景的画面,就是由背景、文字、进度条的重叠,不同的是所用的surface 以及surface的坐标。<p></p><p>
 
 
  
 
recovery main函数中的UI代码基本上已经分析过了。最后一点主菜单的显示,就是通过上面介绍的这些接口将文字图片显示出来。因此就不再多讲。总的来说,recovery的UI显示部分难度不大,应用层调用minui库实现了图形的描绘以及固定大小的文字显示,minui库调用了Pixelflinger库来进行渲染。</p><p>
  
附上minui部分接口的说明。供參考
</p><pre class = "brush:java;" > 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(unsigned char  r, unsigned char  g, unsigned char  b, unsigned char  a);  /* 设置字体颜色 */ 
void  gr_fill( int  x, int  y, int  w, int  h);  /* 填充矩形区域,參数分别代表起始坐标、矩形区域大小 */ 
int  gr_text( int  x, int  y, const  char  *s);  /* 显示字符串 */ 
int  gr_measure( const  char  *s);             /* 获取字符串在默认字库中占用的像素长度 */ 
void  gr_font_size( int  *x, int  *y);         /* 获取当前字库一个字符所占的长宽 */ 
   
void  gr_blit(gr_surface source, int  sx, int  sy, int  w, int  h, int  dx, int  dy);  /* 填充由source指定的图片 */ 
unsigned int  gr_get_width(gr_surface surface);   /* 获取图片宽度 */ 
unsigned int  gr_get_height(gr_surface surface);  /* 获取图片高度 */ 
/* 依据图片创建显示资源数据,name为图片在mk文件指定的相对路径 */ 
int  res_create_surface( const  char * name, gr_surface* pSurface); 
void  res_free_surface(gr_surface surface);       /* 释放资源数据 */ 
</pre><div><br></div></pre></pre> 本文转自mfrbuaa博客园博客,原文链接:http://www.cnblogs.com/mfrbuaa/p/5371988.html,如需转载请自行联系原作者
相关文章
|
20天前
|
安全 Shell Android开发
Android系统 init.rc sys/class系统节点写不进解决方案和原理分析
Android系统 init.rc sys/class系统节点写不进解决方案和原理分析
34 0
|
20天前
|
安全 Android开发
Android13 Root实现和原理分析
Android13 Root实现和原理分析
50 0
|
20天前
|
Java Android开发
Android系统 获取用户最后操作时间回调实现和原理分析
Android系统 获取用户最后操作时间回调实现和原理分析
23 0
|
20天前
|
存储 Java Android开发
Android系统 设置第三方应用为默认Launcher实现和原理分析
Android系统 设置第三方应用为默认Launcher实现和原理分析
47 0
|
4天前
|
存储 Android开发
android launcher总体分析
android launcher总体分析
10 1
|
6天前
|
前端开发 Java Android开发
Android UI底层绘制原理
Android UI底层绘制原理
11 0
|
6天前
|
编解码 缓存 安全
Android SELinux 参数语法介绍及基础分析
Android SELinux 参数语法介绍及基础分析
10 0
|
20天前
|
存储 安全 文件存储
Android OTA升级后输入法异常和应用丢失的分析
Android OTA升级后输入法异常和应用丢失的分析
20 1
|
20天前
|
存储 Java Shell
Android系统 实现低内存白名单防LMK原理分析
Android系统 实现低内存白名单防LMK原理分析
35 0
|
20天前
|
存储 Java Linux
Android系统获取event事件回调等几种实现和原理分析
Android系统获取event事件回调等几种实现和原理分析
31 0