开篇

MIUI 使用代码插桩的方式来移植。即 MIUI 把他们基于 AOSP 的修改的代码全部用 smali 开放出来。这样我们通过对比 MIUI 的 smali 代码和 AOSP 的 smali 代码就可以知道 MIUI 修改了哪些内容,把这些内容移植过去即可完成 MIUI的移植。本文以 jellybean42-mtk 为例,描述使用 patchrom 移植 MIUI的方法以及在过程中遇到的问题及其调试方法。

移植过程

可以查阅 MIUI 移植的文档了解一些背景知识。这里将主体步骤描述如下:

下载 MIUI patchrom

下载 repo 工具

mkdir ~/bin
curl https://storage.googleapis.com/git-repo-downloads/repo > ~/bin/repo
chmod a+x ~/bin/repo

下载 MIUI patchrom 代码

mkdir ~/work/patchrom
cd ~/work/patchrom
repo init -u git://github.com/MiCode/patchrom.git -b jellybean42-mtk
repo sync

repo sync 命令需要很长的时间才能把代码下载完,代码总量大于10G。所以,基本上可以玩儿去了,不要傻傻地等了。

代码下载完成后,我们就可以开始移植工作了。实际的代码目录树结构和内容和文档里描述的会有出入,我们可以忽略文档里的,以实际代码为准。本文使用2014-12-04下载的代码为准。

准备移植目录

在 patchrom 根目录下创建一个产品的工作目录用来移植时使用。

cd ~/work/patchrom
source build/envsetup.sh
mkdir ~/work/patchrom/mtk6582
cd mtk6582

准备一个 OTA 升级包

我们直接拿一个要当作底包的 OTA 升级包来作为 stockrom.zip。对这个底包有以下的要求:

  1. 这个底包必须是 user 版本且足够稳定。因为根据底包移植完的软件是直接拿来当产品使用的。
  2. 这个底包可以直接在手机里通过 recovery 模式升级。这个对后面移植完手的 miui-ota 包的烧录有帮助。

这样,我们直接把这个 OTA 升级包 stockrom.zip 放在刚刚我们创建的 mtk6582 目录下。除此之外,我们还需要一台内核 root 过的手机,以便配合整个移植过程。

关于stockrom.zip

patchrom 官方移植教程是使用 ../tools/ota_target_from_phone -r 来直接从移植手机里生成 stockrom.zip 。这个命令要求手机先运行在 recovery 模式下。我自己验证过无法运行,没去深究。所以,直接拿一个 OTA 升级包来作为移植的底包。

user 版本的 OTA 升级包里,apk 文件都是经过 odex 优化的。而 smali 反汇编又需要优化前的 apk 文件。怎么样解决这个问题呢?

  1. 打开 stockrom.zip 文件,把 system/framework 下的 pacheCoder.jar, gcm.jar, hpe.jar 从 zip 包里删除。这是因为这三个 jar 包没有经过 odex 优化。即找不到相应的 odex 包。这样的情况在下面的步骤处理时会出错。
  2. 在 patchrom/mtk6582 目录下,执行如下命令 ../tools/deodex.sh stockrom.zip ,执行结束后,原 OTA 包会被覆盖掉,而且里面的 odex 文件将全部被打包回 apk 文件里。
  3. 把步骤 1 删除掉的 3 个 jar 包放回 zip 包里。然后运行下面命令对zip包进行重新签名 java -Xmx2048m -jar signapk.jar -w testkey.x509.pem testkey.pk8 stockrom.zip stockrom-signed.zip
  4. 把新生成的 ota zip 包放在手机 SD 卡里,进 recovery 模式进行升级。确保制作出来的包没有问题。

准备一个 makefile

下面的 makefile 可以作为模板,里面有详细的注释说明每个字段的含义。

