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,如需转载请自行联系原作者
相关文章
|
25天前
|
开发框架 前端开发 Android开发
Flutter 与原生模块(Android 和 iOS)之间的通信机制,包括方法调用、事件传递等,分析了通信的必要性、主要方式、数据传递、性能优化及错误处理,并通过实际案例展示了其应用效果,展望了未来的发展趋势
本文深入探讨了 Flutter 与原生模块(Android 和 iOS)之间的通信机制,包括方法调用、事件传递等,分析了通信的必要性、主要方式、数据传递、性能优化及错误处理,并通过实际案例展示了其应用效果,展望了未来的发展趋势。这对于实现高效的跨平台移动应用开发具有重要指导意义。
103 4
|
1月前
|
搜索推荐 Android开发 开发者
探索安卓开发中的自定义视图:打造个性化UI组件
【10月更文挑战第39天】在安卓开发的世界中,自定义视图是实现独特界面设计的关键。本文将引导你理解自定义视图的概念、创建流程,以及如何通过它们增强应用的用户体验。我们将从基础出发,逐步深入,最终让你能够自信地设计和实现专属的UI组件。
|
1月前
|
安全 Android开发 数据安全/隐私保护
深入探讨iOS与Android系统安全性对比分析
在移动操作系统领域,iOS和Android无疑是两大巨头。本文从技术角度出发,对这两个系统的架构、安全机制以及用户隐私保护等方面进行了详细的比较分析。通过深入探讨,我们旨在揭示两个系统在安全性方面的差异,并为用户提供一些实用的安全建议。
|
17天前
|
Java 开发工具 Android开发
安卓与iOS开发环境对比分析
在移动应用开发的广阔天地中,安卓和iOS两大平台各自占据半壁江山。本文深入探讨了这两个平台的开发环境,从编程语言、开发工具到用户界面设计等多个角度进行比较。通过实际案例分析和代码示例,我们旨在为开发者提供一个清晰的指南,帮助他们根据项目需求和个人偏好做出明智的选择。无论你是初涉移动开发领域的新手,还是寻求跨平台解决方案的资深开发者,这篇文章都将为你提供宝贵的信息和启示。
24 8
|
14天前
|
XML 搜索推荐 前端开发
安卓开发中的自定义视图:打造个性化UI组件
在安卓应用开发中,自定义视图是一种强大的工具,它允许开发者创造独一无二的用户界面元素,从而提升应用的外观和用户体验。本文将通过一个简单的自定义视图示例,引导你了解如何在安卓项目中实现自定义组件,并探讨其背后的技术原理。我们将从基础的View类讲起,逐步深入到绘图、事件处理以及性能优化等方面。无论你是初学者还是有经验的开发者,这篇文章都将为你提供有价值的见解和技巧。
|
2月前
|
缓存 Java Shell
Android 系统缓存扫描与清理方法分析
Android 系统缓存从原理探索到实现。
75 15
Android 系统缓存扫描与清理方法分析
|
21天前
|
安全 Android开发 数据安全/隐私保护
深入探索Android与iOS系统安全性的对比分析
在当今数字化时代,移动操作系统的安全已成为用户和开发者共同关注的重点。本文旨在通过比较Android与iOS两大主流操作系统在安全性方面的差异,揭示两者在设计理念、权限管理、应用审核机制等方面的不同之处。我们将探讨这些差异如何影响用户的安全体验以及可能带来的风险。
26 1
|
28天前
|
XML 前端开发 Android开发
Android:UI:Drawable:View/ImageView与Drawable
通过本文的介绍,我们详细探讨了Android中Drawable、View和ImageView的使用方法及其相互关系。Drawable作为图像和图形的抽象表示,提供了丰富的子类和自定义能力,使得开发者能够灵活地实现各种UI效果。View和ImageView则通过使用Drawable实现了各种图像和图形的显示需求。希望本文能为您在Android开发中使用Drawable提供有价值的参考和指导。
40 2
|
26天前
|
开发框架 前端开发 Android开发
安卓与iOS开发中的跨平台策略
在移动应用开发的战场上,安卓和iOS两大阵营各据一方。随着技术的演进,跨平台开发框架成为开发者的新宠,旨在实现一次编码、多平台部署的梦想。本文将探讨跨平台开发的优势与挑战,并分享实用的开发技巧,帮助开发者在安卓和iOS的世界中游刃有余。
|
13天前
|
搜索推荐 前端开发 API
探索安卓开发中的自定义视图:打造个性化用户界面
在安卓应用开发的广阔天地中,自定义视图是一块神奇的画布,让开发者能够突破标准控件的限制,绘制出独一无二的用户界面。本文将带你走进自定义视图的世界,从基础概念到实战技巧,逐步揭示如何在安卓平台上创建和运用自定义视图来提升用户体验。无论你是初学者还是有一定经验的开发者,这篇文章都将为你打开新的视野,让你的应用在众多同质化产品中脱颖而出。
39 19