1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.connectivity;
18 
19 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
20 import static android.net.ConnectivityManager.TYPE_MOBILE;
21 import static android.net.NetworkAgent.CMD_STOP_SOCKET_KEEPALIVE;
22 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
23 import static com.android.server.connectivity.AutomaticOnOffKeepaliveTracker.METRICS_COLLECTION_DURATION_MS;
24 import static com.android.testutils.HandlerUtils.visibleOnHandlerThread;
25 import static org.junit.Assert.assertEquals;
26 import static org.junit.Assert.assertFalse;
27 import static org.junit.Assert.assertNotNull;
28 import static org.junit.Assert.assertNull;
29 import static org.junit.Assert.assertThrows;
30 import static org.junit.Assert.assertTrue;
31 import static org.junit.Assert.fail;
32 import static org.mockito.ArgumentMatchers.any;
33 import static org.mockito.ArgumentMatchers.anyInt;
34 import static org.mockito.ArgumentMatchers.eq;
35 import static org.mockito.ArgumentMatchers.longThat;
36 import static org.mockito.Mockito.clearInvocations;
37 import static org.mockito.Mockito.doCallRealMethod;
38 import static org.mockito.Mockito.doNothing;
39 import static org.mockito.Mockito.doReturn;
40 import static org.mockito.Mockito.ignoreStubs;
41 import static org.mockito.Mockito.mock;
42 import static org.mockito.Mockito.never;
43 import static org.mockito.Mockito.spy;
44 import static org.mockito.Mockito.verify;
45 import static org.mockito.Mockito.verifyNoMoreInteractions;
46 
47 import android.app.AlarmManager;
48 import android.content.Context;
49 import android.content.res.Resources;
50 import android.net.INetd;
51 import android.net.ISocketKeepaliveCallback;
52 import android.net.InetAddresses;
53 import android.net.KeepalivePacketData;
54 import android.net.LinkAddress;
55 import android.net.LinkProperties;
56 import android.net.MarkMaskParcel;
57 import android.net.NattKeepalivePacketData;
58 import android.net.Network;
59 import android.net.NetworkCapabilities;
60 import android.net.NetworkInfo;
61 import android.net.SocketKeepalive;
62 import android.net.TcpKeepalivePacketData;
63 import android.os.Binder;
64 import android.os.Build;
65 import android.os.Handler;
66 import android.os.HandlerThread;
67 import android.os.IBinder;
68 import android.os.Looper;
69 import android.os.Message;
70 import android.os.SystemClock;
71 import android.telephony.SubscriptionManager;
72 import android.util.Log;
73 import androidx.annotation.NonNull;
74 import androidx.annotation.Nullable;
75 import androidx.test.filters.SmallTest;
76 import com.android.internal.util.IndentingPrintWriter;
77 import com.android.server.connectivity.AutomaticOnOffKeepaliveTracker.AutomaticOnOffKeepalive;
78 import com.android.server.connectivity.KeepaliveTracker.KeepaliveInfo;
79 import com.android.testutils.DevSdkIgnoreRule;
80 import com.android.testutils.DevSdkIgnoreRunner;
81 import com.android.testutils.HandlerUtils;
82 import java.io.FileDescriptor;
83 import java.io.StringWriter;
84 import java.net.Inet4Address;
85 import java.net.InetAddress;
86 import java.net.Socket;
87 import java.nio.ByteBuffer;
88 import java.nio.ByteOrder;
89 import java.util.ArrayList;
90 import java.util.List;
91 import libcore.util.HexEncoding;
92 import org.junit.After;
93 import org.junit.Before;
94 import org.junit.Test;
95 import org.junit.runner.RunWith;
96 import org.mockito.ArgumentCaptor;
97 import org.mockito.Mock;
98 import org.mockito.MockitoAnnotations;
99 
100 @RunWith(DevSdkIgnoreRunner.class)
101 @SmallTest
102 @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.TIRAMISU)
103 public class AutomaticOnOffKeepaliveTrackerTest {
104     private static final String TAG = AutomaticOnOffKeepaliveTrackerTest.class.getSimpleName();
105     private static final int TEST_SLOT = 1;
106     private static final int TEST_NETID = 0xA85;
107     private static final int TEST_NETID_FWMARK = 0x0A85;
108     private static final int OTHER_NETID = 0x1A85;
109     private static final int NETID_MASK = 0xffff;
110     private static final int TIMEOUT_MS = 30_000;
111     private static final int MOCK_RESOURCE_ID = 5;
112     private static final int TEST_KEEPALIVE_INTERVAL_SEC = 10;
113     private static final int TEST_KEEPALIVE_INVALID_INTERVAL_SEC = 9;
114     private static final byte[] V4_SRC_ADDR = new byte[] { (byte) 192, 0, 0, (byte) 129 };
115     private static final String TEST_V4_IFACE = "v4-testIface";
116     private AutomaticOnOffKeepaliveTracker mAOOKeepaliveTracker;
117     private HandlerThread mHandlerThread;
118 
119     @Mock INetd mNetd;
120     @Mock AutomaticOnOffKeepaliveTracker.Dependencies mDependencies;
121     @Mock Context mCtx;
122     @Mock AlarmManager mAlarmManager;
123     @Mock NetworkAgentInfo mNai;
124     @Mock SubscriptionManager mSubscriptionManager;
125     @Mock KeepaliveTracker.Dependencies mKeepaliveTrackerDeps;
126     KeepaliveStatsTracker mKeepaliveStatsTracker;
127     TestKeepaliveTracker mKeepaliveTracker;
128     AOOTestHandler mTestHandler;
129     TestTcpKeepaliveController mTcpController;
130 
131     // Hexadecimal representation of a SOCK_DIAG response with tcp info.
132     private static final String SOCK_DIAG_TCP_INET_HEX =
133             // struct nlmsghdr.
134             "14010000"        // length = 276
135             + "1400"            // type = SOCK_DIAG_BY_FAMILY
136             + "0301"            // flags = NLM_F_REQUEST | NLM_F_DUMP
137             + "00000000"        // seqno
138             + "00000000"        // pid (0 == kernel)
139             // struct inet_diag_req_v2
140             + "02"              // family = AF_INET
141             + "06"              // state
142             + "00"              // timer
143             + "00"              // retrans
144             // inet_diag_sockid
145             + "DEA5"            // idiag_sport = 42462
146             + "71B9"            // idiag_dport = 47473
147             + "0a006402000000000000000000000000" // idiag_src = 10.0.100.2
148             + "08080808000000000000000000000000" // idiag_dst = 8.8.8.8
149             + "00000000"            // idiag_if
150             + "34ED000076270000"    // idiag_cookie = 43387759684916
151             + "00000000"            // idiag_expires
152             + "00000000"            // idiag_rqueue
153             + "00000000"            // idiag_wqueue
154             + "39300000"            // idiag_uid = 12345
155             + "00000000"            // idiag_inode
156             // rtattr
157             + "0500"            // len = 5
158             + "0800"            // type = 8
159             + "00000000"        // data
160             + "0800"            // len = 8
161             + "0F00"            // type = 15(INET_DIAG_MARK)
162             + "850A0C00"        // data, socket mark=789125
163             + "AC00"            // len = 172
164             + "0200"            // type = 2(INET_DIAG_INFO)
165             // tcp_info
166             + "01"               // state = TCP_ESTABLISHED
167             + "00"               // ca_state = TCP_CA_OPEN
168             + "05"               // retransmits = 5
169             + "00"               // probes = 0
170             + "00"               // backoff = 0
171             + "07"               // option = TCPI_OPT_WSCALE|TCPI_OPT_SACK|TCPI_OPT_TIMESTAMPS
172             + "88"               // wscale = 8
173             + "00"               // delivery_rate_app_limited = 0
174             + "4A911B00"         // rto = 1806666
175             + "00000000"         // ato = 0
176             + "2E050000"         // sndMss = 1326
177             + "18020000"         // rcvMss = 536
178             + "00000000"         // unsacked = 0
179             + "00000000"         // acked = 0
180             + "00000000"         // lost = 0
181             + "00000000"         // retrans = 0
182             + "00000000"         // fackets = 0
183             + "BB000000"         // lastDataSent = 187
184             + "00000000"         // lastAckSent = 0
185             + "BB000000"         // lastDataRecv = 187
186             + "BB000000"         // lastDataAckRecv = 187
187             + "DC050000"         // pmtu = 1500
188             + "30560100"         // rcvSsthresh = 87600
189             + "3E2C0900"         // rttt = 601150
190             + "1F960400"         // rttvar = 300575
191             + "78050000"         // sndSsthresh = 1400
192             + "0A000000"         // sndCwnd = 10
193             + "A8050000"         // advmss = 1448
194             + "03000000"         // reordering = 3
195             + "00000000"         // rcvrtt = 0
196             + "30560100"         // rcvspace = 87600
197             + "00000000"         // totalRetrans = 0
198             + "53AC000000000000"     // pacingRate = 44115
199             + "FFFFFFFFFFFFFFFF"     // maxPacingRate = 18446744073709551615
200             + "0100000000000000"     // bytesAcked = 1
201             + "0000000000000000"     // bytesReceived = 0
202             + "0A000000"         // SegsOut = 10
203             + "00000000"         // SegsIn = 0
204             + "00000000"         // NotSentBytes = 0
205             + "3E2C0900"         // minRtt = 601150
206             + "00000000"         // DataSegsIn = 0
207             + "00000000"         // DataSegsOut = 0
208             + "0000000000000000"; // deliverRate = 0
209     private static final String SOCK_DIAG_NO_TCP_INET_HEX =
210             // struct nlmsghdr
211             "14000000"     // length = 20
212             + "0300"         // type = NLMSG_DONE
213             + "0301"         // flags = NLM_F_REQUEST | NLM_F_DUMP
214             + "00000000"     // seqno
215             + "00000000"     // pid (0 == kernel)
216             // struct inet_diag_req_v2
217             + "02"           // family = AF_INET
218             + "06"           // state
219             + "00"           // timer
220             + "00";          // retrans
221     private static final byte[] SOCK_DIAG_NO_TCP_INET_BYTES =
222             HexEncoding.decode(SOCK_DIAG_NO_TCP_INET_HEX.toCharArray(), false);
223     private static final String TEST_RESPONSE_HEX =
224             SOCK_DIAG_TCP_INET_HEX + SOCK_DIAG_NO_TCP_INET_HEX;
225     private static final byte[] TEST_RESPONSE_BYTES =
226             HexEncoding.decode(TEST_RESPONSE_HEX.toCharArray(), false);
227 
228     private static class TestKeepaliveInfo {
229         private static List<Socket> sOpenSockets = new ArrayList<>();
230 
closeAllSockets()231         public static void closeAllSockets() throws Exception {
232             for (final Socket socket : sOpenSockets) {
233                 socket.close();
234             }
235             sOpenSockets.clear();
236         }
237 
238         public final Socket socket;
239         public final Binder binder;
240         public final FileDescriptor fd;
241         public final ISocketKeepaliveCallback socketKeepaliveCallback;
242         public final Network underpinnedNetwork;
243         public final KeepalivePacketData kpd;
244 
TestKeepaliveInfo(KeepalivePacketData kpd)245         TestKeepaliveInfo(KeepalivePacketData kpd) throws Exception {
246             this.kpd = kpd;
247             socket = new Socket();
248             socket.bind(null);
249             sOpenSockets.add(socket);
250             fd = socket.getFileDescriptor$();
251 
252             binder = new Binder();
253             socketKeepaliveCallback = mock(ISocketKeepaliveCallback.class);
254             doReturn(binder).when(socketKeepaliveCallback).asBinder();
255             underpinnedNetwork = mock(Network.class);
256         }
257     }
258 
259     private class TestKeepaliveTracker extends KeepaliveTracker {
260         private KeepaliveInfo mKi;
261 
TestKeepaliveTracker(@onNull final Context context, @NonNull final Handler handler, @NonNull final TcpKeepaliveController tcpController)262         TestKeepaliveTracker(@NonNull final Context context, @NonNull final Handler handler,
263                 @NonNull final TcpKeepaliveController tcpController) {
264             super(context, handler, tcpController, mKeepaliveTrackerDeps);
265         }
266 
setReturnedKeepaliveInfo(@onNull final KeepaliveInfo ki)267         public void setReturnedKeepaliveInfo(@NonNull final KeepaliveInfo ki) {
268             mKi = ki;
269         }
270 
271         @NonNull
272         @Override
makeNattKeepaliveInfo(@ullable final NetworkAgentInfo nai, @Nullable final FileDescriptor fd, final int intervalSeconds, @NonNull final ISocketKeepaliveCallback cb, @NonNull final String srcAddrString, final int srcPort, @NonNull final String dstAddrString, final int dstPort)273         public KeepaliveInfo makeNattKeepaliveInfo(@Nullable final NetworkAgentInfo nai,
274                 @Nullable final FileDescriptor fd, final int intervalSeconds,
275                 @NonNull final ISocketKeepaliveCallback cb, @NonNull final String srcAddrString,
276                 final int srcPort,
277                 @NonNull final String dstAddrString, final int dstPort) {
278             if (null == mKi) {
279                 throw new IllegalStateException("Must call setReturnedKeepaliveInfo");
280             }
281             return mKi;
282         }
283 
284         @NonNull
285         @Override
makeTcpKeepaliveInfo(@ullable final NetworkAgentInfo nai, @Nullable final FileDescriptor fd, final int intervalSeconds, @NonNull final ISocketKeepaliveCallback cb)286         public KeepaliveInfo makeTcpKeepaliveInfo(@Nullable final NetworkAgentInfo nai,
287                 @Nullable final FileDescriptor fd, final int intervalSeconds,
288                 @NonNull final ISocketKeepaliveCallback cb) {
289             if (null == mKi) {
290                 throw new IllegalStateException("Please call `setReturnedKeepaliveInfo`"
291                         + " before makeTcpKeepaliveInfo is called");
292             }
293             return mKi;
294         }
295     }
296 
297     private static class TestTcpKeepaliveController extends TcpKeepaliveController {
TestTcpKeepaliveController(final Handler connectivityServiceHandler)298         TestTcpKeepaliveController(final Handler connectivityServiceHandler) {
299             super(connectivityServiceHandler);
300         }
301     }
302 
mockService(String serviceName, Class<T> serviceClass, T service)303     private <T> void mockService(String serviceName, Class<T> serviceClass, T service) {
304         doReturn(serviceName).when(mCtx).getSystemServiceName(serviceClass);
305         doReturn(service).when(mCtx).getSystemService(serviceName);
306         if (mCtx.getSystemService(serviceClass) == null) {
307             // Test is using mockito-extended
308             doCallRealMethod().when(mCtx).getSystemService(serviceClass);
309         }
310     }
311 
312     @Before
setup()313     public void setup() throws Exception {
314         MockitoAnnotations.initMocks(this);
315 
316         mockService(Context.TELEPHONY_SUBSCRIPTION_SERVICE, SubscriptionManager.class,
317                 mSubscriptionManager);
318 
319         mNai.networkCapabilities =
320                 new NetworkCapabilities.Builder().addTransportType(TRANSPORT_CELLULAR).build();
321         mNai.networkInfo = new NetworkInfo(TYPE_MOBILE, 0 /* subtype */, "LTE", "LTE");
322         mNai.networkInfo.setDetailedState(
323                 NetworkInfo.DetailedState.CONNECTED, "test reason", "test extra info");
324         doReturn(new Network(TEST_NETID)).when(mNai).network();
325         mNai.linkProperties = new LinkProperties();
326         doReturn(null).when(mNai).translateV4toClatV6(any());
327         doReturn(null).when(mNai).getClatv6SrcAddress();
328 
329         doReturn(PERMISSION_GRANTED).when(mCtx).checkPermission(any() /* permission */,
330                 anyInt() /* pid */, anyInt() /* uid */);
331         ConnectivityResources.setResourcesContextForTest(mCtx);
332         final Resources mockResources = mock(Resources.class);
333         doReturn(mockResources).when(mCtx).getResources();
334         doReturn(mNetd).when(mDependencies).getNetd();
335         doReturn(mAlarmManager).when(mDependencies).getAlarmManager(any());
336         doReturn(makeMarkMaskParcel(NETID_MASK, TEST_NETID_FWMARK)).when(mNetd)
337                 .getFwmarkForNetwork(TEST_NETID);
338 
339         doNothing().when(mDependencies).sendRequest(any(), any());
340         doReturn(true).when(mKeepaliveTrackerDeps).isAddressTranslationEnabled(mCtx);
341         doReturn(new ConnectivityResources(mCtx)).when(mKeepaliveTrackerDeps)
342                 .createConnectivityResources(mCtx);
343         doReturn(new int[] {3, 0, 0, 3}).when(mKeepaliveTrackerDeps).getSupportedKeepalives(mCtx);
344 
345         mHandlerThread = new HandlerThread("KeepaliveTrackerTest");
346         mHandlerThread.start();
347         mTestHandler = new AOOTestHandler(mHandlerThread.getLooper());
348         mTcpController = new TestTcpKeepaliveController(mTestHandler);
349         mKeepaliveTracker = new TestKeepaliveTracker(mCtx, mTestHandler, mTcpController);
350         mKeepaliveStatsTracker = spy(new KeepaliveStatsTracker(mCtx, mTestHandler));
351         doReturn(mKeepaliveTracker).when(mDependencies).newKeepaliveTracker(mCtx, mTestHandler);
352         doReturn(mKeepaliveStatsTracker)
353                 .when(mDependencies)
354                 .newKeepaliveStatsTracker(mCtx, mTestHandler);
355 
356         doReturn(true).when(mDependencies).isTetheringFeatureNotChickenedOut(any());
357         doReturn(0L).when(mDependencies).getElapsedRealtime();
358         mAOOKeepaliveTracker =
359                 new AutomaticOnOffKeepaliveTracker(mCtx, mTestHandler, mDependencies);
360     }
361 
362     @After
teardown()363     public void teardown() throws Exception {
364         TestKeepaliveInfo.closeAllSockets();
365         if (mHandlerThread != null) {
366             mHandlerThread.quitSafely();
367             mHandlerThread.join();
368         }
369     }
370 
371     private final class AOOTestHandler extends Handler {
372         public AutomaticOnOffKeepaliveTracker.AutomaticOnOffKeepalive mLastAutoKi = null;
373 
AOOTestHandler(@onNull final Looper looper)374         AOOTestHandler(@NonNull final Looper looper) {
375             super(looper);
376         }
377 
378         @Override
handleMessage(@onNull final Message msg)379         public void handleMessage(@NonNull final Message msg) {
380             switch (msg.what) {
381                 case AutomaticOnOffKeepaliveTracker.CMD_REQUEST_START_KEEPALIVE:
382                     Log.d(TAG, "Test handler received CMD_REQUEST_START_KEEPALIVE : " + msg);
383                     mAOOKeepaliveTracker.handleStartKeepalive(msg);
384                     break;
385                 case AutomaticOnOffKeepaliveTracker.CMD_MONITOR_AUTOMATIC_KEEPALIVE:
386                     Log.d(TAG, "Test handler received CMD_MONITOR_AUTOMATIC_KEEPALIVE : " + msg);
387                     mLastAutoKi = mAOOKeepaliveTracker.getKeepaliveForBinder((IBinder) msg.obj);
388                     break;
389                 case CMD_STOP_SOCKET_KEEPALIVE:
390                     Log.d(TAG, "Test handler received CMD_STOP_SOCKET_KEEPALIVE : " + msg);
391                     mLastAutoKi = mAOOKeepaliveTracker.getKeepaliveForBinder((IBinder) msg.obj);
392                     if (mLastAutoKi == null) {
393                         fail("Attempt to stop an already stopped keepalive");
394                     }
395                     mAOOKeepaliveTracker.handleStopKeepalive(mLastAutoKi, msg.arg2);
396                     break;
397             }
398         }
399     }
400 
401     @Test
testIsAnyTcpSocketConnected_runOnNonHandlerThread()402     public void testIsAnyTcpSocketConnected_runOnNonHandlerThread() throws Exception {
403         setupResponseWithSocketExisting();
404         assertThrows(IllegalStateException.class,
405                 () -> mAOOKeepaliveTracker.isAnyTcpSocketConnected(TEST_NETID));
406     }
407 
408     @Test
testIsAnyTcpSocketConnected_withTargetNetId()409     public void testIsAnyTcpSocketConnected_withTargetNetId() throws Exception {
410         setupResponseWithSocketExisting();
411         assertTrue(visibleOnHandlerThread(mTestHandler,
412                 () -> mAOOKeepaliveTracker.isAnyTcpSocketConnected(TEST_NETID)));
413     }
414 
415     @Test
testIsAnyTcpSocketConnected_withIncorrectNetId()416     public void testIsAnyTcpSocketConnected_withIncorrectNetId() throws Exception {
417         setupResponseWithSocketExisting();
418         assertFalse(visibleOnHandlerThread(mTestHandler,
419                 () -> mAOOKeepaliveTracker.isAnyTcpSocketConnected(OTHER_NETID)));
420     }
421 
422     @Test
testIsAnyTcpSocketConnected_noSocketExists()423     public void testIsAnyTcpSocketConnected_noSocketExists() throws Exception {
424         setupResponseWithoutSocketExisting();
425         assertFalse(visibleOnHandlerThread(mTestHandler,
426                 () -> mAOOKeepaliveTracker.isAnyTcpSocketConnected(TEST_NETID)));
427     }
428 
triggerEventKeepalive(int slot, int reason)429     private void triggerEventKeepalive(int slot, int reason) {
430         visibleOnHandlerThread(
431                 mTestHandler,
432                 () -> mAOOKeepaliveTracker.handleEventSocketKeepalive(mNai, slot, reason));
433     }
434 
doStartNattKeepalive(int intervalSeconds)435     private TestKeepaliveInfo doStartNattKeepalive(int intervalSeconds) throws Exception {
436         final InetAddress srcAddress = InetAddress.getByAddress(V4_SRC_ADDR);
437         final int srcPort = 12345;
438         final InetAddress dstAddress = InetAddress.getByAddress(new byte[] {8, 8, 8, 8});
439         final int dstPort = 12345;
440 
441         mNai.linkProperties.addLinkAddress(new LinkAddress(srcAddress, 24));
442 
443         final NattKeepalivePacketData kpd = new NattKeepalivePacketData(srcAddress, srcPort,
444                 dstAddress, dstPort, new byte[] {1});
445 
446         final TestKeepaliveInfo testInfo = new TestKeepaliveInfo(kpd);
447 
448         final KeepaliveInfo ki = mKeepaliveTracker.new KeepaliveInfo(
449                 testInfo.socketKeepaliveCallback, mNai, kpd, intervalSeconds,
450                 KeepaliveInfo.TYPE_NATT, testInfo.fd);
451         mKeepaliveTracker.setReturnedKeepaliveInfo(ki);
452 
453         mAOOKeepaliveTracker.startNattKeepalive(mNai, testInfo.fd, intervalSeconds,
454                 testInfo.socketKeepaliveCallback, srcAddress.toString(), srcPort,
455                 dstAddress.toString(), dstPort, true /* automaticOnOffKeepalives */,
456                 testInfo.underpinnedNetwork);
457         HandlerUtils.waitForIdle(mTestHandler, TIMEOUT_MS);
458 
459         return testInfo;
460     }
461 
doStartNattKeepalive()462     private TestKeepaliveInfo doStartNattKeepalive() throws Exception {
463         return doStartNattKeepalive(TEST_KEEPALIVE_INTERVAL_SEC);
464     }
465 
doPauseKeepalive(AutomaticOnOffKeepalive autoKi)466     private void doPauseKeepalive(AutomaticOnOffKeepalive autoKi) throws Exception {
467         setupResponseWithoutSocketExisting();
468         visibleOnHandlerThread(
469                 mTestHandler,
470                 () -> mAOOKeepaliveTracker.handleMonitorAutomaticKeepalive(autoKi, TEST_NETID));
471     }
472 
doResumeKeepalive(AutomaticOnOffKeepalive autoKi)473     private void doResumeKeepalive(AutomaticOnOffKeepalive autoKi) throws Exception {
474         setupResponseWithSocketExisting();
475         visibleOnHandlerThread(
476                 mTestHandler,
477                 () -> mAOOKeepaliveTracker.handleMonitorAutomaticKeepalive(autoKi, TEST_NETID));
478     }
479 
doStopKeepalive(AutomaticOnOffKeepalive autoKi)480     private void doStopKeepalive(AutomaticOnOffKeepalive autoKi) throws Exception {
481         visibleOnHandlerThread(
482                 mTestHandler,
483                 () -> mAOOKeepaliveTracker.handleStopKeepalive(autoKi, SocketKeepalive.SUCCESS));
484     }
485 
486     @Test
testAlarm()487     public void testAlarm() throws Exception {
488         // Mock elapsed real time to verify the alarm timer.
489         final long time = SystemClock.elapsedRealtime();
490         doReturn(time).when(mDependencies).getElapsedRealtime();
491         final TestKeepaliveInfo testInfo = doStartNattKeepalive();
492 
493         final ArgumentCaptor<AlarmManager.OnAlarmListener> listenerCaptor =
494                 ArgumentCaptor.forClass(AlarmManager.OnAlarmListener.class);
495         // The alarm timer should be smaller than the keepalive delay. Verify the alarm trigger time
496         // is higher than base time but smaller than the keepalive delay.
497         verify(mAlarmManager).setExact(eq(AlarmManager.ELAPSED_REALTIME),
498                 longThat(t -> t > time + 1000L && t < time + TEST_KEEPALIVE_INTERVAL_SEC * 1000L),
499                 any() /* tag */, listenerCaptor.capture(), eq(mTestHandler));
500         final AlarmManager.OnAlarmListener listener = listenerCaptor.getValue();
501 
502         // For realism, the listener should be posted on the handler
503         visibleOnHandlerThread(mTestHandler, () -> listener.onAlarm());
504         // Wait for the message posted by the listener to be processed.
505         HandlerUtils.waitForIdle(mTestHandler, TIMEOUT_MS);
506 
507         assertNotNull(mTestHandler.mLastAutoKi);
508         assertEquals(testInfo.socketKeepaliveCallback, mTestHandler.mLastAutoKi.getCallback());
509         assertEquals(testInfo.underpinnedNetwork, mTestHandler.mLastAutoKi.getUnderpinnedNetwork());
510     }
511 
512     @Test
testAlarm_writeMetrics()513     public void testAlarm_writeMetrics() throws Exception {
514         final ArgumentCaptor<AlarmManager.OnAlarmListener> listenerCaptor =
515                 ArgumentCaptor.forClass(AlarmManager.OnAlarmListener.class);
516 
517         // First AlarmManager.set call from the constructor.
518         verify(mAlarmManager).set(eq(AlarmManager.ELAPSED_REALTIME_WAKEUP),
519                 eq(METRICS_COLLECTION_DURATION_MS), any() /* tag */, listenerCaptor.capture(),
520                 eq(mTestHandler));
521 
522         final AlarmManager.OnAlarmListener listener = listenerCaptor.getValue();
523 
524         doReturn(METRICS_COLLECTION_DURATION_MS).when(mDependencies).getElapsedRealtime();
525         // For realism, the listener should be posted on the handler
526         visibleOnHandlerThread(mTestHandler, () -> listener.onAlarm());
527 
528         verify(mKeepaliveStatsTracker).writeAndResetMetrics();
529         // Alarm is rescheduled.
530         verify(mAlarmManager).set(eq(AlarmManager.ELAPSED_REALTIME_WAKEUP),
531                 eq(METRICS_COLLECTION_DURATION_MS * 2),
532                 any() /* tag */, listenerCaptor.capture(), eq(mTestHandler));
533     }
534 
setupResponseWithSocketExisting()535     private void setupResponseWithSocketExisting() throws Exception {
536         final ByteBuffer tcpBufferV6 = getByteBuffer(TEST_RESPONSE_BYTES);
537         final ByteBuffer tcpBufferV4 = getByteBuffer(TEST_RESPONSE_BYTES);
538         doReturn(tcpBufferV6, tcpBufferV4).when(mDependencies).recvSockDiagResponse(any());
539     }
540 
setupResponseWithoutSocketExisting()541     private void setupResponseWithoutSocketExisting() throws Exception {
542         final ByteBuffer tcpBufferV6 = getByteBuffer(SOCK_DIAG_NO_TCP_INET_BYTES);
543         final ByteBuffer tcpBufferV4 = getByteBuffer(SOCK_DIAG_NO_TCP_INET_BYTES);
544         doReturn(tcpBufferV6, tcpBufferV4).when(mDependencies).recvSockDiagResponse(any());
545     }
546 
makeMarkMaskParcel(final int mask, final int mark)547     private MarkMaskParcel makeMarkMaskParcel(final int mask, final int mark) {
548         final MarkMaskParcel parcel = new MarkMaskParcel();
549         parcel.mask = mask;
550         parcel.mark = mark;
551         return parcel;
552     }
553 
getByteBuffer(final byte[] bytes)554     private ByteBuffer getByteBuffer(final byte[] bytes) {
555         final ByteBuffer buffer = ByteBuffer.wrap(bytes);
556         buffer.order(ByteOrder.nativeOrder());
557         return buffer;
558     }
559 
getAutoKiForBinder(IBinder binder)560     private AutomaticOnOffKeepalive getAutoKiForBinder(IBinder binder) {
561         return visibleOnHandlerThread(
562                 mTestHandler, () -> mAOOKeepaliveTracker.getKeepaliveForBinder(binder));
563     }
564 
checkAndProcessKeepaliveStart(final KeepalivePacketData kpd)565     private void checkAndProcessKeepaliveStart(final KeepalivePacketData kpd) throws Exception {
566         checkAndProcessKeepaliveStart(TEST_SLOT, kpd);
567     }
568 
checkAndProcessKeepaliveStart( int slot, final KeepalivePacketData kpd)569     private void checkAndProcessKeepaliveStart(
570             int slot, final KeepalivePacketData kpd) throws Exception {
571         verify(mNai).onStartNattSocketKeepalive(
572                 slot, TEST_KEEPALIVE_INTERVAL_SEC, (NattKeepalivePacketData) kpd);
573         verify(mNai).onAddNattKeepalivePacketFilter(slot, (NattKeepalivePacketData) kpd);
574         triggerEventKeepalive(slot, SocketKeepalive.SUCCESS);
575     }
576 
checkAndProcessKeepaliveStop()577     private void checkAndProcessKeepaliveStop() throws Exception {
578         checkAndProcessKeepaliveStop(TEST_SLOT);
579     }
580 
checkAndProcessKeepaliveStop(int slot)581     private void checkAndProcessKeepaliveStop(int slot) throws Exception {
582         verify(mNai).onStopSocketKeepalive(slot);
583         verify(mNai).onRemoveKeepalivePacketFilter(slot);
584         triggerEventKeepalive(slot, SocketKeepalive.SUCCESS);
585     }
586 
587     @Test
testStartNattKeepalive_valid()588     public void testStartNattKeepalive_valid() throws Exception {
589         final TestKeepaliveInfo testInfo = doStartNattKeepalive();
590 
591         checkAndProcessKeepaliveStart(testInfo.kpd);
592 
593         final AutomaticOnOffKeepalive autoKi = getAutoKiForBinder(testInfo.binder);
594         assertNotNull(autoKi);
595         assertEquals(testInfo.socketKeepaliveCallback, autoKi.getCallback());
596 
597         verify(testInfo.socketKeepaliveCallback).onStarted();
598         verifyNoMoreInteractions(ignoreStubs(testInfo.socketKeepaliveCallback));
599     }
600 
601     @Test
testStartNattKeepalive_invalidInterval()602     public void testStartNattKeepalive_invalidInterval() throws Exception {
603         final TestKeepaliveInfo testInfo =
604                 doStartNattKeepalive(TEST_KEEPALIVE_INVALID_INTERVAL_SEC);
605 
606         assertNull(getAutoKiForBinder(testInfo.binder));
607 
608         verify(testInfo.socketKeepaliveCallback).onError(SocketKeepalive.ERROR_INVALID_INTERVAL);
609         verifyNoMoreInteractions(ignoreStubs(testInfo.socketKeepaliveCallback));
610     }
611 
setupTestNaiForClat(InetAddress v6Src, InetAddress v6Dst)612     private void setupTestNaiForClat(InetAddress v6Src, InetAddress v6Dst) throws Exception {
613         doReturn(v6Dst).when(mNai).translateV4toClatV6(any());
614         doReturn(v6Src).when(mNai).getClatv6SrcAddress();
615         doReturn(InetAddress.getByAddress(V4_SRC_ADDR)).when(mNai).getClatv4SrcAddress();
616         // Setup nai to add clat address
617         final LinkProperties stacked = new LinkProperties();
618         stacked.setInterfaceName(TEST_V4_IFACE);
619         final InetAddress srcAddress = InetAddress.getByAddress(
620                 new byte[] { (byte) 192, 0, 0, (byte) 129 });
621         mNai.linkProperties.addLinkAddress(new LinkAddress(srcAddress, 24));
622         mNai.linkProperties.addStackedLink(stacked);
623     }
624 
doStartTcpKeepalive(InetAddress srcAddr)625     private TestKeepaliveInfo doStartTcpKeepalive(InetAddress srcAddr) throws Exception {
626         final KeepalivePacketData kpd = new TcpKeepalivePacketData(
627                 srcAddr,
628                 12345 /* srcPort */,
629                 InetAddress.getByAddress(new byte[] { 8, 8, 8, 8}) /* dstAddr */,
630                 12345 /* dstPort */, new byte[] {1},  111 /* tcpSeq */,
631                 222 /* tcpAck */, 800 /* tcpWindow */, 2 /* tcpWindowScale */,
632                 4 /* ipTos */, 64 /* ipTtl */);
633         final TestKeepaliveInfo testInfo = new TestKeepaliveInfo(kpd);
634 
635         final KeepaliveInfo ki = mKeepaliveTracker.new KeepaliveInfo(
636                 testInfo.socketKeepaliveCallback, mNai, kpd,
637                 TEST_KEEPALIVE_INTERVAL_SEC, KeepaliveInfo.TYPE_TCP, testInfo.fd);
638         mKeepaliveTracker.setReturnedKeepaliveInfo(ki);
639 
640         // Setup TCP keepalive.
641         mAOOKeepaliveTracker.startTcpKeepalive(mNai, testInfo.fd, TEST_KEEPALIVE_INTERVAL_SEC,
642                 testInfo.socketKeepaliveCallback);
643         HandlerUtils.waitForIdle(mTestHandler, TIMEOUT_MS);
644         return testInfo;
645     }
646     @Test
testStartTcpKeepalive_addressTranslationOnClat()647     public void testStartTcpKeepalive_addressTranslationOnClat() throws Exception {
648         setupTestNaiForClat(InetAddresses.parseNumericAddress("2001:db8::1") /* v6Src */,
649                 InetAddresses.parseNumericAddress("2001:db8::2") /* v6Dst */);
650         final InetAddress srcAddr = InetAddress.getByAddress(V4_SRC_ADDR);
651         doStartTcpKeepalive(srcAddr);
652         final ArgumentCaptor<TcpKeepalivePacketData> tpdCaptor =
653                 ArgumentCaptor.forClass(TcpKeepalivePacketData.class);
654         verify(mNai).onStartTcpSocketKeepalive(
655                 eq(TEST_SLOT), eq(TEST_KEEPALIVE_INTERVAL_SEC), tpdCaptor.capture());
656         final TcpKeepalivePacketData tpd = tpdCaptor.getValue();
657         // Verify the addresses still be the same address when clat is started.
658         assertEquals(srcAddr, tpd.getSrcAddress());
659     }
660 
661     @Test
testStartNattKeepalive_addressTranslationOnClatNotSupported()662     public void testStartNattKeepalive_addressTranslationOnClatNotSupported() throws Exception {
663         // Disable address translation feature and verify the behavior
664         doReturn(false).when(mKeepaliveTrackerDeps).isAddressTranslationEnabled(mCtx);
665 
666         setupTestNaiForClat(InetAddresses.parseNumericAddress("2001:db8::1"),
667                 InetAddresses.parseNumericAddress("2001:db8::2"));
668 
669         doStartNattKeepalive();
670         final ArgumentCaptor<NattKeepalivePacketData> kpdCaptor =
671                 ArgumentCaptor.forClass(NattKeepalivePacketData.class);
672         verify(mNai).onStartNattSocketKeepalive(
673                 eq(TEST_SLOT), eq(TEST_KEEPALIVE_INTERVAL_SEC), kpdCaptor.capture());
674         // Verify that address translation is not triggered so the addresses are still v4.
675         final NattKeepalivePacketData kpd = kpdCaptor.getValue();
676         assertTrue(kpd.getSrcAddress() instanceof Inet4Address);
677         assertTrue(kpd.getDstAddress() instanceof Inet4Address);
678     }
679 
680     @Test
testStartNattKeepalive_addressTranslationOnClat()681     public void testStartNattKeepalive_addressTranslationOnClat() throws Exception {
682         final InetAddress v6AddrSrc = InetAddresses.parseNumericAddress("2001:db8::1");
683         final InetAddress v6AddrDst = InetAddresses.parseNumericAddress("2001:db8::2");
684         setupTestNaiForClat(v6AddrSrc, v6AddrDst);
685 
686         final TestKeepaliveInfo testInfo = doStartNattKeepalive();
687         final ArgumentCaptor<NattKeepalivePacketData> kpdCaptor =
688                 ArgumentCaptor.forClass(NattKeepalivePacketData.class);
689         verify(mNai).onStartNattSocketKeepalive(
690                 eq(TEST_SLOT), eq(TEST_KEEPALIVE_INTERVAL_SEC), kpdCaptor.capture());
691         final NattKeepalivePacketData kpd = kpdCaptor.getValue();
692         // Verify the addresses are updated to v6 when clat is started.
693         assertEquals(v6AddrSrc, kpd.getSrcAddress());
694         assertEquals(v6AddrDst, kpd.getDstAddress());
695 
696         triggerEventKeepalive(TEST_SLOT, SocketKeepalive.SUCCESS);
697         verify(testInfo.socketKeepaliveCallback).onStarted();
698 
699         // Remove clat address should stop the keepalive.
700         doReturn(null).when(mNai).getClatv6SrcAddress();
701         visibleOnHandlerThread(
702                 mTestHandler, () -> mAOOKeepaliveTracker.handleCheckKeepalivesStillValid(mNai));
703         checkAndProcessKeepaliveStop();
704         assertNull(getAutoKiForBinder(testInfo.binder));
705 
706         verify(testInfo.socketKeepaliveCallback).onError(SocketKeepalive.ERROR_INVALID_IP_ADDRESS);
707         verifyNoMoreInteractions(ignoreStubs(testInfo.socketKeepaliveCallback));
708     }
709 
710     @Test
testHandleEventSocketKeepalive_startingFailureHardwareError()711     public void testHandleEventSocketKeepalive_startingFailureHardwareError() throws Exception {
712         final TestKeepaliveInfo testInfo = doStartNattKeepalive();
713 
714         verify(mNai).onStartNattSocketKeepalive(
715                 TEST_SLOT, TEST_KEEPALIVE_INTERVAL_SEC, (NattKeepalivePacketData) testInfo.kpd);
716         verify(mNai).onAddNattKeepalivePacketFilter(
717                 TEST_SLOT, (NattKeepalivePacketData) testInfo.kpd);
718         // Network agent returns an error, fails to start the keepalive.
719         triggerEventKeepalive(TEST_SLOT, SocketKeepalive.ERROR_HARDWARE_ERROR);
720 
721         checkAndProcessKeepaliveStop();
722 
723         assertNull(getAutoKiForBinder(testInfo.binder));
724 
725         verify(testInfo.socketKeepaliveCallback).onError(SocketKeepalive.ERROR_HARDWARE_ERROR);
726         verifyNoMoreInteractions(ignoreStubs(testInfo.socketKeepaliveCallback));
727     }
728 
729     @Test
testHandleCheckKeepalivesStillValid_linkPropertiesChanged()730     public void testHandleCheckKeepalivesStillValid_linkPropertiesChanged() throws Exception {
731         // Successful start of NATT keepalive.
732         final TestKeepaliveInfo testInfo = doStartNattKeepalive();
733         checkAndProcessKeepaliveStart(testInfo.kpd);
734         verify(testInfo.socketKeepaliveCallback).onStarted();
735 
736         // Source address is removed from link properties by clearing.
737         mNai.linkProperties.clear();
738 
739         // Check for valid keepalives
740         visibleOnHandlerThread(
741                 mTestHandler, () -> mAOOKeepaliveTracker.handleCheckKeepalivesStillValid(mNai));
742 
743         checkAndProcessKeepaliveStop();
744 
745         assertNull(getAutoKiForBinder(testInfo.binder));
746 
747         verify(testInfo.socketKeepaliveCallback).onError(SocketKeepalive.ERROR_INVALID_IP_ADDRESS);
748         verifyNoMoreInteractions(ignoreStubs(testInfo.socketKeepaliveCallback));
749     }
750 
751     @Test
testStopKeepalive()752     public void testStopKeepalive() throws Exception {
753         // Successful start of NATT keepalive.
754         final TestKeepaliveInfo testInfo = doStartNattKeepalive();
755         checkAndProcessKeepaliveStart(testInfo.kpd);
756         verify(testInfo.socketKeepaliveCallback).onStarted();
757 
758         doStopKeepalive(getAutoKiForBinder(testInfo.binder));
759         checkAndProcessKeepaliveStop();
760 
761         assertNull(getAutoKiForBinder(testInfo.binder));
762         verify(testInfo.socketKeepaliveCallback).onStopped();
763         verifyNoMoreInteractions(ignoreStubs(testInfo.socketKeepaliveCallback));
764     }
765 
766     @Test
testPauseKeepalive()767     public void testPauseKeepalive() throws Exception {
768         // Successful start of NATT keepalive.
769         final TestKeepaliveInfo testInfo = doStartNattKeepalive();
770         checkAndProcessKeepaliveStart(testInfo.kpd);
771         verify(testInfo.socketKeepaliveCallback).onStarted();
772 
773         doPauseKeepalive(getAutoKiForBinder(testInfo.binder));
774 
775         checkAndProcessKeepaliveStop();
776         verify(testInfo.socketKeepaliveCallback).onPaused();
777 
778         // Pausing does not cleanup the autoKi
779         assertNotNull(getAutoKiForBinder(testInfo.binder));
780 
781         clearInvocations(mNai);
782         doStopKeepalive(getAutoKiForBinder(testInfo.binder));
783         // The keepalive is already stopped.
784         verify(mNai, never()).onStopSocketKeepalive(TEST_SLOT);
785         verify(mNai, never()).onRemoveKeepalivePacketFilter(TEST_SLOT);
786 
787         // Stopping while paused still calls onStopped.
788         verify(testInfo.socketKeepaliveCallback).onStopped();
789         // autoKi is cleaned up.
790         assertNull(getAutoKiForBinder(testInfo.binder));
791 
792         verifyNoMoreInteractions(ignoreStubs(testInfo.socketKeepaliveCallback));
793 
794         // Make sure the slot is free
795         final TestKeepaliveInfo testInfo2 = doStartNattKeepalive();
796         checkAndProcessKeepaliveStart(testInfo2.kpd);
797     }
798 
799     @Test
testResumeKeepalive()800     public void testResumeKeepalive() throws Exception {
801         // Successful start of NATT keepalive.
802         final TestKeepaliveInfo testInfo = doStartNattKeepalive();
803         checkAndProcessKeepaliveStart(testInfo.kpd);
804         verify(testInfo.socketKeepaliveCallback).onStarted();
805 
806         doPauseKeepalive(getAutoKiForBinder(testInfo.binder));
807         checkAndProcessKeepaliveStop();
808         verify(testInfo.socketKeepaliveCallback).onPaused();
809 
810         clearInvocations(mNai);
811         doResumeKeepalive(getAutoKiForBinder(testInfo.binder));
812         checkAndProcessKeepaliveStart(testInfo.kpd);
813         assertNotNull(getAutoKiForBinder(testInfo.binder));
814         verify(testInfo.socketKeepaliveCallback).onResumed();
815 
816         doStopKeepalive(getAutoKiForBinder(testInfo.binder));
817         checkAndProcessKeepaliveStop();
818         assertNull(getAutoKiForBinder(testInfo.binder));
819 
820         verify(testInfo.socketKeepaliveCallback).onStopped();
821         verifyNoMoreInteractions(ignoreStubs(testInfo.socketKeepaliveCallback));
822     }
823 
824     @Test
testResumeKeepalive_invalidSourceAddress()825     public void testResumeKeepalive_invalidSourceAddress() throws Exception {
826         // Successful start of NATT keepalive.
827         final TestKeepaliveInfo testInfo = doStartNattKeepalive();
828         checkAndProcessKeepaliveStart(testInfo.kpd);
829         verify(testInfo.socketKeepaliveCallback).onStarted();
830 
831         doPauseKeepalive(getAutoKiForBinder(testInfo.binder));
832         checkAndProcessKeepaliveStop();
833         verify(testInfo.socketKeepaliveCallback).onPaused();
834 
835         mNai.linkProperties.clear();
836 
837         clearInvocations(mNai);
838         doResumeKeepalive(getAutoKiForBinder(testInfo.binder));
839         verify(mNai, never()).onStartNattSocketKeepalive(anyInt(), anyInt(), any());
840         verify(mNai, never()).onAddNattKeepalivePacketFilter(anyInt(), any());
841 
842         assertNull(getAutoKiForBinder(testInfo.binder));
843 
844         verify(testInfo.socketKeepaliveCallback).onError(SocketKeepalive.ERROR_INVALID_IP_ADDRESS);
845         verifyNoMoreInteractions(ignoreStubs(testInfo.socketKeepaliveCallback));
846     }
847 
848     @Test
testResumeKeepalive_startingFailureHardwareError()849     public void testResumeKeepalive_startingFailureHardwareError() throws Exception {
850         // Successful start of NATT keepalive.
851         final TestKeepaliveInfo testInfo = doStartNattKeepalive();
852         checkAndProcessKeepaliveStart(testInfo.kpd);
853         verify(testInfo.socketKeepaliveCallback).onStarted();
854 
855         doPauseKeepalive(getAutoKiForBinder(testInfo.binder));
856         checkAndProcessKeepaliveStop();
857         verify(testInfo.socketKeepaliveCallback).onPaused();
858 
859         clearInvocations(mNai);
860         doResumeKeepalive(getAutoKiForBinder(testInfo.binder));
861 
862         verify(mNai).onStartNattSocketKeepalive(
863                 TEST_SLOT, TEST_KEEPALIVE_INTERVAL_SEC, (NattKeepalivePacketData) testInfo.kpd);
864         verify(mNai).onAddNattKeepalivePacketFilter(
865                 TEST_SLOT, (NattKeepalivePacketData) testInfo.kpd);
866         // Network agent returns error on starting the keepalive.
867         triggerEventKeepalive(TEST_SLOT, SocketKeepalive.ERROR_HARDWARE_ERROR);
868 
869         checkAndProcessKeepaliveStop();
870 
871         assertNull(getAutoKiForBinder(testInfo.binder));
872         verify(testInfo.socketKeepaliveCallback).onError(SocketKeepalive.ERROR_HARDWARE_ERROR);
873         verifyNoMoreInteractions(ignoreStubs(testInfo.socketKeepaliveCallback));
874     }
875 
876     @Test
testStopAllKeepalives()877     public void testStopAllKeepalives() throws Exception {
878         final TestKeepaliveInfo testInfo1 = doStartNattKeepalive();
879         final TestKeepaliveInfo testInfo2 = doStartNattKeepalive();
880         checkAndProcessKeepaliveStart(TEST_SLOT, testInfo1.kpd);
881         checkAndProcessKeepaliveStart(TEST_SLOT + 1, testInfo2.kpd);
882 
883         verify(testInfo1.socketKeepaliveCallback).onStarted();
884         verify(testInfo2.socketKeepaliveCallback).onStarted();
885 
886         // Pause the first keepalive
887         doPauseKeepalive(getAutoKiForBinder(testInfo1.binder));
888         checkAndProcessKeepaliveStop(TEST_SLOT);
889         verify(testInfo1.socketKeepaliveCallback).onPaused();
890 
891         visibleOnHandlerThread(
892                 mTestHandler,
893                 () -> mAOOKeepaliveTracker.handleStopAllKeepalives(
894                         mNai, SocketKeepalive.ERROR_INVALID_NETWORK));
895 
896         // Note that checkAndProcessKeepaliveStop is not called since the network agent is assumed
897         // to be disconnected for a handleStopAllKeepalives call.
898         assertNull(getAutoKiForBinder(testInfo1.binder));
899         assertNull(getAutoKiForBinder(testInfo2.binder));
900 
901         verify(testInfo1.socketKeepaliveCallback, never()).onStopped();
902         verify(testInfo2.socketKeepaliveCallback, never()).onStopped();
903         verify(testInfo1.socketKeepaliveCallback).onError(SocketKeepalive.ERROR_INVALID_NETWORK);
904         verify(testInfo2.socketKeepaliveCallback).onError(SocketKeepalive.ERROR_INVALID_NETWORK);
905 
906         verifyNoMoreInteractions(ignoreStubs(testInfo1.socketKeepaliveCallback));
907         verifyNoMoreInteractions(ignoreStubs(testInfo2.socketKeepaliveCallback));
908     }
909 
910     @Test
testTwoKeepalives_startAfterPause()911     public void testTwoKeepalives_startAfterPause() throws Exception {
912         final TestKeepaliveInfo testInfo1 = doStartNattKeepalive();
913         checkAndProcessKeepaliveStart(testInfo1.kpd);
914         verify(testInfo1.socketKeepaliveCallback).onStarted();
915         assertNotNull(getAutoKiForBinder(testInfo1.binder));
916 
917         final AutomaticOnOffKeepalive autoKi1  = getAutoKiForBinder(testInfo1.binder);
918         doPauseKeepalive(autoKi1);
919         checkAndProcessKeepaliveStop(TEST_SLOT);
920         verify(testInfo1.socketKeepaliveCallback).onPaused();
921         assertNotNull(getAutoKiForBinder(testInfo1.binder));
922 
923         clearInvocations(mNai);
924         // Start the second keepalive while the first is paused.
925         final TestKeepaliveInfo testInfo2 = doStartNattKeepalive();
926         // The slot used is TEST_SLOT + 1 since TEST_SLOT is being taken by the paused keepalive.
927         checkAndProcessKeepaliveStart(TEST_SLOT + 1, testInfo2.kpd);
928         verify(testInfo2.socketKeepaliveCallback).onStarted();
929         assertNotNull(getAutoKiForBinder(testInfo2.binder));
930 
931         clearInvocations(mNai);
932         doResumeKeepalive(autoKi1);
933         // Resume on TEST_SLOT.
934         checkAndProcessKeepaliveStart(TEST_SLOT, testInfo1.kpd);
935         verify(testInfo1.socketKeepaliveCallback).onResumed();
936 
937         clearInvocations(mNai);
938         doStopKeepalive(autoKi1);
939         checkAndProcessKeepaliveStop(TEST_SLOT);
940         verify(testInfo1.socketKeepaliveCallback).onStopped();
941         verify(testInfo2.socketKeepaliveCallback, never()).onStopped();
942         assertNull(getAutoKiForBinder(testInfo1.binder));
943 
944         clearInvocations(mNai);
945         assertNotNull(getAutoKiForBinder(testInfo2.binder));
946         doStopKeepalive(getAutoKiForBinder(testInfo2.binder));
947         checkAndProcessKeepaliveStop(TEST_SLOT + 1);
948         verify(testInfo2.socketKeepaliveCallback).onStopped();
949         assertNull(getAutoKiForBinder(testInfo2.binder));
950 
951         verifyNoMoreInteractions(ignoreStubs(testInfo1.socketKeepaliveCallback));
952         verifyNoMoreInteractions(ignoreStubs(testInfo2.socketKeepaliveCallback));
953     }
954 
955     @Test
testStartTcpKeepalive_fdInitiatedStop()956     public void testStartTcpKeepalive_fdInitiatedStop() throws Exception {
957         final InetAddress srcAddress = InetAddress.getByAddress(
958                 new byte[] { (byte) 192, 0, 0, (byte) 129 });
959         mNai.linkProperties.addLinkAddress(new LinkAddress(srcAddress, 24));
960 
961         final TestKeepaliveInfo testInfo =
962                 doStartTcpKeepalive(InetAddress.getByAddress(V4_SRC_ADDR));
963 
964         // A closed socket will result in EVENT_HANGUP and trigger error to
965         // FileDescriptorEventListener.
966         testInfo.socket.close();
967         HandlerUtils.waitForIdle(mTestHandler, TIMEOUT_MS);
968 
969         // The keepalive should be removed in AutomaticOnOffKeepaliveTracker.
970         assertNull(getAutoKiForBinder(testInfo.binder));
971     }
972 
973     @Test
testDumpDoesNotCrash()974     public void testDumpDoesNotCrash() throws Exception {
975         final TestKeepaliveInfo testInfo1 = doStartNattKeepalive();
976         final TestKeepaliveInfo testInfo2 = doStartNattKeepalive();
977         checkAndProcessKeepaliveStart(TEST_SLOT, testInfo1.kpd);
978         checkAndProcessKeepaliveStart(TEST_SLOT + 1, testInfo2.kpd);
979         final AutomaticOnOffKeepalive autoKi1  = getAutoKiForBinder(testInfo1.binder);
980         doPauseKeepalive(autoKi1);
981 
982         final StringWriter stringWriter = new StringWriter();
983         final IndentingPrintWriter pw = new IndentingPrintWriter(stringWriter, "   ");
984         visibleOnHandlerThread(mTestHandler, () -> mAOOKeepaliveTracker.dump(pw));
985         assertFalse(stringWriter.toString().isEmpty());
986     }
987 }
988