#
# Makefile for mtk6582
## 指定我们要移植的手机的底包,就是上一步骤里准备的 stockrom.zip
local-zip-file     := stockrom.zip# 编译我们移植好的 MIUI ROM 时的输出文件名
local-out-zip-file := MIUI_MTK6582.zip# 制作升级差异包时所需要的上一个版本的 ota 包目录,我们暂时还用不着
local-previous-target-dir := ~/work/ota_base/mtk6582# All apps from original ZIP, but has smali files chanded
local-modified-apps :=local-modified-jars :=# 哪些 MIUI 模块不包含在最终生成的 MIUI ROM 里。这里我们默认包含所有的 MIUI 模块。
local-miui-removed-apps :=# 我们在移植过程中,使用了 MIUI 的 Phone 模块,但对 MIUI 的这个模块进行反编译并修改了部分 smali 代码使其功能正常。
# 针对 jellybean42-mtk 这个分支,所有的 MIUI 模块定义在 patchrom/build/jellybean42-mtk.mk 文件里。
local-miui-modified-apps := Phone# density define
local-density := XHDPIinclude phoneapps.mk# To include the local targets before and after zip the final ZIP file,
# and the local-targets should:
# (1) be defined after including porting.mk if using any global variable(see porting.mk)
# (2) the name should be leaded with local- to prevent any conflict with global targets
local-pre-zip := local-pre-zip-misc
local-after-zip:= local-put-to-phone# The local targets after the zip file is generated, could include 'zip2sd' to
# deliver the zip file to phone, or to customize other actionsinclude $(PORT_BUILD)/porting.mk# To define any local-target
updater := $(ZIP_DIR)/META-INF/com/google/android/updater-script
pre_install_data_packages := $(TMP_DIR)/pre_install_apk_pkgname.txt
local-pre-zip-misc:rm -rf $(pre_install_data_packages)for apk in $(ZIP_DIR)/data/media/preinstall_apps/*.apk; do\$(AAPT) d --values resources $$apk | grep 'id=127 packageCount' | sed -e "s/^.*name=//" >> $(pre_install_data_packages);\done
    more $(pre_install_data_packages) | wc -l > $(ZIP_DIR)/system/etc/enforcecopyinglibpackages.txtmore $(pre_install_data_packages) >> $(ZIP_DIR)/system/etc/enforcecopyinglibpackages.txtout/framework2.jar : out/framework.jar%.phone : out/%.jar@echo push -- to --- phoneadb remountadb push $< /system/frameworkadb shell chmod 644 /system/framework/$*.jar%.sign-plat : out/%java -jar $(TOOL_DIR)/signapk.jar $(PORT_ROOT)/build/security/platform.x509.pem $(PORT_ROOT)/build/security/platform.pk8  $< $<.signed@echo push -- to --- phoneadb remountadb push $<.signed /system/app/$*adb shell chmod 644 /system/app/$*

make workspace

在 patchrom/mtk6582 目录下运行 make workspace 命令。这个命令会把 stockrom.zip 文件解压,并且反编译里面的 jar/apk 来作为移植的基础。在上述 makefile 内容下,会生成下面几个文件夹:

  1. android.policy.jar.out
  2. framework.jar.out
  3. framework-res
  4. mediatek-framework.jar.out
  5. secondary-framework.jar.out
  6. services.jar.out

深入理解make workspace

可以阅读 patchrom/build 目录下的 makefile 文件来深入理解 patchrom 的编译系统。对 make workspace 命令,实际上是根据 jellybean42-mtk.mk 里的 private-miui-jars,以及 framework-res.apk 和 makefile 里定义的 local-modified-apps 来决定反编译哪些内容的。

make firstpatch

在 patchrom/mtk6582 目录下运行 make firstpatch 命令。这个命令偿试自动合并 smali 文件。如果无法合并,会在 reject 目录下生成有冲突的文件。所以,运行这个命令后,我们只需要合并 reject 目录下的有冲突的文件即可完成 MIUI ROM 的移植工作。

这个命令在 patchrom/mtk6582/temp 目录下生成的文件树如下:

├── dst_smali_orig # 这个是底包 stockrom.zip 里反编译出来的系统 smali 文件
│   ├── android.policy.jar.out
│   ├── framework.jar.out
│   ├── mediatek-framework.jar.out
│   ├── secondary-framework.jar.out
│   └── services.jar.out
├── dst_smali_patched # 这个是程序自动合并的目标 smali 文件
│   ├── android.policy.jar.out
│   ├── framework.jar.out
│   ├── mediatek-framework.jar.out
│   ├── secondary-framework.jar.out
│   └── services.jar.out
├── new_smali # 这个是 MIUI ROM 里反编译出来的系统 smali 文件
│   ├── android.policy.jar.out
│   ├── framework.jar.out
│   ├── mediatek-framework.jar.out
│   ├── secondary-framework.jar.out
│   └── services.jar.out
├── old_smali # 这个是 AOSP 里反编译出来的系统 smali 文件
│   ├── android.policy.jar.out
│   ├── framework.jar.out
│   ├── mediatek-framework.jar.out
│   ├── secondary-framework.jar.out
│   └── services.jar.out
└── reject # 这个是由于冲突程序无法自动合并,需要手动合并的 smali 文件├── android.policy.jar.out├── framework.jar.out├── secondary-framework.jar.out└── services.jar.out

可以阅读 patchrom/build 和 patchrom/tools 两个目录下的 makefile 和 shell 源码来理解 make firstpatch 过程到底做了什么事情。

关于自动合并

自动合并会把一些差异自动合并进 dst_smali_patched 目录。这个合并过程是怎么样的呢?可以阅读 patchrom/tools/patch_miui_framework.sh 文件来获取详细信息。这里总结自动合并的过程如下:1) 用 diff 命令计算 old_smali 和 new_smali 两个文件夹下的每个文件的补丁 .diff 文件。2) 用 patch 命令把计算出来的 .diff 文件逐个给 dst_smali_orig 目录下的对应文件打补丁,自动合并成功的文件最终生成成 dst_smali_patched 目录下。

手动合并 reject 目录

看起来好简单,其实挑战刚刚开始,要手动合并 reject 目录下的内容不是件容易的事情。即使合并完,后面的调试过程也是痛苦异常。不过也别灰心。办法总比困难多。掌握了基本原理,那么合并过程和调试过程其实还是有规律可以遵循的。在开始这个痛苦过程前,需要先掌握 smali 语法以及 Dalvik 虚拟机的字节码的函义。关于 Dalvik 虚拟机字节码,这个文档可以查阅。

手动合并 smali 代码的流程是这样的:

  1. 用文本编辑器逐个打开 reject 目录下的所有文件,找出冲突的代码块
  2. 用 BeyondCompare/Meld 工具去比较 old_smali 和 new_smali,找出冲突代码块的位置
  3. 通过比较阅读 smali 文件理解 MIUI 在 AOSP 的基础修改了什么逻辑
  4. 用 BeyondCompare/Meld 工具去比较 dst_smali_orig 和 dst_smali_patched,找出冲突代码块的位置
  5. 根据步骤 3 的逻辑修改,把这个修改合并进 dst_smali_patched 目录

这个过程刚做很痛苦,但有做几次积累一定经验后,就轻松了。过程中可能还要结合 AOSP 的 JAVA 源码阅读来理解逻辑。

目标 smali 代码合并进 dst_smali_patched 之后,还需要把这个结果合并回 patchrom/mtk6582 目录下的相应 smali 文件里。比如,需要把 patchrom/mtk6582/android.policy.jar.out 目录和 patchrom/mtk6582/temp/dst_smali_patched/android.policy.jar.out 目录相比较,把最终结果合并进 patchrom/mtk6582/android.policy.jar.out 里。因为 patchrom 编译工具在生成这些需要合并的文件时,把 smali 文件里的行号删除了。这样有利于自动合并和手动合并,而不会被行号干扰。而我们合并完真正进行编译时,实际上参加编译的是 patchrom/mtk6582/android.policy.jar.out 下的 smali 文件。所以必须合并回去才能真正把 MIUI 合并过去。

make fullota

合并完成后,可以在 patchrom/mtk6582 目录下运行 make fullota 来生成目标文件 MIUI_MTK6582.zip。如果你人品足够好,那么可能一步就生成了。但基本上没有这么好的运气。过程中会有 smali 错误。需要根据提示去做适当的修改。编译通过后,就可以把 MIUI_MTK6582.zip 文件通过 recovery 方式升级到手机看移植后的效果。

结语

本文分析了使用 patchrom 移植 MIUI 的全过程,详细解释了 patchrom 编译系统及步骤。这个对理解 patchrom 移植的原理有比较大的帮助。移植过程中可能会碰到各种各样的问题。这些问题都需要一些丰富的知识去识别和解决。下一篇准备介绍一下移植过程中遇到的一些问题,解决方法以及找到解决方法的分析过程。

使用 patchrom 移植 MIUI相关推荐

  1. android+3g移植,惊呆!普耐尔MOMO迷你3G移植MIUI系统

    MIUI操作系统对应的第三方代表作有很多,它基于Android原生系统和针对中国用户使用习惯开发的AndroidRom,在国内年轻用户圈内已经被誉为"发烧友必备".在手机以外的土壤 ...

  2. 简单教教大家如何移植MIUI。(仅供参考)!!!

    此教程仅介绍如何移植MIUI,原理方面的东西不会涉及太多,主要是因为我对原理方面的东西也不是很懂,怕误导了大家. 我以移植MIUI到Incredible为例子: 接下来我们正式讲如何移植MIUI.An ...

  3. [ROM] 【技术帖】MIUI移植的简单方法 [转载]

    [ROM] [技术帖]MIUI移植的简单方法 [转载] 此教程仅介绍如何移植MIUI,原理方面的东西不会涉及太多,主要是因为我对原理方面的东西也不是很懂,怕误导了大家. 我以移植MIUI到Incred ...

  4. linux怎么移植安卓rom,【经验技巧】任意手机移植ROM 教程,超详细ROM 技术详细......

    在刷机时,我们大多使用zip格式的升级包进行刷机 那zip格式的升级包是怎么样的一个组成呢? 如图:这是一个zip升级包的完整构造 其中我们要移植所需要修改的就是META-INF里的刷机脚本* G# ...

  5. android手机各大分区详解

    1. bootloader 当我们拿到一款手机,第一件事应该就是按下电源键开机,那么从开机到进入到桌面程序这中间发生了些什么呢,我们从下面这张简化了的手机结构图开始:   注意:该结构图并不反映手机的 ...

  6. android分区知识,特别的recovery分区的构成

    第一部分,android的分区构成 1,分区介绍第二篇 1. bootloader   当我们拿到一款手机,第一件事应该就是按下电源键开机,那么从开机到进入到桌面程序这中间发生了些什么呢,我们从下面这 ...

  7. android各个分区详解

    1. bootloader   当我们拿到一款手机,第一件事应该就是按下电源键开机,那么从开机到进入到桌面程序这中间发生了些什么呢,我们从下面这张简化了的手机结构图开始: 注意:该结构图并不反映手机的 ...

  8. android:手机各大分区详解

    http://blog.sina.com.cn/s/blog_6b83d8000101i5u3.html 1. bootloader 当我们拿到一款手机,第一件事应该就是按下电源键开机,那么从开机到进 ...

  9. android各分区大小,扫盲:安卓系统各大分区介绍1

    1. bootloader 当我们拿到一款手机,第一件事应该就是按下 电源键开机,那么从开机到进入到桌面程序这中 间发生了些什么呢, 大 家可以简单的把手机的ROM存储类比为我 们电脑上的硬盘,这个硬 ...

  10. 安卓刷机包 各个文件夹的作用

    META-INF 这里面主要是签名文名和刷机时执行的脚本(updater-script),移植时,我们主要要更改的就是刷机的脚本. system 这里面就是android的系统部分 app 这里存放的 ...

最新文章

  1. 40个方法优化你的PHP
  2. 【C 语言】二级指针作为输入 ( 指针数组 | 将 二级指针 作为函数输入 | 抽象函数业务逻辑 )
  3. 最好用的日志分析工具ELK
  4. python中的基本数据结构
  5. Python 列表 append()函数使用详解
  6. dsp广告和信息流广告区别_信息流广告和sem广告有哪些区别2021?
  7. “MySQL 服务正在启动 . MySQL 服务无法启动。 服务没有报告任何错误。”的解决方案
  8. kNN(k-nearest-neighbor)算法的Python实现
  9. Canvas旋转元素
  10. java batik svg_java使用batik转换svg文件
  11. 如何卸载 STEP 7-MicroWIN编程软件?
  12. 【2】使用MATLAB进行机器学习(回归)
  13. ios safari 模拟器_电脑也能运行iOS iOS模拟器体验
  14. 计算机节熊测试报告,PWC170机能实验.pptx
  15. 人工智能顶级会议与国际期刊总结
  16. 游戏数据库数据管理系统开发体会
  17. 她全奖赴海外读博,一作发Science,毅然回国后任东南大学教授!
  18. [ASP.NET MVC 小牛之路]16 - Model 验证
  19. 当我知道这些网址以后,我后悔以前没有好好学
  20. 如何成为一个高级java程序员

热门文章

  1. The system proxy was changed. Click to reenable capturing.
  2. 便利店卷疯了:便利蜂、罗森、易捷“激战”
  3. python自动化测试课程学费一般多少 学习方式不同,价格也会存在差异
  4. aven 项目 pom.xml 第一行报错 Unknow。。。。。。。解决办法
  5. 敏捷团队的病与药:阿里健康医药B2B团队敏捷转型手记
  6. ABOV(12) UART
  7. linux小记 查看dd进度,linux小记:查看dd进度
  8. button layui-btn 色调
  9. Feature Enhancement Network: A Refined Scene Text Detector
  10. android平板电脑卡槽在哪,外观|增加SIM卡槽_酷比魔方 IWORK8_平板电脑评测-中关村在线...