Merge "Nat464Xlat: correct racefree teardown"
This commit is contained in:
@@ -2023,16 +2023,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case NetworkAgent.EVENT_NETWORK_PROPERTIES_CHANGED: {
|
case NetworkAgent.EVENT_NETWORK_PROPERTIES_CHANGED: {
|
||||||
if (VDBG) {
|
handleUpdateLinkProperties(nai, (LinkProperties) msg.obj);
|
||||||
log("Update of LinkProperties for " + nai.name() +
|
|
||||||
"; created=" + nai.created +
|
|
||||||
"; everConnected=" + nai.everConnected);
|
|
||||||
}
|
|
||||||
LinkProperties oldLp = nai.linkProperties;
|
|
||||||
synchronized (nai) {
|
|
||||||
nai.linkProperties = (LinkProperties)msg.obj;
|
|
||||||
}
|
|
||||||
if (nai.everConnected) updateLinkProperties(nai, oldLp);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case NetworkAgent.EVENT_NETWORK_INFO_CHANGED: {
|
case NetworkAgent.EVENT_NETWORK_INFO_CHANGED: {
|
||||||
@@ -2281,7 +2272,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
}
|
}
|
||||||
nai.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_DISCONNECTED);
|
nai.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_DISCONNECTED);
|
||||||
mNetworkAgentInfos.remove(msg.replyTo);
|
mNetworkAgentInfos.remove(msg.replyTo);
|
||||||
maybeStopClat(nai);
|
nai.maybeStopClat();
|
||||||
synchronized (mNetworkForNetId) {
|
synchronized (mNetworkForNetId) {
|
||||||
// Remove the NetworkAgent, but don't mark the netId as
|
// Remove the NetworkAgent, but don't mark the netId as
|
||||||
// available until we've told netd to delete it below.
|
// available until we've told netd to delete it below.
|
||||||
@@ -4375,7 +4366,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
updateDnses(newLp, oldLp, netId);
|
updateDnses(newLp, oldLp, netId);
|
||||||
|
|
||||||
// Start or stop clat accordingly to network state.
|
// Start or stop clat accordingly to network state.
|
||||||
updateClat(networkAgent);
|
networkAgent.updateClat(mNetd);
|
||||||
if (isDefaultNetwork(networkAgent)) {
|
if (isDefaultNetwork(networkAgent)) {
|
||||||
handleApplyDefaultProxy(newLp.getHttpProxy());
|
handleApplyDefaultProxy(newLp.getHttpProxy());
|
||||||
} else {
|
} else {
|
||||||
@@ -4390,32 +4381,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
mKeepaliveTracker.handleCheckKeepalivesStillValid(networkAgent);
|
mKeepaliveTracker.handleCheckKeepalivesStillValid(networkAgent);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateClat(NetworkAgentInfo nai) {
|
|
||||||
if (Nat464Xlat.requiresClat(nai)) {
|
|
||||||
maybeStartClat(nai);
|
|
||||||
} else {
|
|
||||||
maybeStopClat(nai);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Ensure clat has started for this network. */
|
|
||||||
private void maybeStartClat(NetworkAgentInfo nai) {
|
|
||||||
if (nai.clatd != null && nai.clatd.isStarted()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
nai.clatd = new Nat464Xlat(mNetd, mTrackerHandler, nai);
|
|
||||||
nai.clatd.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Ensure clat has stopped for this network. */
|
|
||||||
private void maybeStopClat(NetworkAgentInfo nai) {
|
|
||||||
if (nai.clatd == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
nai.clatd.stop();
|
|
||||||
nai.clatd = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void wakeupModifyInterface(String iface, NetworkCapabilities caps, boolean add) {
|
private void wakeupModifyInterface(String iface, NetworkCapabilities caps, boolean add) {
|
||||||
// Marks are only available on WiFi interaces. Checking for
|
// Marks are only available on WiFi interaces. Checking for
|
||||||
// marks on unsupported interfaces is harmless.
|
// marks on unsupported interfaces is harmless.
|
||||||
@@ -4650,6 +4615,26 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void handleUpdateLinkProperties(NetworkAgentInfo nai, LinkProperties newLp) {
|
||||||
|
if (mNetworkForNetId.get(nai.network.netId) != nai) {
|
||||||
|
// Ignore updates for disconnected networks
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (VDBG) {
|
||||||
|
log("Update of LinkProperties for " + nai.name() +
|
||||||
|
"; created=" + nai.created +
|
||||||
|
"; everConnected=" + nai.everConnected);
|
||||||
|
}
|
||||||
|
LinkProperties oldLp = nai.linkProperties;
|
||||||
|
synchronized (nai) {
|
||||||
|
nai.linkProperties = newLp;
|
||||||
|
}
|
||||||
|
if (nai.everConnected) {
|
||||||
|
updateLinkProperties(nai, oldLp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void sendUpdatedScoreToFactories(NetworkAgentInfo nai) {
|
private void sendUpdatedScoreToFactories(NetworkAgentInfo nai) {
|
||||||
for (int i = 0; i < nai.numNetworkRequests(); i++) {
|
for (int i = 0; i < nai.numNetworkRequests(); i++) {
|
||||||
NetworkRequest nr = nai.requestAt(i);
|
NetworkRequest nr = nai.requestAt(i);
|
||||||
|
|||||||
@@ -20,22 +20,21 @@ import android.net.InterfaceConfiguration;
|
|||||||
import android.net.ConnectivityManager;
|
import android.net.ConnectivityManager;
|
||||||
import android.net.LinkAddress;
|
import android.net.LinkAddress;
|
||||||
import android.net.LinkProperties;
|
import android.net.LinkProperties;
|
||||||
import android.net.NetworkAgent;
|
|
||||||
import android.net.RouteInfo;
|
import android.net.RouteInfo;
|
||||||
import android.os.Handler;
|
|
||||||
import android.os.Message;
|
|
||||||
import android.os.INetworkManagementService;
|
import android.os.INetworkManagementService;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.util.Slog;
|
import android.util.Slog;
|
||||||
|
|
||||||
import com.android.server.net.BaseNetworkObserver;
|
|
||||||
import com.android.internal.util.ArrayUtils;
|
import com.android.internal.util.ArrayUtils;
|
||||||
|
import com.android.server.net.BaseNetworkObserver;
|
||||||
|
|
||||||
import java.net.Inet4Address;
|
import java.net.Inet4Address;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class to manage a 464xlat CLAT daemon.
|
* Class to manage a 464xlat CLAT daemon. Nat464Xlat is not thread safe and should be manipulated
|
||||||
|
* from a consistent and unique thread context. It is the responsibility of ConnectivityService to
|
||||||
|
* call into this class from its own Handler thread.
|
||||||
*
|
*
|
||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
@@ -55,28 +54,23 @@ public class Nat464Xlat extends BaseNetworkObserver {
|
|||||||
|
|
||||||
private final INetworkManagementService mNMService;
|
private final INetworkManagementService mNMService;
|
||||||
|
|
||||||
// ConnectivityService Handler for LinkProperties updates.
|
|
||||||
private final Handler mHandler;
|
|
||||||
|
|
||||||
// The network we're running on, and its type.
|
// The network we're running on, and its type.
|
||||||
private final NetworkAgentInfo mNetwork;
|
private final NetworkAgentInfo mNetwork;
|
||||||
|
|
||||||
private enum State {
|
private enum State {
|
||||||
IDLE, // start() not called. Base iface and stacked iface names are null.
|
IDLE, // start() not called. Base iface and stacked iface names are null.
|
||||||
STARTING, // start() called. Base iface and stacked iface names are known.
|
STARTING, // start() called. Base iface and stacked iface names are known.
|
||||||
RUNNING; // start() called, and the stacked iface is known to be up.
|
RUNNING, // start() called, and the stacked iface is known to be up.
|
||||||
|
STOPPING; // stop() called, this Nat464Xlat is still registered as a network observer for
|
||||||
|
// the stacked interface.
|
||||||
}
|
}
|
||||||
|
|
||||||
// Once mIface is non-null and isStarted() is true, methods called by ConnectivityService on
|
|
||||||
// its handler thread must not modify any internal state variables; they are only updated by the
|
|
||||||
// interface observers, called on the notification threads.
|
|
||||||
private String mBaseIface;
|
private String mBaseIface;
|
||||||
private String mIface;
|
private String mIface;
|
||||||
private volatile State mState = State.IDLE;
|
private State mState = State.IDLE;
|
||||||
|
|
||||||
public Nat464Xlat(INetworkManagementService nmService, Handler handler, NetworkAgentInfo nai) {
|
public Nat464Xlat(INetworkManagementService nmService, NetworkAgentInfo nai) {
|
||||||
mNMService = nmService;
|
mNMService = nmService;
|
||||||
mHandler = handler;
|
|
||||||
mNetwork = nai;
|
mNetwork = nai;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,6 +83,8 @@ public class Nat464Xlat extends BaseNetworkObserver {
|
|||||||
// TODO: migrate to NetworkCapabilities.TRANSPORT_*.
|
// TODO: migrate to NetworkCapabilities.TRANSPORT_*.
|
||||||
final int netType = nai.networkInfo.getType();
|
final int netType = nai.networkInfo.getType();
|
||||||
final boolean supported = ArrayUtils.contains(NETWORK_TYPES, nai.networkInfo.getType());
|
final boolean supported = ArrayUtils.contains(NETWORK_TYPES, nai.networkInfo.getType());
|
||||||
|
// TODO: this should also consider if the network is in SUSPENDED state to avoid stopping
|
||||||
|
// clatd in SUSPENDED state.
|
||||||
final boolean connected = nai.networkInfo.isConnected();
|
final boolean connected = nai.networkInfo.isConnected();
|
||||||
// We only run clat on networks that don't have a native IPv4 address.
|
// We only run clat on networks that don't have a native IPv4 address.
|
||||||
final boolean hasIPv4Address =
|
final boolean hasIPv4Address =
|
||||||
@@ -104,6 +100,13 @@ public class Nat464Xlat extends BaseNetworkObserver {
|
|||||||
return mState != State.IDLE;
|
return mState != State.IDLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true if clatd has been started but the stacked interface is not yet up.
|
||||||
|
*/
|
||||||
|
public boolean isStarting() {
|
||||||
|
return mState == State.STARTING;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return true if clatd has been started and the stacked interface is up.
|
* @return true if clatd has been started and the stacked interface is up.
|
||||||
*/
|
*/
|
||||||
@@ -112,25 +115,77 @@ public class Nat464Xlat extends BaseNetworkObserver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets internal state.
|
* @return true if clatd has been stopped.
|
||||||
|
*/
|
||||||
|
public boolean isStopping() {
|
||||||
|
return mState == State.STOPPING;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start clatd, register this Nat464Xlat as a network observer for the stacked interface,
|
||||||
|
* and set internal state.
|
||||||
*/
|
*/
|
||||||
private void enterStartingState(String baseIface) {
|
private void enterStartingState(String baseIface) {
|
||||||
|
try {
|
||||||
|
mNMService.registerObserver(this);
|
||||||
|
} catch(RemoteException e) {
|
||||||
|
Slog.e(TAG,
|
||||||
|
"startClat: Can't register interface observer for clat on " + mNetwork.name());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
mNMService.startClatd(baseIface);
|
||||||
|
} catch(RemoteException|IllegalStateException e) {
|
||||||
|
Slog.e(TAG, "Error starting clatd on " + baseIface, e);
|
||||||
|
}
|
||||||
mIface = CLAT_PREFIX + baseIface;
|
mIface = CLAT_PREFIX + baseIface;
|
||||||
mBaseIface = baseIface;
|
mBaseIface = baseIface;
|
||||||
mState = State.STARTING;
|
mState = State.STARTING;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clears internal state. Must not be called by ConnectivityService.
|
* Enter running state just after getting confirmation that the stacked interface is up, and
|
||||||
|
* turn ND offload off if on WiFi.
|
||||||
|
*/
|
||||||
|
private void enterRunningState() {
|
||||||
|
maybeSetIpv6NdOffload(mBaseIface, false);
|
||||||
|
mState = State.RUNNING;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stop clatd, and turn ND offload on if it had been turned off.
|
||||||
|
*/
|
||||||
|
private void enterStoppingState() {
|
||||||
|
if (isRunning()) {
|
||||||
|
maybeSetIpv6NdOffload(mBaseIface, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
mNMService.stopClatd(mBaseIface);
|
||||||
|
} catch(RemoteException|IllegalStateException e) {
|
||||||
|
Slog.e(TAG, "Error stopping clatd on " + mBaseIface, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
mState = State.STOPPING;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unregister as a base observer for the stacked interface, and clear internal state.
|
||||||
*/
|
*/
|
||||||
private void enterIdleState() {
|
private void enterIdleState() {
|
||||||
|
try {
|
||||||
|
mNMService.unregisterObserver(this);
|
||||||
|
} catch(RemoteException|IllegalStateException e) {
|
||||||
|
Slog.e(TAG, "Error unregistering clatd observer on " + mBaseIface, e);
|
||||||
|
}
|
||||||
|
|
||||||
mIface = null;
|
mIface = null;
|
||||||
mBaseIface = null;
|
mBaseIface = null;
|
||||||
mState = State.IDLE;
|
mState = State.IDLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Starts the clat daemon. Called by ConnectivityService on the handler thread.
|
* Starts the clat daemon.
|
||||||
*/
|
*/
|
||||||
public void start() {
|
public void start() {
|
||||||
if (isStarted()) {
|
if (isStarted()) {
|
||||||
@@ -143,53 +198,30 @@ public class Nat464Xlat extends BaseNetworkObserver {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
|
||||||
mNMService.registerObserver(this);
|
|
||||||
} catch(RemoteException e) {
|
|
||||||
Slog.e(TAG, "startClat: Can't register interface observer for clat on " + mNetwork);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
String baseIface = mNetwork.linkProperties.getInterfaceName();
|
String baseIface = mNetwork.linkProperties.getInterfaceName();
|
||||||
if (baseIface == null) {
|
if (baseIface == null) {
|
||||||
Slog.e(TAG, "startClat: Can't start clat on null interface");
|
Slog.e(TAG, "startClat: Can't start clat on null interface");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// TODO: should we only do this if mNMService.startClatd() succeeds?
|
// TODO: should we only do this if mNMService.startClatd() succeeds?
|
||||||
|
Slog.i(TAG, "Starting clatd on " + baseIface);
|
||||||
enterStartingState(baseIface);
|
enterStartingState(baseIface);
|
||||||
|
|
||||||
Slog.i(TAG, "Starting clatd on " + mBaseIface);
|
|
||||||
try {
|
|
||||||
mNMService.startClatd(mBaseIface);
|
|
||||||
} catch(RemoteException|IllegalStateException e) {
|
|
||||||
Slog.e(TAG, "Error starting clatd on " + mBaseIface, e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stops the clat daemon. Called by ConnectivityService on the handler thread.
|
* Stops the clat daemon.
|
||||||
*/
|
*/
|
||||||
public void stop() {
|
public void stop() {
|
||||||
if (!isStarted()) {
|
if (!isStarted()) {
|
||||||
Slog.e(TAG, "stopClat: already stopped or not started");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Slog.i(TAG, "Stopping clatd on " + mBaseIface);
|
Slog.i(TAG, "Stopping clatd on " + mBaseIface);
|
||||||
try {
|
|
||||||
mNMService.stopClatd(mBaseIface);
|
|
||||||
} catch(RemoteException|IllegalStateException e) {
|
|
||||||
Slog.e(TAG, "Error stopping clatd on " + mBaseIface, e);
|
|
||||||
}
|
|
||||||
// When clatd stops and its interface is deleted, interfaceRemoved() will notify
|
|
||||||
// ConnectivityService and call enterIdleState().
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateConnectivityService(LinkProperties lp) {
|
boolean wasStarting = isStarting();
|
||||||
Message msg = mHandler.obtainMessage(NetworkAgent.EVENT_NETWORK_PROPERTIES_CHANGED, lp);
|
enterStoppingState();
|
||||||
msg.replyTo = mNetwork.messenger;
|
if (wasStarting) {
|
||||||
Slog.i(TAG, "sending message to ConnectivityService: " + msg);
|
enterIdleState();
|
||||||
msg.sendToTarget();
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -257,59 +289,58 @@ public class Nat464Xlat extends BaseNetworkObserver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds stacked link on base link and transitions to Running state
|
* Adds stacked link on base link and transitions to RUNNING state.
|
||||||
* This is called by the InterfaceObserver on its own thread, so can race with stop().
|
|
||||||
*/
|
*/
|
||||||
@Override
|
private void handleInterfaceLinkStateChanged(String iface, boolean up) {
|
||||||
public void interfaceLinkStateChanged(String iface, boolean up) {
|
if (!isStarting() || !up || !Objects.equals(mIface, iface)) {
|
||||||
if (!isStarted() || !up || !Objects.equals(mIface, iface)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (isRunning()) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
LinkAddress clatAddress = getLinkAddress(iface);
|
LinkAddress clatAddress = getLinkAddress(iface);
|
||||||
if (clatAddress == null) {
|
if (clatAddress == null) {
|
||||||
|
Slog.e(TAG, "clatAddress was null for stacked iface " + iface);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mState = State.RUNNING;
|
|
||||||
Slog.i(TAG, String.format("interface %s is up, adding stacked link %s on top of %s",
|
Slog.i(TAG, String.format("interface %s is up, adding stacked link %s on top of %s",
|
||||||
mIface, mIface, mBaseIface));
|
mIface, mIface, mBaseIface));
|
||||||
|
enterRunningState();
|
||||||
maybeSetIpv6NdOffload(mBaseIface, false);
|
|
||||||
LinkProperties lp = new LinkProperties(mNetwork.linkProperties);
|
LinkProperties lp = new LinkProperties(mNetwork.linkProperties);
|
||||||
lp.addStackedLink(makeLinkProperties(clatAddress));
|
lp.addStackedLink(makeLinkProperties(clatAddress));
|
||||||
updateConnectivityService(lp);
|
mNetwork.connService().handleUpdateLinkProperties(mNetwork, lp);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
public void interfaceRemoved(String iface) {
|
* Removes stacked link on base link and transitions to IDLE state.
|
||||||
if (!isStarted() || !Objects.equals(mIface, iface)) {
|
*/
|
||||||
|
private void handleInterfaceRemoved(String iface) {
|
||||||
|
if (!Objects.equals(mIface, iface)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!isRunning()) {
|
if (!isRunning() && !isStopping()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Slog.i(TAG, "interface " + iface + " removed");
|
Slog.i(TAG, "interface " + iface + " removed");
|
||||||
// The interface going away likely means clatd has crashed. Ask netd to stop it,
|
if (!isStopping()) {
|
||||||
// because otherwise when we try to start it again on the same base interface netd
|
// Ensure clatd is stopped if stop() has not been called: this likely means that clatd
|
||||||
// will complain that it's already started.
|
// has crashed.
|
||||||
//
|
enterStoppingState();
|
||||||
// Note that this method can be called by the interface observer at the same time
|
|
||||||
// that ConnectivityService calls stop(). In this case, the second call to
|
|
||||||
// stopClatd() will just throw IllegalStateException, which we'll ignore.
|
|
||||||
try {
|
|
||||||
mNMService.unregisterObserver(this);
|
|
||||||
mNMService.stopClatd(mBaseIface);
|
|
||||||
} catch (RemoteException|IllegalStateException e) {
|
|
||||||
// Well, we tried.
|
|
||||||
}
|
}
|
||||||
maybeSetIpv6NdOffload(mBaseIface, true);
|
|
||||||
LinkProperties lp = new LinkProperties(mNetwork.linkProperties);
|
|
||||||
lp.removeStackedLink(mIface);
|
|
||||||
enterIdleState();
|
enterIdleState();
|
||||||
updateConnectivityService(lp);
|
LinkProperties lp = new LinkProperties(mNetwork.linkProperties);
|
||||||
|
lp.removeStackedLink(iface);
|
||||||
|
mNetwork.connService().handleUpdateLinkProperties(mNetwork, lp);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void interfaceLinkStateChanged(String iface, boolean up) {
|
||||||
|
mNetwork.handler().post(() -> { handleInterfaceLinkStateChanged(iface, up); });
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void interfaceRemoved(String iface) {
|
||||||
|
mNetwork.handler().post(() -> { handleInterfaceRemoved(iface); });
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -27,7 +27,9 @@ import android.net.NetworkMisc;
|
|||||||
import android.net.NetworkRequest;
|
import android.net.NetworkRequest;
|
||||||
import android.net.NetworkState;
|
import android.net.NetworkState;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
|
import android.os.INetworkManagementService;
|
||||||
import android.os.Messenger;
|
import android.os.Messenger;
|
||||||
|
import android.os.RemoteException;
|
||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.SparseArray;
|
import android.util.SparseArray;
|
||||||
@@ -268,6 +270,14 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
|
|||||||
networkMisc = misc;
|
networkMisc = misc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ConnectivityService connService() {
|
||||||
|
return mConnService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Handler handler() {
|
||||||
|
return mHandler;
|
||||||
|
}
|
||||||
|
|
||||||
// Functions for manipulating the requests satisfied by this network.
|
// Functions for manipulating the requests satisfied by this network.
|
||||||
//
|
//
|
||||||
// These functions must only called on ConnectivityService's main thread.
|
// These functions must only called on ConnectivityService's main thread.
|
||||||
@@ -551,6 +561,32 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
|
|||||||
for (LingerTimer timer : mLingerTimers) { pw.println(timer); }
|
for (LingerTimer timer : mLingerTimers) { pw.println(timer); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void updateClat(INetworkManagementService netd) {
|
||||||
|
if (Nat464Xlat.requiresClat(this)) {
|
||||||
|
maybeStartClat(netd);
|
||||||
|
} else {
|
||||||
|
maybeStopClat();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Ensure clat has started for this network. */
|
||||||
|
public void maybeStartClat(INetworkManagementService netd) {
|
||||||
|
if (clatd != null && clatd.isStarted()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
clatd = new Nat464Xlat(netd, this);
|
||||||
|
clatd.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Ensure clat has stopped for this network. */
|
||||||
|
public void maybeStopClat() {
|
||||||
|
if (clatd == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
clatd.stop();
|
||||||
|
clatd = null;
|
||||||
|
}
|
||||||
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "NetworkAgentInfo{ ni{" + networkInfo + "} " +
|
return "NetworkAgentInfo{ ni{" + networkInfo + "} " +
|
||||||
"network{" + network + "} nethandle{" + network.getNetworkHandle() + "} " +
|
"network{" + network + "} nethandle{" + network.getNetworkHandle() + "} " +
|
||||||
|
|||||||
@@ -0,0 +1,226 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.server.connectivity;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.mockito.Mockito.any;
|
||||||
|
import static org.mockito.Mockito.eq;
|
||||||
|
import static org.mockito.Mockito.times;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import android.net.ConnectivityManager;
|
||||||
|
import android.net.InterfaceConfiguration;
|
||||||
|
import android.net.LinkAddress;
|
||||||
|
import android.net.LinkProperties;
|
||||||
|
import android.net.NetworkInfo;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.INetworkManagementService;
|
||||||
|
import android.os.test.TestLooper;
|
||||||
|
import android.support.test.filters.SmallTest;
|
||||||
|
import android.support.test.runner.AndroidJUnit4;
|
||||||
|
|
||||||
|
import com.android.server.ConnectivityService;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.ArgumentCaptor;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
@SmallTest
|
||||||
|
public class Nat464XlatTest {
|
||||||
|
|
||||||
|
static final String BASE_IFACE = "test0";
|
||||||
|
static final String STACKED_IFACE = "v4-test0";
|
||||||
|
static final LinkAddress ADDR = new LinkAddress("192.0.2.5/29");
|
||||||
|
|
||||||
|
@Mock ConnectivityService mConnectivity;
|
||||||
|
@Mock INetworkManagementService mNms;
|
||||||
|
@Mock InterfaceConfiguration mConfig;
|
||||||
|
@Mock NetworkAgentInfo mNai;
|
||||||
|
|
||||||
|
TestLooper mLooper;
|
||||||
|
Handler mHandler;
|
||||||
|
|
||||||
|
Nat464Xlat makeNat464Xlat() {
|
||||||
|
return new Nat464Xlat(mNms, mNai);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
mLooper = new TestLooper();
|
||||||
|
mHandler = new Handler(mLooper.getLooper());
|
||||||
|
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
|
||||||
|
mNai.linkProperties = new LinkProperties();
|
||||||
|
mNai.linkProperties.setInterfaceName(BASE_IFACE);
|
||||||
|
mNai.networkInfo = new NetworkInfo(null);
|
||||||
|
mNai.networkInfo.setType(ConnectivityManager.TYPE_WIFI);
|
||||||
|
when(mNai.connService()).thenReturn(mConnectivity);
|
||||||
|
when(mNai.handler()).thenReturn(mHandler);
|
||||||
|
|
||||||
|
when(mNms.getInterfaceConfig(eq(STACKED_IFACE))).thenReturn(mConfig);
|
||||||
|
when(mConfig.getLinkAddress()).thenReturn(ADDR);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNormalStartAndStop() throws Exception {
|
||||||
|
Nat464Xlat nat = makeNat464Xlat();
|
||||||
|
ArgumentCaptor<LinkProperties> c = ArgumentCaptor.forClass(LinkProperties.class);
|
||||||
|
|
||||||
|
// ConnectivityService starts clat.
|
||||||
|
nat.start();
|
||||||
|
|
||||||
|
verify(mNms).registerObserver(eq(nat));
|
||||||
|
verify(mNms).startClatd(eq(BASE_IFACE));
|
||||||
|
|
||||||
|
// Stacked interface up notification arrives.
|
||||||
|
nat.interfaceLinkStateChanged(STACKED_IFACE, true);
|
||||||
|
mLooper.dispatchNext();
|
||||||
|
|
||||||
|
verify(mNms).getInterfaceConfig(eq(STACKED_IFACE));
|
||||||
|
verify(mNms).setInterfaceIpv6NdOffload(eq(BASE_IFACE), eq(false));
|
||||||
|
verify(mConnectivity).handleUpdateLinkProperties(eq(mNai), c.capture());
|
||||||
|
assertFalse(c.getValue().getStackedLinks().isEmpty());
|
||||||
|
assertTrue(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE));
|
||||||
|
assertRunning(nat);
|
||||||
|
|
||||||
|
// ConnectivityService stops clat (Network disconnects, IPv4 addr appears, ...).
|
||||||
|
nat.stop();
|
||||||
|
|
||||||
|
verify(mNms).stopClatd(eq(BASE_IFACE));
|
||||||
|
verify(mNms).setInterfaceIpv6NdOffload(eq(BASE_IFACE), eq(true));
|
||||||
|
|
||||||
|
// Stacked interface removed notification arrives.
|
||||||
|
nat.interfaceRemoved(STACKED_IFACE);
|
||||||
|
mLooper.dispatchNext();
|
||||||
|
|
||||||
|
verify(mNms).unregisterObserver(eq(nat));
|
||||||
|
verify(mConnectivity, times(2)).handleUpdateLinkProperties(eq(mNai), c.capture());
|
||||||
|
assertTrue(c.getValue().getStackedLinks().isEmpty());
|
||||||
|
assertFalse(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE));
|
||||||
|
assertIdle(nat);
|
||||||
|
|
||||||
|
verifyNoMoreInteractions(mNms, mConnectivity);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testClatdCrashWhileRunning() throws Exception {
|
||||||
|
Nat464Xlat nat = makeNat464Xlat();
|
||||||
|
ArgumentCaptor<LinkProperties> c = ArgumentCaptor.forClass(LinkProperties.class);
|
||||||
|
|
||||||
|
// ConnectivityService starts clat.
|
||||||
|
nat.start();
|
||||||
|
|
||||||
|
verify(mNms).registerObserver(eq(nat));
|
||||||
|
verify(mNms).startClatd(eq(BASE_IFACE));
|
||||||
|
|
||||||
|
// Stacked interface up notification arrives.
|
||||||
|
nat.interfaceLinkStateChanged(STACKED_IFACE, true);
|
||||||
|
mLooper.dispatchNext();
|
||||||
|
|
||||||
|
verify(mNms).getInterfaceConfig(eq(STACKED_IFACE));
|
||||||
|
verify(mNms).setInterfaceIpv6NdOffload(eq(BASE_IFACE), eq(false));
|
||||||
|
verify(mConnectivity, times(1)).handleUpdateLinkProperties(eq(mNai), c.capture());
|
||||||
|
assertFalse(c.getValue().getStackedLinks().isEmpty());
|
||||||
|
assertTrue(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE));
|
||||||
|
assertRunning(nat);
|
||||||
|
|
||||||
|
// Stacked interface removed notification arrives (clatd crashed, ...).
|
||||||
|
nat.interfaceRemoved(STACKED_IFACE);
|
||||||
|
mLooper.dispatchNext();
|
||||||
|
|
||||||
|
verify(mNms).unregisterObserver(eq(nat));
|
||||||
|
verify(mNms).stopClatd(eq(BASE_IFACE));
|
||||||
|
verify(mNms).setInterfaceIpv6NdOffload(eq(BASE_IFACE), eq(true));
|
||||||
|
verify(mConnectivity, times(2)).handleUpdateLinkProperties(eq(mNai), c.capture());
|
||||||
|
assertTrue(c.getValue().getStackedLinks().isEmpty());
|
||||||
|
assertFalse(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE));
|
||||||
|
assertIdle(nat);
|
||||||
|
|
||||||
|
// ConnectivityService stops clat: no-op.
|
||||||
|
nat.stop();
|
||||||
|
|
||||||
|
verifyNoMoreInteractions(mNms, mConnectivity);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testStopBeforeClatdStarts() throws Exception {
|
||||||
|
Nat464Xlat nat = makeNat464Xlat();
|
||||||
|
|
||||||
|
// ConnectivityService starts clat.
|
||||||
|
nat.start();
|
||||||
|
|
||||||
|
verify(mNms).registerObserver(eq(nat));
|
||||||
|
verify(mNms).startClatd(eq(BASE_IFACE));
|
||||||
|
|
||||||
|
// ConnectivityService immediately stops clat (Network disconnects, IPv4 addr appears, ...)
|
||||||
|
nat.stop();
|
||||||
|
|
||||||
|
verify(mNms).unregisterObserver(eq(nat));
|
||||||
|
verify(mNms).stopClatd(eq(BASE_IFACE));
|
||||||
|
assertIdle(nat);
|
||||||
|
|
||||||
|
// In-flight interface up notification arrives: no-op
|
||||||
|
nat.interfaceLinkStateChanged(STACKED_IFACE, true);
|
||||||
|
mLooper.dispatchNext();
|
||||||
|
|
||||||
|
|
||||||
|
// Interface removed notification arrives after stopClatd() takes effect: no-op.
|
||||||
|
nat.interfaceRemoved(STACKED_IFACE);
|
||||||
|
mLooper.dispatchNext();
|
||||||
|
|
||||||
|
assertIdle(nat);
|
||||||
|
|
||||||
|
verifyNoMoreInteractions(mNms, mConnectivity);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testStopAndClatdNeverStarts() throws Exception {
|
||||||
|
Nat464Xlat nat = makeNat464Xlat();
|
||||||
|
|
||||||
|
// ConnectivityService starts clat.
|
||||||
|
nat.start();
|
||||||
|
|
||||||
|
verify(mNms).registerObserver(eq(nat));
|
||||||
|
verify(mNms).startClatd(eq(BASE_IFACE));
|
||||||
|
|
||||||
|
// ConnectivityService immediately stops clat (Network disconnects, IPv4 addr appears, ...)
|
||||||
|
nat.stop();
|
||||||
|
|
||||||
|
verify(mNms).unregisterObserver(eq(nat));
|
||||||
|
verify(mNms).stopClatd(eq(BASE_IFACE));
|
||||||
|
assertIdle(nat);
|
||||||
|
|
||||||
|
verifyNoMoreInteractions(mNms, mConnectivity);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void assertIdle(Nat464Xlat nat) {
|
||||||
|
assertTrue("Nat464Xlat was not IDLE", !nat.isStarted());
|
||||||
|
}
|
||||||
|
|
||||||
|
static void assertRunning(Nat464Xlat nat) {
|
||||||
|
assertTrue("Nat464Xlat was not RUNNING", nat.isRunning());
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user