diff --git a/api/current.txt b/api/current.txt index bd77dfca4b5f7..638b0a90f9486 100644 --- a/api/current.txt +++ b/api/current.txt @@ -45106,6 +45106,7 @@ package android.telephony { method public long getDataLimitBytes(); method public long getDataUsageBytes(); method public long getDataUsageTime(); + method @Nullable public int[] getNetworkTypes(); method @Nullable public CharSequence getSummary(); method @Nullable public CharSequence getTitle(); method public void writeToParcel(android.os.Parcel, int); @@ -45125,6 +45126,7 @@ package android.telephony { method public static android.telephony.SubscriptionPlan.Builder createRecurring(java.time.ZonedDateTime, java.time.Period); method public android.telephony.SubscriptionPlan.Builder setDataLimit(long, int); method public android.telephony.SubscriptionPlan.Builder setDataUsage(long, long); + method @NonNull public android.telephony.SubscriptionPlan.Builder setNetworkTypes(@Nullable int[]); method public android.telephony.SubscriptionPlan.Builder setSummary(@Nullable CharSequence); method public android.telephony.SubscriptionPlan.Builder setTitle(@Nullable CharSequence); } diff --git a/core/java/android/net/INetworkPolicyListener.aidl b/core/java/android/net/INetworkPolicyListener.aidl index 106b7be5c8d31..fe9141cb6a202 100644 --- a/core/java/android/net/INetworkPolicyListener.aidl +++ b/core/java/android/net/INetworkPolicyListener.aidl @@ -15,6 +15,7 @@ */ package android.net; +import android.telephony.SubscriptionPlan; /** {@hide} */ oneway interface INetworkPolicyListener { @@ -22,5 +23,6 @@ oneway interface INetworkPolicyListener { void onMeteredIfacesChanged(in String[] meteredIfaces); void onRestrictBackgroundChanged(boolean restrictBackground); void onUidPoliciesChanged(int uid, int uidPolicies); - void onSubscriptionOverride(int subId, int overrideMask, int overrideValue, long networkTypeMask); + void onSubscriptionOverride(int subId, int overrideMask, int overrideValue); + void onSubscriptionPlansChanged(int subId, in SubscriptionPlan[] plans); } diff --git a/core/java/android/net/INetworkPolicyManager.aidl b/core/java/android/net/INetworkPolicyManager.aidl index 90327663e34bc..385cb1d68b57f 100644 --- a/core/java/android/net/INetworkPolicyManager.aidl +++ b/core/java/android/net/INetworkPolicyManager.aidl @@ -76,7 +76,7 @@ interface INetworkPolicyManager { SubscriptionPlan[] getSubscriptionPlans(int subId, String callingPackage); void setSubscriptionPlans(int subId, in SubscriptionPlan[] plans, String callingPackage); String getSubscriptionPlansOwner(int subId); - void setSubscriptionOverride(int subId, int overrideMask, int overrideValue, long networkTypeMask, long timeoutMillis, String callingPackage); + void setSubscriptionOverride(int subId, int overrideMask, int overrideValue, long timeoutMillis, String callingPackage); void factoryReset(String subscriber); diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java index 628dcd2691cfd..9150aae14049c 100644 --- a/core/java/android/net/NetworkPolicyManager.java +++ b/core/java/android/net/NetworkPolicyManager.java @@ -31,6 +31,7 @@ import android.net.wifi.WifiInfo; import android.os.Build; import android.os.RemoteException; import android.os.UserHandle; +import android.telephony.SubscriptionPlan; import android.util.DebugUtils; import android.util.Pair; import android.util.Range; @@ -380,7 +381,8 @@ public class NetworkPolicyManager { @Override public void onMeteredIfacesChanged(String[] meteredIfaces) { } @Override public void onRestrictBackgroundChanged(boolean restrictBackground) { } @Override public void onUidPoliciesChanged(int uid, int uidPolicies) { } - @Override public void onSubscriptionOverride(int subId, int overrideMask, int overrideValue, - long networkTypeMask) { } + @Override public void onSubscriptionOverride(int subId, int overrideMask, + int overrideValue) { } + @Override public void onSubscriptionPlansChanged(int subId, SubscriptionPlan[] plans) { } } } diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java index 72c4c5e85f667..812ce32a60303 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -217,7 +217,6 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; import com.android.internal.notification.SystemNotificationChannels; -import com.android.internal.os.SomeArgs; import com.android.internal.telephony.PhoneConstants; import com.android.internal.util.ArrayUtils; import com.android.internal.util.ConcurrentUtils; @@ -385,6 +384,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { private static final int MSG_SUBSCRIPTION_OVERRIDE = 16; private static final int MSG_METERED_RESTRICTED_PACKAGES_CHANGED = 17; private static final int MSG_SET_NETWORK_TEMPLATE_ENABLED = 18; + private static final int MSG_SUBSCRIPTION_PLANS_CHANGED = 19; private static final int UID_MSG_STATE_CHANGED = 100; private static final int UID_MSG_GONE = 101; @@ -3069,6 +3069,34 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { mContext.enforceCallingOrSelfPermission(MANAGE_SUBSCRIPTION_PLANS, TAG); } + private void enforceSubscriptionPlanValidity(SubscriptionPlan[] plans) { + // nothing to check if no plans + if (plans.length == 0) { + return; + } + + long applicableNetworkTypes = 0; + boolean allNetworks = false; + for (SubscriptionPlan plan : plans) { + if (plan.getNetworkTypes() == null) { + allNetworks = true; + } else { + if ((applicableNetworkTypes & plan.getNetworkTypesBitMask()) != 0) { + throw new IllegalArgumentException( + "Multiple subscription plans defined for a single network type."); + } else { + applicableNetworkTypes |= plan.getNetworkTypesBitMask(); + } + } + } + + // ensure at least one plan applies for every network type + if (!allNetworks) { + throw new IllegalArgumentException( + "No generic subscription plan that applies to all network types."); + } + } + @Override public SubscriptionPlan[] getSubscriptionPlans(int subId, String callingPackage) { enforceSubscriptionPlanAccess(subId, Binder.getCallingUid(), callingPackage); @@ -3233,6 +3261,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { @Override public void setSubscriptionPlans(int subId, SubscriptionPlan[] plans, String callingPackage) { enforceSubscriptionPlanAccess(subId, Binder.getCallingUid(), callingPackage); + enforceSubscriptionPlanValidity(plans); for (SubscriptionPlan plan : plans) { Preconditions.checkNotNull(plan); @@ -3261,6 +3290,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { 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); } @@ -3287,7 +3318,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { @Override public void setSubscriptionOverride(int subId, int overrideMask, int overrideValue, - long networkTypeMask, long timeoutMillis, String callingPackage) { + long timeoutMillis, String callingPackage) { enforceSubscriptionPlanAccess(subId, Binder.getCallingUid(), callingPackage); // We can only override when carrier told us about plans @@ -3305,16 +3336,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { final boolean overrideEnabled = Settings.Global.getInt(mContext.getContentResolver(), NETPOLICY_OVERRIDE_ENABLED, 1) != 0; if (overrideEnabled || overrideValue == 0) { - SomeArgs args = SomeArgs.obtain(); - args.arg1 = subId; - args.arg2 = overrideMask; - args.arg3 = overrideValue; - args.arg4 = networkTypeMask; - mHandler.sendMessage(mHandler.obtainMessage(MSG_SUBSCRIPTION_OVERRIDE, args)); + mHandler.sendMessage(mHandler.obtainMessage(MSG_SUBSCRIPTION_OVERRIDE, + overrideMask, overrideValue, subId)); if (timeoutMillis > 0) { - args.arg3 = 0; - mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_SUBSCRIPTION_OVERRIDE, args), - timeoutMillis); + mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_SUBSCRIPTION_OVERRIDE, + overrideMask, 0, subId), timeoutMillis); } } } @@ -4450,11 +4476,20 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } private void dispatchSubscriptionOverride(INetworkPolicyListener listener, int subId, - int overrideMask, int overrideValue, long networkTypeMask) { + int overrideMask, int overrideValue) { if (listener != null) { try { - listener.onSubscriptionOverride(subId, overrideMask, overrideValue, - networkTypeMask); + listener.onSubscriptionOverride(subId, overrideMask, overrideValue); + } catch (RemoteException ignored) { + } + } + } + + private void dispatchSubscriptionPlansChanged(INetworkPolicyListener listener, int subId, + SubscriptionPlan[] plans) { + if (listener != null) { + try { + listener.onSubscriptionPlansChanged(subId, plans); } catch (RemoteException ignored) { } } @@ -4555,16 +4590,13 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { return true; } case MSG_SUBSCRIPTION_OVERRIDE: { - final SomeArgs args = (SomeArgs) msg.obj; - final int subId = (int) args.arg1; - final int overrideMask = (int) args.arg2; - final int overrideValue = (int) args.arg3; - final long networkTypeMask = (long) args.arg4; + final int overrideMask = msg.arg1; + final int overrideValue = msg.arg2; + final int subId = (int) msg.obj; final int length = mListeners.beginBroadcast(); for (int i = 0; i < length; i++) { final INetworkPolicyListener listener = mListeners.getBroadcastItem(i); - dispatchSubscriptionOverride(listener, subId, overrideMask, overrideValue, - networkTypeMask); + dispatchSubscriptionOverride(listener, subId, overrideMask, overrideValue); } mListeners.finishBroadcast(); return true; @@ -4581,6 +4613,17 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { setNetworkTemplateEnabledInner(template, enabled); return true; } + case MSG_SUBSCRIPTION_PLANS_CHANGED: { + final SubscriptionPlan[] plans = (SubscriptionPlan[]) msg.obj; + final int subId = msg.arg1; + final int length = mListeners.beginBroadcast(); + for (int i = 0; i < length; i++) { + final INetworkPolicyListener listener = mListeners.getBroadcastItem(i); + dispatchSubscriptionPlansChanged(listener, subId, plans); + } + mListeners.finishBroadcast(); + return true; + } default: { return false; } diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index 1d5c18d6aae3c..9b4b0829924a8 100755 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -2817,7 +2817,7 @@ public class CarrierConfigManager { "ping_test_before_data_switch_bool"; /** - * Controls time in milli seconds until DcTracker reevaluates 5G connection state. + * Controls time in milliseconds until DcTracker reevaluates 5G connection state. * @hide */ public static final String KEY_5G_WATCHDOG_TIME_MS_LONG = diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java index e288f25315af2..40d057ffd6fe4 100644 --- a/telephony/java/android/telephony/SubscriptionManager.java +++ b/telephony/java/android/telephony/SubscriptionManager.java @@ -53,7 +53,6 @@ import android.os.ParcelUuid; import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager; -import android.telephony.Annotation.NetworkType; import android.telephony.euicc.EuiccManager; import android.telephony.ims.ImsMmTelManager; import android.util.DisplayMetrics; @@ -2420,8 +2419,12 @@ public class SubscriptionManager { * @param plans the list of plans. The first plan is always the primary and * most important plan. Any additional plans are secondary and * may not be displayed or used by decision making logic. + * The list of all plans must meet the requirements defined in + * {@link SubscriptionPlan.Builder#setNetworkTypes(int[])}. * @throws SecurityException if the caller doesn't meet the requirements * outlined above. + * @throws IllegalArgumentException if plans don't meet the requirements + * mentioned above. */ public void setSubscriptionPlans(int subId, @NonNull List plans) { try { @@ -2466,51 +2469,10 @@ public class SubscriptionManager { */ public void setSubscriptionOverrideUnmetered(int subId, boolean overrideUnmetered, @DurationMillisLong long timeoutMillis) { - setSubscriptionOverrideUnmetered(subId, null, overrideUnmetered, timeoutMillis); - } - - /** - * Temporarily override the billing relationship between a carrier and - * a specific subscriber to be considered unmetered for the given network - * types. This will be reflected to apps via - * {@link NetworkCapabilities#NET_CAPABILITY_NOT_METERED}. - * This method is only accessible to the following narrow set of apps: - * - * - * @param subId the subscriber this override applies to. - * @param networkTypes all network types to set an override for. A null - * network type means to apply the override to all network types. - * Any unspecified network types will default to metered. - * @param overrideUnmetered set if the billing relationship should be - * considered unmetered. - * @param timeoutMillis the timeout 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. - * @throws SecurityException if the caller doesn't meet the requirements - * outlined above. - * {@hide} - */ - public void setSubscriptionOverrideUnmetered(int subId, - @Nullable @NetworkType int[] networkTypes, boolean overrideUnmetered, - @DurationMillisLong long timeoutMillis) { try { - long networkTypeMask = 0; - if (networkTypes != null) { - for (int networkType : networkTypes) { - networkTypeMask |= TelephonyManager.getBitMaskForNetworkType(networkType); - } - } else { - networkTypeMask = ~0; - } final int overrideValue = overrideUnmetered ? OVERRIDE_UNMETERED : 0; getNetworkPolicy().setSubscriptionOverride(subId, OVERRIDE_UNMETERED, overrideValue, - networkTypeMask, timeoutMillis, mContext.getOpPackageName()); + timeoutMillis, mContext.getOpPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -2542,52 +2504,10 @@ public class SubscriptionManager { */ public void setSubscriptionOverrideCongested(int subId, boolean overrideCongested, @DurationMillisLong long timeoutMillis) { - setSubscriptionOverrideCongested(subId, null, overrideCongested, timeoutMillis); - } - - /** - * Temporarily override the billing relationship plan between a carrier and - * a specific subscriber to be considered congested. This will cause the - * device to delay certain network requests when possible, such as developer - * jobs that are willing to run in a flexible time window. - *

- * This method is only accessible to the following narrow set of apps: - *

- * - * @param subId the subscriber this override applies to. - * @param networkTypes all network types to set an override for. A null - * network type means to apply the override to all network types. - * Any unspecified network types will default to not congested. - * @param overrideCongested set if the subscription should be considered - * congested. - * @param timeoutMillis the timeout 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. - * @throws SecurityException if the caller doesn't meet the requirements - * outlined above. - * @hide - */ - public void setSubscriptionOverrideCongested(int subId, - @Nullable @NetworkType int[] networkTypes, boolean overrideCongested, - @DurationMillisLong long timeoutMillis) { try { - long networkTypeMask = 0; - if (networkTypes != null) { - for (int networkType : networkTypes) { - networkTypeMask |= TelephonyManager.getBitMaskForNetworkType(networkType); - } - } else { - networkTypeMask = ~0; - } final int overrideValue = overrideCongested ? OVERRIDE_CONGESTED : 0; getNetworkPolicy().setSubscriptionOverride(subId, OVERRIDE_CONGESTED, overrideValue, - networkTypeMask, timeoutMillis, mContext.getOpPackageName()); + timeoutMillis, mContext.getOpPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/telephony/java/android/telephony/SubscriptionPlan.java b/telephony/java/android/telephony/SubscriptionPlan.java index ec2050fb1a44e..e24eb2696c6cd 100644 --- a/telephony/java/android/telephony/SubscriptionPlan.java +++ b/telephony/java/android/telephony/SubscriptionPlan.java @@ -24,6 +24,7 @@ import android.annotation.Nullable; import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; +import android.telephony.Annotation.NetworkType; import android.util.Range; import android.util.RecurrenceRule; @@ -33,6 +34,7 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.time.Period; import java.time.ZonedDateTime; +import java.util.Arrays; import java.util.Iterator; import java.util.Objects; @@ -80,6 +82,8 @@ public final class SubscriptionPlan implements Parcelable { private int dataLimitBehavior = LIMIT_BEHAVIOR_UNKNOWN; private long dataUsageBytes = BYTES_UNKNOWN; private long dataUsageTime = TIME_UNKNOWN; + private @NetworkType int[] networkTypes; + private long networkTypesBitMask; private SubscriptionPlan(RecurrenceRule cycleRule) { this.cycleRule = Preconditions.checkNotNull(cycleRule); @@ -93,6 +97,7 @@ public final class SubscriptionPlan implements Parcelable { dataLimitBehavior = source.readInt(); dataUsageBytes = source.readLong(); dataUsageTime = source.readLong(); + networkTypes = source.createIntArray(); } @Override @@ -109,6 +114,7 @@ public final class SubscriptionPlan implements Parcelable { dest.writeInt(dataLimitBehavior); dest.writeLong(dataUsageBytes); dest.writeLong(dataUsageTime); + dest.writeIntArray(networkTypes); } @Override @@ -121,13 +127,14 @@ public final class SubscriptionPlan implements Parcelable { .append(" dataLimitBehavior=").append(dataLimitBehavior) .append(" dataUsageBytes=").append(dataUsageBytes) .append(" dataUsageTime=").append(dataUsageTime) + .append(" networkTypes=").append(Arrays.toString(networkTypes)) .append("}").toString(); } @Override public int hashCode() { return Objects.hash(cycleRule, title, summary, dataLimitBytes, dataLimitBehavior, - dataUsageBytes, dataUsageTime); + dataUsageBytes, dataUsageTime, Arrays.hashCode(networkTypes)); } @Override @@ -140,7 +147,8 @@ public final class SubscriptionPlan implements Parcelable { && dataLimitBytes == other.dataLimitBytes && dataLimitBehavior == other.dataLimitBehavior && dataUsageBytes == other.dataUsageBytes - && dataUsageTime == other.dataUsageTime; + && dataUsageTime == other.dataUsageTime + && Arrays.equals(networkTypes, other.networkTypes); } return false; } @@ -203,6 +211,32 @@ public final class SubscriptionPlan implements Parcelable { return dataUsageTime; } + /** + * Return an array containing all {@link NetworkType}s this SubscriptionPlan applies to. + * A null array means this SubscriptionPlan applies to all network types. + */ + public @Nullable @NetworkType int[] getNetworkTypes() { + return networkTypes; + } + + /** + * Return the networkTypes array converted to a {@link TelephonyManager.NetworkTypeBitMask} + * @hide + */ + public long getNetworkTypesBitMask() { + // calculate bitmask the first time and save for future calls + if (networkTypesBitMask == 0) { + if (networkTypes == null) { + networkTypesBitMask = ~0; + } else { + for (int networkType : networkTypes) { + networkTypesBitMask |= TelephonyManager.getBitMaskForNetworkType(networkType); + } + } + } + return networkTypesBitMask; + } + /** * Return an iterator that will return all valid data usage cycles based on * any recurrence rules. The iterator starts from the currently active cycle @@ -335,5 +369,24 @@ public final class SubscriptionPlan implements Parcelable { plan.dataUsageTime = dataUsageTime; return this; } + + /** + * Set the network types this SubscriptionPlan applies to. + * The developer must supply at least one plan that applies to all network types (default), + * and all additional plans may not include a particular network type more than once. + * Plan selection will prefer plans that have specific network types defined + * over plans that apply to all network types. + * + * @param networkTypes a set of all {@link NetworkType}s that apply to this plan. + * A null value or empty array means the plan applies to all network types. + */ + public @NonNull Builder setNetworkTypes(@Nullable @NetworkType int[] networkTypes) { + if (networkTypes == null || networkTypes.length == 0) { + plan.networkTypes = null; + } else { + plan.networkTypes = networkTypes; + } + return this; + } } } diff --git a/telephony/java/com/android/internal/telephony/DctConstants.java b/telephony/java/com/android/internal/telephony/DctConstants.java index 668a6af081455..9e786ce327928 100644 --- a/telephony/java/com/android/internal/telephony/DctConstants.java +++ b/telephony/java/com/android/internal/telephony/DctConstants.java @@ -111,7 +111,7 @@ public class DctConstants { public static final int EVENT_DATA_SERVICE_BINDING_CHANGED = BASE + 49; public static final int EVENT_DEVICE_PROVISIONED_CHANGE = BASE + 50; public static final int EVENT_DATA_ENABLED_OVERRIDE_RULES_CHANGED = BASE + 51; - public static final int EVENT_5G_NETWORK_CHANGED = BASE + 52; + public static final int EVENT_SERVICE_STATE_CHANGED = BASE + 52; public static final int EVENT_5G_TIMER_HYSTERESIS = BASE + 53; public static final int EVENT_5G_TIMER_WATCHDOG = BASE + 54;