Merge "remove spurious ifdef POSIX_SPAWN_CLOEXEC_DEFAULT"
diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java
index 6414497..4183ac6 100644
--- a/service/src/com/android/server/ConnectivityService.java
+++ b/service/src/com/android/server/ConnectivityService.java
@@ -108,6 +108,7 @@
import android.app.AppOpsManager;
import android.app.BroadcastOptions;
import android.app.PendingIntent;
+import android.app.admin.DevicePolicyManager;
import android.app.usage.NetworkStatsManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -10639,13 +10640,29 @@
mQosCallbackTracker.unregisterCallback(callback);
}
+ private boolean isNetworkPreferenceAllowedForProfile(@NonNull UserHandle profile) {
+ // UserManager.isManagedProfile returns true for all apps in managed user profiles.
+ // Enterprise device can be fully managed like device owner and such use case
+ // also should be supported. Calling app check for work profile and fully managed device
+ // is already done in DevicePolicyManager.
+ // This check is an extra caution to be sure device is fully managed or not.
+ final UserManager um = mContext.getSystemService(UserManager.class);
+ final DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class);
+ if (um.isManagedProfile(profile.getIdentifier())) {
+ return true;
+ }
+ if (SdkLevel.isAtLeastT() && dpm.getDeviceOwner() != null) return true;
+ return false;
+ }
+
/**
- * Request that a user profile is put by default on a network matching a given preference.
+ * Set a list of default network selection policies for a user profile or device owner.
*
* See the documentation for the individual preferences for a description of the supported
* behaviors.
*
- * @param profile the user profile for whih the preference is being set.
+ * @param profile If the device owner is set, any profile is allowed.
+ Otherwise, the given profile can only be managed profile.
* @param preferences the list of profile network preferences for the
* provided profile.
* @param listener an optional listener to listen for completion of the operation.
@@ -10670,9 +10687,9 @@
throw new IllegalArgumentException("Must explicitly specify a user handle ("
+ "UserHandle.CURRENT not supported)");
}
- final UserManager um = mContext.getSystemService(UserManager.class);
- if (!um.isManagedProfile(profile.getIdentifier())) {
- throw new IllegalArgumentException("Profile must be a managed profile");
+ if (!isNetworkPreferenceAllowedForProfile(profile)) {
+ throw new IllegalArgumentException("Profile must be a managed profile "
+ + "or the device owner must be set. ");
}
final List<ProfileNetworkPreferenceList.Preference> preferenceList =
diff --git a/tests/common/java/android/net/netstats/NetworkStatsCollectionTest.kt b/tests/common/java/android/net/netstats/NetworkStatsCollectionTest.kt
new file mode 100644
index 0000000..ca0e5ed
--- /dev/null
+++ b/tests/common/java/android/net/netstats/NetworkStatsCollectionTest.kt
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2022 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.netstats
+
+import android.net.NetworkIdentitySet
+import android.net.NetworkStatsCollection
+import android.net.NetworkStatsHistory
+import androidx.test.filters.SmallTest
+import com.android.testutils.ConnectivityModuleTest
+import com.android.testutils.DevSdkIgnoreRule
+import com.android.testutils.SC_V2
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import kotlin.test.assertEquals
+import kotlin.test.fail
+
+@ConnectivityModuleTest
+@RunWith(JUnit4::class)
+@SmallTest
+class NetworkStatsCollectionTest {
+ @Rule
+ @JvmField
+ val ignoreRule = DevSdkIgnoreRule(ignoreClassUpTo = SC_V2)
+
+ @Test
+ fun testBuilder() {
+ val ident = NetworkIdentitySet()
+ val key1 = NetworkStatsCollection.Key(ident, /* uid */ 0, /* set */ 0, /* tag */ 0)
+ val key2 = NetworkStatsCollection.Key(ident, /* uid */ 1, /* set */ 0, /* tag */ 0)
+ val bucketDuration = 10L
+ val entry1 = NetworkStatsHistory.Entry(10, 10, 40, 4, 50, 5, 60)
+ val entry2 = NetworkStatsHistory.Entry(30, 10, 3, 41, 7, 1, 0)
+ val history1 = NetworkStatsHistory.Builder(10, 5)
+ .addEntry(entry1)
+ .addEntry(entry2)
+ .build()
+ val history2 = NetworkStatsHistory(10, 5)
+ val actualCollection = NetworkStatsCollection.Builder(bucketDuration)
+ .addEntry(key1, history1)
+ .addEntry(key2, history2)
+ .build()
+
+ // The builder will omit any entry with empty history. Thus, only history1
+ // is expected in the result collection.
+ val actualEntries = actualCollection.entries
+ assertEquals(1, actualEntries.size)
+ val actualHistory = actualEntries[key1] ?: fail("There should be an entry for $key1")
+ assertEquals(history1.entries, actualHistory.entries)
+ }
+}
\ No newline at end of file
diff --git a/tests/common/java/android/net/netstats/NetworkStatsHistoryTest.kt b/tests/common/java/android/net/netstats/NetworkStatsHistoryTest.kt
new file mode 100644
index 0000000..c2654c5
--- /dev/null
+++ b/tests/common/java/android/net/netstats/NetworkStatsHistoryTest.kt
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2022 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.netstats
+
+import android.net.NetworkStatsHistory
+import android.text.format.DateUtils
+import androidx.test.filters.SmallTest
+import com.android.testutils.ConnectivityModuleTest
+import com.android.testutils.DevSdkIgnoreRule
+import com.android.testutils.SC_V2
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import kotlin.test.assertEquals
+
+@ConnectivityModuleTest
+@RunWith(JUnit4::class)
+@SmallTest
+class NetworkStatsHistoryTest {
+ @Rule
+ @JvmField
+ val ignoreRule = DevSdkIgnoreRule(ignoreClassUpTo = SC_V2)
+
+ @Test
+ fun testBuilder() {
+ val entry1 = NetworkStatsHistory.Entry(10, 30, 40, 4, 50, 5, 60)
+ val entry2 = NetworkStatsHistory.Entry(30, 15, 3, 41, 7, 1, 0)
+ val entry3 = NetworkStatsHistory.Entry(7, 301, 11, 14, 31, 2, 80)
+ val statsEmpty = NetworkStatsHistory
+ .Builder(DateUtils.HOUR_IN_MILLIS, /* initialCapacity */ 10).build()
+ assertEquals(0, statsEmpty.entries.size)
+ assertEquals(DateUtils.HOUR_IN_MILLIS, statsEmpty.bucketDuration)
+ val statsSingle = NetworkStatsHistory
+ .Builder(DateUtils.HOUR_IN_MILLIS, /* initialCapacity */ 8)
+ .addEntry(entry1)
+ .build()
+ statsSingle.assertEntriesEqual(entry1)
+ assertEquals(DateUtils.HOUR_IN_MILLIS, statsSingle.bucketDuration)
+ val statsMultiple = NetworkStatsHistory
+ .Builder(DateUtils.SECOND_IN_MILLIS, /* initialCapacity */ 0)
+ .addEntry(entry1).addEntry(entry2).addEntry(entry3)
+ .build()
+ assertEquals(DateUtils.SECOND_IN_MILLIS, statsMultiple.bucketDuration)
+ statsMultiple.assertEntriesEqual(entry1, entry2, entry3)
+ }
+
+ fun NetworkStatsHistory.assertEntriesEqual(vararg entries: NetworkStatsHistory.Entry) {
+ assertEquals(entries.size, this.entries.size)
+ entries.forEachIndexed { i, element ->
+ assertEquals(element, this.entries[i])
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/unit/java/android/net/NetworkStatsCollectionTest.java b/tests/unit/java/android/net/NetworkStatsCollectionTest.java
index 32c106d..0f02850 100644
--- a/tests/unit/java/android/net/NetworkStatsCollectionTest.java
+++ b/tests/unit/java/android/net/NetworkStatsCollectionTest.java
@@ -38,13 +38,11 @@
import static org.junit.Assert.fail;
import android.content.res.Resources;
-import android.net.NetworkStatsCollection.Key;
import android.os.Process;
import android.os.UserHandle;
import android.telephony.SubscriptionPlan;
import android.telephony.TelephonyManager;
import android.text.format.DateUtils;
-import android.util.ArrayMap;
import android.util.RecurrenceRule;
import androidx.test.InstrumentationRegistry;
@@ -75,7 +73,6 @@
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.List;
-import java.util.Map;
/**
* Tests for {@link NetworkStatsCollection}.
@@ -534,52 +531,6 @@
assertThrows(ArithmeticException.class, () -> multiplySafeByRational(30, 3, 0));
}
- @Test
- public void testBuilder() {
- final Map<Key, NetworkStatsHistory> expectedEntries = new ArrayMap<>();
- final NetworkStats.Entry entry = new NetworkStats.Entry();
- final NetworkIdentitySet ident = new NetworkIdentitySet();
- final Key key1 = new Key(ident, 0, 0, 0);
- final Key key2 = new Key(ident, 1, 0, 0);
- final long bucketDuration = 10;
-
- final NetworkStatsHistory.Entry entry1 = new NetworkStatsHistory.Entry(10, 10, 40,
- 4, 50, 5, 60);
- final NetworkStatsHistory.Entry entry2 = new NetworkStatsHistory.Entry(30, 10, 3,
- 41, 7, 1, 0);
-
- NetworkStatsHistory history1 = new NetworkStatsHistory.Builder(10, 5)
- .addEntry(entry1)
- .addEntry(entry2)
- .build();
-
- NetworkStatsHistory history2 = new NetworkStatsHistory(10, 5);
-
- NetworkStatsCollection actualCollection = new NetworkStatsCollection.Builder(bucketDuration)
- .addEntry(key1, history1)
- .addEntry(key2, history2)
- .build();
-
- // The builder will omit any entry with empty history. Thus, history2
- // is not expected in the result collection.
- expectedEntries.put(key1, history1);
-
- final Map<Key, NetworkStatsHistory> actualEntries = actualCollection.getEntries();
-
- assertEquals(expectedEntries.size(), actualEntries.size());
- for (Key expectedKey : expectedEntries.keySet()) {
- final NetworkStatsHistory expectedHistory = expectedEntries.get(expectedKey);
-
- final NetworkStatsHistory actualHistory = actualEntries.get(expectedKey);
- assertNotNull(actualHistory);
-
- assertEquals(expectedHistory.getEntries(), actualHistory.getEntries());
-
- actualEntries.remove(expectedKey);
- }
- assertEquals(0, actualEntries.size());
- }
-
/**
* Copy a {@link Resources#openRawResource(int)} into {@link File} for
* testing purposes.
diff --git a/tests/unit/java/android/net/NetworkStatsHistoryTest.java b/tests/unit/java/android/net/NetworkStatsHistoryTest.java
index c170605..c5f8c00 100644
--- a/tests/unit/java/android/net/NetworkStatsHistoryTest.java
+++ b/tests/unit/java/android/net/NetworkStatsHistoryTest.java
@@ -56,7 +56,6 @@
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
-import java.util.List;
import java.util.Random;
@RunWith(DevSdkIgnoreRunner.class)
@@ -533,40 +532,6 @@
assertEquals(512L + 4096L, stats.getTotalBytes());
}
- @Test
- public void testBuilder() {
- final NetworkStatsHistory.Entry entry1 = new NetworkStatsHistory.Entry(10, 30, 40,
- 4, 50, 5, 60);
- final NetworkStatsHistory.Entry entry2 = new NetworkStatsHistory.Entry(30, 15, 3,
- 41, 7, 1, 0);
- final NetworkStatsHistory.Entry entry3 = new NetworkStatsHistory.Entry(7, 301, 11,
- 14, 31, 2, 80);
-
- final NetworkStatsHistory statsEmpty = new NetworkStatsHistory
- .Builder(HOUR_IN_MILLIS, 10).build();
- assertEquals(0, statsEmpty.getEntries().size());
- assertEquals(HOUR_IN_MILLIS, statsEmpty.getBucketDuration());
-
- NetworkStatsHistory statsSingle = new NetworkStatsHistory
- .Builder(HOUR_IN_MILLIS, 8)
- .addEntry(entry1)
- .build();
- assertEquals(1, statsSingle.getEntries().size());
- assertEquals(HOUR_IN_MILLIS, statsSingle.getBucketDuration());
- assertEquals(entry1, statsSingle.getEntries().get(0));
-
- NetworkStatsHistory statsMultiple = new NetworkStatsHistory
- .Builder(SECOND_IN_MILLIS, 0)
- .addEntry(entry1).addEntry(entry2).addEntry(entry3)
- .build();
- final List<NetworkStatsHistory.Entry> entries = statsMultiple.getEntries();
- assertEquals(3, entries.size());
- assertEquals(SECOND_IN_MILLIS, statsMultiple.getBucketDuration());
- assertEquals(entry1, entries.get(0));
- assertEquals(entry2, entries.get(1));
- assertEquals(entry3, entries.get(2));
- }
-
private static void assertIndexBeforeAfter(
NetworkStatsHistory stats, int before, int after, long time) {
assertEquals("unexpected before", before, stats.getIndexBefore(time));
diff --git a/tests/unit/java/com/android/server/ConnectivityServiceTest.java b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
index 4543817..58b8fa0 100644
--- a/tests/unit/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
@@ -194,6 +194,7 @@
import android.app.AppOpsManager;
import android.app.NotificationManager;
import android.app.PendingIntent;
+import android.app.admin.DevicePolicyManager;
import android.app.usage.NetworkStatsManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -541,6 +542,7 @@
@Mock NetworkPolicyManager mNetworkPolicyManager;
@Mock VpnProfileStore mVpnProfileStore;
@Mock SystemConfigManager mSystemConfigManager;
+ @Mock DevicePolicyManager mDevicePolicyManager;
@Mock Resources mResources;
@Mock ClatCoordinator mClatCoordinator;
@Mock PacProxyManager mPacProxyManager;
@@ -663,6 +665,7 @@
if (Context.TELEPHONY_SERVICE.equals(name)) return mTelephonyManager;
if (Context.ETHERNET_SERVICE.equals(name)) return mEthernetManager;
if (Context.NETWORK_POLICY_SERVICE.equals(name)) return mNetworkPolicyManager;
+ if (Context.DEVICE_POLICY_SERVICE.equals(name)) return mDevicePolicyManager;
if (Context.SYSTEM_CONFIG_SERVICE.equals(name)) return mSystemConfigManager;
if (Context.NETWORK_STATS_SERVICE.equals(name)) return mStatsManager;
if (Context.BATTERY_STATS_SERVICE.equals(name)) return mBatteryStatsManager;
@@ -691,6 +694,14 @@
doReturn(value).when(mUserManager).isManagedProfile(eq(userHandle.getIdentifier()));
}
+ public void setDeviceOwner(@NonNull final UserHandle userHandle, String value) {
+ // This relies on all contexts for a given user returning the same UM mock
+ final DevicePolicyManager dpmMock = createContextAsUser(userHandle, 0 /* flags */)
+ .getSystemService(DevicePolicyManager.class);
+ doReturn(value).when(dpmMock).getDeviceOwner();
+ doReturn(value).when(mDevicePolicyManager).getDeviceOwner();
+ }
+
@Override
public ContentResolver getContentResolver() {
return mContentResolver;
@@ -14731,12 +14742,41 @@
public void testProfileNetworkPrefWrongProfile() throws Exception {
final UserHandle testHandle = UserHandle.of(TEST_WORK_PROFILE_USER_ID);
mServiceContext.setWorkProfile(testHandle, false);
- assertThrows("Should not be able to set a user pref for a non-work profile",
+ mServiceContext.setDeviceOwner(testHandle, null);
+ assertThrows("Should not be able to set a user pref for a non-work profile "
+ + "and non device owner",
IllegalArgumentException.class , () ->
mCm.setProfileNetworkPreference(testHandle,
PROFILE_NETWORK_PREFERENCE_ENTERPRISE, null, null));
}
+ /**
+ * Make sure requests for per-profile default networking for a device owner is
+ * accepted on T and not accepted on S
+ */
+ public void testProfileNetworkDeviceOwner() throws Exception {
+ final UserHandle testHandle = UserHandle.of(TEST_WORK_PROFILE_USER_ID);
+ mServiceContext.setWorkProfile(testHandle, false);
+ mServiceContext.setDeviceOwner(testHandle, "deviceOwnerPackage");
+ ProfileNetworkPreference.Builder profileNetworkPreferenceBuilder =
+ new ProfileNetworkPreference.Builder();
+ profileNetworkPreferenceBuilder.setPreference(PROFILE_NETWORK_PREFERENCE_ENTERPRISE);
+ profileNetworkPreferenceBuilder.setPreferenceEnterpriseId(NET_ENTERPRISE_ID_1);
+ final TestOnCompleteListener listener = new TestOnCompleteListener();
+ if (SdkLevel.isAtLeastT()) {
+ mCm.setProfileNetworkPreferences(testHandle,
+ List.of(profileNetworkPreferenceBuilder.build()),
+ r -> r.run(), listener);
+ } else {
+ // S should not allow setting preference on device owner
+ assertThrows("Should not be able to set a user pref for a non-work profile on S",
+ IllegalArgumentException.class , () ->
+ mCm.setProfileNetworkPreferences(testHandle,
+ List.of(profileNetworkPreferenceBuilder.build()),
+ r -> r.run(), listener));
+ }
+ }
+
@Test
public void testSubIdsClearedWithoutNetworkFactoryPermission() throws Exception {
mServiceContext.setPermission(NETWORK_FACTORY, PERMISSION_DENIED);