1. 程式人生 > >Android客製化-恢復出廠設定但保留檔案

Android客製化-恢復出廠設定但保留檔案

很久沒有記錄了,持之以恆做一件事,需要一定的毅力吶! 
最近遇到了一個需求,要求恢復出廠設定保留內建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。 
如果各位有其他辦法,歡迎留言。有不對之處,歡迎指出。