Merge "NetworkPolicy gets updated due to CarrierConfigManager updates." into oc-dev

am: 334220984e

Change-Id: I48d20978f1382f0c053ffd83ad772fa4b6b5cf1a
This commit is contained in:
Ammar Aijazi
2017-03-29 00:46:34 +00:00
committed by android-build-merger
2 changed files with 569 additions and 25 deletions

View File

@@ -75,6 +75,9 @@ import static android.net.wifi.WifiManager.EXTRA_CHANGE_REASON;
import static android.net.wifi.WifiManager.EXTRA_NETWORK_INFO; import static android.net.wifi.WifiManager.EXTRA_NETWORK_INFO;
import static android.net.wifi.WifiManager.EXTRA_WIFI_CONFIGURATION; import static android.net.wifi.WifiManager.EXTRA_WIFI_CONFIGURATION;
import static android.net.wifi.WifiManager.EXTRA_WIFI_INFO; import static android.net.wifi.WifiManager.EXTRA_WIFI_INFO;
import static android.telephony.CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED;
import static android.telephony.CarrierConfigManager.DATA_CYCLE_USE_PLATFORM_DEFAULT;
import static android.telephony.CarrierConfigManager.DATA_CYCLE_THRESHOLD_DISABLED;
import static android.text.format.DateUtils.DAY_IN_MILLIS; import static android.text.format.DateUtils.DAY_IN_MILLIS;
import static com.android.internal.util.ArrayUtils.appendInt; import static com.android.internal.util.ArrayUtils.appendInt;
@@ -141,6 +144,7 @@ import android.os.IDeviceIdleController;
import android.os.INetworkManagementService; import android.os.INetworkManagementService;
import android.os.Message; import android.os.Message;
import android.os.MessageQueue.IdleHandler; import android.os.MessageQueue.IdleHandler;
import android.os.PersistableBundle;
import android.os.PowerManager; import android.os.PowerManager;
import android.os.PowerManagerInternal; import android.os.PowerManagerInternal;
import android.os.Process; import android.os.Process;
@@ -153,6 +157,7 @@ import android.os.Trace;
import android.os.UserHandle; import android.os.UserHandle;
import android.os.UserManager; import android.os.UserManager;
import android.provider.Settings; import android.provider.Settings;
import android.telephony.CarrierConfigManager;
import android.telephony.SubscriptionManager; import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager; import android.telephony.TelephonyManager;
import android.text.TextUtils; import android.text.TextUtils;
@@ -174,6 +179,7 @@ import com.android.internal.R;
import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.notification.SystemNotificationChannels; import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.telephony.PhoneConstants;
import com.android.internal.util.ArrayUtils; import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastXmlSerializer; import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.IndentingPrintWriter;
@@ -205,6 +211,7 @@ import java.nio.charset.StandardCharsets;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Calendar;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@@ -321,6 +328,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
private UsageStatsManagerInternal mUsageStats; private UsageStatsManagerInternal mUsageStats;
private final TrustedTime mTime; private final TrustedTime mTime;
private final UserManager mUserManager; private final UserManager mUserManager;
private final CarrierConfigManager mCarrierConfigManager;
private IConnectivityManager mConnManager; private IConnectivityManager mConnManager;
private INotificationManager mNotifManager; private INotificationManager mNotifManager;
@@ -472,6 +480,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
Context.DEVICE_IDLE_CONTROLLER)); Context.DEVICE_IDLE_CONTROLLER));
mTime = checkNotNull(time, "missing TrustedTime"); mTime = checkNotNull(time, "missing TrustedTime");
mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
mCarrierConfigManager = mContext.getSystemService(CarrierConfigManager.class);
mIPm = pm; mIPm = pm;
HandlerThread thread = new HandlerThread(TAG); HandlerThread thread = new HandlerThread(TAG);
@@ -756,6 +765,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
WifiManager.NETWORK_STATE_CHANGED_ACTION); WifiManager.NETWORK_STATE_CHANGED_ACTION);
mContext.registerReceiver(mWifiStateReceiver, wifiStateFilter, null, mHandler); mContext.registerReceiver(mWifiStateReceiver, wifiStateFilter, null, mHandler);
// listen for carrier config changes to update data cycle information
final IntentFilter carrierConfigFilter = new IntentFilter(
ACTION_CARRIER_CONFIG_CHANGED);
mContext.registerReceiver(mCarrierConfigReceiver, carrierConfigFilter, null, mHandler);
mUsageStats.addAppIdleStateChangeListener(new AppIdleStateChangeListener()); mUsageStats.addAppIdleStateChangeListener(new AppIdleStateChangeListener());
// tell systemReady() that the service has been initialized // tell systemReady() that the service has been initialized
initCompleteSignal.countDown(); initCompleteSignal.countDown();
@@ -1291,6 +1305,213 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
} }
}; };
/**
* Update mobile policies with data cycle information from {@link CarrierConfigManager}
* if necessary.
*
* @param subId that has its associated NetworkPolicy updated if necessary
* @return if any policies were updated
*/
private boolean maybeUpdateMobilePolicyCycleNL(int subId) {
if (LOGV) Slog.v(TAG, "maybeUpdateMobilePolicyCycleNL()");
final PersistableBundle config = mCarrierConfigManager.getConfigForSubId(subId);
if (config == null) {
return false;
}
boolean policyUpdated = false;
final String subscriberId = TelephonyManager.from(mContext).getSubscriberId(subId);
// find and update the mobile NetworkPolicy for this subscriber id
final NetworkIdentity probeIdent = new NetworkIdentity(TYPE_MOBILE,
TelephonyManager.NETWORK_TYPE_UNKNOWN, subscriberId, null, false, true);
for (int i = mNetworkPolicy.size() - 1; i >= 0; i--) {
final NetworkTemplate template = mNetworkPolicy.keyAt(i);
if (template.matches(probeIdent)) {
NetworkPolicy policy = mNetworkPolicy.valueAt(i);
// only update the policy if the user didn't change any of the defaults.
if (!policy.inferred) {
// TODO: inferred could be split, so that if a user changes their data limit or
// warning, it doesn't prevent their cycle date from being updated.
if (LOGD) Slog.v(TAG, "Didn't update NetworkPolicy because policy.inferred");
continue;
}
final int cycleDay = getCycleDayFromCarrierConfig(config, policy.cycleDay);
final long warningBytes = getWarningBytesFromCarrierConfig(config,
policy.warningBytes);
final long limitBytes = getLimitBytesFromCarrierConfig(config,
policy.limitBytes);
if (policy.cycleDay == cycleDay &&
policy.warningBytes == warningBytes &&
policy.limitBytes == limitBytes) {
continue;
}
policyUpdated = true;
policy.cycleDay = cycleDay;
policy.warningBytes = warningBytes;
policy.limitBytes = limitBytes;
if (LOGD) {
Slog.d(TAG, "Updated NetworkPolicy " + policy + " which matches subscriber "
+ NetworkIdentity.scrubSubscriberId(subscriberId)
+ " from CarrierConfigManager");
}
}
}
return policyUpdated;
}
/**
* Returns the cycle day that should be used for a mobile NetworkPolicy.
*
* It attempts to get an appropriate cycle day from the passed in CarrierConfig. If it's unable
* to do so, it returns the fallback value.
*
* @param config The CarrierConfig to read the value from.
* @param fallbackCycleDay to return if the CarrierConfig can't be read.
* @return cycleDay to use in the mobile NetworkPolicy.
*/
@VisibleForTesting
public int getCycleDayFromCarrierConfig(@Nullable PersistableBundle config,
int fallbackCycleDay) {
if (config == null) {
return fallbackCycleDay;
}
int cycleDay =
config.getInt(CarrierConfigManager.KEY_MONTHLY_DATA_CYCLE_DAY_INT);
if (cycleDay == DATA_CYCLE_USE_PLATFORM_DEFAULT) {
return fallbackCycleDay;
}
// validate cycleDay value
final Calendar cal = Calendar.getInstance();
if (cycleDay < cal.getMinimum(Calendar.DAY_OF_MONTH) ||
cycleDay > cal.getMaximum(Calendar.DAY_OF_MONTH)) {
Slog.e(TAG, "Invalid date in "
+ "CarrierConfigManager.KEY_MONTHLY_DATA_CYCLE_DAY_INT: " + cycleDay);
return fallbackCycleDay;
}
return cycleDay;
}
/**
* Returns the warning bytes that should be used for a mobile NetworkPolicy.
*
* It attempts to get an appropriate value from the passed in CarrierConfig. If it's unable
* to do so, it returns the fallback value.
*
* @param config The CarrierConfig to read the value from.
* @param fallbackWarningBytes to return if the CarrierConfig can't be read.
* @return warningBytes to use in the mobile NetworkPolicy.
*/
@VisibleForTesting
public long getWarningBytesFromCarrierConfig(@Nullable PersistableBundle config,
long fallbackWarningBytes) {
if (config == null) {
return fallbackWarningBytes;
}
long warningBytes =
config.getLong(CarrierConfigManager.KEY_DATA_WARNING_THRESHOLD_BYTES_LONG);
if (warningBytes == DATA_CYCLE_THRESHOLD_DISABLED) {
return WARNING_DISABLED;
} else if (warningBytes == DATA_CYCLE_USE_PLATFORM_DEFAULT) {
return getPlatformDefaultWarningBytes();
} else if (warningBytes < 0) {
Slog.e(TAG, "Invalid value in "
+ "CarrierConfigManager.KEY_DATA_WARNING_THRESHOLD_BYTES_LONG; expected a "
+ "non-negative value but got: " + warningBytes);
return fallbackWarningBytes;
}
return warningBytes;
}
/**
* Returns the limit bytes that should be used for a mobile NetworkPolicy.
*
* It attempts to get an appropriate value from the passed in CarrierConfig. If it's unable
* to do so, it returns the fallback value.
*
* @param config The CarrierConfig to read the value from.
* @param fallbackLimitBytes to return if the CarrierConfig can't be read.
* @return limitBytes to use in the mobile NetworkPolicy.
*/
@VisibleForTesting
public long getLimitBytesFromCarrierConfig(@Nullable PersistableBundle config,
long fallbackLimitBytes) {
if (config == null) {
return fallbackLimitBytes;
}
long limitBytes =
config.getLong(CarrierConfigManager.KEY_DATA_LIMIT_THRESHOLD_BYTES_LONG);
if (limitBytes == DATA_CYCLE_THRESHOLD_DISABLED) {
return LIMIT_DISABLED;
} else if (limitBytes == DATA_CYCLE_USE_PLATFORM_DEFAULT) {
return getPlatformDefaultLimitBytes();
} else if (limitBytes < 0) {
Slog.e(TAG, "Invalid value in "
+ "CarrierConfigManager.KEY_DATA_LIMIT_THRESHOLD_BYTES_LONG; expected a "
+ "non-negative value but got: " + limitBytes);
return fallbackLimitBytes;
}
return limitBytes;
}
/**
* Receiver that watches for {@link CarrierConfigManager} to be changed.
*/
private BroadcastReceiver mCarrierConfigReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
// No need to do a permission check, because the ACTION_CARRIER_CONFIG_CHANGED
// broadcast is protected and can't be spoofed. Runs on a background handler thread.
if (!intent.hasExtra(PhoneConstants.SUBSCRIPTION_KEY)) {
return;
}
final int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY, -1);
final TelephonyManager tele = TelephonyManager.from(mContext);
final String subscriberId = tele.getSubscriberId(subId);
maybeRefreshTrustedTime();
synchronized (mUidRulesFirstLock) {
synchronized (mNetworkPoliciesSecondLock) {
final boolean added = ensureActiveMobilePolicyNL(subId, subscriberId);
if (added) return;
final boolean updated = maybeUpdateMobilePolicyCycleNL(subId);
if (!updated) return;
// update network and notification rules, as the data cycle changed and it's
// possible that we should be triggering warnings/limits now
handleNetworkPoliciesUpdateAL(true);
}
}
}
};
/**
* Handles all tasks that need to be run after a new network policy has been set, or an existing
* one has been updated.
*
* @param shouldNormalizePolicies true iff network policies need to be normalized after the
* update.
*/
void handleNetworkPoliciesUpdateAL(boolean shouldNormalizePolicies) {
if (shouldNormalizePolicies) {
normalizePoliciesNL();
}
updateNetworkEnabledNL();
updateNetworkRulesNL();
updateNotificationsNL();
writePolicyAL();
}
/** /**
* Proactively control network data connections when they exceed * Proactively control network data connections when they exceed
* {@link NetworkPolicy#limitBytes}. * {@link NetworkPolicy#limitBytes}.
@@ -1516,11 +1737,19 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
final int[] subIds = sub.getActiveSubscriptionIdList(); final int[] subIds = sub.getActiveSubscriptionIdList();
for (int subId : subIds) { for (int subId : subIds) {
final String subscriberId = tele.getSubscriberId(subId); final String subscriberId = tele.getSubscriberId(subId);
ensureActiveMobilePolicyNL(subscriberId); ensureActiveMobilePolicyNL(subId, subscriberId);
} }
} }
private void ensureActiveMobilePolicyNL(String subscriberId) { /**
* Once any {@link #mNetworkPolicy} are loaded from disk, ensure that we
* have at least a default mobile policy defined.
*
* @param subId to build a default policy for
* @param subscriberId that we check for an existing policy
* @return true if a mobile network policy was added, or false one already existed.
*/
private boolean ensureActiveMobilePolicyNL(int subId, String subscriberId) {
// Poke around to see if we already have a policy // Poke around to see if we already have a policy
final NetworkIdentity probeIdent = new NetworkIdentity(TYPE_MOBILE, final NetworkIdentity probeIdent = new NetworkIdentity(TYPE_MOBILE,
TelephonyManager.NETWORK_TYPE_UNKNOWN, subscriberId, null, false, true); TelephonyManager.NETWORK_TYPE_UNKNOWN, subscriberId, null, false, true);
@@ -1531,33 +1760,51 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
Slog.d(TAG, "Found template " + template + " which matches subscriber " Slog.d(TAG, "Found template " + template + " which matches subscriber "
+ NetworkIdentity.scrubSubscriberId(subscriberId)); + NetworkIdentity.scrubSubscriberId(subscriberId));
} }
return; return false;
} }
} }
Slog.i(TAG, "No policy for subscriber " + NetworkIdentity.scrubSubscriberId(subscriberId) Slog.i(TAG, "No policy for subscriber " + NetworkIdentity.scrubSubscriberId(subscriberId)
+ "; generating default policy"); + "; generating default policy");
final NetworkPolicy policy = buildDefaultMobilePolicy(subId, subscriberId);
addNetworkPolicyNL(policy);
return true;
}
// Build default mobile policy, and assume usage cycle starts today private long getPlatformDefaultWarningBytes() {
final int dataWarningConfig = mContext.getResources().getInteger( final int dataWarningConfig = mContext.getResources().getInteger(
com.android.internal.R.integer.config_networkPolicyDefaultWarning); com.android.internal.R.integer.config_networkPolicyDefaultWarning);
final long warningBytes;
if (dataWarningConfig == WARNING_DISABLED) { if (dataWarningConfig == WARNING_DISABLED) {
warningBytes = WARNING_DISABLED; return WARNING_DISABLED;
} else { } else {
warningBytes = dataWarningConfig * MB_IN_BYTES; return dataWarningConfig * MB_IN_BYTES;
} }
}
private long getPlatformDefaultLimitBytes() {
return LIMIT_DISABLED;
}
@VisibleForTesting
public NetworkPolicy buildDefaultMobilePolicy(int subId, String subscriberId) {
PersistableBundle config = mCarrierConfigManager.getConfigForSubId(subId);
// assume usage cycle starts today
final Time time = new Time(); final Time time = new Time();
time.setToNow(); time.setToNow();
final int cycleDay = time.monthDay;
final String cycleTimezone = time.timezone; final String cycleTimezone = time.timezone;
final int cycleDay = getCycleDayFromCarrierConfig(config, time.monthDay);
final long warningBytes = getWarningBytesFromCarrierConfig(config,
getPlatformDefaultWarningBytes());
final long limitBytes = getLimitBytesFromCarrierConfig(config,
getPlatformDefaultLimitBytes());
final NetworkTemplate template = buildTemplateMobileAll(subscriberId); final NetworkTemplate template = buildTemplateMobileAll(subscriberId);
final NetworkPolicy policy = new NetworkPolicy(template, cycleDay, cycleTimezone, final NetworkPolicy policy = new NetworkPolicy(template, cycleDay, cycleTimezone,
warningBytes, LIMIT_DISABLED, SNOOZE_NEVER, SNOOZE_NEVER, true, true); warningBytes, limitBytes, SNOOZE_NEVER, SNOOZE_NEVER, true, true);
addNetworkPolicyNL(policy); return policy;
} }
private void readPolicyAL() { private void readPolicyAL() {
@@ -2025,10 +2272,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
synchronized (mUidRulesFirstLock) { synchronized (mUidRulesFirstLock) {
synchronized (mNetworkPoliciesSecondLock) { synchronized (mNetworkPoliciesSecondLock) {
normalizePoliciesNL(policies); normalizePoliciesNL(policies);
updateNetworkEnabledNL(); handleNetworkPoliciesUpdateAL(false);
updateNetworkRulesNL();
updateNotificationsNL();
writePolicyAL();
} }
} }
} finally { } finally {
@@ -2125,11 +2369,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
throw new IllegalArgumentException("unexpected type"); throw new IllegalArgumentException("unexpected type");
} }
normalizePoliciesNL(); handleNetworkPoliciesUpdateAL(true);
updateNetworkEnabledNL();
updateNetworkRulesNL();
updateNotificationsNL();
writePolicyAL();
} }
} }
} }
@@ -2360,11 +2600,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
mNetworkPolicy.valueAt(i).clearSnooze(); mNetworkPolicy.valueAt(i).clearSnooze();
} }
normalizePoliciesNL(); handleNetworkPoliciesUpdateAL(true);
updateNetworkEnabledNL();
updateNetworkRulesNL();
updateNotificationsNL();
writePolicyAL();
fout.println("Cleared snooze timestamps"); fout.println("Cleared snooze timestamps");
return; return;

