Merge changes I5187d17c,I49a76582
* changes:
ConnectivityService: regroup bool <-> int conversions
ConnectivityService: move reportNetworkConnectivity to handler
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index c28294f..5edc7c6 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -18,7 +18,8 @@
import android.os.Parcel;
import android.os.Parcelable;
-import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
import java.util.Objects;
@@ -229,7 +230,8 @@
* Capabilities that suggest that a network is restricted.
* {@see #maybeMarkCapabilitiesRestricted}.
*/
- private static final long RESTRICTED_CAPABILITIES =
+ @VisibleForTesting
+ /* package */ static final long RESTRICTED_CAPABILITIES =
(1 << NET_CAPABILITY_CBS) |
(1 << NET_CAPABILITY_DUN) |
(1 << NET_CAPABILITY_EIMS) |
@@ -240,6 +242,17 @@
(1 << NET_CAPABILITY_XCAP);
/**
+ * Capabilities that suggest that a network is unrestricted.
+ * {@see #maybeMarkCapabilitiesRestricted}.
+ */
+ @VisibleForTesting
+ /* package */ static final long UNRESTRICTED_CAPABILITIES =
+ (1 << NET_CAPABILITY_INTERNET) |
+ (1 << NET_CAPABILITY_MMS) |
+ (1 << NET_CAPABILITY_SUPL) |
+ (1 << NET_CAPABILITY_WIFI_P2P);
+
+ /**
* Adds the given capability to this {@code NetworkCapability} instance.
* Multiple capabilities may be applied sequentially. Note that when searching
* for a network to satisfy a request, all capabilities requested must be satisfied.
@@ -365,12 +378,16 @@
* @hide
*/
public void maybeMarkCapabilitiesRestricted() {
- // If all the capabilities are typically provided by restricted networks, conclude that this
- // network is restricted.
- if ((mNetworkCapabilities & ~(DEFAULT_CAPABILITIES | RESTRICTED_CAPABILITIES)) == 0 &&
- // Must have at least some restricted capabilities, otherwise a request for an
- // internet-less network will get marked restricted.
- (mNetworkCapabilities & RESTRICTED_CAPABILITIES) != 0) {
+ // Verify there aren't any unrestricted capabilities. If there are we say
+ // the whole thing is unrestricted.
+ final boolean hasUnrestrictedCapabilities =
+ ((mNetworkCapabilities & UNRESTRICTED_CAPABILITIES) != 0);
+
+ // Must have at least some restricted capabilities.
+ final boolean hasRestrictedCapabilities =
+ ((mNetworkCapabilities & RESTRICTED_CAPABILITIES) != 0);
+
+ if (hasRestrictedCapabilities && !hasUnrestrictedCapabilities) {
removeCapability(NET_CAPABILITY_NOT_RESTRICTED);
}
}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 408b7ed..616a8c0 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -3696,17 +3696,9 @@
existing.shutdown();
}
- try {
- if (tracker != null) {
- mNetd.setFirewallEnabled(true);
- mNetd.setFirewallInterfaceRule("lo", true);
- mLockdownTracker = tracker;
- mLockdownTracker.init();
- } else {
- mNetd.setFirewallEnabled(false);
- }
- } catch (RemoteException e) {
- // ignored; NMS lives inside system_server
+ if (tracker != null) {
+ mLockdownTracker = tracker;
+ mLockdownTracker.init();
}
}
diff --git a/tests/net/java/android/net/NetworkCapabilitiesTest.java b/tests/net/java/android/net/NetworkCapabilitiesTest.java
new file mode 100644
index 0000000..e3b06c8
--- /dev/null
+++ b/tests/net/java/android/net/NetworkCapabilitiesTest.java
@@ -0,0 +1,117 @@
+/*
+ * 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;
+
+import static android.net.NetworkCapabilities.NET_CAPABILITY_CBS;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_EIMS;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
+import static android.net.NetworkCapabilities.RESTRICTED_CAPABILITIES;
+import static android.net.NetworkCapabilities.UNRESTRICTED_CAPABILITIES;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+
+import android.net.NetworkCapabilities;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class NetworkCapabilitiesTest {
+ @Test
+ public void testMaybeMarkCapabilitiesRestricted() {
+ // verify EIMS is restricted
+ assertEquals((1 << NET_CAPABILITY_EIMS) & RESTRICTED_CAPABILITIES,
+ (1 << NET_CAPABILITY_EIMS));
+
+ // verify CBS is also restricted
+ assertEquals((1 << NET_CAPABILITY_CBS) & RESTRICTED_CAPABILITIES,
+ (1 << NET_CAPABILITY_CBS));
+
+ // verify default is not restricted
+ assertEquals((1 << NET_CAPABILITY_INTERNET) & RESTRICTED_CAPABILITIES, 0);
+
+ // just to see
+ assertEquals(RESTRICTED_CAPABILITIES & UNRESTRICTED_CAPABILITIES, 0);
+
+ // check that internet does not get restricted
+ NetworkCapabilities netCap = new NetworkCapabilities();
+ netCap.addCapability(NET_CAPABILITY_INTERNET);
+ netCap.maybeMarkCapabilitiesRestricted();
+ assertTrue(netCap.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
+
+ // metered-ness shouldn't matter
+ netCap = new NetworkCapabilities();
+ netCap.addCapability(NET_CAPABILITY_INTERNET);
+ netCap.addCapability(NET_CAPABILITY_NOT_METERED);
+ netCap.maybeMarkCapabilitiesRestricted();
+ assertTrue(netCap.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
+ netCap = new NetworkCapabilities();
+ netCap.addCapability(NET_CAPABILITY_INTERNET);
+ netCap.removeCapability(NET_CAPABILITY_NOT_METERED);
+ netCap.maybeMarkCapabilitiesRestricted();
+ assertTrue(netCap.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
+
+ // add EIMS - bundled with unrestricted means it's unrestricted
+ netCap = new NetworkCapabilities();
+ netCap.addCapability(NET_CAPABILITY_INTERNET);
+ netCap.addCapability(NET_CAPABILITY_EIMS);
+ netCap.addCapability(NET_CAPABILITY_NOT_METERED);
+ netCap.maybeMarkCapabilitiesRestricted();
+ assertTrue(netCap.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
+ netCap = new NetworkCapabilities();
+ netCap.addCapability(NET_CAPABILITY_INTERNET);
+ netCap.addCapability(NET_CAPABILITY_EIMS);
+ netCap.removeCapability(NET_CAPABILITY_NOT_METERED);
+ netCap.maybeMarkCapabilitiesRestricted();
+ assertTrue(netCap.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
+
+ // just a restricted cap should be restricted regardless of meteredness
+ netCap = new NetworkCapabilities();
+ netCap.addCapability(NET_CAPABILITY_EIMS);
+ netCap.addCapability(NET_CAPABILITY_NOT_METERED);
+ netCap.maybeMarkCapabilitiesRestricted();
+ assertFalse(netCap.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
+ netCap = new NetworkCapabilities();
+ netCap.addCapability(NET_CAPABILITY_EIMS);
+ netCap.removeCapability(NET_CAPABILITY_NOT_METERED);
+ netCap.maybeMarkCapabilitiesRestricted();
+ assertFalse(netCap.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
+
+ // try 2 restricted caps
+ netCap = new NetworkCapabilities();
+ netCap.addCapability(NET_CAPABILITY_CBS);
+ netCap.addCapability(NET_CAPABILITY_EIMS);
+ netCap.addCapability(NET_CAPABILITY_NOT_METERED);
+ netCap.maybeMarkCapabilitiesRestricted();
+ assertFalse(netCap.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
+ netCap = new NetworkCapabilities();
+ netCap.addCapability(NET_CAPABILITY_CBS);
+ netCap.addCapability(NET_CAPABILITY_EIMS);
+ netCap.removeCapability(NET_CAPABILITY_NOT_METERED);
+ netCap.maybeMarkCapabilitiesRestricted();
+ assertFalse(netCap.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
+ }
+
+}
diff --git a/tests/net/java/android/net/nsd/NsdManagerTest.java b/tests/net/java/android/net/nsd/NsdManagerTest.java
new file mode 100644
index 0000000..2418450
--- /dev/null
+++ b/tests/net/java/android/net/nsd/NsdManagerTest.java
@@ -0,0 +1,156 @@
+/*
+ * 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.nsd;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.times;
+
+import android.os.HandlerThread;
+import android.os.Handler;
+import android.os.Looper;
+import android.content.Context;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.os.Message;
+import android.os.Messenger;
+import com.android.internal.util.AsyncChannel;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class NsdManagerTest {
+
+ @Mock Context mContext;
+ @Mock INsdManager mService;
+ MockServiceHandler mServiceHandler;
+
+ long mTimeoutMs = 100; // non-final so that tests can adjust the value.
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+
+ mServiceHandler = spy(MockServiceHandler.create(mContext));
+ when(mService.getMessenger()).thenReturn(new Messenger(mServiceHandler));
+ }
+
+ @Test
+ public void testResolveService() {
+ NsdManager manager = makeManager();
+
+ NsdServiceInfo request = new NsdServiceInfo("a_name", "a_type");
+ NsdServiceInfo reply = new NsdServiceInfo("resolved_name", "resolved_type");
+ NsdManager.ResolveListener listener = mock(NsdManager.ResolveListener.class);
+
+ manager.resolveService(request, listener);
+ int key1 = verifyRequest(NsdManager.RESOLVE_SERVICE);
+ int err = 33;
+ sendResponse(NsdManager.RESOLVE_SERVICE_FAILED, err, key1, null);
+ verify(listener, timeout(mTimeoutMs).times(1)).onResolveFailed(request, err);
+
+ manager.resolveService(request, listener);
+ int key2 = verifyRequest(NsdManager.RESOLVE_SERVICE);
+ sendResponse(NsdManager.RESOLVE_SERVICE_SUCCEEDED, 0, key2, reply);
+ verify(listener, timeout(mTimeoutMs).times(1)).onServiceResolved(reply);
+ }
+
+ @Test
+ public void testParallelResolveService() {
+ NsdManager manager = makeManager();
+
+ NsdServiceInfo request = new NsdServiceInfo("a_name", "a_type");
+ NsdServiceInfo reply = new NsdServiceInfo("resolved_name", "resolved_type");
+
+ NsdManager.ResolveListener listener1 = mock(NsdManager.ResolveListener.class);
+ NsdManager.ResolveListener listener2 = mock(NsdManager.ResolveListener.class);
+
+ manager.resolveService(request, listener1);
+ int key1 = verifyRequest(NsdManager.RESOLVE_SERVICE);
+
+ manager.resolveService(request, listener2);
+ int key2 = verifyRequest(NsdManager.RESOLVE_SERVICE);
+
+ sendResponse(NsdManager.RESOLVE_SERVICE_SUCCEEDED, 0, key2, reply);
+ sendResponse(NsdManager.RESOLVE_SERVICE_SUCCEEDED, 0, key1, reply);
+
+ verify(listener1, timeout(mTimeoutMs).times(1)).onServiceResolved(reply);
+ verify(listener2, timeout(mTimeoutMs).times(1)).onServiceResolved(reply);
+ }
+
+ NsdManager makeManager() {
+ NsdManager manager = new NsdManager(mContext, mService);
+ // Acknowledge first two messages connecting the AsyncChannel.
+ verify(mServiceHandler, timeout(mTimeoutMs).times(2)).handleMessage(any());
+ reset(mServiceHandler);
+ assertNotNull(mServiceHandler.chan);
+ return manager;
+ }
+
+ int verifyRequest(int expectedMessageType) {
+ verify(mServiceHandler, timeout(mTimeoutMs)).handleMessage(any());
+ reset(mServiceHandler);
+ Message received = mServiceHandler.lastMessage;
+ assertEquals(NsdManager.nameOf(expectedMessageType), NsdManager.nameOf(received.what));
+ return received.arg2;
+ }
+
+ void sendResponse(int replyType, int arg, int key, Object obj) {
+ mServiceHandler.chan.sendMessage(replyType, arg, key, obj);
+ }
+
+ // Implements the server side of AsyncChannel connection protocol
+ public static class MockServiceHandler extends Handler {
+ public Context mContext;
+ public AsyncChannel chan;
+ public Message lastMessage;
+
+ MockServiceHandler(Looper looper, Context context) {
+ super(looper);
+ mContext = context;
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ lastMessage = obtainMessage();
+ lastMessage.copyFrom(msg);
+ if (msg.what == AsyncChannel.CMD_CHANNEL_FULL_CONNECTION) {
+ chan = new AsyncChannel();
+ chan.connect(mContext, this, msg.replyTo);
+ chan.sendMessage(AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED);
+ }
+
+ }
+
+ public static MockServiceHandler create(Context context) {
+ HandlerThread t = new HandlerThread("mock-service-handler");
+ t.start();
+ return new MockServiceHandler(t.getLooper(), context);
+ }
+ }
+}
diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java
index efe6fec..506d9e5 100644
--- a/tests/net/java/com/android/server/connectivity/VpnTest.java
+++ b/tests/net/java/com/android/server/connectivity/VpnTest.java
@@ -27,6 +27,7 @@
import android.app.AppOpsManager;
import android.app.NotificationManager;
import android.content.Context;
+import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
@@ -42,6 +43,8 @@
import android.util.ArrayMap;
import android.util.ArraySet;
+import com.android.internal.net.VpnConfig;
+
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Map;
@@ -101,8 +104,10 @@
@Override
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
+
when(mContext.getPackageManager()).thenReturn(mPackageManager);
setMockedPackages(mPackages);
+
when(mContext.getPackageName()).thenReturn(Vpn.class.getPackage().getName());
when(mContext.getSystemService(eq(Context.USER_SERVICE))).thenReturn(mUserManager);
when(mContext.getSystemService(eq(Context.APP_OPS_SERVICE))).thenReturn(mAppOps);
@@ -258,6 +263,58 @@
}
@SmallTest
+ public void testLockdownRuleRepeatability() throws Exception {
+ final Vpn vpn = createVpn(primaryUser.id);
+
+ // Given legacy lockdown is already enabled,
+ vpn.setLockdown(true);
+ verify(mNetService, times(1)).setAllowOnlyVpnForUids(
+ eq(true), aryEq(new UidRange[] {UidRange.createForUser(primaryUser.id)}));
+
+ // Enabling legacy lockdown twice should do nothing.
+ vpn.setLockdown(true);
+ verify(mNetService, times(1)).setAllowOnlyVpnForUids(anyBoolean(), any(UidRange[].class));
+
+ // And disabling should remove the rules exactly once.
+ vpn.setLockdown(false);
+ verify(mNetService, times(1)).setAllowOnlyVpnForUids(
+ eq(false), aryEq(new UidRange[] {UidRange.createForUser(primaryUser.id)}));
+
+ // Removing the lockdown again should have no effect.
+ vpn.setLockdown(false);
+ verify(mNetService, times(2)).setAllowOnlyVpnForUids(anyBoolean(), any(UidRange[].class));
+ }
+
+ @SmallTest
+ public void testLockdownRuleReversibility() throws Exception {
+ final Vpn vpn = createVpn(primaryUser.id);
+
+ final UidRange[] entireUser = {
+ UidRange.createForUser(primaryUser.id)
+ };
+ final UidRange[] exceptPkg0 = {
+ new UidRange(entireUser[0].start, entireUser[0].start + PKG_UIDS[0] - 1),
+ new UidRange(entireUser[0].start + PKG_UIDS[0] + 1, entireUser[0].stop)
+ };
+
+ final InOrder order = inOrder(mNetService);
+
+ // Given lockdown is enabled with no package (legacy VPN),
+ vpn.setLockdown(true);
+ order.verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(entireUser));
+
+ // When a new VPN package is set the rules should change to cover that package.
+ vpn.prepare(null, PKGS[0]);
+ order.verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(entireUser));
+ order.verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(exceptPkg0));
+
+ // When that VPN package is unset, everything should be undone again in reverse.
+ vpn.prepare(null, VpnConfig.LEGACY_VPN);
+ order.verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(exceptPkg0));
+ order.verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(entireUser));
+ }
+
+ @SmallTest
public void testNotificationShownForAlwaysOnApp() {
final UserHandle userHandle = UserHandle.of(primaryUser.id);
final Vpn vpn = createVpn(primaryUser.id);