blob: f8fb1e5794461cd14d688d984ba0df8ce801849b [file] [log] [blame]
Amith Yamasani220f4d62009-07-02 02:34:14 -07001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.providers.settings;
18
Svetoslav Ganova571a582011-09-20 18:32:20 -070019import android.app.backup.BackupAgentHelper;
20import android.app.backup.BackupDataInput;
21import android.app.backup.BackupDataOutput;
22import android.app.backup.FullBackupDataOutput;
Christopher Tate87bc7e72013-06-10 16:55:02 -070023import android.content.ContentResolver;
Svetoslav Ganova571a582011-09-20 18:32:20 -070024import android.content.ContentValues;
25import android.content.Context;
26import android.database.Cursor;
Ritesh Reddyadca34a2016-02-04 18:33:30 +000027import android.net.NetworkPolicy;
28import android.net.NetworkPolicyManager;
Svetoslav Ganova571a582011-09-20 18:32:20 -070029import android.net.Uri;
Christopher Tatecab915a2015-01-08 12:50:00 -080030import android.net.wifi.WifiConfiguration;
31import android.net.wifi.WifiConfiguration.KeyMgmt;
Svetoslav Ganova571a582011-09-20 18:32:20 -070032import android.net.wifi.WifiManager;
33import android.os.FileUtils;
Christopher Tated488bc02012-10-09 14:06:30 -070034import android.os.Handler;
Svetoslav Ganova571a582011-09-20 18:32:20 -070035import android.os.ParcelFileDescriptor;
36import android.os.Process;
Amith Yamasani072543f2015-02-13 11:09:45 -080037import android.os.UserHandle;
Svetoslav Ganova571a582011-09-20 18:32:20 -070038import android.provider.Settings;
Ritesh Reddyaeb4c062016-01-26 19:40:48 +000039import android.util.BackupUtils;
Svetoslav Ganova571a582011-09-20 18:32:20 -070040import android.util.Log;
41
Amith Yamasani072543f2015-02-13 11:09:45 -080042import com.android.internal.widget.LockPatternUtils;
43
Christopher Tatecab915a2015-01-08 12:50:00 -080044import libcore.io.IoUtils;
45
Brad Fitzpatrick70787892010-11-17 11:31:12 -080046import java.io.BufferedOutputStream;
Amith Yamasani2cfab842009-09-09 18:27:31 -070047import java.io.BufferedReader;
48import java.io.BufferedWriter;
Amith Yamasani072543f2015-02-13 11:09:45 -080049import java.io.ByteArrayInputStream;
Christopher Tatecab915a2015-01-08 12:50:00 -080050import java.io.ByteArrayOutputStream;
Christopher Tate8dfe2b92012-05-15 15:05:04 -070051import java.io.CharArrayReader;
Amith Yamasanid1582142009-07-08 20:04:55 -070052import java.io.DataInputStream;
53import java.io.DataOutputStream;
Amith Yamasani2cfab842009-09-09 18:27:31 -070054import java.io.EOFException;
Amith Yamasani220f4d62009-07-02 02:34:14 -070055import java.io.File;
56import java.io.FileInputStream;
57import java.io.FileOutputStream;
Amith Yamasani2cfab842009-09-09 18:27:31 -070058import java.io.FileReader;
59import java.io.FileWriter;
Amith Yamasani220f4d62009-07-02 02:34:14 -070060import java.io.IOException;
Svetoslav Ganova571a582011-09-20 18:32:20 -070061import java.io.InputStream;
Brad Fitzpatrick70787892010-11-17 11:31:12 -080062import java.io.OutputStream;
Christopher Tatecab915a2015-01-08 12:50:00 -080063import java.io.OutputStreamWriter;
Christopher Tate8dfe2b92012-05-15 15:05:04 -070064import java.io.Writer;
65import java.util.ArrayList;
Christopher Tatecab915a2015-01-08 12:50:00 -080066import java.util.BitSet;
Svetoslav Ganova571a582011-09-20 18:32:20 -070067import java.util.HashMap;
Christopher Tate8dfe2b92012-05-15 15:05:04 -070068import java.util.HashSet;
Christopher Tatecab915a2015-01-08 12:50:00 -080069import java.util.List;
Svetoslav Ganova571a582011-09-20 18:32:20 -070070import java.util.Map;
Christopher Tatecab915a2015-01-08 12:50:00 -080071import java.util.Objects;
Amith Yamasanid1582142009-07-08 20:04:55 -070072import java.util.zip.CRC32;
Amith Yamasani220f4d62009-07-02 02:34:14 -070073
Amith Yamasani220f4d62009-07-02 02:34:14 -070074/**
75 * Performs backup and restore of the System and Secure settings.
76 * List of settings that are backed up are stored in the Settings.java file
77 */
Christopher Tatecc84c692010-03-29 14:54:02 -070078public class SettingsBackupAgent extends BackupAgentHelper {
Christopher Tate436344a2009-09-30 16:17:37 -070079 private static final boolean DEBUG = false;
Christopher Tate8dfe2b92012-05-15 15:05:04 -070080 private static final boolean DEBUG_BACKUP = DEBUG || false;
Amith Yamasani220f4d62009-07-02 02:34:14 -070081
82 private static final String KEY_SYSTEM = "system";
83 private static final String KEY_SECURE = "secure";
Christopher Tate66488d62012-10-02 11:58:01 -070084 private static final String KEY_GLOBAL = "global";
Amith Yamasani8823c0a82009-07-07 14:30:17 -070085 private static final String KEY_LOCALE = "locale";
Amith Yamasani072543f2015-02-13 11:09:45 -080086 private static final String KEY_LOCK_SETTINGS = "lock_settings";
Ritesh Reddyaeb4c062016-01-26 19:40:48 +000087 private static final String KEY_SOFTAP_CONFIG = "softap_config";
Ritesh Reddyadca34a2016-02-04 18:33:30 +000088 private static final String KEY_NETWORK_POLICIES = "network_policies";
Amith Yamasani220f4d62009-07-02 02:34:14 -070089
Christopher Tatea286f412009-09-18 15:51:15 -070090 // Versioning of the state file. Increment this version
91 // number any time the set of state items is altered.
Ritesh Reddyadca34a2016-02-04 18:33:30 +000092 private static final int STATE_VERSION = 6;
93
94 // Versioning of the Network Policies backup payload.
95 private static final int NETWORK_POLICIES_BACKUP_VERSION = 1;
96
Christopher Tatea286f412009-09-18 15:51:15 -070097
Christopher Tate66488d62012-10-02 11:58:01 -070098 // Slots in the checksum array. Never insert new items in the middle
99 // of this array; new slots must be appended.
Ritesh Reddyadca34a2016-02-04 18:33:30 +0000100 private static final int STATE_SYSTEM = 0;
101 private static final int STATE_SECURE = 1;
102 private static final int STATE_LOCALE = 2;
103 private static final int STATE_WIFI_SUPPLICANT = 3;
104 private static final int STATE_WIFI_CONFIG = 4;
105 private static final int STATE_GLOBAL = 5;
106 private static final int STATE_LOCK_SETTINGS = 6;
107 private static final int STATE_SOFTAP_CONFIG = 7;
108 private static final int STATE_NETWORK_POLICIES = 8;
Christopher Tate66488d62012-10-02 11:58:01 -0700109
Ritesh Reddyadca34a2016-02-04 18:33:30 +0000110 private static final int STATE_SIZE = 9; // The current number of state items
Christopher Tate66488d62012-10-02 11:58:01 -0700111
112 // Number of entries in the checksum array at various version numbers
113 private static final int STATE_SIZES[] = {
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000114 0,
115 4, // version 1
116 5, // version 2 added STATE_WIFI_CONFIG
117 6, // version 3 added STATE_GLOBAL
118 7, // version 4 added STATE_LOCK_SETTINGS
Ritesh Reddyadca34a2016-02-04 18:33:30 +0000119 8, // version 5 added STATE_SOFTAP_CONFIG
120 STATE_SIZE // version 6 added STATE_NETWORK_POLICIES
Christopher Tate66488d62012-10-02 11:58:01 -0700121 };
Amith Yamasanid1582142009-07-08 20:04:55 -0700122
Christopher Tate75a99702011-05-18 16:28:19 -0700123 // Versioning of the 'full backup' format
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000124 // Increment this version any time a new item is added
Ritesh Reddyadca34a2016-02-04 18:33:30 +0000125 private static final int FULL_BACKUP_VERSION = 5;
Christopher Tate66488d62012-10-02 11:58:01 -0700126 private static final int FULL_BACKUP_ADDED_GLOBAL = 2; // added the "global" entry
Amith Yamasani072543f2015-02-13 11:09:45 -0800127 private static final int FULL_BACKUP_ADDED_LOCK_SETTINGS = 3; // added the "lock_settings" entry
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000128 private static final int FULL_BACKUP_ADDED_SOFTAP_CONF = 4; //added the "softap_config" entry
Ritesh Reddyadca34a2016-02-04 18:33:30 +0000129 private static final int FULL_BACKUP_ADDED_NETWORK_POLICIES = 5; //added "network_policies"
Christopher Tate75a99702011-05-18 16:28:19 -0700130
Svetoslav Ganova571a582011-09-20 18:32:20 -0700131 private static final int INTEGER_BYTE_COUNT = Integer.SIZE / Byte.SIZE;
Amith Yamasani220f4d62009-07-02 02:34:14 -0700132
133 private static final byte[] EMPTY_DATA = new byte[0];
134
135 private static final String TAG = "SettingsBackupAgent";
136
Amith Yamasani220f4d62009-07-02 02:34:14 -0700137 private static final String[] PROJECTION = {
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000138 Settings.NameValueTable.NAME,
139 Settings.NameValueTable.VALUE
Amith Yamasani220f4d62009-07-02 02:34:14 -0700140 };
141
142 private static final String FILE_WIFI_SUPPLICANT = "/data/misc/wifi/wpa_supplicant.conf";
Amith Yamasani2cfab842009-09-09 18:27:31 -0700143 private static final String FILE_WIFI_SUPPLICANT_TEMPLATE =
144 "/system/etc/wifi/wpa_supplicant.conf";
Christian Sonntag92c17522009-08-07 15:16:17 -0700145
146 // the key to store the WIFI data under, should be sorted as last, so restore happens last.
147 // use very late unicode character to quasi-guarantee last sort position.
Amith Yamasani2cfab842009-09-09 18:27:31 -0700148 private static final String KEY_WIFI_SUPPLICANT = "\uffedWIFI";
Irfan Sheriff4aeca7c52011-03-10 16:53:33 -0800149 private static final String KEY_WIFI_CONFIG = "\uffedCONFIG_WIFI";
Amith Yamasani220f4d62009-07-02 02:34:14 -0700150
Amith Yamasani072543f2015-02-13 11:09:45 -0800151 // Keys within the lock settings section
152 private static final String KEY_LOCK_SETTINGS_OWNER_INFO_ENABLED = "owner_info_enabled";
153 private static final String KEY_LOCK_SETTINGS_OWNER_INFO = "owner_info";
154
Christopher Tate4a627c72011-04-01 14:43:32 -0700155 // Name of the temporary file we use during full backup/restore. This is
156 // stored in the full-backup tarfile as well, so should not be changed.
157 private static final String STAGE_FILE = "flattened-data";
158
Christopher Tated488bc02012-10-09 14:06:30 -0700159 // Delay in milliseconds between the restore operation and when we will bounce
160 // wifi in order to rewrite the supplicant config etc.
161 private static final long WIFI_BOUNCE_DELAY_MILLIS = 60 * 1000; // one minute
162
Amith Yamasani220f4d62009-07-02 02:34:14 -0700163 private SettingsHelper mSettingsHelper;
Irfan Sheriff4aeca7c52011-03-10 16:53:33 -0800164 private WifiManager mWfm;
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000165 private String mWifiConfigFile;
Amith Yamasani220f4d62009-07-02 02:34:14 -0700166
Christopher Tate45dc0d02015-08-07 19:20:05 -0700167 // Chain of asynchronous operations used when rewriting the wifi supplicant config file
168 WifiDisableRunnable mWifiDisable = null;
Christopher Tated488bc02012-10-09 14:06:30 -0700169 WifiRestoreRunnable mWifiRestore = null;
Christopher Tate45dc0d02015-08-07 19:20:05 -0700170 int mRetainedWifiState; // used only during config file rewrite
Christopher Tated488bc02012-10-09 14:06:30 -0700171
Christopher Tate8dfe2b92012-05-15 15:05:04 -0700172 // Class for capturing a network definition from the wifi supplicant config file
173 static class Network {
174 String ssid = ""; // equals() and hashCode() need these to be non-null
175 String key_mgmt = "";
Vinit Deshapnde1d1319e2013-09-06 17:12:41 -0700176 boolean certUsed = false;
Christopher Tatecab915a2015-01-08 12:50:00 -0800177 boolean hasWepKey = false;
Christopher Tate9bc2f472015-11-17 18:01:52 -0800178 boolean isEap = false;
Christopher Tate8dfe2b92012-05-15 15:05:04 -0700179 final ArrayList<String> rawLines = new ArrayList<String>();
180
181 public static Network readFromStream(BufferedReader in) {
182 final Network n = new Network();
183 String line;
184 try {
185 while (in.ready()) {
186 line = in.readLine();
187 if (line == null || line.startsWith("}")) {
188 break;
189 }
190 n.rememberLine(line);
191 }
192 } catch (IOException e) {
193 return null;
194 }
195 return n;
196 }
197
198 void rememberLine(String line) {
199 // can't rely on particular whitespace patterns so strip leading/trailing
200 line = line.trim();
201 if (line.isEmpty()) return; // only whitespace; drop the line
202 rawLines.add(line);
203
204 // remember the ssid and key_mgmt lines for duplicate culling
Christopher Tatecab915a2015-01-08 12:50:00 -0800205 if (line.startsWith("ssid=")) {
Christopher Tate8dfe2b92012-05-15 15:05:04 -0700206 ssid = line;
Christopher Tatecab915a2015-01-08 12:50:00 -0800207 } else if (line.startsWith("key_mgmt=")) {
Christopher Tate8dfe2b92012-05-15 15:05:04 -0700208 key_mgmt = line;
Christopher Tate9bc2f472015-11-17 18:01:52 -0800209 if (line.contains("EAP")) {
210 isEap = true;
211 }
Vinit Deshapnde1d1319e2013-09-06 17:12:41 -0700212 } else if (line.startsWith("client_cert=")) {
213 certUsed = true;
214 } else if (line.startsWith("ca_cert=")) {
215 certUsed = true;
216 } else if (line.startsWith("ca_path=")) {
217 certUsed = true;
Christopher Tatecab915a2015-01-08 12:50:00 -0800218 } else if (line.startsWith("wep_")) {
219 hasWepKey = true;
Christopher Tate9bc2f472015-11-17 18:01:52 -0800220 } else if (line.startsWith("eap=")) {
221 isEap = true;
Christopher Tate8dfe2b92012-05-15 15:05:04 -0700222 }
223 }
224
225 public void write(Writer w) throws IOException {
226 w.write("\nnetwork={\n");
227 for (String line : rawLines) {
228 w.write("\t" + line + "\n");
229 }
230 w.write("}\n");
231 }
232
233 public void dump() {
234 Log.v(TAG, "network={");
235 for (String line : rawLines) {
236 Log.v(TAG, " " + line);
237 }
238 Log.v(TAG, "}");
239 }
240
Christopher Tatecab915a2015-01-08 12:50:00 -0800241 // Calculate the equivalent of WifiConfiguration's configKey()
242 public String configKey() {
243 if (ssid == null) {
244 // No SSID => malformed network definition
245 return null;
246 }
247
248 final String bareSsid = ssid.substring(ssid.indexOf('=') + 1);
249
250 final BitSet types = new BitSet();
251 if (key_mgmt == null) {
252 // no key_mgmt specified; this is defined as equivalent to "WPA-PSK WPA-EAP"
253 types.set(KeyMgmt.WPA_PSK);
254 types.set(KeyMgmt.WPA_EAP);
255 } else {
256 // Need to parse the key_mgmt line
257 final String bareKeyMgmt = key_mgmt.substring(key_mgmt.indexOf('=') + 1);
258 String[] typeStrings = bareKeyMgmt.split("\\s+");
259
260 // Parse out all the key management regimes permitted for this network. The literal
261 // strings here are the standard values permitted in wpa_supplicant.conf.
262 for (int i = 0; i < typeStrings.length; i++) {
263 final String ktype = typeStrings[i];
264 if (ktype.equals("WPA-PSK")) {
265 Log.v(TAG, " + setting WPA_PSK bit");
266 types.set(KeyMgmt.WPA_PSK);
267 } else if (ktype.equals("WPA-EAP")) {
268 Log.v(TAG, " + setting WPA_EAP bit");
269 types.set(KeyMgmt.WPA_EAP);
270 } else if (ktype.equals("IEEE8021X")) {
271 Log.v(TAG, " + setting IEEE8021X bit");
272 types.set(KeyMgmt.IEEE8021X);
273 }
274 }
275 }
276
277 // Now build the canonical config key paralleling the WifiConfiguration semantics
278 final String key;
279 if (types.get(KeyMgmt.WPA_PSK)) {
280 key = bareSsid + KeyMgmt.strings[KeyMgmt.WPA_PSK];
281 } else if (types.get(KeyMgmt.WPA_EAP) || types.get(KeyMgmt.IEEE8021X)) {
282 key = bareSsid + KeyMgmt.strings[KeyMgmt.WPA_EAP];
283 } else if (hasWepKey) {
284 key = bareSsid + "WEP"; // hardcoded this way in WifiConfiguration
285 } else {
286 key = bareSsid + KeyMgmt.strings[KeyMgmt.NONE];
287 }
288 return key;
289 }
290
Christopher Tate8dfe2b92012-05-15 15:05:04 -0700291 // Same approach as Pair.equals() and Pair.hashCode()
292 @Override
293 public boolean equals(Object o) {
294 if (o == this) return true;
295 if (!(o instanceof Network)) return false;
296 final Network other;
297 try {
298 other = (Network) o;
299 } catch (ClassCastException e) {
300 return false;
301 }
302 return ssid.equals(other.ssid) && key_mgmt.equals(other.key_mgmt);
303 }
304
305 @Override
306 public int hashCode() {
307 int result = 17;
308 result = 31 * result + ssid.hashCode();
309 result = 31 * result + key_mgmt.hashCode();
310 return result;
311 }
312 }
313
Christopher Tatecab915a2015-01-08 12:50:00 -0800314 boolean networkInWhitelist(Network net, List<WifiConfiguration> whitelist) {
315 final String netConfigKey = net.configKey();
316 final int N = whitelist.size();
317 for (int i = 0; i < N; i++) {
318 if (Objects.equals(netConfigKey, whitelist.get(i).configKey(true))) {
319 return true;
320 }
321 }
322 return false;
323 }
324
Christopher Tate8dfe2b92012-05-15 15:05:04 -0700325 // Ingest multiple wifi config file fragments, looking for network={} blocks
326 // and eliminating duplicates
327 class WifiNetworkSettings {
328 // One for fast lookup, one for maintaining ordering
329 final HashSet<Network> mKnownNetworks = new HashSet<Network>();
330 final ArrayList<Network> mNetworks = new ArrayList<Network>(8);
331
Paul Stewart45e6fec2016-05-20 08:14:30 -0700332 public void readNetworks(BufferedReader in, List<WifiConfiguration> whitelist,
333 boolean acceptEapNetworks) {
Christopher Tate8dfe2b92012-05-15 15:05:04 -0700334 try {
335 String line;
336 while (in.ready()) {
337 line = in.readLine();
338 if (line != null) {
339 // Parse out 'network=' decls so we can ignore duplicates
340 if (line.startsWith("network")) {
341 Network net = Network.readFromStream(in);
Christopher Tatecab915a2015-01-08 12:50:00 -0800342 if (whitelist != null) {
343 if (!networkInWhitelist(net, whitelist)) {
344 if (DEBUG_BACKUP) {
345 Log.v(TAG, "Network not in whitelist, skipping: "
346 + net.ssid + " / " + net.key_mgmt);
347 }
348 continue;
349 }
350 }
Christopher Tate9bc2f472015-11-17 18:01:52 -0800351 // Don't propagate EAP network definitions
Paul Stewart45e6fec2016-05-20 08:14:30 -0700352 if (net.isEap && !acceptEapNetworks) {
Christopher Tate9bc2f472015-11-17 18:01:52 -0800353 if (DEBUG_BACKUP) {
354 Log.v(TAG, "Skipping EAP network " + net.ssid + " / " + net.key_mgmt);
355 }
356 continue;
357 }
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000358 if (!mKnownNetworks.contains(net)) {
Christopher Tate8dfe2b92012-05-15 15:05:04 -0700359 if (DEBUG_BACKUP) {
360 Log.v(TAG, "Adding " + net.ssid + " / " + net.key_mgmt);
361 }
362 mKnownNetworks.add(net);
363 mNetworks.add(net);
364 } else {
365 if (DEBUG_BACKUP) {
366 Log.v(TAG, "Dupe; skipped " + net.ssid + " / " + net.key_mgmt);
367 }
368 }
369 }
370 }
371 }
372 } catch (IOException e) {
373 // whatever happened, we're done now
374 }
375 }
376
377 public void write(Writer w) throws IOException {
378 for (Network net : mNetworks) {
Vinit Deshapnde1d1319e2013-09-06 17:12:41 -0700379 if (net.certUsed) {
380 // Networks that use certificates for authentication can't be restored
381 // because the certificates they need don't get restored (because they
382 // are stored in keystore, and can't be restored)
383 continue;
384 }
385
Christopher Tate9bc2f472015-11-17 18:01:52 -0800386 if (net.isEap) {
387 // Similarly, omit EAP network definitions to avoid propagating
388 // controlled enterprise network definitions.
389 continue;
390 }
391
Christopher Tate8dfe2b92012-05-15 15:05:04 -0700392 net.write(w);
393 }
394 }
395
396 public void dump() {
397 for (Network net : mNetworks) {
398 net.dump();
399 }
400 }
401 }
402
Svetoslav Ganova571a582011-09-20 18:32:20 -0700403 @Override
Amith Yamasani220f4d62009-07-02 02:34:14 -0700404 public void onCreate() {
Christopher Tate75a99702011-05-18 16:28:19 -0700405 if (DEBUG_BACKUP) Log.d(TAG, "onCreate() invoked");
406
Amith Yamasani220f4d62009-07-02 02:34:14 -0700407 mSettingsHelper = new SettingsHelper(this);
408 super.onCreate();
Irfan Sheriff4aeca7c52011-03-10 16:53:33 -0800409
410 WifiManager mWfm = (WifiManager) getSystemService(Context.WIFI_SERVICE);
411 if (mWfm != null) mWifiConfigFile = mWfm.getConfigFile();
Amith Yamasani220f4d62009-07-02 02:34:14 -0700412 }
413
414 @Override
415 public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
Ritesh Reddy33117fe2016-02-01 13:45:33 +0000416 ParcelFileDescriptor newState) throws IOException {
Amith Yamasani220f4d62009-07-02 02:34:14 -0700417
418 byte[] systemSettingsData = getSystemSettings();
419 byte[] secureSettingsData = getSecureSettings();
Christopher Tate66488d62012-10-02 11:58:01 -0700420 byte[] globalSettingsData = getGlobalSettings();
Amith Yamasani072543f2015-02-13 11:09:45 -0800421 byte[] lockSettingsData = getLockSettings();
Amith Yamasani8823c0a82009-07-07 14:30:17 -0700422 byte[] locale = mSettingsHelper.getLocaleData();
Irfan Sheriff4aeca7c52011-03-10 16:53:33 -0800423 byte[] wifiSupplicantData = getWifiSupplicant(FILE_WIFI_SUPPLICANT);
424 byte[] wifiConfigData = getFileData(mWifiConfigFile);
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000425 byte[] softApConfigData = getSoftAPConfiguration();
Ritesh Reddyadca34a2016-02-04 18:33:30 +0000426 byte[] netPoliciesData = getNetworkPolicies();
Amith Yamasani220f4d62009-07-02 02:34:14 -0700427
Christopher Tate79ec80d2011-06-24 14:58:49 -0700428 long[] stateChecksums = readOldChecksums(oldState);
Amith Yamasani220f4d62009-07-02 02:34:14 -0700429
Christopher Tate79ec80d2011-06-24 14:58:49 -0700430 stateChecksums[STATE_SYSTEM] =
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000431 writeIfChanged(stateChecksums[STATE_SYSTEM], KEY_SYSTEM, systemSettingsData, data);
Christopher Tate79ec80d2011-06-24 14:58:49 -0700432 stateChecksums[STATE_SECURE] =
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000433 writeIfChanged(stateChecksums[STATE_SECURE], KEY_SECURE, secureSettingsData, data);
Christopher Tate66488d62012-10-02 11:58:01 -0700434 stateChecksums[STATE_GLOBAL] =
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000435 writeIfChanged(stateChecksums[STATE_GLOBAL], KEY_GLOBAL, globalSettingsData, data);
Christopher Tate79ec80d2011-06-24 14:58:49 -0700436 stateChecksums[STATE_LOCALE] =
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000437 writeIfChanged(stateChecksums[STATE_LOCALE], KEY_LOCALE, locale, data);
Christopher Tate79ec80d2011-06-24 14:58:49 -0700438 stateChecksums[STATE_WIFI_SUPPLICANT] =
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000439 writeIfChanged(stateChecksums[STATE_WIFI_SUPPLICANT], KEY_WIFI_SUPPLICANT,
440 wifiSupplicantData, data);
Christopher Tate79ec80d2011-06-24 14:58:49 -0700441 stateChecksums[STATE_WIFI_CONFIG] =
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000442 writeIfChanged(stateChecksums[STATE_WIFI_CONFIG], KEY_WIFI_CONFIG, wifiConfigData,
443 data);
Amith Yamasani072543f2015-02-13 11:09:45 -0800444 stateChecksums[STATE_LOCK_SETTINGS] =
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000445 writeIfChanged(stateChecksums[STATE_LOCK_SETTINGS], KEY_LOCK_SETTINGS,
446 lockSettingsData, data);
447 stateChecksums[STATE_SOFTAP_CONFIG] =
448 writeIfChanged(stateChecksums[STATE_SOFTAP_CONFIG], KEY_SOFTAP_CONFIG,
449 softApConfigData, data);
Ritesh Reddyadca34a2016-02-04 18:33:30 +0000450 stateChecksums[STATE_NETWORK_POLICIES] =
451 writeIfChanged(stateChecksums[STATE_NETWORK_POLICIES], KEY_NETWORK_POLICIES,
452 netPoliciesData, data);
Amith Yamasani8823c0a82009-07-07 14:30:17 -0700453
Christopher Tate79ec80d2011-06-24 14:58:49 -0700454 writeNewChecksums(stateChecksums, newState);
Amith Yamasani220f4d62009-07-02 02:34:14 -0700455 }
456
Christopher Tate45dc0d02015-08-07 19:20:05 -0700457 class WifiDisableRunnable implements Runnable {
458 final WifiRestoreRunnable mNextPhase;
459
460 public WifiDisableRunnable(WifiRestoreRunnable next) {
461 mNextPhase = next;
462 }
463
464 @Override
465 public void run() {
466 if (DEBUG_BACKUP) {
467 Log.v(TAG, "Disabling wifi during restore");
468 }
469 final ContentResolver cr = getContentResolver();
470 final int scanAlways = Settings.Global.getInt(cr,
471 Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, 0);
472 final int retainedWifiState = enableWifi(false);
473 if (scanAlways != 0) {
474 Settings.Global.putInt(cr,
475 Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, 0);
476 }
477
478 // Tell the final stage how to clean up after itself
479 mNextPhase.setPriorState(retainedWifiState, scanAlways);
480
481 // And run it after a modest pause to give broadcasts and content
482 // observers time an opportunity to run on this looper thread, so
483 // that the wifi stack actually goes all the way down.
484 new Handler(getMainLooper()).postDelayed(mNextPhase, 2500);
485 }
486 }
487
Christopher Tated488bc02012-10-09 14:06:30 -0700488 class WifiRestoreRunnable implements Runnable {
489 private byte[] restoredSupplicantData;
490 private byte[] restoredWifiConfigFile;
Christopher Tate45dc0d02015-08-07 19:20:05 -0700491 private int retainedWifiState; // provided by disable stage
492 private int scanAlways; // provided by disable stage
493
494 void setPriorState(int retainedState, int always) {
495 retainedWifiState = retainedState;
496 scanAlways = always;
497 }
Christopher Tated488bc02012-10-09 14:06:30 -0700498
499 void incorporateWifiSupplicant(BackupDataInput data) {
500 restoredSupplicantData = new byte[data.getDataSize()];
501 if (restoredSupplicantData.length <= 0) return;
502 try {
503 data.readEntityData(restoredSupplicantData, 0, data.getDataSize());
504 } catch (IOException e) {
505 Log.w(TAG, "Unable to read supplicant data");
506 restoredSupplicantData = null;
507 }
508 }
509
510 void incorporateWifiConfigFile(BackupDataInput data) {
511 restoredWifiConfigFile = new byte[data.getDataSize()];
512 if (restoredWifiConfigFile.length <= 0) return;
513 try {
514 data.readEntityData(restoredWifiConfigFile, 0, data.getDataSize());
515 } catch (IOException e) {
516 Log.w(TAG, "Unable to read config file");
517 restoredWifiConfigFile = null;
518 }
519 }
520
521 @Override
522 public void run() {
523 if (restoredSupplicantData != null || restoredWifiConfigFile != null) {
524 if (DEBUG_BACKUP) {
Christopher Tate45dc0d02015-08-07 19:20:05 -0700525 Log.v(TAG, "Applying restored wifi data");
Christopher Tated488bc02012-10-09 14:06:30 -0700526 }
Christopher Tated488bc02012-10-09 14:06:30 -0700527 if (restoredSupplicantData != null) {
528 restoreWifiSupplicant(FILE_WIFI_SUPPLICANT,
529 restoredSupplicantData, restoredSupplicantData.length);
530 FileUtils.setPermissions(FILE_WIFI_SUPPLICANT,
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000531 FileUtils.S_IRUSR | FileUtils.S_IWUSR
532 | FileUtils.S_IRGRP | FileUtils.S_IWGRP,
Christopher Tated488bc02012-10-09 14:06:30 -0700533 Process.myUid(), Process.WIFI_UID);
534 }
535 if (restoredWifiConfigFile != null) {
536 restoreFileData(mWifiConfigFile,
537 restoredWifiConfigFile, restoredWifiConfigFile.length);
538 }
539 // restore the previous WIFI state.
Christopher Tate87bc7e72013-06-10 16:55:02 -0700540 if (scanAlways != 0) {
Christopher Tate45dc0d02015-08-07 19:20:05 -0700541 Settings.Global.putInt(getContentResolver(),
Christopher Tate87bc7e72013-06-10 16:55:02 -0700542 Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, scanAlways);
543 }
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000544 enableWifi(retainedWifiState == WifiManager.WIFI_STATE_ENABLED
545 || retainedWifiState == WifiManager.WIFI_STATE_ENABLING);
Christopher Tated488bc02012-10-09 14:06:30 -0700546 }
547 }
548 }
549
550 // Instantiate the wifi-config restore runnable, scheduling it for execution
551 // a minute hence
552 void initWifiRestoreIfNecessary() {
553 if (mWifiRestore == null) {
554 mWifiRestore = new WifiRestoreRunnable();
Christopher Tate45dc0d02015-08-07 19:20:05 -0700555 mWifiDisable = new WifiDisableRunnable(mWifiRestore);
Christopher Tated488bc02012-10-09 14:06:30 -0700556 }
557 }
558
Amith Yamasani220f4d62009-07-02 02:34:14 -0700559 @Override
560 public void onRestore(BackupDataInput data, int appVersionCode,
Ritesh Reddy33117fe2016-02-01 13:45:33 +0000561 ParcelFileDescriptor newState) throws IOException {
Amith Yamasani220f4d62009-07-02 02:34:14 -0700562
Christopher Tate66488d62012-10-02 11:58:01 -0700563 HashSet<String> movedToGlobal = new HashSet<String>();
Svetoslav683914b2015-01-15 14:22:26 -0800564 Settings.System.getMovedToGlobalSettings(movedToGlobal);
565 Settings.Secure.getMovedToGlobalSettings(movedToGlobal);
Christopher Tate66488d62012-10-02 11:58:01 -0700566
Amith Yamasani220f4d62009-07-02 02:34:14 -0700567 while (data.readNextHeader()) {
568 final String key = data.getKey();
Amith Yamasani8823c0a82009-07-07 14:30:17 -0700569 final int size = data.getDataSize();
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000570 switch (key) {
571 case KEY_SYSTEM :
572 restoreSettings(data, Settings.System.CONTENT_URI, movedToGlobal);
573 mSettingsHelper.applyAudioSettings();
574 break;
575
576 case KEY_SECURE :
577 restoreSettings(data, Settings.Secure.CONTENT_URI, movedToGlobal);
578 break;
579
580 case KEY_GLOBAL :
581 restoreSettings(data, Settings.Global.CONTENT_URI, null);
582 break;
583
584 case KEY_WIFI_SUPPLICANT :
585 initWifiRestoreIfNecessary();
586 mWifiRestore.incorporateWifiSupplicant(data);
587 break;
588
589 case KEY_LOCALE :
590 byte[] localeData = new byte[size];
591 data.readEntityData(localeData, 0, size);
592 mSettingsHelper.setLocaleData(localeData, size);
593 break;
594
595 case KEY_WIFI_CONFIG :
596 initWifiRestoreIfNecessary();
597 mWifiRestore.incorporateWifiConfigFile(data);
598 break;
599
600 case KEY_LOCK_SETTINGS :
601 restoreLockSettings(data);
602 break;
603
604 case KEY_SOFTAP_CONFIG :
605 byte[] softapData = new byte[size];
606 data.readEntityData(softapData, 0, size);
607 restoreSoftApConfiguration(softapData);
608 break;
609
Ritesh Reddyadca34a2016-02-04 18:33:30 +0000610 case KEY_NETWORK_POLICIES:
611 byte[] netPoliciesData = new byte[size];
612 data.readEntityData(netPoliciesData, 0, size);
613 restoreNetworkPolicies(netPoliciesData);
614 break;
615
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000616 default :
617 data.skipEntityData();
618
Amith Yamasani220f4d62009-07-02 02:34:14 -0700619 }
620 }
Christopher Tated488bc02012-10-09 14:06:30 -0700621
622 // If we have wifi data to restore, post a runnable to perform the
Christopher Tate45dc0d02015-08-07 19:20:05 -0700623 // bounce-and-update operation a little ways in the future. The
624 // 'disable' runnable brings down the stack and remembers its state,
625 // and in turn schedules the 'restore' runnable to do the rewrite
626 // and cleanup operations.
Christopher Tated488bc02012-10-09 14:06:30 -0700627 if (mWifiRestore != null) {
Evan Charltoncc7b0432014-01-14 14:47:11 -0800628 long wifiBounceDelayMillis = Settings.Global.getLong(
629 getContentResolver(),
630 Settings.Global.WIFI_BOUNCE_DELAY_OVERRIDE_MS,
631 WIFI_BOUNCE_DELAY_MILLIS);
Christopher Tate45dc0d02015-08-07 19:20:05 -0700632 new Handler(getMainLooper()).postDelayed(mWifiDisable, wifiBounceDelayMillis);
Christopher Tated488bc02012-10-09 14:06:30 -0700633 }
Amith Yamasani220f4d62009-07-02 02:34:14 -0700634 }
635
Christopher Tate75a99702011-05-18 16:28:19 -0700636 @Override
Christopher Tate79ec80d2011-06-24 14:58:49 -0700637 public void onFullBackup(FullBackupDataOutput data) throws IOException {
638 byte[] systemSettingsData = getSystemSettings();
639 byte[] secureSettingsData = getSecureSettings();
Christopher Tate66488d62012-10-02 11:58:01 -0700640 byte[] globalSettingsData = getGlobalSettings();
Amith Yamasani072543f2015-02-13 11:09:45 -0800641 byte[] lockSettingsData = getLockSettings();
Christopher Tate79ec80d2011-06-24 14:58:49 -0700642 byte[] locale = mSettingsHelper.getLocaleData();
643 byte[] wifiSupplicantData = getWifiSupplicant(FILE_WIFI_SUPPLICANT);
644 byte[] wifiConfigData = getFileData(mWifiConfigFile);
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000645 byte[] softApConfigData = getSoftAPConfiguration();
Ritesh Reddyadca34a2016-02-04 18:33:30 +0000646 byte[] netPoliciesData = getNetworkPolicies();
Christopher Tate79ec80d2011-06-24 14:58:49 -0700647
648 // Write the data to the staging file, then emit that as our tarfile
649 // representation of the backed-up settings.
650 String root = getFilesDir().getAbsolutePath();
651 File stage = new File(root, STAGE_FILE);
652 try {
653 FileOutputStream filestream = new FileOutputStream(stage);
654 BufferedOutputStream bufstream = new BufferedOutputStream(filestream);
655 DataOutputStream out = new DataOutputStream(bufstream);
656
Christopher Tate2efd2db2011-07-19 16:32:49 -0700657 if (DEBUG_BACKUP) Log.d(TAG, "Writing flattened data version " + FULL_BACKUP_VERSION);
Christopher Tate79ec80d2011-06-24 14:58:49 -0700658 out.writeInt(FULL_BACKUP_VERSION);
659
Christopher Tate2efd2db2011-07-19 16:32:49 -0700660 if (DEBUG_BACKUP) Log.d(TAG, systemSettingsData.length + " bytes of settings data");
Christopher Tate79ec80d2011-06-24 14:58:49 -0700661 out.writeInt(systemSettingsData.length);
662 out.write(systemSettingsData);
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000663 if (DEBUG_BACKUP) {
664 Log.d(TAG, secureSettingsData.length + " bytes of secure settings data");
665 }
Christopher Tate79ec80d2011-06-24 14:58:49 -0700666 out.writeInt(secureSettingsData.length);
667 out.write(secureSettingsData);
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000668 if (DEBUG_BACKUP) {
669 Log.d(TAG, globalSettingsData.length + " bytes of global settings data");
670 }
Christopher Tate66488d62012-10-02 11:58:01 -0700671 out.writeInt(globalSettingsData.length);
672 out.write(globalSettingsData);
Christopher Tate2efd2db2011-07-19 16:32:49 -0700673 if (DEBUG_BACKUP) Log.d(TAG, locale.length + " bytes of locale data");
Christopher Tate79ec80d2011-06-24 14:58:49 -0700674 out.writeInt(locale.length);
675 out.write(locale);
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000676 if (DEBUG_BACKUP) {
677 Log.d(TAG, wifiSupplicantData.length + " bytes of wifi supplicant data");
678 }
Christopher Tate79ec80d2011-06-24 14:58:49 -0700679 out.writeInt(wifiSupplicantData.length);
680 out.write(wifiSupplicantData);
Christopher Tate2efd2db2011-07-19 16:32:49 -0700681 if (DEBUG_BACKUP) Log.d(TAG, wifiConfigData.length + " bytes of wifi config data");
Christopher Tate79ec80d2011-06-24 14:58:49 -0700682 out.writeInt(wifiConfigData.length);
683 out.write(wifiConfigData);
Amith Yamasani072543f2015-02-13 11:09:45 -0800684 if (DEBUG_BACKUP) Log.d(TAG, lockSettingsData.length + " bytes of lock settings data");
685 out.writeInt(lockSettingsData.length);
686 out.write(lockSettingsData);
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000687 if (DEBUG_BACKUP) Log.d(TAG, softApConfigData.length + " bytes of softap config data");
688 out.writeInt(softApConfigData.length);
689 out.write(softApConfigData);
Ritesh Reddyadca34a2016-02-04 18:33:30 +0000690 if (DEBUG_BACKUP) Log.d(TAG, netPoliciesData.length + " bytes of net policies data");
691 out.writeInt(netPoliciesData.length);
692 out.write(netPoliciesData);
Christopher Tate79ec80d2011-06-24 14:58:49 -0700693
694 out.flush(); // also flushes downstream
695
696 // now we're set to emit the tar stream
697 fullBackupFile(stage, data);
698 } finally {
699 stage.delete();
700 }
701 }
702
703 @Override
Christopher Tate75a99702011-05-18 16:28:19 -0700704 public void onRestoreFile(ParcelFileDescriptor data, long size,
Ritesh Reddy33117fe2016-02-01 13:45:33 +0000705 int type, String domain, String relpath, long mode, long mtime)
Christopher Tate75a99702011-05-18 16:28:19 -0700706 throws IOException {
707 if (DEBUG_BACKUP) Log.d(TAG, "onRestoreFile() invoked");
708 // Our data is actually a blob of flattened settings data identical to that
709 // produced during incremental backups. Just unpack and apply it all in
710 // turn.
711 FileInputStream instream = new FileInputStream(data.getFileDescriptor());
712 DataInputStream in = new DataInputStream(instream);
713
714 int version = in.readInt();
715 if (DEBUG_BACKUP) Log.d(TAG, "Flattened data version " + version);
Christopher Tate66488d62012-10-02 11:58:01 -0700716 if (version <= FULL_BACKUP_VERSION) {
717 // Generate the moved-to-global lookup table
718 HashSet<String> movedToGlobal = new HashSet<String>();
Svetoslav683914b2015-01-15 14:22:26 -0800719 Settings.System.getMovedToGlobalSettings(movedToGlobal);
720 Settings.Secure.getMovedToGlobalSettings(movedToGlobal);
Christopher Tate66488d62012-10-02 11:58:01 -0700721
Christopher Tate75a99702011-05-18 16:28:19 -0700722 // system settings data first
723 int nBytes = in.readInt();
724 if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of settings data");
725 byte[] buffer = new byte[nBytes];
Christopher Tate2efd2db2011-07-19 16:32:49 -0700726 in.readFully(buffer, 0, nBytes);
Christopher Tate66488d62012-10-02 11:58:01 -0700727 restoreSettings(buffer, nBytes, Settings.System.CONTENT_URI, movedToGlobal);
Christopher Tate75a99702011-05-18 16:28:19 -0700728
729 // secure settings
730 nBytes = in.readInt();
731 if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of secure settings data");
732 if (nBytes > buffer.length) buffer = new byte[nBytes];
Christopher Tate2efd2db2011-07-19 16:32:49 -0700733 in.readFully(buffer, 0, nBytes);
Christopher Tate66488d62012-10-02 11:58:01 -0700734 restoreSettings(buffer, nBytes, Settings.Secure.CONTENT_URI, movedToGlobal);
735
736 // Global only if sufficiently new
737 if (version >= FULL_BACKUP_ADDED_GLOBAL) {
738 nBytes = in.readInt();
739 if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of global settings data");
740 if (nBytes > buffer.length) buffer = new byte[nBytes];
741 in.readFully(buffer, 0, nBytes);
742 movedToGlobal.clear(); // no redirection; this *is* the global namespace
743 restoreSettings(buffer, nBytes, Settings.Global.CONTENT_URI, movedToGlobal);
744 }
Christopher Tate75a99702011-05-18 16:28:19 -0700745
746 // locale
747 nBytes = in.readInt();
748 if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of locale data");
749 if (nBytes > buffer.length) buffer = new byte[nBytes];
Christopher Tate2efd2db2011-07-19 16:32:49 -0700750 in.readFully(buffer, 0, nBytes);
Christopher Tate75a99702011-05-18 16:28:19 -0700751 mSettingsHelper.setLocaleData(buffer, nBytes);
752
753 // wifi supplicant
754 nBytes = in.readInt();
755 if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of wifi supplicant data");
756 if (nBytes > buffer.length) buffer = new byte[nBytes];
Christopher Tate2efd2db2011-07-19 16:32:49 -0700757 in.readFully(buffer, 0, nBytes);
Christopher Tate75a99702011-05-18 16:28:19 -0700758 int retainedWifiState = enableWifi(false);
759 restoreWifiSupplicant(FILE_WIFI_SUPPLICANT, buffer, nBytes);
760 FileUtils.setPermissions(FILE_WIFI_SUPPLICANT,
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000761 FileUtils.S_IRUSR | FileUtils.S_IWUSR
762 | FileUtils.S_IRGRP | FileUtils.S_IWGRP,
Christopher Tate75a99702011-05-18 16:28:19 -0700763 Process.myUid(), Process.WIFI_UID);
764 // retain the previous WIFI state.
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000765 enableWifi(retainedWifiState == WifiManager.WIFI_STATE_ENABLED
766 || retainedWifiState == WifiManager.WIFI_STATE_ENABLING);
Christopher Tate75a99702011-05-18 16:28:19 -0700767
768 // wifi config
769 nBytes = in.readInt();
770 if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of wifi config data");
771 if (nBytes > buffer.length) buffer = new byte[nBytes];
Christopher Tate2efd2db2011-07-19 16:32:49 -0700772 in.readFully(buffer, 0, nBytes);
Christopher Tate75a99702011-05-18 16:28:19 -0700773 restoreFileData(mWifiConfigFile, buffer, nBytes);
774
Amith Yamasani072543f2015-02-13 11:09:45 -0800775 if (version >= FULL_BACKUP_ADDED_LOCK_SETTINGS) {
776 nBytes = in.readInt();
777 if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of lock settings data");
778 if (nBytes > buffer.length) buffer = new byte[nBytes];
779 if (nBytes > 0) {
780 in.readFully(buffer, 0, nBytes);
781 restoreLockSettings(buffer, nBytes);
782 }
783 }
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000784 // softap config
785 if (version >= FULL_BACKUP_ADDED_SOFTAP_CONF) {
786 nBytes = in.readInt();
787 if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of softap config data");
788 if (nBytes > buffer.length) buffer = new byte[nBytes];
789 if (nBytes > 0) {
790 in.readFully(buffer, 0, nBytes);
791 restoreSoftApConfiguration(buffer);
792 }
793 }
Ritesh Reddyadca34a2016-02-04 18:33:30 +0000794 // network policies
795 if (version >= FULL_BACKUP_ADDED_NETWORK_POLICIES) {
796 nBytes = in.readInt();
797 if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of network policies data");
798 if (nBytes > buffer.length) buffer = new byte[nBytes];
799 if (nBytes > 0) {
800 in.readFully(buffer, 0, nBytes);
801 restoreNetworkPolicies(buffer);
802 }
803 }
Christopher Tate75a99702011-05-18 16:28:19 -0700804 if (DEBUG_BACKUP) Log.d(TAG, "Full restore complete.");
805 } else {
806 data.close();
807 throw new IOException("Invalid file schema");
808 }
809 }
810
Amith Yamasanid1582142009-07-08 20:04:55 -0700811 private long[] readOldChecksums(ParcelFileDescriptor oldState) throws IOException {
812 long[] stateChecksums = new long[STATE_SIZE];
813
814 DataInputStream dataInput = new DataInputStream(
815 new FileInputStream(oldState.getFileDescriptor()));
Christopher Tatea286f412009-09-18 15:51:15 -0700816
817 try {
818 int stateVersion = dataInput.readInt();
Ritesh Reddy2400d272016-02-02 11:42:26 +0000819 if (stateVersion > STATE_VERSION) {
820 // Constrain the maximum state version this backup agent
821 // can handle in case a newer or corrupt backup set existed
822 stateVersion = STATE_VERSION;
823 }
Christopher Tate66488d62012-10-02 11:58:01 -0700824 for (int i = 0; i < STATE_SIZES[stateVersion]; i++) {
825 stateChecksums[i] = dataInput.readLong();
Amith Yamasanid1582142009-07-08 20:04:55 -0700826 }
Christopher Tatea286f412009-09-18 15:51:15 -0700827 } catch (EOFException eof) {
828 // With the default 0 checksum we'll wind up forcing a backup of
829 // any unhandled data sets, which is appropriate.
Amith Yamasanid1582142009-07-08 20:04:55 -0700830 }
831 dataInput.close();
832 return stateChecksums;
833 }
834
835 private void writeNewChecksums(long[] checksums, ParcelFileDescriptor newState)
836 throws IOException {
837 DataOutputStream dataOutput = new DataOutputStream(
Marvin Paul68795552014-12-16 14:12:33 -0800838 new BufferedOutputStream(new FileOutputStream(newState.getFileDescriptor())));
Christopher Tatea286f412009-09-18 15:51:15 -0700839
840 dataOutput.writeInt(STATE_VERSION);
Amith Yamasanid1582142009-07-08 20:04:55 -0700841 for (int i = 0; i < STATE_SIZE; i++) {
842 dataOutput.writeLong(checksums[i]);
843 }
844 dataOutput.close();
845 }
846
847 private long writeIfChanged(long oldChecksum, String key, byte[] data,
Ritesh Reddy33117fe2016-02-01 13:45:33 +0000848 BackupDataOutput output) {
Amith Yamasanid1582142009-07-08 20:04:55 -0700849 CRC32 checkSummer = new CRC32();
850 checkSummer.update(data);
851 long newChecksum = checkSummer.getValue();
852 if (oldChecksum == newChecksum) {
853 return oldChecksum;
854 }
855 try {
Amith Yamasani072543f2015-02-13 11:09:45 -0800856 if (DEBUG_BACKUP) {
857 Log.v(TAG, "Writing entity " + key + " of size " + data.length);
858 }
Amith Yamasanid1582142009-07-08 20:04:55 -0700859 output.writeEntityHeader(key, data.length);
860 output.writeEntityData(data, data.length);
861 } catch (IOException ioe) {
862 // Bail
863 }
864 return newChecksum;
865 }
866
Amith Yamasani220f4d62009-07-02 02:34:14 -0700867 private byte[] getSystemSettings() {
Svetoslav Ganova571a582011-09-20 18:32:20 -0700868 Cursor cursor = getContentResolver().query(Settings.System.CONTENT_URI, PROJECTION, null,
869 null, null);
Jeff Brown1d8e7d62011-10-09 15:24:53 -0700870 try {
871 return extractRelevantValues(cursor, Settings.System.SETTINGS_TO_BACKUP);
872 } finally {
873 cursor.close();
874 }
Amith Yamasani220f4d62009-07-02 02:34:14 -0700875 }
876
877 private byte[] getSecureSettings() {
Svetoslav Ganova571a582011-09-20 18:32:20 -0700878 Cursor cursor = getContentResolver().query(Settings.Secure.CONTENT_URI, PROJECTION, null,
879 null, null);
Jeff Brown1d8e7d62011-10-09 15:24:53 -0700880 try {
881 return extractRelevantValues(cursor, Settings.Secure.SETTINGS_TO_BACKUP);
882 } finally {
883 cursor.close();
884 }
Amith Yamasani220f4d62009-07-02 02:34:14 -0700885 }
886
Christopher Tate66488d62012-10-02 11:58:01 -0700887 private byte[] getGlobalSettings() {
888 Cursor cursor = getContentResolver().query(Settings.Global.CONTENT_URI, PROJECTION, null,
889 null, null);
890 try {
891 return extractRelevantValues(cursor, Settings.Global.SETTINGS_TO_BACKUP);
892 } finally {
893 cursor.close();
894 }
895 }
896
Amith Yamasani072543f2015-02-13 11:09:45 -0800897 /**
898 * Serialize the owner info settings
899 */
900 private byte[] getLockSettings() {
901 final LockPatternUtils lockPatternUtils = new LockPatternUtils(this);
Adrian Roos8150d2a2015-04-16 17:11:20 -0700902 final boolean ownerInfoEnabled = lockPatternUtils.isOwnerInfoEnabled(UserHandle.myUserId());
Amith Yamasani072543f2015-02-13 11:09:45 -0800903 final String ownerInfo = lockPatternUtils.getOwnerInfo(UserHandle.myUserId());
904
905 ByteArrayOutputStream baos = new ByteArrayOutputStream();
906 DataOutputStream out = new DataOutputStream(baos);
907 try {
908 out.writeUTF(KEY_LOCK_SETTINGS_OWNER_INFO_ENABLED);
909 out.writeUTF(ownerInfoEnabled ? "1" : "0");
910 if (ownerInfo != null) {
911 out.writeUTF(KEY_LOCK_SETTINGS_OWNER_INFO);
912 out.writeUTF(ownerInfo != null ? ownerInfo : "");
913 }
914 // End marker
915 out.writeUTF("");
916 out.flush();
917 } catch (IOException ioe) {
918 }
919 return baos.toByteArray();
920 }
921
Christopher Tate66488d62012-10-02 11:58:01 -0700922 private void restoreSettings(BackupDataInput data, Uri contentUri,
Ritesh Reddy33117fe2016-02-01 13:45:33 +0000923 HashSet<String> movedToGlobal) {
Christopher Tate75a99702011-05-18 16:28:19 -0700924 byte[] settings = new byte[data.getDataSize()];
925 try {
926 data.readEntityData(settings, 0, settings.length);
927 } catch (IOException ioe) {
928 Log.e(TAG, "Couldn't read entity data");
929 return;
930 }
Christopher Tate66488d62012-10-02 11:58:01 -0700931 restoreSettings(settings, settings.length, contentUri, movedToGlobal);
Christopher Tate75a99702011-05-18 16:28:19 -0700932 }
933
Christopher Tate66488d62012-10-02 11:58:01 -0700934 private void restoreSettings(byte[] settings, int bytes, Uri contentUri,
Ritesh Reddy33117fe2016-02-01 13:45:33 +0000935 HashSet<String> movedToGlobal) {
Svetoslav Ganova571a582011-09-20 18:32:20 -0700936 if (DEBUG) {
937 Log.i(TAG, "restoreSettings: " + contentUri);
938 }
939
Christopher Tate66488d62012-10-02 11:58:01 -0700940 // Figure out the white list and redirects to the global table.
Christopher Tate6597e342015-02-17 12:15:25 -0800941 final String[] whitelist;
Christopher Tate796e0f02009-09-22 11:57:58 -0700942 if (contentUri.equals(Settings.Secure.CONTENT_URI)) {
943 whitelist = Settings.Secure.SETTINGS_TO_BACKUP;
944 } else if (contentUri.equals(Settings.System.CONTENT_URI)) {
945 whitelist = Settings.System.SETTINGS_TO_BACKUP;
Christopher Tate66488d62012-10-02 11:58:01 -0700946 } else if (contentUri.equals(Settings.Global.CONTENT_URI)) {
947 whitelist = Settings.Global.SETTINGS_TO_BACKUP;
Svetoslav Ganova571a582011-09-20 18:32:20 -0700948 } else {
949 throw new IllegalArgumentException("Unknown URI: " + contentUri);
Christopher Tate796e0f02009-09-22 11:57:58 -0700950 }
951
Svetoslav Ganova571a582011-09-20 18:32:20 -0700952 // Restore only the white list data.
Amith Yamasani220f4d62009-07-02 02:34:14 -0700953 int pos = 0;
Svetoslav Ganova571a582011-09-20 18:32:20 -0700954 Map<String, String> cachedEntries = new HashMap<String, String>();
955 ContentValues contentValues = new ContentValues(2);
956 SettingsHelper settingsHelper = mSettingsHelper;
Christopher Tate6597e342015-02-17 12:15:25 -0800957 ContentResolver cr = getContentResolver();
Christopher Tate0738e882009-09-11 16:35:39 -0700958
Svetoslav Ganova571a582011-09-20 18:32:20 -0700959 final int whiteListSize = whitelist.length;
960 for (int i = 0; i < whiteListSize; i++) {
961 String key = whitelist[i];
962 String value = cachedEntries.remove(key);
Christopher Tate0738e882009-09-11 16:35:39 -0700963
Svetoslav Ganova571a582011-09-20 18:32:20 -0700964 // If the value not cached, let us look it up.
965 if (value == null) {
966 while (pos < bytes) {
967 int length = readInt(settings, pos);
968 pos += INTEGER_BYTE_COUNT;
969 String dataKey = length > 0 ? new String(settings, pos, length) : null;
970 pos += length;
971 length = readInt(settings, pos);
972 pos += INTEGER_BYTE_COUNT;
973 String dataValue = length > 0 ? new String(settings, pos, length) : null;
974 pos += length;
975 if (key.equals(dataKey)) {
976 value = dataValue;
977 break;
978 }
979 cachedEntries.put(dataKey, dataValue);
Amith Yamasani70c874b2009-07-06 14:53:25 -0700980 }
Amith Yamasani220f4d62009-07-02 02:34:14 -0700981 }
Amith Yamasani220f4d62009-07-02 02:34:14 -0700982
Svetoslav Ganova571a582011-09-20 18:32:20 -0700983 if (value == null) {
984 continue;
985 }
Christopher Tate796e0f02009-09-22 11:57:58 -0700986
Christopher Tate3543beb2012-10-05 13:35:12 -0700987 final Uri destination = (movedToGlobal != null && movedToGlobal.contains(key))
Christopher Tate66488d62012-10-02 11:58:01 -0700988 ? Settings.Global.CONTENT_URI
989 : contentUri;
Christopher Tate6597e342015-02-17 12:15:25 -0800990 settingsHelper.restoreValue(this, cr, contentValues, destination, key, value);
Svetoslav Ganova571a582011-09-20 18:32:20 -0700991
Christopher Tated488bc02012-10-09 14:06:30 -0700992 if (DEBUG) {
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000993 Log.d(TAG, "Restored setting: " + destination + " : " + key + "=" + value);
Christopher Tate0738e882009-09-11 16:35:39 -0700994 }
995 }
Amith Yamasani220f4d62009-07-02 02:34:14 -0700996 }
997
998 /**
Amith Yamasani072543f2015-02-13 11:09:45 -0800999 * Restores the owner info enabled and owner info settings in LockSettings.
1000 *
1001 * @param buffer
1002 * @param nBytes
1003 */
1004 private void restoreLockSettings(byte[] buffer, int nBytes) {
1005 final LockPatternUtils lockPatternUtils = new LockPatternUtils(this);
1006
1007 ByteArrayInputStream bais = new ByteArrayInputStream(buffer, 0, nBytes);
1008 DataInputStream in = new DataInputStream(bais);
1009 try {
1010 String key;
1011 // Read until empty string marker
1012 while ((key = in.readUTF()).length() > 0) {
1013 final String value = in.readUTF();
1014 if (DEBUG_BACKUP) {
1015 Log.v(TAG, "Restoring lock_settings " + key + " = " + value);
1016 }
1017 switch (key) {
1018 case KEY_LOCK_SETTINGS_OWNER_INFO_ENABLED:
Adrian Roos8150d2a2015-04-16 17:11:20 -07001019 lockPatternUtils.setOwnerInfoEnabled("1".equals(value),
1020 UserHandle.myUserId());
Amith Yamasani072543f2015-02-13 11:09:45 -08001021 break;
1022 case KEY_LOCK_SETTINGS_OWNER_INFO:
1023 lockPatternUtils.setOwnerInfo(value, UserHandle.myUserId());
1024 break;
1025 }
1026 }
1027 in.close();
1028 } catch (IOException ioe) {
1029 }
1030 }
1031
1032 private void restoreLockSettings(BackupDataInput data) {
1033 final byte[] settings = new byte[data.getDataSize()];
1034 try {
1035 data.readEntityData(settings, 0, settings.length);
1036 } catch (IOException ioe) {
1037 Log.e(TAG, "Couldn't read entity data");
1038 return;
1039 }
1040 restoreLockSettings(settings, settings.length);
1041 }
1042
1043 /**
Svetoslav Ganova571a582011-09-20 18:32:20 -07001044 * Given a cursor and a set of keys, extract the required keys and
1045 * values and write them to a byte array.
1046 *
1047 * @param cursor A cursor with settings data.
1048 * @param settings The settings to extract.
1049 * @return The byte array of extracted values.
Amith Yamasani220f4d62009-07-02 02:34:14 -07001050 */
Svetoslav Ganova571a582011-09-20 18:32:20 -07001051 private byte[] extractRelevantValues(Cursor cursor, String[] settings) {
1052 final int settingsCount = settings.length;
1053 byte[][] values = new byte[settingsCount * 2][]; // keys and values
1054 if (!cursor.moveToFirst()) {
Amith Yamasani220f4d62009-07-02 02:34:14 -07001055 Log.e(TAG, "Couldn't read from the cursor");
1056 return new byte[0];
1057 }
Svetoslav Ganova571a582011-09-20 18:32:20 -07001058
1059 // Obtain the relevant data in a temporary array.
Amith Yamasani220f4d62009-07-02 02:34:14 -07001060 int totalSize = 0;
Svetoslav Ganova571a582011-09-20 18:32:20 -07001061 int backedUpSettingIndex = 0;
1062 Map<String, String> cachedEntries = new HashMap<String, String>();
1063 for (int i = 0; i < settingsCount; i++) {
1064 String key = settings[i];
1065 String value = cachedEntries.remove(key);
1066
Svetoslav683914b2015-01-15 14:22:26 -08001067 final int nameColumnIndex = cursor.getColumnIndex(Settings.NameValueTable.NAME);
1068 final int valueColumnIndex = cursor.getColumnIndex(Settings.NameValueTable.VALUE);
1069
Svetoslav Ganova571a582011-09-20 18:32:20 -07001070 // If the value not cached, let us look it up.
1071 if (value == null) {
1072 while (!cursor.isAfterLast()) {
Svetoslav683914b2015-01-15 14:22:26 -08001073 String cursorKey = cursor.getString(nameColumnIndex);
1074 String cursorValue = cursor.getString(valueColumnIndex);
Svetoslav Ganova571a582011-09-20 18:32:20 -07001075 cursor.moveToNext();
1076 if (key.equals(cursorKey)) {
1077 value = cursorValue;
1078 break;
1079 }
1080 cachedEntries.put(cursorKey, cursorValue);
Amith Yamasani220f4d62009-07-02 02:34:14 -07001081 }
Amith Yamasani220f4d62009-07-02 02:34:14 -07001082 }
Svetoslav Ganova571a582011-09-20 18:32:20 -07001083
Amith Yamasani622bf2222013-09-06 13:54:28 -07001084 // Intercept the keys and see if they need special handling
1085 value = mSettingsHelper.onBackupValue(key, value);
1086
Svetoslav Ganova571a582011-09-20 18:32:20 -07001087 if (value == null) {
1088 continue;
1089 }
Svetoslav Ganova571a582011-09-20 18:32:20 -07001090 // Write the key and value in the intermediary array.
1091 byte[] keyBytes = key.getBytes();
1092 totalSize += INTEGER_BYTE_COUNT + keyBytes.length;
1093 values[backedUpSettingIndex * 2] = keyBytes;
1094
1095 byte[] valueBytes = value.getBytes();
1096 totalSize += INTEGER_BYTE_COUNT + valueBytes.length;
1097 values[backedUpSettingIndex * 2 + 1] = valueBytes;
1098
1099 backedUpSettingIndex++;
1100
1101 if (DEBUG) {
1102 Log.d(TAG, "Backed up setting: " + key + "=" + value);
Amith Yamasani220f4d62009-07-02 02:34:14 -07001103 }
1104 }
1105
Svetoslav Ganova571a582011-09-20 18:32:20 -07001106 // Aggregate the result.
Amith Yamasani220f4d62009-07-02 02:34:14 -07001107 byte[] result = new byte[totalSize];
1108 int pos = 0;
Svetoslav Ganova571a582011-09-20 18:32:20 -07001109 final int keyValuePairCount = backedUpSettingIndex * 2;
1110 for (int i = 0; i < keyValuePairCount; i++) {
1111 pos = writeInt(result, pos, values[i].length);
1112 pos = writeBytes(result, pos, values[i]);
Amith Yamasani220f4d62009-07-02 02:34:14 -07001113 }
1114 return result;
1115 }
1116
Irfan Sheriff4aeca7c52011-03-10 16:53:33 -08001117 private byte[] getFileData(String filename) {
1118 InputStream is = null;
1119 try {
1120 File file = new File(filename);
1121 is = new FileInputStream(file);
1122
1123 //Will truncate read on a very long file,
1124 //should not happen for a config file
Ritesh Reddyaeb4c062016-01-26 19:40:48 +00001125 byte[] bytes = new byte[(int) file.length()];
Irfan Sheriff4aeca7c52011-03-10 16:53:33 -08001126
1127 int offset = 0;
1128 int numRead = 0;
1129 while (offset < bytes.length
Ritesh Reddyaeb4c062016-01-26 19:40:48 +00001130 && (numRead = is.read(bytes, offset, bytes.length - offset)) >= 0) {
Irfan Sheriff4aeca7c52011-03-10 16:53:33 -08001131 offset += numRead;
1132 }
1133
1134 //read failure
1135 if (offset < bytes.length) {
1136 Log.w(TAG, "Couldn't backup " + filename);
1137 return EMPTY_DATA;
1138 }
1139 return bytes;
1140 } catch (IOException ioe) {
1141 Log.w(TAG, "Couldn't backup " + filename);
1142 return EMPTY_DATA;
1143 } finally {
1144 if (is != null) {
1145 try {
1146 is.close();
1147 } catch (IOException e) {
1148 }
1149 }
1150 }
Irfan Sheriff4aeca7c52011-03-10 16:53:33 -08001151 }
1152
Christopher Tate75a99702011-05-18 16:28:19 -07001153 private void restoreFileData(String filename, byte[] bytes, int size) {
Irfan Sheriff4aeca7c52011-03-10 16:53:33 -08001154 try {
Irfan Sheriff4aeca7c52011-03-10 16:53:33 -08001155 File file = new File(filename);
1156 if (file.exists()) file.delete();
1157
1158 OutputStream os = new BufferedOutputStream(new FileOutputStream(filename, true));
Christopher Tate75a99702011-05-18 16:28:19 -07001159 os.write(bytes, 0, size);
Irfan Sheriff4aeca7c52011-03-10 16:53:33 -08001160 os.close();
1161 } catch (IOException ioe) {
1162 Log.w(TAG, "Couldn't restore " + filename);
1163 }
1164 }
1165
1166
Amith Yamasani2cfab842009-09-09 18:27:31 -07001167 private byte[] getWifiSupplicant(String filename) {
Brad Fitzpatrick70787892010-11-17 11:31:12 -08001168 BufferedReader br = null;
Amith Yamasani220f4d62009-07-02 02:34:14 -07001169 try {
1170 File file = new File(filename);
Christopher Tatecab915a2015-01-08 12:50:00 -08001171 if (!file.exists()) {
1172 return EMPTY_DATA;
1173 }
1174
1175 WifiManager wifi = (WifiManager) getSystemService(WIFI_SERVICE);
1176 List<WifiConfiguration> configs = wifi.getConfiguredNetworks();
1177
1178 WifiNetworkSettings fromFile = new WifiNetworkSettings();
1179 br = new BufferedReader(new FileReader(file));
Paul Stewart45e6fec2016-05-20 08:14:30 -07001180 fromFile.readNetworks(br, configs, false);
Christopher Tatecab915a2015-01-08 12:50:00 -08001181
1182 // Write the parsed networks into a packed byte array
1183 if (fromFile.mKnownNetworks.size() > 0) {
1184 ByteArrayOutputStream bos = new ByteArrayOutputStream();
1185 OutputStreamWriter out = new OutputStreamWriter(bos);
1186 fromFile.write(out);
Christopher Tate129ea762015-02-17 17:04:01 -08001187 out.flush();
Christopher Tatecab915a2015-01-08 12:50:00 -08001188 return bos.toByteArray();
Amith Yamasani220f4d62009-07-02 02:34:14 -07001189 } else {
Amith Yamasanid1582142009-07-08 20:04:55 -07001190 return EMPTY_DATA;
Amith Yamasani220f4d62009-07-02 02:34:14 -07001191 }
1192 } catch (IOException ioe) {
1193 Log.w(TAG, "Couldn't backup " + filename);
Amith Yamasanid1582142009-07-08 20:04:55 -07001194 return EMPTY_DATA;
Brad Fitzpatrick70787892010-11-17 11:31:12 -08001195 } finally {
Christopher Tatecab915a2015-01-08 12:50:00 -08001196 IoUtils.closeQuietly(br);
Amith Yamasani220f4d62009-07-02 02:34:14 -07001197 }
1198 }
1199
Christopher Tate75a99702011-05-18 16:28:19 -07001200 private void restoreWifiSupplicant(String filename, byte[] bytes, int size) {
Amith Yamasani220f4d62009-07-02 02:34:14 -07001201 try {
Christopher Tate8dfe2b92012-05-15 15:05:04 -07001202 WifiNetworkSettings supplicantImage = new WifiNetworkSettings();
Amith Yamasani2cfab842009-09-09 18:27:31 -07001203
Christopher Tate8dfe2b92012-05-15 15:05:04 -07001204 File supplicantFile = new File(FILE_WIFI_SUPPLICANT);
1205 if (supplicantFile.exists()) {
1206 // Retain the existing APs; we'll append the restored ones to them
1207 BufferedReader in = new BufferedReader(new FileReader(FILE_WIFI_SUPPLICANT));
Paul Stewart45e6fec2016-05-20 08:14:30 -07001208 supplicantImage.readNetworks(in, null, true);
Christopher Tate8dfe2b92012-05-15 15:05:04 -07001209 in.close();
1210
1211 supplicantFile.delete();
1212 }
1213
1214 // Incorporate the restore AP information
1215 if (size > 0) {
1216 char[] restoredAsBytes = new char[size];
1217 for (int i = 0; i < size; i++) restoredAsBytes[i] = (char) bytes[i];
1218 BufferedReader in = new BufferedReader(new CharArrayReader(restoredAsBytes));
Paul Stewart45e6fec2016-05-20 08:14:30 -07001219 supplicantImage.readNetworks(in, null, false);
Christopher Tate8dfe2b92012-05-15 15:05:04 -07001220
1221 if (DEBUG_BACKUP) {
1222 Log.v(TAG, "Final AP list:");
1223 supplicantImage.dump();
1224 }
1225 }
1226
1227 // Install the correct default template
1228 BufferedWriter bw = new BufferedWriter(new FileWriter(FILE_WIFI_SUPPLICANT));
1229 copyWifiSupplicantTemplate(bw);
1230
1231 // Write the restored supplicant config and we're done
1232 supplicantImage.write(bw);
1233 bw.close();
Amith Yamasani220f4d62009-07-02 02:34:14 -07001234 } catch (IOException ioe) {
1235 Log.w(TAG, "Couldn't restore " + filename);
1236 }
1237 }
1238
Christopher Tate8dfe2b92012-05-15 15:05:04 -07001239 private void copyWifiSupplicantTemplate(BufferedWriter bw) {
Amith Yamasani2cfab842009-09-09 18:27:31 -07001240 try {
1241 BufferedReader br = new BufferedReader(new FileReader(FILE_WIFI_SUPPLICANT_TEMPLATE));
Amith Yamasani2cfab842009-09-09 18:27:31 -07001242 char[] temp = new char[1024];
1243 int size;
1244 while ((size = br.read(temp)) > 0) {
1245 bw.write(temp, 0, size);
1246 }
Amith Yamasani2cfab842009-09-09 18:27:31 -07001247 br.close();
1248 } catch (IOException ioe) {
1249 Log.w(TAG, "Couldn't copy wpa_supplicant file");
1250 }
1251 }
1252
Ritesh Reddyaeb4c062016-01-26 19:40:48 +00001253 private byte[] getSoftAPConfiguration() {
1254 WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
1255 try {
1256 return wifiManager.getWifiApConfiguration().getBytesForBackup();
1257 } catch (IOException ioe) {
1258 Log.e(TAG, "Failed to marshal SoftAPConfiguration" + ioe.getMessage());
1259 return new byte[0];
1260 }
1261 }
1262
1263 private void restoreSoftApConfiguration(byte[] data) {
1264 WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
1265 try {
1266 WifiConfiguration config = WifiConfiguration
1267 .getWifiConfigFromBackup(new DataInputStream(new ByteArrayInputStream(data)));
1268 if (DEBUG) Log.d(TAG, "Successfully unMarshaled WifiConfiguration ");
1269 wifiManager.setWifiApConfiguration(config);
1270 } catch (IOException | BackupUtils.BadVersionException e) {
1271 Log.e(TAG, "Failed to unMarshal SoftAPConfiguration " + e.getMessage());
1272 }
1273 }
1274
Ritesh Reddyadca34a2016-02-04 18:33:30 +00001275 private byte[] getNetworkPolicies() {
1276 NetworkPolicyManager networkPolicyManager =
1277 (NetworkPolicyManager) getSystemService(NETWORK_POLICY_SERVICE);
1278 NetworkPolicy[] policies = networkPolicyManager.getNetworkPolicies();
1279 ByteArrayOutputStream baos = new ByteArrayOutputStream();
1280 if (policies != null && policies.length != 0) {
1281 DataOutputStream out = new DataOutputStream(baos);
1282 try {
1283 out.writeInt(NETWORK_POLICIES_BACKUP_VERSION);
1284 out.writeInt(policies.length);
1285 for (NetworkPolicy policy : policies) {
1286 if (policy != null) {
1287 byte[] marshaledPolicy = policy.getBytesForBackup();
1288 out.writeByte(BackupUtils.NOT_NULL);
1289 out.writeInt(marshaledPolicy.length);
1290 out.write(marshaledPolicy);
1291 } else {
1292 out.writeByte(BackupUtils.NULL);
1293 }
1294 }
1295 } catch (IOException ioe) {
1296 Log.e(TAG, "Failed to convert NetworkPolicies to byte array " + ioe.getMessage());
1297 baos.reset();
1298 }
1299 }
1300 return baos.toByteArray();
1301 }
1302
1303 private void restoreNetworkPolicies(byte[] data) {
1304 NetworkPolicyManager networkPolicyManager =
1305 (NetworkPolicyManager) getSystemService(NETWORK_POLICY_SERVICE);
1306 if (data != null && data.length != 0) {
1307 DataInputStream in = new DataInputStream(new ByteArrayInputStream(data));
1308 try {
1309 int version = in.readInt();
1310 if (version < 1 || version > NETWORK_POLICIES_BACKUP_VERSION) {
1311 throw new BackupUtils.BadVersionException(
1312 "Unknown Backup Serialization Version");
1313 }
1314 int length = in.readInt();
1315 NetworkPolicy[] policies = new NetworkPolicy[length];
1316 for (int i = 0; i < length; i++) {
1317 byte isNull = in.readByte();
1318 if (isNull == BackupUtils.NULL) continue;
1319 int byteLength = in.readInt();
1320 byte[] policyData = new byte[byteLength];
1321 in.read(policyData, 0, byteLength);
1322 policies[i] = NetworkPolicy.getNetworkPolicyFromBackup(
1323 new DataInputStream(new ByteArrayInputStream(policyData)));
1324 }
1325 // Only set the policies if there was no error in the restore operation
1326 networkPolicyManager.setNetworkPolicies(policies);
1327 } catch (NullPointerException | IOException | BackupUtils.BadVersionException e) {
1328 // NPE can be thrown when trying to instantiate a NetworkPolicy
1329 Log.e(TAG, "Failed to convert byte array to NetworkPolicies " + e.getMessage());
1330 }
1331 }
1332 }
1333
Amith Yamasani220f4d62009-07-02 02:34:14 -07001334 /**
1335 * Write an int in BigEndian into the byte array.
1336 * @param out byte array
1337 * @param pos current pos in array
1338 * @param value integer to write
Svetoslav Ganova571a582011-09-20 18:32:20 -07001339 * @return the index after adding the size of an int (4) in bytes.
Amith Yamasani220f4d62009-07-02 02:34:14 -07001340 */
1341 private int writeInt(byte[] out, int pos, int value) {
1342 out[pos + 0] = (byte) ((value >> 24) & 0xFF);
1343 out[pos + 1] = (byte) ((value >> 16) & 0xFF);
1344 out[pos + 2] = (byte) ((value >> 8) & 0xFF);
1345 out[pos + 3] = (byte) ((value >> 0) & 0xFF);
Svetoslav Ganova571a582011-09-20 18:32:20 -07001346 return pos + INTEGER_BYTE_COUNT;
Amith Yamasani220f4d62009-07-02 02:34:14 -07001347 }
1348
1349 private int writeBytes(byte[] out, int pos, byte[] value) {
1350 System.arraycopy(value, 0, out, pos, value.length);
1351 return pos + value.length;
1352 }
1353
1354 private int readInt(byte[] in, int pos) {
Ritesh Reddyaeb4c062016-01-26 19:40:48 +00001355 int result = ((in[pos] & 0xFF) << 24)
1356 | ((in[pos + 1] & 0xFF) << 16)
1357 | ((in[pos + 2] & 0xFF) << 8)
1358 | ((in[pos + 3] & 0xFF) << 0);
Amith Yamasani220f4d62009-07-02 02:34:14 -07001359 return result;
1360 }
1361
Christian Sonntagc5b5b0f2009-08-07 10:00:21 -07001362 private int enableWifi(boolean enable) {
Irfan Sheriff4f4f5162012-04-27 14:42:42 -07001363 if (mWfm == null) {
1364 mWfm = (WifiManager) getSystemService(Context.WIFI_SERVICE);
1365 }
Irfan Sheriff4aeca7c52011-03-10 16:53:33 -08001366 if (mWfm != null) {
1367 int state = mWfm.getWifiState();
1368 mWfm.setWifiEnabled(enable);
Christian Sonntagc5b5b0f2009-08-07 10:00:21 -07001369 return state;
Irfan Sheriff4f4f5162012-04-27 14:42:42 -07001370 } else {
1371 Log.e(TAG, "Failed to fetch WifiManager instance");
Amith Yamasani220f4d62009-07-02 02:34:14 -07001372 }
Christian Sonntagc5b5b0f2009-08-07 10:00:21 -07001373 return WifiManager.WIFI_STATE_UNKNOWN;
Amith Yamasani220f4d62009-07-02 02:34:14 -07001374 }
Paul Stewart45e6fec2016-05-20 08:14:30 -07001375}