Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1ef011e5 authored by Sarah Chin's avatar Sarah Chin
Browse files

Ensure SubscriptionPlans can be removed

Add a duration that the plans last and don't read to/write from disk
for plans. Make non-duration setSubscriptionPlans API deprecated.

Test: atest SubscriptionManagerTest, NetworkPolicyManagerServiceTest
Bug: 210696427
Change-Id: I93aece78eda324c333fbf9f1adbedcf46e4864f0
Merged-In: I93aece78eda324c333fbf9f1adbedcf46e4864f0
parent 64eae25b
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -41421,7 +41421,8 @@ package android.telephony {
    method public void setSubscriptionOverrideCongested(int, boolean, @NonNull int[], long);
    method public void setSubscriptionOverrideUnmetered(int, boolean, long);
    method public void setSubscriptionOverrideUnmetered(int, boolean, @NonNull int[], long);
    method public void setSubscriptionPlans(int, @NonNull java.util.List<android.telephony.SubscriptionPlan>);
    method @Deprecated public void setSubscriptionPlans(int, @NonNull java.util.List<android.telephony.SubscriptionPlan>);
    method public void setSubscriptionPlans(int, @NonNull java.util.List<android.telephony.SubscriptionPlan>, long);
    method @RequiresPermission("android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS") public void switchToSubscription(int, @NonNull android.app.PendingIntent);
    field public static final String ACTION_DEFAULT_SMS_SUBSCRIPTION_CHANGED = "android.telephony.action.DEFAULT_SMS_SUBSCRIPTION_CHANGED";
    field public static final String ACTION_DEFAULT_SUBSCRIPTION_CHANGED = "android.telephony.action.DEFAULT_SUBSCRIPTION_CHANGED";
+2 −2
Original line number Diff line number Diff line
@@ -72,9 +72,9 @@ interface INetworkPolicyManager {
    SubscriptionPlan getSubscriptionPlan(in NetworkTemplate template);
    void notifyStatsProviderWarningOrLimitReached();
    SubscriptionPlan[] getSubscriptionPlans(int subId, String callingPackage);
    void setSubscriptionPlans(int subId, in SubscriptionPlan[] plans, String callingPackage);
    void setSubscriptionPlans(int subId, in SubscriptionPlan[] plans, long expirationDurationMillis, String callingPackage);
    String getSubscriptionPlansOwner(int subId);
    void setSubscriptionOverride(int subId, int overrideMask, int overrideValue, in int[] networkTypes, long timeoutMillis, String callingPackage);
    void setSubscriptionOverride(int subId, int overrideMask, int overrideValue, in int[] networkTypes, long expirationDurationMillis, String callingPackage);

    void factoryReset(String subscriber);

+9 −6
Original line number Diff line number Diff line
@@ -484,8 +484,8 @@ public class NetworkPolicyManager {
     * @param networkTypes the network types this override applies to. If no
     *            network types are specified, override values will be ignored.
     *            {@see TelephonyManager#getAllNetworkTypes()}
     * @param timeoutMillis the timeout after which the requested override will
     *            be automatically cleared, or {@code 0} to leave in the
     * @param expirationDurationMillis the duration after which the requested override
     *            will be automatically cleared, or {@code 0} to leave in the
     *            requested state until explicitly cleared, or the next reboot,
     *            whichever happens first
     * @param callingPackage the name of the package making the call.
@@ -493,11 +493,11 @@ public class NetworkPolicyManager {
     */
    public void setSubscriptionOverride(int subId, @SubscriptionOverrideMask int overrideMask,
            @SubscriptionOverrideMask int overrideValue,
            @NonNull @Annotation.NetworkType int[] networkTypes, long timeoutMillis,
            @NonNull @Annotation.NetworkType int[] networkTypes, long expirationDurationMillis,
            @NonNull String callingPackage) {
        try {
            mService.setSubscriptionOverride(subId, overrideMask, overrideValue, networkTypes,
                    timeoutMillis, callingPackage);
                    expirationDurationMillis, callingPackage);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
@@ -508,13 +508,16 @@ public class NetworkPolicyManager {
     *
     * @param subId the subscriber this relationship applies to.
     * @param plans the list of plans.
     * @param expirationDurationMillis the duration after which the subscription plans
     *            will be automatically cleared, or {@code 0} to leave the plans until
     *            explicitly cleared, or the next reboot, whichever happens first
     * @param callingPackage the name of the package making the call
     * @hide
     */
    public void setSubscriptionPlans(int subId, @NonNull SubscriptionPlan[] plans,
            @NonNull String callingPackage) {
            long expirationDurationMillis, @NonNull String callingPackage) {
        try {
            mService.setSubscriptionPlans(subId, plans, callingPackage);
            mService.setSubscriptionPlans(subId, plans, expirationDurationMillis, callingPackage);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
+70 −114
Original line number Diff line number Diff line
@@ -118,9 +118,7 @@ import static com.android.internal.util.XmlUtils.readBooleanAttribute;
import static com.android.internal.util.XmlUtils.readIntAttribute;
import static com.android.internal.util.XmlUtils.readLongAttribute;
import static com.android.internal.util.XmlUtils.readStringAttribute;
import static com.android.internal.util.XmlUtils.readThisIntArrayXml;
import static com.android.internal.util.XmlUtils.writeBooleanAttribute;
import static com.android.internal.util.XmlUtils.writeIntArrayXml;
import static com.android.internal.util.XmlUtils.writeIntAttribute;
import static com.android.internal.util.XmlUtils.writeLongAttribute;
import static com.android.internal.util.XmlUtils.writeStringAttribute;
@@ -243,7 +241,6 @@ import com.android.internal.util.ConcurrentUtils;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.StatLogger;
import com.android.internal.util.XmlUtils;
import com.android.net.module.util.NetworkIdentityUtils;
import com.android.net.module.util.NetworkStatsUtils;
import com.android.net.module.util.PermissionUtils;
@@ -257,8 +254,6 @@ import com.android.server.usage.AppStandbyInternal.AppIdleStateChangeListener;

import libcore.io.IoUtils;

import org.xmlpull.v1.XmlPullParserException;

import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
@@ -334,7 +329,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
    private static final int VERSION_ADDED_CYCLE = 11;
    private static final int VERSION_ADDED_NETWORK_TYPES = 12;
    private static final int VERSION_SUPPORTED_CARRIER_USAGE = 13;
    private static final int VERSION_LATEST = VERSION_SUPPORTED_CARRIER_USAGE;
    private static final int VERSION_REMOVED_SUBSCRIPTION_PLANS = 14;
    private static final int VERSION_LATEST = VERSION_REMOVED_SUBSCRIPTION_PLANS;

    @VisibleForTesting
    public static final int TYPE_WARNING = SystemMessage.NOTE_NET_WARNING;
@@ -347,7 +343,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {

    private static final String TAG_POLICY_LIST = "policy-list";
    private static final String TAG_NETWORK_POLICY = "network-policy";
    private static final String TAG_SUBSCRIPTION_PLAN = "subscription-plan";
    private static final String TAG_UID_POLICY = "uid-policy";
    private static final String TAG_APP_POLICY = "app-policy";
    private static final String TAG_WHITELIST = "whitelist";
@@ -426,6 +421,13 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
     * obj = oldBlockedReasons
     */
    private static final int MSG_BLOCKED_REASON_CHANGED = 21;
    /**
     * Message to indicate that subscription plans expired and should be cleared.
     * arg1 = subId
     * arg2 = setSubscriptionPlans call ID
     * obj = callingPackage
     */
    private static final int MSG_CLEAR_SUBSCRIPTION_PLANS = 22;

    private static final int UID_MSG_STATE_CHANGED = 100;
    private static final int UID_MSG_GONE = 101;
@@ -492,6 +494,12 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
    /** Map from subId to package name that owns subscription plans. */
    @GuardedBy("mNetworkPoliciesSecondLock")
    final SparseArray<String> mSubscriptionPlansOwner = new SparseArray<>();
    /** Map from subId to the ID of the clear plans request. */
    @GuardedBy("mNetworkPoliciesSecondLock")
    final SparseIntArray mSetSubscriptionPlansIds = new SparseIntArray();
    /** Atomic integer to generate a new ID for each clear plans request. */
    @GuardedBy("mNetworkPoliciesSecondLock")
    int mSetSubscriptionPlansIdCounter = 0;

    /** Map from subId to daily opportunistic quota. */
    @GuardedBy("mNetworkPoliciesSecondLock")
@@ -2553,56 +2561,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
                                    warningBytes, limitBytes, lastWarningSnooze,
                                    lastLimitSnooze, metered, inferred));
                        }

                    } else if (TAG_SUBSCRIPTION_PLAN.equals(tag)) {
                        final String start = readStringAttribute(in, ATTR_CYCLE_START);
                        final String end = readStringAttribute(in, ATTR_CYCLE_END);
                        final String period = readStringAttribute(in, ATTR_CYCLE_PERIOD);
                        final SubscriptionPlan.Builder builder = new SubscriptionPlan.Builder(
                                RecurrenceRule.convertZonedDateTime(start),
                                RecurrenceRule.convertZonedDateTime(end),
                                RecurrenceRule.convertPeriod(period));
                        builder.setTitle(readStringAttribute(in, ATTR_TITLE));
                        builder.setSummary(readStringAttribute(in, ATTR_SUMMARY));

                        final long limitBytes = readLongAttribute(in, ATTR_LIMIT_BYTES,
                                SubscriptionPlan.BYTES_UNKNOWN);
                        final int limitBehavior = readIntAttribute(in, ATTR_LIMIT_BEHAVIOR,
                                SubscriptionPlan.LIMIT_BEHAVIOR_UNKNOWN);
                        if (limitBytes != SubscriptionPlan.BYTES_UNKNOWN
                                && limitBehavior != SubscriptionPlan.LIMIT_BEHAVIOR_UNKNOWN) {
                            builder.setDataLimit(limitBytes, limitBehavior);
                        }

                        final long usageBytes = readLongAttribute(in, ATTR_USAGE_BYTES,
                                SubscriptionPlan.BYTES_UNKNOWN);
                        final long usageTime = readLongAttribute(in, ATTR_USAGE_TIME,
                                SubscriptionPlan.TIME_UNKNOWN);
                        if (usageBytes != SubscriptionPlan.BYTES_UNKNOWN
                                && usageTime != SubscriptionPlan.TIME_UNKNOWN) {
                            builder.setDataUsage(usageBytes, usageTime);
                        }

                        final int subId = readIntAttribute(in, ATTR_SUB_ID);
                        final String ownerPackage = readStringAttribute(in, ATTR_OWNER_PACKAGE);

                        if (version >= VERSION_ADDED_NETWORK_TYPES) {
                            final int depth = in.getDepth();
                            while (XmlUtils.nextElementWithin(in, depth)) {
                                if (TAG_XML_UTILS_INT_ARRAY.equals(in.getName())
                                        && ATTR_NETWORK_TYPES.equals(
                                                readStringAttribute(in, ATTR_XML_UTILS_NAME))) {
                                    final int[] networkTypes =
                                            readThisIntArrayXml(in, TAG_XML_UTILS_INT_ARRAY, null);
                                    builder.setNetworkTypes(networkTypes);
                                }
                            }
                        }

                        final SubscriptionPlan plan = builder.build();
                        mSubscriptionPlans.put(subId, ArrayUtils.appendElement(
                                SubscriptionPlan.class, mSubscriptionPlans.get(subId), plan));
                        mSubscriptionPlansOwner.put(subId, ownerPackage);
                    } else if (TAG_UID_POLICY.equals(tag)) {
                        final int uid = readIntAttribute(in, ATTR_UID);
                        final int policy = readIntAttribute(in, ATTR_POLICY);
@@ -2793,38 +2751,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
                out.endTag(null, TAG_NETWORK_POLICY);
            }

            // write all known subscription plans
            for (int i = 0; i < mSubscriptionPlans.size(); i++) {
                final int subId = mSubscriptionPlans.keyAt(i);
                if (subId == INVALID_SUBSCRIPTION_ID) continue;
                final String ownerPackage = mSubscriptionPlansOwner.get(subId);
                final SubscriptionPlan[] plans = mSubscriptionPlans.valueAt(i);
                if (ArrayUtils.isEmpty(plans)) continue;

                for (SubscriptionPlan plan : plans) {
                    out.startTag(null, TAG_SUBSCRIPTION_PLAN);
                    writeIntAttribute(out, ATTR_SUB_ID, subId);
                    writeStringAttribute(out, ATTR_OWNER_PACKAGE, ownerPackage);
                    final RecurrenceRule cycleRule = plan.getCycleRule();
                    writeStringAttribute(out, ATTR_CYCLE_START,
                            RecurrenceRule.convertZonedDateTime(cycleRule.start));
                    writeStringAttribute(out, ATTR_CYCLE_END,
                            RecurrenceRule.convertZonedDateTime(cycleRule.end));
                    writeStringAttribute(out, ATTR_CYCLE_PERIOD,
                            RecurrenceRule.convertPeriod(cycleRule.period));
                    writeStringAttribute(out, ATTR_TITLE, plan.getTitle());
                    writeStringAttribute(out, ATTR_SUMMARY, plan.getSummary());
                    writeLongAttribute(out, ATTR_LIMIT_BYTES, plan.getDataLimitBytes());
                    writeIntAttribute(out, ATTR_LIMIT_BEHAVIOR, plan.getDataLimitBehavior());
                    writeLongAttribute(out, ATTR_USAGE_BYTES, plan.getDataUsageBytes());
                    writeLongAttribute(out, ATTR_USAGE_TIME, plan.getDataUsageTime());
                    try {
                        writeIntArrayXml(plan.getNetworkTypes(), ATTR_NETWORK_TYPES, out);
                    } catch (XmlPullParserException ignored) { }
                    out.endTag(null, TAG_SUBSCRIPTION_PLAN);
                }
            }

            // write all known uid policies
            for (int i = 0; i < mUidPolicy.size(); i++) {
                final int uid = mUidPolicy.keyAt(i);
@@ -3698,7 +3624,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
    }

    @Override
    public void setSubscriptionPlans(int subId, SubscriptionPlan[] plans, String callingPackage) {
    public void setSubscriptionPlans(int subId, SubscriptionPlan[] plans,
            long expirationDurationMillis, String callingPackage) {
        enforceSubscriptionPlanAccess(subId, Binder.getCallingUid(), callingPackage);
        enforceSubscriptionPlanValidity(plans);

@@ -3708,6 +3635,14 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {

        final long token = Binder.clearCallingIdentity();
        try {
            setSubscriptionPlansInternal(subId, plans, expirationDurationMillis, callingPackage);
        } finally {
            Binder.restoreCallingIdentity(token);
        }
    }

    private void setSubscriptionPlansInternal(int subId, SubscriptionPlan[] plans,
            long expirationDurationMillis, String callingPackage) {
        synchronized (mUidRulesFirstLock) {
            synchronized (mNetworkPoliciesSecondLock) {
                mSubscriptionPlans.put(subId, plans);
@@ -3722,17 +3657,22 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
                }

                handleNetworkPoliciesUpdateAL(true);
                }
            }

            final Intent intent = new Intent(SubscriptionManager.ACTION_SUBSCRIPTION_PLANS_CHANGED);
                final Intent intent = new Intent(
                        SubscriptionManager.ACTION_SUBSCRIPTION_PLANS_CHANGED);
                intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
                intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, subId);
            mContext.sendBroadcast(intent, android.Manifest.permission.MANAGE_SUBSCRIPTION_PLANS);
            mHandler.sendMessage(
                    mHandler.obtainMessage(MSG_SUBSCRIPTION_PLANS_CHANGED, subId, 0, plans));
        } finally {
            Binder.restoreCallingIdentity(token);
                mContext.sendBroadcast(intent,
                        android.Manifest.permission.MANAGE_SUBSCRIPTION_PLANS);
                mHandler.sendMessage(mHandler.obtainMessage(
                        MSG_SUBSCRIPTION_PLANS_CHANGED, subId, 0, plans));
                final int setPlansId = mSetSubscriptionPlansIdCounter++;
                mSetSubscriptionPlansIds.put(subId, setPlansId);
                if (expirationDurationMillis > 0) {
                    mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_CLEAR_SUBSCRIPTION_PLANS,
                            subId, setPlansId, callingPackage), expirationDurationMillis);
                }
            }
        }
    }

@@ -3758,7 +3698,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {

    @Override
    public void setSubscriptionOverride(int subId, int overrideMask, int overrideValue,
            int[] networkTypes, long timeoutMillis, String callingPackage) {
            int[] networkTypes, long expirationDurationMillis, String callingPackage) {
        enforceSubscriptionPlanAccess(subId, Binder.getCallingUid(), callingPackage);

        final ArraySet<Integer> allNetworksSet = new ArraySet<>();
@@ -3796,10 +3736,10 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
            args.arg3 = overrideValue;
            args.arg4 = applicableNetworks.toArray();
            mHandler.sendMessage(mHandler.obtainMessage(MSG_SUBSCRIPTION_OVERRIDE, args));
            if (timeoutMillis > 0) {
            if (expirationDurationMillis > 0) {
                args.arg3 = 0;
                mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_SUBSCRIPTION_OVERRIDE, args),
                        timeoutMillis);
                        expirationDurationMillis);
            }
        }
    }
