Use WakeupMesage for delayed events in VcnGatewayConnection.
This CL updates VcnGatewayConnection to use WakeupMessages instead of sendDelayedMessage() for delayed events. This change allows for VcnGatewayConnection to guarantee that all its messages are processed while holding WakeLocks. Bug: 178140973 Test: atest FrameworksVcnTests Change-Id: If8182378fe2e9dad08df88a84934b21e22e25752
This commit is contained in:
@@ -61,6 +61,7 @@ import android.os.Message;
|
||||
import android.os.ParcelUuid;
|
||||
import android.os.PowerManager;
|
||||
import android.os.PowerManager.WakeLock;
|
||||
import android.os.SystemClock;
|
||||
import android.util.ArraySet;
|
||||
import android.util.Slog;
|
||||
|
||||
@@ -68,6 +69,7 @@ import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.annotations.VisibleForTesting.Visibility;
|
||||
import com.android.internal.util.State;
|
||||
import com.android.internal.util.StateMachine;
|
||||
import com.android.internal.util.WakeupMessage;
|
||||
import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
|
||||
import com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkRecord;
|
||||
import com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkTrackerCallback;
|
||||
@@ -129,8 +131,8 @@ import java.util.concurrent.TimeUnit;
|
||||
* lack of WakeLocks).
|
||||
*
|
||||
* <p>Any attempt to remove messages from the Handler should be done using {@link
|
||||
* #removeEqualMessages(int, Object)}. This is necessary to ensure that the WakeLock is correctly
|
||||
* released when no messages remain in the Handler queue.
|
||||
* #removeEqualMessages}. This is necessary to ensure that the WakeLock is correctly released when
|
||||
* no messages remain in the Handler queue.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@@ -140,6 +142,15 @@ public class VcnGatewayConnection extends StateMachine {
|
||||
@VisibleForTesting(visibility = Visibility.PRIVATE)
|
||||
static final InetAddress DUMMY_ADDR = InetAddresses.parseNumericAddress("192.0.2.0");
|
||||
|
||||
@VisibleForTesting(visibility = Visibility.PRIVATE)
|
||||
static final String TEARDOWN_TIMEOUT_ALARM = TAG + "_TEARDOWN_TIMEOUT_ALARM";
|
||||
|
||||
@VisibleForTesting(visibility = Visibility.PRIVATE)
|
||||
static final String DISCONNECT_REQUEST_ALARM = TAG + "_DISCONNECT_REQUEST_ALARM";
|
||||
|
||||
@VisibleForTesting(visibility = Visibility.PRIVATE)
|
||||
static final String RETRY_TIMEOUT_ALARM = TAG + "_RETRY_TIMEOUT_ALARM";
|
||||
|
||||
private static final int[] MERGED_CAPABILITIES =
|
||||
new int[] {NET_CAPABILITY_NOT_METERED, NET_CAPABILITY_NOT_ROAMING};
|
||||
private static final int ARG_NOT_PRESENT = Integer.MIN_VALUE;
|
||||
@@ -150,7 +161,8 @@ public class VcnGatewayConnection extends StateMachine {
|
||||
private static final String DISCONNECT_REASON_TEARDOWN = "teardown() called on VcnTunnel";
|
||||
private static final int TOKEN_ALL = Integer.MIN_VALUE;
|
||||
|
||||
private static final int NETWORK_LOSS_DISCONNECT_TIMEOUT_SECONDS = 30;
|
||||
@VisibleForTesting(visibility = Visibility.PRIVATE)
|
||||
static final int NETWORK_LOSS_DISCONNECT_TIMEOUT_SECONDS = 30;
|
||||
|
||||
@VisibleForTesting(visibility = Visibility.PRIVATE)
|
||||
static final int TEARDOWN_TIMEOUT_SECONDS = 5;
|
||||
@@ -510,6 +522,10 @@ public class VcnGatewayConnection extends StateMachine {
|
||||
*/
|
||||
private NetworkAgent mNetworkAgent;
|
||||
|
||||
@Nullable private WakeupMessage mTeardownTimeoutAlarm;
|
||||
@Nullable private WakeupMessage mDisconnectRequestAlarm;
|
||||
@Nullable private WakeupMessage mRetryTimeoutAlarm;
|
||||
|
||||
public VcnGatewayConnection(
|
||||
@NonNull VcnContext vcnContext,
|
||||
@NonNull ParcelUuid subscriptionGroup,
|
||||
@@ -592,6 +608,10 @@ public class VcnGatewayConnection extends StateMachine {
|
||||
|
||||
releaseWakeLock();
|
||||
|
||||
cancelTeardownTimeoutAlarm();
|
||||
cancelDisconnectRequestAlarm();
|
||||
cancelRetryTimeoutAlarm();
|
||||
|
||||
mUnderlyingNetworkTracker.teardown();
|
||||
}
|
||||
|
||||
@@ -623,17 +643,11 @@ public class VcnGatewayConnection extends StateMachine {
|
||||
// If underlying is null, all underlying networks have been lost. Disconnect VCN after a
|
||||
// timeout.
|
||||
if (underlying == null) {
|
||||
sendMessageDelayed(
|
||||
EVENT_DISCONNECT_REQUESTED,
|
||||
TOKEN_ALL,
|
||||
new EventDisconnectRequestedInfo(DISCONNECT_REASON_UNDERLYING_NETWORK_LOST),
|
||||
TimeUnit.SECONDS.toMillis(NETWORK_LOSS_DISCONNECT_TIMEOUT_SECONDS));
|
||||
setDisconnectRequestAlarm();
|
||||
} else {
|
||||
// Cancel any existing disconnect due to previous loss of underlying network
|
||||
removeEqualMessages(
|
||||
EVENT_DISCONNECT_REQUESTED,
|
||||
new EventDisconnectRequestedInfo(
|
||||
DISCONNECT_REASON_UNDERLYING_NETWORK_LOST));
|
||||
// Received a new Network so any previous alarm is irrelevant - cancel + clear it,
|
||||
// and cancel any queued EVENT_DISCONNECT_REQUEST messages
|
||||
cancelDisconnectRequestAlarm();
|
||||
}
|
||||
|
||||
sendMessageAndAcquireWakeLock(
|
||||
@@ -724,6 +738,10 @@ public class VcnGatewayConnection extends StateMachine {
|
||||
super.sendMessage(msg);
|
||||
}
|
||||
|
||||
// TODO(b/180146061): also override and Log.wtf() other Message handling methods
|
||||
// In mind are sendMessageDelayed(), sendMessageAtFrontOfQueue, removeMessages, and
|
||||
// removeDeferredMessages
|
||||
|
||||
/**
|
||||
* WakeLock-based alternative to {@link #sendMessage}. Use to guarantee that the device will not
|
||||
* go to sleep before processing the sent message.
|
||||
@@ -751,14 +769,13 @@ public class VcnGatewayConnection extends StateMachine {
|
||||
super.sendMessage(what, token, arg2, data);
|
||||
}
|
||||
|
||||
// TODO: remove this method once WakupMessage is used instead
|
||||
private void sendMessageDelayed(int what, int token, EventInfo data, long timeout) {
|
||||
super.sendMessageDelayed(what, token, ARG_NOT_PRESENT, data, timeout);
|
||||
}
|
||||
|
||||
// TODO: remove this method once WakupMessage is used instead
|
||||
private void sendMessageDelayed(int what, int token, int arg2, EventInfo data, long timeout) {
|
||||
super.sendMessageDelayed(what, token, arg2, data, timeout);
|
||||
/**
|
||||
* WakeLock-based alternative to {@link #sendMessage}. Use to guarantee that the device will not
|
||||
* go to sleep before processing the sent message.
|
||||
*/
|
||||
private void sendMessageAndAcquireWakeLock(Message msg) {
|
||||
acquireWakeLock();
|
||||
super.sendMessage(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -788,6 +805,100 @@ public class VcnGatewayConnection extends StateMachine {
|
||||
maybeReleaseWakeLock();
|
||||
}
|
||||
|
||||
private WakeupMessage createScheduledAlarm(
|
||||
@NonNull String cmdName, Message delayedMessage, long delay) {
|
||||
// WakeupMessage uses Handler#dispatchMessage() to immediately handle the specified Runnable
|
||||
// at the scheduled time. dispatchMessage() immediately executes and there may be queued
|
||||
// events that resolve the scheduled alarm pending in the queue. So, use the Runnable to
|
||||
// place the alarm event at the end of the queue with sendMessageAndAcquireWakeLock (which
|
||||
// guarantees the device will stay awake).
|
||||
final WakeupMessage alarm =
|
||||
mDeps.newWakeupMessage(
|
||||
mVcnContext,
|
||||
getHandler(),
|
||||
cmdName,
|
||||
() -> sendMessageAndAcquireWakeLock(delayedMessage));
|
||||
alarm.schedule(mDeps.getElapsedRealTime() + delay);
|
||||
return alarm;
|
||||
}
|
||||
|
||||
private void setTeardownTimeoutAlarm() {
|
||||
// Safe to assign this alarm because it is either 1) already null, or 2) already fired. In
|
||||
// either case, there is nothing to cancel.
|
||||
if (mTeardownTimeoutAlarm != null) {
|
||||
Slog.wtf(TAG, "mTeardownTimeoutAlarm should be null before being set");
|
||||
}
|
||||
|
||||
final Message delayedMessage = obtainMessage(EVENT_TEARDOWN_TIMEOUT_EXPIRED, mCurrentToken);
|
||||
mTeardownTimeoutAlarm =
|
||||
createScheduledAlarm(
|
||||
TEARDOWN_TIMEOUT_ALARM,
|
||||
delayedMessage,
|
||||
TimeUnit.SECONDS.toMillis(TEARDOWN_TIMEOUT_SECONDS));
|
||||
}
|
||||
|
||||
private void cancelTeardownTimeoutAlarm() {
|
||||
if (mTeardownTimeoutAlarm != null) {
|
||||
mTeardownTimeoutAlarm.cancel();
|
||||
mTeardownTimeoutAlarm = null;
|
||||
}
|
||||
|
||||
// Cancel any existing teardown timeouts
|
||||
removeEqualMessages(EVENT_TEARDOWN_TIMEOUT_EXPIRED);
|
||||
}
|
||||
|
||||
private void setDisconnectRequestAlarm() {
|
||||
// Only schedule a NEW alarm if none is already set.
|
||||
if (mDisconnectRequestAlarm != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final Message delayedMessage =
|
||||
obtainMessage(
|
||||
EVENT_DISCONNECT_REQUESTED,
|
||||
TOKEN_ALL,
|
||||
0 /* arg2 */,
|
||||
new EventDisconnectRequestedInfo(
|
||||
DISCONNECT_REASON_UNDERLYING_NETWORK_LOST));
|
||||
mDisconnectRequestAlarm =
|
||||
createScheduledAlarm(
|
||||
DISCONNECT_REQUEST_ALARM,
|
||||
delayedMessage,
|
||||
TimeUnit.SECONDS.toMillis(NETWORK_LOSS_DISCONNECT_TIMEOUT_SECONDS));
|
||||
}
|
||||
|
||||
private void cancelDisconnectRequestAlarm() {
|
||||
if (mDisconnectRequestAlarm != null) {
|
||||
mDisconnectRequestAlarm.cancel();
|
||||
mDisconnectRequestAlarm = null;
|
||||
}
|
||||
|
||||
// Cancel any existing disconnect due to previous loss of underlying network
|
||||
removeEqualMessages(
|
||||
EVENT_DISCONNECT_REQUESTED,
|
||||
new EventDisconnectRequestedInfo(DISCONNECT_REASON_UNDERLYING_NETWORK_LOST));
|
||||
}
|
||||
|
||||
private void setRetryTimeoutAlarm(long delay) {
|
||||
// Safe to assign this alarm because it is either 1) already null, or 2) already fired. In
|
||||
// either case, there is nothing to cancel.
|
||||
if (mRetryTimeoutAlarm != null) {
|
||||
Slog.wtf(TAG, "mRetryTimeoutAlarm should be null before being set");
|
||||
}
|
||||
|
||||
final Message delayedMessage = obtainMessage(EVENT_RETRY_TIMEOUT_EXPIRED, mCurrentToken);
|
||||
mRetryTimeoutAlarm = createScheduledAlarm(RETRY_TIMEOUT_ALARM, delayedMessage, delay);
|
||||
}
|
||||
|
||||
private void cancelRetryTimeoutAlarm() {
|
||||
if (mRetryTimeoutAlarm != null) {
|
||||
mRetryTimeoutAlarm.cancel();
|
||||
mRetryTimeoutAlarm = null;
|
||||
}
|
||||
|
||||
removeEqualMessages(EVENT_RETRY_TIMEOUT_EXPIRED);
|
||||
}
|
||||
|
||||
private void sessionLost(int token, @Nullable Exception exception) {
|
||||
sendMessageAndAcquireWakeLock(
|
||||
EVENT_SESSION_LOST, token, new EventSessionLostInfo(exception));
|
||||
@@ -847,8 +958,8 @@ public class VcnGatewayConnection extends StateMachine {
|
||||
* builds.
|
||||
*
|
||||
* <p>Here be dragons: processMessage() is final to ensure that mWakeLock is released once
|
||||
* the Handler queue is empty. Future changes to processMessage() (or overrides to
|
||||
* processMessage) MUST ensure that mWakeLock is correctly released.
|
||||
* the Handler queue is empty. Future changes (or overrides) to processMessage() to MUST
|
||||
* ensure that mWakeLock is correctly released.
|
||||
*/
|
||||
@Override
|
||||
public final boolean processMessage(Message msg) {
|
||||
@@ -1030,10 +1141,9 @@ public class VcnGatewayConnection extends StateMachine {
|
||||
}
|
||||
|
||||
mIkeSession.close();
|
||||
sendMessageDelayed(
|
||||
EVENT_TEARDOWN_TIMEOUT_EXPIRED,
|
||||
mCurrentToken,
|
||||
TimeUnit.SECONDS.toMillis(TEARDOWN_TIMEOUT_SECONDS));
|
||||
|
||||
// Safe to blindly set up, as it is cancelled and cleared on exiting this state
|
||||
setTeardownTimeoutAlarm();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1084,6 +1194,8 @@ public class VcnGatewayConnection extends StateMachine {
|
||||
@Override
|
||||
protected void exitState() throws Exception {
|
||||
mSkipRetryTimeout = false;
|
||||
|
||||
cancelTeardownTimeoutAlarm();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1385,8 +1497,8 @@ public class VcnGatewayConnection extends StateMachine {
|
||||
Slog.wtf(TAG, "Underlying network was null in retry state");
|
||||
transitionTo(mDisconnectedState);
|
||||
} else {
|
||||
sendMessageDelayed(
|
||||
EVENT_RETRY_TIMEOUT_EXPIRED, mCurrentToken, getNextRetryIntervalsMs());
|
||||
// Safe to blindly set up, as it is cancelled and cleared on exiting this state
|
||||
setRetryTimeoutAlarm(getNextRetryIntervalsMs());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1399,8 +1511,6 @@ public class VcnGatewayConnection extends StateMachine {
|
||||
|
||||
// If new underlying is null, all networks were lost; go back to disconnected.
|
||||
if (mUnderlying == null) {
|
||||
removeEqualMessages(EVENT_RETRY_TIMEOUT_EXPIRED);
|
||||
|
||||
transitionTo(mDisconnectedState);
|
||||
return;
|
||||
} else if (oldUnderlying != null
|
||||
@@ -1411,8 +1521,6 @@ public class VcnGatewayConnection extends StateMachine {
|
||||
|
||||
// Fallthrough
|
||||
case EVENT_RETRY_TIMEOUT_EXPIRED:
|
||||
removeEqualMessages(EVENT_RETRY_TIMEOUT_EXPIRED);
|
||||
|
||||
transitionTo(mConnectingState);
|
||||
break;
|
||||
case EVENT_DISCONNECT_REQUESTED:
|
||||
@@ -1424,6 +1532,11 @@ public class VcnGatewayConnection extends StateMachine {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exitState() {
|
||||
cancelRetryTimeoutAlarm();
|
||||
}
|
||||
|
||||
private long getNextRetryIntervalsMs() {
|
||||
final int retryDelayIndex = mFailedAttempts - 1;
|
||||
final long[] retryIntervalsMs = mConnectionConfig.getRetryIntervalsMs();
|
||||
@@ -1702,6 +1815,20 @@ public class VcnGatewayConnection extends StateMachine {
|
||||
@NonNull Context context, int wakeLockFlag, @NonNull String wakeLockTag) {
|
||||
return new VcnWakeLock(context, wakeLockFlag, wakeLockTag);
|
||||
}
|
||||
|
||||
/** Builds a new WakeupMessage. */
|
||||
public WakeupMessage newWakeupMessage(
|
||||
@NonNull VcnContext vcnContext,
|
||||
@NonNull Handler handler,
|
||||
@NonNull String tag,
|
||||
@NonNull Runnable runnable) {
|
||||
return new WakeupMessage(vcnContext.getContext(), handler, tag, runnable);
|
||||
}
|
||||
|
||||
/** Gets the elapsed real time since boot, in millis. */
|
||||
public long getElapsedRealTime() {
|
||||
return SystemClock.elapsedRealtime();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -81,6 +81,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection
|
||||
|
||||
assertEquals(mGatewayConnection.mConnectedState, mGatewayConnection.getCurrentState());
|
||||
verify(mIkeSession, never()).close();
|
||||
verifyDisconnectRequestAlarmAndGetCallback(false /* expectCanceled */);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -170,6 +171,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection
|
||||
mTestLooper.dispatchAll();
|
||||
|
||||
assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState());
|
||||
verifyTeardownTimeoutAlarmAndGetCallback(false /* expectCanceled */);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -179,5 +181,6 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection
|
||||
|
||||
assertEquals(mGatewayConnection.mRetryTimeoutState, mGatewayConnection.getCurrentState());
|
||||
verify(mIkeSession).close();
|
||||
verifyTeardownTimeoutAlarmAndGetCallback(true /* expectCanceled */);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,6 +61,7 @@ public class VcnGatewayConnectionConnectingStateTest extends VcnGatewayConnectio
|
||||
|
||||
assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState());
|
||||
verify(mIkeSession).kill();
|
||||
verifyDisconnectRequestAlarmAndGetCallback(false /* expectCanceled */);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -73,6 +74,7 @@ public class VcnGatewayConnectionConnectingStateTest extends VcnGatewayConnectio
|
||||
assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState());
|
||||
verify(mIkeSession).close();
|
||||
verify(mIkeSession, never()).kill();
|
||||
verifyTeardownTimeoutAlarmAndGetCallback(false /* expectCanceled */);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -92,6 +94,7 @@ public class VcnGatewayConnectionConnectingStateTest extends VcnGatewayConnectio
|
||||
|
||||
assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState());
|
||||
verify(mIkeSession).close();
|
||||
verifyTeardownTimeoutAlarmAndGetCallback(false /* expectCanceled */);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -101,5 +104,6 @@ public class VcnGatewayConnectionConnectingStateTest extends VcnGatewayConnectio
|
||||
|
||||
assertEquals(mGatewayConnection.mRetryTimeoutState, mGatewayConnection.getCurrentState());
|
||||
verify(mIkeSession).close();
|
||||
verifyTeardownTimeoutAlarmAndGetCallback(true /* expectCanceled */);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,6 +88,7 @@ public class VcnGatewayConnectionDisconnectedStateTest extends VcnGatewayConnect
|
||||
mTestLooper.dispatchAll();
|
||||
|
||||
assertEquals(mGatewayConnection.mDisconnectedState, mGatewayConnection.getCurrentState());
|
||||
verifyDisconnectRequestAlarmAndGetCallback(false /* expectCanceled */);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -16,9 +16,9 @@
|
||||
|
||||
package com.android.server.vcn;
|
||||
|
||||
import static com.android.server.vcn.VcnGatewayConnection.TEARDOWN_TIMEOUT_SECONDS;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
@@ -28,8 +28,6 @@ import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/** Tests for VcnGatewayConnection.DisconnectedState */
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@SmallTest
|
||||
@@ -40,6 +38,9 @@ public class VcnGatewayConnectionDisconnectingStateTest extends VcnGatewayConnec
|
||||
|
||||
mGatewayConnection.setIkeSession(mGatewayConnection.buildIkeSession());
|
||||
|
||||
// ensure that mGatewayConnection has an underlying Network before entering
|
||||
// DisconnectingState
|
||||
mGatewayConnection.setUnderlyingNetwork(TEST_UNDERLYING_NETWORK_RECORD_2);
|
||||
mGatewayConnection.transitionTo(mGatewayConnection.mDisconnectingState);
|
||||
mTestLooper.dispatchAll();
|
||||
}
|
||||
@@ -49,12 +50,22 @@ public class VcnGatewayConnectionDisconnectingStateTest extends VcnGatewayConnec
|
||||
getIkeSessionCallback().onClosed();
|
||||
mTestLooper.dispatchAll();
|
||||
|
||||
assertEquals(mGatewayConnection.mDisconnectedState, mGatewayConnection.getCurrentState());
|
||||
assertEquals(mGatewayConnection.mRetryTimeoutState, mGatewayConnection.getCurrentState());
|
||||
verify(mMockIkeSession).close();
|
||||
verify(mMockIkeSession, never()).kill();
|
||||
verifyTeardownTimeoutAlarmAndGetCallback(true /* expectCanceled */);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTimeoutExpired() throws Exception {
|
||||
mTestLooper.moveTimeForward(TimeUnit.SECONDS.toMillis(TEARDOWN_TIMEOUT_SECONDS));
|
||||
Runnable delayedEvent =
|
||||
verifyTeardownTimeoutAlarmAndGetCallback(false /* expectCanceled */);
|
||||
|
||||
// Can't use mTestLooper to advance the time since VcnGatewayConnection uses WakeupMessages
|
||||
// (which are mocked here). Directly invoke the runnable instead. This is still sufficient,
|
||||
// since verifyTeardownTimeoutAlarmAndGetCallback() verifies the WakeupMessage was scheduled
|
||||
// with the correct delay.
|
||||
delayedEvent.run();
|
||||
mTestLooper.dispatchAll();
|
||||
|
||||
verify(mMockIkeSession).kill();
|
||||
@@ -67,5 +78,6 @@ public class VcnGatewayConnectionDisconnectingStateTest extends VcnGatewayConnec
|
||||
|
||||
// Should do nothing; already tearing down.
|
||||
assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState());
|
||||
verifyTeardownTimeoutAlarmAndGetCallback(false /* expectCanceled */);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,10 +29,14 @@ import org.junit.runner.RunWith;
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@SmallTest
|
||||
public class VcnGatewayConnectionRetryTimeoutStateTest extends VcnGatewayConnectionTestBase {
|
||||
private long mFirstRetryInterval;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
|
||||
mFirstRetryInterval = mConfig.getRetryInterval()[0];
|
||||
|
||||
mGatewayConnection.setUnderlyingNetwork(TEST_UNDERLYING_NETWORK_RECORD_1);
|
||||
mGatewayConnection.transitionTo(mGatewayConnection.mRetryTimeoutState);
|
||||
mTestLooper.dispatchAll();
|
||||
@@ -46,6 +50,7 @@ public class VcnGatewayConnectionRetryTimeoutStateTest extends VcnGatewayConnect
|
||||
mTestLooper.dispatchAll();
|
||||
|
||||
assertEquals(mGatewayConnection.mConnectingState, mGatewayConnection.getCurrentState());
|
||||
verifyRetryTimeoutAlarmAndGetCallback(mFirstRetryInterval, true /* expectCanceled */);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -56,6 +61,7 @@ public class VcnGatewayConnectionRetryTimeoutStateTest extends VcnGatewayConnect
|
||||
mTestLooper.dispatchAll();
|
||||
|
||||
assertEquals(mGatewayConnection.mRetryTimeoutState, mGatewayConnection.getCurrentState());
|
||||
verifyRetryTimeoutAlarmAndGetCallback(mFirstRetryInterval, false /* expectCanceled */);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -66,13 +72,23 @@ public class VcnGatewayConnectionRetryTimeoutStateTest extends VcnGatewayConnect
|
||||
mTestLooper.dispatchAll();
|
||||
|
||||
assertEquals(mGatewayConnection.mDisconnectedState, mGatewayConnection.getCurrentState());
|
||||
verifyRetryTimeoutAlarmAndGetCallback(mFirstRetryInterval, true /* expectCanceled */);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTimeoutElapsingTriggersRetry() throws Exception {
|
||||
mTestLooper.moveTimeForward(mConfig.getRetryIntervalsMs()[0]);
|
||||
final Runnable delayedEvent =
|
||||
verifyRetryTimeoutAlarmAndGetCallback(
|
||||
mFirstRetryInterval, false /* expectCanceled */);
|
||||
|
||||
// Can't use mTestLooper to advance the time since VcnGatewayConnection uses WakeupMessages
|
||||
// (which are mocked here). Directly invoke the runnable instead. This is still sufficient,
|
||||
// since verifyRetryTimeoutAlarmAndGetCallback() verifies the WakeupMessage was scheduled
|
||||
// with the correct delay.
|
||||
delayedEvent.run();
|
||||
mTestLooper.dispatchAll();
|
||||
|
||||
assertEquals(mGatewayConnection.mConnectingState, mGatewayConnection.getCurrentState());
|
||||
verifyRetryTimeoutAlarmAndGetCallback(mFirstRetryInterval, true /* expectCanceled */);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,4 +145,19 @@ public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase {
|
||||
|
||||
verifyWakeLockReleased();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNonNullUnderlyingNetworkRecordUpdateCancelsAlarm() {
|
||||
mGatewayConnection
|
||||
.getUnderlyingNetworkTrackerCallback()
|
||||
.onSelectedUnderlyingNetworkChanged(null);
|
||||
|
||||
verifyDisconnectRequestAlarmAndGetCallback(false /* expectCanceled */);
|
||||
|
||||
mGatewayConnection
|
||||
.getUnderlyingNetworkTrackerCallback()
|
||||
.onSelectedUnderlyingNetworkChanged(TEST_UNDERLYING_NETWORK_RECORD_1);
|
||||
|
||||
verify(mDisconnectRequestAlarm).cancel();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,8 +22,11 @@ import static com.android.server.vcn.VcnTestUtils.setupIpSecManager;
|
||||
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.atLeastOnce;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
|
||||
@@ -47,6 +50,7 @@ import android.os.ParcelUuid;
|
||||
import android.os.PowerManager;
|
||||
import android.os.test.TestLooper;
|
||||
|
||||
import com.android.internal.util.WakeupMessage;
|
||||
import com.android.server.IpSecService;
|
||||
import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
|
||||
import com.android.server.vcn.Vcn.VcnGatewayStatusCallback;
|
||||
@@ -59,6 +63,7 @@ import org.mockito.ArgumentCaptor;
|
||||
import java.net.InetAddress;
|
||||
import java.util.Collections;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class VcnGatewayConnectionTestBase {
|
||||
protected static final ParcelUuid TEST_SUB_GRP = new ParcelUuid(UUID.randomUUID());
|
||||
@@ -72,6 +77,7 @@ public class VcnGatewayConnectionTestBase {
|
||||
protected static final int TEST_IPSEC_TRANSFORM_RESOURCE_ID = 2;
|
||||
protected static final int TEST_IPSEC_TUNNEL_RESOURCE_ID = 3;
|
||||
protected static final int TEST_SUB_ID = 5;
|
||||
protected static final long ELAPSED_REAL_TIME = 123456789L;
|
||||
protected static final String TEST_IPSEC_TUNNEL_IFACE = "IPSEC_IFACE";
|
||||
protected static final UnderlyingNetworkRecord TEST_UNDERLYING_NETWORK_RECORD_1 =
|
||||
new UnderlyingNetworkRecord(
|
||||
@@ -99,6 +105,9 @@ public class VcnGatewayConnectionTestBase {
|
||||
@NonNull protected final VcnGatewayConnection.Dependencies mDeps;
|
||||
@NonNull protected final UnderlyingNetworkTracker mUnderlyingNetworkTracker;
|
||||
@NonNull protected final VcnWakeLock mWakeLock;
|
||||
@NonNull protected final WakeupMessage mTeardownTimeoutAlarm;
|
||||
@NonNull protected final WakeupMessage mDisconnectRequestAlarm;
|
||||
@NonNull protected final WakeupMessage mRetryTimeoutAlarm;
|
||||
|
||||
@NonNull protected final IpSecService mIpSecSvc;
|
||||
@NonNull protected final ConnectivityManager mConnMgr;
|
||||
@@ -116,6 +125,9 @@ public class VcnGatewayConnectionTestBase {
|
||||
mDeps = mock(VcnGatewayConnection.Dependencies.class);
|
||||
mUnderlyingNetworkTracker = mock(UnderlyingNetworkTracker.class);
|
||||
mWakeLock = mock(VcnWakeLock.class);
|
||||
mTeardownTimeoutAlarm = mock(WakeupMessage.class);
|
||||
mDisconnectRequestAlarm = mock(WakeupMessage.class);
|
||||
mRetryTimeoutAlarm = mock(WakeupMessage.class);
|
||||
|
||||
mIpSecSvc = mock(IpSecService.class);
|
||||
setupIpSecManager(mContext, mIpSecSvc);
|
||||
@@ -134,6 +146,16 @@ public class VcnGatewayConnectionTestBase {
|
||||
doReturn(mWakeLock)
|
||||
.when(mDeps)
|
||||
.newWakeLock(eq(mContext), eq(PowerManager.PARTIAL_WAKE_LOCK), any());
|
||||
|
||||
setUpWakeupMessage(mTeardownTimeoutAlarm, VcnGatewayConnection.TEARDOWN_TIMEOUT_ALARM);
|
||||
setUpWakeupMessage(mDisconnectRequestAlarm, VcnGatewayConnection.DISCONNECT_REQUEST_ALARM);
|
||||
setUpWakeupMessage(mRetryTimeoutAlarm, VcnGatewayConnection.RETRY_TIMEOUT_ALARM);
|
||||
|
||||
doReturn(ELAPSED_REAL_TIME).when(mDeps).getElapsedRealTime();
|
||||
}
|
||||
|
||||
private void setUpWakeupMessage(@NonNull WakeupMessage msg, @NonNull String cmdName) {
|
||||
doReturn(msg).when(mDeps).newWakeupMessage(eq(mVcnContext), any(), eq(cmdName), any());
|
||||
}
|
||||
|
||||
@Before
|
||||
@@ -190,4 +212,45 @@ public class VcnGatewayConnectionTestBase {
|
||||
verify(mWakeLock).release();
|
||||
verifyNoMoreInteractions(mWakeLock);
|
||||
}
|
||||
|
||||
private Runnable verifyWakeupMessageSetUpAndGetCallback(
|
||||
@NonNull String tag,
|
||||
@NonNull WakeupMessage msg,
|
||||
long delayInMillis,
|
||||
boolean expectCanceled) {
|
||||
ArgumentCaptor<Runnable> runnableCaptor = ArgumentCaptor.forClass(Runnable.class);
|
||||
verify(mDeps).newWakeupMessage(eq(mVcnContext), any(), eq(tag), runnableCaptor.capture());
|
||||
|
||||
verify(mDeps, atLeastOnce()).getElapsedRealTime();
|
||||
verify(msg).schedule(ELAPSED_REAL_TIME + delayInMillis);
|
||||
verify(msg, expectCanceled ? times(1) : never()).cancel();
|
||||
|
||||
return runnableCaptor.getValue();
|
||||
}
|
||||
|
||||
protected Runnable verifyTeardownTimeoutAlarmAndGetCallback(boolean expectCanceled) {
|
||||
return verifyWakeupMessageSetUpAndGetCallback(
|
||||
VcnGatewayConnection.TEARDOWN_TIMEOUT_ALARM,
|
||||
mTeardownTimeoutAlarm,
|
||||
TimeUnit.SECONDS.toMillis(VcnGatewayConnection.TEARDOWN_TIMEOUT_SECONDS),
|
||||
expectCanceled);
|
||||
}
|
||||
|
||||
protected Runnable verifyDisconnectRequestAlarmAndGetCallback(boolean expectCanceled) {
|
||||
return verifyWakeupMessageSetUpAndGetCallback(
|
||||
VcnGatewayConnection.DISCONNECT_REQUEST_ALARM,
|
||||
mDisconnectRequestAlarm,
|
||||
TimeUnit.SECONDS.toMillis(
|
||||
VcnGatewayConnection.NETWORK_LOSS_DISCONNECT_TIMEOUT_SECONDS),
|
||||
expectCanceled);
|
||||
}
|
||||
|
||||
protected Runnable verifyRetryTimeoutAlarmAndGetCallback(
|
||||
long delayInMillis, boolean expectCanceled) {
|
||||
return verifyWakeupMessageSetUpAndGetCallback(
|
||||
VcnGatewayConnection.RETRY_TIMEOUT_ALARM,
|
||||
mRetryTimeoutAlarm,
|
||||
delayInMillis,
|
||||
expectCanceled);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user