diff --git a/core/api/current.txt b/core/api/current.txt index dfdbd75cbafe..64fac4b1ca5a 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -7185,6 +7185,7 @@ package android.app.admin { method @Nullable public java.util.List getPermittedCrossProfileNotificationListeners(@NonNull android.content.ComponentName); method @Nullable public java.util.List getPermittedInputMethods(@NonNull android.content.ComponentName); method public int getPersonalAppsSuspendedReasons(@NonNull android.content.ComponentName); + method @NonNull public android.app.admin.PreferentialNetworkServiceConfig getPreferentialNetworkServiceConfig(); method public int getRequiredPasswordComplexity(); method public long getRequiredStrongAuthTimeout(@Nullable android.content.ComponentName); method public boolean getScreenCaptureDisabled(@Nullable android.content.ComponentName); @@ -7327,6 +7328,7 @@ package android.app.admin { method public boolean setPermittedCrossProfileNotificationListeners(@NonNull android.content.ComponentName, @Nullable java.util.List); method public boolean setPermittedInputMethods(@NonNull android.content.ComponentName, java.util.List); method public void setPersonalAppsSuspended(@NonNull android.content.ComponentName, boolean); + method public void setPreferentialNetworkServiceConfig(@NonNull android.app.admin.PreferentialNetworkServiceConfig); method public void setPreferentialNetworkServiceEnabled(boolean); method public void setProfileEnabled(@NonNull android.content.ComponentName); method public void setProfileName(@NonNull android.content.ComponentName, String); @@ -7572,6 +7574,32 @@ package android.app.admin { field @NonNull public static final android.os.Parcelable.Creator CREATOR; } + public final class PreferentialNetworkServiceConfig implements android.os.Parcelable { + method public int describeContents(); + method @NonNull public int[] getExcludedUids(); + method @NonNull public int[] getIncludedUids(); + method public int getNetworkId(); + method public boolean isEnabled(); + method public boolean isFallbackToDefaultConnectionAllowed(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator CREATOR; + field public static final int PREFERENTIAL_NETWORK_ID_1 = 1; // 0x1 + field public static final int PREFERENTIAL_NETWORK_ID_2 = 2; // 0x2 + field public static final int PREFERENTIAL_NETWORK_ID_3 = 3; // 0x3 + field public static final int PREFERENTIAL_NETWORK_ID_4 = 4; // 0x4 + field public static final int PREFERENTIAL_NETWORK_ID_5 = 5; // 0x5 + } + + public static final class PreferentialNetworkServiceConfig.Builder { + ctor public PreferentialNetworkServiceConfig.Builder(); + method @NonNull public android.app.admin.PreferentialNetworkServiceConfig build(); + method @NonNull public android.app.admin.PreferentialNetworkServiceConfig.Builder setEnabled(boolean); + method @NonNull public android.app.admin.PreferentialNetworkServiceConfig.Builder setExcludedUids(@NonNull int[]); + method @NonNull public android.app.admin.PreferentialNetworkServiceConfig.Builder setFallbackToDefaultConnectionAllowed(boolean); + method @NonNull public android.app.admin.PreferentialNetworkServiceConfig.Builder setIncludedUids(@NonNull int[]); + method @NonNull public android.app.admin.PreferentialNetworkServiceConfig.Builder setNetworkId(int); + } + public class SecurityLog { ctor public SecurityLog(); field public static final int LEVEL_ERROR = 3; // 0x3 diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 0fe80c45ad2a..3840f760eda8 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -10177,6 +10177,9 @@ public class DevicePolicyManager { * On fully-managed devices this method is unsupported because all traffic is considered * work traffic. * + *

This method enables preferential network service with a default configuration. + * To fine-tune the configuration, use {@link #setPreferentialNetworkServiceConfig) instead. + * *

This method can only be called by the profile owner of a managed profile. * @param enabled whether preferential network service should be enabled. * @throws SecurityException if the caller is not the profile owner. @@ -10214,6 +10217,56 @@ public class DevicePolicyManager { } } + /** + * Sets preferential network configuration on the work profile. + * {@see PreferentialNetworkServiceConfig} + * + * An example of a supported preferential network service is the Enterprise + * slice on 5G networks. + * + * By default, preferential network service is disabled on the work profile on supported + * carriers and devices. Admins can explicitly enable it with this API. + * On fully-managed devices this method is unsupported because all traffic is considered + * work traffic. + * + *

This method can only be called by the profile owner of a managed profile. + * @param preferentialNetworkServiceConfig preferential network configuration. + * @throws SecurityException if the caller is not the profile owner. + **/ + public void setPreferentialNetworkServiceConfig( + @NonNull PreferentialNetworkServiceConfig preferentialNetworkServiceConfig) { + throwIfParentInstance("setPreferentialNetworkServiceConfig"); + if (mService == null) { + return; + } + try { + mService.setPreferentialNetworkServiceConfig(preferentialNetworkServiceConfig); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Get preferential network configuration + * {@see PreferentialNetworkServiceConfig} + * + *

This method can be called by the profile owner of a managed profile. + * + * @return preferential network configuration. + * @throws SecurityException if the caller is not the profile owner. + */ + public @NonNull PreferentialNetworkServiceConfig getPreferentialNetworkServiceConfig() { + throwIfParentInstance("getPreferentialNetworkServiceConfig"); + if (mService == null) { + return PreferentialNetworkServiceConfig.DEFAULT; + } + try { + return mService.getPreferentialNetworkServiceConfig(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + /** * This method is mostly deprecated. * Most of the settings that still have an effect have dedicated setter methods or user diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index d287437b143b..c78a5a00f645 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -21,6 +21,7 @@ import android.app.admin.NetworkEvent; import android.app.IApplicationThread; import android.app.IServiceConnection; import android.app.admin.ParcelableGranteeMap; +import android.app.admin.PreferentialNetworkServiceConfig; import android.app.admin.StartInstallingUpdateCallback; import android.app.admin.SystemUpdateInfo; import android.app.admin.SystemUpdatePolicy; @@ -278,6 +279,10 @@ interface IDevicePolicyManager { void setPreferentialNetworkServiceEnabled(in boolean enabled); boolean isPreferentialNetworkServiceEnabled(int userHandle); + void setPreferentialNetworkServiceConfig( + in PreferentialNetworkServiceConfig preferentialNetworkServiceConfig); + PreferentialNetworkServiceConfig getPreferentialNetworkServiceConfig(); + void setLockTaskPackages(in ComponentName who, in String[] packages); String[] getLockTaskPackages(in ComponentName who); boolean isLockTaskPermitted(in String pkg); diff --git a/core/java/android/app/admin/PreferentialNetworkServiceConfig.aidl b/core/java/android/app/admin/PreferentialNetworkServiceConfig.aidl new file mode 100644 index 000000000000..6b6ee7d8d538 --- /dev/null +++ b/core/java/android/app/admin/PreferentialNetworkServiceConfig.aidl @@ -0,0 +1,20 @@ +/* +** +** Copyright 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.app.admin; + +parcelable PreferentialNetworkServiceConfig; \ No newline at end of file diff --git a/core/java/android/app/admin/PreferentialNetworkServiceConfig.java b/core/java/android/app/admin/PreferentialNetworkServiceConfig.java new file mode 100644 index 000000000000..2849139c606b --- /dev/null +++ b/core/java/android/app/admin/PreferentialNetworkServiceConfig.java @@ -0,0 +1,335 @@ +/* + * 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.app.admin; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.SuppressLint; +import android.os.Parcel; +import android.os.Parcelable; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.Objects; + +/** + * Network configuration to be set for the user profile + * {@see DevicePolicyManager#setPreferentialNetworkServiceConfig}. + */ +public final class PreferentialNetworkServiceConfig implements Parcelable { + final boolean mIsEnabled; + final int mNetworkId; + final boolean mAllowFallbackToDefaultConnection; + final int[] mIncludedUids; + final int[] mExcludedUids; + + /** @hide */ + public static final PreferentialNetworkServiceConfig DEFAULT = + (new PreferentialNetworkServiceConfig.Builder()).build(); + + /** + * Preferential network identifier 1. + */ + public static final int PREFERENTIAL_NETWORK_ID_1 = 1; + + /** + * Preferential network identifier 2. + */ + public static final int PREFERENTIAL_NETWORK_ID_2 = 2; + + /** + * Preferential network identifier 3. + */ + public static final int PREFERENTIAL_NETWORK_ID_3 = 3; + + /** + * Preferential network identifier 4. + */ + public static final int PREFERENTIAL_NETWORK_ID_4 = 4; + + /** + * Preferential network identifier 5. + */ + public static final int PREFERENTIAL_NETWORK_ID_5 = 5; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = { "PREFERENTIAL_NETWORK_ID_" }, value = { + PREFERENTIAL_NETWORK_ID_1, + PREFERENTIAL_NETWORK_ID_2, + PREFERENTIAL_NETWORK_ID_3, + PREFERENTIAL_NETWORK_ID_4, + PREFERENTIAL_NETWORK_ID_5, + }) + + public @interface PreferentialNetworkPreferenceId { + } + + private PreferentialNetworkServiceConfig(boolean isEnabled, + boolean allowFallbackToDefaultConnection, int[] includedUids, + int[] excludedUids, @PreferentialNetworkPreferenceId int networkId) { + mIsEnabled = isEnabled; + mAllowFallbackToDefaultConnection = allowFallbackToDefaultConnection; + mIncludedUids = includedUids; + mExcludedUids = excludedUids; + mNetworkId = networkId; + } + + private PreferentialNetworkServiceConfig(Parcel in) { + mIsEnabled = in.readBoolean(); + mAllowFallbackToDefaultConnection = in.readBoolean(); + mNetworkId = in.readInt(); + mIncludedUids = in.createIntArray(); + mExcludedUids = in.createIntArray(); + } + + /** + * Is the preferential network enabled. + * @return true if enabled else false + */ + public boolean isEnabled() { + return mIsEnabled; + } + + /** + * is fallback to default network allowed. This boolean configures whether default connection + * (default internet or wifi) should be used or not if a preferential network service + * connection is not available. + * @return true if fallback is allowed, else false. + */ + public boolean isFallbackToDefaultConnectionAllowed() { + return mAllowFallbackToDefaultConnection; + } + + /** + * Get the array of uids that are applicable for the profile preference. + * + * {@see #getExcludedUids()} + * Included UIDs and Excluded UIDs can't both be non-empty. + * if both are empty, it means this request applies to all uids in the user profile. + * if included is not empty, then only included UIDs are applied. + * if excluded is not empty, then it is all uids in the user profile except these UIDs. + * @return Array of uids applicable for the profile preference. + * Empty array would mean that this request applies to all uids in the profile. + */ + public @NonNull int[] getIncludedUids() { + return mIncludedUids; + } + + /** + * Get the array of uids that are excluded for the profile preference. + * + * {@see #getIncludedUids()} + * Included UIDs and Excluded UIDs can't both be non-empty. + * if both are empty, it means this request applies to all uids in the user profile. + * if included is not empty, then only included UIDs are applied. + * if excluded is not empty, then it is all uids in the user profile except these UIDs. + * @return Array of uids that are excluded for the profile preference. + * Empty array would mean that this request applies to all uids in the profile. + */ + public @NonNull int[] getExcludedUids() { + return mExcludedUids; + } + + /** + * @return preference enterprise identifier. + * valid values starts from + * {@link #PREFERENTIAL_NETWORK_ID_1} to {@link #PREFERENTIAL_NETWORK_ID_5}. + * preference identifier is applicable only if preference network service is enabled + * + */ + public @PreferentialNetworkPreferenceId int getNetworkId() { + return mNetworkId; + } + + @Override + public String toString() { + return "PreferentialNetworkServiceConfig{" + + "mIsEnabled=" + isEnabled() + + "mAllowFallbackToDefaultConnection=" + isFallbackToDefaultConnectionAllowed() + + "mIncludedUids=" + mIncludedUids.toString() + + "mExcludedUids=" + mExcludedUids.toString() + + "mNetworkId=" + mNetworkId + + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + final PreferentialNetworkServiceConfig that = (PreferentialNetworkServiceConfig) o; + return mIsEnabled == that.mIsEnabled + && mAllowFallbackToDefaultConnection == that.mAllowFallbackToDefaultConnection + && mNetworkId == that.mNetworkId + && Objects.equals(mIncludedUids, that.mIncludedUids) + && Objects.equals(mExcludedUids, that.mExcludedUids); + } + + @Override + public int hashCode() { + return ((Objects.hashCode(mIsEnabled) * 17) + + (Objects.hashCode(mAllowFallbackToDefaultConnection) * 19) + + (Objects.hashCode(mIncludedUids) * 23) + + (Objects.hashCode(mExcludedUids) * 29) + + mNetworkId * 31); + } + + /** + * Builder used to create {@link PreferentialNetworkServiceConfig} objects. + * Specify the preferred Network preference + */ + public static final class Builder { + boolean mIsEnabled = false; + int mNetworkId = 0; + boolean mAllowFallbackToDefaultConnection = true; + int[] mIncludedUids = new int[0]; + int[] mExcludedUids = new int[0]; + + /** + * Constructs an empty Builder with preferential network disabled by default. + */ + public Builder() {} + + /** + * Set the preferential network service enabled state. + * Default value is false. + * @param isEnabled the desired network preference to use, true to enable else false + * @return The builder to facilitate chaining. + */ + @NonNull + public PreferentialNetworkServiceConfig.Builder setEnabled(boolean isEnabled) { + mIsEnabled = isEnabled; + return this; + } + + /** + * Set whether the default connection should be used as fallback. + * This boolean configures whether the default connection (default internet or wifi) + * should be used if a preferential network service connection is not available. + * Default value is true + * @param allowFallbackToDefaultConnection true if fallback is allowed else false + * @return The builder to facilitate chaining. + */ + @NonNull + @SuppressLint("MissingGetterMatchingBuilder") + public PreferentialNetworkServiceConfig.Builder setFallbackToDefaultConnectionAllowed( + boolean allowFallbackToDefaultConnection) { + mAllowFallbackToDefaultConnection = allowFallbackToDefaultConnection; + return this; + } + + /** + * Set the array of uids whose network access will go through this preferential + * network service. + * {@see #setExcludedUids(int[])} + * Included UIDs and Excluded UIDs can't both be non-empty. + * if both are empty, it means this request applies to all uids in the user profile. + * if included is not empty, then only included UIDs are applied. + * if excluded is not empty, then it is all uids in the user profile except these UIDs. + * @param uids array of included uids + * @return The builder to facilitate chaining. + */ + @NonNull + public PreferentialNetworkServiceConfig.Builder setIncludedUids( + @NonNull int[] uids) { + Objects.requireNonNull(uids); + mIncludedUids = uids; + return this; + } + + /** + * Set the array of uids who are not allowed through this preferential + * network service. + * {@see #setIncludedUids(int[])} + * Included UIDs and Excluded UIDs can't both be non-empty. + * if both are empty, it means this request applies to all uids in the user profile. + * if included is not empty, then only included UIDs are applied. + * if excluded is not empty, then it is all uids in the user profile except these UIDs. + * @param uids array of excluded uids + * @return The builder to facilitate chaining. + */ + @NonNull + public PreferentialNetworkServiceConfig.Builder setExcludedUids( + @NonNull int[] uids) { + Objects.requireNonNull(uids); + mExcludedUids = uids; + return this; + } + + /** + * Returns an instance of {@link PreferentialNetworkServiceConfig} created from the + * fields set on this builder. + */ + @NonNull + public PreferentialNetworkServiceConfig build() { + if (mIncludedUids.length > 0 && mExcludedUids.length > 0) { + throw new IllegalStateException("Both includedUids and excludedUids " + + "cannot be nonempty"); + } + return new PreferentialNetworkServiceConfig(mIsEnabled, + mAllowFallbackToDefaultConnection, mIncludedUids, mExcludedUids, mNetworkId); + } + + /** + * Set the preferential network identifier. + * Valid values starts from {@link #PREFERENTIAL_NETWORK_ID_1} to + * {@link #PREFERENTIAL_NETWORK_ID_5}. + * preference identifier is applicable only if preferential network service is enabled. + * @param preferenceId preference Id + * @return The builder to facilitate chaining. + */ + @NonNull + public PreferentialNetworkServiceConfig.Builder setNetworkId( + @PreferentialNetworkPreferenceId int preferenceId) { + if ((preferenceId < PREFERENTIAL_NETWORK_ID_1) + || (preferenceId > PREFERENTIAL_NETWORK_ID_5)) { + throw new IllegalArgumentException("Invalid preference identifier"); + } + mNetworkId = preferenceId; + return this; + } + } + + @Override + public void writeToParcel(@NonNull android.os.Parcel dest, int flags) { + dest.writeBoolean(mIsEnabled); + dest.writeBoolean(mAllowFallbackToDefaultConnection); + dest.writeInt(mNetworkId); + dest.writeIntArray(mIncludedUids); + dest.writeIntArray(mExcludedUids); + } + + @Override + public int describeContents() { + return 0; + } + + @NonNull + public static final Creator CREATOR = + new Creator() { + @Override + public PreferentialNetworkServiceConfig[] newArray(int size) { + return new PreferentialNetworkServiceConfig[size]; + } + + @Override + public PreferentialNetworkServiceConfig createFromParcel( + @NonNull android.os.Parcel in) { + return new PreferentialNetworkServiceConfig(in); + } + }; +} diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java index 37a84f3698c1..1c9d58458629 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java @@ -32,6 +32,7 @@ import android.app.admin.DeviceAdminInfo; import android.app.admin.DevicePolicyManager; import android.app.admin.FactoryResetProtectionPolicy; import android.app.admin.PasswordPolicy; +import android.app.admin.PreferentialNetworkServiceConfig; import android.graphics.Color; import android.os.Bundle; import android.os.PersistableBundle; @@ -294,6 +295,8 @@ class ActiveAdmin { public boolean mAdminCanGrantSensorsPermissions; public boolean mPreferentialNetworkServiceEnabled = DevicePolicyManager.PREFERENTIAL_NETWORK_SERVICE_ENABLED_DEFAULT; + public PreferentialNetworkServiceConfig mPreferentialNetworkServiceConfig = + PreferentialNetworkServiceConfig.DEFAULT; private static final boolean USB_DATA_SIGNALING_ENABLED_DEFAULT = true; boolean mUsbDataSignalingEnabled = USB_DATA_SIGNALING_ENABLED_DEFAULT; diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index a4162ba0e080..564b60825ab0 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -109,6 +109,7 @@ import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE; import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES; import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_DEFAULT; import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_ENTERPRISE; +import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_ENTERPRISE_NO_FALLBACK; import static android.net.NetworkCapabilities.NET_ENTERPRISE_ID_1; import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK; import static android.provider.Settings.Global.PRIVATE_DNS_SPECIFIER; @@ -180,6 +181,7 @@ import android.app.admin.NetworkEvent; import android.app.admin.ParcelableGranteeMap; import android.app.admin.PasswordMetrics; import android.app.admin.PasswordPolicy; +import android.app.admin.PreferentialNetworkServiceConfig; import android.app.admin.SecurityLog; import android.app.admin.SecurityLog.SecurityEvent; import android.app.admin.StartInstallingUpdateCallback; @@ -3278,14 +3280,14 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { updatePermissionPolicyCache(userId); updateAdminCanGrantSensorsPermissionCache(userId); - final boolean preferentialNetworkServiceEnabled; + final PreferentialNetworkServiceConfig preferentialNetworkServiceConfig; synchronized (getLockObject()) { ActiveAdmin owner = getDeviceOrProfileOwnerAdminLocked(userId); - preferentialNetworkServiceEnabled = owner != null - ? owner.mPreferentialNetworkServiceEnabled - : DevicePolicyManager.PREFERENTIAL_NETWORK_SERVICE_ENABLED_DEFAULT; + preferentialNetworkServiceConfig = owner != null + ? owner.mPreferentialNetworkServiceConfig + : PreferentialNetworkServiceConfig.DEFAULT; } - updateNetworkPreferenceForUser(userId, preferentialNetworkServiceEnabled); + updateNetworkPreferenceForUser(userId, preferentialNetworkServiceConfig); startOwnerService(userId, "start-user"); } @@ -3302,7 +3304,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { @Override void handleStopUser(int userId) { - updateNetworkPreferenceForUser(userId, false); + updateNetworkPreferenceForUser(userId, PreferentialNetworkServiceConfig.DEFAULT); stopOwnerService(userId, "stop-user"); } @@ -11846,7 +11848,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { final CallerIdentity caller = getCallerIdentity(); Preconditions.checkCallAuthorization(isProfileOwner(caller), "Caller is not profile owner;" - + " only profile owner may control the preferntial network service"); + + " only profile owner may control the preferential network service"); synchronized (getLockObject()) { final ActiveAdmin requiredAdmin = getProfileOwnerAdminLocked( caller.getUserId()); @@ -11882,6 +11884,47 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } } + @Override + public void setPreferentialNetworkServiceConfig( + PreferentialNetworkServiceConfig preferentialNetworkServiceConfig) { + if (!mHasFeature) { + return; + } + final CallerIdentity caller = getCallerIdentity(); + Preconditions.checkCallAuthorization(isProfileOwner(caller), + "Caller is not profile owner;" + + " only profile owner may control the preferential network service"); + synchronized (getLockObject()) { + final ActiveAdmin requiredAdmin = getProfileOwnerAdminLocked( + caller.getUserId()); + if (!requiredAdmin.mPreferentialNetworkServiceConfig.equals( + preferentialNetworkServiceConfig)) { + requiredAdmin.mPreferentialNetworkServiceConfig = preferentialNetworkServiceConfig; + saveSettingsLocked(caller.getUserId()); + } + } + updateNetworkPreferenceForUser(caller.getUserId(), preferentialNetworkServiceConfig); + DevicePolicyEventLogger + .createEvent(DevicePolicyEnums.SET_PREFERENTIAL_NETWORK_SERVICE_ENABLED) + .setBoolean(preferentialNetworkServiceConfig.isEnabled()) + .write(); + } + + @Override + public PreferentialNetworkServiceConfig getPreferentialNetworkServiceConfig() { + if (!mHasFeature) { + return PreferentialNetworkServiceConfig.DEFAULT; + } + + final CallerIdentity caller = getCallerIdentity(); + Preconditions.checkCallAuthorization(isProfileOwner(caller), + "Caller is not profile owner"); + synchronized (getLockObject()) { + final ActiveAdmin requiredAdmin = getProfileOwnerAdminLocked(caller.getUserId()); + return requiredAdmin.mPreferentialNetworkServiceConfig; + } + } + @Override public void setLockTaskPackages(ComponentName who, String[] packages) throws SecurityException { @@ -17538,8 +17581,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { if (!isManagedProfile(userId)) { return; } - int networkPreference = preferentialNetworkServiceEnabled - ? PROFILE_NETWORK_PREFERENCE_ENTERPRISE : PROFILE_NETWORK_PREFERENCE_DEFAULT; ProfileNetworkPreference.Builder preferenceBuilder = new ProfileNetworkPreference.Builder(); if (preferentialNetworkServiceEnabled) { @@ -17556,6 +17597,40 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { null /* executor */, null /* listener */)); } + private void updateNetworkPreferenceForUser(int userId, + PreferentialNetworkServiceConfig preferentialNetworkServiceConfig) { + if (!isManagedProfile(userId)) { + return; + } + ProfileNetworkPreference.Builder preferenceBuilder = + new ProfileNetworkPreference.Builder(); + if (preferentialNetworkServiceConfig.isEnabled()) { + if (preferentialNetworkServiceConfig.isFallbackToDefaultConnectionAllowed()) { + preferenceBuilder.setPreference(PROFILE_NETWORK_PREFERENCE_ENTERPRISE); + } else { + preferenceBuilder.setPreference(PROFILE_NETWORK_PREFERENCE_ENTERPRISE_NO_FALLBACK); + } + } else { + preferenceBuilder.setPreference(PROFILE_NETWORK_PREFERENCE_DEFAULT); + } + List allowedUids = Arrays.stream( + preferentialNetworkServiceConfig.getIncludedUids()).boxed().collect( + Collectors.toList()); + List excludedUids = Arrays.stream( + preferentialNetworkServiceConfig.getExcludedUids()).boxed().collect( + Collectors.toList()); + preferenceBuilder.setIncludedUids(allowedUids); + preferenceBuilder.setExcludedUids(excludedUids); + preferenceBuilder.setPreferenceEnterpriseId( + preferentialNetworkServiceConfig.getNetworkId()); + List preferences = new ArrayList<>(); + preferences.add(preferenceBuilder.build()); + mInjector.binderWithCleanCallingIdentity(() -> + mInjector.getConnectivityManager().setProfileNetworkPreferences( + UserHandle.of(userId), preferences, + null /* executor */, null /* listener */)); + } + @Override public boolean canAdminGrantSensorsPermissionsForUser(int userId) { if (!mHasFeature) { diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java index 6c1d16402cab..3511fc1c36d5 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java @@ -39,6 +39,7 @@ import static android.app.admin.PasswordMetrics.computeForPasswordOrPin; import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE; import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_DEFAULT; import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_ENTERPRISE; +import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_ENTERPRISE_NO_FALLBACK; import static android.net.InetAddresses.parseNumericAddress; import static android.net.NetworkCapabilities.NET_ENTERPRISE_ID_1; @@ -90,6 +91,7 @@ import android.app.admin.DevicePolicyManagerInternal; import android.app.admin.DevicePolicyManagerLiteInternal; import android.app.admin.FactoryResetProtectionPolicy; import android.app.admin.PasswordMetrics; +import android.app.admin.PreferentialNetworkServiceConfig; import android.app.admin.SystemUpdatePolicy; import android.content.BroadcastReceiver; import android.content.ComponentName; @@ -4119,6 +4121,164 @@ public class DevicePolicyManagerTest extends DpmTestBase { null, null); } + @Test + public void testSetPreferentialNetworkServiceConfig_noProfileOwner() throws Exception { + assertExpectException(SecurityException.class, null, + () -> dpm.setPreferentialNetworkServiceConfig( + PreferentialNetworkServiceConfig.DEFAULT)); + } + + @Test + public void testIsPreferentialNetworkServiceEnabled_noProfileOwner() throws Exception { + assertExpectException(SecurityException.class, null, + () -> dpm.isPreferentialNetworkServiceEnabled()); + } + + @Test + public void testSetPreferentialNetworkServiceConfig_invalidConfig() throws Exception { + final int managedProfileUserId = 15; + final int managedProfileAdminUid = UserHandle.getUid(managedProfileUserId, 19436); + addManagedProfile(admin1, managedProfileAdminUid, admin1); + mContext.binder.callingUid = managedProfileAdminUid; + + PreferentialNetworkServiceConfig.Builder preferentialNetworkServiceConfigBuilder = + new PreferentialNetworkServiceConfig.Builder(); + assertExpectException(NullPointerException.class, null, + () -> preferentialNetworkServiceConfigBuilder.setIncludedUids(null)); + assertExpectException(NullPointerException.class, null, + () -> preferentialNetworkServiceConfigBuilder.setExcludedUids(null)); + assertExpectException(IllegalArgumentException.class, null, + () -> preferentialNetworkServiceConfigBuilder.setNetworkId(6)); + int[] includedUids = new int[]{1, 2}; + int[] excludedUids = new int[]{3, 4}; + preferentialNetworkServiceConfigBuilder.setIncludedUids(includedUids); + preferentialNetworkServiceConfigBuilder.setExcludedUids(excludedUids); + + assertExpectException(IllegalStateException.class, null, + () -> preferentialNetworkServiceConfigBuilder.build()); + } + + @Test + public void testSetPreferentialNetworkServiceConfig_defaultPreference() throws Exception { + final int managedProfileUserId = 15; + final int managedProfileAdminUid = UserHandle.getUid(managedProfileUserId, 19436); + addManagedProfile(admin1, managedProfileAdminUid, admin1); + mContext.binder.callingUid = managedProfileAdminUid; + + dpm.setPreferentialNetworkServiceConfig(PreferentialNetworkServiceConfig.DEFAULT); + assertThat(dpm.isPreferentialNetworkServiceEnabled()).isFalse(); + assertThat(dpm.getPreferentialNetworkServiceConfig() + .isEnabled()).isFalse(); + + ProfileNetworkPreference preferenceDetails = + new ProfileNetworkPreference.Builder() + .setPreference(PROFILE_NETWORK_PREFERENCE_DEFAULT) + .build(); + List preferences = new ArrayList<>(); + preferences.add(preferenceDetails); + verify(getServices().connectivityManager, times(1)) + .setProfileNetworkPreferences(UserHandle.of(managedProfileUserId), preferences, + null, null); + } + + @Test + public void testSetPreferentialNetworkServiceConfig_enterprisePreference() throws Exception { + PreferentialNetworkServiceConfig preferentialNetworkServiceConfigEnabled = + (new PreferentialNetworkServiceConfig.Builder()) + .setEnabled(true) + .setNetworkId(NET_ENTERPRISE_ID_1) + .build(); + + final int managedProfileUserId = 15; + final int managedProfileAdminUid = UserHandle.getUid(managedProfileUserId, 19436); + addManagedProfile(admin1, managedProfileAdminUid, admin1); + mContext.binder.callingUid = managedProfileAdminUid; + + dpm.setPreferentialNetworkServiceConfig(preferentialNetworkServiceConfigEnabled); + assertThat(dpm.getPreferentialNetworkServiceConfig() + .isEnabled()).isTrue(); + ProfileNetworkPreference preferenceDetails = + new ProfileNetworkPreference.Builder() + .setPreference(PROFILE_NETWORK_PREFERENCE_ENTERPRISE) + .setPreferenceEnterpriseId(NET_ENTERPRISE_ID_1) + .build(); + List preferences = new ArrayList<>(); + preferences.add(preferenceDetails); + verify(getServices().connectivityManager, times(1)) + .setProfileNetworkPreferences(UserHandle.of(managedProfileUserId), preferences, + null, null); + } + + @Test + public void testSetPreferentialNetworkServiceConfig_enterprisePreferenceIncludedUids() + throws Exception { + final int managedProfileUserId = 15; + final int managedProfileAdminUid = UserHandle.getUid(managedProfileUserId, 19436); + addManagedProfile(admin1, managedProfileAdminUid, admin1); + mContext.binder.callingUid = managedProfileAdminUid; + + PreferentialNetworkServiceConfig preferentialNetworkServiceConfigEnabled = + (new PreferentialNetworkServiceConfig.Builder()) + .setEnabled(true) + .setNetworkId(NET_ENTERPRISE_ID_1) + .setFallbackToDefaultConnectionAllowed(false) + .setIncludedUids(new int[]{1, 2}) + .build(); + dpm.setPreferentialNetworkServiceConfig(preferentialNetworkServiceConfigEnabled); + assertThat(dpm.getPreferentialNetworkServiceConfig() + .isEnabled()).isTrue(); + List includedList = new ArrayList<>(); + includedList.add(1); + includedList.add(2); + ProfileNetworkPreference preferenceDetails = + new ProfileNetworkPreference.Builder() + .setPreference(PROFILE_NETWORK_PREFERENCE_ENTERPRISE_NO_FALLBACK) + .setPreferenceEnterpriseId(NET_ENTERPRISE_ID_1) + .setIncludedUids(includedList) + .build(); + List preferences = new ArrayList<>(); + preferences.add(preferenceDetails); + verify(getServices().connectivityManager, times(1)) + .setProfileNetworkPreferences(UserHandle.of(managedProfileUserId), preferences, + null, null); + } + + @Test + public void testSetPreferentialNetworkServiceConfig_enterprisePreferenceExcludedUids() + throws Exception { + final int managedProfileUserId = 15; + final int managedProfileAdminUid = UserHandle.getUid(managedProfileUserId, 19436); + addManagedProfile(admin1, managedProfileAdminUid, admin1); + mContext.binder.callingUid = managedProfileAdminUid; + + PreferentialNetworkServiceConfig preferentialNetworkServiceConfigEnabled = + (new PreferentialNetworkServiceConfig.Builder()) + .setEnabled(true) + .setNetworkId(NET_ENTERPRISE_ID_1) + .setFallbackToDefaultConnectionAllowed(false) + .setExcludedUids(new int[]{1, 2}) + .build(); + + dpm.setPreferentialNetworkServiceConfig(preferentialNetworkServiceConfigEnabled); + assertThat(dpm.getPreferentialNetworkServiceConfig() + .isEnabled()).isTrue(); + List excludedUids = new ArrayList<>(); + excludedUids.add(1); + excludedUids.add(2); + ProfileNetworkPreference preferenceDetails = + new ProfileNetworkPreference.Builder() + .setPreference(PROFILE_NETWORK_PREFERENCE_ENTERPRISE_NO_FALLBACK) + .setPreferenceEnterpriseId(NET_ENTERPRISE_ID_1) + .setExcludedUids(excludedUids) + .build(); + List preferences = new ArrayList<>(); + preferences.clear(); + preferences.add(preferenceDetails); + verify(getServices().connectivityManager, times(1)) + .setProfileNetworkPreferences(UserHandle.of(managedProfileUserId), preferences, + null, null); + } + @Test public void testSetSystemSettingFailWithNonWhitelistedSettings() throws Exception { mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;