Merge "[KA02.5] Use binder thread and executor to invoke callback" am: f9ae70a41c am: c93f9c7f0e

am: 06ea4015bf

Change-Id: I881c1ab09187ab23facc03bb71cc38a7978e442c
This commit is contained in:
Junyu Lai
2019-03-15 01:19:55 -07:00
committed by android-build-merger
8 changed files with 235 additions and 226 deletions

View File

@@ -38,7 +38,6 @@ import android.os.Build;
import android.os.Build.VERSION_CODES; import android.os.Build.VERSION_CODES;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder; import android.os.IBinder;
import android.os.INetworkActivityListener; import android.os.INetworkActivityListener;
import android.os.INetworkManagementService; import android.os.INetworkManagementService;
@@ -75,6 +74,9 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.RejectedExecutionException;
/** /**
* Class that answers queries about the state of network connectivity. It also * Class that answers queries about the state of network connectivity. It also
@@ -1813,23 +1815,26 @@ public class ConnectivityManager {
public static final int MIN_INTERVAL = 10; public static final int MIN_INTERVAL = 10;
private final Network mNetwork; private final Network mNetwork;
private final PacketKeepaliveCallback mCallback; private final ISocketKeepaliveCallback mCallback;
private final Looper mLooper; private final ExecutorService mExecutor;
private final Messenger mMessenger;
private volatile Integer mSlot; private volatile Integer mSlot;
void stopLooper() {
mLooper.quit();
}
@UnsupportedAppUsage @UnsupportedAppUsage
public void stop() { public void stop() {
try { try {
mService.stopKeepalive(mNetwork, mSlot); mExecutor.execute(() -> {
} catch (RemoteException e) { try {
Log.e(TAG, "Error stopping packet keepalive: ", e); if (mSlot != null) {
stopLooper(); mService.stopKeepalive(mNetwork, mSlot);
}
} catch (RemoteException e) {
Log.e(TAG, "Error stopping packet keepalive: ", e);
throw e.rethrowFromSystemServer();
}
});
} catch (RejectedExecutionException e) {
// The internal executor has already stopped due to previous event.
} }
} }
@@ -1837,40 +1842,43 @@ public class ConnectivityManager {
Preconditions.checkNotNull(network, "network cannot be null"); Preconditions.checkNotNull(network, "network cannot be null");
Preconditions.checkNotNull(callback, "callback cannot be null"); Preconditions.checkNotNull(callback, "callback cannot be null");
mNetwork = network; mNetwork = network;
mCallback = callback; mExecutor = Executors.newSingleThreadExecutor();
HandlerThread thread = new HandlerThread(TAG); mCallback = new ISocketKeepaliveCallback.Stub() {
thread.start();
mLooper = thread.getLooper();
mMessenger = new Messenger(new Handler(mLooper) {
@Override @Override
public void handleMessage(Message message) { public void onStarted(int slot) {
switch (message.what) { Binder.withCleanCallingIdentity(() ->
case NetworkAgent.EVENT_SOCKET_KEEPALIVE: mExecutor.execute(() -> {
int error = message.arg2; mSlot = slot;
try { callback.onStarted();
if (error == SUCCESS) { }));
if (mSlot == null) {
mSlot = message.arg1;
mCallback.onStarted();
} else {
mSlot = null;
stopLooper();
mCallback.onStopped();
}
} else {
stopLooper();
mCallback.onError(error);
}
} catch (Exception e) {
Log.e(TAG, "Exception in keepalive callback(" + error + ")", e);
}
break;
default:
Log.e(TAG, "Unhandled message " + Integer.toHexString(message.what));
break;
}
} }
});
@Override
public void onStopped() {
Binder.withCleanCallingIdentity(() ->
mExecutor.execute(() -> {
mSlot = null;
callback.onStopped();
}));
mExecutor.shutdown();
}
@Override
public void onError(int error) {
Binder.withCleanCallingIdentity(() ->
mExecutor.execute(() -> {
mSlot = null;
callback.onError(error);
}));
mExecutor.shutdown();
}
@Override
public void onDataReceived() {
// PacketKeepalive is only used for Nat-T keepalive and as such does not invoke
// this callback when data is received.
}
};
} }
} }
@@ -1887,12 +1895,11 @@ public class ConnectivityManager {
InetAddress srcAddr, int srcPort, InetAddress dstAddr) { InetAddress srcAddr, int srcPort, InetAddress dstAddr) {
final PacketKeepalive k = new PacketKeepalive(network, callback); final PacketKeepalive k = new PacketKeepalive(network, callback);
try { try {
mService.startNattKeepalive(network, intervalSeconds, k.mMessenger, new Binder(), mService.startNattKeepalive(network, intervalSeconds, k.mCallback,
srcAddr.getHostAddress(), srcPort, dstAddr.getHostAddress()); srcAddr.getHostAddress(), srcPort, dstAddr.getHostAddress());
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(TAG, "Error starting packet keepalive: ", e); Log.e(TAG, "Error starting packet keepalive: ", e);
k.stopLooper(); throw e.rethrowFromSystemServer();
return null;
} }
return k; return k;
} }

View File

@@ -27,6 +27,7 @@ import android.net.NetworkMisc;
import android.net.NetworkQuotaInfo; import android.net.NetworkQuotaInfo;
import android.net.NetworkRequest; import android.net.NetworkRequest;
import android.net.NetworkState; import android.net.NetworkState;
import android.net.ISocketKeepaliveCallback;
import android.net.ProxyInfo; import android.net.ProxyInfo;
import android.os.Bundle; import android.os.Bundle;
import android.os.IBinder; import android.os.IBinder;
@@ -194,15 +195,15 @@ interface IConnectivityManager
void factoryReset(); void factoryReset();
void startNattKeepalive(in Network network, int intervalSeconds, in Messenger messenger, void startNattKeepalive(in Network network, int intervalSeconds,
in IBinder binder, String srcAddr, int srcPort, String dstAddr); in ISocketKeepaliveCallback cb, String srcAddr, int srcPort, String dstAddr);
void startNattKeepaliveWithFd(in Network network, in FileDescriptor fd, int resourceId, void startNattKeepaliveWithFd(in Network network, in FileDescriptor fd, int resourceId,
int intervalSeconds, in Messenger messenger, in IBinder binder, String srcAddr, int intervalSeconds, in ISocketKeepaliveCallback cb, String srcAddr,
String dstAddr); String dstAddr);
void startTcpKeepalive(in Network network, in FileDescriptor fd, int intervalSeconds, void startTcpKeepalive(in Network network, in FileDescriptor fd, int intervalSeconds,
in Messenger messenger, in IBinder binder); in ISocketKeepaliveCallback cb);
void stopKeepalive(in Network network, int slot); void stopKeepalive(in Network network, int slot);

View File

@@ -17,7 +17,6 @@
package android.net; package android.net;
import android.annotation.NonNull; import android.annotation.NonNull;
import android.os.Binder;
import android.os.RemoteException; import android.os.RemoteException;
import android.util.Log; import android.util.Log;
@@ -52,24 +51,30 @@ public final class NattSocketKeepalive extends SocketKeepalive {
@Override @Override
void startImpl(int intervalSec) { void startImpl(int intervalSec) {
try { mExecutor.execute(() -> {
mService.startNattKeepaliveWithFd(mNetwork, mFd, mResourceId, intervalSec, mMessenger, try {
new Binder(), mSource.getHostAddress(), mDestination.getHostAddress()); mService.startNattKeepaliveWithFd(mNetwork, mFd, mResourceId, intervalSec,
} catch (RemoteException e) { mCallback,
Log.e(TAG, "Error starting packet keepalive: ", e); mSource.getHostAddress(), mDestination.getHostAddress());
stopLooper(); } catch (RemoteException e) {
} Log.e(TAG, "Error starting socket keepalive: ", e);
throw e.rethrowFromSystemServer();
}
});
} }
@Override @Override
void stopImpl() { void stopImpl() {
try { mExecutor.execute(() -> {
if (mSlot != null) { try {
mService.stopKeepalive(mNetwork, mSlot); if (mSlot != null) {
mService.stopKeepalive(mNetwork, mSlot);
}
} catch (RemoteException e) {
Log.e(TAG, "Error stopping socket keepalive: ", e);
throw e.rethrowFromSystemServer();
} }
} catch (RemoteException e) { });
Log.e(TAG, "Error stopping packet keepalive: ", e);
stopLooper();
}
} }
} }

View File

@@ -20,13 +20,8 @@ import android.annotation.IntDef;
import android.annotation.IntRange; import android.annotation.IntRange;
import android.annotation.NonNull; import android.annotation.NonNull;
import android.annotation.Nullable; import android.annotation.Nullable;
import android.os.Handler; import android.os.Binder;
import android.os.HandlerThread; import android.os.RemoteException;
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.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
@@ -152,10 +147,9 @@ public abstract class SocketKeepalive implements AutoCloseable {
@NonNull final IConnectivityManager mService; @NonNull final IConnectivityManager mService;
@NonNull final Network mNetwork; @NonNull final Network mNetwork;
@NonNull private final Executor mExecutor; @NonNull final Executor mExecutor;
@NonNull private final SocketKeepalive.Callback mCallback; @NonNull final ISocketKeepaliveCallback mCallback;
@NonNull private final Looper mLooper; // TODO: remove slot since mCallback could be used to identify which keepalive to stop.
@NonNull final Messenger mMessenger;
@Nullable Integer mSlot; @Nullable Integer mSlot;
SocketKeepalive(@NonNull IConnectivityManager service, @NonNull Network network, SocketKeepalive(@NonNull IConnectivityManager service, @NonNull Network network,
@@ -163,53 +157,53 @@ public abstract class SocketKeepalive implements AutoCloseable {
mService = service; mService = service;
mNetwork = network; mNetwork = network;
mExecutor = executor; mExecutor = executor;
mCallback = callback; mCallback = new ISocketKeepaliveCallback.Stub() {
// 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 @Override
public void handleMessage(Message message) { public void onStarted(int slot) {
switch (message.what) { Binder.withCleanCallingIdentity(() ->
case NetworkAgent.EVENT_SOCKET_KEEPALIVE: mExecutor.execute(() -> {
final int status = message.arg2; mSlot = slot;
try { callback.onStarted();
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;
}
} }
});
@Override
public void onStopped() {
Binder.withCleanCallingIdentity(() ->
executor.execute(() -> {
mSlot = null;
callback.onStopped();
}));
}
@Override
public void onError(int error) {
Binder.withCleanCallingIdentity(() ->
executor.execute(() -> {
mSlot = null;
callback.onError(error);
}));
}
@Override
public void onDataReceived() {
Binder.withCleanCallingIdentity(() ->
executor.execute(() -> {
mSlot = null;
callback.onDataReceived();
}));
}
};
} }
/** /**
* Request that keepalive be started with the given {@code intervalSec}. See * Request that keepalive be started with the given {@code intervalSec}. See
* {@link SocketKeepalive}. * {@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}.
* *
* @param intervalSec The target interval in seconds between keepalive packet transmissions. * @param intervalSec The target interval in seconds between keepalive packet transmissions.
* The interval should be between 10 seconds and 3600 seconds, otherwise * The interval should be between 10 seconds and 3600 seconds, otherwise
@@ -222,12 +216,6 @@ public abstract class SocketKeepalive implements AutoCloseable {
abstract void startImpl(int 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} * Requests that keepalive be stopped. The application must wait for {@link Callback#onStopped}
* before using the object. See {@link SocketKeepalive}. * before using the object. See {@link SocketKeepalive}.
@@ -245,7 +233,6 @@ public abstract class SocketKeepalive implements AutoCloseable {
@Override @Override
public final void close() { public final void close() {
stop(); stop();
stopLooper();
} }
/** /**
@@ -259,7 +246,8 @@ public abstract class SocketKeepalive implements AutoCloseable {
public void onStopped() {} public void onStopped() {}
/** An error occurred. */ /** An error occurred. */
public void onError(@ErrorCode int error) {} public void onError(@ErrorCode int error) {}
/** The keepalive on a TCP socket was stopped because the socket received data. */ /** The keepalive on a TCP socket was stopped because the socket received data. This is
* never called for UDP sockets. */
public void onDataReceived() {} public void onDataReceived() {}
} }
} }

View File

@@ -17,7 +17,6 @@
package android.net; package android.net;
import android.annotation.NonNull; import android.annotation.NonNull;
import android.os.Binder;
import android.os.RemoteException; import android.os.RemoteException;
import android.util.Log; import android.util.Log;
@@ -56,24 +55,28 @@ final class TcpSocketKeepalive extends SocketKeepalive {
*/ */
@Override @Override
void startImpl(int intervalSec) { void startImpl(int intervalSec) {
try { mExecutor.execute(() -> {
final FileDescriptor fd = mSocket.getFileDescriptor$(); try {
mService.startTcpKeepalive(mNetwork, fd, intervalSec, mMessenger, new Binder()); final FileDescriptor fd = mSocket.getFileDescriptor$();
} catch (RemoteException e) { mService.startTcpKeepalive(mNetwork, fd, intervalSec, mCallback);
Log.e(TAG, "Error starting packet keepalive: ", e); } catch (RemoteException e) {
stopLooper(); Log.e(TAG, "Error starting packet keepalive: ", e);
} throw e.rethrowFromSystemServer();
}
});
} }
@Override @Override
void stopImpl() { void stopImpl() {
try { mExecutor.execute(() -> {
if (mSlot != null) { try {
mService.stopKeepalive(mNetwork, mSlot); if (mSlot != null) {
mService.stopKeepalive(mNetwork, mSlot);
}
} catch (RemoteException e) {
Log.e(TAG, "Error stopping packet keepalive: ", e);
throw e.rethrowFromSystemServer();
} }
} catch (RemoteException e) { });
Log.e(TAG, "Error stopping packet keepalive: ", e);
stopLooper();
}
} }
} }

View File

@@ -73,6 +73,7 @@ import android.net.INetworkMonitorCallbacks;
import android.net.INetworkPolicyListener; import android.net.INetworkPolicyListener;
import android.net.INetworkPolicyManager; import android.net.INetworkPolicyManager;
import android.net.INetworkStatsService; import android.net.INetworkStatsService;
import android.net.ISocketKeepaliveCallback;
import android.net.ITetheringEventCallback; import android.net.ITetheringEventCallback;
import android.net.InetAddresses; import android.net.InetAddresses;
import android.net.IpPrefix; import android.net.IpPrefix;
@@ -6699,32 +6700,32 @@ public class ConnectivityService extends IConnectivityManager.Stub
} }
@Override @Override
public void startNattKeepalive(Network network, int intervalSeconds, Messenger messenger, public void startNattKeepalive(Network network, int intervalSeconds,
IBinder binder, String srcAddr, int srcPort, String dstAddr) { ISocketKeepaliveCallback cb, String srcAddr, int srcPort, String dstAddr) {
enforceKeepalivePermission(); enforceKeepalivePermission();
mKeepaliveTracker.startNattKeepalive( mKeepaliveTracker.startNattKeepalive(
getNetworkAgentInfoForNetwork(network), getNetworkAgentInfoForNetwork(network),
intervalSeconds, messenger, binder, intervalSeconds, cb,
srcAddr, srcPort, dstAddr, NattSocketKeepalive.NATT_PORT); srcAddr, srcPort, dstAddr, NattSocketKeepalive.NATT_PORT);
} }
@Override @Override
public void startNattKeepaliveWithFd(Network network, FileDescriptor fd, int resourceId, public void startNattKeepaliveWithFd(Network network, FileDescriptor fd, int resourceId,
int intervalSeconds, Messenger messenger, IBinder binder, String srcAddr, int intervalSeconds, ISocketKeepaliveCallback cb, String srcAddr,
String dstAddr) { String dstAddr) {
enforceKeepalivePermission(); enforceKeepalivePermission();
mKeepaliveTracker.startNattKeepalive( mKeepaliveTracker.startNattKeepalive(
getNetworkAgentInfoForNetwork(network), fd, resourceId, getNetworkAgentInfoForNetwork(network), fd, resourceId,
intervalSeconds, messenger, binder, intervalSeconds, cb,
srcAddr, dstAddr, NattSocketKeepalive.NATT_PORT); srcAddr, dstAddr, NattSocketKeepalive.NATT_PORT);
} }
@Override @Override
public void startTcpKeepalive(Network network, FileDescriptor fd, int intervalSeconds, public void startTcpKeepalive(Network network, FileDescriptor fd, int intervalSeconds,
Messenger messenger, IBinder binder) { ISocketKeepaliveCallback cb) {
enforceKeepalivePermission(); enforceKeepalivePermission();
mKeepaliveTracker.startTcpKeepalive( mKeepaliveTracker.startTcpKeepalive(
getNetworkAgentInfoForNetwork(network), fd, intervalSeconds, messenger, binder); getNetworkAgentInfoForNetwork(network), fd, intervalSeconds, cb);
} }
@Override @Override

View File

@@ -21,8 +21,8 @@ import static android.net.NetworkAgent.CMD_ADD_KEEPALIVE_PACKET_FILTER;
import static android.net.NetworkAgent.CMD_REMOVE_KEEPALIVE_PACKET_FILTER; import static android.net.NetworkAgent.CMD_REMOVE_KEEPALIVE_PACKET_FILTER;
import static android.net.NetworkAgent.CMD_START_SOCKET_KEEPALIVE; import static android.net.NetworkAgent.CMD_START_SOCKET_KEEPALIVE;
import static android.net.NetworkAgent.CMD_STOP_SOCKET_KEEPALIVE; import static android.net.NetworkAgent.CMD_STOP_SOCKET_KEEPALIVE;
import static android.net.NetworkAgent.EVENT_SOCKET_KEEPALIVE;
import static android.net.SocketKeepalive.BINDER_DIED; import static android.net.SocketKeepalive.BINDER_DIED;
import static android.net.SocketKeepalive.DATA_RECEIVED;
import static android.net.SocketKeepalive.ERROR_INVALID_INTERVAL; import static android.net.SocketKeepalive.ERROR_INVALID_INTERVAL;
import static android.net.SocketKeepalive.ERROR_INVALID_IP_ADDRESS; import static android.net.SocketKeepalive.ERROR_INVALID_IP_ADDRESS;
import static android.net.SocketKeepalive.ERROR_INVALID_NETWORK; import static android.net.SocketKeepalive.ERROR_INVALID_NETWORK;
@@ -34,6 +34,7 @@ import static android.net.SocketKeepalive.SUCCESS;
import android.annotation.NonNull; import android.annotation.NonNull;
import android.annotation.Nullable; import android.annotation.Nullable;
import android.net.ISocketKeepaliveCallback;
import android.net.KeepalivePacketData; import android.net.KeepalivePacketData;
import android.net.NattKeepalivePacketData; import android.net.NattKeepalivePacketData;
import android.net.NetworkAgent; import android.net.NetworkAgent;
@@ -47,7 +48,6 @@ import android.os.Binder;
import android.os.Handler; import android.os.Handler;
import android.os.IBinder; import android.os.IBinder;
import android.os.Message; import android.os.Message;
import android.os.Messenger;
import android.os.Process; import android.os.Process;
import android.os.RemoteException; import android.os.RemoteException;
import android.system.ErrnoException; import android.system.ErrnoException;
@@ -99,8 +99,7 @@ public class KeepaliveTracker {
*/ */
class KeepaliveInfo implements IBinder.DeathRecipient { class KeepaliveInfo implements IBinder.DeathRecipient {
// Bookkeeping data. // Bookkeeping data.
private final Messenger mMessenger; private final ISocketKeepaliveCallback mCallback;
private final IBinder mBinder;
private final int mUid; private final int mUid;
private final int mPid; private final int mPid;
private final NetworkAgentInfo mNai; private final NetworkAgentInfo mNai;
@@ -124,15 +123,13 @@ public class KeepaliveTracker {
private static final int STARTED = 3; private static final int STARTED = 3;
private int mStartedState = NOT_STARTED; private int mStartedState = NOT_STARTED;
KeepaliveInfo(@NonNull Messenger messenger, KeepaliveInfo(@NonNull ISocketKeepaliveCallback callback,
@NonNull IBinder binder,
@NonNull NetworkAgentInfo nai, @NonNull NetworkAgentInfo nai,
@NonNull KeepalivePacketData packet, @NonNull KeepalivePacketData packet,
int interval, int interval,
int type, int type,
@NonNull FileDescriptor fd) { @NonNull FileDescriptor fd) {
mMessenger = messenger; mCallback = callback;
mBinder = binder;
mPid = Binder.getCallingPid(); mPid = Binder.getCallingPid();
mUid = Binder.getCallingUid(); mUid = Binder.getCallingUid();
@@ -143,7 +140,7 @@ public class KeepaliveTracker {
mFd = fd; mFd = fd;
try { try {
mBinder.linkToDeath(this, 0); mCallback.asBinder().linkToDeath(this, 0);
} catch (RemoteException e) { } catch (RemoteException e) {
binderDied(); binderDied();
} }
@@ -176,22 +173,14 @@ public class KeepaliveTracker {
+ " ]"; + " ]";
} }
/** Sends a message back to the application via its SocketKeepalive.Callback. */
void notifyMessenger(int slot, int err) {
if (DBG) {
Log.d(TAG, "notify keepalive " + mSlot + " on " + mNai.network + " for " + err);
}
KeepaliveTracker.this.notifyMessenger(mMessenger, slot, err);
}
/** Called when the application process is killed. */ /** Called when the application process is killed. */
public void binderDied() { public void binderDied() {
stop(BINDER_DIED); stop(BINDER_DIED);
} }
void unlinkDeathRecipient() { void unlinkDeathRecipient() {
if (mBinder != null) { if (mCallback != null) {
mBinder.unlinkToDeath(this, 0); mCallback.asBinder().unlinkToDeath(this, 0);
} }
} }
@@ -283,9 +272,23 @@ public class KeepaliveTracker {
Log.wtf(TAG, "Stopping keepalive with unknown type: " + mType); Log.wtf(TAG, "Stopping keepalive with unknown type: " + mType);
} }
} }
// TODO: at the moment we unconditionally return failure here. In cases where the
// NetworkAgent is alive, should we ask it to reply, so it can return failure? if (reason == SUCCESS) {
notifyMessenger(mSlot, reason); try {
mCallback.onStopped();
} catch (RemoteException e) {
Log.w(TAG, "Discarded onStop callback: " + reason);
}
} else if (reason == DATA_RECEIVED) {
try {
mCallback.onDataReceived();
} catch (RemoteException e) {
Log.w(TAG, "Discarded onDataReceived callback: " + reason);
}
} else {
notifyErrorCallback(mCallback, reason);
}
unlinkDeathRecipient(); unlinkDeathRecipient();
} }
@@ -294,16 +297,12 @@ public class KeepaliveTracker {
} }
} }
void notifyMessenger(Messenger messenger, int slot, int err) { void notifyErrorCallback(ISocketKeepaliveCallback cb, int error) {
Message message = Message.obtain(); if (DBG) Log.w(TAG, "Sending onError(" + error + ") callback");
message.what = EVENT_SOCKET_KEEPALIVE;
message.arg1 = slot;
message.arg2 = err;
message.obj = null;
try { try {
messenger.send(message); cb.onError(error);
} catch (RemoteException e) { } catch (RemoteException e) {
// Process died? Log.w(TAG, "Discarded onError(" + error + ") callback");
} }
} }
@@ -414,7 +413,11 @@ public class KeepaliveTracker {
// Keepalive successfully started. // Keepalive successfully started.
if (DBG) Log.d(TAG, "Started keepalive " + slot + " on " + nai.name()); if (DBG) Log.d(TAG, "Started keepalive " + slot + " on " + nai.name());
ki.mStartedState = KeepaliveInfo.STARTED; ki.mStartedState = KeepaliveInfo.STARTED;
ki.notifyMessenger(slot, reason); try {
ki.mCallback.onStarted(slot);
} catch (RemoteException e) {
Log.w(TAG, "Discarded onStarted(" + slot + ") callback");
}
} else { } else {
// Keepalive successfully stopped, or error. // Keepalive successfully stopped, or error.
ki.mStartedState = KeepaliveInfo.NOT_STARTED; ki.mStartedState = KeepaliveInfo.NOT_STARTED;
@@ -436,14 +439,13 @@ public class KeepaliveTracker {
**/ **/
public void startNattKeepalive(@Nullable NetworkAgentInfo nai, public void startNattKeepalive(@Nullable NetworkAgentInfo nai,
int intervalSeconds, int intervalSeconds,
@NonNull Messenger messenger, @NonNull ISocketKeepaliveCallback cb,
@NonNull IBinder binder,
@NonNull String srcAddrString, @NonNull String srcAddrString,
int srcPort, int srcPort,
@NonNull String dstAddrString, @NonNull String dstAddrString,
int dstPort) { int dstPort) {
if (nai == null) { if (nai == null) {
notifyMessenger(messenger, NO_KEEPALIVE, ERROR_INVALID_NETWORK); notifyErrorCallback(cb, ERROR_INVALID_NETWORK);
return; return;
} }
@@ -452,7 +454,7 @@ public class KeepaliveTracker {
srcAddress = NetworkUtils.numericToInetAddress(srcAddrString); srcAddress = NetworkUtils.numericToInetAddress(srcAddrString);
dstAddress = NetworkUtils.numericToInetAddress(dstAddrString); dstAddress = NetworkUtils.numericToInetAddress(dstAddrString);
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
notifyMessenger(messenger, NO_KEEPALIVE, ERROR_INVALID_IP_ADDRESS); notifyErrorCallback(cb, ERROR_INVALID_IP_ADDRESS);
return; return;
} }
@@ -461,11 +463,12 @@ public class KeepaliveTracker {
packet = NattKeepalivePacketData.nattKeepalivePacket( packet = NattKeepalivePacketData.nattKeepalivePacket(
srcAddress, srcPort, dstAddress, NATT_PORT); srcAddress, srcPort, dstAddress, NATT_PORT);
} catch (InvalidPacketException e) { } catch (InvalidPacketException e) {
notifyMessenger(messenger, NO_KEEPALIVE, e.error); notifyErrorCallback(cb, e.error);
return; return;
} }
KeepaliveInfo ki = new KeepaliveInfo(messenger, binder, nai, packet, intervalSeconds, KeepaliveInfo ki = new KeepaliveInfo(cb, nai, packet, intervalSeconds,
KeepaliveInfo.TYPE_NATT, null); KeepaliveInfo.TYPE_NATT, null);
Log.d(TAG, "Created keepalive: " + ki.toString());
mConnectivityServiceHandler.obtainMessage( mConnectivityServiceHandler.obtainMessage(
NetworkAgent.CMD_START_SOCKET_KEEPALIVE, ki).sendToTarget(); NetworkAgent.CMD_START_SOCKET_KEEPALIVE, ki).sendToTarget();
} }
@@ -483,10 +486,9 @@ public class KeepaliveTracker {
public void startTcpKeepalive(@Nullable NetworkAgentInfo nai, public void startTcpKeepalive(@Nullable NetworkAgentInfo nai,
@NonNull FileDescriptor fd, @NonNull FileDescriptor fd,
int intervalSeconds, int intervalSeconds,
@NonNull Messenger messenger, @NonNull ISocketKeepaliveCallback cb) {
@NonNull IBinder binder) {
if (nai == null) { if (nai == null) {
notifyMessenger(messenger, NO_KEEPALIVE, ERROR_INVALID_NETWORK); notifyErrorCallback(cb, ERROR_INVALID_NETWORK);
return; return;
} }
@@ -500,10 +502,10 @@ public class KeepaliveTracker {
} catch (ErrnoException e1) { } catch (ErrnoException e1) {
Log.e(TAG, "Couldn't move fd out of repair mode after failure to start keepalive"); Log.e(TAG, "Couldn't move fd out of repair mode after failure to start keepalive");
} }
notifyMessenger(messenger, NO_KEEPALIVE, e.error); notifyErrorCallback(cb, e.error);
return; return;
} }
KeepaliveInfo ki = new KeepaliveInfo(messenger, binder, nai, packet, intervalSeconds, KeepaliveInfo ki = new KeepaliveInfo(cb, nai, packet, intervalSeconds,
KeepaliveInfo.TYPE_TCP, fd); KeepaliveInfo.TYPE_TCP, fd);
Log.d(TAG, "Created keepalive: " + ki.toString()); Log.d(TAG, "Created keepalive: " + ki.toString());
mConnectivityServiceHandler.obtainMessage(CMD_START_SOCKET_KEEPALIVE, ki).sendToTarget(); mConnectivityServiceHandler.obtainMessage(CMD_START_SOCKET_KEEPALIVE, ki).sendToTarget();
@@ -520,14 +522,13 @@ public class KeepaliveTracker {
@Nullable FileDescriptor fd, @Nullable FileDescriptor fd,
int resourceId, int resourceId,
int intervalSeconds, int intervalSeconds,
@NonNull Messenger messenger, @NonNull ISocketKeepaliveCallback cb,
@NonNull IBinder binder,
@NonNull String srcAddrString, @NonNull String srcAddrString,
@NonNull String dstAddrString, @NonNull String dstAddrString,
int dstPort) { int dstPort) {
// Ensure that the socket is created by IpSecService. // Ensure that the socket is created by IpSecService.
if (!isNattKeepaliveSocketValid(fd, resourceId)) { if (!isNattKeepaliveSocketValid(fd, resourceId)) {
notifyMessenger(messenger, NO_KEEPALIVE, ERROR_INVALID_SOCKET); notifyErrorCallback(cb, ERROR_INVALID_SOCKET);
} }
// Get src port to adopt old API. // Get src port to adopt old API.
@@ -536,11 +537,11 @@ public class KeepaliveTracker {
final SocketAddress srcSockAddr = Os.getsockname(fd); final SocketAddress srcSockAddr = Os.getsockname(fd);
srcPort = ((InetSocketAddress) srcSockAddr).getPort(); srcPort = ((InetSocketAddress) srcSockAddr).getPort();
} catch (ErrnoException e) { } catch (ErrnoException e) {
notifyMessenger(messenger, NO_KEEPALIVE, ERROR_INVALID_SOCKET); notifyErrorCallback(cb, ERROR_INVALID_SOCKET);
} }
// Forward request to old API. // Forward request to old API.
startNattKeepalive(nai, intervalSeconds, messenger, binder, srcAddrString, srcPort, startNattKeepalive(nai, intervalSeconds, cb, srcAddrString, srcPort,
dstAddrString, dstPort); dstAddrString, dstPort);
} }

View File

@@ -64,6 +64,7 @@ import static android.net.shared.NetworkParcelableUtil.fromStableParcelable;
import static com.android.internal.util.TestUtils.waitForIdleHandler; import static com.android.internal.util.TestUtils.waitForIdleHandler;
import static com.android.internal.util.TestUtils.waitForIdleLooper; import static com.android.internal.util.TestUtils.waitForIdleLooper;
import static com.android.internal.util.TestUtils.waitForIdleSerialExecutor;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
@@ -88,6 +89,7 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import android.annotation.NonNull;
import android.app.NotificationManager; import android.app.NotificationManager;
import android.app.PendingIntent; import android.app.PendingIntent;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
@@ -3762,7 +3764,7 @@ public class ConnectivityServiceTest {
} }
} }
private LinkedBlockingQueue<CallbackValue> mCallbacks = new LinkedBlockingQueue<>(); private final LinkedBlockingQueue<CallbackValue> mCallbacks = new LinkedBlockingQueue<>();
@Override @Override
public void onStarted() { public void onStarted() {
@@ -3837,6 +3839,11 @@ public class ConnectivityServiceTest {
} }
private LinkedBlockingQueue<CallbackValue> mCallbacks = new LinkedBlockingQueue<>(); private LinkedBlockingQueue<CallbackValue> mCallbacks = new LinkedBlockingQueue<>();
private final Executor mExecutor;
TestSocketKeepaliveCallback(@NonNull Executor executor) {
mExecutor = executor;
}
@Override @Override
public void onStarted() { public void onStarted() {
@@ -3874,6 +3881,12 @@ public class ConnectivityServiceTest {
public void expectError(int error) { public void expectError(int error) {
expectCallback(new CallbackValue(CallbackType.ON_ERROR, error)); expectCallback(new CallbackValue(CallbackType.ON_ERROR, error));
} }
public void assertNoCallback() {
waitForIdleSerialExecutor(mExecutor, TIMEOUT_MS);
CallbackValue cv = mCallbacks.peek();
assertNull("Unexpected callback: " + cv, cv);
}
} }
private Network connectKeepaliveNetwork(LinkProperties lp) { private Network connectKeepaliveNetwork(LinkProperties lp) {
@@ -3980,19 +3993,6 @@ public class ConnectivityServiceTest {
myNet = connectKeepaliveNetwork(lp); myNet = connectKeepaliveNetwork(lp);
mWiFiNetworkAgent.setStartKeepaliveError(PacketKeepalive.SUCCESS); mWiFiNetworkAgent.setStartKeepaliveError(PacketKeepalive.SUCCESS);
// Check things work as expected when the keepalive is stopped and the network disconnects.
ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv4, 12345, dstIPv4);
callback.expectStarted();
ka.stop();
mWiFiNetworkAgent.disconnect();
waitFor(mWiFiNetworkAgent.getDisconnectedCV());
waitForIdle();
callback.expectStopped();
// Reconnect.
myNet = connectKeepaliveNetwork(lp);
mWiFiNetworkAgent.setStartKeepaliveError(PacketKeepalive.SUCCESS);
// Check that keepalive slots start from 1 and increment. The first one gets slot 1. // Check that keepalive slots start from 1 and increment. The first one gets slot 1.
mWiFiNetworkAgent.setExpectedKeepaliveSlot(1); mWiFiNetworkAgent.setExpectedKeepaliveSlot(1);
ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv4, 12345, dstIPv4); ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv4, 12345, dstIPv4);
@@ -4068,7 +4068,7 @@ public class ConnectivityServiceTest {
Network notMyNet = new Network(61234); Network notMyNet = new Network(61234);
Network myNet = connectKeepaliveNetwork(lp); Network myNet = connectKeepaliveNetwork(lp);
TestSocketKeepaliveCallback callback = new TestSocketKeepaliveCallback(); TestSocketKeepaliveCallback callback = new TestSocketKeepaliveCallback(executor);
SocketKeepalive ka; SocketKeepalive ka;
// Attempt to start keepalives with invalid parameters and check for errors. // Attempt to start keepalives with invalid parameters and check for errors.
@@ -4111,6 +4111,22 @@ public class ConnectivityServiceTest {
ka.stop(); ka.stop();
callback.expectStopped(); callback.expectStopped();
// Check that keepalive could be restarted.
ka.start(validKaInterval);
callback.expectStarted();
ka.stop();
callback.expectStopped();
// Check that keepalive can be restarted without waiting for callback.
ka.start(validKaInterval);
callback.expectStarted();
ka.stop();
ka.start(validKaInterval);
callback.expectStopped();
callback.expectStarted();
ka.stop();
callback.expectStopped();
// Check that deleting the IP address stops the keepalive. // Check that deleting the IP address stops the keepalive.
LinkProperties bogusLp = new LinkProperties(lp); LinkProperties bogusLp = new LinkProperties(lp);
ka = mCm.createSocketKeepalive(myNet, testSocket, myIPv4, dstIPv4, executor, callback); ka = mCm.createSocketKeepalive(myNet, testSocket, myIPv4, dstIPv4, executor, callback);
@@ -4135,20 +4151,7 @@ public class ConnectivityServiceTest {
final Network myNetAlias = myNet; final Network myNetAlias = myNet;
assertNull(mCm.getNetworkCapabilities(myNetAlias)); assertNull(mCm.getNetworkCapabilities(myNetAlias));
ka.stop(); ka.stop();
callback.assertNoCallback();
// Reconnect.
myNet = connectKeepaliveNetwork(lp);
mWiFiNetworkAgent.setStartKeepaliveError(SocketKeepalive.SUCCESS);
// Check things work as expected when the keepalive is stopped and the network disconnects.
ka = mCm.createSocketKeepalive(myNet, testSocket, myIPv4, dstIPv4, executor, callback);
ka.start(validKaInterval);
callback.expectStarted();
ka.stop();
mWiFiNetworkAgent.disconnect();
waitFor(mWiFiNetworkAgent.getDisconnectedCV());
waitForIdle();
callback.expectStopped();
// Reconnect. // Reconnect.
myNet = connectKeepaliveNetwork(lp); myNet = connectKeepaliveNetwork(lp);
@@ -4163,7 +4166,7 @@ public class ConnectivityServiceTest {
// The second one gets slot 2. // The second one gets slot 2.
mWiFiNetworkAgent.setExpectedKeepaliveSlot(2); mWiFiNetworkAgent.setExpectedKeepaliveSlot(2);
final UdpEncapsulationSocket testSocket2 = mIpSec.openUdpEncapsulationSocket(6789); final UdpEncapsulationSocket testSocket2 = mIpSec.openUdpEncapsulationSocket(6789);
TestSocketKeepaliveCallback callback2 = new TestSocketKeepaliveCallback(); TestSocketKeepaliveCallback callback2 = new TestSocketKeepaliveCallback(executor);
SocketKeepalive ka2 = SocketKeepalive ka2 =
mCm.createSocketKeepalive(myNet, testSocket2, myIPv4, dstIPv4, executor, callback2); mCm.createSocketKeepalive(myNet, testSocket2, myIPv4, dstIPv4, executor, callback2);
ka2.start(validKaInterval); ka2.start(validKaInterval);
@@ -4216,7 +4219,7 @@ public class ConnectivityServiceTest {
final Socket testSocketV4 = new Socket(); final Socket testSocketV4 = new Socket();
final Socket testSocketV6 = new Socket(); final Socket testSocketV6 = new Socket();
TestSocketKeepaliveCallback callback = new TestSocketKeepaliveCallback(); TestSocketKeepaliveCallback callback = new TestSocketKeepaliveCallback(executor);
SocketKeepalive ka; SocketKeepalive ka;
// Attempt to start Tcp keepalives with invalid parameters and check for errors. // Attempt to start Tcp keepalives with invalid parameters and check for errors.