MTK平台SimLock功能的recovery模式下实现总结
在介绍SimLock功能的recovery模式实现前,我们先来说明两个问题:第一就是SimLock的功能具体是含义;第二就是系统负责recovery模式下主要实现那些功能。
简单来说,SimLock功能主要是:手机在开机后检测到的sim卡如果是本运营商发放的,那么手机就正常开机使用,如果是非本运营商发放的手机卡,那么开机后将无法正常起网使用,除非经过本运营商授权并提供解锁密码。这样运营商就会提高自己与其他运营商的用户量的竞争。
系统负责的recovery模式的实现的功能主要是:在recovery模式下解析由运营商提供的Config.dat文件。该文件内存储了手机的开机密码且密码与手机的IMEI一一对应,还有运营商的MCCMNC。具体实现就是在当手机进入recovery模式时,我们选择Sim Lock选项,会从外置Sd卡下面读取Config.dat文件,该文件中存储了手机的IMEI号与MCCMNC,然后在从宇龙参数分区内读取本手机的IMEI号,且与Config.dat文件中的IMEI号进行比对,如果两个IMEI号匹配成功,则会生成解锁密码;否则匹配失败,功能停止。如果两个IMEI号匹配成功后,会上生成的密码写入/persist/simlock/unlock中,将MCCMNC写入到/persist/simlock/numerics中,具体如图1所示。
图1 Recovery模式下解析秘钥过程
上层会读取这两个文件中的值,完成SimLock的主要逻辑。接下来我们就recovery模式下具体功能,总结实现的具体过程以及遇到问题。
一. 具体功能实现过程
1. 在recovery模式下增加菜单选项
我们首先需要添加操作的入口,即需要在device.cpp与文件device.h文件中完成。
另外SINLock功能只是针对部分欧洲运营商,因此不能所有产品都添加SIMLock功能,所以需要通过在product_feature中增加客制话的属性FEATURE_TCCM_OEM_CUSTOMIZATION来控制,此外还需要添加对应的入口函数,在device.h中声明。
device.cpp:
#include "device.h"
/* yulong begin, add */
/* include yulong feature, yebiqing, 20160317 */
#include <product/YulongFeature.h>
/* yulong end */
static const char* MENU_ITEMS[] = {
"Reboot system now",
………
/* yulong begin, add */
/* for write SIM Lock info ,requirement from tccm, liucaifei, 20160704*/
#if FEATURE_TCCM_OEM_CUSTOMIZATION == 1
"SIM Lock",
#endif
/* yulong end */
………
null
};
device.h:
enum BuiltinAction { ……..
/* yulong begin, add */
/* for write SIM Lock info ,requirement from tccm, sunliang, 20160317*/
#if FEATURE_TCCM_OEM_CUSTOMIZATION == 1
, WRITE_SIMLOCK_INFO
#endif
/*yulong end*/
};
platform_features
# add for simlock by liucaifei
FEATURE_TCCM_OEM_CUSTOMIZATION = false
product_features
# add for simlock by liucaifei
FEATURE_TCCM_OEM_CUSTOMIZATION = ture
2. Config.dat文件解析及存储
进入static int write_simlock(Device* device)入口函数后,首先查找并加载存储在SdCard上的Config.dat文件,该过程是在lookup_dat_file(const char* path, Device* device)接口内实现,然后会执行static int get_deviceIMEI(char* str_IMEI1,char* str_IMEI2),在该接口函数内完成了获取本设备IMEI1和IMEI2的过程,最后,我们会根据IMEI1进行匹配之前解析的Config.dat文件,将查询到的unlock code存储在/persist/simlock/unlock路径下,此外,会继续解析Configuration Tool中输入的numeric_code(mccmnc),由于可能在Configuration Tool中输入多个mccmnc(针对解决此类一网多号设计),因此需要将解析到的所有mccmnc存储至/persist/simlock/numerics路径下,后续Framework会查询匹配这些参数,下面是详细的解析过程。
recovery.cpp:
while( read(config_dat_fd, buf, CONTENT_OFFSET)){
if ( buf[0] == 0x17 && buf[1] == 0x00 ){
ret = read(config_dat_fd, buf, LEN_IMEI);
buf[ret] = '\0';
printf("readed IMEI %s \n", buf);
if (0 == strncmp(str_IMEI1, buf, LEN_IMEI)) {
matched = 1;
ui->Print("current IMEI matched.\n");
ret = read(config_dat_fd, buf, LEN_ACTIVIATION);
buf[ret] = '\0';
strncpy(activation_code, buf, ret);
ui->Print("current activation code is %s \n", activation_code);
}else{
ret = read(config_dat_fd, buf, LEN_ACTIVIATION);
buf[ret] = '\0';
}
printf("readed activation code is %s \n", buf);
}else{
if(!matched){
ui->Print("IMEI %s not matched.\n",str_IMEI1);
ui->Print("Failed to write SIMLOCK information.\n");
close(config_dat_fd);
return -1;
}
while( ret = read(config_dat_fd, buf, LEN_NUMERIC)){
strncpy(numeric_code, buf, ret);
ui->Print("current numeric code is %s \n", numeric_code);
}
break;
}
}
if(matched){
ensure_path_mounted(PERSIST_PATH);
unlock_fd = open(SIMLOCK_UNLOCK_FILE, O_RDWR|O_CREAT, 0644);
if (unlock_fd < 0) {
ui->Print("open SIMLOCK_UNLOCK_FILE failed, (%s).\n", strerror(errno));
return -1;
}
ret = write(unlock_fd, activation_code, strlen(activation_code));
if (ret <= 0) {
ui->Print("failed to write target activation code.\n");
close(unlock_fd);
return -1;
}else{
ui->Print("target activation code is %s \n", activation_code);
}
close(unlock_fd);
chmod(SIMLOCK_UNLOCK_FILE, 0644);
sync();
numeric_fd = open(SIMLOCK_NUMERIC_FILE, O_RDWR|O_CREAT, 0644);
if (numeric_fd < 0) {
ui->Print("open SIMLOCK_NUMERIC_FILE failed.\n");
return -1;
}
ret = write(numeric_fd, numeric_code, strlen(numeric_code));
if (ret <= 0) {
ui->Print("failed to write target numeric code.\n");
close(numeric_fd);
return -1;
}else{
ui->Print("target numeric code is %s\n", numeric_code);
}
close(numeric_fd);
chmod(SIMLOCK_NUMERIC_FILE, 0644);
sync();
ensure_path_unmounted(PERSIST_PATH);
}
ensure_path_unmounted(SDCARD_ROOT);
ui->Print("Write SIMLOCK information successfully.\n");
具体的修改活动如下:
二. 实现过程中遇到的问题
1. persist分区的挂载问题
在recovery模式下需要将解析的解锁密码和MCCMNC存储到/persist/simlock/unlock和/persist/simlock/numerics下,并且在正常模式下读取这两个文件的值,供上层应用。因此,系统需要在recovery模式和正常模式都挂载persist分区。
1.1问题的确认
确定底层已经打开persist分区:
root@CPY83_U00:/dev/block/platform/mtk-msdc.0/11230000.msdc0/by-name #ls –l
lrwxrwxrwx root root 2016-01-01 20:07 persist -> /dev/block/mmcblk0p21
在projectConfig.mk文件中打开persist相关宏:
MTK_PERSIST_PARTITION_SUPPORT = yes
在recovery.fstab中添加recovery模式下的挂载:
/persist ext4 /dev/block/mmcblk0p21
利用mount命令显示:未挂载persist分区:
1.2 问题分析
确认修改是否成功:
root@CPY83_U00:/ # cat fstab.mt6735
/dev/block/platform/mtk-msdc.0/11230000.msdc0/by-name/persist /persist ext4 noatime,nosuid,nodev,noauto_da_alloc,commit=1,nodelalloc wait,check,formattable
有挂载信息,证明在projectConfig.mk文件中打开的宏起作用
日志分析:
在recovery模式下的last_log打印出的日志为:
readed activation code is 27018334
current numeric code is 46000F46002F
E:failed to mount /persist (Invalid argument)
open SIMLOCK_UNLOCK_FILE failed.
这日志是从\bootable\recovery\root.cpp文件中ensure_path_mounted函数打印出来的:
int ensure_path_mounted(const char* path) {
………
} else if (strcmp(v->fs_type, "ext4") == 0 ||
strcmp(v->fs_type, "squashfs") == 0 ||
strcmp(v->fs_type, "vfat") == 0) {
mt_ensure_dev_ready(v->mount_point);
result = mount(v->blk_device, v->mount_point, v->fs_type,
v->flags, v->fs_options);
if (result == 0) {
goto mount_done;
} else {
result = mt_ensure_path_mounted(v);
if (result == 0)
goto mount_done;
}
LOGE("failed to mount %s (%s)\n", v->mount_point, strerror(errno));
return -1;
}
………
}
进一步分析日志,发现在dumpstate.txt日志中有这样的权限问题:
14>[ 6.426141] .(0)[190:init]fs_mgr: __mount(source=/dev/block/platform/mtk-msdc.0/11230000.msdc0/by-name/persist,target=/persist,type=ext4)=-1
<11>[ 6.428161] .(0)[190:init]fs_mgr: Failed to mount an un-encryptable or wiped partition on/dev/block/platform/mtk-msdc.0/11230000.msdc0/by-name/persist at /persist options: noauto_da_alloc,commit=1,nodelalloc error: Invalid argument
猜测和权限有关,进一步在该日志中发现:
14>[ 6.377590] .(0)[190:init]fs_mgr: check_fs(): mount(/dev/block/platform/mtk-msdc.0/11230000.msdc0/by-name/persist,/persist,ext4)=-1: Invalid argument
<14>[ 6.379324] .(0)[190:init]fs_mgr: Running /system/bin/e2fsck on /dev/block/platform/mtk-msdc.0/11230000.msdc0/by-name/persist
<5>[ 6.396816] .(0)[230:e2fsck]audit: type=1400 audit(1262447888.830:4): avc: denied { open } for pid=230 comm="e2fsck" path="/dev/block/mmcblk0p21" dev="tmpfs" ino=7137 scontext=u:r:fsck:s0 tcontext=u:object_r:persist_block_device:s0 tclass=blk_file permissive=0
因此,可以确定persist分区挂载后的设备没有open权限。我们在MTK\yulong\device\mediatek\common\sepolicy\fsck.te文件中添加open权限
allow fsck persist_block_device:blk_file { open read write getattr ioctl };
1.3.编译版本,利用mount命令查看persist分区挂载成功
C:\Users\liucaifei>adb shell
…….
/dev/block/platform/mtk-msdc.0/11230000.msdc0/by-name/persist /persist ext4 rw,seclabel,nosuid,nodev,noatime,nodelalloc,noauto_da_alloc,comm
it=1,data=ordered 0 0
2. persist根目录及其子目录文件无法访问问题
2.1 问题确认
首先确认persist分区已经挂载到/persist节点:
root@CPY83_U00:/ # mount
/dev/block/platform/mtk-msdc.0/11230000.msdc0/by-name/persist /persist ext4 rw,seclabel,nosuid,nodev,noatime,nodelalloc,noauto_da_alloc,commit=1,data=ordered 0 0
在init.mt6735.rc和init.recovery.mt6735.rc中增加创建挂载点下的目录:
#yulong add for simlock requirement of TCCM by liucaifei,20170719
mkdir /persist/simlock 0760 radio radio
chmod 0760 /persist/simlock/unlock
chown radio radio /persist/simlock/unlock
chmod 0760 /persist/simlock/numerics
chown radio radio /persist/simlock/numerics
#yulong end
cat查看挂载点下的两个文件可以访问:
root@CPY83_U00:/persist/simlock # ls
numerics
unlock
root@CPY83_U00:/persist/simlock # cat numerics
root@CPY83_U00:/persist/simlock # cat unlock
46665716root@CPY83_U00:/persist/simlock #
上层访问出现:
01-01 20:06:49.363693 1218 1218 D CPSimLockUtil: getParamFromPath -- /persist/simlock/unlock is not exist, return N/A
01-01 20:06:49.348407 1218 1218 W System.err: java.io.FileNotFoundException: /persist/simlock/unlock: open failed: EACCES (Permission denied)
2.2日志分析:
2.2.1 /persist目录selinux中标签为unlabeled问题
首先从radio.boot日志发现,确实是上层无法访问该挂载路径下文件:
01-01 20:06:49.363693 1218 1218 D CPSimLockUtil: getParamFromPath -- /persist/simlock/unlock is not exist, return N/A
01-01 20:06:49.372214 1218 1218 D CPSimLockUtil: getParamFromPath -- /persist/simlock/numerics is not exist, return N/A
01-01 20:06:49.372282 1218 1218 D CPSimLockUtil: unlockCode = null
01-01 20:06:49.372323 1218 1218 D CPSimLockUtil: mNumericsUnlocked = N/A
进一步从main.boot日志中发现是由于权限问题:上层应用无法访问/persist,而且发现/persist的标签为unlabeled:
01-01 20:06:49.348407 1218 1218 W System.err: java.io.FileNotFoundException: /persist/simlock/unlock: open failed: EACCES (Permission denied)
01-01 20:06:49.340000 1218 1218 W m.android.phone: type=1400 audit(0.0:36): avc: denied { search } for name="/" dev="mmcblk0p21" ino=2 scontext=u:r:radio:s0 tcontext=u:object_r:unlabeled:s0 tclass=dir permissive=0
可以在手机根目录下执行ls –Z,发现确实/persist挂载点的标签为unlabeled:
root@CPY83_U00:/ # ls –Z
drwxrwx--x system system u:object_r:unlabeled:s0 persist
因此,需要在init.mt6735.rc文件中创建/persist挂载点时,需要添加如下语句:
chown system system /persist
chmod 0771 /persist
#yulong add for simlock requirement of TCCM by sunliang,20160318
mkdir /persist/simlock 0760 radio radio
chmod 0760 /persist/simlock/unlock
chown radio radio /persist/simlock/unlock
chmod 0760 /persist/simlock/numerics
chown radio radio /persist/simlock/numerics
restorecon_recursive /persist
#yulong end
该语句的含义就是根据file_context内容递归给/persist目录添加标签。添加后编译版本利用ls命令进行验证,结果如下:
root@CPY83_U00:/ # ls –Z
drwxrwx--x system system u:object_r:persist_data_file:s0 persist
发现/persist的标签变为persist_data_file,其实这正是/persist子目录文件的标签,这正是restorecon_recursive命令的作用,递归根据子目录给指定的目录添加标签。
root@CPY83_U00:/persist # cd simlock/
root@CPY83_U00:/persist/simlock # ls -Z
-rwxrw---- radio radio u:object_r:persist_data_file:s0 numerics
-rwxrw---- radio radio u:object_r:persist_data_file:s0 unlock
2.2.2 应用访问子目录文件的权限问题
当/persist目录有指定标签后,进一步验证发现上层还是无法访问/persist下面的子目录文件,日志如下:
01-01 20:06:49.363693 1218 1218 D CPSimLockUtil: getParamFromPath -- /persist/simlock/unlock is not exist, return N/A
01-01 20:06:49.372214 1218 1218 D CPSimLockUtil: getParamFromPath -- /persist/simlock/numerics is not exist, return N/A
01-01 20:06:49.372282 1218 1218 D CPSimLockUtil: unlockCode = null
01-01 20:06:49.372323 1218 1218 D CPSimLockUtil: mNumericsUnlocked = N/A
不过此时再来看main.log.boot日志发现,测试报的权限问题是因为无法读取/persist/simlock/numberics,日志如下:
01-01 20:07:22.119138 1211 1211 W System.err: java.io.FileNotFoundException: /persist/simlock/unlock: fstat failed: EACCES (Permission denied)
01-01 20:07:22.110000 1211 1211 W m.android.phone: type=1400 audit(0.0:31): avc: denied { read } for path="/persist/simlock/unlock" dev="mmcblk0p21" ino=13 scontext=u:r:radio:s0 tcontext=u:object_r:persist_data_file:s0 tclass=file permissive=0
因此在radio.te中增加访问该标签的read权限,代码如下:
allow radio persist_data_file:file read ;
编译版本后又发现缺少open权限,所以在radio.te文件添加open权限,代码如下:
allow radio persist_data_file:file { read open };
编译版本后又发现缺少getattr权限,所以在radio.te文件添加getattr权限,代码如下:
allow radio persist_data_file:file { read open getattr };
编译版本后又发现缺少getattr权限,所以在radio.te文件添加write权限,代码如下:
allow radio persist_data_file:file { read open getattr write };
附录1:具体修改活动
http://10.3.11.35:8080/#/c/37909/ (recovery模式增加源文件)
http://10.3.11.35:8080/#/c/37921/3 (增加simlock逻辑)
http://10.3.11.35:8080/#/c/37913/ (增加源文件,打开feature控制,打开读取权限)
http://10.3.11.35:8080/#/c/37955/ (打开挂载persist分区宏开关)
|