Merge "Bootstrap IpReachabilityMonitor unit tests" am: a9889c94aa
am: 39a707813b
Change-Id: Ie56377ae158d32a3592fd700e93fc827754ecaa3
diff --git a/services/net/java/android/net/ip/IpReachabilityMonitor.java b/services/net/java/android/net/ip/IpReachabilityMonitor.java
index 97c9d82..e833f6a 100644
--- a/services/net/java/android/net/ip/IpReachabilityMonitor.java
+++ b/services/net/java/android/net/ip/IpReachabilityMonitor.java
@@ -16,8 +16,6 @@
package android.net.ip;
-import com.android.internal.annotations.GuardedBy;
-
import android.content.Context;
import android.net.LinkAddress;
import android.net.LinkProperties;
@@ -31,18 +29,22 @@
import android.net.netlink.NetlinkMessage;
import android.net.netlink.NetlinkSocket;
import android.net.netlink.RtNetlinkNeighborMessage;
-import android.net.netlink.StructNdaCacheInfo;
import android.net.netlink.StructNdMsg;
+import android.net.netlink.StructNdaCacheInfo;
import android.net.netlink.StructNlMsgHdr;
import android.net.util.MultinetworkPolicyTracker;
import android.net.util.SharedLog;
import android.os.PowerManager;
+import android.os.PowerManager.WakeLock;
import android.os.SystemClock;
import android.system.ErrnoException;
import android.system.NetlinkSocketAddress;
import android.system.OsConstants;
import android.util.Log;
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+
import java.io.InterruptedIOException;
import java.net.Inet6Address;
import java.net.InetAddress;
@@ -147,12 +149,32 @@
public void notifyLost(InetAddress ip, String logMsg);
}
+ /**
+ * Encapsulates IpReachabilityMonitor depencencies on systems that hinder unit testing.
+ * TODO: consider also wrapping MultinetworkPolicyTracker in this interface.
+ */
+ interface Dependencies {
+ void acquireWakeLock(long durationMs);
+
+ static Dependencies makeDefault(Context context, String iface) {
+ final String lockName = TAG + "." + iface;
+ final PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
+ final WakeLock lock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, lockName);
+
+ return new Dependencies() {
+ public void acquireWakeLock(long durationMs) {
+ lock.acquire(durationMs);
+ }
+ };
+ }
+ }
+
private final Object mLock = new Object();
- private final PowerManager.WakeLock mWakeLock;
private final String mInterfaceName;
private final int mInterfaceIndex;
private final SharedLog mLog;
private final Callback mCallback;
+ private final Dependencies mDependencies;
private final MultinetworkPolicyTracker mMultinetworkPolicyTracker;
private final NetlinkSocketObserver mNetlinkSocketObserver;
private final Thread mObserverThread;
@@ -228,20 +250,20 @@
}
public IpReachabilityMonitor(Context context, String ifName, SharedLog log, Callback callback,
- MultinetworkPolicyTracker tracker) throws IllegalArgumentException {
+ MultinetworkPolicyTracker tracker) {
+ this(ifName, getInterfaceIndex(ifName), log, callback, tracker,
+ Dependencies.makeDefault(context, ifName));
+ }
+
+ @VisibleForTesting
+ IpReachabilityMonitor(String ifName, int ifIndex, SharedLog log, Callback callback,
+ MultinetworkPolicyTracker tracker, Dependencies dependencies) {
mInterfaceName = ifName;
- int ifIndex = -1;
- try {
- NetworkInterface netIf = NetworkInterface.getByName(ifName);
- mInterfaceIndex = netIf.getIndex();
- } catch (SocketException | NullPointerException e) {
- throw new IllegalArgumentException("invalid interface '" + ifName + "': ", e);
- }
- mWakeLock = ((PowerManager) context.getSystemService(Context.POWER_SERVICE)).newWakeLock(
- PowerManager.PARTIAL_WAKE_LOCK, TAG + "." + mInterfaceName);
mLog = log.forSubComponent(TAG);
mCallback = callback;
mMultinetworkPolicyTracker = tracker;
+ mInterfaceIndex = ifIndex;
+ mDependencies = dependencies;
mNetlinkSocketObserver = new NetlinkSocketObserver();
mObserverThread = new Thread(mNetlinkSocketObserver);
mObserverThread.start();
@@ -398,7 +420,7 @@
// The wakelock we use is (by default) refcounted, and this version
// of acquire(timeout) queues a release message to keep acquisitions
// and releases balanced.
- mWakeLock.acquire(getProbeWakeLockDuration());
+ mDependencies.acquireWakeLock(getProbeWakeLockDuration());
}
for (InetAddress target : ipProbeList) {
@@ -429,6 +451,19 @@
return (numUnicastProbes * retransTimeMs) + gracePeriodMs;
}
+ private static int getInterfaceIndex(String ifname) {
+ final NetworkInterface iface;
+ try {
+ iface = NetworkInterface.getByName(ifname);
+ } catch (SocketException e) {
+ throw new IllegalArgumentException("invalid interface '" + ifname + "': ", e);
+ }
+ if (iface == null) {
+ throw new IllegalArgumentException("NetworkInterface was null for " + ifname);
+ }
+ return iface.getIndex();
+ }
+
private void logEvent(int probeType, int errorCode) {
int eventType = probeType | (errorCode & 0xff);
mMetricsLog.log(mInterfaceName, new IpReachabilityEvent(eventType));
diff --git a/tests/net/java/android/net/ip/IpReachabilityMonitorTest.java b/tests/net/java/android/net/ip/IpReachabilityMonitorTest.java
new file mode 100644
index 0000000..f849689
--- /dev/null
+++ b/tests/net/java/android/net/ip/IpReachabilityMonitorTest.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.ip;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyInt;
+
+import android.net.util.SharedLog;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+
+/**
+ * Tests for IpReachabilityMonitor.
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class IpReachabilityMonitorTest {
+
+ @Mock IpReachabilityMonitor.Callback mCallback;
+ @Mock IpReachabilityMonitor.Dependencies mDependencies;
+ @Mock SharedLog mLog;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ IpReachabilityMonitor makeMonitor() {
+ return new IpReachabilityMonitor("fake0", 1, mLog, mCallback, null, mDependencies);
+ }
+
+ @Test
+ public void testNothing() {
+ IpReachabilityMonitor monitor = makeMonitor();
+ }
+}