Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6a1058da authored by Kweku Adams's avatar Kweku Adams
Browse files

Adjust execution limits for new job types.

Set new execution limits for user-initiated and data transfer jobs.
To start, we'll have the following execution limits:
* User-initiated: [10 minutes, 60 minutes]
* Data transfer: [10 minutes, 30 minutes] (same as regular jobs)
* User-initiated data transfer:
    [max{10 minutes, 1.35 * estimated transfer time}, 292471 millenia)

Also fix a bug in the estimated transfer time calculation.

Bug: 261622663
Test: atest FrameworksMockingServicesTests:ConnectivityControllerTest
Test: atest FrameworksMockingServicesTests:JobSchedulerServiceTest
Change-Id: Ib80008acba98f740746d7f2d74ce33c57221bee5
parent 045bda74
Loading
Loading
Loading
Loading
+200 −15
Original line number Diff line number Diff line
@@ -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;
            }

+50 −13
Original line number Diff line number Diff line
@@ -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
+9 −0
Original line number Diff line number Diff line
@@ -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.
     */
+109 −0

File changed.

Preview size limit exceeded, changes collapsed.

+86 −8

File changed.

Preview size limit exceeded, changes collapsed.