给Pixel 7/7 Pro添加32位apk支持
很早就有传闻,Pixel 7将会是第一台纯64位Android设备,不能安装纯32位apk,笔者也拿到了一台美版Pixel 7,就尝试了一下,发现确实无法安装32位apk:

提示ISNTALL_FAILED_NO_MATCHING_ABIS,我们getporp看一下abi:
panther:/ $ getprop | grep abi
[ro.product.cpu.abi]: [arm64-v8a]
[ro.product.cpu.abilist]: [arm64-v8a]
[ro.product.cpu.abilist32]: []
[ro.product.cpu.abilist64]: [arm64-v8a]
panther:/ $ getprop | grep zygote
[ro.zygote]: [zygote64]
可以看到,abilist32是空的,整个手机只支持64位ABI,zygote使用的是zygote64,因此导致装不上。
同样的,对比一下Pixel 6的情况,发现Pixel 6是支持的:
oriole:/ $ getprop | grep abi
[ro.product.cpu.abi]: [arm64-v8a]
[ro.product.cpu.abilist]: [arm64-v8a,armeabi-v7a,armeabi]
[ro.product.cpu.abilist32]: [armeabi-v7a,armeabi]
[ro.product.cpu.abilist64]: [arm64-v8a]
oriole:/ $ getprop | grep zygote
[ro.zygote]: [zygote64_32]
支持了完整的armeabi-v7a和armeabi。并且使用的zygote是zygote64_32,可以支持32位apk。
进一步测试发现,Pixel 7设备中,存在32位lib目录,和app_process32(zygote32)程序,因为abilist中没有32位ABI,因此32位的zygote没有启动,实测也可以运行ELF32程序。
这就说明了,Pixel 7实际上只是系统层面限制不让安装,实际上32位native支持是完整的,那么,如果要让Pixel 7可以安装32位apk,是不是把abilist中的prop加回去就可以了呢?经过笔者一番折腾测试,发现是可行的。这里给出两个方案:
方案一:修改vendor.img中的build.prop文件刷机
经过最后确认,Pixel 7的ro.product.cpu.abilist属性是init进程通过读取/vendor/build.prop中的ro.vendor.product.cpu.abilist设置的,因此需要修改vendor.img,在这里给出修改方法:
首先去Google官方https://developers.google.com/android/images下载一份和手机中Build版本相同的刷机包,解压,从中得到vendor.img和vbmeta_vendor.img文件vendor.img,vbmeta.img,和vbmeta_vendor.img文件。接下来修改vendor.img中的build.prop
$ file vendor.img
vendor.img: Linux rev 1.0 ext2 filesystem data, UUID=defad607-7fa7-5dc3-8ba5-b7843eb7d85d, volume name "vendor" (extents) (large files) (huge files)
这里看起来刷机包里面的vendor.img不是spare image,直接就是ext文件系统了,那试试直接挂载:
$ sudo mount vendor.img /mnt/test
mount: /mnt/test: wrong fs type, bad option, bad superblock on /dev/loop16, missing codepage or helper program, or other error.
直接挂载失败,查看dmesg,发现失败原因是:
EXT4-fs (loop16): couldn’t mount RDWR because of unsupported optional features (4000)
网上搜了一下feature 0x4000是什么。
#define EXT4_FEATURE_RO_COMPAT_SHARED_BLOCKS 0x4000
通过一番测试发现,vendor可以挂载为ro,但是一旦挂载为rw,就会提示上面的错误
sudo mount -t ext4 -o loop,ro vendor.img /mnt/test #成功
sudo mount -t ext4 -o loop,rw vendor.img /mnt/test #失败
通过tun2fs查看,确实vendor.img比可以挂载为rw的ext4镜像多了一个shared_blocks feature。
$ tune2fs -l vendor.img | grep feat
Filesystem features: ext_attr dir_index filetype extent sparse_super large_file huge_file uninit_bg dir_nlink extra_isize shared_blocks
那有没有办法去掉这个feature呢?经过了一番搜索,网上大多数人也都碰到这样的问题,但最后都没有什么特别的解决办法,找了很长时间终于在一个systemrw的项目里找到了一个可用的方法,就是用e2fsck -E unshare_block命令去掉feature,下面说过程。
首先将镜像文件扩容,否则在后面的操作中,会因为镜像没有空间而失败,我这里的vendor.img大小是665M,因为我们只需要改build.prop,稍微扩大一点就行,我这里给了670M。
fallocate -l 670M vendor.img
接下来对镜像进行操作,解除shared_blocks feature:
e2fsck -yf vendor.img
resize2fs vendor.img 670M
e2fsck -y -E unshare_blocks vendor.img
正常来说的话,这样就去掉了vendor.img的shared_blocks特性,我们重新用tun2fs看一下:
$ tune2fs -l vendor.img | grep feat
Filesystem features: ext_attr dir_index filetype extent sparse_super large_file huge_file uninit_bg dir_nlink extra_isize
可以看到果然已经去掉了,现在尝试挂载,就可以成功挂载为rw了:
sudo mount -t ext4 -o loop,rw vendor.img /mnt/test
然后接下来我们修改build.prop文件,只需要修改如下几行就可以:
ro.vendor.product.cpu.abilist=arm64-v8a,armeabi-v7a,armeabi #在后面加上armeabi-v7a,armeabi
ro.vendor.product.cpu.abilist32=armeabi-v7a,armeabi #加上32位abi支持
ro.vendor.product.cpu.abilist64=arm64-v8a
ro.zygote=zygote64_32 #zygote64改为zygote64_32
修改完成以后保存:
sudo umount /mnt/test
e2fsck -yf vendor.img
resize2fs -M vendor.img #压缩大小,去掉无用空间
e2fsck -yf vendor.img
然后接下来我们尝试将vendor.img刷回手机。但是这里还需要解决一个问题,就是Pixel 7相比Pixel 6,多了一个vbmeta_vendor分区,也就是说,开机过程中,也会对vendor分区进行校验,如果修改了vendor分区,也会因为校验不通过而无法启动,因此也需要对vbmeta_vendor分区进行patch经过多次测试,需要同时修改vbmeta和vbmeta_vendor(笔者做实验时,对vbmeta,vbmeta_system,vbmeta_vendor都进行了修改),去掉校验,修改vbmeta_vendor.img的第124个字节(其他vbmeta分区修改同理),改成03:(03的含义是disable dm-verity and verification)

