0%

Google OTA下载完升级包后无法进入Recovery模式

Android版本 7.0
平台 MT6755

问题简介

预置了客户提供的Google OTA后,能下载升级包,但是下载完成后无法自动重启进入Recovery模式安装升级包。

分析过程

首先打印log:

1
adb logcat | grep GoogleOta

发现如下一条可疑的信息:

1
GoogleOta: HttpManager:engine error to set flag to reboot into recovery mode.

这应该是GoogleOta.apk中打印出来的,要想进一步判定问题,需要源码,所以尝试反编译GoogleOta.apk,很幸运,能够反编译,并且没有混淆代码。
因为上面那句log还有一个“HttpManager”标签,所以尝试搜索HttpManager文件:

1
2
segon:GoogleOta$ find -name HttpManager.smali
./smali/com/mediatek/GoogleOta/HttpManager.smali

找到了,在HttpManager.smali文件中找一下log中的关键字,能找到,这里是直接赋值的英文字串而不是通过getString()获取的:

1
const-string v7, "engine error to set flag to reboot into recovery mode."

下面我们来看分析一下这句log所在的方法的代码,下面是简要翻译成Java后的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public void resetDescriptionInfo() {
logInfo("HttpManager:", "onSetRebootRecoveryFlag");
GoogleOtaBinder agent = GoogleOtaBinder.Stub.asInterface(ServiceManager.getService("GoogleOtaBinder"));
if (agent == null) {
// 绑定服务失败就会打印出此log
logInfo("HttpManager:", "engine error to set flag to reboot into recovery mode.");
} else {
Boolean ret = agent.setRebootFlag();
logInfo("HttpManager:", "setRebootFlag() return = " + ret);
Intent intent = new Intent();
intent.setComponent(
new ComponentName("com.mediatek.systemupdate.sysoper",
"com.mediatek.systemupdate.sysoper.WriteCommandService"));
intent.putExtra("COMMANDPART2", getPackageFileName());
try{
mContext.startService(intent);
} catch (Exception e){
// ...
}
}
}

好了,现在我们知道是绑定”GoogleOtaBinder”失败了,为什么呢?我们先看看手机中”GoogleOtaBinder”服务是否有启动:

1
adb shell ps | grep GoogleOtaBinder

结果为空,那么就说明”GoogleOtaBinder”没有起来,继续往下分析,我们知道,像启动这种服务,一般是在init.rc或者init.xxx.rc中起来,检查一下init.xxx.rc中,有配置:

1
2
3
4
service GoogleOtaBinder /system/bin/GoogleOtaBinder     
class main
user root
group root

估计是服务启动的时候出了什么问题,打开mtklog,重新开机抓log,然后我们grep一下”GoogleOtaBinder”,在kernel_log找到了如下一句关键log:

1
[1:init]init: Service GoogleOtaAgent does not have a SELinux domain defined.

关于这个错误,MTK Online上有解释:
FAQ14743 init 启动 Native Service 时出现Service xxxx needs a SELinux domain defined; please fix 警告的说明

开始以为是没有GoogleOtaBinder.te,可以查找以后,该有的都有:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ grep -r GoogleOtaBinder device/
device/mediatek/mt6735/device.mk:PRODUCT_PACKAGES += GoogleOtaBinder
device/mediatek/mt6735/init.mt6735.rc:service GoogleOtaAgent /vendor/bin/GoogleOtaBinder
device/mediatek/common/sepolicy/bsp/GoogleOtaBinder.te:# Policy File of /system/binGoogleOtaBinder Executable File
device/mediatek/common/sepolicy/bsp/GoogleOtaBinder.te:type GoogleOtaBinder_exec , exec_type, file_type;
device/mediatek/common/sepolicy/bsp/GoogleOtaBinder.te:type GoogleOtaBinder ,domain, domain_deprecated;
device/mediatek/common/sepolicy/bsp/GoogleOtaBinder.te:#permissive GoogleOtaBinder;
device/mediatek/common/sepolicy/bsp/GoogleOtaBinder.te:init_daemon_domain(GoogleOtaBinder)
device/mediatek/common/sepolicy/bsp/GoogleOtaBinder.te:#unconfined_domain(GoogleOtaBinder)
device/mediatek/common/sepolicy/bsp/GoogleOtaBinder.te:binder_use(GoogleOtaBinder)
device/mediatek/common/sepolicy/bsp/GoogleOtaBinder.te:binder_service(GoogleOtaBinder)
...
device/mediatek/common/sepolicy/bsp/file_contexts:/(system\/vendor|vendor)/bin/GoogleOtaBinder u:object_r:GoogleOtaBinder_exec:s0
device/mediatek/common/sepolicy/bsp/service_contexts:GoogleOtaBinder u:object_r:ota_agent_service:s0
device/mediatek/common/sepolicy/bsp/dumpstate.te:allow dumpstate GoogleOtaBinder:binder call;
device/mediatek/common/sepolicy/bsp/shell.te:allow shell GoogleOtaBinder_exec:file rx_file_perms;

到底哪里出问题了呢?看一下GoogleOtaBinder的security context属性吧:

1
2
$ adb shell ls -Z /system/bin/GoogleOtaBinder
u:object_r:system_file:s0 system/bin/GoogleOtaBinder

咦,不对啊,在file_contexts定义是这样的:

1
device/mediatek/common/sepolicy/bsp/file_contexts:/(system\/vendor|vendor)/bin/GoogleOtaBinder u:object_r:GoogleOtaBinder_exec:s0

也就是说GoogleOtaBinder的type应该是GoogleOtaBinder_exec但是现在却是system_file,然后再仔细看看file_contexts的定义,路径居然是system/vendor/bin/GoogleOtaBinder或者vendor/bin/GoogleOtaBinder,而当前版本中GoogleOtaBinder的路径是/system/bin/GoogleOtaBinder,原来问题出在这里,将GoogleOtaBinder编译到system/vendor/bin/GoogleOtaBinder这个路径后,验证一下,问题解决了,能自动重启进入Recovery模式了。