diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java index 57f2ad4b78..06556ad5f1 100644 --- a/service/src/com/android/server/ConnectivityService.java +++ b/service/src/com/android/server/ConnectivityService.java @@ -1600,6 +1600,11 @@ public class ConnectivityService extends IConnectivityManager.Stub cr.registerContentObserver(uri, notifyForDescendants, observer); } + public void registerContentObserverAsUser(ContentResolver cr, Uri uri, + boolean notifyForDescendants, ContentObserver observer, UserHandle userHandle) { + cr.registerContentObserverAsUser(uri, notifyForDescendants, observer, userHandle); + } + /** * Get a reference to the ModuleNetworkStackClient. */ @@ -2518,7 +2523,7 @@ public class ConnectivityService extends IConnectivityManager.Stub EVENT_CONFIGURE_ALWAYS_ON_NETWORKS); // Watch for mobile data preferred uids changes. - mSettingsObserver.observe( + mSettingsObserver.observeForAllUsers( Settings.Secure.getUriFor(ConnectivitySettingsManager.MOBILE_DATA_PREFERRED_UIDS), EVENT_MOBILE_DATA_PREFERRED_UIDS_CHANGED); @@ -4390,7 +4395,7 @@ public class ConnectivityService extends IConnectivityManager.Stub // Note that updating can be skipped here if the list is empty only because no uid // rules are applied before system ready. Normally, the empty uid list means to clear // the uids rules on netd. - if (!ConnectivitySettingsManager.getMobileDataPreferredUids(mContext).isEmpty()) { + if (!getMobileDataPreferredUids().isEmpty()) { mHandler.sendEmptyMessage(EVENT_MOBILE_DATA_PREFERRED_UIDS_CHANGED); } @@ -7674,11 +7679,20 @@ public class ConnectivityService extends IConnectivityManager.Stub } private static class SettingsObserver extends ContentObserver { - private final HashMap mUriEventMap; + private final HashMap mUriEventMap; private final Context mContext; private final Handler mHandler; private final Dependencies mDeps; + private static class SettingInfo { + final int what; + final boolean forAllUsers; + SettingInfo(int what, boolean forAllUsers) { + this.what = what; + this.forAllUsers = forAllUsers; + } + } + SettingsObserver(Context context, Handler handler, Dependencies deps) { super(null); mUriEventMap = new HashMap<>(); @@ -7687,9 +7701,50 @@ public class ConnectivityService extends IConnectivityManager.Stub mDeps = deps; } + /** + * Observe settings changes for the specified URI on the current user. + * + * Sends an empty message with the specified {@code what} whenever the setting changes on + * the current user. + * + * @param uri The URI to observe. + * @param what The empty message to send whenever the setting changes. + */ void observe(Uri uri, int what) { - mUriEventMap.put(uri, what); - mDeps.registerContentObserver(mContext.getContentResolver(), uri, false, this); + mUriEventMap.put(uri, new SettingInfo(what, false /* forAllUsers */)); + final ContentResolver resolver = mContext.getContentResolver(); + mDeps.registerContentObserver(resolver, uri, false, this); + } + + /** + * Observe settings changes for the specified URI on all users. + * + * Sends an empty message with the specified {@code what} whenever the setting changes on + * any user, or whenever a user is added or removed. + * + * @param uri The URI to observe. + * @param what The empty message to send whenever the setting changes. + */ + void observeForAllUsers(Uri uri, int what) { + if (!SdkLevel.isAtLeastT()) { + observe(uri, what); + return; + } + mUriEventMap.put(uri, new SettingInfo(what, true /* forAllUsers */)); + final ContentResolver resolver = mContext.getContentResolver(); + mDeps.registerContentObserverAsUser(resolver, uri, false, this, UserHandle.ALL); + } + + void onUsersChanged() { + for (SettingInfo si : mUriEventMap.values()) { + if (si.forAllUsers) { + sendMessage(si.what); + } + } + } + + private void sendMessage(int what) { + mHandler.obtainMessage(what).sendToTarget(); } @Override @@ -7699,13 +7754,21 @@ public class ConnectivityService extends IConnectivityManager.Stub @Override public void onChange(boolean selfChange, Uri uri) { - final Integer what = mUriEventMap.get(uri); - if (what != null) { - mHandler.obtainMessage(what).sendToTarget(); + final SettingInfo si = mUriEventMap.get(uri); + if (si != null) { + sendMessage(si.what); } else { loge("No matching event to send for URI=" + uri); } } + + @Override + public void onChange(boolean selfChange, @NonNull Collection uris, + int flags, UserHandle unused) { + for (Uri uri : uris) { + onChange(selfChange, uri); + } + } } private static void log(String s) { @@ -8005,6 +8068,7 @@ public class ConnectivityService extends IConnectivityManager.Stub if (mSatelliteAccessController != null) { mSatelliteAccessController.onUserAddedWithInstalledPackageList(user, apps); } + mSettingsObserver.onUsersChanged(); } @Override @@ -8023,6 +8087,7 @@ public class ConnectivityService extends IConnectivityManager.Stub if (mSatelliteAccessController != null) { mSatelliteAccessController.onUserRemoved(user); } + mSettingsObserver.onUsersChanged(); } @Override @@ -14919,8 +14984,17 @@ public class ConnectivityService extends IConnectivityManager.Stub return requests; } + private Set getMobileDataPreferredUids() { + Set uids = new ArraySet<>(); + for (UserHandle userHandle : mUserManager.getUserHandles(/* excludeDying= */ true)) { + final Context userContext = mContext.createContextAsUser(userHandle, 0 /* flags */); + uids.addAll(ConnectivitySettingsManager.getMobileDataPreferredUids(userContext)); + } + return uids; + } + private void handleMobileDataPreferredUidsChanged() { - mMobileDataPreferredUids = ConnectivitySettingsManager.getMobileDataPreferredUids(mContext); + mMobileDataPreferredUids = getMobileDataPreferredUids(); removeDefaultNetworkRequestsForPreference(PREFERENCE_ORDER_MOBILE_DATA_PREFERERRED); addPerAppDefaultNetworkRequests( createNrisFromMobileDataPreferredUids(mMobileDataPreferredUids)); diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java index e25eddb63d..6d5cc5f6f2 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -28,7 +28,6 @@ import static android.Manifest.permission.NETWORK_SETUP_WIZARD; import static android.Manifest.permission.NETWORK_STACK; import static android.Manifest.permission.READ_DEVICE_CONFIG; import static android.Manifest.permission.TETHER_PRIVILEGED; -import static android.content.pm.PackageManager.FEATURE_AUTOMOTIVE; import static android.content.pm.PackageManager.FEATURE_BLUETOOTH; import static android.content.pm.PackageManager.FEATURE_ETHERNET; import static android.content.pm.PackageManager.FEATURE_TELEPHONY; @@ -3416,9 +3415,6 @@ public class ConnectivityManagerTest { && mPackageManager.hasSystemFeature(FEATURE_TELEPHONY); assumeTrue("testMobileDataPreferredUidsWithCallback cannot execute" + " unless device supports both WiFi and telephony", canRunTest); - // TODO(b/404186833): re-enable - assumeFalse("testMobileDataPreferredUids is broken on automotive", - mPackageManager.hasSystemFeature(FEATURE_AUTOMOTIVE)); final int uid = mPackageManager.getPackageUid(mContext.getPackageName(), 0 /* flag */); final Set mobileDataPreferredUids = diff --git a/tests/unit/java/com/android/server/ConnectivityServiceTest.java b/tests/unit/java/com/android/server/ConnectivityServiceTest.java index 86e0c34035..fcbf416fbf 100644 --- a/tests/unit/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/unit/java/com/android/server/ConnectivityServiceTest.java @@ -2036,6 +2036,13 @@ public class ConnectivityServiceTest { .registerContentObserver(uri, observer); } + @Override + public void registerContentObserverAsUser(ContentResolver cr, Uri uri, + boolean notifyForDescendants, ContentObserver observer, UserHandle userHandle) { + ((ContentResolverWithFakeSettingsProvider) mServiceContext.getContentResolver()) + .registerContentObserverAsUser(uri, observer, userHandle); + } + @Override public NetworkStackClientBase getNetworkStack() { return mNetworkStack; diff --git a/tests/unit/java/com/android/server/connectivityservice/base/CSTest.kt b/tests/unit/java/com/android/server/connectivityservice/base/CSTest.kt index 68b05dc842..e7fe16082e 100644 --- a/tests/unit/java/com/android/server/connectivityservice/base/CSTest.kt +++ b/tests/unit/java/com/android/server/connectivityservice/base/CSTest.kt @@ -358,6 +358,10 @@ open class CSTest { ) = (cr as ContentResolverWithFakeSettingsProvider).registerContentObserver(uri, observer) + override fun registerContentObserverAsUser(cr: ContentResolver, uri: Uri, + notifyForDescendants: Boolean, observer: ContentObserver, userHandle: UserHandle) = + context.getContentResolver().registerContentObserverAsUser(uri, observer, userHandle) + override fun makeCarrierPrivilegeAuthenticator( context: Context, tm: TelephonyManager,