然后启动到fastboot进行刷机:(解锁BL的过程教程很多,这里就不多说了)
adb reboot-bootloader
fastboot flash vbmeta vbmeta_patched.img
fastboot flash vbmeta_vendor vbmeta_vendor_patched.img
fastboot flash vbmeta_system vbmeta_system_patched.img #可选
fastboot reboot fastboot #安卓10之后使用了动态分区,vendor分区需要启动到fastbootd才能刷
fastboot flash vendor vendor.img
fastboot reboot
注意事项:
以上刷完之后,很有可能会无法开机,因为当vbmeta/vbmeta_system/vbmeta_vendor这3个分区任何一个修改之后,都需要factory reset才可以正常启动,这一点和解锁BL的时候一样,所以如果碰到无法开机的情况,就进入fastboot尝试清除userdata再尝试开机:
fastboot -w
如果一切顺利的话,启动之后应该就可以看到32位zygote也同时在运行了,getporp查看也应该能看到abilist已经修改,此时应该可以安装32位apk。
panther:/ $ getprop | grep abi
[ro.product.cpu.abi]: [arm64-v8a]
[ro.product.cpu.abilist]: [arm64-v8a,armeabi-v7a,armeabi]
[ro.product.cpu.abilist32]: [armeabi-v7a,armeabi]
[ro.product.cpu.abilist64]: [arm64-v8a]
[ro.vendor.product.cpu.abilist]: [arm64-v8a,armeabi-v7a,armeabi]
[ro.vendor.product.cpu.abilist32]: [armeabi-v7a,armeabi]
[ro.vendor.product.cpu.abilist64]: [arm64-v8a]
panther:/ $ ps -e | grep zygote
root 988 1 14859936 167616 0 0 S zygote64
root 1092 1 1859028 142600 0 0 S zygote
webview_zygote 2194 988 14793052 76512 0 0 S webview_zygote
u0_a171 22742 988 13865996 86540 0 0 S com.android.chrome_zygote
panther:/ $
方案二:使用修改过的Magisk在系统启动过程中修改vendor/build.prop
这个方法适合于已经有Magisk的小伙伴使用,曾经我尝试过使用Magisk Module的resetprop来在启动阶段修改prop,但是失败了,阅读了Magisk源码后发现,magisk在注入init进程后才会加载module,而ro.zygote这属性,加载module之前就已经被init进程读取,因此在后面修改就无效了,所以唯一的办法就是修改magisk本身。
经过一些探索,最后发现只需要修改magisk源码的native/jni/init/rootdir.cpp文件即可,以下给出patch
--- rootdir.cpp 2022-11-13 19:25:15.462486225 +0800
+++ rootdir_patch.cpp 2022-11-13 19:24:28.287059699 +0800
@@ -61,6 +61,62 @@
clone_attr(src, dest);
}
+
+static void patch_pixel7_32bit_prop() {
+ bool isPixel7 = false;
+ if (access("/vendor/build.prop", F_OK) == 0) {
+ xmkdirs(dirname(ROOTOVL "/vendor/build.prop"), 0755);
+ FILE *fprop = xfopen(ROOTOVL "/vendor/build.new.prop", "we");
+ if (!fprop) {
+ PLOGE("%s: open %s failed", __PRETTY_FUNCTION__, "/vendor/build.prop");
+ return;
+ }
+ file_readline("/vendor/build.prop", [&](string_view line)mutable -> bool{
+
+ if (str_contains(line, "Pixel 7")) {
+ isPixel7 = true;
+ }
+
+ if (str_starts(line, "ro.vendor.product.cpu.abilist=")) {
+ LOGD("Patch abilist\n");
+ fprintf(fprop, "ro.vendor.product.cpu.abilist=arm64-v8a,armeabi-v7a,armeabi\n");
+ return true;
+ }
+
+ if (str_starts(line, "ro.vendor.product.cpu.abilist32=")) {
+ LOGD("Patch abilist32\n");
+ fprintf(fprop, "ro.vendor.product.cpu.abilist32=armeabi-v7a,armeabi\n");
+ return true;
+ }
+
+ if (str_starts(line, "ro.zygote=zygote64")) {
+ LOGD("Patch zygote type\n");
+ fprintf(fprop, "ro.zygote=zygote64_32\n");
+ return true;
+ }
+ // Else just write the line
+ fprintf(fprop, "%s", line.data());
+ return true;
+ });
+
+ fclose(fprop);
+
+ if (isPixel7) {
+ rename(ROOTOVL "/vendor/build.new.prop", ROOTOVL "/vendor/build.prop");
+ clone_attr("/vendor/build.prop", ROOTOVL "/vendor/build.prop");
+ } else {
+ int origfile = xopen("/vendor/build.prop", O_RDONLY | O_CLOEXEC);
+ auto vendordata = mmap_data("/vendor/build.prop");
+ int outfile = xopen(ROOTOVL "/vendor/build.prop", O_CREAT | O_WRONLY | O_CLOEXEC, 0);
+ xwrite(outfile, vendordata.buf, vendordata.sz);
+ fclone_attr(origfile, outfile);
+ close(origfile);
+ close(outfile);
+ unlink(ROOTOVL "/vendor/build.new.prop");
+ }
+ }
+}
+
static void load_overlay_rc(const char *overlay) {
auto dir = open_dir(overlay);
if (!dir) return;
@@ -237,6 +293,9 @@
} else {
patch_init_rc("/init.rc", ROOTOVL "/init.rc", tmp_dir.data());
}
+
+ // if it is Pixel 7 Enable 32bit support
+ patch_pixel7_32bit_prop();
// Extract magisk
extract_files(false);
@@ -301,6 +360,8 @@
if ((!treble && access("/sepolicy", F_OK) == 0) || !hijack_sepolicy()) {
patch_sepolicy("/sepolicy", "/sepolicy");
}
+
+
chdir("/");
@@ -333,4 +394,3 @@
execv("/sbin/magisk", argv);
return 1;
}
-
对于伸手党来说,可以直接到这里下载笔者已经编译好的Magisk app,对于已经安装过Magisk的小伙伴来说,只需要安装这个新的Magisk然后直接在app中重新点击安装就可以,或者重新patch init_boot.img然后用fastboot刷入:
使用Magisk同样可以达到目的。
总结
Pixel 7取消掉32位应用支持说明了Google的态度,虽然Pixel 7可以通过一定手段开启,但是可以预见在明年,armv9架构的芯片将物理不支持32位指令集,到那时候将完全不可能支持。因此,建议所有仍然只编译32位库的app尽早迁移到纯64位系统。
鸣谢
感谢ThomasKing大佬提供的思路:https://github.com/ThomasKing2014/Pixel7_32bit_helper
在
老大,第二种方式,安装你的软件不成功,怎么办
米小维
选择安装包解析后安装失败。。。。
Edison
请问刷完软件之后手机变砖,一直重启不能开机是为什么呢。。
Jarvis
所以你用了哪个方案?
Edison
我用的第二个方案,更换回官网面具就恢复正常了
武逗会
用了第二种方法,面具修补,一直卡第二屏,不断重启。
武逗会
估计是系统的原因,14系统一直卡第二屏,退回13系统,用第二种方法,可以正常