工作,学习,生活,这里将会有一些记录. 备用域名:http://meisw.51099.com 注册 | 登陆
浏览模式: 标准 | 列表分类:android

反编译与回编译android的framework.jar(其他jar文件也可参考)

最近对android 2.3.3的framework.jar进行了一些反编译和回编译的操作,写下来备忘。

一、framework.jar反编译为smali文件

1、下载smali-1.2.6.jarbaksmali-1.2.6.jar这两个工具(下载地址:http://code.google.com/p/smali/downloads/list

2、将framework.jar中的classes.dex解压出来(好像不解压,直接用framework.jar也行)

3、使用baksmali.jar对classes.dex进行反编译(前提是安装了jdk,并且设置好了环境变量),执行命令:

java -jar baksmali-1.2.6.jar classes.dex -o out/

其中classes.dex是要反编译的文件,out/是要把反编译后的文件存放到的文件夹,如果不是在当前目录下,那么baksmali-1.2.6.jar还要加上路径

这样就OK了,在out文件夹中可以看到一堆扩展名为.smali的文件,用记事本就可以打开它们,从中可以窥到一些信息。但是与.java文件还是有一些不同,我也不太清楚这是什么结构。

二、smali文件回编译为classes.dex

1、一条命令就OK了:java -jar smali-1.2.6.jar out/ -o classes.dex

2、再把编译好的classes.dex放回到framework.jar中就行了(可以使用winrar、winzip之类的工具作为辅助)。

三、framework.jar反编译为.class和.java文件

1、下载以下工具:

(1)dex2jar(http://code.google.com/p/dex2jar/

(2)xjad(http://www.skycn.com/soft/41898.html)或jd-gui(http://java.decompiler.free.fr/?q=jdgui

2、使用dex2jar对framework.jar进行转换,执行命令:dex2jar.bat framework.jar   将会生成一个framework.jar.dex2jar.jar

3、直接对该jar文件解压,可以看到里面都是.class文件了

4、如果还需要转换成.java文件,可以使用xjad或jd-gui,均可将class文件变为java文件。

注:dex2jar工具也可以处理.dex文件,因此也可以不直接处理framework.jar。而是先将framework.jar解压,生成classes.dex后再处理也行。

android触摸屏坐标手工校准/调整成功

1.简述
android 的坐标转换处理:
This implementation is a linear transformation using 7 parameters
(a, b, c, d, e, f and s) to transform the device coordinates (Xd, Yd)
into screen coordinates (Xs, Ys) using the following equations:

s*Xs = a*Xd + b*Yd + c
s*Ys = d*Xd + e*Yd + f

Xs,Ys:LCD坐标
Xd,Yd:触摸屏坐标

在编译好了的ANDROID根文件系统的system/etc/pointercal这个文件内,存放着7个数,
这7个数就是对应上面公式的a,b,c,d,e,f,s
比如我原来的:(如果表格没对齐,请拷到记事本里面看)
+----+-----+--------+------+--+--------+----+
| a | b | c     | d    |e |   f    | s |
+----+-----+--------+------+--+--------+----+
|-411|37818|-3636780|-51325|39|47065584|6553|
+----+-----+--------+------+--+--------+----+

2.处理说明:
“system/etc/pointercal”这个文件是被java程序读取使用的,文件目录:
f rameworks/base/services/java/com/android/server/InputDevice.java
---注:我用的是koolu的源码(http://git.koolu.org/),官方的源码请自行搜索。
该文件的第32行定义了:static final String CALIBRATION_FILE = "/system/etc/pointercal";
这个CALIBRATION_FILE变量在第237行被使用于打开该文件:
FileInputStream is = new FileInputStream(CALIBRATION_FILE);
后面的代码就是从这个文件里读取那7个数据,用于上层函数的坐标转换。
所以只要根据该公式通过手工计算出那7个值,就可以准确的进行触摸操作了。

3.计算
计算前需要取得4个触摸屏的坐标,我们取LCD 4个对角的坐标,因为只有这4个坐标知道确切的LCD坐标。
要取坐标必须打开内核中触摸屏的调试代码,启动后在console上使用dmesg命令来跟踪取得。
我是在一个角上用笔点一下,再用dmesg调出记录,然后记录下来。如下是我的320x240屏记录的结果:
坐标轴里小括号()里面的是调试信息给的触摸屏坐标,中括号[]里的是对应的LCD坐标。

x坐标
/|\
|(X:870, Y:140)   (X:870, Y:890)
| [320,0]          [320,240]
|
|
|
+-------------------------------> y坐标
(X:120, Y:140)    (X:120, Y:890)
     [0,0]             [0,240]

*LCD 分辨率:320 x 240 ,也是LCD坐标的最大值
             x     y

设定s=65536
将那4个坐标代入那个公式,可以得出8个方程组

        0 = a*120 + b*140 + c
        0 = d*120 + e*140 + f
        0 = a*120 + b*890 + c
65536*240 = d*120 + e*890 + f
65536*320 = a*870 + b*140 + c
        0 = d*870 + e*140 + f
65536*320 = a*870 + b*890 + c
65536*240 = d*870 + e*890 + f
解方程组后就可得:
a = 0
b = 20971
c = -2935940
d = 27962
e = 0
f = -3355440
s = 65535
然后用工具打开andriod的“system/etc/pointercal”文件,把这几个数输进去,用空格分开,
注意不要改文件结尾的两个字节0x00 0x0A,我是用Ghex工具打开的,在右边窗口中进行输入,在编辑里可以切换插入和覆盖模式。
此时启动试试。

////////////////////////////
我的屏到这个步骤后触摸操作的左右变成了上下,上下变成了左右操作,
处理方法:把a,b,c值和d,e,f值分别对调。
再启动试试。。
还是不行,左右是正确的,上下是反的。
处理方法:
把Y坐标再反向的公式:
Ys‘ = 320 - Ys = 320 - (a*Xd + b*Yd + c)/s
重新计算a,b,c的值,就OK了。

现在我点击计算器的按钮等操作都很准了,指哪打哪。

前面发的那个视频里的坐标是在内核里调的坐标,不是很准。

这是手工调的方法,如果要用程序校准的话可以用tslib,有时间再玩下。

Android 开机画面

Android 开机会出现3个画面:
a.  Bootloader启动,出现Android机器人图像;
b.  Android平台启动初始化,出现"A N D R I O D"文字字样画面;
c.  Android平台图形系统启动,出现含闪动的ANDROID字样的动画图片(start)。

 

a. Bootloader显示的Android机器人图像

 

b. 开机文字("A N D R I O D")

 

Android 系统启动后,读取 /initlogo.rle(一张565 rle压缩的位图),如果读取成功,测在/dev/graphics/fb0显示Logo图片;如果读取失败,则将/dev/tty0设为TEXT模式,并打开/dev/tty0,输出文本“A N D R I O D”字样。

相关代码:

/system/core/init/init.c
/system/core/init/init.h
/system/core/init/init.rc
/system/core/init/logo.c

*.rle文件的制作步骤:
1. 使用GIMP或者Advanced Batch Converter软件,将图象转换为RAW格式;
2. 使用android自带的rgb2565工具,将RAW格式文件转换为RLE格式(如:rgb2565 -rle < initlogo.raw > initlogo.rle)。

 

c. Android平台图形系统启动

 

Android的系统登录动画类似于Windows系统的滚动条,是由前景和背景两张PNG图片组成。前景图片(android-logo-mask.png)上的Android文字部分镂空,背景图片(android-logo-shine.png)则是简单的纹理。系统登录时,前景图片在最上层显示,程序代码控制背景图片连续滚动,透过前景图片文字镂空部分滚动显示背景纹理,从而实现动画效果。

相关代码:
frameworks/base/cmds/bootanimation/BootAnimation.h
frameworks/base/cmds/bootanimation/BootAnimation.cpp

frameworks/base/core/res/assets/images/android-logo-mask.png
Android默认的前景图片,文字部分镂空,大小256×64
frameworks/base/core/res/assets/images/ android-logo-shine.png
Android默认的背景图片,有动感效果,大小512×64

修改Android开机画面

Android系统开机动画包括两部分:
开机显示的 ANDROID 文字;
ANDROID发光动画。
这篇文章说的开机动画是第一种,下面开始正文!

1. 制作当前屏幕像素的图片(模拟器默认为320*480)
使用PS制作一张320*480的图片,保存时选“保存为 Web 所用格式”,然后在弹开的窗口上,“预设”项选择“PNG-24”,保存为android_logo.png
注:好像只支持png-24,其他格式生成的rle文件显示不正常,有兴趣大家可以再验证一下。

2. 将图片转换为raw格式
使用linux下的ImageMagick自带的convert命令,进行raw格式转换,命令为:
  convert -depth 8 android_logo.png rgb:android_logo.raw
注:ubuntu 10.04 默认已经安装ImgageMagick工具,如果当前系统没有安装,可以执行下面的命令安装:
  sudo apt-get install imagemagick

3. 将raw格式转化为rle文件
需要用到android编译后的rgb2565工具,在android/out/host/linux-x86/bin目录下(android为当前源码所在目录),转换命令如下:
rgb2565 -rle < android_logo.raw > initlogo.rle
到目前为止,启动需要显示的图像已经做好了,就是initlogo.rle,注意文件名必须是这个,如果想改文件名,需要修改android/system/core/init/init.h中的宏:
#define INIT_IMAGE_FILE "/initlogo.rle"
============================================================================================

下面需要将initlogo.rle加入的android文件系统中
4. 找到ramdisk.img文件(android/out/target/product/generic/ramdisk.img),将文件名改为ramdisk.img.gz,然后使用下面的命令解压:
gunzip ramdisk.img.gz
解压后得到ramdisk.img,可能有人要问,怎么文件名又改回去了?其实不然,使用file ramdisk.img查看一下就知道了:
解压前:ramdisk.img: gzip compressed data, from Unix
解压后:ramdisk.img: ASCII cpio archive (SVR4 with no CRC)
跑题了,还是说正事儿。

5. 使用cpio提取文件:
新建一个temp目录:
mkdir temp
cd temp
cpio -i -F ../ramdisk.img

6. 导出文件列表:
cpio -i -t -F ../ramdisk.img > list      
注:list是一个文本文件,里面存储了ramdisk.img的文件结构,我们需要在这个文件中加入initlogo.rle这一行,修改后的文件如下:
data
default.prop
dev
init
init.goldfish.rc
init.rc
initlogo.rle
proc
sbin
sbin/adbd
sys
system

7. 生成ramdisk.img
cpio -o -H newc -O ramdisk.img < list
注:根据list文件的描述,生成ramdisk.img文件

8. 用ramdisk.img覆盖sdk目录下的ramdisk.img(android-sdk-windows/platforms/android-2.1/images/ramdisk.img),最好先备份一下。

9. 启动模拟器,就可以看到我们自己做的的开机界面了。
/////////////////////////
开机图片设置 的下载地址为:http://docs.google.com/leaf?id=0 ... TIzOGQ5OWQ3&amp;hl=en

init 文件下载地址 http://docs.google.com/leaf?id=0 ... 2RiYjZjNjM2&amp;hl=en

split_bootimg.pl 下载地址:http://android-dls.com/files/linux/split_bootimg.zip

T卡文件下载地址:http://docs.google.com/leaf?id=0 ... GVjYzVhMjg4&amp;hl=en


开机图片设置 软件原理:
     根据android 系统 开机LOGO和开机动画的存放路径:/initlogo.rle 和 /data/local/bootanimation.zip 在init.rc 中 建立两个链接:
/initlogo.rle ->/data/data/com.android.e139.gallery/initlogo.rle 和 /data/local/bootanimation.zip ->/data/data/com.android.e139.gallery/bootanimation.zip 
来完成开机LOGO和开机动画的动态设定

安装要求:

1.本apk文件只能安装在android 2.1 或 2.0的操作系统 中
2.必须修改android 根目录下面的两个文件:init.rc 和 init 功能才能实现设置开机LOGO和开机动画的功能


修改init.rc 和 init 的方法:

1.修改 init.rc 和init文件需要修改手机中的 boot.img
导出方法:
cat /dev/mtd/mtd2 > /sdcard/root.img

然后

adb pull /sdcard/root.img ./

这样就把root.img拷贝到本地目录下了。

boot.img的组成结构是

+—————–+
| boot header | 1 page
+—————–+
| kernel | n pages
+—————–+
| ramdisk | m pages
+—————–+
| second stage | o pages
+—————–+


那我们要做的就是把这几个部分分别分离出来

我们现在先进行镜像分离。用命令

./split_bootimg.pl boot.img

 

成功执行后,可以得到两个文件,一个是boot.img-kernel,另一个是boot.img-ramdisk.gz。我们这里以修改ramdisk为例,所以将其解包

mkdir ramdisk

cd ramdisk

gzip -dc ../boot.img-ramdisk.gz | cpio -i

cd ..

2.进入ramdisk 修改init.rc 在init.rc 中增加:

on logo-init

    mkdir /data 0775 system system

# We chown/chmod /data again so because mount is run as root + defaults
    mount yaffs2 mtd@userdata /data nosuid nodev
    chown system system /data
    #for other user can read this dir
    chmod 0775 /data

    symlink /data/data/com.android.e139.gallery/initlogo.rle /initlogo.rle

on early-boot
# copy file   
    symlink /data/data/com.android.e139.gallery/bootanimation.zip /data/local/bootanimation.zip
    chmod 0666 /data/local/bootanimation.zip

再将已经下载的init文件覆盖到目录下面的init文件
3.生成新img 回到ramdisk 的上一级目录后执行:
mkbootfs ./ramdisk | gzip > ramdisk-new.gz mkbootimg --cmdline 'no_console_suspend=1 console=null' --kernel boot.img-kernel --ramdisk ramdisk-new.gz -o boot-new.img
就会重新生成 boot-new.img
3.刷入新img

生成了新的img后,我们如何在系统上应用我们的新boot.img呢?首先,把img文件放到sdcard上去

adb push ./boot_new.img /sdcard

然后执行这两个操作

cat /dev/zero > /dev/mtd/mtd2
flash_image boot /sdcard/mynewimage.img

执行第一个操作时,可能会提示你

write: No space left on device

这个信息没关系,不用管它。两个命令都执行后,最后adb shell reboot即可。如果重启顺利,那么恭喜你,你刷成功了.


安装步骤:
1.按上面的步骤修改手机中的init.rc 和init文件
2.把下载的T卡文件放到T卡中
3.安装 开机图片设置.apk文件

修改boot.img的方法参考:http://www.kunli.info/2009/09/14/how-to-modify-ramdisk-android/ 和
http://android-dls.com/wiki/index.php?title=HOWTO:_Unpack,_Edit,_and_Re-Pack_Boot_Images

关于boot.img和recovery.img的编辑和修改( 转)

以下是偶翻译的关于boot.img和recovery.img的编辑和修改方面的文章,希望能够为感兴趣的朋友节约一些看资料的时间。感谢本文的作者:Alansj, DarkriftX, RyeBrye, Will, Try OP9, Tonyb486, Timmmm, Lxrose还有好多不知名的作者们在wiki上的不懈努力。

如何解包/编辑/大包boot.img文件

很多人用自己的方式解决了boot.img的解包/编辑/打包的问题,有人要求我来写一篇关于boot和recovery映像的文件结构和如何对其编辑的文章,于是就有了下面这篇文章。

目录
1、背景知识
2、boot和recovery映像的文件结构
3、对映像文件进行解包、编辑、打包的常规方法
3.1、另一种解包、编辑、打包的方法
4、将新的映像刷回到手机
5、解包、编辑、打包为我们带来了什么
6、本文讲的内容与使用update.zip刷机包不是一码事

正文

1、背景知识

Android手机的文件系统有许多存储器组成,以下是在adb shell下面的输出:
#cat /proc/mtd
dev:    size   erasesize  name
mtd0: 00040000 00020000 "misc"
mtd1: 00500000 00020000 "recovery"
mtd2: 00280000 00020000 "boot"
mtd3: 04380000 00020000 "system"
mtd4: 04380000 00020000 "cache"
mtd5: 04ac0000 00020000 "userdata"

注意,不同的手机在上述存储设备的顺序可能会各不相同!一定要检查您的手机,确定在以下的操作中选择正确的设备号(mtdX,这个X的序号一定要检查清楚)。
在本向导中,我们主要描述对"recovery"和"boot"的存储设备进行操作;"system"存储设备保存了android系统目录的所有数据(在系统启动后会挂载到“system/”目录);“userdata”存储设备将保存了android数据目录中的所有数据(在系统启动后会挂载到“data/”目录,里面是会有很多应用数据以及用户的preference之类的配置数据)。

从上面的输出可以看出来,recovery和boot分区对应着/dev/mtd/mtd1和/dev/mtd/mtd2,在你您开始做任何修改之前一定要做两件事情,第一件事情,一定要先对这两个分区进行备份。

可以使用如下命令进行备份:
# cat /dev/mtd/mtd1 > /sdcard/recovery.img
# cat /dev/mtd/mtd2 > /sdcard/boot.img
(注意added by lxros,只有手机获取了ROOT权限以后才能够执行上述的备份命令)

第二件事情,你您应该把你您最喜欢的update.zip刷机包放置到你您的sd卡的根目录上面。如此一来,即使你您在后续的操作中出了问题,也可以启动到recovery模式进行恢复。

另外一个你您需要知道的重要文件是在android系统目录下的/system/recovery.img,此文件是mtd1存储设备的完全拷贝。这个文件在每次关机的时候,会自动地被写回到mtd1存储设备里面。

这会意味着两个事情:
(1)任何对/dev/mtd/mtd1中数据的直接修改都会在下一次重启手机以后消失。

(2)如果希望对/dev/mtd/mtd1进行修改,最简单的做法是用你您自己的recovery.img替换掉/system/recovery.img。当你您创建自己的update.zip刷机包的时候(特别是在做刷机包的适配的时候),如果你您忘记替换这个/system/recovery.img,这个recovery.img就会在关机的时候被烧写到mtd1里面去或许会变砖。一定要注意这一点!
(译者的话,关于这个/system/recovery.img文件,在2.1的android的平台里面并没有找到,或许这个机制已经out了?!或者偶本人对这段话的理解不够深入?!希望明白的朋友不吝斧正)

2、boot和recovery映像的文件结构

boot和recovery映像并不是一个完整的文件系统,它们是一种android自定义的文件格式,该格式包括了2K的文件头,后面紧跟着是用gzip压缩过的内核,再后面是一个ramdisk内存盘,然后紧跟着第二阶段的载入器程序(这个载入器程序是可选的,在某些映像中或许没有这部分)。此类文件的定义可以从源代码android-src/system/core/mkbootimg找到一个叫做bootimg.h的文件。

(译者的话,原文是一个叫做mkbootimg.h的文件,但从Android 2.1的代码来看,该文件名应该是改为bootimg.h了)。
/*
** +-----------------+
** | boot header     | 1 page
** +-----------------+
** | kernel          | n pages  
** +-----------------+
** | ramdisk         | m pages  
** +-----------------+
** | second stage    | o pages
** +-----------------+
**
** n = (kernel_size + page_size - 1) / page_size
** m = (ramdisk_size + page_size - 1) / page_size
** o = (second_size + page_size - 1) / page_size
**
** 0. all entities are page_size aligned in flash
** 1. kernel and ramdisk are required (size != 0)
** 2. second is optional (second_size == 0 -> no second)
** 3. load each element (kernel, ramdisk, second) at
**    the specified physical address (kernel_addr, etc)
** 4. prepare tags at tag_addr.  kernel_args[] is
**    appended to the kernel commandline in the tags.
** 5. r0 = 0, r1 = MACHINE_TYPE, r2 = tags_addr
** 6. if second_size != 0: jump to second_addr
**    else: jump to kernel_addr
*/
ramdisk映像是一个最基础的小型文件系统,它包括了初始化系统所需要的全部核心文件,例如:初始化init进程以及init.rc(可以用于设置很多系统的参数)等文件。如果你您希望了解更多关于此文件的信息可以参考以下网址:
http://git.source.android.com/?p=kernel/common.git;a=blob;f=Documentation/filesystems/ramfs-rootfs-initramfs.txt
以下是一个典型的ramdisk中包含的文件列表:
./init.trout.rc
./default.prop
./proc
./dev
./init.rc
./init
./sys
./init.goldfish.rc
./sbin
./sbin/adbd
./system
./data
recovery映像包含了一些额外的文件,例如一个叫做recovery的二进制程序,以及一些对该程序支持性的资源图片文件(当你您按下home+power组合键的时候就会运行这个recovery程序)。
典型的文件列表如下:
./res
./res/images
./res/images/progress_bar_empty_left_round.bmp
./res/images/icon_firmware_install.bmp
./res/images/indeterminate3.bmp
./res/images/progress_bar_fill.bmp
./res/images/progress_bar_left_round.bmp
./res/images/icon_error.bmp
./res/images/indeterminate1.bmp
./res/images/progress_bar_empty_right_round.bmp
./res/images/icon_firmware_error.bmp
./res/images/progress_bar_right_round.bmp
./res/images/indeterminate4.bmp
./res/images/indeterminate5.bmp
./res/images/indeterminate6.bmp
./res/images/progress_bar_empty.bmp
./res/images/indeterminate2.bmp
./res/images/icon_unpacking.bmp
./res/images/icon_installing.bmp
./sbin/recovery

3、对映像文件进行解包、编辑、打包的常规方法

(注意,下面我给你您介绍的是手工命令行方式进行解包以及重新打包的方法,但是我仍然创建了两个perl脚本,这两个脚本可以让你您的解包和打包工作变得轻松许多。可以参考本文的附件unpack-bootimg.zip和repack-bootimg.zip)

如果你您很擅长使用16进制编辑器的话,你您可以打开boot.img或者recovery.img,然后跳过开始的2K的头数据,然后寻找一大堆0的数据,在这一堆0的数据后面,紧跟着1F 8B这两个数字(1F 8B是gzip格式的文件的结束标记)。从此文件开始的地方(跳过2K的头),一大堆0后面紧跟着到1F 8B这两个数字为止的全部数据,就是gzip压缩过的linux内核。从1F 8B后面紧跟着的数据一直到文件的结尾包含的全部数据,就是ramdisk内存盘的数据。你您可以把把内核和ramdisk两个文件分别保存下来,在进行分别的修改和处理。我们可以通过un-cpio和un-gzip操作来读取ramdisk文件中的数据,可以使用如下的命令来实现这个目的,以下操作会生成一个目录,直接cd进去就可以看到ramdisk中的数据了:
gunzip -c ../your-ramdisk-file | cpio -i
此命令可以将ramdisk中的所有的文件解包到当前的工作目录下面,然后就可以对它进行编辑了。

当需要重新打包ramdisk的时候,就需要re-cpio然后re-gzip这些数据和目录,可以通过如下命令来实现:(cpio会把所有当前目录下面的文件都打包进去,因此,在进行此步骤之前,请把不需要的文件都清除掉。)
find . | cpio -o -H newc | gzip > ../newramdisk.cpio.gz
最后一步就是通过mkbootimg这个工具,把kernel和ramdisk打包在一起,生成一个boot.img:
mkbootimg --cmdline 'no_console_suspend=1 console=null' --kernel your-kernel-file --ramdisk newramdisk.cpio.gz -o mynewimage.img
这里的mkbootimg工具会在编译android的源代码的时候会在~/android-src/out/host/linux-x86/bin目录下面自动生成。
下载地址:
http://git.source.android.com/?p=platform/system/core.git;a=tree;f=mkbootimg

现在,如果不想背这些复杂的命令或者摆弄那个让人眩晕的16进制编辑器的话,可以尝试使用我编写的用于解包和打包的perl脚本了。希望这些脚本能够节约各位的键盘。

3.1、另一种解包、编辑、打包的方法

下载split_bootimg.zip文件(译者注,会在本文的附件中提供),在此zip文件中包含一个perl文件,split_bootimg.pl脚本,该脚本可以读取boot.img头(根据Android源码中的bootimg.h读取)将kernel和ramdisk读取出来,此脚本也会输出内核命令行和板子名字。
(注意,不要使用从/dev/mtd/mtd2直接拷贝出来的boot.img,此映像可能在读取过程遭到损坏。)
下面是一个从TC4-RC28更新中提取出来的boot.img进行解包操作:
% ./split_bootimg.pl boot.img
Page size: 2048 (0x00000800)
Kernel size: 1388548 (0x00153004)
Ramdisk size: 141518 (0x000228ce)
Second size: 0 (0x00000000)
Board name:
Command line: no_console_suspend=1
Writing boot.img-kernel ... complete.
Writing boot.img-ramdisk.gz ... complete.
解包ramdisk的命令如下:
% mkdir ramdisk
% cd ramdisk
% gzip -dc ../boot.img-ramdisk.gz | cpio -i
% cd ..
解码完毕后,就可以修改了(例如,在default.prop设置ro.secure=0等等)

使用mkbootfs工具(mkbootfs工具是编译完毕Android源代码以后,就会在~/android-src/out/host/linux-x86/bin自动生成)来重新创建ramdisk,可以使用如下命令来操作:
% mkbootfs ./ramdisk | gzip > ramdisk-new.gz
使用mkbootimg来重新创建boot.img,mkbootimg也可以在~/android-src/out/host/linux-x86/bin目录中可以找到:
% mkbootimg --cmdline 'no_console_suspend=1 console=null' --kernel boot.img-kernel --ramdisk ramdisk-new.gz -o boot-new.img
(注意:console=null的命令行选现是从TC4-RC30的boot.img引入的,用以去掉root shell)

4、将新的映像刷回到手机

可以将recovery.img拷贝到/system目录下面,然后重新启动手机,让手机自动为你您刷写到mtd里面(工作原理在上面已经提过了)。对于boot.img可以通过将其拷贝到sd卡的根目录,然后通过手机内的刷写工具将此映像写入到手机中。

例如,使用adb工具将boot.img拷贝到手机的sd卡的根目录:
adb push ./mynewimage.img /sdcard
然后通过adb shell登录手机的shell交互模式,利用命令行进行交互:
# cat /dev/zero > /dev/mtd/mtd2
   write: No space left on device [this is ok, you can ignore]
# flash_image boot /sdcard/mynewimage.img
然后重启。
如果能够正常启动,那么祝贺你您,你您的修改和替换已经成功了;如果不能够顺利启动,则需要重新启动进入recovery模式,并且使用update.zip来恢复。

5、解包、编辑、打包为我们带来了什么

可以修改开机启动时候的画面,具体的操作的地址为:
http://forum.xda-developers.com/showthread.php?t=443431

6、本文讲的内容与使用update.zip刷机包不是一码事

您可以很容易地在其他论坛上看到关于如何自制update.zip刷机包的方法,也可以下载到很多在网络上共享的自制刷机包。

Android System Services 环境浅析

原创文章欢迎转载,转载请注明住处rickleaf

1.System Services

首先我要声明一下,我讲的System Services并非Android 开发应用程序时,所涉及的Service(后台应用服务程序)的概念。

我要讲的System Services是Android操作系统Java应用程序下层的,伴随操作系统启动而运行的系统后台服务程序。

它是Android系统运行的基石,它配合binder(Android多进程通讯方法)、dalvik虚拟机和Android应用程序构成了一个多进程

交互通讯,交互服务的Android系统。

2.浏览一下Android系统的service

启动shell

adb shell

执行下面指令

#service list

Found 47 services:
0    phone: [com.android.internal.telephony.ITelephony]
1    iphonesubinfo: [com.android.internal.telephony.IPhoneSubInfo]
2    simphonebook: [com.android.internal.telephony.IIccPhoneBook]
3    isms: [com.android.internal.telephony.ISms]
4    appwidget: [com.android.internal.appwidget.IAppWidgetService]
42    SurfaceFlinger: [android.ui.ISurfaceComposer]
43    media.audio_policy: [android.media.IAudioPolicyService]
46    media.audio_flinger: [android.media.IAudioFlinger]
#


从结果看来Android后台有很多的service,他们是分散在不同进程中的线程实体(有点绕嘴,但是我认为这样说比较确切)。

 

3.什么是Service Manager

里面理解一下就可以了,Service manager是管理以上services的一个进程,他是实际存在的。

您可以在adb shell中运行ps看看进程列表就知道了。

 

源代码位于:

frameworks/base/cmds/servicemanager

执行方式:

他是用c和c++语言编写的natvie可以执行文件。在Android中称之为EXECUTABLE,这个名称很重要因为Android.mk文件中

用这个名字来确定他是可以执行的二进制文件。

 

4.探究一下Service Manager的启动过程和方法

开始有点复杂了,也该开始进入真正的Linux阶段了。

众所周知Linux的启动和文件系统的加载需要一个ramdisk,ramdisk负责让Linux kernel加载第一个进程init进程

 

在Android的ramdisk中就有这样一个可执行文件init,

在深入一下,我们可以去看一下

 

system/core/init/init.c

 

int main(int argc, char **argv)
{
    。。。。。。
    parse_config_file("/init.rc");

    。。。。。。

 

对的,没看错。这个文件会编译出一个init的二进制可执行文件,并且去读init.rc文件。

 

至此,我们称init.rc文件为Android启动配置脚本。

 

现在我们打开init.rc文件,(如果您不知道init.rc,请参考google吧)

 

## Daemon processes to be run by init.
##
service servicemanager /system/bin/servicemanager
    user system
    critical
    onrestart restart zygote
    onrestart restart media

 

看到吗,servicemanager 是init通过init.rc加载的第一个进程

接下来启动了zygote和media

4.system server进程

继续阅读init.rc

servicemanager进程运行起来以后,我们就可以应用binder来应用servicemanager提供的服务函数去创建

system-server和mediaserver了,下面是init.rc中的代码

 

service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server

#system-server的创建是通过app_process这个二进制程序去加载的
    socket zygote stream 666
    onrestart write /sys/android_power/request_state wake
    onrestart write /sys/power/state on
    onrestart restart media

service media /system/bin/mediaserver   #mediaserver的启动代码比较简单,看看就知道了不用参数就创建了
    user media
    group system audio camera graphics inet net_bt net_bt_admin

 

5.回过头再看系统的进程列表

# ps
USER     PID   PPID  VSIZE  RSS     WCHAN    PC         NAME
root      1     0     296    204   c009a694 0000c93c S /init
root      2     0     0      0     c004dea0 00000000 S kthreadd
root      25    1     728    316   c003d444 afe0d6ac S /system/bin/sh
system    26    1     796    256   c019a810 afe0ca7c S /system/bin/servicemanager
root      30    1     82860  26580 c009a694 afe0cba4 S zygote
media     31    1     20944  3184  ffffffff afe0ca7c S /system/bin/mediaserver
root      32    1     784    280   c0209468 afe0c7dc S /system/bin/installd
keystore  33    1     1616   396   c01a65a4 afe0d40c S /system/bin/keystore
root      34    1     728    272   c003d444 afe0d6ac S /system/bin/sh
root      35    1     824    332   c00b7dd0 afe0d7fc S /system/bin/qemud
root      37    1     1308   152   ffffffff 0000eca4 S /sbin/adbd
root      44    34    780    304   c0209468 afe0c7dc S /system/bin/qemu-props
system    52    30    158356 37804 ffffffff afe0ca7c S system_server
app_1     92    30    108640 20580 ffffffff afe0da04 S com.android.inputmethod.pinyin
radio     93    30    122852 23340 ffffffff afe0da04 S com.android.phone
app_1     98    30    143244 34888 ffffffff afe0da04 S android.process.acore

 

有点复杂了,请大家跟上思路。我们注意观察进程列表的PID和PPID,我们要通过实际的列表去理清他们的亲缘关系。

 

servicemanager是init的子进程

mediaserver是init的子进程

zygote是init的子进程

system_server和所有的java应用程序是zygote的子进程

 

休息一下我们看看他们的应用程序代码方式

Java script caller (executable)
frameworks/base/cmds/app_process/
app_main.cpp

app_process是android系统下面基于命令行的java的应用程序的调用工具

 

system_server executable(c/c++写的程序)


frameworks/base/cmds/system_server/

system_main.cpp
library/system_init.cpp

 

SystemServer (java程序)
frameworks/base/services/java/com/android/server/
SystemServer.java


Zygote (java程序)
frameworks/base/core/java/com/android/internal/os/
ZygoteInit.java

 

6.分析具体的调用过程(很痛苦)

app_main 调用 zygoteInit

p { margin-bottom: 0.21cm; }

/ Next arg is startup classname or "--zygote"

if ( i < argc ) {

arg = argv [ i ++];

if ( 0 == strcmp ( "--zygote" , arg )) {

bool startSystemServer = ( i < argc ) ?

strcmp ( argv [ i ], "--start-system-server" ) == 0 : false ;

setArgv0 ( argv0 , "zygote" );

set_process_name ( "zygote" );

runtime. start ( "com.android.internal.os.ZygoteInit" ,

startSystemServer );

} else {

set_process_name ( argv0 );


runtime. mClassName = arg ;


// Remainder of args get passed to startup class main ()

runtime. mArgC = argc - i ;

runtime. mArgV = argv + i ;


LOGV ( "App process is starting with pid=%d, class=%s. /n " ,

getpid (), runtime. getClassName ());

runtime. start ();

}

}


Zygote 分裂出 system_server



p { margin-bottom: 0.21cm; }

public static void main ( String argv []) {

try {

// Start profiling the zygote initialization.

if ( argv [ 1 ] . equals ( "true" )) {

startSystemServer ();

}

Log. i ( TAG, "Accepting command socket connections" );


if ( ZYGOTE_FORK_MODE ) {

runForkMode ();

} else {

runSelectLoopMode ();

}

}


frameworks/base/core/java/com/android/internal/os/
ZygoteInit.java

p { margin-bottom: 0.21cm; }

private static boolean startSystemServer()

throws MethodAndArgsCaller, RuntimeException {

/* Hardcoded command line to start the system server */

try {

/* Request to fork the system server process */

pid = Zygote. forkSystemServer (

parsedArgs. uid , parsedArgs. gid ,

parsedArgs. gids , debugFlags, null );

} catch ( IllegalArgumentException ex) {

throw new RuntimeException (ex);

}

/* For child process */

if (pid == 0 ) {

handleSystemServerProcess(parsedArgs);

}

return true ;

}


1.如果大家还能看到这里请复习一下 Linux的两个系统调用 fork和exec


frameworks/base/services/java/com/android/server/SystemService.java

p { margin-bottom: 0.21cm; }

public static void main ( String [] args ) {

if ( SamplingProfilerIntegration. isEnabled ()) {

SamplingProfilerIntegration. start ();

timer = new Timer ();

timer . schedule ( new TimerTask () {

@ Override

public void run () {

SamplingProfilerIntegration. writeSnapshot ( "system_server" );

}

} , SNAPSHOT_INTERVAL, SNAPSHOT_INTERVAL );

}

VMRuntime. getRuntime () . setTargetHeapUtilization ( 0 .8f );

System . loadLibrary ( "android_servers" );

init1 ( args );------------------>

}


public static final void init2 () {

Log. i ( TAG, "Entered the Android system server!" );

Thread thr = new ServerThread ();

thr. setName ( "android.server.ServerThread" );-------------->

thr.start();

}



红色的部分最后会执行我们上面列出的jni代码

frameworks/base/cmds/system_server/
library/system_init.cpp


Init2 这里启动了java的system service


p { margin-bottom: 0.21cm; }

class ServerThread extends Thread {

@ Override

public void run () {


Log. i ( TAG, "System Content Providers" );

ActivityManagerService. installSystemProviders ();


Log. i ( TAG, "Battery Service" );

battery = new BatteryService ( context );

ServiceManager. addService ( "battery" , battery );


Log. i ( TAG, "Hardware Service" );

hardware = new HardwareService ( context );

ServiceManager. addService ( "hardware" , hardware );


Log. i ( TAG, "Alarm Manager" );

AlarmManagerService alarm = new AlarmManagerService ( context );

ServiceManager. addService ( Context . ALARM_SERVICE , alarm );


}

}

 

原创文章欢迎转载,转载请注明住处rickleaf

7. 整理Android系统启动流程

 

至此System Service的服务环境启动起来了


  

 

 

8. 最后引用霍金的一句话:“懂与不懂都是收获”

http://blog.csdn.net/rickleaf/article/details/6369720

Android虚拟平台的编译和整合

概要

 

Android从2008年开始到本文写的2011年,短短三年的时间里成为手机行业首屈一指的操作系统,在平板电脑,GPS PND甚至工业控制等领域也迅速流行起来。

越来越多的CPU厂商提供完整的Android解决方案使得Android的编译方法千差万别。

本文从Google原生态的Android系统入手,试图跳过所有的CPU厂商从Android自带的ARM QEMU入手一步步的编译出定制的Android系统。

 

(本文原创:欢迎转载请注明出处和作者 Ricky.Wu rickleaf.wu@gmail.com)

资源

 

Android 2.1 r2
Android Goldfish kernel 2.6.29
ubuntu 10.04 LTS AMD64

 

下载源代码

 

安装工具包

 

安装必要的工具包

 

$sudo apt-get install git-core gnupg flex bison gperf build-essential zip curl zlib1g-dev libc6-dev  lib32ncurses5-dev ia32-libs x11proto-core-dev libx11-dev lib32readline5-dev lib32z-dev

 

安装64bit Linux编译32位系统需要的工具包

 

$ sudo apt-get install gcc-multilib g++-multilib libc6-i386 libc6-dev-i386

 

看需要安装下面工具包

 

$ sudo apt-get install make gcc g++ libc6-dev  patch texinfo
 Zlib1g-dev valgrind python

 

下载源代码

 

下载repo工具,更改为可执行权限,并确保安装路径包含在PATH中
$ curl http://android.git.kernel.org/repo > ~/bin/repo
$ chmod a+x ~/bin/repo
建立Android工作目录
$cd ~
$mkdir android_platform
下载Android 2.1 r2源代码
$repo init -u git://android.git.kernel.org/platform/manifest.git /
-b android-2.1_r2
$repo sync

 

定制化Vendor

 

Android系统的vendor

 

记下Android系统的代码仓库网页
http://android.git.kernel.org/
网页浏览platform/vendor目录

 

 

vendor目录的作用

 

vendor的英文单词有“提供商”的意思,我们结合刚才看到的Android源码仓库中的vendor子目录就可以看出,在Google的Android原始代码里vendor目录包含了CPU硬件提供商的一些信息。
Android系统作为开放的手持设备操作系统,在发布之初必须要提供配置接口给CPU提供商,这样Android的系统才能在不同的CPU上运行。
实际上vendor目录就是Android系统预留给我们加入定制化信息的目录。在这个目录中可以完成对系统默认应用程序的添加移除、及其背光,GPS和OpenGL硬件适应层的vendor库文件或者代码。

 

加入自己的vendor目录

 

参考sample和htc dream建立rickleaf作为一个新的cpu厂商,在rickleaf建立一个heaven的目录作为厂商的一个特别设备

 

Android.mk

 

在android的platform代码中,如果你的代码需要编译或者一些二进制文件和库需要复制到目标板,就必须有个Android.mk文件来管理。
Vendor里面的Android.mk文件主要负责编译CPU厂商的特定代码和复制文件到目标半
Heaven中的Android.mk文件内容如下:

BoardConfig.mk

 

这个文件负责对Android系统的一些配置,包括如下等
ARM CPU的版本
Audio的架构类型
GPS的适应层名字
是否vendor有自己的init.rc文件
Android的image类型(inand需要yaffs2的image,mmc需要ext3或者ext4(android2.3)的image
如果在platform中加入了自己的模块,也可以加入配置机制,并且在这个文件中决定是否加入到系统中来

Heaven下面BoardConfig.mk的内容

AndroidProducts.mk

 

这个文件为PRODUCT_MAKEFILES指定一个mk文件
在指定的mk文件中完成对Android系统中APP层面的一些配置,下面简单列举:
添加默认的Android应用程序
采用哪种dpi
采用哪种图资
为android添加vendor的信息
加入默认铃声

 

PRODUCT_PROPERTY_OVERRIDES
修改一些默认的property设置,关于什么是property请大家去浏览google的文档,可以粗略的理解为类似注册表的东西驻留在内存中,可以供应用程序读写

 

PRODUCT_PACKAGES
PRODUCT_COPY_FILES
Android通过以上两个变量来对android packages和一些系统文件进行添加和移除

 

PRODUCT_LOCALES
这个变有两个作用一个是加入系统支持的语言类型;另一个是决定默认用哪一种图资,比如ldpi,mdpi还是hdpi

 

PRODUCT_BRAND
厂商名字
PRODUCT_NAME
产品名字
PRODUCT_DEVICE
设备名字

 

Linux kernel集成化

 

获得内核源代码

 

克隆kernel到android_platform根目录
$ git clone git://android.git.kernel.org/kernel/common.git kernel
切换kernel分支到2.6.29
$ cd kernel
$ git checkout -b android-goldfish-2.6.29 origin/android-goldfish-2.6.29

 

增加kernel编译到系统

 

修改platform下面的build

------------------------------- core/Makefile --------------------------------

index 2f316ca..7a92961 100644

@@ -288,6 +288,9 @@ endif

 

 INSTALLED_BOOTIMAGE_TARGET := $(PRODUCT_OUT)/boot.img

 

+kernel: $(INSTALLED_BOOTIMAGE_TARGET)

+.PHONY:kernel

+

 ifeq ($(TARGET_BOOTIMAGE_USE_EXT2),true)

 tmp_dir_for_image := $(call intermediates-dir-for,EXECUTABLES,boot_img)/bootimg

 INTERNAL_BOOTIMAGE_ARGS += --tmpdir $(tmp_dir_for_image)

 

AndroidBoard.mk

 

 

kernel配置

 

make kernelconfig

 

 

make kernelgconfig

 

 

Android系统的编译命令集

 

Android编译命令

 

执行环境配置命令
$ . build/envsetup.sh (.后面有空格)
当前终端会多出一些命令:
- croot:   Changes directory to the top of the tree.
- m:       Makes from the top of the tree.
- mm:      Builds all of the modules in the current directory.
- mmm:     Builds all of the modules in the supplied directories.
- cgrep:   Greps on all local C/C++ files.
- jgrep:   Greps on all local Java files.
- resgrep: Greps on all local res/*.xml files.
- godir:   Go to the directory containing a file.

 

—help查看帮助

 

编译模块

 

使用mmm来编译指定目录的模块,如编译Launcher:
$ mmm packages/apps/Launcher/
编完之后生成两个文件:
out/target/product/heaven/data/app/LauncherTests.apk
out/target/product/heaven/system/app/Launcher.apk
可以使用
$ make snod
重新生成system.img,再运行模拟器

 

选择product编译

 

按照如下图的方式,可以选择heaven这个Product

 

用OpenJDK骗过Android的

既然我们在虚拟系统编译,就不用非要去安装官方推荐的java sdk 1.5了。

只要我们在out目录建立这个文件就可以了

 

编译整个系统

 

make -j2 (2表示我有的两个cpu)

 

 

 

 

模拟器加载Android系统

 

创建Heaven模拟环境

创建标准Android 2.1模拟器命名为heaven
更改~/.android/avd/heaven/config.ini文件
hw.lcd.density=240
sdcard.size=64M
skin.name=WVGA800-L
skin.path=platforms/android-2.1/skins/WVGA800-L
vm.heapSize=24
image.sysdir.1=platforms/android-2.1/heaven/
更改以后,我们只要我们把我们编译好的image放到SDK的
platforms/android-2.1/heaven/目录就可以用emualtor了

把out目录中编译好的zimage改名成qemu-kernel放到Heaven仿真目录中
重新冷启动emulator
emulator -avd heaven -wipe-data
这时候heaven的emualtor的所以image都是我们自己生成的了,当然也可以调试apk到这个emulator

 

加入kernel logo

 

手机的about信息

http://blog.csdn.net/rickleaf/article/details/6369065

android中修改默认语言

本文是主要对android定制多语言的问题进行深入研究后,总结了其定制的 机制和其具体实现方法。如果想深入了解其定制的机制,可阅读本文第一部分,如 果只想了解如何定制,请参考第二部分。 


第一部分 多语言定制的机制 


1、ICU4C简介 

ICU4C(ICU for C, http://site.icu-project.org/ ) 是ICU在C/C++平台下的版本, ICU(International Component for Unicode)是基于"IBM公共许可证"的,与开源组织合作研究的, 用于支持软件国际化的开源项目。ICU4C提供了C/C++平台强大的国际化开发能力,软件开发者几乎可以使用ICU4C解决任何国际化的问题,根据各地 的风俗和语言习惯,实现对数字、货币、时间、日期、和消息的格式化、解析,对字符串进行大小写转换、整理、搜索和排序等功能,必须一提的是,ICU4C提 供了强大的BIDI算法,对阿拉伯语等BIDI语言提供了完善的支持。 

ICU首先是由Taligent公司开发的,Taligent公司现在被合并为IBM?公司全球化认证中心的Unicode研究组,然后ICU由IBM和 开源组织合作继续开发,开源组织给与了ICU极大的帮助。 
开始ICU只有Java平台的版本,后来这个平台下的ICU类被吸纳入SUN公司开发的JDK1.1,并在JDK以后的版本中不断改进。C++和C平台下 的ICU是由JAVA平台下的ICU移植过来的,移植过的版本被称为ICU4C,来支持这C/C++两个平台下的国际化应用。 ICU4J和ICU4C区别不大,但由于ICU4C是开源的,并且紧密跟进Unicode标准,ICU4C支持的Unicode标准总是最新的;同时,因 为JAVA平台的ICU4J的发布需要和JDK绑定,ICU4C支持Unicode标准改变的速度要比ICU4J快的多。 

2、 ANDROID语言包 

Android 使用的语言包就是ICU4C,位置:external/icu4c。Android支持的语言有: Locale CANADA 
Locale constant for en_CA. 
Locale CANADA_FRENCH 
Locale constant for fr_CA. 
Locale CHINA 
Locale constant for zh_CN. 
Locale CHINESE 
Locale constant for zh. 
Locale ENGLISH 
Locale constant for en. 
Locale FRANCE 
Locale constant for fr_FR. 
Locale FRENCH 
Locale constant for fr. 
Locale GERMAN 
Locale constant for de. 
Locale GERMANY 
Locale constant for de_DE. 
Locale ITALIAN 
Locale constant for it. 
Locale ITALY 
Locale constant for it_IT. 
Locale JAPAN 
Locale constant for ja_JP. 
Locale JAPANESE 
Locale constant for ja. 
Locale KOREA 
Locale constant for ko_KR. 
Locale KOREAN 
Locale constant for ko. 
Locale PRC 
Locale constant for zh_CN. 
Locale SIMPLIFIED_CHINESE 
Locale constant for zh_CN. 
Locale TAIWAN 
Locale constant for zh_TW. 
Locale TRADITIONAL_CHINESE 
Locale constant for zh_TW. 
Locale UK 
Locale constant for en_GB. 
Locale US 
Locale constant for en_US. 

3、定制语言 

定制语言在PRODUCT_LOCALES字段里添加需要语言,如: PRODUCT_LOCALES := en_US zh_CN,则系统里只有英语和汉语两种语言。然后语言的选择处理是在external/icu4c/stubdata/Android.mk里进行的, 如下: 
config := $(word 1, / $(if $(findstring ar,$(PRODUCT_LOCALES)),large) / 
$(if $(findstring da,$(PRODUCT_LOCALES)),large) / 
$(if $(findstring el,$(PRODUCT_LOCALES)),large) / 
$(if $(findstring fi,$(PRODUCT_LOCALES)),large) / 
$(if $(findstring he,$(PRODUCT_LOCALES)),large) / 
$(if $(findstring hr,$(PRODUCT_LOCALES)),large) / 
$(if $(findstring hu,$(PRODUCT_LOCALES)),large) / 
$(if $(findstring id,$(PRODUCT_LOCALES)),large) / 
$(if $(findstring ko,$(PRODUCT_LOCALES)),large) / 
$(if $(findstring nb,$(PRODUCT_LOCALES)),large) / 
$(if $(findstring pt,$(PRODUCT_LOCALES)),large) / 
$(if $(findstring ro,$(PRODUCT_LOCALES)),large) / 
$(if $(findstring ru,$(PRODUCT_LOCALES)),large) / 
$(if $(findstring sk,$(PRODUCT_LOCALES)),large) / 
$(if $(findstring sr,$(PRODUCT_LOCALES)),large) / 
$(if $(findstring sv,$(PRODUCT_LOCALES)),large) / 
$(if $(findstring th,$(PRODUCT_LOCALES)),large) / 
$(if $(findstring tr,$(PRODUCT_LOCALES)),large) / 
$(if $(findstring uk,$(PRODUCT_LOCALES)),large) / 
$(if $(findstring zh,$(PRODUCT_LOCALES)),large) / 
$(if $(findstring ja,$(PRODUCT_LOCALES)),us-japan) / 
$(if $(findstring it,$(PRODUCT_LOCALES)),us-euro) / 
$(if $(findstring pl,$(PRODUCT_LOCALES)),us-euro) / 
$(if $(findstring cs,$(PRODUCT_LOCALES)),default) / 
$(if $(findstring de,$(PRODUCT_LOCALES)),default) / 
$(if $(findstring fr,$(PRODUCT_LOCALES)),default) / 
$(if $(findstring nl,$(PRODUCT_LOCALES)),default) / 
us) 

4、默认语言 
默认语言的选择实现是在build/core/Makefile里,从PRODUCT_LOCALES里选择第一个语言作为默认语言,如下: 
define default-locale $(subst _, , $(firstword $(1))) 
endef 
# Selects the first locale in the list given as the argument 
# and returns the language (or the region) 
define default-locale-language $(word 2, 2, $(call default-locale, $(1))) 
endef 
define default-locale-region $(word 3, 3, $(call default-locale, $(1))) 
Endef ... PRODUCT_DEFAULT_LANGUAGE="$(call default-locale-language,$(PRODUCT_LOCALES))" / 
PRODUCT_DEFAULT_REGION="$(call default-locale-region,$(PRODUCT_LOCALES))" 
然后通过build/tool/buildinfo.sh文件将如下段写到文件build.prop,如下: 
echo "ro.product.locale.language=$PRODUCT_DEFAULT_LANGUAGE" 
echo "ro.product.locale.region=$PRODUCT_DEFAULT_REGION" 。 

因此,要改变默认语言用下面两种方法中的一种就行了: 

4.1、在PRODUCT_LOCALES字段里,将要选择的语言放在第一位,

如: PRODUCT_LOCALES := en_US zh_CN 默认语言是英语; 


4.2、在persist.sys.language 和persist.sys.country 里指定语言,如下:

PRODUCT_PROPERTY_OVERRIDES := / 
persist.sys.language=zh / 
persist.sys.country=CN /

 

rickleaf我测试后发现需要再添加两个值,算是对原作者的补充吧

 

ro.product.locale.language=zh /

ro.product.locale.region=CN

(在编译的时候一定要删除system下面的build.prop,在编译才有效,否则这个文件不会被更新)

 

build.prop文件的处理是在system/core/init/property_service.c。 


第二部分 多语言定制的方法 


1、多语言定制的实现步骤 

1)进入build/target/product目录,在languages_full.mk或languages_small.mk文件中, 修改PRODUCT_LOCALES的值,来定制语言,比如PRODUCT_LOCALES := en_US zh_CN zh_TW en_GB fr_FR it_IT de_DE es_ES; 

2)相同目录下,修改full.mk文件的 
$(call inherit-product, build/target/product/languages_small|full.mk)语句来切换所使用的文件; 

3)重新编译即可。 

2、设置默认语言的实现步骤 
1)进入build/target/product目录,修改文件core.mk的PRODUCT_PROPERTY_OVERRIDES 值,例如,欲修改为默认中文,则增加 
“/ persist.sys.language=zh / persist.sys.country=CN”,增加后的语句如PRODUCT_PROPERTY_OVERRIDES := / 

ro.config.notification_sound=OnTheHunt.ogg / 

ro.config.alarm_alert=Alarm_Classic.ogg / persist.sys.language=zh / persist.sys.country=CN 
2)重新编译即可。 

3、与多语言定制相关的字段及其所在的文件 

PREVIOUS_BUILD_CONFIG out/target/product/dream/previous_build_config.mk 

NO_FALLBACK_FONT的定义 device/htc/dream-sapphire/BoardConfigCommon.mk 

NO_FALLBACK_FONT的调用 frameworks/base/data/fonts/Android.mk 

extra_locales CUSTOM_LOCALES nodpi mdpi hdpi build/core/product_config.mk 

PRODUCT_PROPERTY_OVERRIDES build/target/product 
build.prop out/target/product/generic/system

Records:8112345678910»