diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java index e2c4cbdc829cb..cceb7586e1a6f 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -220,6 +220,7 @@ import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener; import android.telephony.SubscriptionPlan; +import android.telephony.TelephonyCallback; import android.telephony.TelephonyManager; import android.text.TextUtils; import android.text.format.DateUtils; @@ -801,6 +802,16 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } return buckets; } + + /** Require IPC call. Don't call when holding a lock. */ + int getDefaultDataSubId() { + return SubscriptionManager.getDefaultDataSubscriptionId(); + } + + /** Require IPC call. Don't call when holding a lock. */ + int getActivateDataSubId() { + return SubscriptionManager.getActiveDataSubscriptionId(); + } } @VisibleForTesting @@ -828,7 +839,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { mSuppressDefaultPolicy = suppressDefaultPolicy; mDeps = Objects.requireNonNull(deps, "missing Dependencies"); - + mActiveDataSubIdListener = new ActiveDataSubIdListener(); mPolicyFile = new AtomicFile(new File(systemDir, "netpolicy.xml"), "net-policy"); mAppOps = context.getSystemService(AppOpsManager.class); @@ -1088,6 +1099,10 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } }); + // Listen for active data sub Id change, upon which data notifications is shown/hidden. + mContext.getSystemService(TelephonyManager.class).registerTelephonyCallback(executor, + mActiveDataSubIdListener); + // tell systemReady() that the service has been initialized initCompleteSignal.countDown(); } finally { @@ -1256,6 +1271,38 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } }; + /** + * Listener that watches for active data sub Id change, upon which data notifications are + * shown/hidden. + */ + private final ActiveDataSubIdListener mActiveDataSubIdListener; + private class ActiveDataSubIdListener extends TelephonyCallback implements + TelephonyCallback.ActiveDataSubscriptionIdListener { + /** + * In most cases active data sub is the same as the default data sub, but if user enabled + * auto data switch {@link TelephonyManager#MOBILE_DATA_POLICY_AUTO_DATA_SWITCH}, + * active data sub could be the non-default data sub. + * + * If the listener is initialized before the phone process is up, the IPC call to the + * static method of SubscriptionManager lead to INVALID_SUBSCRIPTION_ID to be returned, + * indicating the phone process is unable to determine a valid data sub Id at this point, in + * which case no data notifications should be shown anyway. Later on when an active data + * sub is known, notifications will be re-evaluated by this callback. + */ + private int mDefaultDataSubId = mDeps.getDefaultDataSubId(); + private int mActiveDataSubId = mDeps.getActivateDataSubId(); + // Only listen to active data sub change is sufficient because default data sub change + // leads to active data sub change as well. + @Override + public void onActiveDataSubscriptionIdChanged(int subId) { + mActiveDataSubId = subId; + mDefaultDataSubId = mDeps.getDefaultDataSubId(); + synchronized (mNetworkPoliciesSecondLock) { + updateNotificationsNL(); + } + } + } + /** * Listener that watches for {@link NetworkStatsManager} updates, which * NetworkPolicyManagerService uses to check against {@link NetworkPolicy#warningBytes}. @@ -1445,6 +1492,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { // ignore policies that aren't relevant to user if (subId == INVALID_SUBSCRIPTION_ID) continue; + // ignore if the data sub is neither default nor active for data at the moment. + if (subId != mActiveDataSubIdListener.mDefaultDataSubId + && subId != mActiveDataSubIdListener.mActiveDataSubId) continue; if (!policy.hasCycle()) continue; final Pair cycle = NetworkPolicyManager diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java index 821ce5edad27f..da1a277322cab 100644 --- a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java @@ -148,6 +148,7 @@ import android.telephony.CarrierConfigManager; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.SubscriptionPlan; +import android.telephony.TelephonyCallback; import android.telephony.TelephonyManager; import android.test.suitebuilder.annotation.MediumTest; import android.text.TextUtils; @@ -236,6 +237,7 @@ public class NetworkPolicyManagerServiceTest { private static final String TEST_WIFI_NETWORK_KEY = "TestWifiNetworkKey"; private static final String TEST_IMSI = "310210"; private static final int TEST_SUB_ID = 42; + private static final int TEST_SUB_ID2 = 24; private static final Network TEST_NETWORK = mock(Network.class, CALLS_REAL_METHODS); private static NetworkTemplate sTemplateWifi = new NetworkTemplate.Builder(MATCH_WIFI) @@ -277,6 +279,8 @@ public class NetworkPolicyManagerServiceTest { private ArgumentCaptor mNetworkCallbackCaptor = ArgumentCaptor.forClass(ConnectivityManager.NetworkCallback.class); + private TelephonyCallback.ActiveDataSubscriptionIdListener mActiveDataSubIdListener; + private ActivityManagerInternal mActivityManagerInternal; private PackageManagerInternal mPackageManagerInternal; @@ -350,6 +354,8 @@ public class NetworkPolicyManagerServiceTest { private class TestDependencies extends NetworkPolicyManagerService.Dependencies { private final SparseArray mMockedStats = new SparseArray<>(); + private int mMockDefaultDataSubId; + private int mMockedActiveDataSubId; TestDependencies(Context context) { super(context); @@ -387,6 +393,21 @@ public class NetworkPolicyManagerServiceTest { final NetworkStats.Bucket bucket = mMockedStats.get(uid); setMockedTotalBytes(uid, bucket.getRxBytes() + rxBytes, bucket.getTxBytes() + txBytes); } + + void setDefaultAndActiveDataSubId(int defaultDataSubId, int activeDataSubId) { + mMockDefaultDataSubId = defaultDataSubId; + mMockedActiveDataSubId = activeDataSubId; + } + + @Override + int getDefaultDataSubId() { + return mMockDefaultDataSubId; + } + + @Override + int getActivateDataSubId() { + return mMockedActiveDataSubId; + } } @Before @@ -529,6 +550,14 @@ public class NetworkPolicyManagerServiceTest { NetworkPolicy defaultPolicy = mService.buildDefaultCarrierPolicy(0, ""); mDefaultWarningBytes = defaultPolicy.warningBytes; mDefaultLimitBytes = defaultPolicy.limitBytes; + + // Catch TelephonyCallback during systemReady(). + ArgumentCaptor telephonyCallbackArgumentCaptor = + ArgumentCaptor.forClass(TelephonyCallback.class); + verify(mTelephonyManager).registerTelephonyCallback(any(), + telephonyCallbackArgumentCaptor.capture()); + mActiveDataSubIdListener = (TelephonyCallback.ActiveDataSubscriptionIdListener) + telephonyCallbackArgumentCaptor.getValue(); } @After @@ -1214,6 +1243,7 @@ public class NetworkPolicyManagerServiceTest { reset(mTelephonyManager, mNetworkManager, mNotifManager); TelephonyManager tmSub = expectMobileDefaults(); + clearInvocations(mNotifManager); mService.updateNetworks(); @@ -1229,6 +1259,7 @@ public class NetworkPolicyManagerServiceTest { reset(mTelephonyManager, mNetworkManager, mNotifManager); TelephonyManager tmSub = expectMobileDefaults(); + clearInvocations(mNotifManager); mService.updateNetworks(); @@ -1246,6 +1277,7 @@ public class NetworkPolicyManagerServiceTest { reset(mTelephonyManager, mNetworkManager, mNotifManager); TelephonyManager tmSub = expectMobileDefaults(); expectDefaultCarrierConfig(); + clearInvocations(mNotifManager); mService.updateNetworks(); @@ -1262,6 +1294,7 @@ public class NetworkPolicyManagerServiceTest { reset(mTelephonyManager, mNetworkManager, mNotifManager); TelephonyManager tmSub = expectMobileDefaults(); + clearInvocations(mNotifManager); mService.updateNetworks(); @@ -1275,6 +1308,7 @@ public class NetworkPolicyManagerServiceTest { { reset(mTelephonyManager, mNetworkManager, mNotifManager); TelephonyManager tmSub = expectMobileDefaults(); + clearInvocations(mNotifManager); mService.snoozeLimit(sTemplateCarrierMetered); mService.updateNetworks(); @@ -1285,6 +1319,31 @@ public class NetworkPolicyManagerServiceTest { verify(mNotifManager, atLeastOnce()).notifyAsUser(any(), eq(TYPE_LIMIT_SNOOZED), isA(Notification.class), eq(UserHandle.ALL)); } + // The sub is no longer used for data(e.g. user uses another sub), hide the notifications. + { + reset(mTelephonyManager, mNetworkManager, mNotifManager); + + notifyDefaultAndActiveDataSubIdChange(TEST_SUB_ID2, TEST_SUB_ID2); + verify(mNotifManager, atLeastOnce()).cancel(any(), eq(TYPE_LIMIT_SNOOZED)); + } + // The sub is not active for data(e.g. due to auto data switch), but still default for data, + // show notification. + { + reset(mTelephonyManager, mNetworkManager, mNotifManager); + + notifyDefaultAndActiveDataSubIdChange(TEST_SUB_ID, TEST_SUB_ID2); + verify(mNotifManager, atLeastOnce()).notifyAsUser(any(), eq(TYPE_LIMIT_SNOOZED), + isA(Notification.class), eq(UserHandle.ALL)); + } + // The sub is active for data, but not the default(e.g. due to auto data switch), + // show notification. + { + reset(mTelephonyManager, mNetworkManager, mNotifManager); + + notifyDefaultAndActiveDataSubIdChange(TEST_SUB_ID2, TEST_SUB_ID); + verify(mNotifManager, atLeastOnce()).notifyAsUser(any(), eq(TYPE_LIMIT_SNOOZED), + isA(Notification.class), eq(UserHandle.ALL)); + } } @Test @@ -2348,6 +2407,7 @@ public class NetworkPolicyManagerServiceTest { String subscriberId) { when(mSubscriptionManager.getActiveSubscriptionInfoList()).thenReturn( createSubscriptionInfoList(subscriptionId)); + notifyDefaultAndActiveDataSubIdChange(subscriptionId, subscriptionId); TelephonyManager subTelephonyManager; subTelephonyManager = mock(TelephonyManager.class); @@ -2358,6 +2418,16 @@ public class NetworkPolicyManagerServiceTest { return subTelephonyManager; } + /** + * Telephony Manager callback notifies data sub Id changes. + * @param defaultDataSubId The mock default data sub Id. + * @param activeDataSubId The mock active data sub Id. + */ + private void notifyDefaultAndActiveDataSubIdChange(int defaultDataSubId, int activeDataSubId) { + mDeps.setDefaultAndActiveDataSubId(defaultDataSubId, activeDataSubId); + mActiveDataSubIdListener.onActiveDataSubscriptionIdChanged(activeDataSubId); + } + /** * Creates mock {@link SubscriptionInfo} from subscription id. */