Merge "API to set managed subscriptions policy"
diff --git a/core/api/current.txt b/core/api/current.txt
index 5f3b1f3..4e281ec 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -7535,6 +7535,7 @@
method @Nullable public android.app.admin.PackagePolicy getManagedProfileCallerIdAccessPolicy();
method @Nullable public android.app.admin.PackagePolicy getManagedProfileContactsAccessPolicy();
method public long getManagedProfileMaximumTimeOff(@NonNull android.content.ComponentName);
+ method @NonNull public android.app.admin.ManagedSubscriptionsPolicy getManagedSubscriptionsPolicy();
method public int getMaximumFailedPasswordsForWipe(@Nullable android.content.ComponentName);
method public long getMaximumTimeToLock(@Nullable android.content.ComponentName);
method @NonNull public java.util.List<java.lang.String> getMeteredDataDisabledPackages(@NonNull android.content.ComponentName);
@@ -7685,6 +7686,7 @@
method public void setManagedProfileCallerIdAccessPolicy(@Nullable android.app.admin.PackagePolicy);
method public void setManagedProfileContactsAccessPolicy(@Nullable android.app.admin.PackagePolicy);
method public void setManagedProfileMaximumTimeOff(@NonNull android.content.ComponentName, long);
+ method public void setManagedSubscriptionsPolicy(@Nullable android.app.admin.ManagedSubscriptionsPolicy);
method public void setMasterVolumeMuted(@NonNull android.content.ComponentName, boolean);
method public void setMaximumFailedPasswordsForWipe(@NonNull android.content.ComponentName, int);
method public void setMaximumTimeToLock(@NonNull android.content.ComponentName, long);
@@ -7987,6 +7989,16 @@
method public java.time.MonthDay getStart();
}
+ public final class ManagedSubscriptionsPolicy implements android.os.Parcelable {
+ ctor public ManagedSubscriptionsPolicy(int);
+ method public int describeContents();
+ method public int getPolicyType();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.app.admin.ManagedSubscriptionsPolicy> CREATOR;
+ field public static final int TYPE_ALL_MANAGED_SUBSCRIPTIONS = 1; // 0x1
+ field public static final int TYPE_ALL_PERSONAL_SUBSCRIPTIONS = 0; // 0x0
+ }
+
public abstract class NetworkEvent implements android.os.Parcelable {
method public int describeContents();
method public long getId();
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index de03ba4..484ef4f 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -10997,6 +10997,51 @@
}
/**
+ * Called by a profile owner of an organization-owned device to specify {@link
+ * ManagedSubscriptionsPolicy}
+ *
+ * <p>Managed subscriptions policy controls how SIMs would be associated with the
+ * managed profile. For example a policy of type
+ * {@link ManagedSubscriptionsPolicy#TYPE_ALL_MANAGED_SUBSCRIPTIONS} assigns all
+ * SIM-based subscriptions to the managed profile. In this case OEM default
+ * dialer and messages app are automatically installed in the managed profile
+ * and all incoming and outgoing calls and text messages are handled by them.
+ * <p>This API can only be called during device setup.
+ *
+ * @param policy {@link ManagedSubscriptionsPolicy} policy, passing null for this resets the
+ * policy to be the default.
+ * @throws SecurityException if the caller is not a profile owner on an organization-owned
+ * managed profile.
+ * @throws IllegalStateException if called after the device setup has been completed.
+ * @see ManagedSubscriptionsPolicy
+ */
+ public void setManagedSubscriptionsPolicy(@Nullable ManagedSubscriptionsPolicy policy) {
+ throwIfParentInstance("setManagedSubscriptionsPolicy");
+ try {
+ mService.setManagedSubscriptionsPolicy(policy);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Returns the current {@link ManagedSubscriptionsPolicy}.
+ * If the policy has not been set, it will return a default policy of Type {@link
+ * ManagedSubscriptionsPolicy#TYPE_ALL_PERSONAL_SUBSCRIPTIONS}.
+ *
+ * @see #setManagedSubscriptionsPolicy(ManagedSubscriptionsPolicy)
+ */
+ @NonNull
+ public ManagedSubscriptionsPolicy getManagedSubscriptionsPolicy() {
+ throwIfParentInstance("getManagedSubscriptionsPolicy");
+ try {
+ return mService.getManagedSubscriptionsPolicy();
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Similar to {@link #logoutUser(ComponentName)}, except:
*
* <ul>
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 26d7667..20695ca 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -34,6 +34,7 @@
import android.app.admin.FactoryResetProtectionPolicy;
import android.app.admin.ManagedProfileProvisioningParams;
import android.app.admin.FullyManagedDeviceProvisioningParams;
+import android.app.admin.ManagedSubscriptionsPolicy;
import android.app.admin.WifiSsidPolicy;
import android.content.ComponentName;
import android.content.Intent;
@@ -583,4 +584,7 @@
void setMtePolicy(int flag);
int getMtePolicy();
+
+ void setManagedSubscriptionsPolicy(in ManagedSubscriptionsPolicy policy);
+ ManagedSubscriptionsPolicy getManagedSubscriptionsPolicy();
}
diff --git a/core/java/android/app/admin/ManagedSubscriptionsPolicy.aidl b/core/java/android/app/admin/ManagedSubscriptionsPolicy.aidl
new file mode 100644
index 0000000..f634f11
--- /dev/null
+++ b/core/java/android/app/admin/ManagedSubscriptionsPolicy.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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;
+
+parcelable ManagedSubscriptionsPolicy;
\ No newline at end of file
diff --git a/core/java/android/app/admin/ManagedSubscriptionsPolicy.java b/core/java/android/app/admin/ManagedSubscriptionsPolicy.java
new file mode 100644
index 0000000..1098c38
--- /dev/null
+++ b/core/java/android/app/admin/ManagedSubscriptionsPolicy.java
@@ -0,0 +1,156 @@
+/*
+ * 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.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
+
+import java.io.IOException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
+
+/**
+ * A policy class that describes how managed SIM subscriptions should behave on the device.
+ */
+public final class ManagedSubscriptionsPolicy implements Parcelable {
+ private static final String TAG = "ManagedSubscriptionsPolicy";
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"TYPE_"}, value = {TYPE_ALL_PERSONAL_SUBSCRIPTIONS,
+ TYPE_ALL_MANAGED_SUBSCRIPTIONS})
+ @interface ManagedSubscriptionsPolicyType {
+ }
+
+ /**
+ * Represents default policy to not have any managed subscriptions on the device.
+ */
+ public static final int TYPE_ALL_PERSONAL_SUBSCRIPTIONS = 0;
+
+ /**
+ * Represents policy to have only managed subscriptions on the device, any existing and
+ * future subscriptions on the device are exclusively associated with the managed profile.
+ *
+ * <p>When a subscription is associated with the managed profile, incoming/outgoing calls and
+ * text message using that subscription would only work via apps on managed profile.
+ * Also, Call logs and messages would be accessible only from the managed profile.
+ */
+ public static final int TYPE_ALL_MANAGED_SUBSCRIPTIONS = 1;
+
+ @ManagedSubscriptionsPolicyType
+ private final int mPolicyType;
+
+ private static final String KEY_POLICY_TYPE = "policy_type";
+
+ public ManagedSubscriptionsPolicy(@ManagedSubscriptionsPolicyType int policyType) {
+ if (policyType != TYPE_ALL_PERSONAL_SUBSCRIPTIONS
+ && policyType != TYPE_ALL_MANAGED_SUBSCRIPTIONS) {
+ throw new IllegalArgumentException("Invalid policy type");
+ }
+ mPolicyType = policyType;
+ }
+
+ @NonNull
+ public static final Parcelable.Creator<ManagedSubscriptionsPolicy> CREATOR =
+ new Parcelable.Creator<ManagedSubscriptionsPolicy>() {
+ public ManagedSubscriptionsPolicy createFromParcel(Parcel in) {
+ ManagedSubscriptionsPolicy policy = new ManagedSubscriptionsPolicy(
+ in.readInt());
+ return policy;
+ }
+
+ @Override
+ public ManagedSubscriptionsPolicy[] newArray(int size) {
+ return new ManagedSubscriptionsPolicy[size];
+ }
+ };
+
+ /**
+ * Returns the type of managed subscriptions policy, or {@link #TYPE_ALL_PERSONAL_SUBSCRIPTIONS}
+ * if no policy has been set.
+ *
+ * @return The policy type.
+ */
+ @ManagedSubscriptionsPolicyType
+ public int getPolicyType() {
+ return mPolicyType;
+ }
+
+ @Override
+ public String toString() {
+ return TextUtils.formatSimple("ManagedSubscriptionsPolicy (type: %d)", mPolicyType);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeInt(mPolicyType);
+ }
+
+ @Override
+ public boolean equals(Object thatObject) {
+ if (this == thatObject) {
+ return true;
+ }
+ if (!(thatObject instanceof ManagedSubscriptionsPolicy)) {
+ return false;
+ }
+ ManagedSubscriptionsPolicy that = (ManagedSubscriptionsPolicy) thatObject;
+ return mPolicyType == that.mPolicyType;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mPolicyType);
+ }
+
+ /** @hide */
+ @Nullable
+ public static ManagedSubscriptionsPolicy readFromXml(@NonNull TypedXmlPullParser parser) {
+ try {
+ ManagedSubscriptionsPolicy policy = new ManagedSubscriptionsPolicy(
+ parser.getAttributeInt(null, KEY_POLICY_TYPE, -1));
+
+ return policy;
+ } catch (IllegalArgumentException e) {
+ // Fail through
+ Log.w(TAG, "Load xml failed", e);
+ }
+ return null;
+ }
+
+ /**
+ * @hide
+ */
+ public void saveToXml(TypedXmlSerializer out) throws IOException {
+ out.attributeInt(null, KEY_POLICY_TYPE, mPolicyType);
+ }
+}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
index 70a7a02..4c42791 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
@@ -34,6 +34,7 @@
import android.app.admin.DeviceAdminInfo;
import android.app.admin.DevicePolicyManager;
import android.app.admin.FactoryResetProtectionPolicy;
+import android.app.admin.ManagedSubscriptionsPolicy;
import android.app.admin.PackagePolicy;
import android.app.admin.PasswordPolicy;
import android.app.admin.PreferentialNetworkServiceConfig;
@@ -168,6 +169,7 @@
private static final String TAG_PROTECTED_PACKAGES = "protected_packages";
private static final String TAG_SUSPENDED_PACKAGES = "suspended-packages";
private static final String TAG_MTE_POLICY = "mte-policy";
+ private static final String TAG_MANAGED_SUBSCRIPTIONS_POLICY = "managed_subscriptions_policy";
private static final String ATTR_VALUE = "value";
private static final String ATTR_LAST_NETWORK_LOGGING_NOTIFICATION = "last-notification";
private static final String ATTR_NUM_NETWORK_LOGGING_NOTIFICATIONS = "num-notifications";
@@ -272,6 +274,9 @@
// Wi-Fi SSID restriction policy.
WifiSsidPolicy mWifiSsidPolicy;
+ // Managed subscriptions policy.
+ ManagedSubscriptionsPolicy mManagedSubscriptionsPolicy;
+
// TODO: review implementation decisions with frameworks team
boolean specifiesGlobalProxy = false;
String globalProxySpec = null;
@@ -642,6 +647,11 @@
mManagedProfileCallerIdAccess);
writePackagePolicy(out, TAG_CROSS_PROFILE_CONTACTS_SEARCH_POLICY,
mManagedProfileContactsAccess);
+ if (mManagedSubscriptionsPolicy != null) {
+ out.startTag(null, TAG_MANAGED_SUBSCRIPTIONS_POLICY);
+ mManagedSubscriptionsPolicy.saveToXml(out);
+ out.endTag(null, TAG_MANAGED_SUBSCRIPTIONS_POLICY);
+ }
}
private void writePackagePolicy(TypedXmlSerializer out, String tag,
@@ -946,6 +956,8 @@
mManagedProfileCallerIdAccess = readPackagePolicy(parser);
} else if (TAG_CROSS_PROFILE_CONTACTS_SEARCH_POLICY.equals(tag)) {
mManagedProfileContactsAccess = readPackagePolicy(parser);
+ } else if (TAG_MANAGED_SUBSCRIPTIONS_POLICY.equals(tag)) {
+ mManagedSubscriptionsPolicy = ManagedSubscriptionsPolicy.readFromXml(parser);
} else {
Slogf.w(LOG_TAG, "Unknown admin tag: %s", tag);
XmlUtils.skipCurrentTag(parser);
@@ -1414,5 +1426,13 @@
pw.print("accountTypesWithManagementDisabled=");
pw.println(accountTypesWithManagementDisabled);
+
+ if (mManagedSubscriptionsPolicy != null) {
+ pw.println("mManagedSubscriptionsPolicy:");
+ pw.increaseIndent();
+ pw.print("mPolicyType=");
+ mManagedSubscriptionsPolicy.getPolicyType();
+ pw.decreaseIndent();
+ }
}
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 2b92b22..cdb2e08 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -218,6 +218,7 @@
import android.app.admin.FactoryResetProtectionPolicy;
import android.app.admin.FullyManagedDeviceProvisioningParams;
import android.app.admin.ManagedProfileProvisioningParams;
+import android.app.admin.ManagedSubscriptionsPolicy;
import android.app.admin.NetworkEvent;
import android.app.admin.PackagePolicy;
import android.app.admin.ParcelableGranteeMap;
@@ -334,6 +335,8 @@
import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.ParcelableKeyGenParameterSpec;
import android.stats.devicepolicy.DevicePolicyEnums;
+import android.telecom.TelecomManager;
+import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.telephony.data.ApnSetting;
import android.text.TextUtils;
@@ -768,6 +771,9 @@
private final DeviceStateCacheImpl mStateCache = new DeviceStateCacheImpl();
private final Object mESIDInitilizationLock = new Object();
private EnterpriseSpecificIdCalculator mEsidCalculator;
+ private final Object mSubscriptionsChangedListenerLock = new Object();
+ @GuardedBy("mSubscriptionsChangedListenerLock")
+ private SubscriptionManager.OnSubscriptionsChangedListener mSubscriptionsChangedListener;
/**
* Contains the list of OEM Default Role Holders for Contact-related roles
@@ -973,8 +979,6 @@
@GuardedBy("getLockObject()")
final SparseArray<DevicePolicyData> mUserData;
- @GuardedBy("getLockObject()")
-
final Handler mHandler;
final Handler mBackgroundHandler;
@@ -3092,6 +3096,7 @@
onLockSettingsReady();
loadAdminDataAsync();
mOwners.systemReady();
+ applyManagedSubscriptionsPolicyIfRequired();
break;
case SystemService.PHASE_ACTIVITY_MANAGER_READY:
synchronized (getLockObject()) {
@@ -3110,6 +3115,22 @@
}
}
+ private void applyManagedSubscriptionsPolicyIfRequired() {
+ int copeProfileUserId = getOrganizationOwnedProfileUserId();
+ // This policy is relevant only for COPE devices.
+ if (copeProfileUserId != UserHandle.USER_NULL) {
+ unregisterOnSubscriptionsChangedListener();
+ int policyType = getManagedSubscriptionsPolicy().getPolicyType();
+ if (policyType == ManagedSubscriptionsPolicy.TYPE_ALL_PERSONAL_SUBSCRIPTIONS) {
+ // By default, assign all current and future subs to system user on COPE devices.
+ registerListenerToAssignSubscriptionsToUser(UserHandle.USER_SYSTEM);
+ } else if (policyType == ManagedSubscriptionsPolicy.TYPE_ALL_MANAGED_SUBSCRIPTIONS) {
+ // Add listener to assign all current and future subs to managed profile.
+ registerListenerToAssignSubscriptionsToUser(copeProfileUserId);
+ }
+ }
+ }
+
private void updatePersonalAppsSuspensionOnUserStart(int userHandle) {
final int profileUserHandle = getManagedUserId(userHandle);
if (profileUserHandle >= 0) {
@@ -6993,9 +7014,23 @@
}
mLockSettingsInternal.refreshStrongAuthTimeout(parentId);
+ clearManagedSubscriptionsPolicy();
+
Slogf.i(LOG_TAG, "Cleaning up device-wide policies done.");
}
+ private void clearManagedSubscriptionsPolicy() {
+ unregisterOnSubscriptionsChangedListener();
+
+ SubscriptionManager subscriptionManager = mContext.getSystemService(
+ SubscriptionManager.class);
+ //Iterate over all the subscriptions and remove association with any user.
+ int[] subscriptionIds = subscriptionManager.getActiveSubscriptionIdList(false);
+ for (int subId : subscriptionIds) {
+ subscriptionManager.setSubscriptionUserHandle(subId, null);
+ }
+ }
+
/**
* @param factoryReset null: legacy behaviour, false: attempt to remove user, true: attempt to
* factory reset
@@ -10088,6 +10123,10 @@
mStateCache.dump(pw);
pw.println();
}
+
+ synchronized (mSubscriptionsChangedListenerLock) {
+ pw.println("Subscription changed listener : " + mSubscriptionsChangedListener);
+ }
mHandler.post(() -> handleDump(pw));
dumpResources(pw);
}
@@ -19952,4 +19991,139 @@
HEADLESS_FLAG,
DEFAULT_HEADLESS_FLAG);
}
+
+ @Override
+ public ManagedSubscriptionsPolicy getManagedSubscriptionsPolicy() {
+ synchronized (getLockObject()) {
+ ActiveAdmin admin = getProfileOwnerOfOrganizationOwnedDeviceLocked();
+ if (admin != null && admin.mManagedSubscriptionsPolicy != null) {
+ return admin.mManagedSubscriptionsPolicy;
+ }
+ }
+ return new ManagedSubscriptionsPolicy(
+ ManagedSubscriptionsPolicy.TYPE_ALL_PERSONAL_SUBSCRIPTIONS);
+ }
+
+ @Override
+ public void setManagedSubscriptionsPolicy(ManagedSubscriptionsPolicy policy) {
+ CallerIdentity caller = getCallerIdentity();
+ Preconditions.checkCallAuthorization(isProfileOwnerOfOrganizationOwnedDevice(caller),
+ "This policy can only be set by a profile owner on an organization-owned device.");
+
+ synchronized (getLockObject()) {
+ final ActiveAdmin admin = getProfileOwnerLocked(caller.getUserId());
+ if (hasUserSetupCompleted(UserHandle.USER_SYSTEM) && !isAdminTestOnlyLocked(
+ admin.info.getComponent(), caller.getUserId())) {
+ throw new IllegalStateException("Not allowed to apply this policy after setup");
+ }
+ boolean changed = false;
+ if (!Objects.equals(policy, admin.mManagedSubscriptionsPolicy)) {
+ admin.mManagedSubscriptionsPolicy = policy;
+ changed = true;
+ }
+ if (changed) {
+ saveSettingsLocked(caller.getUserId());
+ } else {
+ return;
+ }
+ }
+
+ applyManagedSubscriptionsPolicyIfRequired();
+
+ int policyType = getManagedSubscriptionsPolicy().getPolicyType();
+ if (policyType == ManagedSubscriptionsPolicy.TYPE_ALL_MANAGED_SUBSCRIPTIONS) {
+ final long id = mInjector.binderClearCallingIdentity();
+ try {
+ int parentUserId = getProfileParentId(caller.getUserId());
+ installOemDefaultDialerAndMessagesApp(parentUserId, caller.getUserId());
+ } finally {
+ mInjector.binderRestoreCallingIdentity(id);
+ }
+ }
+ }
+
+ private void installOemDefaultDialerAndMessagesApp(int sourceUserId, int targetUserId) {
+ try {
+ UserHandle sourceUserHandle = UserHandle.of(sourceUserId);
+ TelecomManager telecomManager = mContext.getSystemService(TelecomManager.class);
+ String dialerAppPackage = telecomManager.getDefaultDialerPackage(
+ sourceUserHandle);
+ String messagesAppPackage = SmsApplication.getDefaultSmsApplicationAsUser(mContext,
+ true, sourceUserHandle).getPackageName();
+ if (dialerAppPackage != null) {
+ mIPackageManager.installExistingPackageAsUser(dialerAppPackage, targetUserId,
+ PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS,
+ PackageManager.INSTALL_REASON_POLICY, null);
+ } else {
+ Slogf.w(LOG_TAG, "Couldn't install dialer app, dialer app package is null");
+ }
+
+ if (messagesAppPackage != null) {
+ mIPackageManager.installExistingPackageAsUser(messagesAppPackage, targetUserId,
+ PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS,
+ PackageManager.INSTALL_REASON_POLICY, null);
+ } else {
+ Slogf.w(LOG_TAG, "Couldn't install messages app, messages app package is null");
+ }
+ } catch (RemoteException re) {
+ // shouldn't happen
+ Slogf.wtf(LOG_TAG, "Failed to install dialer/messages app", re);
+ }
+ }
+
+ private void registerListenerToAssignSubscriptionsToUser(int userId) {
+ synchronized (mSubscriptionsChangedListenerLock) {
+ if (mSubscriptionsChangedListener != null) {
+ return;
+ }
+ SubscriptionManager subscriptionManager = mContext.getSystemService(
+ SubscriptionManager.class);
+ // Listener to assign all current and future subs to managed profile.
+ mSubscriptionsChangedListener = new SubscriptionManager.OnSubscriptionsChangedListener(
+ mHandler.getLooper()) {
+ @Override
+ public void onSubscriptionsChanged() {
+ final long id = mInjector.binderClearCallingIdentity();
+ try {
+ int[] subscriptionIds = subscriptionManager.getActiveSubscriptionIdList(
+ false);
+ for (int subId : subscriptionIds) {
+ UserHandle associatedUserHandle =
+ subscriptionManager.getSubscriptionUserHandle(subId);
+ if (associatedUserHandle == null
+ || associatedUserHandle.getIdentifier() != userId) {
+ subscriptionManager.setSubscriptionUserHandle(subId,
+ UserHandle.of(userId));
+ }
+ }
+ } finally {
+ mInjector.binderRestoreCallingIdentity(id);
+ }
+ }
+ };
+
+ final long id = mInjector.binderClearCallingIdentity();
+ try {
+ // When listener is added onSubscriptionsChanged gets called immediately for once
+ // (even if subscriptions are not changed) and later on when subscriptions changes.
+ subscriptionManager.addOnSubscriptionsChangedListener(
+ mSubscriptionsChangedListener.getHandlerExecutor(),
+ mSubscriptionsChangedListener);
+ } finally {
+ mInjector.binderRestoreCallingIdentity(id);
+ }
+ }
+ }
+
+ private void unregisterOnSubscriptionsChangedListener() {
+ synchronized (mSubscriptionsChangedListenerLock) {
+ if (mSubscriptionsChangedListener != null) {
+ SubscriptionManager subscriptionManager = mContext.getSystemService(
+ SubscriptionManager.class);
+ subscriptionManager.removeOnSubscriptionsChangedListener(
+ mSubscriptionsChangedListener);
+ mSubscriptionsChangedListener = null;
+ }
+ }
+ }
}
\ No newline at end of file
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 a55b196..61c3f13 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -5014,7 +5014,8 @@
.thenReturn(new UserInfo(UserHandle.USER_SYSTEM, "user system", 0));
when(getServices().userManager.getPrimaryUser())
.thenReturn(new UserInfo(UserHandle.USER_SYSTEM, "user system", 0));
-
+ when(getServices().subscriptionManager.getActiveSubscriptionIdList(false)).thenReturn(
+ new int[1]);
// Set some device-wide policies:
// Security logging
when(getServices().settings.securityLogGetLoggingEnabledProperty()).thenReturn(true);
@@ -5062,6 +5063,7 @@
// Unsuspend personal apps
verify(getServices().packageManagerInternal)
.unsuspendForSuspendingPackage(PLATFORM_PACKAGE_NAME, UserHandle.USER_SYSTEM);
+ verify(getServices().subscriptionManager).setSubscriptionUserHandle(0, null);
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
index ac1667d..c739969 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
@@ -239,6 +239,8 @@
return mMockSystemServices.locationManager;
case Context.ROLE_SERVICE:
return mMockSystemServices.roleManager;
+ case Context.TELEPHONY_SUBSCRIPTION_SERVICE:
+ return mMockSystemServices.subscriptionManager;
}
throw new UnsupportedOperationException();
}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
index cec9d50..2a6a979 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
@@ -63,6 +63,7 @@
import android.permission.IPermissionManager;
import android.provider.Settings;
import android.security.KeyChain;
+import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.test.mock.MockContentProvider;
import android.test.mock.MockContentResolver;
@@ -135,6 +136,7 @@
public final DevicePolicyManager devicePolicyManager;
public final LocationManager locationManager;
public final RoleManager roleManager;
+ public final SubscriptionManager subscriptionManager;
/** Note this is a partial mock, not a real mock. */
public final PackageManager packageManager;
public final BuildMock buildMock = new BuildMock();
@@ -188,6 +190,7 @@
devicePolicyManager = mock(DevicePolicyManager.class);
locationManager = mock(LocationManager.class);
roleManager = realContext.getSystemService(RoleManager.class);
+ subscriptionManager = mock(SubscriptionManager.class);
// Package manager is huge, so we use a partial mock instead.
packageManager = spy(realContext.getPackageManager());