View File

@@ -19,6 +19,7 @@ package com.android.server;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION; import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
import static android.net.ConnectivityManager.TYPE_WIFI; import static android.net.ConnectivityManager.TYPE_WIFI;
import static android.net.NetworkPolicy.LIMIT_DISABLED; import static android.net.NetworkPolicy.LIMIT_DISABLED;
import static android.net.NetworkPolicy.SNOOZE_NEVER;
import static android.net.NetworkPolicy.WARNING_DISABLED; import static android.net.NetworkPolicy.WARNING_DISABLED;
import static android.net.NetworkPolicyManager.POLICY_ALLOW_METERED_BACKGROUND; import static android.net.NetworkPolicyManager.POLICY_ALLOW_METERED_BACKGROUND;
import static android.net.NetworkPolicyManager.POLICY_NONE; import static android.net.NetworkPolicyManager.POLICY_NONE;
@@ -26,8 +27,15 @@ import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
import static android.net.NetworkPolicyManager.computeLastCycleBoundary; import static android.net.NetworkPolicyManager.computeLastCycleBoundary;
import static android.net.NetworkPolicyManager.computeNextCycleBoundary; import static android.net.NetworkPolicyManager.computeNextCycleBoundary;
import static android.net.NetworkPolicyManager.uidPoliciesToString; import static android.net.NetworkPolicyManager.uidPoliciesToString;
import static android.net.NetworkTemplate.buildTemplateMobileAll;
import static android.net.TrafficStats.KB_IN_BYTES; import static android.net.TrafficStats.KB_IN_BYTES;
import static android.net.TrafficStats.MB_IN_BYTES; import static android.net.TrafficStats.MB_IN_BYTES;
import static android.telephony.CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED;
import static android.telephony.CarrierConfigManager.DATA_CYCLE_USE_PLATFORM_DEFAULT;
import static android.telephony.CarrierConfigManager.DATA_CYCLE_THRESHOLD_DISABLED;
import static android.telephony.CarrierConfigManager.KEY_DATA_LIMIT_THRESHOLD_BYTES_LONG;
import static android.telephony.CarrierConfigManager.KEY_DATA_WARNING_THRESHOLD_BYTES_LONG;
import static android.telephony.CarrierConfigManager.KEY_MONTHLY_DATA_CYCLE_DAY_INT;
import static android.text.format.DateUtils.DAY_IN_MILLIS; import static android.text.format.DateUtils.DAY_IN_MILLIS;
import static android.text.format.DateUtils.MINUTE_IN_MILLIS; import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
import static android.text.format.Time.TIMEZONE_UTC; import static android.text.format.Time.TIMEZONE_UTC;
@@ -94,18 +102,24 @@ import android.net.NetworkStats;
import android.net.NetworkTemplate; import android.net.NetworkTemplate;
import android.os.Binder; import android.os.Binder;
import android.os.INetworkManagementService; import android.os.INetworkManagementService;
import android.os.PersistableBundle;
import android.os.PowerManagerInternal; import android.os.PowerManagerInternal;
import android.os.PowerSaveState; import android.os.PowerSaveState;
import android.os.RemoteException;
import android.os.UserHandle; import android.os.UserHandle;
import android.support.test.InstrumentationRegistry; import android.support.test.InstrumentationRegistry;
import android.support.test.filters.MediumTest; import android.support.test.filters.MediumTest;
import android.support.test.runner.AndroidJUnit4; import android.support.test.runner.AndroidJUnit4;
import android.telephony.CarrierConfigManager;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.text.TextUtils; import android.text.TextUtils;
import android.text.format.Time; import android.text.format.Time;
import android.util.Log; import android.util.Log;
import android.util.TrustedTime; import android.util.TrustedTime;
import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.telephony.PhoneConstants;
import com.android.internal.util.test.BroadcastInterceptingContext; import com.android.internal.util.test.BroadcastInterceptingContext;
import com.android.internal.util.test.BroadcastInterceptingContext.FutureIntent; import com.android.internal.util.test.BroadcastInterceptingContext.FutureIntent;
import com.android.server.net.NetworkPolicyManagerInternal; import com.android.server.net.NetworkPolicyManagerInternal;
@@ -143,6 +157,7 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; import java.lang.annotation.Target;
import java.util.Arrays; import java.util.Arrays;
import java.util.Calendar;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import java.util.List; import java.util.List;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
@@ -200,6 +215,9 @@ public class NetworkPolicyManagerServiceTest {
private @Mock INotificationManager mNotifManager; private @Mock INotificationManager mNotifManager;
private @Mock PackageManager mPackageManager; private @Mock PackageManager mPackageManager;
private @Mock IPackageManager mIpm; private @Mock IPackageManager mIpm;
private @Mock SubscriptionManager mSubscriptionManager;
private @Mock CarrierConfigManager mCarrierConfigManager;
private @Mock TelephonyManager mTelephonyManager;
private static ActivityManagerInternal mActivityManagerInternal; private static ActivityManagerInternal mActivityManagerInternal;
@@ -214,6 +232,12 @@ public class NetworkPolicyManagerServiceTest {
private long mElapsedRealtime; private long mElapsedRealtime;
private static final int USER_ID = 0; private static final int USER_ID = 0;
private static final int FAKE_SUB_ID = 3737373;
private static final String FAKE_SUBSCRIBER_ID = "FAKE_SUB_ID";
private static final int DEFAULT_CYCLE_DAY = 1;
private static final int INVALID_CARRIER_CONFIG_VALUE = -9999;
private long mDefaultWarningBytes; // filled in with the actual default before tests are run
private long mDefaultLimitBytes; // filled in with the actual default before tests are run
private static final int APP_ID_A = android.os.Process.FIRST_APPLICATION_UID + 4; private static final int APP_ID_A = android.os.Process.FIRST_APPLICATION_UID + 4;
private static final int APP_ID_B = android.os.Process.FIRST_APPLICATION_UID + 8; private static final int APP_ID_B = android.os.Process.FIRST_APPLICATION_UID + 8;
@@ -235,6 +259,8 @@ public class NetworkPolicyManagerServiceTest {
@BeforeClass @BeforeClass
public static void registerLocalServices() { public static void registerLocalServices() {
final PowerManagerInternal powerManager = addLocalServiceMock(PowerManagerInternal.class);
when(powerManager.getLowPowerState(anyInt())).thenReturn(mock(PowerSaveState.class));
addLocalServiceMock(DeviceIdleController.LocalService.class); addLocalServiceMock(DeviceIdleController.LocalService.class);
final UsageStatsManagerInternal usageStats = final UsageStatsManagerInternal usageStats =
addLocalServiceMock(UsageStatsManagerInternal.class); addLocalServiceMock(UsageStatsManagerInternal.class);
@@ -255,7 +281,8 @@ public class NetworkPolicyManagerServiceTest {
setCurrentTimeMillis(TEST_START); setCurrentTimeMillis(TEST_START);
// intercept various broadcasts, and pretend that uids have packages // Intercept various broadcasts, and pretend that uids have packages.
// Also return mock service instances for a few critical services.
mServiceContext = new BroadcastInterceptingContext(context) { mServiceContext = new BroadcastInterceptingContext(context) {
@Override @Override
public PackageManager getPackageManager() { public PackageManager getPackageManager() {
@@ -266,6 +293,20 @@ public class NetworkPolicyManagerServiceTest {
public void startActivity(Intent intent) { public void startActivity(Intent intent) {
// ignored // ignored
} }
@Override
public Object getSystemService(String name) {
switch (name) {
case Context.TELEPHONY_SUBSCRIPTION_SERVICE:
return mSubscriptionManager;
case Context.CARRIER_CONFIG_SERVICE:
return mCarrierConfigManager;
case Context.TELEPHONY_SERVICE:
return mTelephonyManager;
default:
return super.getSystemService(name);
}
}
}; };
setNetpolicyXml(context); setNetpolicyXml(context);
@@ -321,6 +362,10 @@ public class NetworkPolicyManagerServiceTest {
ArgumentCaptor.forClass(INetworkManagementEventObserver.class); ArgumentCaptor.forClass(INetworkManagementEventObserver.class);
verify(mNetworkManager).registerObserver(networkObserver.capture()); verify(mNetworkManager).registerObserver(networkObserver.capture());
mNetworkObserver = networkObserver.getValue(); mNetworkObserver = networkObserver.getValue();
NetworkPolicy defaultPolicy = mService.buildDefaultMobilePolicy(0, "");
mDefaultWarningBytes = defaultPolicy.warningBytes;
mDefaultLimitBytes = defaultPolicy.limitBytes;
} }
@After @After
@@ -1132,6 +1177,269 @@ public class NetworkPolicyManagerServiceTest {
} }
} }
private void assertCycleDayAsExpected(PersistableBundle config, int carrierCycleDay,
boolean expectValid) {
config.putInt(KEY_MONTHLY_DATA_CYCLE_DAY_INT, carrierCycleDay);
int actualCycleDay = mService.getCycleDayFromCarrierConfig(config,
INVALID_CARRIER_CONFIG_VALUE);
if (expectValid) {
assertEquals(carrierCycleDay, actualCycleDay);
} else {
// INVALID_CARRIER_CONFIG_VALUE is returned for invalid values
assertEquals(INVALID_CARRIER_CONFIG_VALUE, actualCycleDay);
}
}
@Test
public void testGetCycleDayFromCarrierConfig() {
PersistableBundle config = CarrierConfigManager.getDefaultConfig();
final Calendar cal = Calendar.getInstance();
int actualCycleDay;
config.putInt(KEY_MONTHLY_DATA_CYCLE_DAY_INT, DATA_CYCLE_USE_PLATFORM_DEFAULT);
actualCycleDay = mService.getCycleDayFromCarrierConfig(config, DEFAULT_CYCLE_DAY);
assertEquals(DEFAULT_CYCLE_DAY, actualCycleDay);
// null config returns a default value
actualCycleDay = mService.getCycleDayFromCarrierConfig(null, DEFAULT_CYCLE_DAY);
assertEquals(DEFAULT_CYCLE_DAY, actualCycleDay);
// Sane, non-default values
assertCycleDayAsExpected(config, 1, true);
assertCycleDayAsExpected(config, cal.getMaximum(Calendar.DAY_OF_MONTH), true);
assertCycleDayAsExpected(config, cal.getMinimum(Calendar.DAY_OF_MONTH), true);
// Invalid values
assertCycleDayAsExpected(config, 0, false);
assertCycleDayAsExpected(config, DATA_CYCLE_THRESHOLD_DISABLED, false);
assertCycleDayAsExpected(config, cal.getMaximum(Calendar.DAY_OF_MONTH) + 1, false);
assertCycleDayAsExpected(config, cal.getMinimum(Calendar.DAY_OF_MONTH) - 5, false);
}
private void assertWarningBytesAsExpected(PersistableBundle config, long carrierWarningBytes,
long expected) {
config.putLong(KEY_DATA_WARNING_THRESHOLD_BYTES_LONG, carrierWarningBytes);
long actualWarning = mService.getWarningBytesFromCarrierConfig(config,
INVALID_CARRIER_CONFIG_VALUE);
assertEquals(expected, actualWarning);
}
@Test
public void testGetWarningBytesFromCarrierConfig() {
PersistableBundle config = CarrierConfigManager.getDefaultConfig();
long actualWarningBytes;
assertWarningBytesAsExpected(config, DATA_CYCLE_USE_PLATFORM_DEFAULT,
mDefaultWarningBytes);
assertWarningBytesAsExpected(config, DATA_CYCLE_THRESHOLD_DISABLED, WARNING_DISABLED);
assertWarningBytesAsExpected(config, 0, 0);
// not a valid value
assertWarningBytesAsExpected(config, -1000, INVALID_CARRIER_CONFIG_VALUE);
// null config returns a default value
actualWarningBytes = mService.getWarningBytesFromCarrierConfig(null, mDefaultWarningBytes);
assertEquals(mDefaultWarningBytes, actualWarningBytes);
}
private void assertLimitBytesAsExpected(PersistableBundle config, long carrierWarningBytes,
long expected) {
config.putLong(KEY_DATA_LIMIT_THRESHOLD_BYTES_LONG, carrierWarningBytes);
long actualWarning = mService.getLimitBytesFromCarrierConfig(config,
INVALID_CARRIER_CONFIG_VALUE);
assertEquals(expected, actualWarning);
}
@Test
public void testGetLimitBytesFromCarrierConfig() {
PersistableBundle config = CarrierConfigManager.getDefaultConfig();
long actualLimitBytes;
assertLimitBytesAsExpected(config, DATA_CYCLE_USE_PLATFORM_DEFAULT,
mDefaultLimitBytes);
assertLimitBytesAsExpected(config, DATA_CYCLE_THRESHOLD_DISABLED, LIMIT_DISABLED);
assertLimitBytesAsExpected(config, 0, 0);
// not a valid value
assertLimitBytesAsExpected(config, -1000, INVALID_CARRIER_CONFIG_VALUE);
// null config returns a default value
actualLimitBytes = mService.getWarningBytesFromCarrierConfig(null, mDefaultLimitBytes);
assertEquals(mDefaultLimitBytes, actualLimitBytes);
}
private PersistableBundle setupUpdateMobilePolicyCycleTests() throws RemoteException {
when(mConnManager.getAllNetworkState()).thenReturn(new NetworkState[0]);
when(mSubscriptionManager.getActiveSubscriptionIdList()).thenReturn(new int[]{FAKE_SUB_ID});
when(mTelephonyManager.getSubscriberId(FAKE_SUB_ID)).thenReturn(FAKE_SUBSCRIBER_ID);
PersistableBundle bundle = CarrierConfigManager.getDefaultConfig();
when(mCarrierConfigManager.getConfigForSubId(FAKE_SUB_ID)).thenReturn(bundle);
setNetworkPolicies(buildDefaultFakeMobilePolicy());
return bundle;
}
@Test
public void testUpdateMobilePolicyCycleWithNullConfig() throws RemoteException {
when(mConnManager.getAllNetworkState()).thenReturn(new NetworkState[0]);
when(mSubscriptionManager.getActiveSubscriptionIdList()).thenReturn(new int[]{FAKE_SUB_ID});
when(mTelephonyManager.getSubscriberId(FAKE_SUB_ID)).thenReturn(FAKE_SUBSCRIBER_ID);
when(mCarrierConfigManager.getConfigForSubId(FAKE_SUB_ID)).thenReturn(null);
setNetworkPolicies(buildDefaultFakeMobilePolicy());
// smoke test to make sure no errors are raised
mServiceContext.sendBroadcast(
new Intent(ACTION_CARRIER_CONFIG_CHANGED)
.putExtra(PhoneConstants.SUBSCRIPTION_KEY, FAKE_SUB_ID)
);
assertNetworkPolicyEquals(DEFAULT_CYCLE_DAY, mDefaultWarningBytes, mDefaultLimitBytes,
true);
}
@Test
public void testUpdateMobilePolicyCycleWithInvalidConfig() throws RemoteException {
PersistableBundle bundle = setupUpdateMobilePolicyCycleTests();
// Test with an invalid CarrierConfig, there should be no changes or crashes.
bundle.putInt(CarrierConfigManager.KEY_MONTHLY_DATA_CYCLE_DAY_INT, -100);
bundle.putLong(CarrierConfigManager.KEY_DATA_WARNING_THRESHOLD_BYTES_LONG, -100);
bundle.putLong(CarrierConfigManager.KEY_DATA_LIMIT_THRESHOLD_BYTES_LONG, -100);
mServiceContext.sendBroadcast(
new Intent(ACTION_CARRIER_CONFIG_CHANGED)
.putExtra(PhoneConstants.SUBSCRIPTION_KEY, FAKE_SUB_ID)
);
assertNetworkPolicyEquals(DEFAULT_CYCLE_DAY, mDefaultWarningBytes, mDefaultLimitBytes,
true);
}
@Test
public void testUpdateMobilePolicyCycleWithDefaultConfig() throws RemoteException {
PersistableBundle bundle = setupUpdateMobilePolicyCycleTests();
// Test that we respect the platform values when told to
bundle.putInt(CarrierConfigManager.KEY_MONTHLY_DATA_CYCLE_DAY_INT,
DATA_CYCLE_USE_PLATFORM_DEFAULT);
bundle.putLong(CarrierConfigManager.KEY_DATA_WARNING_THRESHOLD_BYTES_LONG,
DATA_CYCLE_USE_PLATFORM_DEFAULT);
bundle.putLong(CarrierConfigManager.KEY_DATA_LIMIT_THRESHOLD_BYTES_LONG,
DATA_CYCLE_USE_PLATFORM_DEFAULT);
mServiceContext.sendBroadcast(
new Intent(ACTION_CARRIER_CONFIG_CHANGED)
.putExtra(PhoneConstants.SUBSCRIPTION_KEY, FAKE_SUB_ID)
);
assertNetworkPolicyEquals(DEFAULT_CYCLE_DAY, mDefaultWarningBytes, mDefaultLimitBytes,
true);
}
@Test
public void testUpdateMobilePolicyCycleWithUserOverrides() throws RemoteException {
PersistableBundle bundle = setupUpdateMobilePolicyCycleTests();
// inferred = false implies that a user manually modified this policy.
NetworkPolicy policy = buildDefaultFakeMobilePolicy();
policy.inferred = false;
setNetworkPolicies(policy);
bundle.putInt(CarrierConfigManager.KEY_MONTHLY_DATA_CYCLE_DAY_INT, 31);
bundle.putLong(CarrierConfigManager.KEY_DATA_WARNING_THRESHOLD_BYTES_LONG, 9999);
bundle.putLong(CarrierConfigManager.KEY_DATA_LIMIT_THRESHOLD_BYTES_LONG,
DATA_CYCLE_THRESHOLD_DISABLED);
mServiceContext.sendBroadcast(
new Intent(ACTION_CARRIER_CONFIG_CHANGED)
.putExtra(PhoneConstants.SUBSCRIPTION_KEY, FAKE_SUB_ID)
);
// The policy still shouldn't change, because we don't want to overwrite user settings.
assertNetworkPolicyEquals(DEFAULT_CYCLE_DAY, mDefaultWarningBytes, mDefaultLimitBytes,
false);
}
@Test
public void testUpdateMobilePolicyCycleUpdatesDataCycle() throws RemoteException {
PersistableBundle bundle = setupUpdateMobilePolicyCycleTests();
bundle.putInt(CarrierConfigManager.KEY_MONTHLY_DATA_CYCLE_DAY_INT, 31);
bundle.putLong(CarrierConfigManager.KEY_DATA_WARNING_THRESHOLD_BYTES_LONG, 9999);
bundle.putLong(CarrierConfigManager.KEY_DATA_LIMIT_THRESHOLD_BYTES_LONG, 9999);
mServiceContext.sendBroadcast(
new Intent(ACTION_CARRIER_CONFIG_CHANGED)
.putExtra(PhoneConstants.SUBSCRIPTION_KEY, FAKE_SUB_ID)
);
assertNetworkPolicyEquals(31, 9999, 9999, true);
}
@Test
public void testUpdateMobilePolicyCycleDisableThresholds() throws RemoteException {
PersistableBundle bundle = setupUpdateMobilePolicyCycleTests();
bundle.putInt(CarrierConfigManager.KEY_MONTHLY_DATA_CYCLE_DAY_INT, 31);
bundle.putLong(CarrierConfigManager.KEY_DATA_WARNING_THRESHOLD_BYTES_LONG,
DATA_CYCLE_THRESHOLD_DISABLED);
bundle.putLong(CarrierConfigManager.KEY_DATA_LIMIT_THRESHOLD_BYTES_LONG,
DATA_CYCLE_THRESHOLD_DISABLED);
mServiceContext.sendBroadcast(
new Intent(ACTION_CARRIER_CONFIG_CHANGED)
.putExtra(PhoneConstants.SUBSCRIPTION_KEY, FAKE_SUB_ID)
);
assertNetworkPolicyEquals(31, WARNING_DISABLED, LIMIT_DISABLED, true);
}
@Test
public void testUpdateMobilePolicyCycleRevertsToDefault() throws RemoteException {
PersistableBundle bundle = setupUpdateMobilePolicyCycleTests();
bundle.putInt(CarrierConfigManager.KEY_MONTHLY_DATA_CYCLE_DAY_INT, 31);
bundle.putLong(CarrierConfigManager.KEY_DATA_WARNING_THRESHOLD_BYTES_LONG,
DATA_CYCLE_THRESHOLD_DISABLED);
bundle.putLong(CarrierConfigManager.KEY_DATA_LIMIT_THRESHOLD_BYTES_LONG,
DATA_CYCLE_THRESHOLD_DISABLED);
mServiceContext.sendBroadcast(
new Intent(ACTION_CARRIER_CONFIG_CHANGED)
.putExtra(PhoneConstants.SUBSCRIPTION_KEY, FAKE_SUB_ID)
);
assertNetworkPolicyEquals(31, WARNING_DISABLED, LIMIT_DISABLED, true);
// If the user switches carriers to one that doesn't use a CarrierConfig, we should revert
// to the default data limit and warning. The cycle date doesn't need to revert as it's
// arbitrary anyways.
bundle.putInt(CarrierConfigManager.KEY_MONTHLY_DATA_CYCLE_DAY_INT,
DATA_CYCLE_USE_PLATFORM_DEFAULT);
bundle.putLong(CarrierConfigManager.KEY_DATA_WARNING_THRESHOLD_BYTES_LONG,
DATA_CYCLE_USE_PLATFORM_DEFAULT);
bundle.putLong(CarrierConfigManager.KEY_DATA_LIMIT_THRESHOLD_BYTES_LONG,
DATA_CYCLE_USE_PLATFORM_DEFAULT);
mServiceContext.sendBroadcast(
new Intent(ACTION_CARRIER_CONFIG_CHANGED)
.putExtra(PhoneConstants.SUBSCRIPTION_KEY, FAKE_SUB_ID)
);
assertNetworkPolicyEquals(31, mDefaultWarningBytes, mDefaultLimitBytes,
true);
}
private NetworkPolicy buildDefaultFakeMobilePolicy() {
NetworkPolicy p = mService.buildDefaultMobilePolicy(FAKE_SUB_ID, FAKE_SUBSCRIBER_ID);
// set a deterministic cycle date
p.cycleDay = DEFAULT_CYCLE_DAY;
return p;
}
private static NetworkPolicy buildFakeMobilePolicy(int cycleDay, long warningBytes,
long limitBytes, boolean inferred){
final NetworkTemplate template = buildTemplateMobileAll(FAKE_SUBSCRIBER_ID);
return new NetworkPolicy(template, cycleDay, "America/Los_Angeles", warningBytes,
limitBytes, SNOOZE_NEVER, SNOOZE_NEVER, true, inferred);
}
private void assertNetworkPolicyEquals(int expectedCycleDay, long expectedWarningBytes,
long expectedLimitBytes, boolean expectedInferred) {
NetworkPolicy[] policies = mService.getNetworkPolicies(
mServiceContext.getOpPackageName());
assertEquals("Unexpected number of network policies", 1, policies.length);
NetworkPolicy actualPolicy = policies[0];
NetworkPolicy expectedPolicy = buildFakeMobilePolicy(expectedCycleDay, expectedWarningBytes,
expectedLimitBytes, expectedInferred);
assertEquals(expectedPolicy, actualPolicy);
}
private static long parseTime(String time) { private static long parseTime(String time) {
final Time result = new Time(); final Time result = new Time();
result.parse3339(time); result.parse3339(time);