Merge "Adjust execution limits for new job types."
This commit is contained in:
@@ -266,6 +266,8 @@ public class JobSchedulerService extends com.android.server.SystemService
|
||||
private final List<RestrictingController> mRestrictiveControllers;
|
||||
/** Need direct access to this for testing. */
|
||||
private final StorageController mStorageController;
|
||||
/** Needed to get estimated transfer time. */
|
||||
private final ConnectivityController mConnectivityController;
|
||||
/** Need directly for sending uid state changes */
|
||||
private final DeviceIdleJobsController mDeviceIdleJobsController;
|
||||
/** Needed to get next estimated launch time. */
|
||||
@@ -464,6 +466,13 @@ public class JobSchedulerService extends com.android.server.SystemService
|
||||
case Constants.KEY_RUNTIME_MIN_GUARANTEE_MS:
|
||||
case Constants.KEY_RUNTIME_MIN_EJ_GUARANTEE_MS:
|
||||
case Constants.KEY_RUNTIME_MIN_HIGH_PRIORITY_GUARANTEE_MS:
|
||||
case Constants.KEY_RUNTIME_MIN_DATA_TRANSFER_GUARANTEE_MS:
|
||||
case Constants.KEY_RUNTIME_DATA_TRANSFER_LIMIT_MS:
|
||||
case Constants.KEY_RUNTIME_MIN_USER_INITIATED_GUARANTEE_MS:
|
||||
case Constants.KEY_RUNTIME_USER_INITIATED_LIMIT_MS:
|
||||
case Constants.KEY_RUNTIME_MIN_USER_INITIATED_DATA_TRANSFER_GUARANTEE_BUFFER_FACTOR:
|
||||
case Constants.KEY_RUNTIME_MIN_USER_INITIATED_DATA_TRANSFER_GUARANTEE_MS:
|
||||
case Constants.KEY_RUNTIME_USER_INITIATED_DATA_TRANSFER_LIMIT_MS:
|
||||
if (!runtimeUpdated) {
|
||||
mConstants.updateRuntimeConstantsLocked();
|
||||
runtimeUpdated = true;
|
||||
@@ -555,6 +564,21 @@ public class JobSchedulerService extends com.android.server.SystemService
|
||||
private static final String KEY_RUNTIME_MIN_EJ_GUARANTEE_MS = "runtime_min_ej_guarantee_ms";
|
||||
private static final String KEY_RUNTIME_MIN_HIGH_PRIORITY_GUARANTEE_MS =
|
||||
"runtime_min_high_priority_guarantee_ms";
|
||||
private static final String KEY_RUNTIME_MIN_DATA_TRANSFER_GUARANTEE_MS =
|
||||
"runtime_min_data_transfer_guarantee_ms";
|
||||
private static final String KEY_RUNTIME_DATA_TRANSFER_LIMIT_MS =
|
||||
"runtime_data_transfer_limit_ms";
|
||||
private static final String KEY_RUNTIME_MIN_USER_INITIATED_GUARANTEE_MS =
|
||||
"runtime_min_user_initiated_guarantee_ms";
|
||||
private static final String KEY_RUNTIME_USER_INITIATED_LIMIT_MS =
|
||||
"runtime_user_initiated_limit_ms";
|
||||
private static final String
|
||||
KEY_RUNTIME_MIN_USER_INITIATED_DATA_TRANSFER_GUARANTEE_BUFFER_FACTOR =
|
||||
"runtime_min_user_initiated_data_transfer_guarantee_buffer_factor";
|
||||
private static final String KEY_RUNTIME_MIN_USER_INITIATED_DATA_TRANSFER_GUARANTEE_MS =
|
||||
"runtime_min_user_initiated_data_transfer_guarantee_ms";
|
||||
private static final String KEY_RUNTIME_USER_INITIATED_DATA_TRANSFER_LIMIT_MS =
|
||||
"runtime_user_initiated_data_transfer_limit_ms";
|
||||
|
||||
private static final String KEY_PERSIST_IN_SPLIT_FILES = "persist_in_split_files";
|
||||
|
||||
@@ -584,6 +608,20 @@ public class JobSchedulerService extends com.android.server.SystemService
|
||||
public static final long DEFAULT_RUNTIME_MIN_EJ_GUARANTEE_MS = 3 * MINUTE_IN_MILLIS;
|
||||
@VisibleForTesting
|
||||
static final long DEFAULT_RUNTIME_MIN_HIGH_PRIORITY_GUARANTEE_MS = 5 * MINUTE_IN_MILLIS;
|
||||
public static final long DEFAULT_RUNTIME_MIN_DATA_TRANSFER_GUARANTEE_MS =
|
||||
DEFAULT_RUNTIME_MIN_GUARANTEE_MS;
|
||||
public static final long DEFAULT_RUNTIME_DATA_TRANSFER_LIMIT_MS =
|
||||
DEFAULT_RUNTIME_FREE_QUOTA_MAX_LIMIT_MS;
|
||||
public static final long DEFAULT_RUNTIME_MIN_USER_INITIATED_GUARANTEE_MS =
|
||||
Math.max(10 * MINUTE_IN_MILLIS, DEFAULT_RUNTIME_MIN_GUARANTEE_MS);
|
||||
public static final long DEFAULT_RUNTIME_USER_INITIATED_LIMIT_MS =
|
||||
Math.max(60 * MINUTE_IN_MILLIS, DEFAULT_RUNTIME_FREE_QUOTA_MAX_LIMIT_MS);
|
||||
public static final float
|
||||
DEFAULT_RUNTIME_MIN_USER_INITIATED_DATA_TRANSFER_GUARANTEE_BUFFER_FACTOR = 1.35f;
|
||||
public static final long DEFAULT_RUNTIME_MIN_USER_INITIATED_DATA_TRANSFER_GUARANTEE_MS =
|
||||
Math.max(10 * MINUTE_IN_MILLIS, DEFAULT_RUNTIME_MIN_USER_INITIATED_GUARANTEE_MS);
|
||||
public static final long DEFAULT_RUNTIME_USER_INITIATED_DATA_TRANSFER_LIMIT_MS =
|
||||
Math.max(Long.MAX_VALUE, DEFAULT_RUNTIME_USER_INITIATED_LIMIT_MS);
|
||||
static final boolean DEFAULT_PERSIST_IN_SPLIT_FILES = true;
|
||||
private static final boolean DEFAULT_USE_TARE_POLICY = false;
|
||||
|
||||
@@ -699,6 +737,49 @@ public class JobSchedulerService extends com.android.server.SystemService
|
||||
public long RUNTIME_MIN_HIGH_PRIORITY_GUARANTEE_MS =
|
||||
DEFAULT_RUNTIME_MIN_HIGH_PRIORITY_GUARANTEE_MS;
|
||||
|
||||
/**
|
||||
* The minimum amount of time we try to guarantee normal data transfer jobs will run for.
|
||||
*/
|
||||
public long RUNTIME_MIN_DATA_TRANSFER_GUARANTEE_MS =
|
||||
DEFAULT_RUNTIME_MIN_DATA_TRANSFER_GUARANTEE_MS;
|
||||
|
||||
/**
|
||||
* The maximum amount of time we will let a normal data transfer job run for. This will only
|
||||
* apply if there are no other limits that apply to the specific data transfer job.
|
||||
*/
|
||||
public long RUNTIME_DATA_TRANSFER_LIMIT_MS = DEFAULT_RUNTIME_DATA_TRANSFER_LIMIT_MS;
|
||||
|
||||
/**
|
||||
* The minimum amount of time we try to guarantee normal user-initiated jobs will run for.
|
||||
*/
|
||||
public long RUNTIME_MIN_USER_INITIATED_GUARANTEE_MS =
|
||||
DEFAULT_RUNTIME_MIN_USER_INITIATED_GUARANTEE_MS;
|
||||
|
||||
/**
|
||||
* The maximum amount of time we will let a user-initiated job run for. This will only
|
||||
* apply if there are no other limits that apply to the specific user-initiated job.
|
||||
*/
|
||||
public long RUNTIME_USER_INITIATED_LIMIT_MS = DEFAULT_RUNTIME_USER_INITIATED_LIMIT_MS;
|
||||
|
||||
/**
|
||||
* A factor to apply to estimated transfer durations for user-initiated data transfer jobs
|
||||
* so that we give some extra time for unexpected situations. This will be at least 1 and
|
||||
* so can just be multiplied with the original value to get the final value.
|
||||
*/
|
||||
public float RUNTIME_MIN_USER_INITIATED_DATA_TRANSFER_GUARANTEE_BUFFER_FACTOR =
|
||||
DEFAULT_RUNTIME_MIN_USER_INITIATED_DATA_TRANSFER_GUARANTEE_BUFFER_FACTOR;
|
||||
|
||||
/**
|
||||
* The minimum amount of time we try to guarantee user-initiated data transfer jobs
|
||||
* will run for.
|
||||
*/
|
||||
public long RUNTIME_MIN_USER_INITIATED_DATA_TRANSFER_GUARANTEE_MS =
|
||||
DEFAULT_RUNTIME_MIN_USER_INITIATED_DATA_TRANSFER_GUARANTEE_MS;
|
||||
|
||||
/** The maximum amount of time we will let a user-initiated data transfer job run for. */
|
||||
public long RUNTIME_USER_INITIATED_DATA_TRANSFER_LIMIT_MS =
|
||||
DEFAULT_RUNTIME_USER_INITIATED_DATA_TRANSFER_LIMIT_MS;
|
||||
|
||||
/**
|
||||
* Whether to persist jobs in split files (by UID). If false, all persisted jobs will be
|
||||
* saved in a single file.
|
||||
@@ -801,7 +882,14 @@ public class JobSchedulerService extends com.android.server.SystemService
|
||||
DeviceConfig.NAMESPACE_JOB_SCHEDULER,
|
||||
KEY_RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
|
||||
KEY_RUNTIME_MIN_GUARANTEE_MS, KEY_RUNTIME_MIN_EJ_GUARANTEE_MS,
|
||||
KEY_RUNTIME_MIN_HIGH_PRIORITY_GUARANTEE_MS);
|
||||
KEY_RUNTIME_MIN_HIGH_PRIORITY_GUARANTEE_MS,
|
||||
KEY_RUNTIME_MIN_USER_INITIATED_DATA_TRANSFER_GUARANTEE_BUFFER_FACTOR,
|
||||
KEY_RUNTIME_MIN_DATA_TRANSFER_GUARANTEE_MS,
|
||||
KEY_RUNTIME_DATA_TRANSFER_LIMIT_MS,
|
||||
KEY_RUNTIME_MIN_USER_INITIATED_GUARANTEE_MS,
|
||||
KEY_RUNTIME_USER_INITIATED_LIMIT_MS,
|
||||
KEY_RUNTIME_MIN_USER_INITIATED_DATA_TRANSFER_GUARANTEE_MS,
|
||||
KEY_RUNTIME_USER_INITIATED_DATA_TRANSFER_LIMIT_MS);
|
||||
|
||||
// Make sure min runtime for regular jobs is at least 10 minutes.
|
||||
RUNTIME_MIN_GUARANTEE_MS = Math.max(10 * MINUTE_IN_MILLIS,
|
||||
@@ -819,6 +907,49 @@ public class JobSchedulerService extends com.android.server.SystemService
|
||||
RUNTIME_FREE_QUOTA_MAX_LIMIT_MS = Math.max(RUNTIME_MIN_GUARANTEE_MS,
|
||||
properties.getLong(KEY_RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
|
||||
DEFAULT_RUNTIME_FREE_QUOTA_MAX_LIMIT_MS));
|
||||
// Make sure min runtime is at least as long as regular jobs.
|
||||
RUNTIME_MIN_DATA_TRANSFER_GUARANTEE_MS = Math.max(RUNTIME_MIN_GUARANTEE_MS,
|
||||
properties.getLong(
|
||||
KEY_RUNTIME_MIN_DATA_TRANSFER_GUARANTEE_MS,
|
||||
DEFAULT_RUNTIME_MIN_DATA_TRANSFER_GUARANTEE_MS));
|
||||
// Max limit should be at least the min guarantee AND the free quota.
|
||||
RUNTIME_DATA_TRANSFER_LIMIT_MS = Math.max(RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
|
||||
Math.max(RUNTIME_MIN_DATA_TRANSFER_GUARANTEE_MS,
|
||||
properties.getLong(
|
||||
KEY_RUNTIME_DATA_TRANSFER_LIMIT_MS,
|
||||
DEFAULT_RUNTIME_DATA_TRANSFER_LIMIT_MS)));
|
||||
// Make sure min runtime is at least as long as regular jobs.
|
||||
RUNTIME_MIN_USER_INITIATED_GUARANTEE_MS = Math.max(RUNTIME_MIN_GUARANTEE_MS,
|
||||
properties.getLong(
|
||||
KEY_RUNTIME_MIN_USER_INITIATED_GUARANTEE_MS,
|
||||
DEFAULT_RUNTIME_MIN_USER_INITIATED_GUARANTEE_MS));
|
||||
// Max limit should be at least the min guarantee AND the free quota.
|
||||
RUNTIME_USER_INITIATED_LIMIT_MS = Math.max(RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
|
||||
Math.max(RUNTIME_MIN_USER_INITIATED_GUARANTEE_MS,
|
||||
properties.getLong(
|
||||
KEY_RUNTIME_USER_INITIATED_LIMIT_MS,
|
||||
DEFAULT_RUNTIME_USER_INITIATED_LIMIT_MS)));
|
||||
// The buffer factor should be at least 1 (so we don't decrease the time).
|
||||
RUNTIME_MIN_USER_INITIATED_DATA_TRANSFER_GUARANTEE_BUFFER_FACTOR = Math.max(1,
|
||||
properties.getFloat(
|
||||
KEY_RUNTIME_MIN_USER_INITIATED_DATA_TRANSFER_GUARANTEE_BUFFER_FACTOR,
|
||||
DEFAULT_RUNTIME_MIN_USER_INITIATED_DATA_TRANSFER_GUARANTEE_BUFFER_FACTOR
|
||||
));
|
||||
// Make sure min runtime is at least as long as other user-initiated jobs.
|
||||
RUNTIME_MIN_USER_INITIATED_DATA_TRANSFER_GUARANTEE_MS = Math.max(
|
||||
RUNTIME_MIN_USER_INITIATED_GUARANTEE_MS,
|
||||
properties.getLong(
|
||||
KEY_RUNTIME_MIN_USER_INITIATED_DATA_TRANSFER_GUARANTEE_MS,
|
||||
DEFAULT_RUNTIME_MIN_USER_INITIATED_DATA_TRANSFER_GUARANTEE_MS));
|
||||
// Data transfer requires RUN_LONG_JOBS permission, so the upper limit will be higher
|
||||
// than other jobs.
|
||||
// Max limit should be the min guarantee and the max of other user-initiated jobs.
|
||||
RUNTIME_USER_INITIATED_DATA_TRANSFER_LIMIT_MS = Math.max(
|
||||
RUNTIME_MIN_USER_INITIATED_DATA_TRANSFER_GUARANTEE_MS,
|
||||
Math.max(RUNTIME_USER_INITIATED_LIMIT_MS,
|
||||
properties.getLong(
|
||||
KEY_RUNTIME_USER_INITIATED_DATA_TRANSFER_LIMIT_MS,
|
||||
DEFAULT_RUNTIME_USER_INITIATED_DATA_TRANSFER_LIMIT_MS)));
|
||||
}
|
||||
|
||||
private boolean updateTareSettingsLocked(boolean isTareEnabled) {
|
||||
@@ -867,6 +998,20 @@ public class JobSchedulerService extends com.android.server.SystemService
|
||||
RUNTIME_MIN_HIGH_PRIORITY_GUARANTEE_MS).println();
|
||||
pw.print(KEY_RUNTIME_FREE_QUOTA_MAX_LIMIT_MS, RUNTIME_FREE_QUOTA_MAX_LIMIT_MS)
|
||||
.println();
|
||||
pw.print(KEY_RUNTIME_MIN_DATA_TRANSFER_GUARANTEE_MS,
|
||||
RUNTIME_MIN_DATA_TRANSFER_GUARANTEE_MS).println();
|
||||
pw.print(KEY_RUNTIME_DATA_TRANSFER_LIMIT_MS,
|
||||
RUNTIME_DATA_TRANSFER_LIMIT_MS).println();
|
||||
pw.print(KEY_RUNTIME_MIN_USER_INITIATED_GUARANTEE_MS,
|
||||
RUNTIME_MIN_USER_INITIATED_GUARANTEE_MS).println();
|
||||
pw.print(KEY_RUNTIME_USER_INITIATED_LIMIT_MS,
|
||||
RUNTIME_USER_INITIATED_LIMIT_MS).println();
|
||||
pw.print(KEY_RUNTIME_MIN_USER_INITIATED_DATA_TRANSFER_GUARANTEE_BUFFER_FACTOR,
|
||||
RUNTIME_MIN_USER_INITIATED_DATA_TRANSFER_GUARANTEE_BUFFER_FACTOR).println();
|
||||
pw.print(KEY_RUNTIME_MIN_USER_INITIATED_DATA_TRANSFER_GUARANTEE_MS,
|
||||
RUNTIME_MIN_USER_INITIATED_DATA_TRANSFER_GUARANTEE_MS).println();
|
||||
pw.print(KEY_RUNTIME_USER_INITIATED_DATA_TRANSFER_LIMIT_MS,
|
||||
RUNTIME_USER_INITIATED_DATA_TRANSFER_LIMIT_MS).println();
|
||||
|
||||
pw.print(KEY_PERSIST_IN_SPLIT_FILES, PERSIST_IN_SPLIT_FILES).println();
|
||||
|
||||
@@ -1858,9 +2003,9 @@ public class JobSchedulerService extends com.android.server.SystemService
|
||||
final FlexibilityController flexibilityController =
|
||||
new FlexibilityController(this, mPrefetchController);
|
||||
mControllers.add(flexibilityController);
|
||||
final ConnectivityController connectivityController =
|
||||
mConnectivityController =
|
||||
new ConnectivityController(this, flexibilityController);
|
||||
mControllers.add(connectivityController);
|
||||
mControllers.add(mConnectivityController);
|
||||
mControllers.add(new TimeController(this));
|
||||
final IdleController idleController = new IdleController(this, flexibilityController);
|
||||
mControllers.add(idleController);
|
||||
@@ -1876,16 +2021,16 @@ public class JobSchedulerService extends com.android.server.SystemService
|
||||
mDeviceIdleJobsController = new DeviceIdleJobsController(this);
|
||||
mControllers.add(mDeviceIdleJobsController);
|
||||
mQuotaController =
|
||||
new QuotaController(this, backgroundJobsController, connectivityController);
|
||||
new QuotaController(this, backgroundJobsController, mConnectivityController);
|
||||
mControllers.add(mQuotaController);
|
||||
mControllers.add(new ComponentController(this));
|
||||
mTareController =
|
||||
new TareController(this, backgroundJobsController, connectivityController);
|
||||
new TareController(this, backgroundJobsController, mConnectivityController);
|
||||
mControllers.add(mTareController);
|
||||
|
||||
mRestrictiveControllers = new ArrayList<>();
|
||||
mRestrictiveControllers.add(batteryController);
|
||||
mRestrictiveControllers.add(connectivityController);
|
||||
mRestrictiveControllers.add(mConnectivityController);
|
||||
mRestrictiveControllers.add(idleController);
|
||||
|
||||
// Create restrictions
|
||||
@@ -3028,7 +3173,30 @@ public class JobSchedulerService extends com.android.server.SystemService
|
||||
/** Returns the minimum amount of time we should let this job run before timing out. */
|
||||
public long getMinJobExecutionGuaranteeMs(JobStatus job) {
|
||||
synchronized (mLock) {
|
||||
if (job.shouldTreatAsExpeditedJob()) {
|
||||
final boolean shouldTreatAsDataTransfer = job.getJob().isDataTransfer()
|
||||
&& checkRunLongJobsPermission(job.getSourceUid(), job.getSourcePackageName());
|
||||
if (job.shouldTreatAsUserInitiated()) {
|
||||
if (shouldTreatAsDataTransfer) {
|
||||
final long estimatedTransferTimeMs =
|
||||
mConnectivityController.getEstimatedTransferTimeMs(job);
|
||||
if (estimatedTransferTimeMs == ConnectivityController.UNKNOWN_TIME) {
|
||||
return mConstants.RUNTIME_MIN_USER_INITIATED_DATA_TRANSFER_GUARANTEE_MS;
|
||||
}
|
||||
// Try to give the job at least as much time as we think the transfer will take,
|
||||
// but cap it at the maximum limit
|
||||
final long factoredTransferTimeMs = (long) (estimatedTransferTimeMs
|
||||
* mConstants
|
||||
.RUNTIME_MIN_USER_INITIATED_DATA_TRANSFER_GUARANTEE_BUFFER_FACTOR);
|
||||
return Math.min(mConstants.RUNTIME_USER_INITIATED_DATA_TRANSFER_LIMIT_MS,
|
||||
Math.max(factoredTransferTimeMs,
|
||||
mConstants.RUNTIME_MIN_USER_INITIATED_DATA_TRANSFER_GUARANTEE_MS
|
||||
));
|
||||
}
|
||||
return mConstants.RUNTIME_MIN_USER_INITIATED_GUARANTEE_MS;
|
||||
} else if (shouldTreatAsDataTransfer) {
|
||||
// For now, don't increase a bg data transfer's minimum guarantee.
|
||||
return mConstants.RUNTIME_MIN_DATA_TRANSFER_GUARANTEE_MS;
|
||||
} else if (job.shouldTreatAsExpeditedJob()) {
|
||||
// Don't guarantee RESTRICTED jobs more than 5 minutes.
|
||||
return job.getEffectiveStandbyBucket() != RESTRICTED_INDEX
|
||||
? mConstants.RUNTIME_MIN_EJ_GUARANTEE_MS
|
||||
@@ -3044,6 +3212,16 @@ public class JobSchedulerService extends com.android.server.SystemService
|
||||
/** Returns the maximum amount of time this job could run for. */
|
||||
public long getMaxJobExecutionTimeMs(JobStatus job) {
|
||||
synchronized (mLock) {
|
||||
final boolean shouldTreatAsDataTransfer = job.getJob().isDataTransfer()
|
||||
&& checkRunLongJobsPermission(job.getSourceUid(), job.getSourcePackageName());
|
||||
if (job.shouldTreatAsUserInitiated()) {
|
||||
if (shouldTreatAsDataTransfer) {
|
||||
return mConstants.RUNTIME_USER_INITIATED_DATA_TRANSFER_LIMIT_MS;
|
||||
}
|
||||
return mConstants.RUNTIME_USER_INITIATED_LIMIT_MS;
|
||||
} else if (shouldTreatAsDataTransfer) {
|
||||
return mConstants.RUNTIME_DATA_TRANSFER_LIMIT_MS;
|
||||
}
|
||||
return Math.min(mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
|
||||
mConstants.USE_TARE_POLICY
|
||||
? mTareController.getMaxJobExecutionTimeMsLocked(job)
|
||||
@@ -3703,13 +3881,6 @@ public class JobSchedulerService extends com.android.server.SystemService
|
||||
return checkRunLongJobsPermission(uid, packageName);
|
||||
}
|
||||
|
||||
private boolean checkRunLongJobsPermission(int packageUid, String packageName) {
|
||||
// Returns true if both the appop and permission are granted.
|
||||
return PermissionChecker.checkPermissionForPreflight(getContext(),
|
||||
android.Manifest.permission.RUN_LONG_JOBS, PermissionChecker.PID_UNKNOWN,
|
||||
packageUid, packageName) == PermissionChecker.PERMISSION_GRANTED;
|
||||
}
|
||||
|
||||
/**
|
||||
* "dumpsys" infrastructure
|
||||
*/
|
||||
@@ -3985,13 +4156,27 @@ public class JobSchedulerService extends com.android.server.SystemService
|
||||
}
|
||||
}
|
||||
|
||||
private boolean checkRunLongJobsPermission(int packageUid, String packageName) {
|
||||
// Returns true if both the appop and permission are granted.
|
||||
return PermissionChecker.checkPermissionForPreflight(getTestableContext(),
|
||||
android.Manifest.permission.RUN_LONG_JOBS, PermissionChecker.PID_UNKNOWN,
|
||||
packageUid, packageName) == PermissionChecker.PERMISSION_GRANTED;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
protected ConnectivityController getConnectivityController() {
|
||||
return mConnectivityController;
|
||||
}
|
||||
|
||||
// Shell command infrastructure
|
||||
int getJobState(PrintWriter pw, String pkgName, int userId, int jobId) {
|
||||
try {
|
||||
final int uid = AppGlobals.getPackageManager().getPackageUid(pkgName, 0,
|
||||
userId != UserHandle.USER_ALL ? userId : UserHandle.USER_SYSTEM);
|
||||
if (uid < 0) {
|
||||
pw.print("unknown("); pw.print(pkgName); pw.println(")");
|
||||
pw.print("unknown(");
|
||||
pw.print(pkgName);
|
||||
pw.println(")");
|
||||
return JobSchedulerShellCommand.CMD_ERR_NO_PACKAGE;
|
||||
}
|
||||
|
||||
|
||||
@@ -42,7 +42,6 @@ import android.telephony.TelephonyManager;
|
||||
import android.text.format.DateUtils;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.ArraySet;
|
||||
import android.util.DataUnit;
|
||||
import android.util.IndentingPrintWriter;
|
||||
import android.util.Log;
|
||||
import android.util.Pools;
|
||||
@@ -82,6 +81,8 @@ public final class ConnectivityController extends RestrictingController implemen
|
||||
private static final boolean DEBUG = JobSchedulerService.DEBUG
|
||||
|| Log.isLoggable(TAG, Log.DEBUG);
|
||||
|
||||
public static final long UNKNOWN_TIME = -1L;
|
||||
|
||||
// The networking stack has a hard limit so we can't make this configurable.
|
||||
private static final int MAX_NETWORK_CALLBACKS = 125;
|
||||
/**
|
||||
@@ -570,9 +571,8 @@ public final class ConnectivityController extends RestrictingController implemen
|
||||
// If we don't know the bandwidth, all we can do is hope the job finishes the minimum
|
||||
// chunk in time.
|
||||
if (bandwidthDown > 0) {
|
||||
// Divide by 8 to convert bits to bytes.
|
||||
final long estimatedMillis = ((minimumChunkBytes * DateUtils.SECOND_IN_MILLIS)
|
||||
/ (DataUnit.KIBIBYTES.toBytes(bandwidthDown) / 8));
|
||||
final long estimatedMillis =
|
||||
calculateTransferTimeMs(minimumChunkBytes, bandwidthDown);
|
||||
if (estimatedMillis > maxJobExecutionTimeMs) {
|
||||
// If we'd never finish the minimum chunk before the timeout, we'd be insane!
|
||||
Slog.w(TAG, "Minimum chunk " + minimumChunkBytes + " bytes over "
|
||||
@@ -585,9 +585,8 @@ public final class ConnectivityController extends RestrictingController implemen
|
||||
final long bandwidthUp = capabilities.getLinkUpstreamBandwidthKbps();
|
||||
// If we don't know the bandwidth, all we can do is hope the job finishes in time.
|
||||
if (bandwidthUp > 0) {
|
||||
// Divide by 8 to convert bits to bytes.
|
||||
final long estimatedMillis = ((minimumChunkBytes * DateUtils.SECOND_IN_MILLIS)
|
||||
/ (DataUnit.KIBIBYTES.toBytes(bandwidthUp) / 8));
|
||||
final long estimatedMillis =
|
||||
calculateTransferTimeMs(minimumChunkBytes, bandwidthUp);
|
||||
if (estimatedMillis > maxJobExecutionTimeMs) {
|
||||
// If we'd never finish the minimum chunk before the timeout, we'd be insane!
|
||||
Slog.w(TAG, "Minimum chunk " + minimumChunkBytes + " bytes over " + bandwidthUp
|
||||
@@ -615,9 +614,7 @@ public final class ConnectivityController extends RestrictingController implemen
|
||||
final long bandwidth = capabilities.getLinkDownstreamBandwidthKbps();
|
||||
// If we don't know the bandwidth, all we can do is hope the job finishes in time.
|
||||
if (bandwidth > 0) {
|
||||
// Divide by 8 to convert bits to bytes.
|
||||
final long estimatedMillis = ((downloadBytes * DateUtils.SECOND_IN_MILLIS)
|
||||
/ (DataUnit.KIBIBYTES.toBytes(bandwidth) / 8));
|
||||
final long estimatedMillis = calculateTransferTimeMs(downloadBytes, bandwidth);
|
||||
if (estimatedMillis > maxJobExecutionTimeMs) {
|
||||
// If we'd never finish before the timeout, we'd be insane!
|
||||
Slog.w(TAG, "Estimated " + downloadBytes + " download bytes over " + bandwidth
|
||||
@@ -633,9 +630,7 @@ public final class ConnectivityController extends RestrictingController implemen
|
||||
final long bandwidth = capabilities.getLinkUpstreamBandwidthKbps();
|
||||
// If we don't know the bandwidth, all we can do is hope the job finishes in time.
|
||||
if (bandwidth > 0) {
|
||||
// Divide by 8 to convert bits to bytes.
|
||||
final long estimatedMillis = ((uploadBytes * DateUtils.SECOND_IN_MILLIS)
|
||||
/ (DataUnit.KIBIBYTES.toBytes(bandwidth) / 8));
|
||||
final long estimatedMillis = calculateTransferTimeMs(uploadBytes, bandwidth);
|
||||
if (estimatedMillis > maxJobExecutionTimeMs) {
|
||||
// If we'd never finish before the timeout, we'd be insane!
|
||||
Slog.w(TAG, "Estimated " + uploadBytes + " upload bytes over " + bandwidth
|
||||
@@ -649,6 +644,48 @@ public final class ConnectivityController extends RestrictingController implemen
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the estimated amount of time this job will be transferring data,
|
||||
* based on the current network speed.
|
||||
*/
|
||||
public long getEstimatedTransferTimeMs(JobStatus jobStatus) {
|
||||
final long downloadBytes = jobStatus.getEstimatedNetworkDownloadBytes();
|
||||
final long uploadBytes = jobStatus.getEstimatedNetworkUploadBytes();
|
||||
if (downloadBytes == JobInfo.NETWORK_BYTES_UNKNOWN
|
||||
&& uploadBytes == JobInfo.NETWORK_BYTES_UNKNOWN) {
|
||||
return UNKNOWN_TIME;
|
||||
}
|
||||
if (jobStatus.network == null) {
|
||||
// This job doesn't have a network assigned.
|
||||
return UNKNOWN_TIME;
|
||||
}
|
||||
NetworkCapabilities capabilities = getNetworkCapabilities(jobStatus.network);
|
||||
if (capabilities == null) {
|
||||
return UNKNOWN_TIME;
|
||||
}
|
||||
final long estimatedDownloadTimeMs = calculateTransferTimeMs(downloadBytes,
|
||||
capabilities.getLinkDownstreamBandwidthKbps());
|
||||
final long estimatedUploadTimeMs = calculateTransferTimeMs(uploadBytes,
|
||||
capabilities.getLinkUpstreamBandwidthKbps());
|
||||
if (estimatedDownloadTimeMs == UNKNOWN_TIME) {
|
||||
return estimatedUploadTimeMs;
|
||||
} else if (estimatedUploadTimeMs == UNKNOWN_TIME) {
|
||||
return estimatedDownloadTimeMs;
|
||||
}
|
||||
return estimatedDownloadTimeMs + estimatedUploadTimeMs;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
static long calculateTransferTimeMs(long transferBytes, long bandwidthKbps) {
|
||||
if (transferBytes == JobInfo.NETWORK_BYTES_UNKNOWN || bandwidthKbps <= 0) {
|
||||
return UNKNOWN_TIME;
|
||||
}
|
||||
return (transferBytes * DateUtils.SECOND_IN_MILLIS)
|
||||
// Multiply by 1000 to convert kilobits to bits.
|
||||
// Divide by 8 to convert bits to bytes.
|
||||
/ (bandwidthKbps * 1000 / 8);
|
||||
}
|
||||
|
||||
private static boolean isCongestionDelayed(JobStatus jobStatus, Network network,
|
||||
NetworkCapabilities capabilities, Constants constants) {
|
||||
// If network is congested, and job is less than 50% through the
|
||||
|
||||
@@ -1344,6 +1344,15 @@ public final class JobStatus {
|
||||
return mExpeditedQuotaApproved && mExpeditedTareApproved && isRequestedExpeditedJob();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the job was scheduled as a user-initiated job and it hasn't been downgraded
|
||||
* for any reason.
|
||||
*/
|
||||
public boolean shouldTreatAsUserInitiated() {
|
||||
// TODO(248386641): implement
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a summary that uniquely identifies the underlying job.
|
||||
*/
|
||||
|
||||
@@ -34,6 +34,8 @@ import static org.junit.Assert.fail;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyBoolean;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
@@ -46,6 +48,7 @@ import android.app.job.JobScheduler;
|
||||
import android.app.usage.UsageStatsManagerInternal;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.PermissionChecker;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManagerInternal;
|
||||
import android.content.res.Resources;
|
||||
@@ -63,6 +66,7 @@ import com.android.server.DeviceIdleInternal;
|
||||
import com.android.server.LocalServices;
|
||||
import com.android.server.PowerAllowlistInternal;
|
||||
import com.android.server.SystemServiceManager;
|
||||
import com.android.server.job.controllers.ConnectivityController;
|
||||
import com.android.server.job.controllers.JobStatus;
|
||||
import com.android.server.pm.UserManagerInternal;
|
||||
import com.android.server.usage.AppStandbyInternal;
|
||||
@@ -102,6 +106,7 @@ public class JobSchedulerServiceTest {
|
||||
.initMocks(this)
|
||||
.strictness(Strictness.LENIENT)
|
||||
.mockStatic(LocalServices.class)
|
||||
.mockStatic(PermissionChecker.class)
|
||||
.mockStatic(ServiceManager.class)
|
||||
.startMocking();
|
||||
|
||||
@@ -193,6 +198,15 @@ public class JobSchedulerServiceTest {
|
||||
jobInfoBuilder.build(), callingUid, "com.android.test", 0, testTag);
|
||||
}
|
||||
|
||||
private void grantRunLongJobsPermission(boolean grant) {
|
||||
final int permissionStatus = grant
|
||||
? PermissionChecker.PERMISSION_GRANTED : PermissionChecker.PERMISSION_HARD_DENIED;
|
||||
doReturn(permissionStatus)
|
||||
.when(() -> PermissionChecker.checkPermissionForPreflight(
|
||||
any(), eq(android.Manifest.permission.RUN_LONG_JOBS),
|
||||
anyInt(), anyInt(), anyString()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetMinJobExecutionGuaranteeMs() {
|
||||
JobStatus ejMax = createJobStatus("testGetMinJobExecutionGuaranteeMs",
|
||||
@@ -207,6 +221,15 @@ public class JobSchedulerServiceTest {
|
||||
createJobInfo(5).setPriority(JobInfo.PRIORITY_HIGH));
|
||||
JobStatus jobDef = createJobStatus("testGetMinJobExecutionGuaranteeMs",
|
||||
createJobInfo(6));
|
||||
JobStatus jobDT = createJobStatus("testGetMinJobExecutionGuaranteeMs",
|
||||
createJobInfo(7)
|
||||
.setDataTransfer(true).setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY));
|
||||
JobStatus jobUI = createJobStatus("testGetMinJobExecutionGuaranteeMs",
|
||||
createJobInfo(8)); // TODO(255371817): add setUserInitiated(true)
|
||||
JobStatus jobUIDT = createJobStatus("testGetMinJobExecutionGuaranteeMs",
|
||||
// TODO(255371817): add setUserInitiated(true)
|
||||
createJobInfo(9)
|
||||
.setDataTransfer(true).setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY));
|
||||
|
||||
spyOn(ejMax);
|
||||
spyOn(ejHigh);
|
||||
@@ -214,6 +237,9 @@ public class JobSchedulerServiceTest {
|
||||
spyOn(ejHighDowngraded);
|
||||
spyOn(jobHigh);
|
||||
spyOn(jobDef);
|
||||
spyOn(jobDT);
|
||||
spyOn(jobUI);
|
||||
spyOn(jobUIDT);
|
||||
|
||||
when(ejMax.shouldTreatAsExpeditedJob()).thenReturn(true);
|
||||
when(ejHigh.shouldTreatAsExpeditedJob()).thenReturn(true);
|
||||
@@ -221,6 +247,16 @@ public class JobSchedulerServiceTest {
|
||||
when(ejHighDowngraded.shouldTreatAsExpeditedJob()).thenReturn(false);
|
||||
when(jobHigh.shouldTreatAsExpeditedJob()).thenReturn(false);
|
||||
when(jobDef.shouldTreatAsExpeditedJob()).thenReturn(false);
|
||||
when(jobUI.shouldTreatAsUserInitiated()).thenReturn(true);
|
||||
when(jobUIDT.shouldTreatAsUserInitiated()).thenReturn(true);
|
||||
|
||||
ConnectivityController connectivityController = mService.getConnectivityController();
|
||||
spyOn(connectivityController);
|
||||
mService.mConstants.RUNTIME_MIN_DATA_TRANSFER_GUARANTEE_MS = 10 * MINUTE_IN_MILLIS;
|
||||
mService.mConstants.RUNTIME_DATA_TRANSFER_LIMIT_MS = 60 * MINUTE_IN_MILLIS;
|
||||
mService.mConstants.RUNTIME_MIN_USER_INITIATED_DATA_TRANSFER_GUARANTEE_BUFFER_FACTOR = 1.5f;
|
||||
mService.mConstants.RUNTIME_MIN_USER_INITIATED_DATA_TRANSFER_GUARANTEE_MS = HOUR_IN_MILLIS;
|
||||
mService.mConstants.RUNTIME_USER_INITIATED_DATA_TRANSFER_LIMIT_MS = 6 * HOUR_IN_MILLIS;
|
||||
|
||||
assertEquals(mService.mConstants.RUNTIME_MIN_EJ_GUARANTEE_MS,
|
||||
mService.getMinJobExecutionGuaranteeMs(ejMax));
|
||||
@@ -234,8 +270,81 @@ public class JobSchedulerServiceTest {
|
||||
mService.getMinJobExecutionGuaranteeMs(jobHigh));
|
||||
assertEquals(mService.mConstants.RUNTIME_MIN_GUARANTEE_MS,
|
||||
mService.getMinJobExecutionGuaranteeMs(jobDef));
|
||||
grantRunLongJobsPermission(false); // Without permission
|
||||
assertEquals(mService.mConstants.RUNTIME_MIN_GUARANTEE_MS,
|
||||
mService.getMinJobExecutionGuaranteeMs(jobDT));
|
||||
grantRunLongJobsPermission(true); // With permission
|
||||
doReturn(ConnectivityController.UNKNOWN_TIME)
|
||||
.when(connectivityController).getEstimatedTransferTimeMs(any());
|
||||
assertEquals(mService.mConstants.RUNTIME_MIN_DATA_TRANSFER_GUARANTEE_MS,
|
||||
mService.getMinJobExecutionGuaranteeMs(jobDT));
|
||||
doReturn(mService.mConstants.RUNTIME_MIN_DATA_TRANSFER_GUARANTEE_MS / 2)
|
||||
.when(connectivityController).getEstimatedTransferTimeMs(any());
|
||||
assertEquals(mService.mConstants.RUNTIME_MIN_DATA_TRANSFER_GUARANTEE_MS,
|
||||
mService.getMinJobExecutionGuaranteeMs(jobDT));
|
||||
doReturn(mService.mConstants.RUNTIME_MIN_DATA_TRANSFER_GUARANTEE_MS * 2)
|
||||
.when(connectivityController).getEstimatedTransferTimeMs(any());
|
||||
assertEquals(mService.mConstants.RUNTIME_MIN_DATA_TRANSFER_GUARANTEE_MS,
|
||||
mService.getMinJobExecutionGuaranteeMs(jobDT));
|
||||
doReturn(mService.mConstants.RUNTIME_DATA_TRANSFER_LIMIT_MS * 2)
|
||||
.when(connectivityController).getEstimatedTransferTimeMs(any());
|
||||
assertEquals(mService.mConstants.RUNTIME_MIN_DATA_TRANSFER_GUARANTEE_MS,
|
||||
mService.getMinJobExecutionGuaranteeMs(jobDT));
|
||||
// UserInitiated
|
||||
assertEquals(mService.mConstants.RUNTIME_MIN_USER_INITIATED_GUARANTEE_MS,
|
||||
mService.getMinJobExecutionGuaranteeMs(jobUI));
|
||||
grantRunLongJobsPermission(false);
|
||||
assertEquals(mService.mConstants.RUNTIME_MIN_USER_INITIATED_GUARANTEE_MS,
|
||||
mService.getMinJobExecutionGuaranteeMs(jobUIDT));
|
||||
grantRunLongJobsPermission(true); // With permission
|
||||
doReturn(ConnectivityController.UNKNOWN_TIME)
|
||||
.when(connectivityController).getEstimatedTransferTimeMs(any());
|
||||
assertEquals(mService.mConstants.RUNTIME_MIN_USER_INITIATED_DATA_TRANSFER_GUARANTEE_MS,
|
||||
mService.getMinJobExecutionGuaranteeMs(jobUIDT));
|
||||
doReturn(mService.mConstants.RUNTIME_MIN_USER_INITIATED_DATA_TRANSFER_GUARANTEE_MS / 2)
|
||||
.when(connectivityController).getEstimatedTransferTimeMs(any());
|
||||
assertEquals(mService.mConstants.RUNTIME_MIN_USER_INITIATED_DATA_TRANSFER_GUARANTEE_MS,
|
||||
mService.getMinJobExecutionGuaranteeMs(jobUIDT));
|
||||
doReturn(mService.mConstants.RUNTIME_MIN_USER_INITIATED_DATA_TRANSFER_GUARANTEE_MS * 2)
|
||||
.when(connectivityController).getEstimatedTransferTimeMs(any());
|
||||
assertEquals(
|
||||
(long) (mService.mConstants.RUNTIME_MIN_USER_INITIATED_DATA_TRANSFER_GUARANTEE_MS
|
||||
* 2 * 1.5),
|
||||
mService.getMinJobExecutionGuaranteeMs(jobUIDT));
|
||||
doReturn(mService.mConstants.RUNTIME_USER_INITIATED_DATA_TRANSFER_LIMIT_MS * 2)
|
||||
.when(connectivityController).getEstimatedTransferTimeMs(any());
|
||||
assertEquals(mService.mConstants.RUNTIME_USER_INITIATED_DATA_TRANSFER_LIMIT_MS,
|
||||
mService.getMinJobExecutionGuaranteeMs(jobUIDT));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetMaxJobExecutionTimeMs() {
|
||||
JobStatus jobDT = createJobStatus("testGetMaxJobExecutionTimeMs",
|
||||
createJobInfo(7)
|
||||
.setDataTransfer(true).setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY));
|
||||
JobStatus jobUI = createJobStatus("testGetMaxJobExecutionTimeMs",
|
||||
createJobInfo(9)); // TODO(255371817): add setUserInitiated(true)
|
||||
JobStatus jobUIDT = createJobStatus("testGetMaxJobExecutionTimeMs",
|
||||
// TODO(255371817): add setUserInitiated(true)
|
||||
createJobInfo(10)
|
||||
.setDataTransfer(true).setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY));
|
||||
|
||||
spyOn(jobDT);
|
||||
spyOn(jobUI);
|
||||
spyOn(jobUIDT);
|
||||
|
||||
when(jobUI.shouldTreatAsUserInitiated()).thenReturn(true);
|
||||
when(jobUIDT.shouldTreatAsUserInitiated()).thenReturn(true);
|
||||
|
||||
grantRunLongJobsPermission(true);
|
||||
|
||||
assertEquals(mService.mConstants.RUNTIME_DATA_TRANSFER_LIMIT_MS,
|
||||
mService.getMaxJobExecutionTimeMs(jobDT));
|
||||
assertEquals(mService.mConstants.RUNTIME_USER_INITIATED_LIMIT_MS,
|
||||
mService.getMaxJobExecutionTimeMs(jobUI));
|
||||
assertEquals(mService.mConstants.RUNTIME_USER_INITIATED_DATA_TRANSFER_LIMIT_MS,
|
||||
mService.getMaxJobExecutionTimeMs(jobUIDT));
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirm that {@link JobSchedulerService#getRescheduleJobForFailureLocked(JobStatus, int)}
|
||||
|
||||
@@ -24,6 +24,7 @@ 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 android.text.format.DateUtils.SECOND_IN_MILLIS;
|
||||
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
|
||||
@@ -35,6 +36,7 @@ import static com.android.server.job.JobSchedulerService.FREQUENT_INDEX;
|
||||
import static com.android.server.job.JobSchedulerService.RARE_INDEX;
|
||||
import static com.android.server.job.JobSchedulerService.RESTRICTED_INDEX;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
@@ -240,20 +242,20 @@ public class ConnectivityControllerTest {
|
||||
.setLinkDownstreamBandwidthKbps(1).build(), mConstants));
|
||||
// Slow downstream
|
||||
assertFalse(controller.isSatisfied(createJobStatus(job), net,
|
||||
createCapabilitiesBuilder().setLinkUpstreamBandwidthKbps(137)
|
||||
createCapabilitiesBuilder().setLinkUpstreamBandwidthKbps(140)
|
||||
.setLinkDownstreamBandwidthKbps(1).build(), mConstants));
|
||||
// Slow upstream
|
||||
assertFalse(controller.isSatisfied(createJobStatus(job), net,
|
||||
createCapabilitiesBuilder().setLinkUpstreamBandwidthKbps(1)
|
||||
.setLinkDownstreamBandwidthKbps(137).build(), mConstants));
|
||||
.setLinkDownstreamBandwidthKbps(140).build(), mConstants));
|
||||
// Network good enough
|
||||
assertTrue(controller.isSatisfied(createJobStatus(job), net,
|
||||
createCapabilitiesBuilder().setLinkUpstreamBandwidthKbps(137)
|
||||
.setLinkDownstreamBandwidthKbps(137).build(), mConstants));
|
||||
createCapabilitiesBuilder().setLinkUpstreamBandwidthKbps(140)
|
||||
.setLinkDownstreamBandwidthKbps(140).build(), mConstants));
|
||||
// Network slightly too slow given reduced time
|
||||
assertFalse(controller.isSatisfied(createJobStatus(job), net,
|
||||
createCapabilitiesBuilder().setLinkUpstreamBandwidthKbps(130)
|
||||
.setLinkDownstreamBandwidthKbps(130).build(), mConstants));
|
||||
createCapabilitiesBuilder().setLinkUpstreamBandwidthKbps(139)
|
||||
.setLinkDownstreamBandwidthKbps(139).build(), mConstants));
|
||||
// Slow network is too slow, but device is charging and network is unmetered.
|
||||
when(mService.isBatteryCharging()).thenReturn(true);
|
||||
controller.onBatteryStateChangedLocked();
|
||||
@@ -1188,6 +1190,78 @@ public class ConnectivityControllerTest {
|
||||
assertFalse(unnetworked.isConstraintSatisfied(JobStatus.CONSTRAINT_CONNECTIVITY));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCalculateTransferTimeMs() {
|
||||
assertEquals(ConnectivityController.UNKNOWN_TIME,
|
||||
ConnectivityController.calculateTransferTimeMs(1, 0));
|
||||
assertEquals(ConnectivityController.UNKNOWN_TIME,
|
||||
ConnectivityController.calculateTransferTimeMs(JobInfo.NETWORK_BYTES_UNKNOWN, 512));
|
||||
assertEquals(1, ConnectivityController.calculateTransferTimeMs(1, 8));
|
||||
assertEquals(1000, ConnectivityController.calculateTransferTimeMs(1000, 8));
|
||||
assertEquals(8, ConnectivityController.calculateTransferTimeMs(1024, 1024));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetEstimatedTransferTimeMs() {
|
||||
final ArgumentCaptor<NetworkCallback> callbackCaptor =
|
||||
ArgumentCaptor.forClass(NetworkCallback.class);
|
||||
doNothing().when(mConnManager).registerNetworkCallback(any(), callbackCaptor.capture());
|
||||
|
||||
final JobStatus job = createJobStatus(createJob()
|
||||
.setEstimatedNetworkBytes(DataUnit.MEBIBYTES.toBytes(10_000),
|
||||
DataUnit.MEBIBYTES.toBytes(1_000))
|
||||
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY));
|
||||
|
||||
final ConnectivityController controller = new ConnectivityController(mService,
|
||||
mFlexibilityController);
|
||||
|
||||
final JobStatus jobNoEstimates = createJobStatus(createJob());
|
||||
assertEquals(ConnectivityController.UNKNOWN_TIME,
|
||||
controller.getEstimatedTransferTimeMs(jobNoEstimates));
|
||||
|
||||
// No network
|
||||
job.network = null;
|
||||
assertEquals(ConnectivityController.UNKNOWN_TIME,
|
||||
controller.getEstimatedTransferTimeMs(job));
|
||||
|
||||
final NetworkCallback generalCallback = callbackCaptor.getValue();
|
||||
|
||||
// No capabilities
|
||||
final Network network = mock(Network.class);
|
||||
answerNetwork(generalCallback, null, null, network, null);
|
||||
job.network = network;
|
||||
assertEquals(ConnectivityController.UNKNOWN_TIME,
|
||||
controller.getEstimatedTransferTimeMs(job));
|
||||
|
||||
// Capabilities don't have bandwidth values
|
||||
NetworkCapabilities caps = createCapabilitiesBuilder().build();
|
||||
answerNetwork(generalCallback, null, null, network, caps);
|
||||
assertEquals(ConnectivityController.UNKNOWN_TIME,
|
||||
controller.getEstimatedTransferTimeMs(job));
|
||||
|
||||
// Capabilities only has downstream bandwidth
|
||||
caps = createCapabilitiesBuilder()
|
||||
.setLinkDownstreamBandwidthKbps(1024)
|
||||
.build();
|
||||
answerNetwork(generalCallback, null, null, network, caps);
|
||||
assertEquals(81920 * SECOND_IN_MILLIS, controller.getEstimatedTransferTimeMs(job));
|
||||
|
||||
// Capabilities only has upstream bandwidth
|
||||
caps = createCapabilitiesBuilder()
|
||||
.setLinkUpstreamBandwidthKbps(2 * 1024)
|
||||
.build();
|
||||
answerNetwork(generalCallback, null, null, network, caps);
|
||||
assertEquals(4096 * SECOND_IN_MILLIS, controller.getEstimatedTransferTimeMs(job));
|
||||
|
||||
// Capabilities only both stream bandwidths
|
||||
caps = createCapabilitiesBuilder()
|
||||
.setLinkDownstreamBandwidthKbps(1024)
|
||||
.setLinkUpstreamBandwidthKbps(2 * 1024)
|
||||
.build();
|
||||
answerNetwork(generalCallback, null, null, network, caps);
|
||||
assertEquals((81920 + 4096) * SECOND_IN_MILLIS, controller.getEstimatedTransferTimeMs(job));
|
||||
}
|
||||
|
||||
private void answerNetwork(@NonNull NetworkCallback generalCallback,
|
||||
@Nullable NetworkCallback uidCallback, @Nullable Network lastNetwork,
|
||||
@Nullable Network net, @Nullable NetworkCapabilities caps) {
|
||||
@@ -1198,11 +1272,15 @@ public class ConnectivityControllerTest {
|
||||
}
|
||||
} else {
|
||||
generalCallback.onAvailable(net);
|
||||
generalCallback.onCapabilitiesChanged(net, caps);
|
||||
if (caps != null) {
|
||||
generalCallback.onCapabilitiesChanged(net, caps);
|
||||
}
|
||||
if (uidCallback != null) {
|
||||
uidCallback.onAvailable(net);
|
||||
uidCallback.onBlockedStatusChanged(net, ConnectivityManager.BLOCKED_REASON_NONE);
|
||||
uidCallback.onCapabilitiesChanged(net, caps);
|
||||
if (caps != null) {
|
||||
uidCallback.onCapabilitiesChanged(net, caps);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user