@@ -5214,6 +5154,22 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
                    mListeners.finishBroadcast();
                    return true;
                }
                case MSG_CLEAR_SUBSCRIPTION_PLANS: {
                    synchronized (mUidRulesFirstLock) {
                        synchronized (mNetworkPoliciesSecondLock) {
                            int subId = msg.arg1;
                            if (msg.arg2 == mSetSubscriptionPlansIds.get(subId)) {
                                if (LOGD) Slog.d(TAG, "Clearing expired subscription plans.");
                                setSubscriptionPlansInternal(subId, new SubscriptionPlan[]{},
                                        0 /* expirationDurationMillis */,
                                        (String) msg.obj /* callingPackage */);
                            } else {
                                if (LOGD) Slog.d(TAG, "Ignoring stale CLEAR_SUBSCRIPTION_PLANS.");
                            }
                        }
                    }
                    return true;
                }
                case MSG_BLOCKED_REASON_CHANGED: {
                    final int uid = msg.arg1;
                    final int newBlockedReasons = msg.arg2;
+1 −1
Original line number Diff line number Diff line
@@ -2238,7 +2238,7 @@ public class NetworkPolicyManagerServiceTest {

    private void setSubscriptionPlans(int subId, SubscriptionPlan[] plans, String callingPackage)
            throws InterruptedException {
        mService.setSubscriptionPlans(subId, plans, callingPackage);
        mService.setSubscriptionPlans(subId, plans, 0, callingPackage);
        // setSubscriptionPlans() triggers async events, wait for those to be completed before
        // moving forward as they could interfere with the tests later.
        postMsgAndWaitForCompletion();
Loading