Android客製化-恢復出廠設定但保留檔案
阿新 • • 發佈:2018-11-20
很久沒有記錄了,持之以恆做一件事,需要一定的毅力吶!
最近遇到了一個需求,要求恢復出廠設定保留內建sd卡下某個目錄的檔案。思來想去,從驅動那邊備份校準訊號檔案得到了一些思路。因為帶通話設定的裝置需要進行校準,我們會將校準的檔案儲存在/data下。具體做法呢,在執行恢復出廠設定時,將此檔案copy到tmp分割槽,然後在恢復完成時,再次copy回/data分割槽。因為我們是備份資料夾,所以我們需要對copy函式進行修改。下面貼出部分程式碼。
diff --git a/bootable/recovery/recovery.cpp b/bootable/recovery/recovery.cpp index 598840c..3693cf1 100644 --- a/bootable/recovery/recovery.cpp +++ b/bootable/recovery/recovery.cpp @@ -111,6 +111,8 @@ static const char *OTA_FLAG_FILE = "/cache/recovery/last_ota_flag"; #ifdef STK_BACKUP_OFFSET //要備份的資料夾 +static const char *BACKUP_APK_PATH = "/system/third"; //臨時儲存路徑 +static const char *TEMP_APK_BACKUP_PATH = "/tmp/third_app"; #endif // Number of lines per page when displaying a file on screen @@ -286,6 +288,116 @@ static int stk_copy_file(const char *src,const char *dstFilePath) printf("stk_copy_file end src=%s,dst=%s\n",src,dstFilePath); return 0; } //拷貝資料夾的主體函式 +void error_quit(const char *msg) +{ + perror(msg); + //printf("something is error %s \n",msg); +} + +void change_path(const char *path) +{ + printf("Leave %s Successed . . .\n",getcwd(NULL,0)); + + if(chdir(path)==-1){ + error_quit(path); + printf("chdir(path)==-1 %s \n",path); + return; + } + + printf("Entry %s Successed . . .\n",getcwd(NULL,0)); +} + + +void _copy_file(const char *old_path,const char *new_path) +{ + FILE *in,*out; + size_t len; + char buf[64]; + char *p=getcwd(NULL,0); + + if((in=fopen(old_path,"rb"))==NULL){ + error_quit(old_path); + printf("(in=fopen(old_path %s \n",old_path); + return;} + change_path(new_path); + + if((out=fopen(old_path,"wb"))==NULL){ + error_quit(old_path); + printf("out=fopen(old_path %s \n",old_path); + return;} + + while(!feof(in)) + { + bzero(buf,sizeof(buf)); + + len=fread(&buf,1,sizeof(buf)-1,in); + fwrite(&buf,len,1,out); + } + + fclose(in); + fclose(out); + + change_path(p); +} + +char *get_rel_path(const char *dir,const char *path) +{ + char *rel_path; + unsigned long d_len,p_len; + + d_len=strlen(dir); + p_len=strlen(path); + bzero(rel_path,d_len+p_len+2); + + strncpy(rel_path,path,p_len); + strncat(rel_path,"/",sizeof(char)); + strncat(rel_path,dir,d_len); + + return rel_path; +} + +void copy_dir(const char *old_path,const char *new_path) +{ + DIR *dir; + struct stat buf; + struct dirent *dirp; + char *p=getcwd(NULL,0); + + if((dir=opendir(old_path))==NULL){ + error_quit(old_path); + printf("dir=opendir(old_path) %s \n",old_path); + return; + } + if(mkdir(new_path,0777)==-1){ + error_quit(new_path); + printf("mkdir(new_path %s \n",new_path); + return; + } + + change_path(old_path); + + while((dirp=readdir(dir))) + { + if(strcmp(dirp->d_name,".")==0 || strcmp(dirp->d_name,"..")==0) + continue; + if(stat(dirp->d_name,&buf)==-1){ + error_quit("stat"); + printf("stat(dirp->d_name %s \n",stat); + return; + } + if(S_ISDIR(buf.st_mode)) + { + copy_dir(dirp->d_name,get_rel_path(dirp->d_name,new_path)); + continue; + } + + _copy_file(dirp->d_name,new_path); + } + + closedir(dir); + change_path(p); +} #endif // command line args come from, in decreasing precedence: // - the actual command line @@ -1326,6 +1438,7 @@ main(int argc, char **argv) { } #ifdef STK_BACKUP_OFFSET //在開始進入恢復出廠時,進行一次拷貝 + copy_dir(BACKUP_APK_PATH,TEMP_APK_BACKUP_PATH); #endif device->StartRecovery(); property_get("UserVolumeLabel", gVolume_label, ""); @@ -1567,8 +1680,11 @@ main(int argc, char **argv) { finish_recovery(send_intent); #ifdef STK_BACKUP_OFFSET //在恢復出廠完成時,我們再次將其拷貝回來 + copy_dir(TEMP_APK_BACKUP_PATH,BACKUP_APK_PATH); + //賦予許可權操作 + chmod(BACKUP_APK_PATH, 0666); + chown(BACKUP_APK_PATH, 1000, 1000); // system system #endif #ifdef FOTA_UPDATE_SUPPORT if (perform_fota == 1) {
我們只要重點關注在finish_recovery(send_intent);與device->StartRecovery();這兩個函式身上即可。我測試過直接從/mnt/sdcard下拷貝,這樣是不行的。因為在執行恢復出廠設定時,這個分割槽此時還未掛載,我通過程式碼讓其先掛載,但是無效。當然也可能在恢復出廠設定時,我們所要備份的資料夾並不存在,所以貼出程式碼片中的一些判空都進行了return。否則會無法開機,串列埠log一直重複列印log。
如果各位有其他辦法,歡迎留言。有不對之處,歡迎指出。