Merge "Avoid unregistering the same receiver more than once." into tm-dev
diff --git a/nearby/tests/cts/fastpair/AndroidTest.xml b/nearby/tests/cts/fastpair/AndroidTest.xml
index 360bbf3..2800069 100644
--- a/nearby/tests/cts/fastpair/AndroidTest.xml
+++ b/nearby/tests/cts/fastpair/AndroidTest.xml
@@ -14,6 +14,9 @@
limitations under the License.
-->
<configuration description="Config for CTS Nearby Fast Pair test cases">
+ <!-- Only run tests if the device under test is SDK version 33 (Android 13) or above. -->
+ <object type="module_controller" class="com.android.tradefed.testtype.suite.module.Sdk33ModuleController" />
+
<option name="test-suite-tag" value="cts" />
<option name="config-descriptor:metadata" key="component" value="location" />
<!-- Instant cannot access NearbyManager. -->
diff --git a/nearby/tests/integration/privileged/AndroidManifest.xml b/nearby/tests/integration/privileged/AndroidManifest.xml
index 00845f1..86ec111 100644
--- a/nearby/tests/integration/privileged/AndroidManifest.xml
+++ b/nearby/tests/integration/privileged/AndroidManifest.xml
@@ -18,6 +18,10 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="android.nearby.integration.privileged">
+ <uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
+ <uses-permission android:name="android.permission.BLUETOOTH_PRIVILEGED" />
+ <uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
+ <uses-permission android:name="android.permission.READ_DEVICE_CONFIG" />
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
<instrumentation
diff --git a/nearby/tests/integration/privileged/src/android/nearby/integration/privileged/NearbyManagerTest.kt b/nearby/tests/integration/privileged/src/android/nearby/integration/privileged/NearbyManagerTest.kt
index 3b6337a..66bab23 100644
--- a/nearby/tests/integration/privileged/src/android/nearby/integration/privileged/NearbyManagerTest.kt
+++ b/nearby/tests/integration/privileged/src/android/nearby/integration/privileged/NearbyManagerTest.kt
@@ -17,22 +17,81 @@
package android.nearby.integration.privileged
import android.content.Context
+import android.nearby.BroadcastCallback
+import android.nearby.BroadcastRequest
+import android.nearby.NearbyDevice
import android.nearby.NearbyManager
+import android.nearby.PresenceBroadcastRequest
+import android.nearby.PresenceCredential
+import android.nearby.PrivateCredential
+import android.nearby.ScanCallback
+import android.nearby.ScanRequest
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.google.common.truth.Truth.assertThat
+import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class NearbyManagerTest {
+ private lateinit var appContext: Context
+
+ @Before
+ fun setUp() {
+ appContext = ApplicationProvider.getApplicationContext<Context>()
+ }
/** Verify privileged app can get Nearby service. */
@Test
fun testContextGetNearbySystemService_fromPrivilegedApp_returnsNoneNull() {
- val appContext = ApplicationProvider.getApplicationContext<Context>()
- val nearbyManager = appContext.getSystemService(Context.NEARBY_SERVICE) as NearbyManager
+ assertThat(appContext.getSystemService(Context.NEARBY_SERVICE)).isNotNull()
+ }
- assertThat(nearbyManager).isNotNull()
+ /** Verify privileged app can start/stop scan without exception. */
+ @Test
+ fun testNearbyManagerStartScanStopScan_fromPrivilegedApp_succeed() {
+ val nearbyManager = appContext.getSystemService(Context.NEARBY_SERVICE) as NearbyManager
+ val scanRequest = ScanRequest.Builder()
+ .setScanMode(ScanRequest.SCAN_MODE_LOW_LATENCY)
+ .setScanType(ScanRequest.SCAN_TYPE_FAST_PAIR)
+ .setBleEnabled(true)
+ .build()
+ val scanCallback = object : ScanCallback {
+ override fun onDiscovered(device: NearbyDevice) {}
+
+ override fun onUpdated(device: NearbyDevice) {}
+
+ override fun onLost(device: NearbyDevice) {}
+ }
+
+ nearbyManager.startScan(scanRequest, /* executor */ { it.run() }, scanCallback)
+ nearbyManager.stopScan(scanCallback)
+ }
+
+ /** Verify privileged app can start/stop broadcast without exception. */
+ @Test
+ fun testNearbyManagerStartBroadcastStopBroadcast_fromPrivilegedApp_succeed() {
+ val nearbyManager = appContext.getSystemService(Context.NEARBY_SERVICE) as NearbyManager
+ val salt = byteArrayOf(1, 2)
+ val secreteId = byteArrayOf(1, 2, 3, 4)
+ val metadataEncryptionKey = ByteArray(14)
+ val authenticityKey = byteArrayOf(0, 1, 1, 1)
+ val deviceName = "test_device"
+ val mediums = listOf(BroadcastRequest.MEDIUM_BLE)
+ val credential =
+ PrivateCredential.Builder(secreteId, authenticityKey, metadataEncryptionKey, deviceName)
+ .setIdentityType(PresenceCredential.IDENTITY_TYPE_PRIVATE)
+ .build()
+ val broadcastRequest: BroadcastRequest =
+ PresenceBroadcastRequest.Builder(mediums, salt, credential)
+ .addAction(123)
+ .build()
+ val broadcastCallback = BroadcastCallback { }
+
+ nearbyManager.startBroadcast(
+ broadcastRequest, /* executor */ { it.run() }, broadcastCallback
+ )
+ nearbyManager.stopBroadcast(broadcastCallback)
}
}
diff --git a/nearby/tests/integration/untrusted/src/android/nearby/integration/untrusted/NearbyManagerTest.kt b/nearby/tests/integration/untrusted/src/android/nearby/integration/untrusted/NearbyManagerTest.kt
index 04c5e30..3bfac6d 100644
--- a/nearby/tests/integration/untrusted/src/android/nearby/integration/untrusted/NearbyManagerTest.kt
+++ b/nearby/tests/integration/untrusted/src/android/nearby/integration/untrusted/NearbyManagerTest.kt
@@ -17,20 +17,127 @@
package android.nearby.integration.untrusted
import android.content.Context
+import android.nearby.BroadcastCallback
+import android.nearby.BroadcastRequest
+import android.nearby.NearbyDevice
import android.nearby.NearbyManager
+import android.nearby.PresenceBroadcastRequest
+import android.nearby.PresenceCredential
+import android.nearby.PrivateCredential
+import android.nearby.ScanCallback
+import android.nearby.ScanRequest
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.google.common.truth.Truth.assertThat
+import org.junit.Assert.assertThrows
+import org.junit.Before
+import org.junit.Ignore
import org.junit.Test
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class NearbyManagerTest {
+ private lateinit var appContext: Context
+
+ @Before
+ fun setUp() {
+ appContext = ApplicationProvider.getApplicationContext<Context>()
+ }
/** Verify untrusted app can get Nearby service. */
@Test
fun testContextGetNearbyService_fromUnTrustedApp_returnsNotNull() {
- val appContext = ApplicationProvider.getApplicationContext<Context>()
assertThat(appContext.getSystemService(Context.NEARBY_SERVICE)).isNotNull()
}
+
+ /**
+ * Verify untrusted app can't start scan because it needs BLUETOOTH_PRIVILEGED
+ * permission which is not for use by third-party applications.
+ */
+ @Test
+ fun testNearbyManagerStartScan_fromUnTrustedApp_throwsException() {
+ val nearbyManager = appContext.getSystemService(Context.NEARBY_SERVICE) as NearbyManager
+ val scanRequest = ScanRequest.Builder()
+ .setScanMode(ScanRequest.SCAN_MODE_LOW_LATENCY)
+ .setScanType(ScanRequest.SCAN_TYPE_FAST_PAIR)
+ .setBleEnabled(true)
+ .build()
+ val scanCallback = object : ScanCallback {
+ override fun onDiscovered(device: NearbyDevice) {}
+
+ override fun onUpdated(device: NearbyDevice) {}
+
+ override fun onLost(device: NearbyDevice) {}
+ }
+
+ assertThrows(SecurityException::class.java) {
+ nearbyManager.startScan(scanRequest, /* executor */ { it.run() }, scanCallback)
+ }
+ }
+
+ /**
+ * Verify untrusted app can't stop scan because it needs BLUETOOTH_PRIVILEGED
+ * permission which is not for use by third-party applications.
+ */
+ @Test
+ @Ignore("Permission check for stopXXX not yet implement: b/229338477#comment24")
+ fun testNearbyManagerStopScan_fromUnTrustedApp_throwsException() {
+ val nearbyManager = appContext.getSystemService(Context.NEARBY_SERVICE) as NearbyManager
+ val scanCallback = object : ScanCallback {
+ override fun onDiscovered(device: NearbyDevice) {}
+
+ override fun onUpdated(device: NearbyDevice) {}
+
+ override fun onLost(device: NearbyDevice) {}
+ }
+
+ assertThrows(SecurityException::class.java) {
+ nearbyManager.stopScan(scanCallback)
+ }
+ }
+
+ /**
+ * Verify untrusted app can't start broadcast because it needs BLUETOOTH_PRIVILEGED
+ * permission which is not for use by third-party applications.
+ */
+ @Test
+ fun testNearbyManagerStartBroadcast_fromUnTrustedApp_throwsException() {
+ val nearbyManager = appContext.getSystemService(Context.NEARBY_SERVICE) as NearbyManager
+ val salt = byteArrayOf(1, 2)
+ val secreteId = byteArrayOf(1, 2, 3, 4)
+ val metadataEncryptionKey = ByteArray(14)
+ val authenticityKey = byteArrayOf(0, 1, 1, 1)
+ val deviceName = "test_device"
+ val mediums = listOf(BroadcastRequest.MEDIUM_BLE)
+ val credential =
+ PrivateCredential.Builder(secreteId, authenticityKey, metadataEncryptionKey, deviceName)
+ .setIdentityType(PresenceCredential.IDENTITY_TYPE_PRIVATE)
+ .build()
+ val broadcastRequest: BroadcastRequest =
+ PresenceBroadcastRequest.Builder(mediums, salt, credential)
+ .addAction(123)
+ .build()
+ val broadcastCallback = BroadcastCallback { }
+
+ assertThrows(SecurityException::class.java) {
+ nearbyManager.startBroadcast(
+ broadcastRequest, /* executor */ { it.run() }, broadcastCallback
+ )
+ }
+ }
+
+ /**
+ * Verify untrusted app can't stop broadcast because it needs BLUETOOTH_PRIVILEGED
+ * permission which is not for use by third-party applications.
+ */
+ @Test
+ @Ignore("Permission check for stopXXX not yet implement: b/229338477#comment24")
+ fun testNearbyManagerStopBroadcast_fromUnTrustedApp_throwsException() {
+ val nearbyManager = appContext.getSystemService(Context.NEARBY_SERVICE) as NearbyManager
+ val broadcastCallback = BroadcastCallback { }
+
+ assertThrows(SecurityException::class.java) {
+ nearbyManager.stopBroadcast(broadcastCallback)
+ }
+ }
}
diff --git a/nearby/tests/multidevices/host/AndroidTest.xml b/nearby/tests/multidevices/host/AndroidTest.xml
index 5926cc1..43cf136 100644
--- a/nearby/tests/multidevices/host/AndroidTest.xml
+++ b/nearby/tests/multidevices/host/AndroidTest.xml
@@ -36,7 +36,6 @@
<!-- Any python dependencies can be specified and will be installed with pip -->
<!-- TODO(b/225958696): Import python dependencies -->
<option name="dep-module" value="mobly" />
- <option name="dep-module" value="retry" />
</target_preparer>
<target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
<option name="force-skip-system-props" value="true" /> <!-- avoid restarting device -->
diff --git a/nearby/tests/multidevices/host/test_helper/fast_pair_provider_simulator.py b/nearby/tests/multidevices/host/test_helper/fast_pair_provider_simulator.py
index d6484fb..592c4f1 100644
--- a/nearby/tests/multidevices/host/test_helper/fast_pair_provider_simulator.py
+++ b/nearby/tests/multidevices/host/test_helper/fast_pair_provider_simulator.py
@@ -14,10 +14,12 @@
"""Fast Pair provider simulator role."""
+import time
+
from mobly import asserts
from mobly.controllers import android_device
+from mobly.controllers.android_device_lib import jsonrpc_client_base
from mobly.controllers.android_device_lib import snippet_event
-import retry
from typing import Optional
from test_helper import event_helper
@@ -104,7 +106,6 @@
"""Tears down the Fast Pair provider simulator."""
self._ad.fp.teardownProviderSimulator()
- @retry.retry(tries=3)
def get_ble_mac_address(self) -> str:
"""Gets Bluetooth low energy mac address of the provider simulator.
@@ -115,7 +116,11 @@
Returns:
The BLE mac address of the Fast Pair provider simulator.
"""
- return self._ad.fp.getBluetoothLeAddress()
+ for _ in range(3):
+ try:
+ return self._ad.fp.getBluetoothLeAddress()
+ except jsonrpc_client_base.ApiError:
+ time.sleep(1)
def wait_for_discoverable_mode(self, timeout_seconds: int) -> None:
"""Waits onScanModeChange event to ensure provider is discoverable.
diff --git a/nearby/tests/unit/AndroidTest.xml b/nearby/tests/unit/AndroidTest.xml
index fdf665d..ad52316 100644
--- a/nearby/tests/unit/AndroidTest.xml
+++ b/nearby/tests/unit/AndroidTest.xml
@@ -15,6 +15,9 @@
~ limitations under the License.
-->
<configuration description="Runs Nearby Mainline API Tests.">
+ <!-- Only run tests if the device under test is SDK version 33 (Android 13) or above. -->
+ <object type="module_controller" class="com.android.tradefed.testtype.suite.module.Sdk33ModuleController" />
+
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="test-file-name" value="NearbyUnitTests.apk" />
</target_preparer>
diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java
index 6de6625..ae00a3a 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;
@@ -10645,13 +10646,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.
@@ -10676,9 +10693,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/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java b/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java
index f633df4..7a613b3 100644
--- a/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java
+++ b/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java
@@ -16,7 +16,6 @@
package com.android.cts.net;
-import android.platform.test.annotations.FlakyTest;
import android.platform.test.annotations.SecurityTest;
import com.android.ddmlib.Log;
@@ -155,7 +154,6 @@
"testBackgroundNetworkAccess_disabled");
}
- @FlakyTest(bugId=170180675)
public void testAppIdleMetered_whitelisted() throws Exception {
runDeviceTests(TEST_PKG, TEST_PKG + ".AppIdleMeteredTest",
"testBackgroundNetworkAccess_whitelisted");
@@ -186,7 +184,6 @@
"testBackgroundNetworkAccess_disabled");
}
- @FlakyTest(bugId=170180675)
public void testAppIdleNonMetered_whitelisted() throws Exception {
runDeviceTests(TEST_PKG, TEST_PKG + ".AppIdleNonMeteredTest",
"testBackgroundNetworkAccess_whitelisted");
diff --git a/tests/unit/java/com/android/server/ConnectivityServiceTest.java b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
index 6316c72..ed36a4f 100644
--- a/tests/unit/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
@@ -195,6 +195,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;
@@ -542,6 +543,7 @@
@Mock NetworkPolicyManager mNetworkPolicyManager;
@Mock VpnProfileStore mVpnProfileStore;
@Mock SystemConfigManager mSystemConfigManager;
+ @Mock DevicePolicyManager mDevicePolicyManager;
@Mock Resources mResources;
@Mock ClatCoordinator mClatCoordinator;
@Mock PacProxyManager mPacProxyManager;
@@ -664,6 +666,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;
@@ -693,6 +696,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;
@@ -14733,12 +14744,42 @@
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
+ */
+ @Test
+ 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);