Fix wifi disable during restore

The main looper needs to run freely for a moment after disabling
wifi in order for various signals (content observers, broadcast) to
propagate to all the listeners that need to take action for the
wifi stack to shut all the way down.  This patch breaks up the
disable-and-rewrite-config sequence of wifi AP restore in to two
distinct operations separated by a moment so as not to block those
necessary messages.

Bug 22979342

Change-Id: I271766cad0e454669a194652fb67f835bb022cd1
This commit is contained in:
Christopher Tate
2015-08-07 19:20:05 -07:00
parent 9d92955894
commit 45dc0d03fd

View File

@@ -148,7 +148,10 @@ public class SettingsBackupAgent extends BackupAgentHelper {
private WifiManager mWfm;
private static String mWifiConfigFile;
// Chain of asynchronous operations used when rewriting the wifi supplicant config file
WifiDisableRunnable mWifiDisable = null;
WifiRestoreRunnable mWifiRestore = null;
int mRetainedWifiState; // used only during config file rewrite
// Class for capturing a network definition from the wifi supplicant config file
static class Network {
@@ -407,9 +410,47 @@ public class SettingsBackupAgent extends BackupAgentHelper {
writeNewChecksums(stateChecksums, newState);
}
class WifiDisableRunnable implements Runnable {
final WifiRestoreRunnable mNextPhase;
public WifiDisableRunnable(WifiRestoreRunnable next) {
mNextPhase = next;
}
@Override
public void run() {
if (DEBUG_BACKUP) {
Log.v(TAG, "Disabling wifi during restore");
}
final ContentResolver cr = getContentResolver();
final int scanAlways = Settings.Global.getInt(cr,
Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, 0);
final int retainedWifiState = enableWifi(false);
if (scanAlways != 0) {
Settings.Global.putInt(cr,
Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, 0);
}
// Tell the final stage how to clean up after itself
mNextPhase.setPriorState(retainedWifiState, scanAlways);
// And run it after a modest pause to give broadcasts and content
// observers time an opportunity to run on this looper thread, so
// that the wifi stack actually goes all the way down.
new Handler(getMainLooper()).postDelayed(mNextPhase, 2500);
}
}
class WifiRestoreRunnable implements Runnable {
private byte[] restoredSupplicantData;
private byte[] restoredWifiConfigFile;
private int retainedWifiState; // provided by disable stage
private int scanAlways; // provided by disable stage
void setPriorState(int retainedState, int always) {
retainedWifiState = retainedState;
scanAlways = always;
}
void incorporateWifiSupplicant(BackupDataInput data) {
restoredSupplicantData = new byte[data.getDataSize()];
@@ -437,20 +478,8 @@ public class SettingsBackupAgent extends BackupAgentHelper {
public void run() {
if (restoredSupplicantData != null || restoredWifiConfigFile != null) {
if (DEBUG_BACKUP) {
Log.v(TAG, "Starting deferred restore of wifi data");
Log.v(TAG, "Applying restored wifi data");
}
final ContentResolver cr = getContentResolver();
final int scanAlways = Settings.Global.getInt(cr,
Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, 0);
final int retainedWifiState = enableWifi(false);
if (scanAlways != 0) {
Settings.Global.putInt(cr,
Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, 0);
}
// !!! Give the wifi stack a moment to quiesce. We've observed the
// response to disabling WIFI_SCAN_ALWAYS_AVAILABLE taking more
// than 1500ms, so we wait a generous 2500 here before proceeding.
try { Thread.sleep(2500); } catch (InterruptedException e) {}
if (restoredSupplicantData != null) {
restoreWifiSupplicant(FILE_WIFI_SUPPLICANT,
restoredSupplicantData, restoredSupplicantData.length);
@@ -465,7 +494,7 @@ public class SettingsBackupAgent extends BackupAgentHelper {
}
// restore the previous WIFI state.
if (scanAlways != 0) {
Settings.Global.putInt(cr,
Settings.Global.putInt(getContentResolver(),
Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, scanAlways);
}
enableWifi(retainedWifiState == WifiManager.WIFI_STATE_ENABLED ||
@@ -479,6 +508,7 @@ public class SettingsBackupAgent extends BackupAgentHelper {
void initWifiRestoreIfNecessary() {
if (mWifiRestore == null) {
mWifiRestore = new WifiRestoreRunnable();
mWifiDisable = new WifiDisableRunnable(mWifiRestore);
}
}
@@ -518,13 +548,16 @@ public class SettingsBackupAgent extends BackupAgentHelper {
}
// If we have wifi data to restore, post a runnable to perform the
// bounce-and-update operation a little ways in the future.
// bounce-and-update operation a little ways in the future. The
// 'disable' runnable brings down the stack and remembers its state,
// and in turn schedules the 'restore' runnable to do the rewrite
// and cleanup operations.
if (mWifiRestore != null) {
long wifiBounceDelayMillis = Settings.Global.getLong(
getContentResolver(),
Settings.Global.WIFI_BOUNCE_DELAY_OVERRIDE_MS,
WIFI_BOUNCE_DELAY_MILLIS);
new Handler(getMainLooper()).postDelayed(mWifiRestore, wifiBounceDelayMillis);
new Handler(getMainLooper()).postDelayed(mWifiDisable, wifiBounceDelayMillis);
}
}