禁止非法root的设备OTA升级
来源:互联网 发布:内网外网切换软件 编辑:程序博客网 时间:2024/09/21 08:51
一、问题描述:
常常跟OTA打交道的朋友可能会经常遇到客户root后的手机OTA升级失败的问题,如果用户取得root权限,手误破坏了system分区数据,是很有可能导致OTA升级失败的,甚至导致手机无法正常开机,因此为了避免取得root权限的手机ota升级失败导致无法开机的情况,我们在OTA升级前对设备进行root检测,如果发现设备已经root,则禁止手机安装更新。
二、实现方案:
1.修改update_script打包脚本:
/* /bootable/recovery/ota_from_target_files.py */
def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip):
......
script.AssertRootCheck()
script.AssertSomeFingerprint(source_fp, target_fp)
......
/* Edify_generator.py */
def AssertRootCheck(self):
cmd = ('root_check() ||abort("This phone has been root or an error occurred, can not upgrade.");')
cmd = ('root_check() ||abort("This phone has been root or an error occurred, can not upgrade.");')
self.script.append(cmd)
下面是升级过程中recovery相关log:
====== Updater-Script:
mount("ext4", "EMMC", "/dev/block/mmcblk0p6", "/system");
root_check() ||abort("This phone has been root or an error occurred, can not upgrade.");
file_getprop("/system/build.prop", "ro.build.fingerprint") == "***" || file_getprop("/system/build.prop", "ro.build.fingerprint") == "***" || abort("Package expects build fingerprint of *** or ***; this device has " + getprop("ro.build.fingerprint") + ".");
getprop("ro.product.device") == "***" || abort("This package is for \"***\" devices; this is a \"" + getprop("ro.product.device") + "\".");
ui_print("Verifying current system...");
......
如上,脚本第一句是挂载system分区,这是升级前必须要做的动作。之后,在校验fingerprint之前增加了root_check()的动作。这里root_check()是一个接口,该函数的函数体以二进制代码的形式也保存在HOTA包中,供升级时调用。
2.修改安装更新时对应root检测接口root_check()函数:
#define ROOT_SAVE_MAGIC 0x00071029
#define ROOT_UNIT_MAGIC 0x00071029
#define ROOT_UNIT_MAGIC 0x00071029
#define ROOT_MAX_RECORD 1024
#define MAX_TIME_LEN 32
#define MAX_ACTION_LEN 32
#define TASK_COMM_LEN 16
struct root_save_head{
int magic;
int count;
char reserved[512-8];
};
struct root_save_unit{
int magic;
pid_t ppid;
pid_t pid;
pid_t tid;
int cap;
int fork_by_sh;
char parent_name[TASK_COMM_LEN];
char process_name[TASK_COMM_LEN];
char thread_name[TASK_COMM_LEN];
char action[MAX_ACTION_LEN];
char time[MAX_TIME_LEN];
char reserved[512-136];
};
static struct root_save_head save_head_tmp;
static struct root_save_unit save_unit_tmp;
#define MAX_ACTION_LEN 32
#define TASK_COMM_LEN 16
struct root_save_head{
int magic;
int count;
char reserved[512-8];
};
struct root_save_unit{
int magic;
pid_t ppid;
pid_t pid;
pid_t tid;
int cap;
int fork_by_sh;
char parent_name[TASK_COMM_LEN];
char process_name[TASK_COMM_LEN];
char thread_name[TASK_COMM_LEN];
char action[MAX_ACTION_LEN];
char time[MAX_TIME_LEN];
char reserved[512-136];
};
static struct root_save_head save_head_tmp;
static struct root_save_unit save_unit_tmp;
static const char *ROOTM_PATCH = "/dev/rootm";
Value* RootCheckFN(const char* name, State* state, int argc, Expr* argv[]) {
if (argc != 0) {
return ErrorAbort(state, "%s() expects no args, got %d", name, argc);
}
int result = 1;
int fd;
int magic = 0;
int count = 0;
if (argc != 0) {
return ErrorAbort(state, "%s() expects no args, got %d", name, argc);
}
int result = 1;
int fd;
int magic = 0;
int count = 0;
int index = 0;
int result_check=1;
fd = open(ROOTM_PATCH, O_RDONLY, 0);
if(fd == -1){
fprintf(stderr, "Can not open %s, errno=%d\n", ROOTM_PATCH, errno);
result = 1;
return StringValue(strdup(result == 0 ? "t" : ""));
}
if(sizeof(struct root_save_head) != read(fd, &save_head_tmp, sizeof(struct root_save_head))){
fprintf(stderr, "Can not read the header of records\n");
close(fd);
result = 1;
return StringValue(strdup(result == 0 ? "t" : ""));
}
magic = save_head_tmp.magic;
count = save_head_tmp.count;
if(magic != ROOT_SAVE_MAGIC || count > ROOT_MAX_RECORD || count <= 0){
close(fd);
fprintf(stderr, "System partition check Pass!\n");
result = 0;
return StringValue(strdup(result == 0 ? "t" : ""));
fd = open(ROOTM_PATCH, O_RDONLY, 0);
if(fd == -1){
fprintf(stderr, "Can not open %s, errno=%d\n", ROOTM_PATCH, errno);
result = 1;
return StringValue(strdup(result == 0 ? "t" : ""));
}
if(sizeof(struct root_save_head) != read(fd, &save_head_tmp, sizeof(struct root_save_head))){
fprintf(stderr, "Can not read the header of records\n");
close(fd);
result = 1;
return StringValue(strdup(result == 0 ? "t" : ""));
}
magic = save_head_tmp.magic;
count = save_head_tmp.count;
if(magic != ROOT_SAVE_MAGIC || count > ROOT_MAX_RECORD || count <= 0){
close(fd);
fprintf(stderr, "System partition check Pass!\n");
result = 0;
return StringValue(strdup(result == 0 ? "t" : ""));
}else{
fprintf(stderr,"System partition check Fail!\n");
fprintf(stderr, "System have been Root.\n");
result = 1;
return StringValue(strdup(result == 0 ? "t" : ""));
}
return StringValue(strdup(result == 0 ? "t" : ""));
fprintf(stderr, "System have been Root.\n");
result = 1;
return StringValue(strdup(result == 0 ? "t" : ""));
}
return StringValue(strdup(result == 0 ? "t" : ""));
}
void RegisterInstallFunctions() {
RegisterFunction("root_check", RootCheckFN);
这部分代码逻辑在项目的updater/install.c中,增加了一个root_check()的函数,该函数主要用来进行root检测。之后在/tools/releasetools/edify_generator.py脚本中增加对root_check()的调用。这个脚本的作用就是在制作升级包时生成升级包中的updater-script脚本。上述修改都是在该项目的代码中修改,专门用于制作升级包时生成脚本文件使用的,并不参与实际的软件版本编译,所以对这部分的修改只在生成HOTA升级包时生效,最终在HOTA包中的脚本updater-script中添加了root检测的逻辑调用。 而对已经发布的版本没有任何影响。
经过修改后,用户在进行HOTA升级时,实际的流程是:
主系统下获取升级包 (差分包)---> 进行HOTA升级 ---> 手机重启后进入recovery模式 ---> 在recovery下解析HOTA升级包中的updater-script脚本 ---> 调用root_chek()函数检查root标志是否存在 ----> 如果存在,则执行“abort”退出升级流程并给出手机被root的提示语。 如果不存在,继续执行脚本的下一行,直到脚本执行完毕,开始对版本进行差分升级。【如果root检查没有通过,升级流程abort,那么手机停止在recovery模式,用户点击power键后选中reboot选项,手机重启回到正常模式。】
下面是root过的设备禁止OTA所记录的日志片段:
mount /system /dev/block/platform/mtk-msdc.0/by-name/system
System partition check Fail!
System have been Root.
script aborted: This phone has been root or an error occurred, can not upgrade.
This phone has been root or an error occurred, can not upgrade.
E:Error in /sdcard/dload/update.zip
(Status 7)
Installation aborted.
I:no boot messages recovery
I:[1]check the otaupdate is done!
factory_poweroff_flag=0
demo_mode_flag=0
1 0
- 禁止非法root的设备OTA升级
- OTA升级
- OTA升级
- OTA升级
- recovery image的OTA升级过程
- OTA 差分升级包的制作
- 安卓OTA升级文件的制作
- Android OTA升级的补救措施
- OTA空中升级的难点与解决方案
- 切合OTA升级的版本升级包自动生成脚本
- OTA升级包的解释和升级方法
- 禁止键入非法值
- android OTA升级
- Android OTA 升级
- Android OTA 升级
- Android OTA 升级
- Android OTA升级过程
- android OTA 升级
- Ubuntu 下面安装gtk+-2.0
- mysql wordpress JQuery html5 Ajax Python全下载
- iOS申请真机调试证书-图文详解
- 属性动画Animator
- [leetcode] Ugly Number
- 禁止非法root的设备OTA升级
- 使用 lint 工具优化 Android 布局
- sql server 数据库备份还原
- 2015盘点最佳5笔小投资引援:骑士得枪勇士收肉盾
- CSS样式优先级机制
- Android自带的分享功能案例
- mac 配置
- [转]Android开发:实时处理摄像头预览帧视频------浅析PreviewCallback,onPreviewFrame,AsyncTask的综合应用
- 在arcgis javascript 的sdk中 地图自动居中和放大 到一个graphic的位置.并且自动打开InfoWindow