Adnroid Precovery升级Map of '@/cache/recovery/block.map’failed问题分析指南
前言
自从Android 4.4将SELinux加入Android以后,这个东西虽然说有了安全但是在开发中经常会遇到一些莫名其妙的问题,本篇今天要说的就是就是由于SELinux规则问题导致的Map of '@/cache/recovery/block.map’failed无法升级问题。
注意:本篇讲解的代码是在Android P 高通8953平台。
一.问题复盘
随着android版本升级,升级包越来越大,当升级包无法存储在cache分区的时候,会把升级包下载到data分区,然后从data分区升级,最近从data分区加载升级包升级的时候,遇到了如下错误,这个错误可以在升级失败以后在/cache/recovery/last_log中查看,具体日志如下:
[ 0.000179] __bionic_open_tzdata: couldn't find any tzdata when looking for Asia/Shanghai! [ 0.000238] Starting recovery (pid 387) on Thu Jan 1 05:28:26 1970 [ 0.001760] recovery filesystem table [ 0.001783] ========================= [ 0.001789] 0 /vendor ext4 /dev/block/platform/soc/7824900.sdhci/by-name/vendor 0 [ 0.001794] 1 / ext4 /dev/block/bootdevice/by-name/system 0 [ 0.001799] 2 /cache ext4 /dev/block/bootdevice/by-name/cache 0 [ 0.001804] 3 /vendor ext4 /dev/block/bootdevice/by-name/vendor 0 [ 0.001809] 4 /data ext4 /dev/block/bootdevice/by-name/userdata 0 [ 0.001814] 5 /sdcard vfat /dev/block/mmcblk1p1 0 [ 0.001819] 6 /boot emmc /dev/block/bootdevice/by-name/boot 0 [ 0.001823] 7 /recovery emmc /dev/block/bootdevice/by-name/recovery 0 [ 0.001828] 8 /misc emmc /dev/block/bootdevice/by-name/misc 0 [ 0.001833] 9 /tmp ramdisk ramdisk 0 [ 0.001837] [ 0.003088] I:Boot command: boot-recovery [ 0.003104] I:Got 3 arguments from boot message [ 0.047245] locale is [zh-CN] [ 0.047297] stage is [] [ 0.047321] reason is [(null)] [ 0.047981] W:Failed to read max brightness: No such file or directory [ 0.048017] I:Screensaver disabled [ 0.049631] cannot find/open a drm device: No such file or directory [ 0.050030] fb0 reports (possibly inaccurate): [ 0.050049] vi.bits_per_pixel = 32 [ 0.050055] vi.red.offset = 0 .length = 8 [ 0.050060] vi.green.offset = 8 .length = 8 [ 0.050065] vi.blue.offset = 16 .length = 8 [ 0.064662] framebuffer: 0 (1920 x 1080) [ 0.515251] erasing_text: zh (81 x 38 @ 5031) [ 0.527722] no_command_text: zh (111 x 38 @ 5031) [ 0.538287] error_text: zh (65 x 38 @ 5031) [ 0.993697] installing_text: zh (222 x 38 @ 5922) [ 1.023212] SELinux: Loaded file_contexts [ 1.023333] Command: "/sbin/recovery" "--update_package=@/cache/recovery/block.map" "--locale=zh-CN" [ 1.152498] I:Update location: @/cache/recovery/block.map [ 1.152563] Opening update package... [ 1.185800] E:Failed to read /cache/recovery/block.map: No such file or directory [ 1.202350] E:Map of '@/cache/recovery/block.map' failed
[ 1.235591] E:failed to map file
[ 1.280567] W:Failed to read /sys/class/thermal/thermal_zone53/temp: Invalid argument
[ 1.280665] W:Failed to read /sys/class/thermal/thermal_zone52/temp: Invalid argument
[ 1.280730] W:Failed to read /sys/class/thermal/thermal_zone51/temp: Invalid argument
[ 1.280872] W:Failed to read /sys/class/thermal/thermal_zone49/temp: No such device
[ 1.280936] W:Failed to read /sys/class/thermal/thermal_zone48/temp: No such device
[ 1.281001] W:Failed to read /sys/class/thermal/thermal_zone47/temp: No such device
[ 1.281064] W:Failed to read /sys/class/thermal/thermal_zone46/temp: Invalid argument
[ 1.281127] W:Failed to read /sys/class/thermal/thermal_zone45/temp: Invalid argument
[ 1.287659] I:current maximum temperature: 90000
[ 1.287840] I:@/cache/recovery/block.map
[ 1.287866] I:0
[ 1.287889] I:time_total: 0
[ 1.287911] I:retry: 0
[ 1.287933] I:error: 26
[ 1.287955] I:uncrypt_time: 0
[ 1.287977] I:uncrypt_error: 117
[ 1.287999] I:temperature_start: 90000
[ 1.288021] I:temperature_end: 90000
[ 1.288043] I:temperature_max: 90000
[ 1.288065] I:
[ 1.288093] Installation aborted.
[ 1.303354] Mounted /cache/pax-recovery
[ 1.336868] mkdir /cache/pax-recovery error[File exists]
[ 1.356593] Recovery install reason=update_package result=fail on Thu Jan 1 05:28:27 1970
[ 1.356622] !
[ 6.421470] I:Saving locale "zh-CN"
其中关键点信息如下:
[ 1.185800] E:Failed to read /cache/recovery/block.map: No such file or directory
[ 1.202350] E:Map of '@/cache/recovery/block.map' failed
[ 1.235591] E:failed to map file
根据关键点信息去终端cache分区下查找是否存在该文件, 结果如下:
130|msm8953_64:/cache/recovery # ls -l
total 448
-rw------- 1 root root 277 2020-05-12 17:48 block.map
-rw-r--r-- 1 root root 271 1970-01-02 15:42 last_install
-rw------- 1 system system 368240 1970-01-02 15:42 last_kmsg
-rw------- 1 root root 5 1970-01-02 15:42 last_locale
-rw------- 1 system system 38 2020-05-12 17:47 uncrypt_file
果真不存在,这个就是问题关键了。
二.解决问题
我们我们追寻重启进入recovery之前的log信息,通过logcat -b events | grep avc查看,日志如下所示:
[ 1212.869820@3] type=1400 audit(1209.144:3355): avc: denied { setattr } for pid=4433 comm="Thread-3" name="uncrypt_file" dev="mmcblk0p32" ino=13 scontext=u:r:system_app:s0 tcontext=u:object_r:cache_recovery_file:s0 tclass=file permissive=0
[ 1212.885402@3] type=1400 audit(1212.820:3356): avc: denied { getattr } for pid=4501 comm="uncrypt" path="/data/cache" dev="mmcblk0p65" ino=19 scontext=u:r:uncrypt:s0 tcontext=u:object_r:cache_file:s0 tclass=dir permissive=0
[ 1212.906032@2] watchdogd: watchdogd started (interval 10, margin 20)!
[ 1212.906143@2] watchdogd: Failed to open /dev/watchdog: No such file or directory
从日志很明显的可以看到处理/data与/cache分区时候遇到了SELinux权限问题。(mmcblk0p32和mmcblk0p65对应的分别是cache与data分区),对应关系可以在终端下面通过如下方式查询:
130|msm8953_64:/dev/block/by-name # ls -l | grep cache
lrwxrwxrwx 1 root root 21 1970-01-01 08:00 cache -> /dev/block/mmcblk0p32
msm8953_64:/dev/block/by-name # ls -l | grep data
lrwxrwxrwx 1 root root 21 1970-01-01 08:00 userdata -> /dev/block/mmcblk0p65
msm8953_64:/dev/block/by-name #
找到了问题的根本点就好办了,我们只需要为升级的应用和recovery赋予相应的SELinux权限即可,但是上面遇到SELinux权限就没有继续了,我们需要知道所有需要的SELinux权限,那么我们把SELinux设置为 permissive 状态,然后再升级一次,我们观察log状态:
[ 98.295965@1] type=1400 audit(84.812:43): avc: denied { open } for pid=2890 comm="HwBinder:2890_1" path="/sys/module/tvin_hdmirx/parameters/en_4k_2_2k" dev="sysfs" ino=6874 scontext=u:r:system_control:s0 tcontext=u:object_r:sysfs_cec:s0 tclass=file permissive=1
[ 98.313718@1] type=1400 audit(98.244:44): avc: denied { remove_name } for pid=4076 comm="Thread-4" name="update.zip" dev="mmcblk0p65" ino=316 scontext=u:r:system_app:s0 tcontext=u:object_r:cache_file:s0 tclass=dir permissive=1
[ 98.333696@1] type=1400 audit(98.244:44): avc: denied { remove_name } for pid=4076 comm="Thread-4" name="update.zip" dev="mmcblk0p65" ino=316 scontext=u:r:system_app:s0 tcontext=u:object_r:cache_file:s0 tclass=dir permissive=1
[ 98.353378@1] type=1400 audit(98.244:45): avc: denied { unlink } for pid=4076 comm="Thread-4" name="update.zip" dev="mmcblk0p65" ino=316 scontext=u:r:system_app:s0 tcontext=u:object_r:cache_file:s0 tclass=file permissive=1
[ 98.373096@1] type=1400 audit(98.244:45): avc: denied { unlink } for pid=4076 comm="Thread-4" name="update.zip" dev="mmcblk0p65" ino=316 scontext=u:r:system_app:s0 tcontext=u:object_r:cache_file:s0 tclass=file permissive=1
[ 98.392458@1] type=1400 audit(98.304:46): avc: denied { read } for pid=4076 comm="Thread-4" path="/data/cache/update.zip" dev="mmcblk0p65" ino=316 scontext=u:r:system_app:s0 tcontext=u:object_r:cache_file:s0 tclass=file permissive=1
[ 98.618368@2] success set parent gpu_p1_composite rate to 500000000
[ 99.302385@1] success set parent gpu_p0_composite rate to 400000000
[ 100.074360@1] success set parent gpu_p1_composite rate to 285714285
[ 101.234329@3] success set parent gpu_p0_composite rate to 125000000
[ 101.344037@0] aml_snd_card_tv aml_snd_tv: I2S playback disable
[ 101.344244@0] aml_snd_card_tv aml_snd_tv: IEC958 playback disable
[ 120.075238@1] type=1400 audit(98.304:46): avc: denied { read } for pid=4076 comm="Thread-4" path="/data/cache/update.zip" dev="mmcblk0p65" ino=316 scontext=u:r:system_app:s0 tcontext=u:object_r:cache_file:s0 tclass=file permissive=1
[ 120.090346@1] type=1400 audit(120.024:47): avc: denied { setattr } for pid=4076 comm="Thread-4" name="uncrypt_file" dev="mmcblk0p32" ino=13 scontext=u:r:system_app:s0 tcontext=u:object_r:cache_recovery_file:s0 tclass=file permissive=1
[ 121.326417@0] success set parent gpu_p1_composite rate to 666666666
[ 121.734307@0] success set parent gpu_p0_composite rate to 500000000
[ 121.897440@1] BT_RADIO going: off
[ 121.897470@1] BCM_BT: going OFF
[ 122.342361@2] success set parent gpu_p1_composite rate to 400000000
[ 123.438484@0] success set parent gpu_p0_composite rate to 285714285
[ 123.556904@1] type=1400 audit(120.024:47): avc: denied { setattr } for pid=4076 comm="Thread-4" name="uncrypt_file" dev="mmcblk0p32" ino=13 scontext=u:r:system_app:s0 tcontext=u:object_r:cache_recovery_file:s0 tclass=file permissive=1
[ 123.572107@1] type=1400 audit(123.508:48): avc: denied { getattr } for pid=4211 comm="uncrypt" path="/data/cache" dev="mmcblk0p65" ino=19 scontext=u:r:uncrypt:s0 tcontext=u:object_r:cache_file:s0 tclass=dir permissive=1
[ 123.591568@1] type=1400 audit(123.508:48): avc: denied { getattr } for pid=4211 comm="uncrypt" path="/data/cache" dev="mmcblk0p65" ino=19 scontext=u:r:uncrypt:s0 tcontext=u:object_r:cache_file:s0 tclass=dir permissive=1
[ 123.610598@1] type=1400 audit(123.508:49): avc: denied { getattr } for pid=4211 comm="uncrypt" path="/data/cache/update.zip" dev="mmcblk0p65" ino=316 scontext=u:r:uncrypt:s0 tcontext=u:object_r:cache_file:s0 tclass=file permissive=1
[ 123.631453@1] type=1400 audit(123.508:49): avc: denied { getattr } for pid=4211 comm="uncrypt" path="/data/cache/update.zip" dev="mmcblk0p65" ino=316 scontext=u:r:uncrypt:s0 tcontext=u:object_r:cache_file:s0 tclass=file permissive=1
[ 123.652217@1] type=1400 audit(123.512:50): avc: denied { read } for pid=4211 comm="uncrypt" name="update.zip" dev="mmcblk0p65" ino=316 scontext=u:r:uncrypt:s0 tcontext=u:object_r:cache_file:s0 tclass=file permissive=1
[ 123.672583@1] type=1400 audit(123.512:50): avc: denied { read } for pid=4211 comm="uncrypt" name="update.zip" dev="mmcblk0p65" ino=316 scontext=u:r:uncrypt:s0 tcontext=u:object_r:cache_file:s0 tclass=file permissive=1
[ 123.689809@1] type=1400 audit(123.512:51): avc: denied { open } for pid=4211 comm="uncrypt" path="/data/cache/update.zip" dev="mmcblk0p65" ino=316 scontext=u:r:uncrypt:s0 tcontext=u:object_r:cache_file:s0 tclass=file permissive=1
[ 124.950389@3] success set parent gpu_p1_composite rate to 125000000
这就简单了,添加对应的SELinux规则即可,关于SELinux的学习大家可以参阅博客Android SELinux开发入门指南,这里就不对SELinux的规则做过多的细述了,附上修改好的git提交记录:
diff --git a/device/qcom/sepolicy/private/paxdroid_share_file.te b/device/qcom/sepolicy/private/paxdroid_share_file.te
index ea24edb..72f043d 100755
--- a/device/qcom/sepolicy/private/paxdroid_share_file.te
+++ b/device/qcom/sepolicy/private/paxdroid_share_file.te
@@ -31,5 +31,11 @@ allow PortPlugInit11 paxdroid_share_file:file { create write setattr relabelfrom
allow { auth_bpadownload posprintupdate} paxdroid_share_file:dir { open search write create add_name remove_name setattr relabelfrom relabelto append unlink link rename getattr};
allow { auth_bpadownload posprintupdate} paxdroid_share_file:file { create write setattr relabelfrom relabelto append rename open getattr read lock };
-allow {zygote bluetooth} paxdroid_share_file:file {rw_file_perms};
-allow {zygote bluetooth} paxdroid_share_file:dir {rw_dir_perms};
+allow {zygote bluetooth uncrypt} paxdroid_share_file:file {rw_file_perms};
+allow {zygote bluetooth uncrypt} paxdroid_share_file:dir {rw_dir_perms};
+
+allow system_app cache_file:dir { search add_name remove_name write };
+allow system_app cache_file:file { create getattr open write unlink read };
+
+allow uncrypt cache_file:dir getattr;
+allow uncrypt cache_file:file { open read getattr };
其中paxdroid_share_file.te 是我们添加的策略文件,如果童靴真的有遇到了这个问题请根据实际情况进行策略的添加。好了编译策略文件,重试OK了。看看recovery的升级成功记录如下,在/cache/recovery/last_log查看,内容太多了我只截取了一部分。
[ 0.000181] __bionic_open_tzdata: couldn't find any tzdata when looking for Asia/Shanghai! [ 0.000238] Starting recovery (pid 383) on Fri Jan 2 07:41:18 1970 [ 0.001824] recovery filesystem table [ 0.001851] ========================= [ 0.001857] 0 /vendor ext4 /dev/block/platform/soc/7824900.sdhci/by-name/vendor 0 [ 0.001862] 1 / ext4 /dev/block/bootdevice/by-name/system 0 [ 0.001867] 2 /cache ext4 /dev/block/bootdevice/by-name/cache 0 [ 0.001872] 3 /vendor ext4 /dev/block/bootdevice/by-name/vendor 0 [ 0.001877] 4 /data ext4 /dev/block/bootdevice/by-name/userdata 0 [ 0.001882] 5 /sdcard vfat /dev/block/mmcblk1p1 0 [ 0.001886] 6 /boot emmc /dev/block/bootdevice/by-name/boot 0 [ 0.001891] 7 /recovery emmc /dev/block/bootdevice/by-name/recovery 0 [ 0.001896] 8 /misc emmc /dev/block/bootdevice/by-name/misc 0 [ 0.001901] 9 /tmp ramdisk ramdisk 0 [ 0.001905] [ 0.003103] I:Boot command: boot-recovery [ 0.003121] I:Got 3 arguments from boot message [ 0.057346] locale is [zh-CN] [ 0.057379] stage is [] [ 0.057385] reason is [(null)] [ 0.057390] W:Failed to read max brightness: No such file or directory [ 0.057395] I:Screensaver disabled [ 0.058859] cannot find/open a drm device: No such file or directory [ 0.059139] fb0 reports (possibly inaccurate): [ 0.059150] vi.bits_per_pixel = 32 [ 0.059156] vi.red.offset = 0 .length = 8 [ 0.059161] vi.green.offset = 8 .length = 8 [ 0.059166] vi.blue.offset = 16 .length = 8 [ 0.072937] framebuffer: 0 (1920 x 1080) [ 0.521428] erasing_text: zh (81 x 38 @ 5031) [ 0.533880] no_command_text: zh (111 x 38 @ 5031) [ 0.544223] error_text: zh (65 x 38 @ 5031) [ 0.998365] installing_text: zh (222 x 38 @ 5922) [ 1.029506] SELinux: Loaded file_contexts [ 1.029631] Command: "/sbin/recovery" "--update_package=@/cache/recovery/block.map" "--locale=zh-CN" [ 88.676745] wrote 129279 blocks; expected 129279 [ 88.676811] stashed 0 blocks [ 88.676840] max alloc needed was 4096 [ 88.676930] deleting stash 34a21d3b3dc53f7084ea0b7f275c179b3062f9be [ 90.216571] Patching firmware images... [ 90.217492] prepare_partitions: Preparing for primary partition update [ 90.217700] 'apdp' partition not backup - skip safe update [ 90.217744] 'keystore' partition not backup - skip safe update [ 90.217795] 'msadp' partition not backup - skip safe update [ 90.217825] 'mdtp' partition not backup - skip safe update [ 90.217860] 'dsp' partition not backup - skip safe update
[ 90.375081] prepare_partitions: Preparing for backup partition update
[ 90.543922] prepare_partitions: Finalizing partitions
[ 90.601289]
[ 90.854443] W:Failed to read /sys/class/thermal/thermal_zone53/temp: Invalid argument
[ 90.854541] W:Failed to read /sys/class/thermal/thermal_zone52/temp: Invalid argument
[ 90.854606] W:Failed to read /sys/class/thermal/thermal_zone51/temp: Invalid argument
[ 90.854752] W:Failed to read /sys/class/thermal/thermal_zone49/temp: No such device
[ 90.854818] W:Failed to read /sys/class/thermal/thermal_zone48/temp: No such device
[ 90.854883] W:Failed to read /sys/class/thermal/thermal_zone47/temp: No such device
[ 90.854946] W:Failed to read /sys/class/thermal/thermal_zone46/temp: Invalid argument
[ 90.855009] W:Failed to read /sys/class/thermal/thermal_zone45/temp: Invalid argument
[ 90.861607] I:current maximum temperature: 90277
[ 90.861798] I:@/cache/recovery/block.map
[ 90.861823] I:1
[ 90.861846] I:time_total: 89
[ 90.861868] I:retry: 0
[ 90.861890] I:target_build: 57
[ 90.861913] I:bytes_written_system: 1574789120
[ 90.861935] I:bytes_stashed_system: 0
[ 90.861956] I:bytes_written_vendor: 529526784
[ 90.861978] I:bytes_stashed_vendor: 0
[ 90.862000] I:uncrypt_time: 20
[ 90.862022] I:temperature_start: 90555
[ 90.862043] I:temperature_end: 90277
[ 90.862065] I:temperature_max: 90555
[ 90.862087] I:
[ 90.862308] Mounted /cache/pax-recovery
[ 90.882512] mkdir /cache/pax-recovery error[File exists]
[ 90.902829] Recovery install reason=update_package result=success on Fri Jan 2 07:42:48 1970
[ 90.902859] !
[ 90.948791] I:Saving locale "zh-CN"
升级成功以后/cache/recovery 的目录结构如下:
msm8953_64:/cache/recovery # ls -l
total 448
-rw------- 1 root root 277 2020-05-12 17:48 block.map
-rw-r--r-- 1 root root 271 1970-01-02 15:42 last_install
-rw------- 1 system system 368240 1970-01-02 15:42 last_kmsg
-rw------- 1 root root 5 1970-01-02 15:42 last_locale
-rw-r----- 1 root root 49067 1970-01-02 15:42 last_log
-rw------- 1 system system 38 2020-05-12 17:47 uncrypt_file
结语
好了,这个问题没有多说的了,强调一点如果真的遇到这个问题了,一定要通过logcat -b events | grep avc一步步查看权限问题,然后添加对应权限即可。
写在最后
各位读者看官朋友们,Android P recovery升级Map of ‘@/cache/recovery/block.map’ failed问题分析指南已经全部完毕,不多说什么了。在最后麻烦读者朋友们如果本篇对你有帮助,关注和点赞一下,当然如果有错误和不足的地方也可以拍砖。