More correct startup and shutdown procedures.

During IpManager startup, anything sending messages to the state machine
must not begin doing so until after the state machine has been started.
Reorder the constructor accordingly.

During shutdown, AvoidBadWifiTracker needs to unregister the registered
BroadcastReceiver and might as well also unregister the ContentObserver.

Bug: 33388922
Change-Id: I58e07f7ccddaab160c153bcfb69fd45f50bb8710
This commit is contained in:
Erik Kline
2016-12-12 21:21:40 +09:00
parent 3a39fe6bed
commit 6c0782f1ae
3 changed files with 74 additions and 22 deletions

View File

@@ -864,6 +864,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
mAvoidBadWifiTracker = createAvoidBadWifiTracker( mAvoidBadWifiTracker = createAvoidBadWifiTracker(
mContext, mHandler, () -> rematchForAvoidBadWifiUpdate()); mContext, mHandler, () -> rematchForAvoidBadWifiUpdate());
mAvoidBadWifiTracker.start();
} }
private NetworkRequest createInternetRequestForTransport( private NetworkRequest createInternetRequestForTransport(

View File

@@ -438,6 +438,9 @@ public class IpManager extends StateMachine {
mCallback = new LoggingCallbackWrapper(callback); mCallback = new LoggingCallbackWrapper(callback);
mNwService = nwService; mNwService = nwService;
mLocalLog = new LocalLog(MAX_LOG_RECORDS);
mMsgStateLogger = new MessageHandlingLogger();
mNetlinkTracker = new NetlinkTracker( mNetlinkTracker = new NetlinkTracker(
mInterfaceName, mInterfaceName,
new NetlinkTracker.Callback() { new NetlinkTracker.Callback() {
@@ -451,48 +454,79 @@ public class IpManager extends StateMachine {
super.interfaceAdded(iface); super.interfaceAdded(iface);
if (mClatInterfaceName.equals(iface)) { if (mClatInterfaceName.equals(iface)) {
mCallback.setNeighborDiscoveryOffload(false); mCallback.setNeighborDiscoveryOffload(false);
} else if (!mInterfaceName.equals(iface)) {
return;
} }
final String msg = "interfaceAdded(" + iface +")";
logMsg(msg);
} }
@Override @Override
public void interfaceRemoved(String iface) { public void interfaceRemoved(String iface) {
super.interfaceRemoved(iface); super.interfaceRemoved(iface);
// TODO: Also observe mInterfaceName going down and take some
// kind of appropriate action.
if (mClatInterfaceName.equals(iface)) { if (mClatInterfaceName.equals(iface)) {
// TODO: consider sending a message to the IpManager main // TODO: consider sending a message to the IpManager main
// StateMachine thread, in case "NDO enabled" state becomes // StateMachine thread, in case "NDO enabled" state becomes
// tied to more things that 464xlat operation. // tied to more things that 464xlat operation.
mCallback.setNeighborDiscoveryOffload(true); mCallback.setNeighborDiscoveryOffload(true);
} else if (!mInterfaceName.equals(iface)) {
return;
} }
final String msg = "interfaceRemoved(" + iface +")";
logMsg(msg);
}
private void logMsg(String msg) {
Log.d(mTag, msg);
getHandler().post(() -> { mLocalLog.log("OBSERVED " + msg); });
} }
}; };
try { mLinkProperties = new LinkProperties();
mNwService.registerObserver(mNetlinkTracker); mLinkProperties.setInterfaceName(mInterfaceName);
} catch (RemoteException e) {
Log.e(mTag, "Couldn't register NetlinkTracker: " + e.toString());
}
mAvoidBadWifiTracker = new AvoidBadWifiTracker(mContext, getHandler()); mAvoidBadWifiTracker = new AvoidBadWifiTracker(mContext, getHandler(),
() -> { mLocalLog.log("OBSERVED AvoidBadWifi changed"); });
resetLinkProperties();
mProvisioningTimeoutAlarm = new WakeupMessage(mContext, getHandler(), mProvisioningTimeoutAlarm = new WakeupMessage(mContext, getHandler(),
mTag + ".EVENT_PROVISIONING_TIMEOUT", EVENT_PROVISIONING_TIMEOUT); mTag + ".EVENT_PROVISIONING_TIMEOUT", EVENT_PROVISIONING_TIMEOUT);
mDhcpActionTimeoutAlarm = new WakeupMessage(mContext, getHandler(), mDhcpActionTimeoutAlarm = new WakeupMessage(mContext, getHandler(),
mTag + ".EVENT_DHCPACTION_TIMEOUT", EVENT_DHCPACTION_TIMEOUT); mTag + ".EVENT_DHCPACTION_TIMEOUT", EVENT_DHCPACTION_TIMEOUT);
// Super simple StateMachine. // Anything the StateMachine may access must have been instantiated
// before this point.
configureAndStartStateMachine();
// Anything that may send messages to the StateMachine must only be
// configured to do so after the StateMachine has started (above).
startStateMachineUpdaters();
}
private void configureAndStartStateMachine() {
addState(mStoppedState); addState(mStoppedState);
addState(mStartedState); addState(mStartedState);
addState(mRunningState, mStartedState); addState(mRunningState, mStartedState);
addState(mStoppingState); addState(mStoppingState);
setInitialState(mStoppedState); setInitialState(mStoppedState);
mLocalLog = new LocalLog(MAX_LOG_RECORDS);
mMsgStateLogger = new MessageHandlingLogger();
super.start(); super.start();
} }
private void startStateMachineUpdaters() {
try {
mNwService.registerObserver(mNetlinkTracker);
} catch (RemoteException e) {
Log.e(mTag, "Couldn't register NetlinkTracker: " + e.toString());
}
mAvoidBadWifiTracker.start();
}
@Override @Override
protected void onQuitting() { protected void onQuitting() {
mCallback.onQuit(); mCallback.onQuit();
@@ -501,6 +535,7 @@ public class IpManager extends StateMachine {
// Shut down this IpManager instance altogether. // Shut down this IpManager instance altogether.
public void shutdown() { public void shutdown() {
stop(); stop();
mAvoidBadWifiTracker.shutdown();
quit(); quit();
} }

View File

@@ -57,7 +57,11 @@ public class AvoidBadWifiTracker {
private final Context mContext; private final Context mContext;
private final Handler mHandler; private final Handler mHandler;
private final Runnable mReevaluateRunnable; private final Runnable mReevaluateRunnable;
private final Uri mUri;
private final ContentResolver mResolver;
private final SettingObserver mSettingObserver; private final SettingObserver mSettingObserver;
private final BroadcastReceiver mBroadcastReceiver;
private volatile boolean mAvoidBadWifi = true; private volatile boolean mAvoidBadWifi = true;
public AvoidBadWifiTracker(Context ctx, Handler handler) { public AvoidBadWifiTracker(Context ctx, Handler handler) {
@@ -68,19 +72,36 @@ public class AvoidBadWifiTracker {
mContext = ctx; mContext = ctx;
mHandler = handler; mHandler = handler;
mReevaluateRunnable = () -> { if (update() && cb != null) cb.run(); }; mReevaluateRunnable = () -> { if (update() && cb != null) cb.run(); };
mUri = Settings.Global.getUriFor(NETWORK_AVOID_BAD_WIFI);
mResolver = mContext.getContentResolver();
mSettingObserver = new SettingObserver(); mSettingObserver = new SettingObserver();
mBroadcastReceiver = new BroadcastReceiver() {
final IntentFilter intentFilter = new IntentFilter(); @Override
intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
mContext.registerReceiverAsUser(new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
reevaluate(); reevaluate();
} }
}, UserHandle.ALL, intentFilter, null, null); };
update(); update();
} }
public void start() {
mResolver.registerContentObserver(mUri, false, mSettingObserver);
final IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
mContext.registerReceiverAsUser(
mBroadcastReceiver, UserHandle.ALL, intentFilter, null, null);
reevaluate();
}
public void shutdown() {
mResolver.unregisterContentObserver(mSettingObserver);
mContext.unregisterReceiver(mBroadcastReceiver);
}
public boolean currentValue() { public boolean currentValue() {
return mAvoidBadWifi; return mAvoidBadWifi;
} }
@@ -100,8 +121,7 @@ public class AvoidBadWifiTracker {
} }
public String getSettingsValue() { public String getSettingsValue() {
final ContentResolver resolver = mContext.getContentResolver(); return Settings.Global.getString(mResolver, NETWORK_AVOID_BAD_WIFI);
return Settings.Global.getString(resolver, NETWORK_AVOID_BAD_WIFI);
} }
@VisibleForTesting @VisibleForTesting
@@ -117,12 +137,8 @@ public class AvoidBadWifiTracker {
} }
private class SettingObserver extends ContentObserver { private class SettingObserver extends ContentObserver {
private final Uri mUri = Settings.Global.getUriFor(NETWORK_AVOID_BAD_WIFI);
public SettingObserver() { public SettingObserver() {
super(null); super(null);
final ContentResolver resolver = mContext.getContentResolver();
resolver.registerContentObserver(mUri, false, this);
} }
@Override @Override