Loading services/net/java/android/net/ip/IpReachabilityMonitor.java +50 −15 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -31,18 +29,22 @@ import android.net.netlink.NetlinkErrorMessage; 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; Loading Loading @@ -147,12 +149,32 @@ public class IpReachabilityMonitor { 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; Loading Loading @@ -228,20 +250,20 @@ public class IpReachabilityMonitor { } public IpReachabilityMonitor(Context context, String ifName, SharedLog log, Callback callback, MultinetworkPolicyTracker tracker) throws IllegalArgumentException { 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); MultinetworkPolicyTracker tracker) { this(ifName, getInterfaceIndex(ifName), log, callback, tracker, Dependencies.makeDefault(context, ifName)); } mWakeLock = ((PowerManager) context.getSystemService(Context.POWER_SERVICE)).newWakeLock( PowerManager.PARTIAL_WAKE_LOCK, TAG + "." + mInterfaceName); @VisibleForTesting IpReachabilityMonitor(String ifName, int ifIndex, SharedLog log, Callback callback, MultinetworkPolicyTracker tracker, Dependencies dependencies) { mInterfaceName = ifName; mLog = log.forSubComponent(TAG); mCallback = callback; mMultinetworkPolicyTracker = tracker; mInterfaceIndex = ifIndex; mDependencies = dependencies; mNetlinkSocketObserver = new NetlinkSocketObserver(); mObserverThread = new Thread(mNetlinkSocketObserver); mObserverThread.start(); Loading Loading @@ -398,7 +420,7 @@ public class IpReachabilityMonitor { // 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) { Loading Loading @@ -429,6 +451,19 @@ public class IpReachabilityMonitor { 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)); Loading tests/net/java/android/net/ip/IpReachabilityMonitorTest.java 0 → 100644 +59 −0 Original line number Diff line number Diff line /* * 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(); } } Loading
services/net/java/android/net/ip/IpReachabilityMonitor.java +50 −15 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -31,18 +29,22 @@ import android.net.netlink.NetlinkErrorMessage; 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; Loading Loading @@ -147,12 +149,32 @@ public class IpReachabilityMonitor { 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; Loading Loading @@ -228,20 +250,20 @@ public class IpReachabilityMonitor { } public IpReachabilityMonitor(Context context, String ifName, SharedLog log, Callback callback, MultinetworkPolicyTracker tracker) throws IllegalArgumentException { 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); MultinetworkPolicyTracker tracker) { this(ifName, getInterfaceIndex(ifName), log, callback, tracker, Dependencies.makeDefault(context, ifName)); } mWakeLock = ((PowerManager) context.getSystemService(Context.POWER_SERVICE)).newWakeLock( PowerManager.PARTIAL_WAKE_LOCK, TAG + "." + mInterfaceName); @VisibleForTesting IpReachabilityMonitor(String ifName, int ifIndex, SharedLog log, Callback callback, MultinetworkPolicyTracker tracker, Dependencies dependencies) { mInterfaceName = ifName; mLog = log.forSubComponent(TAG); mCallback = callback; mMultinetworkPolicyTracker = tracker; mInterfaceIndex = ifIndex; mDependencies = dependencies; mNetlinkSocketObserver = new NetlinkSocketObserver(); mObserverThread = new Thread(mNetlinkSocketObserver); mObserverThread.start(); Loading Loading @@ -398,7 +420,7 @@ public class IpReachabilityMonitor { // 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) { Loading Loading @@ -429,6 +451,19 @@ public class IpReachabilityMonitor { 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)); Loading
tests/net/java/android/net/ip/IpReachabilityMonitorTest.java 0 → 100644 +59 −0 Original line number Diff line number Diff line /* * 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(); } }