背景:之前遇到有項目需要在恢復出廠設置之後,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的連接了。