Merge "[DK2]Add new SocketKeepalive.start to dynamically control keepalive" am: a31dc31b20
Original change: https://android-review.googlesource.com/c/platform/packages/modules/Connectivity/+/2334604 Change-Id: I5b7864804518bef1898c3d463d6b4b2c06978ae7 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
commit
bfd498d605
10 changed files with 504 additions and 68 deletions
|
|
@ -43,7 +43,9 @@
|
|||
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
|
||||
|
||||
<!-- Sending non-protected broadcast from system uid is not allowed. -->
|
||||
<protected-broadcast android:name="com.android.server.connectivity.tethering.DISABLE_TETHERING" />
|
||||
<protected-broadcast android:name="com.android.server.connectivity.KeepaliveTracker.TCP_POLLING_ALARM" />
|
||||
|
||||
<application
|
||||
android:process="com.android.networkstack.process"
|
||||
|
|
|
|||
|
|
@ -470,7 +470,9 @@ package android.net {
|
|||
}
|
||||
|
||||
public abstract class SocketKeepalive implements java.lang.AutoCloseable {
|
||||
method public final void start(@IntRange(from=0xa, to=0xe10) int, int);
|
||||
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 SUCCESS = 0; // 0x0
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -188,7 +188,7 @@ interface IConnectivityManager
|
|||
|
||||
void startNattKeepaliveWithFd(in Network network, in ParcelFileDescriptor pfd, int resourceId,
|
||||
int intervalSeconds, in ISocketKeepaliveCallback cb, String srcAddr,
|
||||
String dstAddr);
|
||||
String dstAddr, boolean automaticOnOffKeepalives);
|
||||
|
||||
void startTcpKeepalive(in Network network, in ParcelFileDescriptor pfd, int intervalSeconds,
|
||||
in ISocketKeepaliveCallback cb);
|
||||
|
|
|
|||
|
|
@ -47,13 +47,39 @@ public final class NattSocketKeepalive extends SocketKeepalive {
|
|||
mResourceId = resourceId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Request that keepalive be started with the given {@code intervalSec}.
|
||||
*
|
||||
* When a VPN is running with the network for this keepalive as its underlying network, the
|
||||
* system can monitor the TCP connections on that VPN to determine whether this keepalive is
|
||||
* necessary. To enable this behavior, pass {@link SocketKeepalive#FLAG_AUTOMATIC_ON_OFF} into
|
||||
* the flags. When this is enabled, the system will disable sending keepalive packets when
|
||||
* there are no TCP connections over the VPN(s) running over this network to save battery, and
|
||||
* restart sending them as soon as any TCP connection is opened over one of the VPN networks.
|
||||
* When no VPN is running on top of this network, this flag has no effect, i.e. the keepalives
|
||||
* are always sent with the specified interval.
|
||||
*
|
||||
* Also {@see SocketKeepalive}.
|
||||
*
|
||||
* @param intervalSec The target interval in seconds between keepalive packet transmissions.
|
||||
* The interval should be between 10 seconds and 3600 seconds. Otherwise,
|
||||
* the supplied {@link Callback} will see a call to
|
||||
* {@link Callback#onError(int)} with {@link #ERROR_INVALID_INTERVAL}.
|
||||
* @param flags Flags to enable/disable available options on this keepalive.
|
||||
* @hide
|
||||
*/
|
||||
@Override
|
||||
protected void startImpl(int intervalSec) {
|
||||
protected void startImpl(int intervalSec, int flags) {
|
||||
if (0 != (flags & ~FLAG_AUTOMATIC_ON_OFF)) {
|
||||
throw new IllegalArgumentException("Illegal flag value for "
|
||||
+ this.getClass().getSimpleName() + " : " + flags);
|
||||
}
|
||||
final boolean automaticOnOffKeepalives = 0 != (flags & FLAG_AUTOMATIC_ON_OFF);
|
||||
mExecutor.execute(() -> {
|
||||
try {
|
||||
mService.startNattKeepaliveWithFd(mNetwork, mPfd, mResourceId,
|
||||
intervalSec, mCallback,
|
||||
mSource.getHostAddress(), mDestination.getHostAddress());
|
||||
intervalSec, mCallback, mSource.getHostAddress(),
|
||||
mDestination.getHostAddress(), automaticOnOffKeepalives);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Error starting socket keepalive: ", e);
|
||||
throw e.rethrowFromSystemServer();
|
||||
|
|
|
|||
|
|
@ -483,6 +483,20 @@ public abstract class NetworkAgent {
|
|||
*/
|
||||
public static final int EVENT_UNREGISTER_AFTER_REPLACEMENT = BASE + 29;
|
||||
|
||||
/**
|
||||
* Sent by AutomaticOnOffKeepaliveTracker periodically (when relevant) to trigger monitor
|
||||
* automatic keepalive request.
|
||||
*
|
||||
* NATT keepalives have an automatic mode where the system only sends keepalive packets when
|
||||
* TCP sockets are open over a VPN. The system will check periodically for presence of
|
||||
* such open sockets, and this message is what triggers the re-evaluation.
|
||||
*
|
||||
* arg1 = hardware slot number of the keepalive
|
||||
* obj = {@link Network} that the keepalive is started on.
|
||||
* @hide
|
||||
*/
|
||||
public static final int CMD_MONITOR_AUTOMATIC_KEEPALIVE = BASE + 30;
|
||||
|
||||
private static NetworkInfo getLegacyNetworkInfo(final NetworkAgentConfig config) {
|
||||
final NetworkInfo ni = new NetworkInfo(config.legacyType, config.legacySubType,
|
||||
config.legacyTypeName, config.legacySubTypeName);
|
||||
|
|
|
|||
|
|
@ -16,6 +16,8 @@
|
|||
|
||||
package android.net;
|
||||
|
||||
import static android.annotation.SystemApi.Client.PRIVILEGED_APPS;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.IntRange;
|
||||
import android.annotation.NonNull;
|
||||
|
|
@ -173,6 +175,27 @@ public abstract class SocketKeepalive implements AutoCloseable {
|
|||
})
|
||||
public @interface KeepaliveEvent {}
|
||||
|
||||
/**
|
||||
* Whether the system automatically toggles keepalive when no TCP connection is open on the VPN.
|
||||
*
|
||||
* If this flag is present, the system will monitor the VPN(s) running on top of the specified
|
||||
* network for open TCP connections. When no such connections are open, it will turn off the
|
||||
* keepalives to conserve battery power. When there is at least one such connection it will
|
||||
* turn on the keepalives to make sure functionality is preserved.
|
||||
*
|
||||
* This only works with {@link NattSocketKeepalive}.
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public static final int FLAG_AUTOMATIC_ON_OFF = 1 << 0;
|
||||
|
||||
/** @hide */
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef(prefix = { "FLAG_"}, flag = true, value = {
|
||||
FLAG_AUTOMATIC_ON_OFF
|
||||
})
|
||||
public @interface StartFlags {}
|
||||
|
||||
/**
|
||||
* The minimum interval in seconds between keepalive packet transmissions.
|
||||
*
|
||||
|
|
@ -294,13 +317,15 @@ public abstract class SocketKeepalive implements AutoCloseable {
|
|||
}
|
||||
|
||||
/**
|
||||
* Request that keepalive be started with the given {@code intervalSec}. See
|
||||
* {@link SocketKeepalive}. If the remote binder dies, or the binder call throws an exception
|
||||
* when invoking start or stop of the {@link SocketKeepalive}, a {@link RemoteException} will be
|
||||
* thrown into the {@code executor}. This is typically not important to catch because the remote
|
||||
* party is the system, so if it is not in shape to communicate through binder the system is
|
||||
* probably going down anyway. If the caller cares regardless, it can use a custom
|
||||
* {@link Executor} to catch the {@link RemoteException}.
|
||||
* Request that keepalive be started with the given {@code intervalSec}.
|
||||
*
|
||||
* See {@link SocketKeepalive}. If the remote binder dies, or the binder call throws an
|
||||
* exception when invoking start or stop of the {@link SocketKeepalive}, a
|
||||
* {@link RuntimeException} caused by a {@link RemoteException} will be thrown into the
|
||||
* {@link Executor}. This is typically not important to catch because the remote party is
|
||||
* the system, so if it is not in shape to communicate through binder the system is going
|
||||
* down anyway. If the caller still cares, it can use a custom {@link Executor} to catch the
|
||||
* {@link RuntimeException}.
|
||||
*
|
||||
* @param intervalSec The target interval in seconds between keepalive packet transmissions.
|
||||
* The interval should be between 10 seconds and 3600 seconds, otherwise
|
||||
|
|
@ -308,11 +333,35 @@ public abstract class SocketKeepalive implements AutoCloseable {
|
|||
*/
|
||||
public final void start(@IntRange(from = MIN_INTERVAL_SEC, to = MAX_INTERVAL_SEC)
|
||||
int intervalSec) {
|
||||
startImpl(intervalSec);
|
||||
startImpl(intervalSec, 0 /* flags */);
|
||||
}
|
||||
|
||||
/**
|
||||
* Request that keepalive be started with the given {@code intervalSec}.
|
||||
*
|
||||
* See {@link SocketKeepalive}. If the remote binder dies, or the binder call throws an
|
||||
* exception when invoking start or stop of the {@link SocketKeepalive}, a
|
||||
* {@link RuntimeException} caused by a {@link RemoteException} will be thrown into the
|
||||
* {@link Executor}. This is typically not important to catch because the remote party is
|
||||
* the system, so if it is not in shape to communicate through binder the system is going
|
||||
* down anyway. If the caller still cares, it can use a custom {@link Executor} to catch the
|
||||
* {@link RuntimeException}.
|
||||
*
|
||||
* @param intervalSec The target interval in seconds between keepalive packet transmissions.
|
||||
* The interval should be between 10 seconds and 3600 seconds. Otherwise,
|
||||
* the supplied {@link Callback} will see a call to
|
||||
* {@link Callback#onError(int)} with {@link #ERROR_INVALID_INTERVAL}.
|
||||
* @param flags Flags to enable/disable available options on this keepalive.
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi(client = PRIVILEGED_APPS)
|
||||
public final void start(@IntRange(from = MIN_INTERVAL_SEC, to = MAX_INTERVAL_SEC)
|
||||
int intervalSec, @StartFlags int flags) {
|
||||
startImpl(intervalSec, flags);
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
protected abstract void startImpl(int intervalSec);
|
||||
protected abstract void startImpl(int intervalSec, @StartFlags int flags);
|
||||
|
||||
/**
|
||||
* Requests that keepalive be stopped. The application must wait for {@link Callback#onStopped}
|
||||
|
|
|
|||
|
|
@ -50,7 +50,11 @@ public final class TcpSocketKeepalive extends SocketKeepalive {
|
|||
* acknowledgement.
|
||||
*/
|
||||
@Override
|
||||
protected void startImpl(int intervalSec) {
|
||||
protected void startImpl(int intervalSec, int flags) {
|
||||
if (0 != flags) {
|
||||
throw new IllegalArgumentException("Illegal flag value for "
|
||||
+ this.getClass().getSimpleName() + " : " + flags);
|
||||
}
|
||||
mExecutor.execute(() -> {
|
||||
try {
|
||||
mService.startTcpKeepalive(mNetwork, mPfd, intervalSec, mCallback);
|
||||
|
|
|
|||
|
|
@ -101,7 +101,6 @@ import static com.android.net.module.util.NetworkMonitorUtils.isPrivateDnsValida
|
|||
import static com.android.net.module.util.PermissionUtils.enforceAnyPermissionOf;
|
||||
import static com.android.net.module.util.PermissionUtils.enforceNetworkStackPermission;
|
||||
import static com.android.net.module.util.PermissionUtils.enforceNetworkStackPermissionOr;
|
||||
import static com.android.server.connectivity.KeepaliveTracker.PERMISSION;
|
||||
|
||||
import static java.util.Map.Entry;
|
||||
|
||||
|
|
@ -278,6 +277,7 @@ import com.android.server.connectivity.DnsManager;
|
|||
import com.android.server.connectivity.DnsManager.PrivateDnsValidationUpdate;
|
||||
import com.android.server.connectivity.DscpPolicyTracker;
|
||||
import com.android.server.connectivity.FullScore;
|
||||
import com.android.server.connectivity.KeepaliveTracker;
|
||||
import com.android.server.connectivity.LingerMonitor;
|
||||
import com.android.server.connectivity.MockableSystemProperties;
|
||||
import com.android.server.connectivity.MultinetworkPolicyTracker;
|
||||
|
|
@ -2999,7 +2999,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||
}
|
||||
|
||||
private void enforceKeepalivePermission() {
|
||||
mContext.enforceCallingOrSelfPermission(PERMISSION, "ConnectivityService");
|
||||
mContext.enforceCallingOrSelfPermission(KeepaliveTracker.PERMISSION, "ConnectivityService");
|
||||
}
|
||||
|
||||
private boolean checkLocalMacAddressPermission(int pid, int uid) {
|
||||
|
|
@ -5545,6 +5545,33 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||
mKeepaliveTracker.handleStartKeepalive(msg);
|
||||
break;
|
||||
}
|
||||
case NetworkAgent.CMD_MONITOR_AUTOMATIC_KEEPALIVE: {
|
||||
final Network network = (Network) msg.obj;
|
||||
final int slot = msg.arg1;
|
||||
|
||||
boolean networkFound = false;
|
||||
final ArrayList<NetworkAgentInfo> vpnsRunningOnThisNetwork = new ArrayList<>();
|
||||
for (NetworkAgentInfo n : mNetworkAgentInfos) {
|
||||
if (n.network.equals(network)) networkFound = true;
|
||||
if (n.isVPN() && n.everConnected() && hasUnderlyingNetwork(n, network)) {
|
||||
vpnsRunningOnThisNetwork.add(n);
|
||||
}
|
||||
}
|
||||
|
||||
// If the network no longer exists, then the keepalive should have been
|
||||
// cleaned up already. There is no point trying to resume keepalives.
|
||||
if (!networkFound) return;
|
||||
|
||||
if (!vpnsRunningOnThisNetwork.isEmpty()) {
|
||||
mKeepaliveTracker.handleMonitorAutomaticKeepalive(network, slot,
|
||||
// TODO: check all the VPNs running on top of this network
|
||||
vpnsRunningOnThisNetwork.get(0).network.netId);
|
||||
} else {
|
||||
// If no VPN, then make sure the keepalive is running.
|
||||
mKeepaliveTracker.handleMaybeResumeKeepalive(network, slot);
|
||||
}
|
||||
break;
|
||||
}
|
||||
// Sent by KeepaliveTracker to process an app request on the state machine thread.
|
||||
case NetworkAgent.CMD_STOP_SOCKET_KEEPALIVE: {
|
||||
NetworkAgentInfo nai = getNetworkAgentInfoForNetwork((Network) msg.obj);
|
||||
|
|
@ -9789,20 +9816,23 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||
enforceKeepalivePermission();
|
||||
mKeepaliveTracker.startNattKeepalive(
|
||||
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
|
||||
// false because there is no way and no plan to configure automaticOnOffKeepalives
|
||||
// in this deprecated method.
|
||||
false /* automaticOnOffKeepalives */);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startNattKeepaliveWithFd(Network network, ParcelFileDescriptor pfd, int resourceId,
|
||||
int intervalSeconds, ISocketKeepaliveCallback cb, String srcAddr,
|
||||
String dstAddr) {
|
||||
String dstAddr, boolean automaticOnOffKeepalives) {
|
||||
try {
|
||||
final FileDescriptor fd = pfd.getFileDescriptor();
|
||||
mKeepaliveTracker.startNattKeepalive(
|
||||
getNetworkAgentInfoForNetwork(network), fd, resourceId,
|
||||
intervalSeconds, cb,
|
||||
srcAddr, dstAddr, NattSocketKeepalive.NATT_PORT);
|
||||
srcAddr, dstAddr, NattSocketKeepalive.NATT_PORT, automaticOnOffKeepalives);
|
||||
} finally {
|
||||
// FileDescriptors coming from AIDL calls must be manually closed to prevent leaks.
|
||||
// startNattKeepalive calls Os.dup(fd) before returning, so we can close immediately.
|
||||
|
|
|
|||
|
|
@ -16,6 +16,9 @@
|
|||
|
||||
package com.android.server.connectivity;
|
||||
|
||||
import static android.net.NetworkAgent.CMD_START_SOCKET_KEEPALIVE;
|
||||
import static android.net.SocketKeepalive.ERROR_INVALID_SOCKET;
|
||||
import static android.net.SocketKeepalive.SUCCESS;
|
||||
import static android.system.OsConstants.AF_INET;
|
||||
import static android.system.OsConstants.AF_INET6;
|
||||
import static android.system.OsConstants.SOL_SOCKET;
|
||||
|
|
@ -26,16 +29,28 @@ import static com.android.net.module.util.netlink.NetlinkConstants.SOCKDIAG_MSG_
|
|||
import static com.android.net.module.util.netlink.NetlinkConstants.SOCK_DIAG_BY_FAMILY;
|
||||
import static com.android.net.module.util.netlink.NetlinkUtils.IO_TIMEOUT_MS;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.app.AlarmManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.net.INetd;
|
||||
import android.net.ISocketKeepaliveCallback;
|
||||
import android.net.MarkMaskParcel;
|
||||
import android.net.Network;
|
||||
import android.net.NetworkAgent;
|
||||
import android.net.SocketKeepalive;
|
||||
import android.net.SocketKeepalive.InvalidSocketException;
|
||||
import android.os.FileUtils;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.Message;
|
||||
import android.os.RemoteException;
|
||||
import android.os.SystemClock;
|
||||
import android.system.ErrnoException;
|
||||
import android.system.Os;
|
||||
import android.system.StructTimeval;
|
||||
|
|
@ -44,6 +59,7 @@ import android.util.SparseArray;
|
|||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.util.IndentingPrintWriter;
|
||||
import com.android.modules.utils.build.SdkLevel;
|
||||
import com.android.net.module.util.HexDump;
|
||||
import com.android.net.module.util.SocketUtils;
|
||||
import com.android.net.module.util.netlink.InetDiagMessage;
|
||||
|
|
@ -52,23 +68,57 @@ import com.android.net.module.util.netlink.StructNlAttr;
|
|||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.InterruptedIOException;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.net.SocketException;
|
||||
import java.nio.BufferUnderflowException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Manages automatic on/off socket keepalive requests.
|
||||
*
|
||||
* Provides methods to stop and start automatic keepalive requests, and keeps track of keepalives
|
||||
* across all networks. For non-automatic on/off keepalive request, this class bypass the requests
|
||||
* and send to KeepaliveTrakcer. This class is tightly coupled to ConnectivityService. It is not
|
||||
* across all networks. For non-automatic on/off keepalive request, this class just forwards the
|
||||
* requests to KeepaliveTracker. This class is tightly coupled to ConnectivityService. It is not
|
||||
* thread-safe and its handle* methods must be called only from the ConnectivityService handler
|
||||
* thread.
|
||||
*/
|
||||
public class AutomaticOnOffKeepaliveTracker {
|
||||
private static final String TAG = "AutomaticOnOffKeepaliveTracker";
|
||||
private static final int[] ADDRESS_FAMILIES = new int[] {AF_INET6, AF_INET};
|
||||
private static final String ACTION_TCP_POLLING_ALARM =
|
||||
"com.android.server.connectivity.KeepaliveTracker.TCP_POLLING_ALARM";
|
||||
private static final String EXTRA_NETWORK = "network_id";
|
||||
private static final String EXTRA_SLOT = "slot";
|
||||
private static final long DEFAULT_TCP_POLLING_INTERVAL_MS = 120_000L;
|
||||
/**
|
||||
* States for {@code #AutomaticOnOffKeepalive}.
|
||||
*
|
||||
* A new AutomaticOnOffKeepalive starts with STATE_ENABLED. The system will monitor
|
||||
* the TCP sockets on VPN networks running on top of the specified network, and turn off
|
||||
* keepalive if there is no TCP socket any of the VPN networks. Conversely, it will turn
|
||||
* keepalive back on if any TCP socket is open on any of the VPN networks.
|
||||
*
|
||||
* When there is no TCP socket on any of the VPN networks, the state becomes STATE_SUSPENDED.
|
||||
* The {@link KeepaliveTracker.KeepaliveInfo} object is kept to remember the parameters so it
|
||||
* is possible to resume keepalive later with the same parameters.
|
||||
*
|
||||
* When the system detects some TCP socket is open on one of the VPNs while in STATE_SUSPENDED,
|
||||
* this AutomaticOnOffKeepalive goes to STATE_ENABLED again.
|
||||
*
|
||||
* When finishing keepalive, this object is deleted.
|
||||
*/
|
||||
private static final int STATE_ENABLED = 0;
|
||||
private static final int STATE_SUSPENDED = 1;
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef(prefix = { "STATE_" }, value = {
|
||||
STATE_ENABLED,
|
||||
STATE_SUSPENDED
|
||||
})
|
||||
private @interface AutomaticOnOffState {}
|
||||
|
||||
@NonNull
|
||||
private final Handler mConnectivityServiceHandler;
|
||||
|
|
@ -76,6 +126,8 @@ public class AutomaticOnOffKeepaliveTracker {
|
|||
private final KeepaliveTracker mKeepaliveTracker;
|
||||
@NonNull
|
||||
private final Context mContext;
|
||||
@NonNull
|
||||
private final AlarmManager mAlarmManager;
|
||||
|
||||
/**
|
||||
* The {@code inetDiagReqV2} messages for different IP family.
|
||||
|
|
@ -88,8 +140,73 @@ public class AutomaticOnOffKeepaliveTracker {
|
|||
private final SparseArray<byte[]> mSockDiagMsg = new SparseArray<>();
|
||||
private final Dependencies mDependencies;
|
||||
private final INetd mNetd;
|
||||
/**
|
||||
* Keeps track of automatic on/off keepalive requests.
|
||||
* This should be only updated in ConnectivityService handler thread.
|
||||
*/
|
||||
private final ArrayList<AutomaticOnOffKeepalive> mAutomaticOnOffKeepalives = new ArrayList<>();
|
||||
|
||||
public AutomaticOnOffKeepaliveTracker(Context context, Handler handler) {
|
||||
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (ACTION_TCP_POLLING_ALARM.equals(intent.getAction())) {
|
||||
Log.d(TAG, "Received TCP polling intent");
|
||||
final Network network = intent.getParcelableExtra(EXTRA_NETWORK);
|
||||
final int slot = intent.getIntExtra(EXTRA_SLOT, -1);
|
||||
mConnectivityServiceHandler.obtainMessage(
|
||||
NetworkAgent.CMD_MONITOR_AUTOMATIC_KEEPALIVE,
|
||||
slot, 0 , network).sendToTarget();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private static class AutomaticOnOffKeepalive {
|
||||
@NonNull
|
||||
private final KeepaliveTracker.KeepaliveInfo mKi;
|
||||
@NonNull
|
||||
private final FileDescriptor mFd;
|
||||
@NonNull
|
||||
private final PendingIntent mTcpPollingAlarm;
|
||||
private final int mSlot;
|
||||
@AutomaticOnOffState
|
||||
private int mAutomaticOnOffState = STATE_ENABLED;
|
||||
|
||||
AutomaticOnOffKeepalive(@NonNull KeepaliveTracker.KeepaliveInfo ki,
|
||||
@NonNull Context context) throws InvalidSocketException {
|
||||
this.mKi = Objects.requireNonNull(ki);
|
||||
// A null fd is acceptable in KeepaliveInfo for backward compatibility of
|
||||
// PacketKeepalive API, but it should not happen here because legacy API cannot setup
|
||||
// automatic keepalive.
|
||||
Objects.requireNonNull(ki.mFd);
|
||||
|
||||
// Get the slot from keepalive because the slot information may be missing when the
|
||||
// keepalive is stopped.
|
||||
this.mSlot = ki.getSlot();
|
||||
try {
|
||||
this.mFd = Os.dup(ki.mFd);
|
||||
} catch (ErrnoException e) {
|
||||
Log.e(TAG, "Cannot dup fd: ", e);
|
||||
throw new InvalidSocketException(ERROR_INVALID_SOCKET, e);
|
||||
}
|
||||
mTcpPollingAlarm = createTcpPollingAlarmIntent(
|
||||
context, ki.getNai().network(), ki.getSlot());
|
||||
}
|
||||
|
||||
public boolean match(Network network, int slot) {
|
||||
return this.mKi.getNai().network().equals(network) && this.mSlot == slot;
|
||||
}
|
||||
|
||||
private static PendingIntent createTcpPollingAlarmIntent(@NonNull Context context,
|
||||
@NonNull Network network, int slot) {
|
||||
final Intent intent = new Intent(ACTION_TCP_POLLING_ALARM);
|
||||
intent.putExtra(EXTRA_NETWORK, network);
|
||||
intent.putExtra(EXTRA_SLOT, slot);
|
||||
return PendingIntent.getBroadcast(
|
||||
context, 0 /* requestCode */, intent, PendingIntent.FLAG_IMMUTABLE);
|
||||
}
|
||||
}
|
||||
|
||||
public AutomaticOnOffKeepaliveTracker(@NonNull Context context, @NonNull Handler handler) {
|
||||
this(context, handler, new Dependencies(context));
|
||||
}
|
||||
|
||||
|
|
@ -97,15 +214,111 @@ public class AutomaticOnOffKeepaliveTracker {
|
|||
public AutomaticOnOffKeepaliveTracker(@NonNull Context context, @NonNull Handler handler,
|
||||
@NonNull Dependencies dependencies) {
|
||||
mContext = Objects.requireNonNull(context);
|
||||
mDependencies = dependencies;
|
||||
this.mConnectivityServiceHandler = Objects.requireNonNull(handler);
|
||||
mDependencies = Objects.requireNonNull(dependencies);
|
||||
mConnectivityServiceHandler = Objects.requireNonNull(handler);
|
||||
mNetd = mDependencies.getNetd();
|
||||
mKeepaliveTracker = mDependencies.newKeepaliveTracker(
|
||||
mContext, mConnectivityServiceHandler);
|
||||
|
||||
if (SdkLevel.isAtLeastU()) {
|
||||
mContext.registerReceiver(mReceiver, new IntentFilter(ACTION_TCP_POLLING_ALARM),
|
||||
null, handler);
|
||||
}
|
||||
mAlarmManager = mContext.getSystemService(AlarmManager.class);
|
||||
}
|
||||
|
||||
private void startTcpPollingAlarm(@NonNull PendingIntent alarm) {
|
||||
final long triggerAtMillis =
|
||||
SystemClock.elapsedRealtime() + DEFAULT_TCP_POLLING_INTERVAL_MS;
|
||||
// Setup a non-wake up alarm.
|
||||
mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME, triggerAtMillis, alarm);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if any state transition is needed for the specific automatic keepalive.
|
||||
*/
|
||||
public void handleMonitorAutomaticKeepalive(@NonNull Network network, int slot, int vpnNetId) {
|
||||
final AutomaticOnOffKeepalive autoKi = findAutomaticOnOffKeepalive(network, slot);
|
||||
// This may happen if the keepalive is removed by the app, and the alarm is fired at the
|
||||
// same time.
|
||||
if (autoKi == null) return;
|
||||
|
||||
handleMonitorTcpConnections(autoKi, vpnNetId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if disable or re-enable keepalive is needed or not based on TCP sockets status.
|
||||
*/
|
||||
private void handleMonitorTcpConnections(@NonNull AutomaticOnOffKeepalive ki, int vpnNetId) {
|
||||
if (!isAnyTcpSocketConnected(vpnNetId)) {
|
||||
// No TCP socket exists. Stop keepalive if ENABLED, and remain SUSPENDED if currently
|
||||
// SUSPENDED.
|
||||
if (ki.mAutomaticOnOffState == STATE_ENABLED) {
|
||||
ki.mAutomaticOnOffState = STATE_SUSPENDED;
|
||||
handleSuspendKeepalive(ki.mKi.mNai, ki.mSlot, SUCCESS);
|
||||
}
|
||||
} else {
|
||||
handleMaybeResumeKeepalive(ki);
|
||||
}
|
||||
// TODO: listen to socket status instead of periodically check.
|
||||
startTcpPollingAlarm(ki.mTcpPollingAlarm);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resume keepalive for this slot on this network, if it wasn't already resumed.
|
||||
*/
|
||||
public void handleMaybeResumeKeepalive(@NonNull final Network network, final int slot) {
|
||||
final AutomaticOnOffKeepalive autoKi = findAutomaticOnOffKeepalive(network, slot);
|
||||
// This may happen if the keepalive is removed by the app, and the alarm is fired at
|
||||
// the same time.
|
||||
if (autoKi == null) return;
|
||||
handleMaybeResumeKeepalive(autoKi);
|
||||
}
|
||||
|
||||
private void handleMaybeResumeKeepalive(@NonNull AutomaticOnOffKeepalive autoKi) {
|
||||
if (autoKi.mAutomaticOnOffState == STATE_ENABLED) return;
|
||||
KeepaliveTracker.KeepaliveInfo newKi;
|
||||
try {
|
||||
// Get fd from AutomaticOnOffKeepalive since the fd in the original
|
||||
// KeepaliveInfo should be closed.
|
||||
newKi = autoKi.mKi.withFd(autoKi.mFd);
|
||||
} catch (InvalidSocketException | IllegalArgumentException | SecurityException e) {
|
||||
Log.e(TAG, "Fail to construct keepalive", e);
|
||||
mKeepaliveTracker.notifyErrorCallback(autoKi.mKi.mCallback, ERROR_INVALID_SOCKET);
|
||||
return;
|
||||
}
|
||||
autoKi.mAutomaticOnOffState = STATE_ENABLED;
|
||||
handleResumeKeepalive(mConnectivityServiceHandler.obtainMessage(
|
||||
NetworkAgent.CMD_START_SOCKET_KEEPALIVE,
|
||||
autoKi.mAutomaticOnOffState, 0, newKi));
|
||||
}
|
||||
|
||||
private int findAutomaticOnOffKeepaliveIndex(@NonNull Network network, int slot) {
|
||||
ensureRunningOnHandlerThread();
|
||||
|
||||
int index = 0;
|
||||
for (AutomaticOnOffKeepalive ki : mAutomaticOnOffKeepalives) {
|
||||
if (ki.match(network, slot)) {
|
||||
return index;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private AutomaticOnOffKeepalive findAutomaticOnOffKeepalive(@NonNull Network network,
|
||||
int slot) {
|
||||
ensureRunningOnHandlerThread();
|
||||
|
||||
final int index = findAutomaticOnOffKeepaliveIndex(network, slot);
|
||||
return (index >= 0) ? mAutomaticOnOffKeepalives.get(index) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle keepalive events from lower layer.
|
||||
*
|
||||
* Forward to KeepaliveTracker.
|
||||
*/
|
||||
public void handleEventSocketKeepalive(@NonNull NetworkAgentInfo nai, int slot, int reason) {
|
||||
mKeepaliveTracker.handleEventSocketKeepalive(nai, slot, reason);
|
||||
|
|
@ -116,27 +329,86 @@ public class AutomaticOnOffKeepaliveTracker {
|
|||
*/
|
||||
public void handleStopAllKeepalives(NetworkAgentInfo nai, int reason) {
|
||||
mKeepaliveTracker.handleStopAllKeepalives(nai, reason);
|
||||
final Iterator<AutomaticOnOffKeepalive> iterator = mAutomaticOnOffKeepalives.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
final AutomaticOnOffKeepalive autoKi = iterator.next();
|
||||
if (autoKi.mKi.getNai() == nai) {
|
||||
cleanupAutoOnOffKeepalive(autoKi);
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle start keepalives with the message.
|
||||
* Handle start keepalive contained within a message.
|
||||
*
|
||||
* The message is expected to be a KeepaliveTracker.KeepaliveInfo.
|
||||
* The message is expected to contain a KeepaliveTracker.KeepaliveInfo.
|
||||
*/
|
||||
public void handleStartKeepalive(Message message) {
|
||||
mKeepaliveTracker.handleStartKeepalive(message);
|
||||
|
||||
// Add automatic on/off request into list to track its life cycle.
|
||||
final boolean automaticOnOff = message.arg1 != 0;
|
||||
if (automaticOnOff) {
|
||||
final KeepaliveTracker.KeepaliveInfo ki = (KeepaliveTracker.KeepaliveInfo) message.obj;
|
||||
AutomaticOnOffKeepalive autoKi;
|
||||
try {
|
||||
// CAREFUL : mKeepaliveTracker.handleStartKeepalive will assign |ki.mSlot| after
|
||||
// pulling |ki| from the message. The constructor below will read this member
|
||||
// (through ki.getSlot()) and therefore actively relies on handleStartKeepalive
|
||||
// having assigned this member before this is called.
|
||||
// TODO : clean this up by assigning the slot at the start of this method instead
|
||||
// and ideally removing the mSlot member from KeepaliveInfo.
|
||||
autoKi = new AutomaticOnOffKeepalive(ki, mContext);
|
||||
} catch (SocketKeepalive.InvalidSocketException | IllegalArgumentException e) {
|
||||
Log.e(TAG, "Fail to construct keepalive", e);
|
||||
mKeepaliveTracker.notifyErrorCallback(ki.mCallback, ERROR_INVALID_SOCKET);
|
||||
return;
|
||||
}
|
||||
mAutomaticOnOffKeepalives.add(autoKi);
|
||||
startTcpPollingAlarm(autoKi.mTcpPollingAlarm);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleResumeKeepalive(Message message) {
|
||||
mKeepaliveTracker.handleStartKeepalive(message);
|
||||
}
|
||||
|
||||
private void handleSuspendKeepalive(NetworkAgentInfo nai, int slot, int reason) {
|
||||
mKeepaliveTracker.handleStopKeepalive(nai, slot, reason);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle stop keepalives on the specific network with given slot.
|
||||
*/
|
||||
public void handleStopKeepalive(NetworkAgentInfo nai, int slot, int reason) {
|
||||
mKeepaliveTracker.handleStopKeepalive(nai, slot, reason);
|
||||
final AutomaticOnOffKeepalive autoKi = findAutomaticOnOffKeepalive(nai.network, slot);
|
||||
|
||||
// Let the original keepalive do the stop first, and then clean up the keepalive if it's an
|
||||
// automatic keepalive.
|
||||
if (autoKi == null || autoKi.mAutomaticOnOffState == STATE_ENABLED) {
|
||||
mKeepaliveTracker.handleStopKeepalive(nai, slot, reason);
|
||||
}
|
||||
|
||||
// Not an AutomaticOnOffKeepalive.
|
||||
if (autoKi == null) return;
|
||||
|
||||
cleanupAutoOnOffKeepalive(autoKi);
|
||||
mAutomaticOnOffKeepalives.remove(autoKi);
|
||||
}
|
||||
|
||||
private void cleanupAutoOnOffKeepalive(@NonNull final AutomaticOnOffKeepalive autoKi) {
|
||||
ensureRunningOnHandlerThread();
|
||||
mAlarmManager.cancel(autoKi.mTcpPollingAlarm);
|
||||
// Close the duplicated fd that maintains the lifecycle of socket.
|
||||
FileUtils.closeQuietly(autoKi.mFd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when requesting that keepalives be started on a IPsec NAT-T socket. See
|
||||
* {@link android.net.SocketKeepalive}.
|
||||
*
|
||||
* Forward to KeepaliveTracker.
|
||||
**/
|
||||
public void startNattKeepalive(@Nullable NetworkAgentInfo nai,
|
||||
@Nullable FileDescriptor fd,
|
||||
|
|
@ -145,14 +417,21 @@ public class AutomaticOnOffKeepaliveTracker {
|
|||
@NonNull String srcAddrString,
|
||||
int srcPort,
|
||||
@NonNull String dstAddrString,
|
||||
int dstPort) {
|
||||
mKeepaliveTracker.startNattKeepalive(nai, fd, intervalSeconds, cb, srcAddrString,
|
||||
srcPort, dstAddrString, dstPort);
|
||||
int dstPort, boolean automaticOnOffKeepalives) {
|
||||
final KeepaliveTracker.KeepaliveInfo ki = mKeepaliveTracker.makeNattKeepaliveInfo(nai, fd,
|
||||
intervalSeconds, cb, srcAddrString, srcPort, dstAddrString, dstPort);
|
||||
if (null != ki) {
|
||||
mConnectivityServiceHandler.obtainMessage(NetworkAgent.CMD_START_SOCKET_KEEPALIVE,
|
||||
// TODO : move ConnectivityService#encodeBool to a static lib.
|
||||
automaticOnOffKeepalives ? 1 : 0, 0, ki).sendToTarget();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when requesting that keepalives be started on a IPsec NAT-T socket. See
|
||||
* {@link android.net.SocketKeepalive}.
|
||||
*
|
||||
* Forward to KeepaliveTracker.
|
||||
**/
|
||||
public void startNattKeepalive(@Nullable NetworkAgentInfo nai,
|
||||
@Nullable FileDescriptor fd,
|
||||
|
|
@ -161,9 +440,15 @@ public class AutomaticOnOffKeepaliveTracker {
|
|||
@NonNull ISocketKeepaliveCallback cb,
|
||||
@NonNull String srcAddrString,
|
||||
@NonNull String dstAddrString,
|
||||
int dstPort) {
|
||||
mKeepaliveTracker.startNattKeepalive(nai, fd, resourceId, intervalSeconds, cb,
|
||||
srcAddrString, dstAddrString, dstPort);
|
||||
int dstPort,
|
||||
boolean automaticOnOffKeepalives) {
|
||||
final KeepaliveTracker.KeepaliveInfo ki = mKeepaliveTracker.makeNattKeepaliveInfo(nai, fd,
|
||||
resourceId, intervalSeconds, cb, srcAddrString, dstAddrString, dstPort);
|
||||
if (null != ki) {
|
||||
mConnectivityServiceHandler.obtainMessage(NetworkAgent.CMD_START_SOCKET_KEEPALIVE,
|
||||
// TODO : move ConnectivityService#encodeBool to a static lib.
|
||||
automaticOnOffKeepalives ? 1 : 0, 0, ki).sendToTarget();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -173,26 +458,34 @@ public class AutomaticOnOffKeepaliveTracker {
|
|||
* other fields are needed to form the keepalive packet. Thus, this function synchronously
|
||||
* puts the socket into repair mode to get the necessary information. After the socket has been
|
||||
* put into repair mode, the application cannot access the socket until reverted to normal.
|
||||
*
|
||||
* See {@link android.net.SocketKeepalive}.
|
||||
*
|
||||
* Forward to KeepaliveTracker.
|
||||
**/
|
||||
public void startTcpKeepalive(@Nullable NetworkAgentInfo nai,
|
||||
@NonNull FileDescriptor fd,
|
||||
int intervalSeconds,
|
||||
@NonNull ISocketKeepaliveCallback cb) {
|
||||
mKeepaliveTracker.startTcpKeepalive(nai, fd, intervalSeconds, cb);
|
||||
final KeepaliveTracker.KeepaliveInfo ki = mKeepaliveTracker.makeTcpKeepaliveInfo(nai, fd,
|
||||
intervalSeconds, cb);
|
||||
if (null != ki) {
|
||||
mConnectivityServiceHandler.obtainMessage(CMD_START_SOCKET_KEEPALIVE, ki)
|
||||
.sendToTarget();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dump AutomaticOnOffKeepaliveTracker state.
|
||||
*/
|
||||
public void dump(IndentingPrintWriter pw) {
|
||||
// TODO: Dump the necessary information for automatic on/off keepalive.
|
||||
// TODO: Dump the necessary information for automatic on/off keepalive.
|
||||
mKeepaliveTracker.dump(pw);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check all keeplaives on the network are still valid.
|
||||
* Check all keepalives on the network are still valid.
|
||||
*
|
||||
* Forward to KeepaliveTracker.
|
||||
*/
|
||||
public void handleCheckKeepalivesStillValid(NetworkAgentInfo nai) {
|
||||
mKeepaliveTracker.handleCheckKeepalivesStillValid(nai);
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ package com.android.server.connectivity;
|
|||
|
||||
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
|
||||
import static android.net.NattSocketKeepalive.NATT_PORT;
|
||||
import static android.net.NetworkAgent.CMD_START_SOCKET_KEEPALIVE;
|
||||
import static android.net.SocketKeepalive.BINDER_DIED;
|
||||
import static android.net.SocketKeepalive.DATA_RECEIVED;
|
||||
import static android.net.SocketKeepalive.ERROR_INSUFFICIENT_RESOURCES;
|
||||
|
|
@ -88,7 +87,6 @@ public class KeepaliveTracker {
|
|||
/** Keeps track of keepalive requests. */
|
||||
private final HashMap <NetworkAgentInfo, HashMap<Integer, KeepaliveInfo>> mKeepalives =
|
||||
new HashMap<> ();
|
||||
private final Handler mConnectivityServiceHandler;
|
||||
@NonNull
|
||||
private final TcpKeepaliveController mTcpController;
|
||||
@NonNull
|
||||
|
|
@ -109,7 +107,6 @@ public class KeepaliveTracker {
|
|||
private final int mAllowedUnprivilegedSlotsForUid;
|
||||
|
||||
public KeepaliveTracker(Context context, Handler handler) {
|
||||
mConnectivityServiceHandler = handler;
|
||||
mTcpController = new TcpKeepaliveController(handler);
|
||||
mContext = context;
|
||||
|
||||
|
|
@ -130,13 +127,13 @@ public class KeepaliveTracker {
|
|||
*/
|
||||
class KeepaliveInfo implements IBinder.DeathRecipient {
|
||||
// Bookkeeping data.
|
||||
private final ISocketKeepaliveCallback mCallback;
|
||||
public final ISocketKeepaliveCallback mCallback;
|
||||
private final int mUid;
|
||||
private final int mPid;
|
||||
private final boolean mPrivileged;
|
||||
private final NetworkAgentInfo mNai;
|
||||
public final NetworkAgentInfo mNai;
|
||||
private final int mType;
|
||||
private final FileDescriptor mFd;
|
||||
public final FileDescriptor mFd;
|
||||
|
||||
public static final int TYPE_NATT = 1;
|
||||
public static final int TYPE_TCP = 2;
|
||||
|
|
@ -244,6 +241,10 @@ public class KeepaliveTracker {
|
|||
}
|
||||
}
|
||||
|
||||
public int getSlot() {
|
||||
return mSlot;
|
||||
}
|
||||
|
||||
private int checkNetworkConnected() {
|
||||
if (!mNai.networkInfo.isConnectedOrConnecting()) {
|
||||
return ERROR_INVALID_NETWORK;
|
||||
|
|
@ -416,6 +417,13 @@ public class KeepaliveTracker {
|
|||
void onFileDescriptorInitiatedStop(final int socketKeepaliveReason) {
|
||||
handleStopKeepalive(mNai, mSlot, socketKeepaliveReason);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new KeepaliveInfo from existing KeepaliveInfo with a new fd.
|
||||
*/
|
||||
public KeepaliveInfo withFd(@NonNull FileDescriptor fd) throws InvalidSocketException {
|
||||
return new KeepaliveInfo(mCallback, mNai, mPacket, mInterval, mType, fd);
|
||||
}
|
||||
}
|
||||
|
||||
void notifyErrorCallback(ISocketKeepaliveCallback cb, int error) {
|
||||
|
|
@ -445,6 +453,9 @@ public class KeepaliveTracker {
|
|||
return slot;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle start keepalives with the message.
|
||||
*/
|
||||
public void handleStartKeepalive(Message message) {
|
||||
KeepaliveInfo ki = (KeepaliveInfo) message.obj;
|
||||
NetworkAgentInfo nai = ki.getNai();
|
||||
|
|
@ -605,7 +616,8 @@ public class KeepaliveTracker {
|
|||
* Called when requesting that keepalives be started on a IPsec NAT-T socket. See
|
||||
* {@link android.net.SocketKeepalive}.
|
||||
**/
|
||||
public void startNattKeepalive(@Nullable NetworkAgentInfo nai,
|
||||
@Nullable
|
||||
public KeepaliveInfo makeNattKeepaliveInfo(@Nullable NetworkAgentInfo nai,
|
||||
@Nullable FileDescriptor fd,
|
||||
int intervalSeconds,
|
||||
@NonNull ISocketKeepaliveCallback cb,
|
||||
|
|
@ -615,7 +627,7 @@ public class KeepaliveTracker {
|
|||
int dstPort) {
|
||||
if (nai == null) {
|
||||
notifyErrorCallback(cb, ERROR_INVALID_NETWORK);
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
InetAddress srcAddress, dstAddress;
|
||||
|
|
@ -624,7 +636,7 @@ public class KeepaliveTracker {
|
|||
dstAddress = InetAddresses.parseNumericAddress(dstAddrString);
|
||||
} catch (IllegalArgumentException e) {
|
||||
notifyErrorCallback(cb, ERROR_INVALID_IP_ADDRESS);
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
KeepalivePacketData packet;
|
||||
|
|
@ -633,7 +645,7 @@ public class KeepaliveTracker {
|
|||
srcAddress, srcPort, dstAddress, NATT_PORT);
|
||||
} catch (InvalidPacketException e) {
|
||||
notifyErrorCallback(cb, e.getError());
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
KeepaliveInfo ki = null;
|
||||
try {
|
||||
|
|
@ -642,15 +654,14 @@ public class KeepaliveTracker {
|
|||
} catch (InvalidSocketException | IllegalArgumentException | SecurityException e) {
|
||||
Log.e(TAG, "Fail to construct keepalive", e);
|
||||
notifyErrorCallback(cb, ERROR_INVALID_SOCKET);
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
Log.d(TAG, "Created keepalive: " + ki.toString());
|
||||
mConnectivityServiceHandler.obtainMessage(
|
||||
NetworkAgent.CMD_START_SOCKET_KEEPALIVE, ki).sendToTarget();
|
||||
Log.d(TAG, "Created keepalive: " + ki);
|
||||
return ki;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by ConnectivityService to start TCP keepalive on a file descriptor.
|
||||
* Make a KeepaliveInfo for a TCP socket.
|
||||
*
|
||||
* In order to offload keepalive for application correctly, sequence number, ack number and
|
||||
* other fields are needed to form the keepalive packet. Thus, this function synchronously
|
||||
|
|
@ -659,13 +670,14 @@ public class KeepaliveTracker {
|
|||
*
|
||||
* See {@link android.net.SocketKeepalive}.
|
||||
**/
|
||||
public void startTcpKeepalive(@Nullable NetworkAgentInfo nai,
|
||||
@Nullable
|
||||
public KeepaliveInfo makeTcpKeepaliveInfo(@Nullable NetworkAgentInfo nai,
|
||||
@NonNull FileDescriptor fd,
|
||||
int intervalSeconds,
|
||||
@NonNull ISocketKeepaliveCallback cb) {
|
||||
if (nai == null) {
|
||||
notifyErrorCallback(cb, ERROR_INVALID_NETWORK);
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
final TcpKeepalivePacketData packet;
|
||||
|
|
@ -673,10 +685,10 @@ public class KeepaliveTracker {
|
|||
packet = TcpKeepaliveController.getTcpKeepalivePacket(fd);
|
||||
} catch (InvalidSocketException e) {
|
||||
notifyErrorCallback(cb, e.error);
|
||||
return;
|
||||
return null;
|
||||
} catch (InvalidPacketException e) {
|
||||
notifyErrorCallback(cb, e.getError());
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
KeepaliveInfo ki = null;
|
||||
try {
|
||||
|
|
@ -685,20 +697,22 @@ public class KeepaliveTracker {
|
|||
} catch (InvalidSocketException | IllegalArgumentException | SecurityException e) {
|
||||
Log.e(TAG, "Fail to construct keepalive e=" + e);
|
||||
notifyErrorCallback(cb, ERROR_INVALID_SOCKET);
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
Log.d(TAG, "Created keepalive: " + ki.toString());
|
||||
mConnectivityServiceHandler.obtainMessage(CMD_START_SOCKET_KEEPALIVE, ki).sendToTarget();
|
||||
return ki;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when requesting that keepalives be started on a IPsec NAT-T socket. This function is
|
||||
* identical to {@link #startNattKeepalive}, but also takes a {@code resourceId}, which is the
|
||||
* resource index bound to the {@link UdpEncapsulationSocket} when creating by
|
||||
* {@link com.android.server.IpSecService} to verify whether the given
|
||||
* {@link UdpEncapsulationSocket} is legitimate.
|
||||
**/
|
||||
public void startNattKeepalive(@Nullable NetworkAgentInfo nai,
|
||||
/**
|
||||
* Make a KeepaliveInfo for an IPSec NAT-T socket.
|
||||
*
|
||||
* This function is identical to {@link #makeNattKeepaliveInfo}, but also takes a
|
||||
* {@code resourceId}, which is the resource index bound to the {@link UdpEncapsulationSocket}
|
||||
* when creating by {@link com.android.server.IpSecService} to verify whether the given
|
||||
* {@link UdpEncapsulationSocket} is legitimate.
|
||||
**/
|
||||
@Nullable
|
||||
public KeepaliveInfo makeNattKeepaliveInfo(@Nullable NetworkAgentInfo nai,
|
||||
@Nullable FileDescriptor fd,
|
||||
int resourceId,
|
||||
int intervalSeconds,
|
||||
|
|
@ -709,6 +723,7 @@ public class KeepaliveTracker {
|
|||
// Ensure that the socket is created by IpSecService.
|
||||
if (!isNattKeepaliveSocketValid(fd, resourceId)) {
|
||||
notifyErrorCallback(cb, ERROR_INVALID_SOCKET);
|
||||
return null;
|
||||
}
|
||||
|
||||
// Get src port to adopt old API.
|
||||
|
|
@ -718,10 +733,11 @@ public class KeepaliveTracker {
|
|||
srcPort = ((InetSocketAddress) srcSockAddr).getPort();
|
||||
} catch (ErrnoException e) {
|
||||
notifyErrorCallback(cb, ERROR_INVALID_SOCKET);
|
||||
return null;
|
||||
}
|
||||
|
||||
// Forward request to old API.
|
||||
startNattKeepalive(nai, fd, intervalSeconds, cb, srcAddrString, srcPort,
|
||||
return makeNattKeepaliveInfo(nai, fd, intervalSeconds, cb, srcAddrString, srcPort,
|
||||
dstAddrString, dstPort);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue