Merge changes I8fcaa1f0,I8925fbe4,I78394645,Iadf9f060 am: 48e61a4520
Original change: https://android-review.googlesource.com/c/platform/packages/modules/Connectivity/+/2597608 Change-Id: I1be995e227c715ec140a4ba9e5d954da491640c7 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -18,6 +18,7 @@ package com.android.server.connectivity;
|
|||||||
|
|
||||||
import static android.net.SocketKeepalive.ERROR_INVALID_SOCKET;
|
import static android.net.SocketKeepalive.ERROR_INVALID_SOCKET;
|
||||||
import static android.net.SocketKeepalive.MIN_INTERVAL_SEC;
|
import static android.net.SocketKeepalive.MIN_INTERVAL_SEC;
|
||||||
|
import static android.net.SocketKeepalive.SUCCESS;
|
||||||
import static android.net.SocketKeepalive.SUCCESS_PAUSED;
|
import static android.net.SocketKeepalive.SUCCESS_PAUSED;
|
||||||
import static android.provider.DeviceConfig.NAMESPACE_TETHERING;
|
import static android.provider.DeviceConfig.NAMESPACE_TETHERING;
|
||||||
import static android.system.OsConstants.AF_INET;
|
import static android.system.OsConstants.AF_INET;
|
||||||
@@ -52,6 +53,7 @@ import android.system.OsConstants;
|
|||||||
import android.system.StructTimeval;
|
import android.system.StructTimeval;
|
||||||
import android.util.LocalLog;
|
import android.util.LocalLog;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import android.util.Pair;
|
||||||
import android.util.SparseArray;
|
import android.util.SparseArray;
|
||||||
|
|
||||||
import com.android.internal.annotations.VisibleForTesting;
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
@@ -381,7 +383,11 @@ public class AutomaticOnOffKeepaliveTracker {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
autoKi.mAutomaticOnOffState = STATE_ENABLED;
|
autoKi.mAutomaticOnOffState = STATE_ENABLED;
|
||||||
handleResumeKeepalive(newKi);
|
final int error = handleResumeKeepalive(newKi);
|
||||||
|
if (error != SUCCESS) {
|
||||||
|
// Failed to start the keepalive
|
||||||
|
cleanupAutoOnOffKeepalive(autoKi);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -402,7 +408,20 @@ public class AutomaticOnOffKeepaliveTracker {
|
|||||||
* Forward to KeepaliveTracker.
|
* Forward to KeepaliveTracker.
|
||||||
*/
|
*/
|
||||||
public void handleEventSocketKeepalive(@NonNull NetworkAgentInfo nai, int slot, int reason) {
|
public void handleEventSocketKeepalive(@NonNull NetworkAgentInfo nai, int slot, int reason) {
|
||||||
mKeepaliveTracker.handleEventSocketKeepalive(nai, slot, reason);
|
if (mKeepaliveTracker.handleEventSocketKeepalive(nai, slot, reason)) return;
|
||||||
|
|
||||||
|
// The keepalive was stopped and so the autoKi should be cleaned up.
|
||||||
|
final AutomaticOnOffKeepalive autoKi =
|
||||||
|
CollectionUtils.findFirst(
|
||||||
|
mAutomaticOnOffKeepalives, it -> it.match(nai.network(), slot));
|
||||||
|
if (autoKi == null) {
|
||||||
|
// This may occur when the autoKi gets cleaned up elsewhere (i.e
|
||||||
|
// handleCheckKeepalivesStillValid) while waiting for the network agent to
|
||||||
|
// start the keepalive and the network agent returns an error event.
|
||||||
|
Log.e(TAG, "Attempt cleanup on unknown network, slot");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
cleanupAutoOnOffKeepalive(autoKi);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -414,6 +433,9 @@ public class AutomaticOnOffKeepaliveTracker {
|
|||||||
final List<AutomaticOnOffKeepalive> matches =
|
final List<AutomaticOnOffKeepalive> matches =
|
||||||
CollectionUtils.filter(mAutomaticOnOffKeepalives, it -> it.mKi.getNai() == nai);
|
CollectionUtils.filter(mAutomaticOnOffKeepalives, it -> it.mKi.getNai() == nai);
|
||||||
for (final AutomaticOnOffKeepalive ki : matches) {
|
for (final AutomaticOnOffKeepalive ki : matches) {
|
||||||
|
if (ki.mAutomaticOnOffState == STATE_SUSPENDED) {
|
||||||
|
mKeepaliveTracker.finalizePausedKeepalive(ki.mKi, reason);
|
||||||
|
}
|
||||||
cleanupAutoOnOffKeepalive(ki);
|
cleanupAutoOnOffKeepalive(ki);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -425,9 +447,14 @@ public class AutomaticOnOffKeepaliveTracker {
|
|||||||
*/
|
*/
|
||||||
public void handleStartKeepalive(Message message) {
|
public void handleStartKeepalive(Message message) {
|
||||||
final AutomaticOnOffKeepalive autoKi = (AutomaticOnOffKeepalive) message.obj;
|
final AutomaticOnOffKeepalive autoKi = (AutomaticOnOffKeepalive) message.obj;
|
||||||
|
final int error = mKeepaliveTracker.handleStartKeepalive(autoKi.mKi);
|
||||||
|
if (error != SUCCESS) {
|
||||||
|
mEventLog.log("Failed to start keepalive " + autoKi.mCallback + " on "
|
||||||
|
+ autoKi.getNetwork() + " with error " + error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
mEventLog.log("Start keepalive " + autoKi.mCallback + " on " + autoKi.getNetwork());
|
mEventLog.log("Start keepalive " + autoKi.mCallback + " on " + autoKi.getNetwork());
|
||||||
mKeepaliveStatsTracker.onStartKeepalive();
|
mKeepaliveStatsTracker.onStartKeepalive();
|
||||||
mKeepaliveTracker.handleStartKeepalive(autoKi.mKi);
|
|
||||||
|
|
||||||
// Add automatic on/off request into list to track its life cycle.
|
// Add automatic on/off request into list to track its life cycle.
|
||||||
try {
|
try {
|
||||||
@@ -443,10 +470,22 @@ public class AutomaticOnOffKeepaliveTracker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleResumeKeepalive(@NonNull final KeepaliveTracker.KeepaliveInfo ki) {
|
/**
|
||||||
|
* Handle resume keepalive with the given KeepaliveInfo
|
||||||
|
*
|
||||||
|
* @return SUCCESS if the keepalive is successfully starting and the error reason otherwise.
|
||||||
|
*/
|
||||||
|
private int handleResumeKeepalive(@NonNull final KeepaliveTracker.KeepaliveInfo ki) {
|
||||||
|
final int error = mKeepaliveTracker.handleStartKeepalive(ki);
|
||||||
|
if (error != SUCCESS) {
|
||||||
|
mEventLog.log("Failed to resume keepalive " + ki.mCallback + " on " + ki.mNai
|
||||||
|
+ " with error " + error);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
mKeepaliveStatsTracker.onResumeKeepalive();
|
mKeepaliveStatsTracker.onResumeKeepalive();
|
||||||
mKeepaliveTracker.handleStartKeepalive(ki);
|
|
||||||
mEventLog.log("Resumed successfully keepalive " + ki.mCallback + " on " + ki.mNai);
|
mEventLog.log("Resumed successfully keepalive " + ki.mCallback + " on " + ki.mNai);
|
||||||
|
|
||||||
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handlePauseKeepalive(@NonNull final KeepaliveTracker.KeepaliveInfo ki) {
|
private void handlePauseKeepalive(@NonNull final KeepaliveTracker.KeepaliveInfo ki) {
|
||||||
@@ -467,7 +506,7 @@ public class AutomaticOnOffKeepaliveTracker {
|
|||||||
final KeepaliveTracker.KeepaliveInfo ki = autoKi.mKi;
|
final KeepaliveTracker.KeepaliveInfo ki = autoKi.mKi;
|
||||||
mKeepaliveTracker.handleStopKeepalive(ki.getNai(), ki.getSlot(), reason);
|
mKeepaliveTracker.handleStopKeepalive(ki.getNai(), ki.getSlot(), reason);
|
||||||
} else {
|
} else {
|
||||||
mKeepaliveTracker.finalizePausedKeepalive(autoKi.mKi);
|
mKeepaliveTracker.finalizePausedKeepalive(autoKi.mKi, reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
cleanupAutoOnOffKeepalive(autoKi);
|
cleanupAutoOnOffKeepalive(autoKi);
|
||||||
@@ -612,7 +651,22 @@ public class AutomaticOnOffKeepaliveTracker {
|
|||||||
* Forward to KeepaliveTracker.
|
* Forward to KeepaliveTracker.
|
||||||
*/
|
*/
|
||||||
public void handleCheckKeepalivesStillValid(NetworkAgentInfo nai) {
|
public void handleCheckKeepalivesStillValid(NetworkAgentInfo nai) {
|
||||||
mKeepaliveTracker.handleCheckKeepalivesStillValid(nai);
|
ArrayList<Pair<AutomaticOnOffKeepalive, Integer>> invalidKeepalives = null;
|
||||||
|
|
||||||
|
for (final AutomaticOnOffKeepalive autoKi : mAutomaticOnOffKeepalives) {
|
||||||
|
if (!nai.equals(autoKi.mKi.mNai)) continue;
|
||||||
|
final int error = autoKi.mKi.isValid();
|
||||||
|
if (error != SUCCESS) {
|
||||||
|
if (invalidKeepalives == null) {
|
||||||
|
invalidKeepalives = new ArrayList<>();
|
||||||
|
}
|
||||||
|
invalidKeepalives.add(Pair.create(autoKi, error));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (invalidKeepalives == null) return;
|
||||||
|
for (final Pair<AutomaticOnOffKeepalive, Integer> keepaliveAndError : invalidKeepalives) {
|
||||||
|
handleStopKeepalive(keepaliveAndError.first, keepaliveAndError.second);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
|
|||||||
@@ -54,7 +54,6 @@ import android.os.RemoteException;
|
|||||||
import android.system.ErrnoException;
|
import android.system.ErrnoException;
|
||||||
import android.system.Os;
|
import android.system.Os;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.Pair;
|
|
||||||
|
|
||||||
import com.android.connectivity.resources.R;
|
import com.android.connectivity.resources.R;
|
||||||
import com.android.internal.annotations.VisibleForTesting;
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
@@ -337,7 +336,12 @@ public class KeepaliveTracker {
|
|||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int isValid() {
|
/**
|
||||||
|
* Checks if the keepalive info is valid to start.
|
||||||
|
*
|
||||||
|
* @return SUCCESS if the keepalive is valid and the error reason otherwise.
|
||||||
|
*/
|
||||||
|
public int isValid() {
|
||||||
synchronized (mNai) {
|
synchronized (mNai) {
|
||||||
int error = checkInterval();
|
int error = checkInterval();
|
||||||
if (error == SUCCESS) error = checkLimit();
|
if (error == SUCCESS) error = checkLimit();
|
||||||
@@ -348,11 +352,17 @@ public class KeepaliveTracker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void start(int slot) {
|
/**
|
||||||
|
* Attempt to start the keepalive on the given slot.
|
||||||
|
*
|
||||||
|
* @param slot the slot to start the keepalive on.
|
||||||
|
* @return SUCCESS if the keepalive is successfully starting and the error reason otherwise.
|
||||||
|
*/
|
||||||
|
int start(int slot) {
|
||||||
// BINDER_DIED can happen if the binder died before the KeepaliveInfo was created and
|
// BINDER_DIED can happen if the binder died before the KeepaliveInfo was created and
|
||||||
// the constructor set the state to BINDER_DIED. If that's the case, the KI is already
|
// the constructor set the state to BINDER_DIED. If that's the case, the KI is already
|
||||||
// cleaned up.
|
// cleaned up.
|
||||||
if (BINDER_DIED == mStartedState) return;
|
if (BINDER_DIED == mStartedState) return BINDER_DIED;
|
||||||
mSlot = slot;
|
mSlot = slot;
|
||||||
int error = isValid();
|
int error = isValid();
|
||||||
if (error == SUCCESS) {
|
if (error == SUCCESS) {
|
||||||
@@ -368,7 +378,7 @@ public class KeepaliveTracker {
|
|||||||
mTcpController.startSocketMonitor(mFd, this, mSlot);
|
mTcpController.startSocketMonitor(mFd, this, mSlot);
|
||||||
} catch (InvalidSocketException e) {
|
} catch (InvalidSocketException e) {
|
||||||
handleStopKeepalive(mNai, mSlot, ERROR_INVALID_SOCKET);
|
handleStopKeepalive(mNai, mSlot, ERROR_INVALID_SOCKET);
|
||||||
return;
|
return ERROR_INVALID_SOCKET;
|
||||||
}
|
}
|
||||||
final TcpKeepalivePacketData tcpData = (TcpKeepalivePacketData) mPacket;
|
final TcpKeepalivePacketData tcpData = (TcpKeepalivePacketData) mPacket;
|
||||||
mNai.onAddTcpKeepalivePacketFilter(slot, tcpData);
|
mNai.onAddTcpKeepalivePacketFilter(slot, tcpData);
|
||||||
@@ -377,13 +387,14 @@ public class KeepaliveTracker {
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
Log.wtf(TAG, "Starting keepalive with unknown type: " + mType);
|
Log.wtf(TAG, "Starting keepalive with unknown type: " + mType);
|
||||||
handleStopKeepalive(mNai, mSlot, error);
|
handleStopKeepalive(mNai, mSlot, ERROR_UNSUPPORTED);
|
||||||
return;
|
return ERROR_UNSUPPORTED;
|
||||||
}
|
}
|
||||||
mStartedState = STARTING;
|
mStartedState = STARTING;
|
||||||
|
return SUCCESS;
|
||||||
} else {
|
} else {
|
||||||
handleStopKeepalive(mNai, mSlot, error);
|
handleStopKeepalive(mNai, mSlot, error);
|
||||||
return;
|
return error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -444,6 +455,8 @@ public class KeepaliveTracker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: This does not clean up the autoKi in AutomaticOnOffKeepaliveTracker and it is not
|
||||||
|
// possible without a big refactor.
|
||||||
void onFileDescriptorInitiatedStop(final int socketKeepaliveReason) {
|
void onFileDescriptorInitiatedStop(final int socketKeepaliveReason) {
|
||||||
handleStopKeepalive(mNai, mSlot, socketKeepaliveReason);
|
handleStopKeepalive(mNai, mSlot, socketKeepaliveReason);
|
||||||
}
|
}
|
||||||
@@ -486,12 +499,15 @@ public class KeepaliveTracker {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle start keepalives with the message.
|
* Handle start keepalives with the message.
|
||||||
|
*
|
||||||
|
* @param ki the keepalive to start.
|
||||||
|
* @return SUCCESS if the keepalive is successfully starting and the error reason otherwise.
|
||||||
*/
|
*/
|
||||||
public void handleStartKeepalive(KeepaliveInfo ki) {
|
public int handleStartKeepalive(KeepaliveInfo ki) {
|
||||||
NetworkAgentInfo nai = ki.getNai();
|
NetworkAgentInfo nai = ki.getNai();
|
||||||
int slot = findFirstFreeSlot(nai);
|
int slot = findFirstFreeSlot(nai);
|
||||||
mKeepalives.get(nai).put(slot, ki);
|
mKeepalives.get(nai).put(slot, ki);
|
||||||
ki.start(slot);
|
return ki.start(slot);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void handleStopAllKeepalives(NetworkAgentInfo nai, int reason) {
|
public void handleStopAllKeepalives(NetworkAgentInfo nai, int reason) {
|
||||||
@@ -593,40 +609,33 @@ public class KeepaliveTracker {
|
|||||||
/**
|
/**
|
||||||
* Finalize a paused keepalive.
|
* Finalize a paused keepalive.
|
||||||
*
|
*
|
||||||
* This will simply send the onStopped() callback after checking that this keepalive is
|
* This will send the appropriate callback after checking that this keepalive is indeed paused.
|
||||||
* indeed paused.
|
|
||||||
*
|
*
|
||||||
* @param ki the keepalive to finalize
|
* @param ki the keepalive to finalize
|
||||||
|
* @param reason the reason the keepalive is stopped
|
||||||
*/
|
*/
|
||||||
public void finalizePausedKeepalive(@NonNull final KeepaliveInfo ki) {
|
public void finalizePausedKeepalive(@NonNull final KeepaliveInfo ki, int reason) {
|
||||||
if (SUCCESS_PAUSED != ki.mStopReason) {
|
if (SUCCESS_PAUSED != ki.mStopReason) {
|
||||||
throw new IllegalStateException("Keepalive is not paused");
|
throw new IllegalStateException("Keepalive is not paused");
|
||||||
}
|
}
|
||||||
try {
|
if (reason == SUCCESS) {
|
||||||
ki.mCallback.onStopped();
|
try {
|
||||||
} catch (RemoteException e) {
|
ki.mCallback.onStopped();
|
||||||
Log.w(TAG, "Discarded onStopped callback while finalizing paused keepalive");
|
} catch (RemoteException e) {
|
||||||
|
Log.w(TAG, "Discarded onStopped callback while finalizing paused keepalive");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
notifyErrorCallback(ki.mCallback, reason);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void handleCheckKeepalivesStillValid(NetworkAgentInfo nai) {
|
/**
|
||||||
HashMap <Integer, KeepaliveInfo> networkKeepalives = mKeepalives.get(nai);
|
* Handle keepalive events from lower layer.
|
||||||
if (networkKeepalives != null) {
|
*
|
||||||
ArrayList<Pair<Integer, Integer>> invalidKeepalives = new ArrayList<>();
|
* @return false if the event caused handleStopKeepalive to be called, i.e. the keepalive is
|
||||||
for (int slot : networkKeepalives.keySet()) {
|
* forced to stop. Otherwise, return true.
|
||||||
int error = networkKeepalives.get(slot).isValid();
|
*/
|
||||||
if (error != SUCCESS) {
|
public boolean handleEventSocketKeepalive(@NonNull NetworkAgentInfo nai, int slot, int reason) {
|
||||||
invalidKeepalives.add(Pair.create(slot, error));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (Pair<Integer, Integer> slotAndError: invalidKeepalives) {
|
|
||||||
handleStopKeepalive(nai, slotAndError.first, slotAndError.second);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Handle keepalive events from lower layer. */
|
|
||||||
public void handleEventSocketKeepalive(@NonNull NetworkAgentInfo nai, int slot, int reason) {
|
|
||||||
KeepaliveInfo ki = null;
|
KeepaliveInfo ki = null;
|
||||||
try {
|
try {
|
||||||
ki = mKeepalives.get(nai).get(slot);
|
ki = mKeepalives.get(nai).get(slot);
|
||||||
@@ -634,7 +643,7 @@ public class KeepaliveTracker {
|
|||||||
if (ki == null) {
|
if (ki == null) {
|
||||||
Log.e(TAG, "Event " + NetworkAgent.EVENT_SOCKET_KEEPALIVE + "," + slot + "," + reason
|
Log.e(TAG, "Event " + NetworkAgent.EVENT_SOCKET_KEEPALIVE + "," + slot + "," + reason
|
||||||
+ " for unknown keepalive " + slot + " on " + nai.toShortString());
|
+ " for unknown keepalive " + slot + " on " + nai.toShortString());
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This can be called in a number of situations :
|
// This can be called in a number of situations :
|
||||||
@@ -667,11 +676,13 @@ public class KeepaliveTracker {
|
|||||||
Log.w(TAG, "Discarded " + (ki.mResumed ? "onResumed" : "onStarted")
|
Log.w(TAG, "Discarded " + (ki.mResumed ? "onResumed" : "onStarted")
|
||||||
+ " callback for slot " + slot);
|
+ " callback for slot " + slot);
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
} else {
|
} else {
|
||||||
Log.d(TAG, "Failed to start keepalive " + slot + " on " + nai.toShortString()
|
Log.d(TAG, "Failed to start keepalive " + slot + " on " + nai.toShortString()
|
||||||
+ ": " + reason);
|
+ ": " + reason);
|
||||||
// The message indicated some error trying to start: do call handleStopKeepalive.
|
// The message indicated some error trying to start: do call handleStopKeepalive.
|
||||||
handleStopKeepalive(nai, slot, reason);
|
handleStopKeepalive(nai, slot, reason);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
} else if (KeepaliveInfo.STOPPING == ki.mStartedState) {
|
} else if (KeepaliveInfo.STOPPING == ki.mStartedState) {
|
||||||
// The message indicated result of stopping : clean up keepalive slots.
|
// The message indicated result of stopping : clean up keepalive slots.
|
||||||
@@ -679,9 +690,12 @@ public class KeepaliveTracker {
|
|||||||
+ " stopped: " + reason);
|
+ " stopped: " + reason);
|
||||||
ki.mStartedState = KeepaliveInfo.NOT_STARTED;
|
ki.mStartedState = KeepaliveInfo.NOT_STARTED;
|
||||||
cleanupStoppedKeepalive(nai, slot);
|
cleanupStoppedKeepalive(nai, slot);
|
||||||
|
return true;
|
||||||
} else {
|
} else {
|
||||||
Log.wtf(TAG, "Event " + NetworkAgent.EVENT_SOCKET_KEEPALIVE + "," + slot + "," + reason
|
Log.wtf(TAG, "Event " + NetworkAgent.EVENT_SOCKET_KEEPALIVE + "," + slot + "," + reason
|
||||||
+ " for keepalive in wrong state: " + ki.toString());
|
+ " for keepalive in wrong state: " + ki.toString());
|
||||||
|
// Although this is an unexpected event, the keepalive is not stopped here.
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,9 +20,12 @@ import static android.content.pm.PackageManager.PERMISSION_GRANTED;
|
|||||||
import static android.net.ConnectivityManager.TYPE_MOBILE;
|
import static android.net.ConnectivityManager.TYPE_MOBILE;
|
||||||
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
|
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
|
||||||
|
|
||||||
|
import static com.android.testutils.HandlerUtils.visibleOnHandlerThread;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
import static org.junit.Assert.assertNotNull;
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
import static org.junit.Assert.assertThrows;
|
import static org.junit.Assert.assertThrows;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
@@ -30,17 +33,20 @@ import static org.mockito.ArgumentMatchers.anyBoolean;
|
|||||||
import static org.mockito.ArgumentMatchers.anyInt;
|
import static org.mockito.ArgumentMatchers.anyInt;
|
||||||
import static org.mockito.ArgumentMatchers.eq;
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
import static org.mockito.ArgumentMatchers.longThat;
|
import static org.mockito.ArgumentMatchers.longThat;
|
||||||
|
import static org.mockito.Mockito.clearInvocations;
|
||||||
import static org.mockito.Mockito.doNothing;
|
import static org.mockito.Mockito.doNothing;
|
||||||
import static org.mockito.Mockito.doReturn;
|
import static org.mockito.Mockito.doReturn;
|
||||||
|
import static org.mockito.Mockito.ignoreStubs;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.never;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||||
|
|
||||||
import android.app.AlarmManager;
|
import android.app.AlarmManager;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import android.net.INetd;
|
import android.net.INetd;
|
||||||
import android.net.ISocketKeepaliveCallback;
|
import android.net.ISocketKeepaliveCallback;
|
||||||
import android.net.KeepalivePacketData;
|
|
||||||
import android.net.LinkAddress;
|
import android.net.LinkAddress;
|
||||||
import android.net.LinkProperties;
|
import android.net.LinkProperties;
|
||||||
import android.net.MarkMaskParcel;
|
import android.net.MarkMaskParcel;
|
||||||
@@ -48,6 +54,7 @@ import android.net.NattKeepalivePacketData;
|
|||||||
import android.net.Network;
|
import android.net.Network;
|
||||||
import android.net.NetworkCapabilities;
|
import android.net.NetworkCapabilities;
|
||||||
import android.net.NetworkInfo;
|
import android.net.NetworkInfo;
|
||||||
|
import android.net.SocketKeepalive;
|
||||||
import android.os.Binder;
|
import android.os.Binder;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
@@ -63,6 +70,7 @@ import androidx.annotation.NonNull;
|
|||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
import com.android.connectivity.resources.R;
|
import com.android.connectivity.resources.R;
|
||||||
|
import com.android.server.connectivity.AutomaticOnOffKeepaliveTracker.AutomaticOnOffKeepalive;
|
||||||
import com.android.server.connectivity.KeepaliveTracker.KeepaliveInfo;
|
import com.android.server.connectivity.KeepaliveTracker.KeepaliveInfo;
|
||||||
import com.android.testutils.DevSdkIgnoreRule;
|
import com.android.testutils.DevSdkIgnoreRule;
|
||||||
import com.android.testutils.DevSdkIgnoreRunner;
|
import com.android.testutils.DevSdkIgnoreRunner;
|
||||||
@@ -70,6 +78,7 @@ import com.android.testutils.HandlerUtils;
|
|||||||
|
|
||||||
import libcore.util.HexEncoding;
|
import libcore.util.HexEncoding;
|
||||||
|
|
||||||
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
@@ -82,12 +91,15 @@ import java.net.InetAddress;
|
|||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.ByteOrder;
|
import java.nio.ByteOrder;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
@RunWith(DevSdkIgnoreRunner.class)
|
@RunWith(DevSdkIgnoreRunner.class)
|
||||||
@SmallTest
|
@SmallTest
|
||||||
@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.TIRAMISU)
|
@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.TIRAMISU)
|
||||||
public class AutomaticOnOffKeepaliveTrackerTest {
|
public class AutomaticOnOffKeepaliveTrackerTest {
|
||||||
private static final String TAG = AutomaticOnOffKeepaliveTrackerTest.class.getSimpleName();
|
private static final String TAG = AutomaticOnOffKeepaliveTrackerTest.class.getSimpleName();
|
||||||
|
private static final int TEST_SLOT = 1;
|
||||||
private static final int TEST_NETID = 0xA85;
|
private static final int TEST_NETID = 0xA85;
|
||||||
private static final int TEST_NETID_FWMARK = 0x0A85;
|
private static final int TEST_NETID_FWMARK = 0x0A85;
|
||||||
private static final int OTHER_NETID = 0x1A85;
|
private static final int OTHER_NETID = 0x1A85;
|
||||||
@@ -95,6 +107,8 @@ public class AutomaticOnOffKeepaliveTrackerTest {
|
|||||||
private static final int TIMEOUT_MS = 30_000;
|
private static final int TIMEOUT_MS = 30_000;
|
||||||
private static final int MOCK_RESOURCE_ID = 5;
|
private static final int MOCK_RESOURCE_ID = 5;
|
||||||
private static final int TEST_KEEPALIVE_INTERVAL_SEC = 10;
|
private static final int TEST_KEEPALIVE_INTERVAL_SEC = 10;
|
||||||
|
private static final int TEST_KEEPALIVE_INVALID_INTERVAL_SEC = 9;
|
||||||
|
|
||||||
private AutomaticOnOffKeepaliveTracker mAOOKeepaliveTracker;
|
private AutomaticOnOffKeepaliveTracker mAOOKeepaliveTracker;
|
||||||
private HandlerThread mHandlerThread;
|
private HandlerThread mHandlerThread;
|
||||||
|
|
||||||
@@ -102,6 +116,8 @@ public class AutomaticOnOffKeepaliveTrackerTest {
|
|||||||
@Mock AutomaticOnOffKeepaliveTracker.Dependencies mDependencies;
|
@Mock AutomaticOnOffKeepaliveTracker.Dependencies mDependencies;
|
||||||
@Mock Context mCtx;
|
@Mock Context mCtx;
|
||||||
@Mock AlarmManager mAlarmManager;
|
@Mock AlarmManager mAlarmManager;
|
||||||
|
@Mock NetworkAgentInfo mNai;
|
||||||
|
|
||||||
TestKeepaliveTracker mKeepaliveTracker;
|
TestKeepaliveTracker mKeepaliveTracker;
|
||||||
AOOTestHandler mTestHandler;
|
AOOTestHandler mTestHandler;
|
||||||
|
|
||||||
@@ -202,6 +218,37 @@ public class AutomaticOnOffKeepaliveTrackerTest {
|
|||||||
private static final byte[] TEST_RESPONSE_BYTES =
|
private static final byte[] TEST_RESPONSE_BYTES =
|
||||||
HexEncoding.decode(TEST_RESPONSE_HEX.toCharArray(), false);
|
HexEncoding.decode(TEST_RESPONSE_HEX.toCharArray(), false);
|
||||||
|
|
||||||
|
private static class TestKeepaliveInfo {
|
||||||
|
private static List<Socket> sOpenSockets = new ArrayList<>();
|
||||||
|
|
||||||
|
public static void closeAllSockets() throws Exception {
|
||||||
|
for (final Socket socket : sOpenSockets) {
|
||||||
|
socket.close();
|
||||||
|
}
|
||||||
|
sOpenSockets.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public final Socket socket;
|
||||||
|
public final Binder binder;
|
||||||
|
public final FileDescriptor fd;
|
||||||
|
public final ISocketKeepaliveCallback socketKeepaliveCallback;
|
||||||
|
public final Network underpinnedNetwork;
|
||||||
|
public final NattKeepalivePacketData kpd;
|
||||||
|
|
||||||
|
TestKeepaliveInfo(NattKeepalivePacketData kpd) throws Exception {
|
||||||
|
this.kpd = kpd;
|
||||||
|
socket = new Socket();
|
||||||
|
socket.bind(null);
|
||||||
|
sOpenSockets.add(socket);
|
||||||
|
fd = socket.getFileDescriptor$();
|
||||||
|
|
||||||
|
binder = new Binder();
|
||||||
|
socketKeepaliveCallback = mock(ISocketKeepaliveCallback.class);
|
||||||
|
doReturn(binder).when(socketKeepaliveCallback).asBinder();
|
||||||
|
underpinnedNetwork = mock(Network.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private class TestKeepaliveTracker extends KeepaliveTracker {
|
private class TestKeepaliveTracker extends KeepaliveTracker {
|
||||||
private KeepaliveInfo mKi;
|
private KeepaliveInfo mKi;
|
||||||
|
|
||||||
@@ -231,6 +278,14 @@ public class AutomaticOnOffKeepaliveTrackerTest {
|
|||||||
public void setup() throws Exception {
|
public void setup() throws Exception {
|
||||||
MockitoAnnotations.initMocks(this);
|
MockitoAnnotations.initMocks(this);
|
||||||
|
|
||||||
|
mNai.networkCapabilities =
|
||||||
|
new NetworkCapabilities.Builder().addTransportType(TRANSPORT_CELLULAR).build();
|
||||||
|
mNai.networkInfo = new NetworkInfo(TYPE_MOBILE, 0 /* subtype */, "LTE", "LTE");
|
||||||
|
mNai.networkInfo.setDetailedState(
|
||||||
|
NetworkInfo.DetailedState.CONNECTED, "test reason", "test extra info");
|
||||||
|
doReturn(new Network(TEST_NETID)).when(mNai).network();
|
||||||
|
mNai.linkProperties = new LinkProperties();
|
||||||
|
|
||||||
doReturn(PERMISSION_GRANTED).when(mCtx).checkPermission(any() /* permission */,
|
doReturn(PERMISSION_GRANTED).when(mCtx).checkPermission(any() /* permission */,
|
||||||
anyInt() /* pid */, anyInt() /* uid */);
|
anyInt() /* pid */, anyInt() /* uid */);
|
||||||
ConnectivityResources.setResourcesContextForTest(mCtx);
|
ConnectivityResources.setResourcesContextForTest(mCtx);
|
||||||
@@ -255,6 +310,11 @@ public class AutomaticOnOffKeepaliveTrackerTest {
|
|||||||
new AutomaticOnOffKeepaliveTracker(mCtx, mTestHandler, mDependencies);
|
new AutomaticOnOffKeepaliveTracker(mCtx, mTestHandler, mDependencies);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void teardown() throws Exception {
|
||||||
|
TestKeepaliveInfo.closeAllSockets();
|
||||||
|
}
|
||||||
|
|
||||||
private final class AOOTestHandler extends Handler {
|
private final class AOOTestHandler extends Handler {
|
||||||
public AutomaticOnOffKeepaliveTracker.AutomaticOnOffKeepalive mLastAutoKi = null;
|
public AutomaticOnOffKeepaliveTracker.AutomaticOnOffKeepalive mLastAutoKi = null;
|
||||||
|
|
||||||
@@ -305,45 +365,70 @@ public class AutomaticOnOffKeepaliveTrackerTest {
|
|||||||
() -> assertFalse(mAOOKeepaliveTracker.isAnyTcpSocketConnected(TEST_NETID)));
|
() -> assertFalse(mAOOKeepaliveTracker.isAnyTcpSocketConnected(TEST_NETID)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
private void triggerEventKeepalive(int slot, int reason) {
|
||||||
public void testAlarm() throws Exception {
|
visibleOnHandlerThread(
|
||||||
|
mTestHandler,
|
||||||
|
() -> mAOOKeepaliveTracker.handleEventSocketKeepalive(mNai, slot, reason));
|
||||||
|
}
|
||||||
|
|
||||||
|
private TestKeepaliveInfo doStartNattKeepalive(int intervalSeconds) throws Exception {
|
||||||
final InetAddress srcAddress = InetAddress.getByAddress(
|
final InetAddress srcAddress = InetAddress.getByAddress(
|
||||||
new byte[] { (byte) 192, 0, 0, (byte) 129 });
|
new byte[] { (byte) 192, 0, 0, (byte) 129 });
|
||||||
final int srcPort = 12345;
|
final int srcPort = 12345;
|
||||||
final InetAddress dstAddress = InetAddress.getByAddress(new byte[] { 8, 8, 8, 8});
|
final InetAddress dstAddress = InetAddress.getByAddress(new byte[] {8, 8, 8, 8});
|
||||||
final int dstPort = 12345;
|
final int dstPort = 12345;
|
||||||
|
|
||||||
final NetworkAgentInfo nai = mock(NetworkAgentInfo.class);
|
mNai.linkProperties.addLinkAddress(new LinkAddress(srcAddress, 24));
|
||||||
nai.networkCapabilities = new NetworkCapabilities.Builder()
|
|
||||||
.addTransportType(TRANSPORT_CELLULAR).build();
|
|
||||||
nai.networkInfo = new NetworkInfo(TYPE_MOBILE, 0 /* subtype */, "LTE", "LTE");
|
|
||||||
nai.networkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, "test reason",
|
|
||||||
"test extra info");
|
|
||||||
nai.linkProperties = new LinkProperties();
|
|
||||||
nai.linkProperties.addLinkAddress(new LinkAddress(srcAddress, 24));
|
|
||||||
|
|
||||||
final Socket socket = new Socket();
|
final NattKeepalivePacketData kpd = new NattKeepalivePacketData(srcAddress, srcPort,
|
||||||
socket.bind(null);
|
|
||||||
final FileDescriptor fd = socket.getFileDescriptor$();
|
|
||||||
final IBinder binder = new Binder();
|
|
||||||
final ISocketKeepaliveCallback cb = mock(ISocketKeepaliveCallback.class);
|
|
||||||
doReturn(binder).when(cb).asBinder();
|
|
||||||
final Network underpinnedNetwork = mock(Network.class);
|
|
||||||
|
|
||||||
final KeepalivePacketData kpd = new NattKeepalivePacketData(srcAddress, srcPort,
|
|
||||||
dstAddress, dstPort, new byte[] {1});
|
dstAddress, dstPort, new byte[] {1});
|
||||||
final KeepaliveInfo ki = mKeepaliveTracker.new KeepaliveInfo(cb, nai, kpd,
|
|
||||||
TEST_KEEPALIVE_INTERVAL_SEC, KeepaliveInfo.TYPE_NATT, fd);
|
final TestKeepaliveInfo testInfo = new TestKeepaliveInfo(kpd);
|
||||||
|
|
||||||
|
final KeepaliveInfo ki = mKeepaliveTracker.new KeepaliveInfo(
|
||||||
|
testInfo.socketKeepaliveCallback, mNai, kpd, intervalSeconds,
|
||||||
|
KeepaliveInfo.TYPE_NATT, testInfo.fd);
|
||||||
mKeepaliveTracker.setReturnedKeepaliveInfo(ki);
|
mKeepaliveTracker.setReturnedKeepaliveInfo(ki);
|
||||||
|
|
||||||
|
mAOOKeepaliveTracker.startNattKeepalive(mNai, testInfo.fd, intervalSeconds,
|
||||||
|
testInfo.socketKeepaliveCallback, srcAddress.toString(), srcPort,
|
||||||
|
dstAddress.toString(), dstPort, true /* automaticOnOffKeepalives */,
|
||||||
|
testInfo.underpinnedNetwork);
|
||||||
|
HandlerUtils.waitForIdle(mTestHandler, TIMEOUT_MS);
|
||||||
|
|
||||||
|
return testInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
private TestKeepaliveInfo doStartNattKeepalive() throws Exception {
|
||||||
|
return doStartNattKeepalive(TEST_KEEPALIVE_INTERVAL_SEC);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doPauseKeepalive(AutomaticOnOffKeepalive autoKi) throws Exception {
|
||||||
|
setupResponseWithoutSocketExisting();
|
||||||
|
visibleOnHandlerThread(
|
||||||
|
mTestHandler,
|
||||||
|
() -> mAOOKeepaliveTracker.handleMonitorAutomaticKeepalive(autoKi, TEST_NETID));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doResumeKeepalive(AutomaticOnOffKeepalive autoKi) throws Exception {
|
||||||
|
setupResponseWithSocketExisting();
|
||||||
|
visibleOnHandlerThread(
|
||||||
|
mTestHandler,
|
||||||
|
() -> mAOOKeepaliveTracker.handleMonitorAutomaticKeepalive(autoKi, TEST_NETID));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doStopKeepalive(AutomaticOnOffKeepalive autoKi) throws Exception {
|
||||||
|
visibleOnHandlerThread(
|
||||||
|
mTestHandler,
|
||||||
|
() -> mAOOKeepaliveTracker.handleStopKeepalive(autoKi, SocketKeepalive.SUCCESS));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAlarm() throws Exception {
|
||||||
// Mock elapsed real time to verify the alarm timer.
|
// Mock elapsed real time to verify the alarm timer.
|
||||||
final long time = SystemClock.elapsedRealtime();
|
final long time = SystemClock.elapsedRealtime();
|
||||||
doReturn(time).when(mDependencies).getElapsedRealtime();
|
doReturn(time).when(mDependencies).getElapsedRealtime();
|
||||||
|
final TestKeepaliveInfo testInfo = doStartNattKeepalive();
|
||||||
mAOOKeepaliveTracker.startNattKeepalive(nai, fd, 10 /* intervalSeconds */, cb,
|
|
||||||
srcAddress.toString(), srcPort, dstAddress.toString(), dstPort,
|
|
||||||
true /* automaticOnOffKeepalives */, underpinnedNetwork);
|
|
||||||
HandlerUtils.waitForIdle(mTestHandler, TIMEOUT_MS);
|
|
||||||
|
|
||||||
final ArgumentCaptor<AlarmManager.OnAlarmListener> listenerCaptor =
|
final ArgumentCaptor<AlarmManager.OnAlarmListener> listenerCaptor =
|
||||||
ArgumentCaptor.forClass(AlarmManager.OnAlarmListener.class);
|
ArgumentCaptor.forClass(AlarmManager.OnAlarmListener.class);
|
||||||
@@ -362,9 +447,8 @@ public class AutomaticOnOffKeepaliveTrackerTest {
|
|||||||
HandlerUtils.waitForIdle(mTestHandler, TIMEOUT_MS);
|
HandlerUtils.waitForIdle(mTestHandler, TIMEOUT_MS);
|
||||||
|
|
||||||
assertNotNull(mTestHandler.mLastAutoKi);
|
assertNotNull(mTestHandler.mLastAutoKi);
|
||||||
assertEquals(cb, mTestHandler.mLastAutoKi.getCallback());
|
assertEquals(testInfo.socketKeepaliveCallback, mTestHandler.mLastAutoKi.getCallback());
|
||||||
assertEquals(underpinnedNetwork, mTestHandler.mLastAutoKi.getUnderpinnedNetwork());
|
assertEquals(testInfo.underpinnedNetwork, mTestHandler.mLastAutoKi.getUnderpinnedNetwork());
|
||||||
socket.close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setupResponseWithSocketExisting() throws Exception {
|
private void setupResponseWithSocketExisting() throws Exception {
|
||||||
@@ -391,4 +475,301 @@ public class AutomaticOnOffKeepaliveTrackerTest {
|
|||||||
buffer.order(ByteOrder.nativeOrder());
|
buffer.order(ByteOrder.nativeOrder());
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private AutomaticOnOffKeepalive getAutoKiForBinder(IBinder binder) {
|
||||||
|
return visibleOnHandlerThread(
|
||||||
|
mTestHandler, () -> mAOOKeepaliveTracker.getKeepaliveForBinder(binder));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkAndProcessKeepaliveStart(final NattKeepalivePacketData kpd) throws Exception {
|
||||||
|
checkAndProcessKeepaliveStart(TEST_SLOT, kpd);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkAndProcessKeepaliveStart(
|
||||||
|
int slot, final NattKeepalivePacketData kpd) throws Exception {
|
||||||
|
verify(mNai).onStartNattSocketKeepalive(slot, TEST_KEEPALIVE_INTERVAL_SEC, kpd);
|
||||||
|
verify(mNai).onAddNattKeepalivePacketFilter(slot, kpd);
|
||||||
|
triggerEventKeepalive(slot, SocketKeepalive.SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkAndProcessKeepaliveStop() throws Exception {
|
||||||
|
checkAndProcessKeepaliveStop(TEST_SLOT);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkAndProcessKeepaliveStop(int slot) throws Exception {
|
||||||
|
verify(mNai).onStopSocketKeepalive(slot);
|
||||||
|
verify(mNai).onRemoveKeepalivePacketFilter(slot);
|
||||||
|
triggerEventKeepalive(slot, SocketKeepalive.SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testStartNattKeepalive_valid() throws Exception {
|
||||||
|
final TestKeepaliveInfo testInfo = doStartNattKeepalive();
|
||||||
|
|
||||||
|
checkAndProcessKeepaliveStart(testInfo.kpd);
|
||||||
|
|
||||||
|
final AutomaticOnOffKeepalive autoKi = getAutoKiForBinder(testInfo.binder);
|
||||||
|
assertNotNull(autoKi);
|
||||||
|
assertEquals(testInfo.socketKeepaliveCallback, autoKi.getCallback());
|
||||||
|
|
||||||
|
verify(testInfo.socketKeepaliveCallback).onStarted();
|
||||||
|
verifyNoMoreInteractions(ignoreStubs(testInfo.socketKeepaliveCallback));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testStartNattKeepalive_invalidInterval() throws Exception {
|
||||||
|
final TestKeepaliveInfo testInfo =
|
||||||
|
doStartNattKeepalive(TEST_KEEPALIVE_INVALID_INTERVAL_SEC);
|
||||||
|
|
||||||
|
assertNull(getAutoKiForBinder(testInfo.binder));
|
||||||
|
|
||||||
|
verify(testInfo.socketKeepaliveCallback).onError(SocketKeepalive.ERROR_INVALID_INTERVAL);
|
||||||
|
verifyNoMoreInteractions(ignoreStubs(testInfo.socketKeepaliveCallback));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testHandleEventSocketKeepalive_startingFailureHardwareError() throws Exception {
|
||||||
|
final TestKeepaliveInfo testInfo = doStartNattKeepalive();
|
||||||
|
|
||||||
|
verify(mNai)
|
||||||
|
.onStartNattSocketKeepalive(TEST_SLOT, TEST_KEEPALIVE_INTERVAL_SEC, testInfo.kpd);
|
||||||
|
verify(mNai).onAddNattKeepalivePacketFilter(TEST_SLOT, testInfo.kpd);
|
||||||
|
// Network agent returns an error, fails to start the keepalive.
|
||||||
|
triggerEventKeepalive(TEST_SLOT, SocketKeepalive.ERROR_HARDWARE_ERROR);
|
||||||
|
|
||||||
|
checkAndProcessKeepaliveStop();
|
||||||
|
|
||||||
|
assertNull(getAutoKiForBinder(testInfo.binder));
|
||||||
|
|
||||||
|
verify(testInfo.socketKeepaliveCallback).onError(SocketKeepalive.ERROR_HARDWARE_ERROR);
|
||||||
|
verifyNoMoreInteractions(ignoreStubs(testInfo.socketKeepaliveCallback));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testHandleCheckKeepalivesStillValid_linkPropertiesChanged() throws Exception {
|
||||||
|
// Successful start of NATT keepalive.
|
||||||
|
final TestKeepaliveInfo testInfo = doStartNattKeepalive();
|
||||||
|
checkAndProcessKeepaliveStart(testInfo.kpd);
|
||||||
|
verify(testInfo.socketKeepaliveCallback).onStarted();
|
||||||
|
|
||||||
|
// Source address is removed from link properties by clearing.
|
||||||
|
mNai.linkProperties.clear();
|
||||||
|
|
||||||
|
// Check for valid keepalives
|
||||||
|
visibleOnHandlerThread(
|
||||||
|
mTestHandler, () -> mAOOKeepaliveTracker.handleCheckKeepalivesStillValid(mNai));
|
||||||
|
|
||||||
|
checkAndProcessKeepaliveStop();
|
||||||
|
|
||||||
|
assertNull(getAutoKiForBinder(testInfo.binder));
|
||||||
|
|
||||||
|
verify(testInfo.socketKeepaliveCallback).onError(SocketKeepalive.ERROR_INVALID_IP_ADDRESS);
|
||||||
|
verifyNoMoreInteractions(ignoreStubs(testInfo.socketKeepaliveCallback));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testStopKeepalive() throws Exception {
|
||||||
|
// Successful start of NATT keepalive.
|
||||||
|
final TestKeepaliveInfo testInfo = doStartNattKeepalive();
|
||||||
|
checkAndProcessKeepaliveStart(testInfo.kpd);
|
||||||
|
verify(testInfo.socketKeepaliveCallback).onStarted();
|
||||||
|
|
||||||
|
doStopKeepalive(getAutoKiForBinder(testInfo.binder));
|
||||||
|
checkAndProcessKeepaliveStop();
|
||||||
|
|
||||||
|
assertNull(getAutoKiForBinder(testInfo.binder));
|
||||||
|
verify(testInfo.socketKeepaliveCallback).onStopped();
|
||||||
|
verifyNoMoreInteractions(ignoreStubs(testInfo.socketKeepaliveCallback));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPauseKeepalive() throws Exception {
|
||||||
|
// Successful start of NATT keepalive.
|
||||||
|
final TestKeepaliveInfo testInfo = doStartNattKeepalive();
|
||||||
|
checkAndProcessKeepaliveStart(testInfo.kpd);
|
||||||
|
verify(testInfo.socketKeepaliveCallback).onStarted();
|
||||||
|
|
||||||
|
doPauseKeepalive(getAutoKiForBinder(testInfo.binder));
|
||||||
|
|
||||||
|
checkAndProcessKeepaliveStop();
|
||||||
|
verify(testInfo.socketKeepaliveCallback).onPaused();
|
||||||
|
|
||||||
|
// Pausing does not cleanup the autoKi
|
||||||
|
assertNotNull(getAutoKiForBinder(testInfo.binder));
|
||||||
|
|
||||||
|
clearInvocations(mNai);
|
||||||
|
doStopKeepalive(getAutoKiForBinder(testInfo.binder));
|
||||||
|
// The keepalive is already stopped.
|
||||||
|
verify(mNai, never()).onStopSocketKeepalive(TEST_SLOT);
|
||||||
|
verify(mNai, never()).onRemoveKeepalivePacketFilter(TEST_SLOT);
|
||||||
|
|
||||||
|
// Stopping while paused still calls onStopped.
|
||||||
|
verify(testInfo.socketKeepaliveCallback).onStopped();
|
||||||
|
// autoKi is cleaned up.
|
||||||
|
assertNull(getAutoKiForBinder(testInfo.binder));
|
||||||
|
|
||||||
|
verifyNoMoreInteractions(ignoreStubs(testInfo.socketKeepaliveCallback));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testResumeKeepalive() throws Exception {
|
||||||
|
// Successful start of NATT keepalive.
|
||||||
|
final TestKeepaliveInfo testInfo = doStartNattKeepalive();
|
||||||
|
checkAndProcessKeepaliveStart(testInfo.kpd);
|
||||||
|
verify(testInfo.socketKeepaliveCallback).onStarted();
|
||||||
|
|
||||||
|
doPauseKeepalive(getAutoKiForBinder(testInfo.binder));
|
||||||
|
checkAndProcessKeepaliveStop();
|
||||||
|
verify(testInfo.socketKeepaliveCallback).onPaused();
|
||||||
|
|
||||||
|
clearInvocations(mNai);
|
||||||
|
doResumeKeepalive(getAutoKiForBinder(testInfo.binder));
|
||||||
|
checkAndProcessKeepaliveStart(testInfo.kpd);
|
||||||
|
assertNotNull(getAutoKiForBinder(testInfo.binder));
|
||||||
|
verify(testInfo.socketKeepaliveCallback).onResumed();
|
||||||
|
|
||||||
|
doStopKeepalive(getAutoKiForBinder(testInfo.binder));
|
||||||
|
checkAndProcessKeepaliveStop();
|
||||||
|
assertNull(getAutoKiForBinder(testInfo.binder));
|
||||||
|
|
||||||
|
verify(testInfo.socketKeepaliveCallback).onStopped();
|
||||||
|
verifyNoMoreInteractions(ignoreStubs(testInfo.socketKeepaliveCallback));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testResumeKeepalive_invalidSourceAddress() throws Exception {
|
||||||
|
// Successful start of NATT keepalive.
|
||||||
|
final TestKeepaliveInfo testInfo = doStartNattKeepalive();
|
||||||
|
checkAndProcessKeepaliveStart(testInfo.kpd);
|
||||||
|
verify(testInfo.socketKeepaliveCallback).onStarted();
|
||||||
|
|
||||||
|
doPauseKeepalive(getAutoKiForBinder(testInfo.binder));
|
||||||
|
checkAndProcessKeepaliveStop();
|
||||||
|
verify(testInfo.socketKeepaliveCallback).onPaused();
|
||||||
|
|
||||||
|
mNai.linkProperties.clear();
|
||||||
|
|
||||||
|
clearInvocations(mNai);
|
||||||
|
doResumeKeepalive(getAutoKiForBinder(testInfo.binder));
|
||||||
|
verify(mNai, never()).onStartNattSocketKeepalive(anyInt(), anyInt(), any());
|
||||||
|
verify(mNai, never()).onAddNattKeepalivePacketFilter(anyInt(), any());
|
||||||
|
|
||||||
|
assertNull(getAutoKiForBinder(testInfo.binder));
|
||||||
|
|
||||||
|
verify(testInfo.socketKeepaliveCallback).onError(SocketKeepalive.ERROR_INVALID_IP_ADDRESS);
|
||||||
|
verifyNoMoreInteractions(ignoreStubs(testInfo.socketKeepaliveCallback));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testResumeKeepalive_startingFailureHardwareError() throws Exception {
|
||||||
|
// Successful start of NATT keepalive.
|
||||||
|
final TestKeepaliveInfo testInfo = doStartNattKeepalive();
|
||||||
|
checkAndProcessKeepaliveStart(testInfo.kpd);
|
||||||
|
verify(testInfo.socketKeepaliveCallback).onStarted();
|
||||||
|
|
||||||
|
doPauseKeepalive(getAutoKiForBinder(testInfo.binder));
|
||||||
|
checkAndProcessKeepaliveStop();
|
||||||
|
verify(testInfo.socketKeepaliveCallback).onPaused();
|
||||||
|
|
||||||
|
clearInvocations(mNai);
|
||||||
|
doResumeKeepalive(getAutoKiForBinder(testInfo.binder));
|
||||||
|
|
||||||
|
verify(mNai)
|
||||||
|
.onStartNattSocketKeepalive(TEST_SLOT, TEST_KEEPALIVE_INTERVAL_SEC, testInfo.kpd);
|
||||||
|
verify(mNai).onAddNattKeepalivePacketFilter(TEST_SLOT, testInfo.kpd);
|
||||||
|
// Network agent returns error on starting the keepalive.
|
||||||
|
triggerEventKeepalive(TEST_SLOT, SocketKeepalive.ERROR_HARDWARE_ERROR);
|
||||||
|
|
||||||
|
checkAndProcessKeepaliveStop();
|
||||||
|
|
||||||
|
assertNull(getAutoKiForBinder(testInfo.binder));
|
||||||
|
verify(testInfo.socketKeepaliveCallback).onError(SocketKeepalive.ERROR_HARDWARE_ERROR);
|
||||||
|
verifyNoMoreInteractions(ignoreStubs(testInfo.socketKeepaliveCallback));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testStopAllKeepalives() throws Exception {
|
||||||
|
final TestKeepaliveInfo testInfo1 = doStartNattKeepalive();
|
||||||
|
final TestKeepaliveInfo testInfo2 = doStartNattKeepalive();
|
||||||
|
checkAndProcessKeepaliveStart(TEST_SLOT, testInfo1.kpd);
|
||||||
|
checkAndProcessKeepaliveStart(TEST_SLOT + 1, testInfo2.kpd);
|
||||||
|
|
||||||
|
verify(testInfo1.socketKeepaliveCallback).onStarted();
|
||||||
|
verify(testInfo2.socketKeepaliveCallback).onStarted();
|
||||||
|
|
||||||
|
// Pause the first keepalive
|
||||||
|
doPauseKeepalive(getAutoKiForBinder(testInfo1.binder));
|
||||||
|
checkAndProcessKeepaliveStop(TEST_SLOT);
|
||||||
|
verify(testInfo1.socketKeepaliveCallback).onPaused();
|
||||||
|
|
||||||
|
visibleOnHandlerThread(
|
||||||
|
mTestHandler,
|
||||||
|
() -> mAOOKeepaliveTracker.handleStopAllKeepalives(
|
||||||
|
mNai, SocketKeepalive.ERROR_INVALID_NETWORK));
|
||||||
|
|
||||||
|
// Note that checkAndProcessKeepaliveStop is not called since the network agent is assumed
|
||||||
|
// to be disconnected for a handleStopAllKeepalives call.
|
||||||
|
assertNull(getAutoKiForBinder(testInfo1.binder));
|
||||||
|
assertNull(getAutoKiForBinder(testInfo2.binder));
|
||||||
|
|
||||||
|
verify(testInfo1.socketKeepaliveCallback, never()).onStopped();
|
||||||
|
verify(testInfo2.socketKeepaliveCallback, never()).onStopped();
|
||||||
|
verify(testInfo1.socketKeepaliveCallback).onError(SocketKeepalive.ERROR_INVALID_NETWORK);
|
||||||
|
verify(testInfo2.socketKeepaliveCallback).onError(SocketKeepalive.ERROR_INVALID_NETWORK);
|
||||||
|
|
||||||
|
verifyNoMoreInteractions(ignoreStubs(testInfo1.socketKeepaliveCallback));
|
||||||
|
verifyNoMoreInteractions(ignoreStubs(testInfo2.socketKeepaliveCallback));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTwoKeepalives_startAfterPause() throws Exception {
|
||||||
|
final TestKeepaliveInfo testInfo1 = doStartNattKeepalive();
|
||||||
|
checkAndProcessKeepaliveStart(testInfo1.kpd);
|
||||||
|
verify(testInfo1.socketKeepaliveCallback).onStarted();
|
||||||
|
assertNotNull(getAutoKiForBinder(testInfo1.binder));
|
||||||
|
|
||||||
|
final AutomaticOnOffKeepalive autoKi1 = getAutoKiForBinder(testInfo1.binder);
|
||||||
|
doPauseKeepalive(autoKi1);
|
||||||
|
checkAndProcessKeepaliveStop(TEST_SLOT);
|
||||||
|
verify(testInfo1.socketKeepaliveCallback).onPaused();
|
||||||
|
assertNotNull(getAutoKiForBinder(testInfo1.binder));
|
||||||
|
|
||||||
|
clearInvocations(mNai);
|
||||||
|
// Start the second keepalive while the first is paused.
|
||||||
|
final TestKeepaliveInfo testInfo2 = doStartNattKeepalive();
|
||||||
|
// The slot used is TEST_SLOT since it is now a free slot.
|
||||||
|
checkAndProcessKeepaliveStart(TEST_SLOT, testInfo2.kpd);
|
||||||
|
verify(testInfo2.socketKeepaliveCallback).onStarted();
|
||||||
|
assertNotNull(getAutoKiForBinder(testInfo2.binder));
|
||||||
|
|
||||||
|
clearInvocations(mNai);
|
||||||
|
doResumeKeepalive(autoKi1);
|
||||||
|
// The next free slot is TEST_SLOT + 1.
|
||||||
|
checkAndProcessKeepaliveStart(TEST_SLOT + 1, testInfo1.kpd);
|
||||||
|
verify(testInfo1.socketKeepaliveCallback).onResumed();
|
||||||
|
|
||||||
|
clearInvocations(mNai);
|
||||||
|
doStopKeepalive(autoKi1);
|
||||||
|
// TODO: The slot should be consistent with the checkAndProcessKeepaliveStart directly above
|
||||||
|
checkAndProcessKeepaliveStop(TEST_SLOT);
|
||||||
|
// TODO: onStopped should only be called on the first keepalive callback.
|
||||||
|
verify(testInfo1.socketKeepaliveCallback, never()).onStopped();
|
||||||
|
verify(testInfo2.socketKeepaliveCallback).onStopped();
|
||||||
|
assertNull(getAutoKiForBinder(testInfo1.binder));
|
||||||
|
|
||||||
|
clearInvocations(mNai);
|
||||||
|
assertNotNull(getAutoKiForBinder(testInfo2.binder));
|
||||||
|
doStopKeepalive(getAutoKiForBinder(testInfo2.binder));
|
||||||
|
// This slot should be consistent with its corresponding checkAndProcessKeepaliveStart.
|
||||||
|
// TODO: checkAndProcessKeepaliveStop should be called instead but the keepalive is
|
||||||
|
// unexpectedly already stopped above.
|
||||||
|
verify(mNai, never()).onStopSocketKeepalive(TEST_SLOT);
|
||||||
|
verify(mNai, never()).onRemoveKeepalivePacketFilter(TEST_SLOT);
|
||||||
|
|
||||||
|
verify(testInfo2.socketKeepaliveCallback).onStopped();
|
||||||
|
assertNull(getAutoKiForBinder(testInfo2.binder));
|
||||||
|
|
||||||
|
verifyNoMoreInteractions(ignoreStubs(testInfo1.socketKeepaliveCallback));
|
||||||
|
verifyNoMoreInteractions(ignoreStubs(testInfo2.socketKeepaliveCallback));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user