Defer low priority jobs in poor network conditions.
A poor network connection typically means it takes more power to transmit data and the device will heat up quickly trying to transmit data. In a poor network scenario, we should try to only use the network for important work, so defer low priority jobs on poorer network connections. Bug: 210077394 Test: atest frameworks/base/services/tests/servicestests/src/com/android/server/job Test: atest frameworks/base/services/tests/mockingservicestests/src/com/android/server/job Test: atest CtsJobSchedulerTestCases Change-Id: I33f2daac404ef2c399c58364e4c214152cc47de0
This commit is contained in:
@@ -417,6 +417,9 @@ public class JobSchedulerService extends com.android.server.SystemService
|
||||
break;
|
||||
case Constants.KEY_CONN_CONGESTION_DELAY_FRAC:
|
||||
case Constants.KEY_CONN_PREFETCH_RELAX_FRAC:
|
||||
case Constants.KEY_CONN_LOW_SIGNAL_STRENGTH_RELAX_FRAC:
|
||||
case Constants.KEY_CONN_USE_CELL_SIGNAL_STRENGTH:
|
||||
case Constants.KEY_CONN_UPDATE_ALL_JOBS_MIN_INTERVAL_MS:
|
||||
mConstants.updateConnectivityConstantsLocked();
|
||||
break;
|
||||
case Constants.KEY_PREFETCH_FORCE_BATCH_RELAX_THRESHOLD_MS:
|
||||
@@ -489,6 +492,12 @@ public class JobSchedulerService extends com.android.server.SystemService
|
||||
private static final String KEY_MIN_EXP_BACKOFF_TIME_MS = "min_exp_backoff_time_ms";
|
||||
private static final String KEY_CONN_CONGESTION_DELAY_FRAC = "conn_congestion_delay_frac";
|
||||
private static final String KEY_CONN_PREFETCH_RELAX_FRAC = "conn_prefetch_relax_frac";
|
||||
private static final String KEY_CONN_USE_CELL_SIGNAL_STRENGTH =
|
||||
"conn_use_cell_signal_strength";
|
||||
private static final String KEY_CONN_UPDATE_ALL_JOBS_MIN_INTERVAL_MS =
|
||||
"conn_update_all_jobs_min_interval_ms";
|
||||
private static final String KEY_CONN_LOW_SIGNAL_STRENGTH_RELAX_FRAC =
|
||||
"conn_low_signal_strength_relax_frac";
|
||||
private static final String KEY_PREFETCH_FORCE_BATCH_RELAX_THRESHOLD_MS =
|
||||
"prefetch_force_batch_relax_threshold_ms";
|
||||
private static final String KEY_ENABLE_API_QUOTAS = "enable_api_quotas";
|
||||
@@ -514,6 +523,9 @@ public class JobSchedulerService extends com.android.server.SystemService
|
||||
private static final long DEFAULT_MIN_EXP_BACKOFF_TIME_MS = JobInfo.MIN_BACKOFF_MILLIS;
|
||||
private static final float DEFAULT_CONN_CONGESTION_DELAY_FRAC = 0.5f;
|
||||
private static final float DEFAULT_CONN_PREFETCH_RELAX_FRAC = 0.5f;
|
||||
private static final boolean DEFAULT_CONN_USE_CELL_SIGNAL_STRENGTH = true;
|
||||
private static final long DEFAULT_CONN_UPDATE_ALL_JOBS_MIN_INTERVAL_MS = MINUTE_IN_MILLIS;
|
||||
private static final float DEFAULT_CONN_LOW_SIGNAL_STRENGTH_RELAX_FRAC = 0.5f;
|
||||
private static final long DEFAULT_PREFETCH_FORCE_BATCH_RELAX_THRESHOLD_MS = HOUR_IN_MILLIS;
|
||||
private static final boolean DEFAULT_ENABLE_API_QUOTAS = true;
|
||||
private static final int DEFAULT_API_QUOTA_SCHEDULE_COUNT = 250;
|
||||
@@ -569,6 +581,23 @@ public class JobSchedulerService extends com.android.server.SystemService
|
||||
* we consider matching it against a metered network.
|
||||
*/
|
||||
public float CONN_PREFETCH_RELAX_FRAC = DEFAULT_CONN_PREFETCH_RELAX_FRAC;
|
||||
/**
|
||||
* Whether to use the cell signal strength to determine if a particular job is eligible to
|
||||
* run.
|
||||
*/
|
||||
public boolean CONN_USE_CELL_SIGNAL_STRENGTH = DEFAULT_CONN_USE_CELL_SIGNAL_STRENGTH;
|
||||
/**
|
||||
* When throttling updating all tracked jobs, make sure not to update them more frequently
|
||||
* than this value.
|
||||
*/
|
||||
public long CONN_UPDATE_ALL_JOBS_MIN_INTERVAL_MS =
|
||||
DEFAULT_CONN_UPDATE_ALL_JOBS_MIN_INTERVAL_MS;
|
||||
/**
|
||||
* The fraction of a job's running window that must pass before we consider running it on
|
||||
* low signal strength networks.
|
||||
*/
|
||||
public float CONN_LOW_SIGNAL_STRENGTH_RELAX_FRAC =
|
||||
DEFAULT_CONN_LOW_SIGNAL_STRENGTH_RELAX_FRAC;
|
||||
|
||||
/**
|
||||
* The amount of time within which we would consider the app to be launching relatively soon
|
||||
@@ -661,6 +690,18 @@ public class JobSchedulerService extends com.android.server.SystemService
|
||||
CONN_PREFETCH_RELAX_FRAC = DeviceConfig.getFloat(DeviceConfig.NAMESPACE_JOB_SCHEDULER,
|
||||
KEY_CONN_PREFETCH_RELAX_FRAC,
|
||||
DEFAULT_CONN_PREFETCH_RELAX_FRAC);
|
||||
CONN_USE_CELL_SIGNAL_STRENGTH = DeviceConfig.getBoolean(
|
||||
DeviceConfig.NAMESPACE_JOB_SCHEDULER,
|
||||
KEY_CONN_USE_CELL_SIGNAL_STRENGTH,
|
||||
DEFAULT_CONN_USE_CELL_SIGNAL_STRENGTH);
|
||||
CONN_UPDATE_ALL_JOBS_MIN_INTERVAL_MS = DeviceConfig.getLong(
|
||||
DeviceConfig.NAMESPACE_JOB_SCHEDULER,
|
||||
KEY_CONN_UPDATE_ALL_JOBS_MIN_INTERVAL_MS,
|
||||
DEFAULT_CONN_UPDATE_ALL_JOBS_MIN_INTERVAL_MS);
|
||||
CONN_LOW_SIGNAL_STRENGTH_RELAX_FRAC = DeviceConfig.getFloat(
|
||||
DeviceConfig.NAMESPACE_JOB_SCHEDULER,
|
||||
KEY_CONN_LOW_SIGNAL_STRENGTH_RELAX_FRAC,
|
||||
DEFAULT_CONN_LOW_SIGNAL_STRENGTH_RELAX_FRAC);
|
||||
}
|
||||
|
||||
private void updatePrefetchConstantsLocked() {
|
||||
@@ -739,6 +780,11 @@ public class JobSchedulerService extends com.android.server.SystemService
|
||||
pw.print(KEY_MIN_EXP_BACKOFF_TIME_MS, MIN_EXP_BACKOFF_TIME_MS).println();
|
||||
pw.print(KEY_CONN_CONGESTION_DELAY_FRAC, CONN_CONGESTION_DELAY_FRAC).println();
|
||||
pw.print(KEY_CONN_PREFETCH_RELAX_FRAC, CONN_PREFETCH_RELAX_FRAC).println();
|
||||
pw.print(KEY_CONN_USE_CELL_SIGNAL_STRENGTH, CONN_USE_CELL_SIGNAL_STRENGTH).println();
|
||||
pw.print(KEY_CONN_UPDATE_ALL_JOBS_MIN_INTERVAL_MS, CONN_UPDATE_ALL_JOBS_MIN_INTERVAL_MS)
|
||||
.println();
|
||||
pw.print(KEY_CONN_LOW_SIGNAL_STRENGTH_RELAX_FRAC, CONN_LOW_SIGNAL_STRENGTH_RELAX_FRAC)
|
||||
.println();
|
||||
pw.print(KEY_PREFETCH_FORCE_BATCH_RELAX_THRESHOLD_MS,
|
||||
PREFETCH_FORCE_BATCH_RELAX_THRESHOLD_MS).println();
|
||||
|
||||
|
||||
@@ -35,6 +35,10 @@ import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.os.UserHandle;
|
||||
import android.telephony.CellSignalStrength;
|
||||
import android.telephony.SignalStrength;
|
||||
import android.telephony.TelephonyCallback;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.text.format.DateUtils;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.ArraySet;
|
||||
@@ -60,6 +64,7 @@ import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
@@ -213,9 +218,16 @@ public final class ConnectivityController extends RestrictingController implemen
|
||||
* is only done in {@link #maybeAdjustRegisteredCallbacksLocked()} and may sometimes be stale.
|
||||
*/
|
||||
private final List<UidStats> mSortedStats = new ArrayList<>();
|
||||
@GuardedBy("mLock")
|
||||
private long mLastCallbackAdjustmentTimeElapsed;
|
||||
@GuardedBy("mLock")
|
||||
private final SparseArray<CellSignalStrengthCallback> mSignalStrengths = new SparseArray<>();
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private long mLastAllJobUpdateTimeElapsed;
|
||||
|
||||
private static final int MSG_ADJUST_CALLBACKS = 0;
|
||||
private static final int MSG_UPDATE_ALL_TRACKED_JOBS = 1;
|
||||
|
||||
private final Handler mHandler;
|
||||
|
||||
@@ -529,11 +541,7 @@ public final class ConnectivityController extends RestrictingController implemen
|
||||
@GuardedBy("mLock")
|
||||
public void onBatteryStateChangedLocked() {
|
||||
// Update job bookkeeping out of band to avoid blocking broadcast progress.
|
||||
JobSchedulerBackgroundThread.getHandler().post(() -> {
|
||||
synchronized (mLock) {
|
||||
updateTrackedJobsLocked(-1, null);
|
||||
}
|
||||
});
|
||||
mHandler.sendEmptyMessage(MSG_UPDATE_ALL_TRACKED_JOBS);
|
||||
}
|
||||
|
||||
private boolean isUsable(NetworkCapabilities capabilities) {
|
||||
@@ -650,6 +658,82 @@ public final class ConnectivityController extends RestrictingController implemen
|
||||
}
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private boolean isStrongEnough(JobStatus jobStatus, NetworkCapabilities capabilities,
|
||||
Constants constants) {
|
||||
final int priority = jobStatus.getEffectivePriority();
|
||||
if (priority >= JobInfo.PRIORITY_HIGH) {
|
||||
return true;
|
||||
}
|
||||
if (!constants.CONN_USE_CELL_SIGNAL_STRENGTH) {
|
||||
return true;
|
||||
}
|
||||
if (!capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
|
||||
return true;
|
||||
}
|
||||
if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_VPN)) {
|
||||
// Exclude VPNs because it's currently not possible to determine the VPN's underlying
|
||||
// network, and thus the correct signal strength of the VPN's network.
|
||||
// Transmitting data over a VPN is generally more battery-expensive than on the
|
||||
// underlying network, so:
|
||||
// TODO: find a good way to reduce job use of VPN when it'll be very expensive
|
||||
// For now, we just pretend VPNs are always strong enough
|
||||
return true;
|
||||
}
|
||||
|
||||
// VCNs running over WiFi will declare TRANSPORT_CELLULAR. When connected, a VCN will
|
||||
// most likely be the default network. We ideally don't want this to restrict jobs when the
|
||||
// VCN incorrectly declares the CELLULAR transport, but there's currently no way to
|
||||
// determine if a network is a VCN. When there is:
|
||||
// TODO(216127782): exclude VCN running over WiFi from this check
|
||||
|
||||
int signalStrength = CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
|
||||
// Use the best strength found.
|
||||
final Set<Integer> subscriptionIds = capabilities.getSubscriptionIds();
|
||||
for (int subId : subscriptionIds) {
|
||||
CellSignalStrengthCallback callback = mSignalStrengths.get(subId);
|
||||
if (callback != null) {
|
||||
signalStrength = Math.max(signalStrength, callback.signalStrength);
|
||||
} else {
|
||||
Slog.wtf(TAG,
|
||||
"Subscription ID " + subId + " doesn't have a registered callback");
|
||||
}
|
||||
}
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "Cell signal strength for job=" + signalStrength);
|
||||
}
|
||||
// Treat "NONE_OR_UNKNOWN" as "NONE".
|
||||
if (signalStrength <= CellSignalStrength.SIGNAL_STRENGTH_POOR) {
|
||||
// If signal strength is poor, don't run MIN or LOW priority jobs, and only
|
||||
// run DEFAULT priority jobs if the device is charging or the job has been waiting
|
||||
// long enough.
|
||||
if (priority > JobInfo.PRIORITY_DEFAULT) {
|
||||
return true;
|
||||
}
|
||||
if (priority < JobInfo.PRIORITY_DEFAULT) {
|
||||
return false;
|
||||
}
|
||||
// DEFAULT job.
|
||||
return (mService.isBatteryCharging() && mService.isBatteryNotLow())
|
||||
|| jobStatus.getFractionRunTime() > constants.CONN_PREFETCH_RELAX_FRAC;
|
||||
}
|
||||
if (signalStrength <= CellSignalStrength.SIGNAL_STRENGTH_MODERATE) {
|
||||
// If signal strength is moderate, only run MIN priority jobs when the device
|
||||
// is charging, or the job is already running.
|
||||
if (priority >= JobInfo.PRIORITY_LOW) {
|
||||
return true;
|
||||
}
|
||||
// MIN job.
|
||||
if (mService.isBatteryCharging() && mService.isBatteryNotLow()) {
|
||||
return true;
|
||||
}
|
||||
final UidStats uidStats = getUidStats(
|
||||
jobStatus.getSourceUid(), jobStatus.getSourcePackageName(), true);
|
||||
return uidStats.runningJobs.contains(jobStatus);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static NetworkCapabilities.Builder copyCapabilities(
|
||||
@NonNull final NetworkRequest request) {
|
||||
final NetworkCapabilities.Builder builder = new NetworkCapabilities.Builder();
|
||||
@@ -717,10 +801,12 @@ public final class ConnectivityController extends RestrictingController implemen
|
||||
// Second, is the network congested?
|
||||
if (isCongestionDelayed(jobStatus, network, capabilities, constants)) return false;
|
||||
|
||||
// Third, is the network a strict match?
|
||||
if (!isStrongEnough(jobStatus, capabilities, constants)) return false;
|
||||
|
||||
// Is the network a strict match?
|
||||
if (isStrictSatisfied(jobStatus, network, capabilities, constants)) return true;
|
||||
|
||||
// Third, is the network a relaxed match?
|
||||
// Is the network a relaxed match?
|
||||
if (isRelaxedSatisfied(jobStatus, network, capabilities, constants)) return true;
|
||||
|
||||
return false;
|
||||
@@ -985,6 +1071,24 @@ public final class ConnectivityController extends RestrictingController implemen
|
||||
return changed;
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private void updateAllTrackedJobsLocked(boolean allowThrottle) {
|
||||
if (allowThrottle) {
|
||||
final long throttleTimeLeftMs =
|
||||
(mLastAllJobUpdateTimeElapsed + mConstants.CONN_UPDATE_ALL_JOBS_MIN_INTERVAL_MS)
|
||||
- sElapsedRealtimeClock.millis();
|
||||
if (throttleTimeLeftMs > 0) {
|
||||
Message msg = mHandler.obtainMessage(MSG_UPDATE_ALL_TRACKED_JOBS, 1, 0);
|
||||
mHandler.sendMessageDelayed(msg, throttleTimeLeftMs);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
mHandler.removeMessages(MSG_UPDATE_ALL_TRACKED_JOBS);
|
||||
updateTrackedJobsLocked(-1, null);
|
||||
mLastAllJobUpdateTimeElapsed = sElapsedRealtimeClock.millis();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update any jobs tracked by this controller that match given filters.
|
||||
*
|
||||
@@ -1088,7 +1192,11 @@ public final class ConnectivityController extends RestrictingController implemen
|
||||
Slog.v(TAG, "onCapabilitiesChanged: " + network);
|
||||
}
|
||||
synchronized (mLock) {
|
||||
mAvailableNetworks.put(network, capabilities);
|
||||
final NetworkCapabilities oldCaps = mAvailableNetworks.put(network, capabilities);
|
||||
if (oldCaps != null) {
|
||||
maybeUnregisterSignalStrengthCallbackLocked(oldCaps);
|
||||
}
|
||||
maybeRegisterSignalStrengthCallbackLocked(capabilities);
|
||||
updateTrackedJobsLocked(-1, network);
|
||||
postAdjustCallbacks();
|
||||
}
|
||||
@@ -1100,7 +1208,10 @@ public final class ConnectivityController extends RestrictingController implemen
|
||||
Slog.v(TAG, "onLost: " + network);
|
||||
}
|
||||
synchronized (mLock) {
|
||||
mAvailableNetworks.remove(network);
|
||||
final NetworkCapabilities capabilities = mAvailableNetworks.remove(network);
|
||||
if (capabilities != null) {
|
||||
maybeUnregisterSignalStrengthCallbackLocked(capabilities);
|
||||
}
|
||||
for (int u = 0; u < mCurrentDefaultNetworkCallbacks.size(); ++u) {
|
||||
UidDefaultNetworkCallback callback = mCurrentDefaultNetworkCallbacks.valueAt(u);
|
||||
if (Objects.equals(callback.mDefaultNetwork, network)) {
|
||||
@@ -1111,6 +1222,63 @@ public final class ConnectivityController extends RestrictingController implemen
|
||||
postAdjustCallbacks();
|
||||
}
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private void maybeRegisterSignalStrengthCallbackLocked(
|
||||
@NonNull NetworkCapabilities capabilities) {
|
||||
if (!capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
|
||||
return;
|
||||
}
|
||||
TelephonyManager telephonyManager = mContext.getSystemService(TelephonyManager.class);
|
||||
final Set<Integer> subscriptionIds = capabilities.getSubscriptionIds();
|
||||
for (int subId : subscriptionIds) {
|
||||
if (mSignalStrengths.indexOfKey(subId) >= 0) {
|
||||
continue;
|
||||
}
|
||||
TelephonyManager idTm = telephonyManager.createForSubscriptionId(subId);
|
||||
CellSignalStrengthCallback callback = new CellSignalStrengthCallback();
|
||||
idTm.registerTelephonyCallback(
|
||||
JobSchedulerBackgroundThread.getExecutor(), callback);
|
||||
mSignalStrengths.put(subId, callback);
|
||||
|
||||
final SignalStrength signalStrength = idTm.getSignalStrength();
|
||||
if (signalStrength != null) {
|
||||
callback.signalStrength = signalStrength.getLevel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private void maybeUnregisterSignalStrengthCallbackLocked(
|
||||
@NonNull NetworkCapabilities capabilities) {
|
||||
if (!capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
|
||||
return;
|
||||
}
|
||||
ArraySet<Integer> activeIds = new ArraySet<>();
|
||||
for (int i = 0, size = mAvailableNetworks.size(); i < size; ++i) {
|
||||
NetworkCapabilities nc = mAvailableNetworks.valueAt(i);
|
||||
if (nc.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
|
||||
activeIds.addAll(nc.getSubscriptionIds());
|
||||
}
|
||||
}
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "Active subscription IDs: " + activeIds);
|
||||
}
|
||||
TelephonyManager telephonyManager = mContext.getSystemService(TelephonyManager.class);
|
||||
Set<Integer> subscriptionIds = capabilities.getSubscriptionIds();
|
||||
for (int subId : subscriptionIds) {
|
||||
if (activeIds.contains(subId)) {
|
||||
continue;
|
||||
}
|
||||
TelephonyManager idTm = telephonyManager.createForSubscriptionId(subId);
|
||||
CellSignalStrengthCallback callback = mSignalStrengths.removeReturnOld(subId);
|
||||
if (callback != null) {
|
||||
idTm.unregisterTelephonyCallback(callback);
|
||||
} else {
|
||||
Slog.wtf(TAG, "Callback for sub " + subId + " didn't exist?!?!");
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private class CcHandler extends Handler {
|
||||
@@ -1127,6 +1295,13 @@ public final class ConnectivityController extends RestrictingController implemen
|
||||
maybeAdjustRegisteredCallbacksLocked();
|
||||
}
|
||||
break;
|
||||
|
||||
case MSG_UPDATE_ALL_TRACKED_JOBS:
|
||||
synchronized (mLock) {
|
||||
final boolean allowThrottle = msg.arg1 == 1;
|
||||
updateAllTrackedJobsLocked(allowThrottle);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1268,6 +1443,33 @@ public final class ConnectivityController extends RestrictingController implemen
|
||||
}
|
||||
}
|
||||
|
||||
private class CellSignalStrengthCallback extends TelephonyCallback
|
||||
implements TelephonyCallback.SignalStrengthsListener {
|
||||
@GuardedBy("mLock")
|
||||
public int signalStrength = CellSignalStrength.SIGNAL_STRENGTH_GREAT;
|
||||
|
||||
@Override
|
||||
public void onSignalStrengthsChanged(@NonNull SignalStrength signalStrength) {
|
||||
synchronized (mLock) {
|
||||
final int newSignalStrength = signalStrength.getLevel();
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "Signal strength changing from "
|
||||
+ this.signalStrength + " to " + newSignalStrength);
|
||||
for (CellSignalStrength css : signalStrength.getCellSignalStrengths()) {
|
||||
Slog.d(TAG, "CSS: " + css.getLevel() + " " + css);
|
||||
}
|
||||
}
|
||||
if (this.signalStrength == newSignalStrength) {
|
||||
// This happens a lot.
|
||||
return;
|
||||
}
|
||||
this.signalStrength = newSignalStrength;
|
||||
// Update job bookkeeping out of band to avoid blocking callback progress.
|
||||
mHandler.obtainMessage(MSG_UPDATE_ALL_TRACKED_JOBS, 1, 0).sendToTarget();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
@Override
|
||||
public void dumpControllerStateLocked(IndentingPrintWriter pw,
|
||||
@@ -1299,6 +1501,20 @@ public final class ConnectivityController extends RestrictingController implemen
|
||||
}
|
||||
pw.println();
|
||||
|
||||
if (mSignalStrengths.size() > 0) {
|
||||
pw.println("Subscription ID signal strengths:");
|
||||
pw.increaseIndent();
|
||||
for (int i = 0; i < mSignalStrengths.size(); ++i) {
|
||||
pw.print(mSignalStrengths.keyAt(i));
|
||||
pw.print(": ");
|
||||
pw.println(mSignalStrengths.valueAt(i).signalStrength);
|
||||
}
|
||||
pw.decreaseIndent();
|
||||
} else {
|
||||
pw.println("No cached signal strengths");
|
||||
}
|
||||
pw.println();
|
||||
|
||||
pw.println("Current default network callbacks:");
|
||||
pw.increaseIndent();
|
||||
for (int i = 0; i < mCurrentDefaultNetworkCallbacks.size(); i++) {
|
||||
|
||||
@@ -1139,11 +1139,12 @@ public final class JobStatus {
|
||||
*/
|
||||
public float getFractionRunTime() {
|
||||
final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
|
||||
if (earliestRunTimeElapsedMillis == 0 && latestRunTimeElapsedMillis == Long.MAX_VALUE) {
|
||||
if (earliestRunTimeElapsedMillis == NO_EARLIEST_RUNTIME
|
||||
&& latestRunTimeElapsedMillis == NO_LATEST_RUNTIME) {
|
||||
return 1;
|
||||
} else if (earliestRunTimeElapsedMillis == 0) {
|
||||
} else if (earliestRunTimeElapsedMillis == NO_EARLIEST_RUNTIME) {
|
||||
return now >= latestRunTimeElapsedMillis ? 1 : 0;
|
||||
} else if (latestRunTimeElapsedMillis == Long.MAX_VALUE) {
|
||||
} else if (latestRunTimeElapsedMillis == NO_LATEST_RUNTIME) {
|
||||
return now >= earliestRunTimeElapsedMillis ? 1 : 0;
|
||||
} else {
|
||||
if (now <= earliestRunTimeElapsedMillis) {
|
||||
|
||||
@@ -23,6 +23,7 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED;
|
||||
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED;
|
||||
import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
|
||||
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
|
||||
import static android.net.NetworkCapabilities.TRANSPORT_VPN;
|
||||
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
|
||||
@@ -59,6 +60,10 @@ import android.net.NetworkPolicyManager;
|
||||
import android.os.Build;
|
||||
import android.os.Looper;
|
||||
import android.os.SystemClock;
|
||||
import android.telephony.CellSignalStrength;
|
||||
import android.telephony.SignalStrength;
|
||||
import android.telephony.TelephonyCallback;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.util.DataUnit;
|
||||
|
||||
import com.android.server.LocalServices;
|
||||
@@ -76,6 +81,7 @@ import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
import java.time.Clock;
|
||||
import java.time.ZoneOffset;
|
||||
import java.util.Set;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class ConnectivityControllerTest {
|
||||
@@ -301,6 +307,427 @@ public class ConnectivityControllerTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStrongEnough_Cellular() {
|
||||
mConstants.CONN_UPDATE_ALL_JOBS_MIN_INTERVAL_MS = 0;
|
||||
|
||||
final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
|
||||
final TelephonyManager telephonyManager = mock(TelephonyManager.class);
|
||||
when(mContext.getSystemService(TelephonyManager.class))
|
||||
.thenReturn(telephonyManager);
|
||||
when(telephonyManager.createForSubscriptionId(anyInt()))
|
||||
.thenReturn(telephonyManager);
|
||||
final ArgumentCaptor<TelephonyCallback> signalStrengthsCaptor =
|
||||
ArgumentCaptor.forClass(TelephonyCallback.class);
|
||||
doNothing().when(telephonyManager)
|
||||
.registerTelephonyCallback(any(), signalStrengthsCaptor.capture());
|
||||
final ArgumentCaptor<NetworkCallback> callbackCaptor =
|
||||
ArgumentCaptor.forClass(NetworkCallback.class);
|
||||
doNothing().when(mConnManager).registerNetworkCallback(any(), callbackCaptor.capture());
|
||||
final Network net = mock(Network.class);
|
||||
final NetworkCapabilities caps = createCapabilitiesBuilder()
|
||||
.addTransportType(TRANSPORT_CELLULAR)
|
||||
.addCapability(NET_CAPABILITY_NOT_CONGESTED)
|
||||
.setSubscriptionIds(Set.of(7357))
|
||||
.build();
|
||||
final JobInfo.Builder baseJobBuilder = createJob()
|
||||
.setEstimatedNetworkBytes(DataUnit.MEBIBYTES.toBytes(1),
|
||||
DataUnit.MEBIBYTES.toBytes(1))
|
||||
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY);
|
||||
final JobStatus jobExp = createJobStatus(baseJobBuilder.setExpedited(true));
|
||||
final JobStatus jobHigh = createJobStatus(
|
||||
baseJobBuilder.setExpedited(false).setPriority(JobInfo.PRIORITY_HIGH));
|
||||
final JobStatus jobDefEarly = createJobStatus(
|
||||
baseJobBuilder.setExpedited(false).setPriority(JobInfo.PRIORITY_DEFAULT),
|
||||
now - 1000, now + 100_000);
|
||||
final JobStatus jobDefLate = createJobStatus(
|
||||
baseJobBuilder.setExpedited(false).setPriority(JobInfo.PRIORITY_DEFAULT),
|
||||
now - 100_000, now + 1000);
|
||||
final JobStatus jobLow = createJobStatus(
|
||||
baseJobBuilder.setExpedited(false).setPriority(JobInfo.PRIORITY_LOW));
|
||||
final JobStatus jobMin = createJobStatus(
|
||||
baseJobBuilder.setExpedited(false).setPriority(JobInfo.PRIORITY_MIN));
|
||||
final JobStatus jobMinRunner = createJobStatus(
|
||||
baseJobBuilder.setExpedited(false).setPriority(JobInfo.PRIORITY_MIN));
|
||||
|
||||
final ConnectivityController controller = new ConnectivityController(mService);
|
||||
|
||||
final NetworkCallback generalCallback = callbackCaptor.getValue();
|
||||
|
||||
when(mService.getMaxJobExecutionTimeMs(any())).thenReturn(10 * 60_000L);
|
||||
|
||||
when(mService.isBatteryCharging()).thenReturn(false);
|
||||
when(mService.isBatteryNotLow()).thenReturn(false);
|
||||
answerNetwork(generalCallback, null, null, net, caps);
|
||||
|
||||
final TelephonyCallback.SignalStrengthsListener signalStrengthsListener =
|
||||
(TelephonyCallback.SignalStrengthsListener) signalStrengthsCaptor.getValue();
|
||||
|
||||
controller.maybeStartTrackingJobLocked(jobMinRunner, null);
|
||||
controller.prepareForExecutionLocked(jobMinRunner);
|
||||
|
||||
final SignalStrength signalStrength = mock(SignalStrength.class);
|
||||
|
||||
when(signalStrength.getLevel()).thenReturn(
|
||||
CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN);
|
||||
signalStrengthsListener.onSignalStrengthsChanged(signalStrength);
|
||||
|
||||
assertTrue(controller.isSatisfied(jobExp, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobHigh, net, caps, mConstants));
|
||||
assertFalse(controller.isSatisfied(jobDefEarly, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobDefLate, net, caps, mConstants));
|
||||
assertFalse(controller.isSatisfied(jobLow, net, caps, mConstants));
|
||||
assertFalse(controller.isSatisfied(jobMin, net, caps, mConstants));
|
||||
assertFalse(controller.isSatisfied(jobMinRunner, net, caps, mConstants));
|
||||
|
||||
when(signalStrength.getLevel()).thenReturn(
|
||||
CellSignalStrength.SIGNAL_STRENGTH_POOR);
|
||||
signalStrengthsListener.onSignalStrengthsChanged(signalStrength);
|
||||
|
||||
assertTrue(controller.isSatisfied(jobExp, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobHigh, net, caps, mConstants));
|
||||
assertFalse(controller.isSatisfied(jobDefEarly, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobDefLate, net, caps, mConstants));
|
||||
assertFalse(controller.isSatisfied(jobLow, net, caps, mConstants));
|
||||
assertFalse(controller.isSatisfied(jobMin, net, caps, mConstants));
|
||||
assertFalse(controller.isSatisfied(jobMinRunner, net, caps, mConstants));
|
||||
|
||||
when(mService.isBatteryCharging()).thenReturn(true);
|
||||
when(mService.isBatteryNotLow()).thenReturn(false);
|
||||
|
||||
assertTrue(controller.isSatisfied(jobExp, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobHigh, net, caps, mConstants));
|
||||
assertFalse(controller.isSatisfied(jobDefEarly, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobDefLate, net, caps, mConstants));
|
||||
assertFalse(controller.isSatisfied(jobLow, net, caps, mConstants));
|
||||
assertFalse(controller.isSatisfied(jobMin, net, caps, mConstants));
|
||||
assertFalse(controller.isSatisfied(jobMinRunner, net, caps, mConstants));
|
||||
|
||||
when(mService.isBatteryCharging()).thenReturn(true);
|
||||
when(mService.isBatteryNotLow()).thenReturn(true);
|
||||
|
||||
assertTrue(controller.isSatisfied(jobExp, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobHigh, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobDefEarly, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobDefLate, net, caps, mConstants));
|
||||
assertFalse(controller.isSatisfied(jobLow, net, caps, mConstants));
|
||||
assertFalse(controller.isSatisfied(jobMin, net, caps, mConstants));
|
||||
assertFalse(controller.isSatisfied(jobMinRunner, net, caps, mConstants));
|
||||
|
||||
when(mService.isBatteryCharging()).thenReturn(false);
|
||||
when(mService.isBatteryNotLow()).thenReturn(false);
|
||||
when(signalStrength.getLevel()).thenReturn(
|
||||
CellSignalStrength.SIGNAL_STRENGTH_MODERATE);
|
||||
signalStrengthsListener.onSignalStrengthsChanged(signalStrength);
|
||||
|
||||
assertTrue(controller.isSatisfied(jobExp, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobHigh, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobDefEarly, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobDefLate, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobLow, net, caps, mConstants));
|
||||
assertFalse(controller.isSatisfied(jobMin, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobMinRunner, net, caps, mConstants));
|
||||
|
||||
when(mService.isBatteryCharging()).thenReturn(false);
|
||||
when(mService.isBatteryNotLow()).thenReturn(true);
|
||||
|
||||
assertTrue(controller.isSatisfied(jobExp, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobHigh, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobDefEarly, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobDefLate, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobLow, net, caps, mConstants));
|
||||
assertFalse(controller.isSatisfied(jobMin, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobMinRunner, net, caps, mConstants));
|
||||
|
||||
when(mService.isBatteryCharging()).thenReturn(true);
|
||||
when(mService.isBatteryNotLow()).thenReturn(true);
|
||||
|
||||
assertTrue(controller.isSatisfied(jobExp, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobHigh, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobDefEarly, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobDefLate, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobLow, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobMin, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobMinRunner, net, caps, mConstants));
|
||||
|
||||
when(mService.isBatteryCharging()).thenReturn(false);
|
||||
when(mService.isBatteryNotLow()).thenReturn(false);
|
||||
when(signalStrength.getLevel()).thenReturn(
|
||||
CellSignalStrength.SIGNAL_STRENGTH_GOOD);
|
||||
signalStrengthsListener.onSignalStrengthsChanged(signalStrength);
|
||||
|
||||
assertTrue(controller.isSatisfied(jobExp, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobHigh, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobDefEarly, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobDefLate, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobLow, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobMin, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobMinRunner, net, caps, mConstants));
|
||||
|
||||
when(mService.isBatteryCharging()).thenReturn(false);
|
||||
when(mService.isBatteryNotLow()).thenReturn(false);
|
||||
when(signalStrength.getLevel()).thenReturn(
|
||||
CellSignalStrength.SIGNAL_STRENGTH_GREAT);
|
||||
signalStrengthsListener.onSignalStrengthsChanged(signalStrength);
|
||||
|
||||
assertTrue(controller.isSatisfied(jobExp, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobHigh, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobDefEarly, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobDefLate, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobLow, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobMin, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobMinRunner, net, caps, mConstants));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStrongEnough_Cellular_CheckDisabled() {
|
||||
mConstants.CONN_USE_CELL_SIGNAL_STRENGTH = false;
|
||||
mConstants.CONN_UPDATE_ALL_JOBS_MIN_INTERVAL_MS = 0;
|
||||
|
||||
final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
|
||||
final TelephonyManager telephonyManager = mock(TelephonyManager.class);
|
||||
when(mContext.getSystemService(TelephonyManager.class))
|
||||
.thenReturn(telephonyManager);
|
||||
when(telephonyManager.createForSubscriptionId(anyInt()))
|
||||
.thenReturn(telephonyManager);
|
||||
final ArgumentCaptor<TelephonyCallback> signalStrengthsCaptor =
|
||||
ArgumentCaptor.forClass(TelephonyCallback.class);
|
||||
doNothing().when(telephonyManager)
|
||||
.registerTelephonyCallback(any(), signalStrengthsCaptor.capture());
|
||||
final ArgumentCaptor<NetworkCallback> callbackCaptor =
|
||||
ArgumentCaptor.forClass(NetworkCallback.class);
|
||||
doNothing().when(mConnManager).registerNetworkCallback(any(), callbackCaptor.capture());
|
||||
final Network net = mock(Network.class);
|
||||
final NetworkCapabilities caps = createCapabilitiesBuilder()
|
||||
.addTransportType(TRANSPORT_CELLULAR)
|
||||
.addCapability(NET_CAPABILITY_NOT_CONGESTED)
|
||||
.setSubscriptionIds(Set.of(7357))
|
||||
.build();
|
||||
final JobInfo.Builder baseJobBuilder = createJob()
|
||||
.setEstimatedNetworkBytes(DataUnit.MEBIBYTES.toBytes(1),
|
||||
DataUnit.MEBIBYTES.toBytes(1))
|
||||
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY);
|
||||
final JobStatus jobExp = createJobStatus(baseJobBuilder.setExpedited(true));
|
||||
final JobStatus jobHigh = createJobStatus(
|
||||
baseJobBuilder.setExpedited(false).setPriority(JobInfo.PRIORITY_HIGH));
|
||||
final JobStatus jobDefEarly = createJobStatus(
|
||||
baseJobBuilder.setExpedited(false).setPriority(JobInfo.PRIORITY_DEFAULT),
|
||||
now - 1000, now + 100_000);
|
||||
final JobStatus jobDefLate = createJobStatus(
|
||||
baseJobBuilder.setExpedited(false).setPriority(JobInfo.PRIORITY_DEFAULT),
|
||||
now - 100_000, now + 1000);
|
||||
final JobStatus jobLow = createJobStatus(
|
||||
baseJobBuilder.setExpedited(false).setPriority(JobInfo.PRIORITY_LOW));
|
||||
final JobStatus jobMin = createJobStatus(
|
||||
baseJobBuilder.setExpedited(false).setPriority(JobInfo.PRIORITY_MIN));
|
||||
final JobStatus jobMinRunner = createJobStatus(
|
||||
baseJobBuilder.setExpedited(false).setPriority(JobInfo.PRIORITY_MIN));
|
||||
|
||||
final ConnectivityController controller = new ConnectivityController(mService);
|
||||
|
||||
final NetworkCallback generalCallback = callbackCaptor.getValue();
|
||||
|
||||
when(mService.getMaxJobExecutionTimeMs(any())).thenReturn(10 * 60_000L);
|
||||
|
||||
when(mService.isBatteryCharging()).thenReturn(false);
|
||||
when(mService.isBatteryNotLow()).thenReturn(false);
|
||||
answerNetwork(generalCallback, null, null, net, caps);
|
||||
|
||||
final TelephonyCallback.SignalStrengthsListener signalStrengthsListener =
|
||||
(TelephonyCallback.SignalStrengthsListener) signalStrengthsCaptor.getValue();
|
||||
|
||||
controller.maybeStartTrackingJobLocked(jobMinRunner, null);
|
||||
controller.prepareForExecutionLocked(jobMinRunner);
|
||||
|
||||
final SignalStrength signalStrength = mock(SignalStrength.class);
|
||||
|
||||
when(signalStrength.getLevel()).thenReturn(
|
||||
CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN);
|
||||
signalStrengthsListener.onSignalStrengthsChanged(signalStrength);
|
||||
|
||||
assertTrue(controller.isSatisfied(jobExp, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobHigh, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobDefEarly, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobDefLate, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobLow, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobMin, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobMinRunner, net, caps, mConstants));
|
||||
|
||||
when(signalStrength.getLevel()).thenReturn(
|
||||
CellSignalStrength.SIGNAL_STRENGTH_POOR);
|
||||
signalStrengthsListener.onSignalStrengthsChanged(signalStrength);
|
||||
|
||||
assertTrue(controller.isSatisfied(jobExp, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobHigh, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobDefEarly, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobDefLate, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobLow, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobMin, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobMinRunner, net, caps, mConstants));
|
||||
|
||||
when(mService.isBatteryCharging()).thenReturn(true);
|
||||
when(mService.isBatteryNotLow()).thenReturn(false);
|
||||
|
||||
assertTrue(controller.isSatisfied(jobExp, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobHigh, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobDefEarly, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobDefLate, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobLow, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobMin, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobMinRunner, net, caps, mConstants));
|
||||
|
||||
when(mService.isBatteryCharging()).thenReturn(true);
|
||||
when(mService.isBatteryNotLow()).thenReturn(true);
|
||||
|
||||
assertTrue(controller.isSatisfied(jobExp, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobHigh, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobDefEarly, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobDefLate, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobLow, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobMin, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobMinRunner, net, caps, mConstants));
|
||||
|
||||
when(mService.isBatteryCharging()).thenReturn(false);
|
||||
when(mService.isBatteryNotLow()).thenReturn(false);
|
||||
when(signalStrength.getLevel()).thenReturn(
|
||||
CellSignalStrength.SIGNAL_STRENGTH_MODERATE);
|
||||
signalStrengthsListener.onSignalStrengthsChanged(signalStrength);
|
||||
|
||||
assertTrue(controller.isSatisfied(jobExp, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobHigh, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobDefEarly, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobDefLate, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobLow, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobMin, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobMinRunner, net, caps, mConstants));
|
||||
|
||||
when(mService.isBatteryCharging()).thenReturn(false);
|
||||
when(mService.isBatteryNotLow()).thenReturn(true);
|
||||
|
||||
assertTrue(controller.isSatisfied(jobExp, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobHigh, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobDefEarly, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobDefLate, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobLow, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobMin, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobMinRunner, net, caps, mConstants));
|
||||
|
||||
when(mService.isBatteryCharging()).thenReturn(true);
|
||||
when(mService.isBatteryNotLow()).thenReturn(true);
|
||||
|
||||
assertTrue(controller.isSatisfied(jobExp, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobHigh, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobDefEarly, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobDefLate, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobLow, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobMin, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobMinRunner, net, caps, mConstants));
|
||||
|
||||
when(mService.isBatteryCharging()).thenReturn(false);
|
||||
when(mService.isBatteryNotLow()).thenReturn(false);
|
||||
when(signalStrength.getLevel()).thenReturn(
|
||||
CellSignalStrength.SIGNAL_STRENGTH_GOOD);
|
||||
signalStrengthsListener.onSignalStrengthsChanged(signalStrength);
|
||||
|
||||
assertTrue(controller.isSatisfied(jobExp, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobHigh, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobDefEarly, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobDefLate, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobLow, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobMin, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobMinRunner, net, caps, mConstants));
|
||||
|
||||
when(mService.isBatteryCharging()).thenReturn(false);
|
||||
when(mService.isBatteryNotLow()).thenReturn(false);
|
||||
when(signalStrength.getLevel()).thenReturn(
|
||||
CellSignalStrength.SIGNAL_STRENGTH_GREAT);
|
||||
signalStrengthsListener.onSignalStrengthsChanged(signalStrength);
|
||||
|
||||
assertTrue(controller.isSatisfied(jobExp, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobHigh, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobDefEarly, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobDefLate, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobLow, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobMin, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobMinRunner, net, caps, mConstants));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStrongEnough_Cellular_VPN() {
|
||||
mConstants.CONN_UPDATE_ALL_JOBS_MIN_INTERVAL_MS = 0;
|
||||
|
||||
final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
|
||||
final TelephonyManager telephonyManager = mock(TelephonyManager.class);
|
||||
when(mContext.getSystemService(TelephonyManager.class))
|
||||
.thenReturn(telephonyManager);
|
||||
when(telephonyManager.createForSubscriptionId(anyInt()))
|
||||
.thenReturn(telephonyManager);
|
||||
final ArgumentCaptor<TelephonyCallback> signalStrengthsCaptor =
|
||||
ArgumentCaptor.forClass(TelephonyCallback.class);
|
||||
doNothing().when(telephonyManager)
|
||||
.registerTelephonyCallback(any(), signalStrengthsCaptor.capture());
|
||||
final ArgumentCaptor<NetworkCallback> callbackCaptor =
|
||||
ArgumentCaptor.forClass(NetworkCallback.class);
|
||||
doNothing().when(mConnManager).registerNetworkCallback(any(), callbackCaptor.capture());
|
||||
final Network net = mock(Network.class);
|
||||
final NetworkCapabilities caps = createCapabilitiesBuilder()
|
||||
.addTransportType(TRANSPORT_CELLULAR)
|
||||
.addTransportType(TRANSPORT_VPN)
|
||||
.addCapability(NET_CAPABILITY_NOT_CONGESTED)
|
||||
.setSubscriptionIds(Set.of(7357))
|
||||
.build();
|
||||
final JobInfo.Builder baseJobBuilder = createJob()
|
||||
.setEstimatedNetworkBytes(DataUnit.MEBIBYTES.toBytes(1),
|
||||
DataUnit.MEBIBYTES.toBytes(1))
|
||||
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY);
|
||||
final JobStatus jobExp = createJobStatus(baseJobBuilder.setExpedited(true));
|
||||
final JobStatus jobHigh = createJobStatus(
|
||||
baseJobBuilder.setExpedited(false).setPriority(JobInfo.PRIORITY_HIGH));
|
||||
final JobStatus jobDefEarly = createJobStatus(
|
||||
baseJobBuilder.setExpedited(false).setPriority(JobInfo.PRIORITY_DEFAULT),
|
||||
now - 1000, now + 100_000);
|
||||
final JobStatus jobDefLate = createJobStatus(
|
||||
baseJobBuilder.setExpedited(false).setPriority(JobInfo.PRIORITY_DEFAULT),
|
||||
now - 100_000, now + 1000);
|
||||
final JobStatus jobLow = createJobStatus(
|
||||
baseJobBuilder.setExpedited(false).setPriority(JobInfo.PRIORITY_LOW));
|
||||
final JobStatus jobMin = createJobStatus(
|
||||
baseJobBuilder.setExpedited(false).setPriority(JobInfo.PRIORITY_MIN));
|
||||
final JobStatus jobMinRunner = createJobStatus(
|
||||
baseJobBuilder.setExpedited(false).setPriority(JobInfo.PRIORITY_MIN));
|
||||
|
||||
final ConnectivityController controller = new ConnectivityController(mService);
|
||||
|
||||
final NetworkCallback generalCallback = callbackCaptor.getValue();
|
||||
|
||||
when(mService.getMaxJobExecutionTimeMs(any())).thenReturn(10 * 60_000L);
|
||||
|
||||
when(mService.isBatteryCharging()).thenReturn(false);
|
||||
when(mService.isBatteryNotLow()).thenReturn(false);
|
||||
answerNetwork(generalCallback, null, null, net, caps);
|
||||
|
||||
final TelephonyCallback.SignalStrengthsListener signalStrengthsListener =
|
||||
(TelephonyCallback.SignalStrengthsListener) signalStrengthsCaptor.getValue();
|
||||
|
||||
controller.maybeStartTrackingJobLocked(jobMinRunner, null);
|
||||
controller.prepareForExecutionLocked(jobMinRunner);
|
||||
|
||||
final SignalStrength signalStrength = mock(SignalStrength.class);
|
||||
|
||||
when(signalStrength.getLevel()).thenReturn(
|
||||
CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN);
|
||||
signalStrengthsListener.onSignalStrengthsChanged(signalStrength);
|
||||
|
||||
// We don't restrict data via VPN over cellular.
|
||||
assertTrue(controller.isSatisfied(jobExp, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobHigh, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobDefEarly, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobDefLate, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobLow, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobMin, net, caps, mConstants));
|
||||
assertTrue(controller.isSatisfied(jobMinRunner, net, caps, mConstants));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRelaxed() throws Exception {
|
||||
final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
|
||||
|
||||
Reference in New Issue
Block a user