Android recovery 下刪除第一次啓動後的痕跡

 在Aandroid系統啓動後,Android系統會把APK的資源文件解壓到系統的/data/app; 啓動OOBE(開機設置程序);第一次啓動與通常的啓動是不同的。

 在工廠生產系統時,爲了測試產線的設備,必須需要開機測試。但是一但啓動系統,產品到客戶手中就不是第一次啓動了。如果重新燒寫系統,又比較耗費時間。爲了解決這個矛盾,需要在生產線上,開機測試後清除第一次啓動痕跡。

基本的方法如下:

1 在應用層,寫一個小app,發出清除痕跡的命令。

2 在server層,添加一個ResetFactoryReceiver.java;接受應用層的“清除痕跡“的命令。

3 在recover層,添加功能reset-factory,處理“清除痕跡“的實現。具體就是刪除/data/目錄下面的所有內容,保留自己的備份文件夾。因爲recover模式下,沒有刪除文件夾的功能函數,需要我們自己遞歸刪除文件。

4 刪除之後直接關機。具體代碼如下:

 

1 的實現:發一個intent即可;

 

2 的實現;在/data/system/packages.xml文件,記錄了文件啓動的類名,只啓動一次的程序OOBE,有屬性disabled-components

刪除disabled-components 屬性,就可以讓這個程序重新開機啓動

packages.xml文件省略內容如下:

 

  1. <package name="com.android.oobeshell" codePath="/system/app/OOBESHELL.apk" nativeLibraryPath="/data/data/com.android.oobeshell/lib" flags="1" ft="134b20d6348" it="134b20d6348" ut="134b20d6348" version="13" userId="10016"> 
  2. <sigs count="1"> 
  3. <cert index="0" /> 
  4. </sigs> 
  5. <disabled-components> 
  6. <item name="com.android.oobeshell.DefaultActivity" /> 
  7. </disabled-components> 
  8. </package> 
  1. /**
  2. * ResetFactoryReceiver.java
  3. * delete </disabled-components> node
  4. **/
  5.  
  6. public class ResetFactoryReceiver extends BroadcastReceiver { 
  7.     private String TAG = "ResetFactoryReceiver"
  8.     private android.tv.TvManager mTM; 
  9.     private static final String xmlPath = "/data/system/packages.xml"
  10.     @Override 
  11.     public void onReceive(final Context context, Intent intent) { 
  12.         Log.i(TAG, TAG); 
  13.         Context mCx = context ; 
  14.         mTM = (TvManager) mCx.getSystemService(Context.TV_SERVICE); 
  15.         rm_Pkgxml(); 
  16.         if (intent.getAction().equals("android.intent.action.resetfactory")) { 
  17.             Thread thr = new Thread("resetfactory") { 
  18.                 @Override 
  19.                 public void run() { 
  20.                     try { 
  21.                         Log.i(TAG, "resetFactory"); 
  22.                         RecoverySystem.resetFactory(context); 
  23.                     } catch (IOException e) { 
  24.                         Slog.e(TAG, "Can't perform master resetfactory :", e); 
  25.                     } 
  26.  
  27.                 } 
  28.             }; 
  29.             thr.start(); 
  30.         } 
  31.     } 
  32.      
  33.     private void rm_Pkgxml() { 
  34.         DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); 
  35.         DocumentBuilder db; 
  36.         try { 
  37.             db = factory.newDocumentBuilder(); 
  38.             Document doc = (Document) db.parse(new File(xmlPath)); 
  39.             doc.normalize(); 
  40.             NodeList packagename = doc.getElementsByTagName("package"); 
  41.             int i = 0
  42.             for (; i < packagename.getLength(); i++) { 
  43.                 Element elt = (Element) packagename.item(i); 
  44.                 if (elt.getAttribute("name").equals("com.android.oobeshell")) { 
  45.                     NodeList list = elt.getChildNodes(); 
  46.                     if (list.getLength() > 0) { 
  47.                         for (int j = 0; j < list.getLength()-1; j++) { 
  48.                             Slog.d(TAG,list.item(j).getNodeName()); 
  49. //                          if("sigs".equals((list.item(j).getNodeName()))){ 
  50. //                              list.item(j).getChildNodes().item(0).getAttributes().item(0).setNodeValue("1"); 
  51. //                          } 
  52.                             if ((list.item(j).getNodeName()) 
  53.                                     .equals("disabled-components")) { 
  54.                                 elt.removeChild(list.item(j)); 
  55.                             } 
  56.                         } 
  57.                     } 
  58.                 } 
  59.             } 
  60.             doc2XmlFile(doc,xmlPath);   
  61.         } catch (ParserConfigurationException e) { 
  62.             Slog.e(TAG,"ParserConfigurationException",e); 
  63.         } catch (SAXException e) { 
  64.             Slog.e(TAG,"SAXException",e); 
  65.         } catch (IOException e) { 
  66.             Slog.e(TAG,"IOException",e); 
  67.         } catch(NullPointerException e){ 
  68.             Slog.e(TAG,"NullPointerException",e); 
  69.         } 
  70.  
  71.     } 

