|
34 | 34 | import java.io.BufferedOutputStream; |
35 | 35 | import java.io.BufferedReader; |
36 | 36 | import java.io.BufferedWriter; |
| 37 | +import java.io.CharArrayReader; |
37 | 38 | import java.io.DataInputStream; |
38 | 39 | import java.io.DataOutputStream; |
39 | 40 | import java.io.EOFException; |
|
45 | 46 | import java.io.IOException; |
46 | 47 | import java.io.InputStream; |
47 | 48 | import java.io.OutputStream; |
| 49 | +import java.io.Reader; |
| 50 | +import java.io.Writer; |
| 51 | +import java.util.ArrayList; |
48 | 52 | import java.util.HashMap; |
| 53 | +import java.util.HashSet; |
49 | 54 | import java.util.Map; |
50 | 55 | import java.util.zip.CRC32; |
51 | 56 |
|
|
55 | 60 | */ |
56 | 61 | public class SettingsBackupAgent extends BackupAgentHelper { |
57 | 62 | private static final boolean DEBUG = false; |
58 | | - private static final boolean DEBUG_BACKUP = DEBUG || true; |
| 63 | + private static final boolean DEBUG_BACKUP = DEBUG || false; |
59 | 64 |
|
60 | 65 | private static final String KEY_SYSTEM = "system"; |
61 | 66 | private static final String KEY_SECURE = "secure"; |
@@ -111,6 +116,130 @@ public class SettingsBackupAgent extends BackupAgentHelper { |
111 | 116 | private WifiManager mWfm; |
112 | 117 | private static String mWifiConfigFile; |
113 | 118 |
|
| 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 | + |
114 | 243 | @Override |
115 | 244 | public void onCreate() { |
116 | 245 | if (DEBUG_BACKUP) Log.d(TAG, "onCreate() invoked"); |
@@ -622,29 +751,51 @@ private void restoreWifiSupplicant(String filename, BackupDataInput data) { |
622 | 751 |
|
623 | 752 | private void restoreWifiSupplicant(String filename, byte[] bytes, int size) { |
624 | 753 | try { |
| 754 | + WifiNetworkSettings supplicantImage = new WifiNetworkSettings(); |
| 755 | + |
625 | 756 | 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(); |
628 | 762 |
|
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(); |
633 | 786 | } catch (IOException ioe) { |
634 | 787 | Log.w(TAG, "Couldn't restore " + filename); |
635 | 788 | } |
636 | 789 | } |
637 | 790 |
|
638 | | - private void copyWifiSupplicantTemplate() { |
| 791 | + private void copyWifiSupplicantTemplate(BufferedWriter bw) { |
639 | 792 | try { |
640 | 793 | BufferedReader br = new BufferedReader(new FileReader(FILE_WIFI_SUPPLICANT_TEMPLATE)); |
641 | | - BufferedWriter bw = new BufferedWriter(new FileWriter(FILE_WIFI_SUPPLICANT)); |
642 | 794 | char[] temp = new char[1024]; |
643 | 795 | int size; |
644 | 796 | while ((size = br.read(temp)) > 0) { |
645 | 797 | bw.write(temp, 0, size); |
646 | 798 | } |
647 | | - bw.close(); |
648 | 799 | br.close(); |
649 | 800 | } catch (IOException ioe) { |
650 | 801 | Log.w(TAG, "Couldn't copy wpa_supplicant file"); |
|
0 commit comments