Android 恢復出廠備份wifi狀態

背景:之前遇到有項目需要在恢復出廠設置之後,wifi能保持之前的狀態,用戶不需要重新輸入密碼,就可以連接上以前的熱點。

對於recovery來說,有兩種1、只清除data分區;2、清除data分區和cache分區。wifi狀態,密碼都是保存在data分區的,所以回覆出廠後便會被清除掉。

要實現這個功能,修改及思路也比較簡單,如下:
備份wifi狀態->恢復出廠->還原wifi狀態

恢復出廠是在recovery中控制的,這個我們就不修改了。
1、備份wifi狀態

備份wifi狀態選擇在RecoverySystem類中去做,目錄:frameworks/base/core/java/android/os/RecoverySystem.java
補丁如下:

     private static void bootCommand(Context context, String arg, Boolean update) throws IOException {
+       if(SystemProperties.getBoolean("persist.wifi.restore_enable",false) && !update && WIFI_SUPPLICANT_FILE.exists()){
+		    Log.d(TAG, "recovery: Wi-Fi backup!!!");
+		    WIFI_DIR.mkdirs();  // In case we need it
+		    WIFI_STATE_FILE.delete();  // In case it's not writable
+		    WIFI_SUPPLICANT_BACKUP_FILE.delete();  // In case it's not writable
+		    backupWifiSupplicantTemplate();
+		    backupWifiState(context);
+        }
+        //
         RECOVERY_DIR.mkdirs();  // In case we need it
         COMMAND_FILE.delete();  // In case it's not writable
         LOG_FILE.delete();
@@ -665,5 +682,42 @@
         return log;
     }
 

+    private static File WIFI_SUPPLICANT_FILE = new File("/data/misc/wifi/wpa_supplicant.conf");
+    private static File WIFI_DIR = new File("/backup/wifi");
+    private static File WIFI_STATE_FILE = new File(WIFI_DIR,"wifistate.conf");
+    private static File WIFI_SUPPLICANT_BACKUP_FILE = new File(WIFI_DIR,"wpa_supplicant.conf");
+
+    private static void backupWifiSupplicantTemplate() {
+	    try {
+		    BufferedReader br = new BufferedReader(new FileReader(WIFI_SUPPLICANT_FILE));
+		    BufferedWriter bw = new BufferedWriter(new FileWriter(WIFI_SUPPLICANT_BACKUP_FILE));
+
+	        char[] temp = new char[1024];
+	        int size;
+	        while ((size = br.read(temp)) > 0) {
+	            bw.write(temp, 0, size);
+	        }
+	        br.close();
+		    bw.close();
+	    } catch (Exception e) {
+		    Log.e(TAG, "backupWifiSupplicantTemplate error" );
+	    }		
+    }
+    
+    private static void backupWifiState(Context context) {
+		try{
+			final ContentResolver cr = context.getContentResolver();
+			int wifistate = Settings.Global.getInt(cr, Settings.Global.WIFI_ON);
+			
+			FileWriter file = new FileWriter(WIFI_STATE_FILE);
+			file.write(String.valueOf(wifistate));
+			file.close();
+		}
+		catch (Exception e) {
+			Log.e(TAG, "backupWifiState error" );
+		}
+    }
+    //
     private void RecoverySystem() { }  // Do not instantiate
 }

基本的流程就是在RecoverySystem增加對wifi狀態的備份,備份兩個東西:
1)wifi的ssid密碼等信息。存放在/data/misc/wifi/wpa_supplicant.conf文件中的,wpa_supplicant會根據文件中的信息去進行wifi的連接。如果恢復出廠後沒有該文件的話,會將system/etc/wifi/下的文件拷貝過去。
private static void backupWifiSupplicantTemplate() 對此過程實現。

2)wifi狀態的開關。存放在數據庫中Settings.Global.WIFI_ON字段。該字段如果是開着的話,開機會自動去連接wifi,framework有一整套wifi狀態機來控制。
private static void backupWifiState(Context context) 對此過程實現。

2、還原wifi狀態

還原wifi狀態選擇在SystemServer 中去處理,選擇在wifiservice初始化之前。目錄:frameworks/base/services/java/com/android/server/SystemServer.java
補丁如下:

+    private static File WIFI_SUPPLICANT_FILE = new File("/data/misc/wifi/wpa_supplicant.conf");
+    private static File WIFI_DIR = new File("/backup/wifi");
+    private static File WIFI_STATE_FILE = new File(WIFI_DIR,"wifistate.conf");
+    private static File WIFI_SUPPLICANT_BACKUP_FILE = new File(WIFI_DIR,"wpa_supplicant.conf");
+
+    private  void restoreWifi(){
+	    try {
+		    //cp "/backup/wifi/wpa_supplicant.conf" to "/data/misc/wifi/wpa_supplicant.conf"
+		    BufferedReader br = new BufferedReader(new FileReader(WIFI_SUPPLICANT_BACKUP_FILE));
+		    BufferedWriter bw = new BufferedWriter(new FileWriter(WIFI_SUPPLICANT_FILE));
+
+	        char[] temp = new char[1024];
+	        int size;
+	        while ((size = br.read(temp)) > 0) {
+	            bw.write(temp, 0, size);
+	        }
+	        br.close();
+		    bw.close();
+		    if(WIFI_SUPPLICANT_FILE.exists()){
+			    Process p = Runtime.getRuntime().exec("chmod 644 /data/misc/wifi/wpa_supplicant.conf");
+			    p.waitFor();
+		    }
+
+		    //put wifi_on to setting.db
+		    br = new BufferedReader(new FileReader(WIFI_STATE_FILE));
+		    String str = br.readLine();
+	        br.close();
+		    if(mContentResolver != null){
+			    Settings.Global.putInt(mContentResolver, Settings.Global.WIFI_ON, Integer.parseInt(str));
+		    }
+
+		    //"rm -rf backup/wifi/" 
+		    if(WIFI_DIR.exists()){
+			    Process p = Runtime.getRuntime().exec("rm -rf backup/wifi/");
+			    p.waitFor();
+		    }
+	    } catch (Exception e) {
+			Log.e(TAG, "restoreWifi error" );
+	    }	
+    }
+	//
     void reportWtf(String msg, Throwable e) {
         Slog.w(TAG, "***********************************************");
         Log.wtf(TAG, "BOOT FAILURE " + msg, e);
@@ -605,6 +655,13 @@
                 }
 
                try {	   		
+			   		if(firstBoot && WIFI_SUPPLICANT_BACKUP_FILE.exists()){
+						Slog.i(TAG, "firstBoot: Wi-Fi restore!!!");
+						restoreWifi();
+						WIFI_DIR.delete();
+					}
+					//end
                     Slog.i(TAG, "Wi-Fi Service");
                     wifi = new WifiService(context);
                     ServiceManager.addService(Context.WIFI_SERVICE, wifi);

和備份的流程差不多,就是將備份的wpa_supplicant.conf文件拷貝到/data/misc/wifi/wpa_supplicant.conf,權限改爲644。把Settings.Global.WIFI_ON的狀態重新寫回數據庫即可,也沒什麼好說的。這樣在初始化wifiservice的時候,就會根據之前保存的狀態進行wifi的連接了。

發佈了58 篇原創文章 · 獲贊 46 · 訪問量 16萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章