上篇记录了我给 LT26i 刷机的过程,现在该是修改它的启动代码了。
这部分内容我折腾了好久,现在把技术细节分享出来。有次我都看到有人明确表示 Sony 的 boot.img 不一样,还亲自做了新的,却没能看到修改方法,实在遗憾。
所有操作都是在 Linux 下完成的。用到的 Windows 软件 WinHex 是可以 wine 的。
解包
Sony Xperia S 使用了自己定制的格式,因此网上流传的split_bootimg.pl
并不能用。Sony 提供了制作这种文件的脚本,但是没有解包的脚本。不过其格式很简单,自己写一个根本不费事:
#!/usr/bin/env python3
# vim:fileencoding=utf-8
import sys
import os
import struct
def getSegNum(f):
f.seek(44)
d = f.read(2)
return struct.unpack('<H', d)[0]
def readSegInfo(f):
d = f.read(32)
info = struct.unpack('<LLLLLLLL', d)
return info[4], info[1] # size, offset
def main(fname, output):
if os.path.isdir(output):
os.rmdir(output)
os.mkdir(output)
f = open(fname, 'rb')
os.chdir(output)
n = getSegNum(f)
f.seek(52)
segs = [readSegInfo(f) for i in range(n)]
for i, seg in enumerate(segs):
f.seek(seg[1])
data = f.read(seg[0])
with open(str(i), 'wb') as wf:
wf.write(data)
if __name__ == '__main__':
if len(sys.argv) != 3:
print('Which file and where to extract?')
else:
main(*sys.argv[1:])
使用方法很简单(至少比 Sony 那个mkelf.py
简单 :-)
unpackelf.py .../android/cm-9.1.0-nozomi/boot.img boot_cm
对于 CyanogenMod,解开的目标目录boot_cm
下会有0
、1
、2
三个文件。使用file
命令便知,initramfs(或称 ramdisk)是1
。解开它很容易:
mkdir ramdisk && cd ramdisk && gunzip < ../1 | cpio -i
对于官方 ROM 也只是多了一个叫3
的文件(它的数据在boot.img
的开始处)。
启动图片
很明显,logo.rle
最有可能是启动图片了。可是,它是什么格式呢?Google 便有了答案。使用那里的 C 程序可将这图片有损地转成 RGB 原始数据。
5652rgb -rle < logo.rle > logo.raw
然后用 ImageMagick 的convert
命令转换成常见图像格式:
convert -depth 8 -size 720x1280 rgb:logo.raw logo.png
-size
那里填上自己的屏幕分辨率。不知道的话就根据屏幕比例和像素数解二元二次方程吧 ^_^ 反正要是转换出来不止一张图片肯定就不对了。
以上是显示启动图片的方法。至于生成的方法嘛,我没有需要就不弄了,直接用 Sony 原生 ROM 里的logo.rle
文件替换之。
换回官方 ROM,安装 recovery
修改完启动图片,我还是不太满意 CyanogenMod 的主题啊之类的,和 Sony 的比起来太丑了。于是又刷了从网上某处找来的「索爱 LT26i 基于6.1.A.1.58最新官方ROM纯净版」。它已经 root 了,但是没有开机时按音量键的恢复模式了。于是我手动修改 initramfs,自己给它加上了。
通过比较和搜索可知,在init.semc.rc
文件中,CyanogenMod 在 early-boot 的时候调用了sbin/bootrec
命令。在官方 ROM 的 330 行那里加上即可。另外一个可以修改的地方是default.prop
文件的ro.debuggable
项,其值改成1
,可以让 adb 使用 root 权限,push/pull 系统文件的时候特别方便。
然后把官方 ROM 的sbin
下没有的文件从 CyanogenMod 那边复制过来即可。注意有大量软链接,可使用cp -ia
来复制。我顺手把sbin/bootrec-device
里的sleep 3
改成只暂停一秒了。这是启动时检测按键以进入恢复模式的等待时间。同时可以看到,这个脚本会将各种指示灯点亮,有兴趣的也可以改改,比如换个指示灯颜色什么的。
打包
首先把文件们弄回 initramfs 里去:
find . | cpio -o -H newc | gzip > ../new_ram
注意这里一定要指定 cpio 的格式为newc,不然启动不了的。
本来,Sony 官方提供的mkelf.py
可以用来打包,对付 CyanogenMod 的 boot.img 足够。但是官方 ROM 多出了一段,因此打包参数不一样。我直接用 WinHex 修改 boot.img 文件了。除了 initramfs 本体之外,还有三处需要修改:initramfs 的长度(两个)、下一个叫「RPM」部分的偏移位置。还好没有 checksum 之类的东西。
弄好后刷回去就可以了。不用担心刷出问题。如果导致不能开机,同时按住开机键和音量上键,直到机身震动一下,然后松开开机键,就进入 bootloader 可以刷回原来的了。
附:Reverse USB Tethering 方法
没有网上说的那么复杂,还网桥什么的,都要把电脑的网络重连 :-(
-
连接 USB 线,启用 USB 绑定
-
电脑上给新出现的
usb0
网络接口配置 IP,IP 段可在手机上使用ip addr
命令查看rndis0
网络接口的地址。比如我这里手机的 IP 是 192.168.42.129,就在电脑上执行
ifconfig usb0 192.168.42.1
-
电脑开启 NAT 功能和 IPv4 转发
echo 1 > /proc/sys/net/ipv4/ip_forward
iptables -t nat -A POSTROUTING -s 192.168.42.0/24 -j MASQUERADE
-
手机上配置路由表
ip route add default via 192.168.42.1 dev rndis0
手机上的route
命令很不一样,总是说参数无效,我没弄明白该怎么用,就用ip
命令了。
注意这样的网络部分功能不认可导致无法使用,比如 TrackID™、VPN。