Add underpinned Network parameter in SocketKeepalive.start()

Take a Network parameter to have an one-to-one mapping between
keepalive and its underpinned network on the automatic keepalive.

Existing design could not really tell which network should the
automatic keepalive check for the TCP socket status if there are
multiple automatic keepalives enabled, e.g. Bothe IWLAN and VPN
on WiFi enable the automatic keepalive. The keepalive for IWLAN
should check if there are any TCP sockets on the IWLAN network
instead of VPN network.

Bug: 259000745
Test: atest FrameworksNetTests
Test: Cts in the follow up commit
Change-Id: I7353f4ef43e8fdad02c4d4a0bb5f6efa7d94c1b4
This commit is contained in:
chiachangwang
2023-02-14 09:22:05 +00:00
parent 7c17c283ea
commit 676c84ef98
7 changed files with 46 additions and 28 deletions

View File

@@ -470,7 +470,7 @@ package android.net {
} }
public abstract class SocketKeepalive implements java.lang.AutoCloseable { public abstract class SocketKeepalive implements java.lang.AutoCloseable {
method public final void start(@IntRange(from=0xa, to=0xe10) int, int); method public final void start(@IntRange(from=0xa, to=0xe10) int, int, @NonNull android.net.Network);
field public static final int ERROR_NO_SUCH_SLOT = -33; // 0xffffffdf field public static final int ERROR_NO_SUCH_SLOT = -33; // 0xffffffdf
field public static final int FLAG_AUTOMATIC_ON_OFF = 1; // 0x1 field public static final int FLAG_AUTOMATIC_ON_OFF = 1; // 0x1
field public static final int SUCCESS = 0; // 0x0 field public static final int SUCCESS = 0; // 0x0

View File

@@ -188,7 +188,7 @@ interface IConnectivityManager
void startNattKeepaliveWithFd(in Network network, in ParcelFileDescriptor pfd, int resourceId, void startNattKeepaliveWithFd(in Network network, in ParcelFileDescriptor pfd, int resourceId,
int intervalSeconds, in ISocketKeepaliveCallback cb, String srcAddr, int intervalSeconds, in ISocketKeepaliveCallback cb, String srcAddr,
String dstAddr, boolean automaticOnOffKeepalives); String dstAddr, boolean automaticOnOffKeepalives, in Network underpinnedNetwork);
void startTcpKeepalive(in Network network, in ParcelFileDescriptor pfd, int intervalSeconds, void startTcpKeepalive(in Network network, in ParcelFileDescriptor pfd, int intervalSeconds,
in ISocketKeepaliveCallback cb); in ISocketKeepaliveCallback cb);

View File

@@ -66,10 +66,12 @@ public final class NattSocketKeepalive extends SocketKeepalive {
* the supplied {@link Callback} will see a call to * the supplied {@link Callback} will see a call to
* {@link Callback#onError(int)} with {@link #ERROR_INVALID_INTERVAL}. * {@link Callback#onError(int)} with {@link #ERROR_INVALID_INTERVAL}.
* @param flags Flags to enable/disable available options on this keepalive. * @param flags Flags to enable/disable available options on this keepalive.
* @param underpinnedNetwork The underpinned network of this keepalive.
*
* @hide * @hide
*/ */
@Override @Override
protected void startImpl(int intervalSec, int flags) { protected void startImpl(int intervalSec, int flags, Network underpinnedNetwork) {
if (0 != (flags & ~FLAG_AUTOMATIC_ON_OFF)) { if (0 != (flags & ~FLAG_AUTOMATIC_ON_OFF)) {
throw new IllegalArgumentException("Illegal flag value for " throw new IllegalArgumentException("Illegal flag value for "
+ this.getClass().getSimpleName() + " : " + flags); + this.getClass().getSimpleName() + " : " + flags);
@@ -79,7 +81,8 @@ public final class NattSocketKeepalive extends SocketKeepalive {
try { try {
mService.startNattKeepaliveWithFd(mNetwork, mPfd, mResourceId, mService.startNattKeepaliveWithFd(mNetwork, mPfd, mResourceId,
intervalSec, mCallback, mSource.getHostAddress(), intervalSec, mCallback, mSource.getHostAddress(),
mDestination.getHostAddress(), automaticOnOffKeepalives); mDestination.getHostAddress(), automaticOnOffKeepalives,
underpinnedNetwork);
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(TAG, "Error starting socket keepalive: ", e); Log.e(TAG, "Error starting socket keepalive: ", e);
throw e.rethrowFromSystemServer(); throw e.rethrowFromSystemServer();

View File

@@ -355,7 +355,7 @@ public abstract class SocketKeepalive implements AutoCloseable {
*/ */
public final void start(@IntRange(from = MIN_INTERVAL_SEC, to = MAX_INTERVAL_SEC) public final void start(@IntRange(from = MIN_INTERVAL_SEC, to = MAX_INTERVAL_SEC)
int intervalSec) { int intervalSec) {
startImpl(intervalSec, 0 /* flags */); startImpl(intervalSec, 0 /* flags */, null /* underpinnedNetwork */);
} }
/** /**
@@ -374,16 +374,18 @@ public abstract class SocketKeepalive implements AutoCloseable {
* the supplied {@link Callback} will see a call to * the supplied {@link Callback} will see a call to
* {@link Callback#onError(int)} with {@link #ERROR_INVALID_INTERVAL}. * {@link Callback#onError(int)} with {@link #ERROR_INVALID_INTERVAL}.
* @param flags Flags to enable/disable available options on this keepalive. * @param flags Flags to enable/disable available options on this keepalive.
* @param underpinnedNetwork The underpinned network of this keepalive.
* @hide * @hide
*/ */
@SystemApi(client = PRIVILEGED_APPS) @SystemApi(client = PRIVILEGED_APPS)
public final void start(@IntRange(from = MIN_INTERVAL_SEC, to = MAX_INTERVAL_SEC) public final void start(@IntRange(from = MIN_INTERVAL_SEC, to = MAX_INTERVAL_SEC)
int intervalSec, @StartFlags int flags) { int intervalSec, @StartFlags int flags, @NonNull Network underpinnedNetwork) {
startImpl(intervalSec, flags); startImpl(intervalSec, flags, underpinnedNetwork);
} }
/** @hide */ /** @hide */
protected abstract void startImpl(int intervalSec, @StartFlags int flags); protected abstract void startImpl(int intervalSec, @StartFlags int flags,
Network underpinnedNetwork);
/** /**
* Requests that keepalive be stopped. The application must wait for {@link Callback#onStopped} * Requests that keepalive be stopped. The application must wait for {@link Callback#onStopped}

View File

@@ -50,7 +50,7 @@ public final class TcpSocketKeepalive extends SocketKeepalive {
* acknowledgement. * acknowledgement.
*/ */
@Override @Override
protected void startImpl(int intervalSec, int flags) { protected void startImpl(int intervalSec, int flags, Network underpinnedNetwork) {
if (0 != flags) { if (0 != flags) {
throw new IllegalArgumentException("Illegal flag value for " throw new IllegalArgumentException("Illegal flag value for "
+ this.getClass().getSimpleName() + " : " + flags); + this.getClass().getSimpleName() + " : " + flags);

View File

@@ -5589,13 +5589,14 @@ public class ConnectivityService extends IConnectivityManager.Stub
mKeepaliveTracker.getKeepaliveForBinder((IBinder) msg.obj); mKeepaliveTracker.getKeepaliveForBinder((IBinder) msg.obj);
if (null == ki) return; // The callback was unregistered before the alarm fired if (null == ki) return; // The callback was unregistered before the alarm fired
final Network underpinnedNetwork = ki.getUnderpinnedNetwork();
final Network network = ki.getNetwork(); final Network network = ki.getNetwork();
boolean networkFound = false; boolean networkFound = false;
final ArrayList<NetworkAgentInfo> vpnsRunningOnThisNetwork = new ArrayList<>(); boolean underpinnedNetworkFound = false;
for (NetworkAgentInfo n : mNetworkAgentInfos) { for (NetworkAgentInfo n : mNetworkAgentInfos) {
if (n.network.equals(network)) networkFound = true; if (n.network.equals(network)) networkFound = true;
if (n.isVPN() && n.everConnected() && hasUnderlyingNetwork(n, network)) { if (n.everConnected() && n.network.equals(underpinnedNetwork)) {
vpnsRunningOnThisNetwork.add(n); underpinnedNetworkFound = true;
} }
} }
@@ -5603,12 +5604,11 @@ public class ConnectivityService extends IConnectivityManager.Stub
// cleaned up already. There is no point trying to resume keepalives. // cleaned up already. There is no point trying to resume keepalives.
if (!networkFound) return; if (!networkFound) return;
if (!vpnsRunningOnThisNetwork.isEmpty()) { if (underpinnedNetworkFound) {
mKeepaliveTracker.handleMonitorAutomaticKeepalive(ki, mKeepaliveTracker.handleMonitorAutomaticKeepalive(ki,
// TODO: check all the VPNs running on top of this network underpinnedNetwork.netId);
vpnsRunningOnThisNetwork.get(0).network.netId);
} else { } else {
// If no VPN, then make sure the keepalive is running. // If no underpinned network, then make sure the keepalive is running.
mKeepaliveTracker.handleMaybeResumeKeepalive(ki); mKeepaliveTracker.handleMaybeResumeKeepalive(ki);
} }
break; break;
@@ -9868,21 +9868,22 @@ public class ConnectivityService extends IConnectivityManager.Stub
getNetworkAgentInfoForNetwork(network), null /* fd */, getNetworkAgentInfoForNetwork(network), null /* fd */,
intervalSeconds, cb, srcAddr, srcPort, dstAddr, NattSocketKeepalive.NATT_PORT, intervalSeconds, cb, srcAddr, srcPort, dstAddr, NattSocketKeepalive.NATT_PORT,
// Keep behavior of the deprecated method as it is. Set automaticOnOffKeepalives to // Keep behavior of the deprecated method as it is. Set automaticOnOffKeepalives to
// false because there is no way and no plan to configure automaticOnOffKeepalives // false and set the underpinned network to null because there is no way and no
// in this deprecated method. // plan to configure automaticOnOffKeepalives or underpinnedNetwork in this
false /* automaticOnOffKeepalives */); // deprecated method.
false /* automaticOnOffKeepalives */, null /* underpinnedNetwork */);
} }
@Override @Override
public void startNattKeepaliveWithFd(Network network, ParcelFileDescriptor pfd, int resourceId, public void startNattKeepaliveWithFd(Network network, ParcelFileDescriptor pfd, int resourceId,
int intervalSeconds, ISocketKeepaliveCallback cb, String srcAddr, int intervalSeconds, ISocketKeepaliveCallback cb, String srcAddr,
String dstAddr, boolean automaticOnOffKeepalives) { String dstAddr, boolean automaticOnOffKeepalives, Network underpinnedNetwork) {
try { try {
final FileDescriptor fd = pfd.getFileDescriptor(); final FileDescriptor fd = pfd.getFileDescriptor();
mKeepaliveTracker.startNattKeepalive( mKeepaliveTracker.startNattKeepalive(
getNetworkAgentInfoForNetwork(network), fd, resourceId, getNetworkAgentInfoForNetwork(network), fd, resourceId,
intervalSeconds, cb, intervalSeconds, cb, srcAddr, dstAddr, NattSocketKeepalive.NATT_PORT,
srcAddr, dstAddr, NattSocketKeepalive.NATT_PORT, automaticOnOffKeepalives); automaticOnOffKeepalives, underpinnedNetwork);
} finally { } finally {
// FileDescriptors coming from AIDL calls must be manually closed to prevent leaks. // FileDescriptors coming from AIDL calls must be manually closed to prevent leaks.
// startNattKeepalive calls Os.dup(fd) before returning, so we can close immediately. // startNattKeepalive calls Os.dup(fd) before returning, so we can close immediately.

View File

@@ -196,11 +196,16 @@ public class AutomaticOnOffKeepaliveTracker {
private final PendingIntent mTcpPollingAlarm; private final PendingIntent mTcpPollingAlarm;
@AutomaticOnOffState @AutomaticOnOffState
private int mAutomaticOnOffState; private int mAutomaticOnOffState;
@Nullable
private final Network mUnderpinnedNetwork;
AutomaticOnOffKeepalive(@NonNull final KeepaliveTracker.KeepaliveInfo ki, AutomaticOnOffKeepalive(@NonNull final KeepaliveTracker.KeepaliveInfo ki,
final boolean autoOnOff, @NonNull Context context) throws InvalidSocketException { final boolean autoOnOff, @NonNull Context context,
@Nullable Network underpinnedNetwork)
throws InvalidSocketException {
this.mKi = Objects.requireNonNull(ki); this.mKi = Objects.requireNonNull(ki);
mCallback = ki.mCallback; mCallback = ki.mCallback;
mUnderpinnedNetwork = underpinnedNetwork;
if (autoOnOff && mDependencies.isFeatureEnabled(AUTOMATIC_ON_OFF_KEEPALIVE_VERSION)) { if (autoOnOff && mDependencies.isFeatureEnabled(AUTOMATIC_ON_OFF_KEEPALIVE_VERSION)) {
mAutomaticOnOffState = STATE_ENABLED; mAutomaticOnOffState = STATE_ENABLED;
if (null == ki.mFd) { if (null == ki.mFd) {
@@ -228,6 +233,11 @@ public class AutomaticOnOffKeepaliveTracker {
return mKi.getNai().network; return mKi.getNai().network;
} }
@Nullable
public Network getUnderpinnedNetwork() {
return mUnderpinnedNetwork;
}
public boolean match(Network network, int slot) { public boolean match(Network network, int slot) {
return mKi.getNai().network().equals(network) && mKi.getSlot() == slot; return mKi.getNai().network().equals(network) && mKi.getSlot() == slot;
} }
@@ -475,13 +485,13 @@ public class AutomaticOnOffKeepaliveTracker {
@NonNull String srcAddrString, @NonNull String srcAddrString,
int srcPort, int srcPort,
@NonNull String dstAddrString, @NonNull String dstAddrString,
int dstPort, boolean automaticOnOffKeepalives) { int dstPort, boolean automaticOnOffKeepalives, @Nullable Network underpinnedNetwork) {
final KeepaliveTracker.KeepaliveInfo ki = mKeepaliveTracker.makeNattKeepaliveInfo(nai, fd, final KeepaliveTracker.KeepaliveInfo ki = mKeepaliveTracker.makeNattKeepaliveInfo(nai, fd,
intervalSeconds, cb, srcAddrString, srcPort, dstAddrString, dstPort); intervalSeconds, cb, srcAddrString, srcPort, dstAddrString, dstPort);
if (null == ki) return; if (null == ki) return;
try { try {
final AutomaticOnOffKeepalive autoKi = new AutomaticOnOffKeepalive(ki, final AutomaticOnOffKeepalive autoKi = new AutomaticOnOffKeepalive(ki,
automaticOnOffKeepalives, mContext); automaticOnOffKeepalives, mContext, underpinnedNetwork);
mConnectivityServiceHandler.obtainMessage(NetworkAgent.CMD_START_SOCKET_KEEPALIVE, mConnectivityServiceHandler.obtainMessage(NetworkAgent.CMD_START_SOCKET_KEEPALIVE,
// TODO : move ConnectivityService#encodeBool to a static lib. // TODO : move ConnectivityService#encodeBool to a static lib.
automaticOnOffKeepalives ? 1 : 0, 0, autoKi).sendToTarget(); automaticOnOffKeepalives ? 1 : 0, 0, autoKi).sendToTarget();
@@ -504,13 +514,14 @@ public class AutomaticOnOffKeepaliveTracker {
@NonNull String srcAddrString, @NonNull String srcAddrString,
@NonNull String dstAddrString, @NonNull String dstAddrString,
int dstPort, int dstPort,
boolean automaticOnOffKeepalives) { boolean automaticOnOffKeepalives,
@Nullable Network underpinnedNetwork) {
final KeepaliveTracker.KeepaliveInfo ki = mKeepaliveTracker.makeNattKeepaliveInfo(nai, fd, final KeepaliveTracker.KeepaliveInfo ki = mKeepaliveTracker.makeNattKeepaliveInfo(nai, fd,
resourceId, intervalSeconds, cb, srcAddrString, dstAddrString, dstPort); resourceId, intervalSeconds, cb, srcAddrString, dstAddrString, dstPort);
if (null == ki) return; if (null == ki) return;
try { try {
final AutomaticOnOffKeepalive autoKi = new AutomaticOnOffKeepalive(ki, final AutomaticOnOffKeepalive autoKi = new AutomaticOnOffKeepalive(ki,
automaticOnOffKeepalives, mContext); automaticOnOffKeepalives, mContext, underpinnedNetwork);
mConnectivityServiceHandler.obtainMessage(NetworkAgent.CMD_START_SOCKET_KEEPALIVE, mConnectivityServiceHandler.obtainMessage(NetworkAgent.CMD_START_SOCKET_KEEPALIVE,
// TODO : move ConnectivityService#encodeBool to a static lib. // TODO : move ConnectivityService#encodeBool to a static lib.
automaticOnOffKeepalives ? 1 : 0, 0, autoKi).sendToTarget(); automaticOnOffKeepalives ? 1 : 0, 0, autoKi).sendToTarget();
@@ -539,7 +550,8 @@ public class AutomaticOnOffKeepaliveTracker {
if (null == ki) return; if (null == ki) return;
try { try {
final AutomaticOnOffKeepalive autoKi = new AutomaticOnOffKeepalive(ki, final AutomaticOnOffKeepalive autoKi = new AutomaticOnOffKeepalive(ki,
false /* autoOnOff, tcp keepalives are never auto on/off */, mContext); false /* autoOnOff, tcp keepalives are never auto on/off */,
mContext, null /* underpinnedNetwork, tcp keepalives do not refer to this */);
mConnectivityServiceHandler.obtainMessage(CMD_START_SOCKET_KEEPALIVE, autoKi) mConnectivityServiceHandler.obtainMessage(CMD_START_SOCKET_KEEPALIVE, autoKi)
.sendToTarget(); .sendToTarget();
} catch (InvalidSocketException e) { } catch (InvalidSocketException e) {