Merge changes from topic "ka05" am: b3656c7b1b am: 14e51c8a84
am: 3dea854998
Change-Id: Ie56c431a6d934c752d1de30fc4bf98a7e557e5b2
This commit is contained in:
@@ -15,6 +15,9 @@
|
||||
*/
|
||||
package android.net;
|
||||
|
||||
import static android.net.IpSecManager.INVALID_RESOURCE_ID;
|
||||
|
||||
import android.annotation.CallbackExecutor;
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
@@ -28,6 +31,8 @@ import android.annotation.UnsupportedAppUsage;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.IpSecManager.UdpEncapsulationSocket;
|
||||
import android.net.SocketKeepalive.Callback;
|
||||
import android.os.Binder;
|
||||
import android.os.Build;
|
||||
import android.os.Build.VERSION_CODES;
|
||||
@@ -58,6 +63,7 @@ import com.android.internal.util.Protocol;
|
||||
|
||||
import libcore.net.event.NetworkEventDispatcher;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.net.InetAddress;
|
||||
@@ -66,6 +72,7 @@ import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
/**
|
||||
* Class that answers queries about the state of network connectivity. It also
|
||||
@@ -1699,6 +1706,8 @@ public class ConnectivityManager {
|
||||
* {@link PacketKeepaliveCallback#onStopped} if the operation was successful or
|
||||
* {@link PacketKeepaliveCallback#onError} if an error occurred.
|
||||
*
|
||||
* @deprecated Use {@link SocketKeepalive} instead.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class PacketKeepalive {
|
||||
@@ -1802,6 +1811,8 @@ public class ConnectivityManager {
|
||||
/**
|
||||
* Starts an IPsec NAT-T keepalive packet with the specified parameters.
|
||||
*
|
||||
* @deprecated Use {@link #createSocketKeepalive} instead.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@UnsupportedAppUsage
|
||||
@@ -1820,6 +1831,62 @@ public class ConnectivityManager {
|
||||
return k;
|
||||
}
|
||||
|
||||
/**
|
||||
* Request that keepalives be started on a IPsec NAT-T socket.
|
||||
*
|
||||
* @param network The {@link Network} the socket is on.
|
||||
* @param socket The socket that needs to be kept alive.
|
||||
* @param source The source address of the {@link UdpEncapsulationSocket}.
|
||||
* @param destination The destination address of the {@link UdpEncapsulationSocket}.
|
||||
* @param executor The executor on which callback will be invoked. The provided {@link Executor}
|
||||
* must run callback sequentially, otherwise the order of callbacks cannot be
|
||||
* guaranteed.
|
||||
* @param callback A {@link SocketKeepalive.Callback}. Used for notifications about keepalive
|
||||
* changes. Must be extended by applications that use this API.
|
||||
*
|
||||
* @return A {@link SocketKeepalive} object, which can be used to control this keepalive object.
|
||||
**/
|
||||
public SocketKeepalive createSocketKeepalive(@NonNull Network network,
|
||||
@NonNull UdpEncapsulationSocket socket,
|
||||
@NonNull InetAddress source,
|
||||
@NonNull InetAddress destination,
|
||||
@NonNull @CallbackExecutor Executor executor,
|
||||
@NonNull Callback callback) {
|
||||
return new NattSocketKeepalive(mService, network, socket.getFileDescriptor(),
|
||||
socket.getResourceId(), source, destination, executor, callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Request that keepalives be started on a IPsec NAT-T socket file descriptor. Directly called
|
||||
* by system apps which don't use IpSecService to create {@link UdpEncapsulationSocket}.
|
||||
*
|
||||
* @param network The {@link Network} the socket is on.
|
||||
* @param fd The {@link FileDescriptor} that needs to be kept alive. The provided
|
||||
* {@link FileDescriptor} must be bound to a port and the keepalives will be sent from
|
||||
* that port.
|
||||
* @param source The source address of the {@link UdpEncapsulationSocket}.
|
||||
* @param destination The destination address of the {@link UdpEncapsulationSocket}. The
|
||||
* keepalive packets will always be sent to port 4500 of the given {@code destination}.
|
||||
* @param executor The executor on which callback will be invoked. The provided {@link Executor}
|
||||
* must run callback sequentially, otherwise the order of callbacks cannot be
|
||||
* guaranteed.
|
||||
* @param callback A {@link SocketKeepalive.Callback}. Used for notifications about keepalive
|
||||
* changes. Must be extended by applications that use this API.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
@RequiresPermission(android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD)
|
||||
public SocketKeepalive createNattKeepalive(@NonNull Network network,
|
||||
@NonNull FileDescriptor fd,
|
||||
@NonNull InetAddress source,
|
||||
@NonNull InetAddress destination,
|
||||
@NonNull @CallbackExecutor Executor executor,
|
||||
@NonNull Callback callback) {
|
||||
return new NattSocketKeepalive(mService, network, fd, INVALID_RESOURCE_ID /* Unused */,
|
||||
source, destination, executor, callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that a network route exists to deliver traffic to the specified
|
||||
* host via the specified network interface. An attempt to add a route that
|
||||
|
||||
@@ -181,6 +181,10 @@ interface IConnectivityManager
|
||||
void startNattKeepalive(in Network network, int intervalSeconds, in Messenger messenger,
|
||||
in IBinder binder, String srcAddr, int srcPort, String dstAddr);
|
||||
|
||||
void startNattKeepaliveWithFd(in Network network, in FileDescriptor fd, int resourceId,
|
||||
int intervalSeconds, in Messenger messenger, in IBinder binder, String srcAddr,
|
||||
String dstAddr);
|
||||
|
||||
void stopKeepalive(in Network network, int slot);
|
||||
|
||||
String getCaptivePortalServerUrl();
|
||||
|
||||
75
core/java/android/net/NattSocketKeepalive.java
Normal file
75
core/java/android/net/NattSocketKeepalive.java
Normal file
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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 android.net;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.os.Binder;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.net.InetAddress;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
/** @hide */
|
||||
public final class NattSocketKeepalive extends SocketKeepalive {
|
||||
/** The NAT-T destination port for IPsec */
|
||||
public static final int NATT_PORT = 4500;
|
||||
|
||||
@NonNull private final InetAddress mSource;
|
||||
@NonNull private final InetAddress mDestination;
|
||||
@NonNull private final FileDescriptor mFd;
|
||||
private final int mResourceId;
|
||||
|
||||
NattSocketKeepalive(@NonNull IConnectivityManager service,
|
||||
@NonNull Network network,
|
||||
@NonNull FileDescriptor fd,
|
||||
int resourceId,
|
||||
@NonNull InetAddress source,
|
||||
@NonNull InetAddress destination,
|
||||
@NonNull Executor executor,
|
||||
@NonNull Callback callback) {
|
||||
super(service, network, executor, callback);
|
||||
mSource = source;
|
||||
mDestination = destination;
|
||||
mFd = fd;
|
||||
mResourceId = resourceId;
|
||||
}
|
||||
|
||||
@Override
|
||||
void startImpl(int intervalSec) {
|
||||
try {
|
||||
mService.startNattKeepaliveWithFd(mNetwork, mFd, mResourceId, intervalSec, mMessenger,
|
||||
new Binder(), mSource.getHostAddress(), mDestination.getHostAddress());
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Error starting packet keepalive: ", e);
|
||||
stopLooper();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void stopImpl() {
|
||||
try {
|
||||
if (mSlot != null) {
|
||||
mService.stopKeepalive(mNetwork, mSlot);
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Error stopping packet keepalive: ", e);
|
||||
stopLooper();
|
||||
}
|
||||
}
|
||||
}
|
||||
224
core/java/android/net/SocketKeepalive.java
Normal file
224
core/java/android/net/SocketKeepalive.java
Normal file
@@ -0,0 +1,224 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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 android.net;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.IntRange;
|
||||
import android.annotation.NonNull;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.os.Messenger;
|
||||
import android.os.Process;
|
||||
import android.util.Log;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
/**
|
||||
* Allows applications to request that the system periodically send specific packets on their
|
||||
* behalf, using hardware offload to save battery power.
|
||||
*
|
||||
* To request that the system send keepalives, call one of the methods that return a
|
||||
* {@link SocketKeepalive} object, such as {@link ConnectivityManager#createSocketKeepalive},
|
||||
* passing in a non-null callback. If the {@link SocketKeepalive} is successfully
|
||||
* started, the callback's {@code onStarted} method will be called. If an error occurs,
|
||||
* {@code onError} will be called, specifying one of the {@code ERROR_*} constants in this
|
||||
* class.
|
||||
*
|
||||
* To stop an existing keepalive, call {@link SocketKeepalive#stop}. The system will call
|
||||
* {@link SocketKeepalive.Callback#onStopped} if the operation was successful or
|
||||
* {@link SocketKeepalive.Callback#onError} if an error occurred.
|
||||
*/
|
||||
public abstract class SocketKeepalive implements AutoCloseable {
|
||||
static final String TAG = "SocketKeepalive";
|
||||
|
||||
/** @hide */
|
||||
public static final int SUCCESS = 0;
|
||||
|
||||
/** @hide */
|
||||
public static final int NO_KEEPALIVE = -1;
|
||||
|
||||
/** @hide */
|
||||
public static final int DATA_RECEIVED = -2;
|
||||
|
||||
/** @hide */
|
||||
public static final int BINDER_DIED = -10;
|
||||
|
||||
/** The specified {@code Network} is not connected. */
|
||||
public static final int ERROR_INVALID_NETWORK = -20;
|
||||
/** The specified IP addresses are invalid. For example, the specified source IP address is
|
||||
* not configured on the specified {@code Network}. */
|
||||
public static final int ERROR_INVALID_IP_ADDRESS = -21;
|
||||
/** The requested port is invalid. */
|
||||
public static final int ERROR_INVALID_PORT = -22;
|
||||
/** The packet length is invalid (e.g., too long). */
|
||||
public static final int ERROR_INVALID_LENGTH = -23;
|
||||
/** The packet transmission interval is invalid (e.g., too short). */
|
||||
public static final int ERROR_INVALID_INTERVAL = -24;
|
||||
/** The target socket is invalid. */
|
||||
public static final int ERROR_INVALID_SOCKET = -25;
|
||||
/** The target socket is not idle. */
|
||||
public static final int ERROR_SOCKET_NOT_IDLE = -26;
|
||||
|
||||
/** The hardware does not support this request. */
|
||||
public static final int ERROR_HARDWARE_UNSUPPORTED = -30;
|
||||
/** The hardware returned an error. */
|
||||
public static final int ERROR_HARDWARE_ERROR = -31;
|
||||
|
||||
/** @hide */
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef(prefix = { "ERROR_" }, value = {
|
||||
ERROR_INVALID_NETWORK,
|
||||
ERROR_INVALID_IP_ADDRESS,
|
||||
ERROR_INVALID_PORT,
|
||||
ERROR_INVALID_LENGTH,
|
||||
ERROR_INVALID_INTERVAL,
|
||||
ERROR_INVALID_SOCKET,
|
||||
ERROR_SOCKET_NOT_IDLE
|
||||
})
|
||||
public @interface ErrorCode {}
|
||||
|
||||
/**
|
||||
* The minimum interval in seconds between keepalive packet transmissions.
|
||||
*
|
||||
* @hide
|
||||
**/
|
||||
public static final int MIN_INTERVAL_SEC = 10;
|
||||
|
||||
/**
|
||||
* The maximum interval in seconds between keepalive packet transmissions.
|
||||
*
|
||||
* @hide
|
||||
**/
|
||||
public static final int MAX_INTERVAL_SEC = 3600;
|
||||
|
||||
@NonNull final IConnectivityManager mService;
|
||||
@NonNull final Network mNetwork;
|
||||
@NonNull private final Executor mExecutor;
|
||||
@NonNull private final SocketKeepalive.Callback mCallback;
|
||||
@NonNull private final Looper mLooper;
|
||||
@NonNull final Messenger mMessenger;
|
||||
@NonNull Integer mSlot;
|
||||
|
||||
SocketKeepalive(@NonNull IConnectivityManager service, @NonNull Network network,
|
||||
@NonNull Executor executor, @NonNull Callback callback) {
|
||||
mService = service;
|
||||
mNetwork = network;
|
||||
mExecutor = executor;
|
||||
mCallback = callback;
|
||||
// TODO: 1. Use other thread modeling instead of create one thread for every instance to
|
||||
// reduce the memory cost.
|
||||
// 2. support restart.
|
||||
// 3. Fix race condition which caused by rapidly start and stop.
|
||||
HandlerThread thread = new HandlerThread(TAG, Process.THREAD_PRIORITY_BACKGROUND
|
||||
+ Process.THREAD_PRIORITY_LESS_FAVORABLE);
|
||||
thread.start();
|
||||
mLooper = thread.getLooper();
|
||||
mMessenger = new Messenger(new Handler(mLooper) {
|
||||
@Override
|
||||
public void handleMessage(Message message) {
|
||||
switch (message.what) {
|
||||
case NetworkAgent.EVENT_PACKET_KEEPALIVE:
|
||||
final int status = message.arg2;
|
||||
try {
|
||||
if (status == SUCCESS) {
|
||||
if (mSlot == null) {
|
||||
mSlot = message.arg1;
|
||||
mExecutor.execute(() -> mCallback.onStarted());
|
||||
} else {
|
||||
mSlot = null;
|
||||
stopLooper();
|
||||
mExecutor.execute(() -> mCallback.onStopped());
|
||||
}
|
||||
} else if (status == DATA_RECEIVED) {
|
||||
stopLooper();
|
||||
mExecutor.execute(() -> mCallback.onDataReceived());
|
||||
} else {
|
||||
stopLooper();
|
||||
mExecutor.execute(() -> mCallback.onError(status));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Exception in keepalive callback(" + status + ")", e);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Log.e(TAG, "Unhandled message " + Integer.toHexString(message.what));
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Request that keepalive be started with the given {@code intervalSec}. See
|
||||
* {@link SocketKeepalive}.
|
||||
*
|
||||
* @param intervalSec The target interval in seconds between keepalive packet transmissions.
|
||||
* The interval should be between 10 seconds and 3600 seconds, otherwise
|
||||
* {@link #ERROR_INVALID_INTERVAL} will be returned.
|
||||
*/
|
||||
public final void start(@IntRange(from = MIN_INTERVAL_SEC, to = MAX_INTERVAL_SEC)
|
||||
int intervalSec) {
|
||||
startImpl(intervalSec);
|
||||
}
|
||||
|
||||
abstract void startImpl(int intervalSec);
|
||||
|
||||
/** @hide */
|
||||
protected void stopLooper() {
|
||||
// TODO: remove this after changing thread modeling.
|
||||
mLooper.quit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests that keepalive be stopped. The application must wait for {@link Callback#onStopped}
|
||||
* before using the object. See {@link SocketKeepalive}.
|
||||
*/
|
||||
public final void stop() {
|
||||
stopImpl();
|
||||
}
|
||||
|
||||
abstract void stopImpl();
|
||||
|
||||
/**
|
||||
* Deactivate this {@link SocketKeepalive} and free allocated resources. The instance won't be
|
||||
* usable again if {@code close()} is called.
|
||||
*/
|
||||
@Override
|
||||
public final void close() {
|
||||
stop();
|
||||
stopLooper();
|
||||
}
|
||||
|
||||
/**
|
||||
* The callback which app can use to learn the status changes of {@link SocketKeepalive}. See
|
||||
* {@link SocketKeepalive}.
|
||||
*/
|
||||
public static class Callback {
|
||||
/** The requested keepalive was successfully started. */
|
||||
public void onStarted() {}
|
||||
/** The keepalive was successfully stopped. */
|
||||
public void onStopped() {}
|
||||
/** An error occurred. */
|
||||
public void onError(@ErrorCode int error) {}
|
||||
/** The keepalive on a TCP socket was stopped because the socket received data. */
|
||||
public void onDataReceived() {}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user