Skip to content

Commit 8dfe2b9

Browse files
author
Christopher Tate
committed
Merge restored wifi APs, don't overwrite
We now preserve any already-known AP configuration information when restoring wifi from backup, instead of flatly overwriting the known definitions with the historical ones. This means that if you are performing setup while connected to an AP unknown in the restored dataset, you will retain your connection instead of seeing it drop partway through the restore process because suddenly the supplicant "forgot" how to connect to it. Duplicates are resolved by retaining the currently-defined network configuration and discarding the historical one. Bug 6443790 Change-Id: I1f44cc6a01fc4ae7c4b680682a10fcb7a0be65dc
1 parent 718af32 commit 8dfe2b9

File tree

1 file changed

+161
-10
lines changed

1 file changed

+161
-10
lines changed

packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java

Lines changed: 161 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import java.io.BufferedOutputStream;
3535
import java.io.BufferedReader;
3636
import java.io.BufferedWriter;
37+
import java.io.CharArrayReader;
3738
import java.io.DataInputStream;
3839
import java.io.DataOutputStream;
3940
import java.io.EOFException;
@@ -45,7 +46,11 @@
4546
import java.io.IOException;
4647
import java.io.InputStream;
4748
import java.io.OutputStream;
49+
import java.io.Reader;
50+
import java.io.Writer;
51+
import java.util.ArrayList;
4852
import java.util.HashMap;
53+
import java.util.HashSet;
4954
import java.util.Map;
5055
import java.util.zip.CRC32;
5156

@@ -55,7 +60,7 @@
5560
*/
5661
public class SettingsBackupAgent extends BackupAgentHelper {
5762
private static final boolean DEBUG = false;
58-
private static final boolean DEBUG_BACKUP = DEBUG || true;
63+
private static final boolean DEBUG_BACKUP = DEBUG || false;
5964

6065
private static final String KEY_SYSTEM = "system";
6166
private static final String KEY_SECURE = "secure";
@@ -111,6 +116,130 @@ public class SettingsBackupAgent extends BackupAgentHelper {
111116
private WifiManager mWfm;
112117
private static String mWifiConfigFile;
113118

119+
// Class for capturing a network definition from the wifi supplicant config file
120+
static class Network {
121+
String ssid = ""; // equals() and hashCode() need these to be non-null
122+
String key_mgmt = "";
123+
final ArrayList<String> rawLines = new ArrayList<String>();
124+
125+
public static Network readFromStream(BufferedReader in) {
126+
final Network n = new Network();
127+
String line;
128+
try {
129+
while (in.ready()) {
130+
line = in.readLine();
131+
if (line == null || line.startsWith("}")) {
132+
break;
133+
}
134+
n.rememberLine(line);
135+
}
136+
} catch (IOException e) {
137+
return null;
138+
}
139+
return n;
140+
}
141+
142+
void rememberLine(String line) {
143+
// can't rely on particular whitespace patterns so strip leading/trailing
144+
line = line.trim();
145+
if (line.isEmpty()) return; // only whitespace; drop the line
146+
rawLines.add(line);
147+
148+
// remember the ssid and key_mgmt lines for duplicate culling
149+
if (line.startsWith("ssid")) {
150+
ssid = line;
151+
} else if (line.startsWith("key_mgmt")) {
152+
key_mgmt = line;
153+
}
154+
}
155+
156+
public void write(Writer w) throws IOException {
157+
w.write("\nnetwork={\n");
158+
for (String line : rawLines) {
159+
w.write("\t" + line + "\n");
160+
}
161+
w.write("}\n");
162+
}
163+
164+
public void dump() {
165+
Log.v(TAG, "network={");
166+
for (String line : rawLines) {
167+
Log.v(TAG, " " + line);
168+
}
169+
Log.v(TAG, "}");
170+
}
171+
172+
// Same approach as Pair.equals() and Pair.hashCode()
173+
@Override
174+
public boolean equals(Object o) {
175+
if (o == this) return true;
176+
if (!(o instanceof Network)) return false;
177+
final Network other;
178+
try {
179+
other = (Network) o;
180+
} catch (ClassCastException e) {
181+
return false;
182+
}
183+
return ssid.equals(other.ssid) && key_mgmt.equals(other.key_mgmt);
184+
}
185+
186+
@Override
187+
public int hashCode() {
188+
int result = 17;
189+
result = 31 * result + ssid.hashCode();
190+
result = 31 * result + key_mgmt.hashCode();
191+
return result;
192+
}
193+
}
194+
195+
// Ingest multiple wifi config file fragments, looking for network={} blocks
196+
// and eliminating duplicates
197+
class WifiNetworkSettings {
198+
// One for fast lookup, one for maintaining ordering
199+
final HashSet<Network> mKnownNetworks = new HashSet<Network>();
200+
final ArrayList<Network> mNetworks = new ArrayList<Network>(8);
201+
202+
public void readNetworks(BufferedReader in) {
203+
try {
204+
String line;
205+
while (in.ready()) {
206+
line = in.readLine();
207+
if (line != null) {
208+
// Parse out 'network=' decls so we can ignore duplicates
209+
if (line.startsWith("network")) {
210+
Network net = Network.readFromStream(in);
211+
if (! mKnownNetworks.contains(net)) {
212+
if (DEBUG_BACKUP) {
213+
Log.v(TAG, "Adding " + net.ssid + " / " + net.key_mgmt);
214+
}
215+
mKnownNetworks.add(net);
216+
mNetworks.add(net);
217+
} else {
218+
if (DEBUG_BACKUP) {
219+
Log.v(TAG, "Dupe; skipped " + net.ssid + " / " + net.key_mgmt);
220+
}
221+
}
222+
}
223+
}
224+
}
225+
} catch (IOException e) {
226+
// whatever happened, we're done now
227+
}
228+
}
229+
230+
public void write(Writer w) throws IOException {
231+
for (Network net : mNetworks) {
232+
net.write(w);
233+
}
234+
}
235+
236+
public void dump() {
237+
for (Network net : mNetworks) {
238+
net.dump();
239+
}
240+
}
241+
}
242+
114243
@Override
115244
public void onCreate() {
116245
if (DEBUG_BACKUP) Log.d(TAG, "onCreate() invoked");
@@ -622,29 +751,51 @@ private void restoreWifiSupplicant(String filename, BackupDataInput data) {
622751

623752
private void restoreWifiSupplicant(String filename, byte[] bytes, int size) {
624753
try {
754+
WifiNetworkSettings supplicantImage = new WifiNetworkSettings();
755+
625756
File supplicantFile = new File(FILE_WIFI_SUPPLICANT);
626-
if (supplicantFile.exists()) supplicantFile.delete();
627-
copyWifiSupplicantTemplate();
757+
if (supplicantFile.exists()) {
758+
// Retain the existing APs; we'll append the restored ones to them
759+
BufferedReader in = new BufferedReader(new FileReader(FILE_WIFI_SUPPLICANT));
760+
supplicantImage.readNetworks(in);
761+
in.close();
628762

629-
OutputStream os = new BufferedOutputStream(new FileOutputStream(filename, true));
630-
os.write("\n".getBytes());
631-
os.write(bytes, 0, size);
632-
os.close();
763+
supplicantFile.delete();
764+
}
765+
766+
// Incorporate the restore AP information
767+
if (size > 0) {
768+
char[] restoredAsBytes = new char[size];
769+
for (int i = 0; i < size; i++) restoredAsBytes[i] = (char) bytes[i];
770+
BufferedReader in = new BufferedReader(new CharArrayReader(restoredAsBytes));
771+
supplicantImage.readNetworks(in);
772+
773+
if (DEBUG_BACKUP) {
774+
Log.v(TAG, "Final AP list:");
775+
supplicantImage.dump();
776+
}
777+
}
778+
779+
// Install the correct default template
780+
BufferedWriter bw = new BufferedWriter(new FileWriter(FILE_WIFI_SUPPLICANT));
781+
copyWifiSupplicantTemplate(bw);
782+
783+
// Write the restored supplicant config and we're done
784+
supplicantImage.write(bw);
785+
bw.close();
633786
} catch (IOException ioe) {
634787
Log.w(TAG, "Couldn't restore " + filename);
635788
}
636789
}
637790

638-
private void copyWifiSupplicantTemplate() {
791+
private void copyWifiSupplicantTemplate(BufferedWriter bw) {
639792
try {
640793
BufferedReader br = new BufferedReader(new FileReader(FILE_WIFI_SUPPLICANT_TEMPLATE));
641-
BufferedWriter bw = new BufferedWriter(new FileWriter(FILE_WIFI_SUPPLICANT));
642794
char[] temp = new char[1024];
643795
int size;
644796
while ((size = br.read(temp)) > 0) {
645797
bw.write(temp, 0, size);
646798
}
647-
bw.close();
648799
br.close();
649800
} catch (IOException ioe) {
650801
Log.w(TAG, "Couldn't copy wpa_supplicant file");

0 commit comments

Comments
 (0)