3,4 的實現: 

 

 

  1. /bootable/recovery/recovery.c  
  2.  
  3. //需要保留的目錄 
  4. static char *preserve_file[] = { 
  5.     "/data/app"
  6.     "/data/res-private"
  7.     NULL 
  8. }; 
  9.  

 


  1. //bootable/recovery/recovery.c
     
  2. else if (wipe_data) 之後 
  3.  
  4.   } else if (wipe_data) { 
  5.         printf("wipe_data..., default INSTALL_SUCCESS value = %d\n", status); 
  6.         if (device_wipe_data()) status = INSTALL_ERROR; 
  7.         if (erase_volume("/data")) status = INSTALL_ERROR; 
  8.         if (wipe_cache && erase_volume("/cache")) status = INSTALL_ERROR; 
  9.         if (status != INSTALL_SUCCESS) ui_print("Data wipe failed.\n"); 
  10.  
  11.  
  12. /* add by lhc 2011-12-16 */ 
  13.     } else if (reset_data) { 
  14.         printf("reset_factory..., default INSTALL_SUCCESS value = %d\n", status); 
  15.         if (device_wipe_data()) status = INSTALL_ERROR; 
  16.  
  17.  
  18.         if (erase_file("/data")) status = INSTALL_ERROR; 
  19.  
  20.  
  21.         if (wipe_cache && erase_volume("/cache")) status = INSTALL_ERROR; 
  22.         if (status != INSTALL_SUCCESS) ui_print("Data wipe failed.\n"); 
  23. /* add by lhc end */ 
  24.  
  25.  

 

  1. //添加函數,遞歸刪除文件 
  2. int remove_file(char *rmpath) 
  3.     struct stat statbuf; 
  4.     struct dirent   *dirp; 
  5.     DIR     *dp; 
  6.     int     ret = 0; 
  7.     char        childpath[PATH_LEN] = {0}; 
  8.     char        **preserve_p; 
  9.  
  10.     if (lstat(rmpath, &statbuf) < 0) { 
  11.         printf("%s can't lstat.\n", rmpath); 
  12.         return -1; 
  13.     } 
  14.  
  15.     for (preserve_p = preserve_file; *preserve_p; preserve_p++) { 
  16.         if (!strcmp(rmpath, *preserve_p)) 
  17.             return 0; 
  18.     } 
  19.     printf("rmpath = %s\n", rmpath); 
  20.  
  21.     if (S_ISDIR(statbuf.st_mode) == 0) { 
  22.         unlink(rmpath); 
  23.         printf("%s is not a dir, is removed.\n", rmpath); 
  24.         return 0; 
  25.     } 
  26.  
  27.     if ((dp = opendir(rmpath)) == NULL) { 
  28.         printf("can't read dir: %s, %s\n", rmpath, strerror(errno)); 
  29.         return -1; 
  30.     } 
  31.  
  32.     while ((dirp = readdir(dp)) != NULL) { 
  33.         if (strcmp(dirp->d_name, ".") == 0 || 
  34.                 strcmp(dirp->d_name, "..") == 0) 
  35.             continue
  36.  
  37.         snprintf(childpath, PATH_LEN, "%s/%s", rmpath, dirp->d_name); 
  38.         if ((ret = remove_file(childpath)) != 0) /* R */ 
  39.             return -1; 
  40.     } 
  41.  
  42.     if (closedir(dp) < 0) { 
  43.         printf("closedir error.\n"); 
  44.         return -1; 
  45.     } 
  46.  
  47.     if (rmdir(rmpath) == -1) { 
  48.         for (preserve_p = preserve_file; *preserve_p; preserve_p++) { 
  49.             if (!strstr(*preserve_p, rmpath)) { 
  50.                 printf("rmdir %s error,%s.\n", rmpath, strerror(errno)); 
  51.                 return -1; 
  52.             } 
  53.         } 
  54.     } 
  55.  
  56.     printf("rmdir ok %s\n", rmpath); 
  57.  
  58.     return ret; 
  59.  
  60. //遞歸刪除文件 
  61. static int 
  62. erase_file(const char *path) { 
  63.     ui_set_background(BACKGROUND_ICON_INSTALLING); 
  64.     ui_show_indeterminate_progress(); 
  65.     ui_print("erase %s...\n", path); 
  66.  
  67.     if (!strcmp(path, "/data")) { 
  68.         if (ensure_path_mounted(path) != 0) { 
  69.             LOGE("ensure_path_mounted failed to nmount \"%s\"\n", path); 
  70.             return -1; 
  71.      } 
  72.         return remove_file("/data"); 
  73.     } 
  74.  
  75.     return 0; 
  76.  
  77.  
  78.  
  79.  
  80.  
  81. /* add by lhc 2011-12-16 */ 
  82.     if (update_package) { 
  83.         set_recovery_status(status, "update"); 
  84.     } else { 
  85.         set_recovery_status(status, "recovery"); 
  86.     } 
  87. /* add by lhc end */ 
  88.  
  89.  
  90.  
  91.     //  
  92.     printf("before finish_recovery.\n"); 
  93.     finish_recovery(send_intent);  
  94.     printf("status = %d.\n", status); 
  95.     if (status == INSTALL_SUCCESS) { 
  96.  
  97. /* add by lhc 2011-12-16 */ 
  98. //power off  直接關機。
  99.         if (reset_data) { 
  100.             printf("Power off...\n"); 
  101.             android_reboot(ANDROID_RB_POWEROFF, 0, 0); 
  102.         } 
  103. /* add by lhc end */ 
  104.         printf("Rebooting...\n"); 
  105.         android_reboot(ANDROID_RB_RESTART, 0, 0); 
  106.     } 
  107. //} 
  108.     return EXIT_SUCCESS; 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章