[Key Words]
SW相关,Factory Mode
[DESCRIPTION]
如何在工厂模式支持special factory reset功能,执行reset后可以清除测试痕迹并保留/data/app下预置apk?
[SOLUTION]
可以参考以下sample code,新增ftm_factory_reset.c。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "common.h"
#include "ftm.h"
#include
#include "mtdutils.h"
//#ifdef FEATURE_FTM_FACTORY_RESET
#define FILENAME_MAX 100
#define NAND_TYPE 0
#define EMMC_TYPE 1
#define UNKNOWN_TYPE 2
#define SDCARD_PARTITION "fat"
extern int usb_com_port;
extern int get_is_ata();
static int format_data=0;
static int dir_level=0;
static int phone_type = 2;
static int has_fat = 0;
static bool check_phone_type(void)
{
FILE *fp_info;
char buf[512];
char p_name[32], p_size[32], p_addr[32], p_actname[64];
unsigned int p_type;
fp_info = fopen("/proc/dumchar_info", "r");
if (fp_info) {
if (fgets(buf, sizeof(buf), fp_info) != NULL) {
printf("check_phone_type get partition Information\n");
while (fgets(buf, sizeof(buf), fp_info)) {
if (sscanf(buf, "%s %s %s %d %s", p_name, p_size, p_addr, &p_type, p_actname) == 5) {
if (!strcmp(p_name, "bmtpool")) {
break;
}
if (!strcmp(p_name, "preloader")) {
if (p_type == 2) {
phone_type = EMMC_TYPE;
} else {
phone_type = NAND_TYPE;
}
} else if (!strcmp(p_name, "fat")) {
has_fat = 1;
}
}
}
if(2 == phone_type) return false;
}else{
return false;
}
}else{
return false;
}
return true;
}
static int recursiveDelete(char* dirname)
{
DIR *dp;
struct dirent *ep;
char abs_filename[FILENAME_MAX];
dir_level++;
printf("enter dir_level %d\n",dir_level);
dp = opendir (dirname);
if (dp != NULL)
{
while (ep = readdir (dp)) {
struct stat stFileInfo;
snprintf(abs_filename, FILENAME_MAX, "%s/%s", dirname, ep->d_name);
if (lstat(abs_filename, &stFileInfo) < 0)
perror ( abs_filename );
if(S_ISDIR(stFileInfo.st_mode)) {
if(strcmp(ep->d_name, ".") &&
strcmp(ep->d_name, "..") ) {
if ( dir_level==1 && !strcmp(abs_filename, "data/app") ) {
printf("Skip %s directory\n",abs_filename);
continue;
}
printf("%s directory\n",abs_filename);
recursiveDelete(abs_filename);
}
} else {
printf("%s file\n",abs_filename);
remove(abs_filename);
}
}
(void) closedir (dp);
dir_level--;
}else{
perror ("Couldn't open the directory");
}
printf("leave dir_level %d\n",dir_level);
if (dir_level>0 ) remove(dirname);
return 0;
}
static bool format_sdcard_nand(void)
{
const MtdPartition *partition = NULL;
MtdWriteContext *write = NULL;
mtd_scan_partitions();
partition = mtd_find_partition_by_name(SDCARD_PARTITION);
if (partition == NULL)
{
printf( "format_sdcard_nand: can't find mtd partition \"%s\"\n", SDCARD_PARTITION);
return true; //jin has no internal sdcard
}
write = mtd_write_partition(partition);
if (write == NULL)
{
printf("format_sdcard_nand: can't open \"%s\"\n", SDCARD_PARTITION);
return false;
}else if (mtd_erase_blocks(write, -1) == (off_t) - 1)
{
printf("format_sdcard_nand: can't erase \"%s\"\n", SDCARD_PARTITION);
mtd_write_close(write);
return false;
}else if (mtd_write_close(write))
{
printf("format_sdcard_nand: can't close \"%s\"\n", SDCARD_PARTITION);
return false;
}else{
return true;
}
}
static bool special_factory_reset() {
char prev_cwd[FILENAME_MAX];
bool erase_result = false;
if(!format_data){
getcwd(prev_cwd,FILENAME_MAX);
chdir("/");
recursiveDelete("data");
if(check_phone_type()){
if(EMMC_TYPE == phone_type){
recursiveDelete("sdcard");
}else if(NAND_TYPE == phone_type){
return format_sdcard_nand();
}else{
return false;
}
}else{
return false;
}
chdir(prev_cwd);
} else {
//format data partition
}
return true;
}
int factory_reset_entry(struct ftm_param *param, void *priv)
{
int write_len = 0;
bool erase_result;
erase_result = special_factory_reset();
sync();
if((1 == get_is_ata()))
{
if(erase_result){
write_len = write(usb_com_port, "ok\r\n", strlen("ok\r\n"));
}else{
write_len = write(usb_com_port, "clean_fail\r\n", strlen("ok\r\n"));
}
}
reboot(RB_POWER_OFF);
return 0;
}
int factory_reset_init(void)
{
int ret = 0;
struct ftm_module *mod;
LOGD("%s\n", __FUNCTION__);
mod = ftm_alloc(ITEM_FACTORY_RESET, sizeof(struct ftm_module));
if (!mod)
return -ENOMEM;
ret = ftm_register(mod, factory_reset_entry, (void*)mod);
return ret;
}
//#endif