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

Commit 0cd3e8f6 authored by Dianne Hackborn's avatar Dianne Hackborn Committed by Android (Google) Code Review
Browse files

Merge "Fix issue #38244875: Bring back testChargingConstraintFails" into oc-dev

parents 0553cbcf 6d06826b
Loading
Loading
Loading
Loading
+99 −23
Original line number Diff line number Diff line
@@ -1270,6 +1270,17 @@ public final class JobSchedulerService extends com.android.server.SystemService
        }
    }

    private void stopNonReadyActiveJobsLocked() {
        for (int i=0; i<mActiveServices.size(); i++) {
            JobServiceContext serviceContext = mActiveServices.get(i);
            final JobStatus running = serviceContext.getRunningJobLocked();
            if (running != null && !running.isReady()) {
                serviceContext.cancelExecutingJobLocked(
                        JobParameters.REASON_CONSTRAINTS_NOT_SATISFIED);
            }
        }
    }

    /**
     * Run through list of jobs and execute all possible - at least one is expired so we do
     * as many as we can.
@@ -1280,6 +1291,7 @@ public final class JobSchedulerService extends com.android.server.SystemService
        }
        noteJobsNonpending(mPendingJobs);
        mPendingJobs.clear();
        stopNonReadyActiveJobsLocked();
        mJobs.forEachJob(mReadyQueueFunctor);
        mReadyQueueFunctor.postProcess();

@@ -1306,9 +1318,6 @@ public final class JobSchedulerService extends com.android.server.SystemService
                    newReadyJobs = new ArrayList<JobStatus>();
                }
                newReadyJobs.add(job);
            } else if (areJobConstraintsNotSatisfiedLocked(job)) {
                stopJobOnServiceContextLocked(job,
                        JobParameters.REASON_CONSTRAINTS_NOT_SATISFIED);
            }
        }

@@ -1387,9 +1396,6 @@ public final class JobSchedulerService extends com.android.server.SystemService
                    runnableJobs = new ArrayList<>();
                }
                runnableJobs.add(job);
            } else if (areJobConstraintsNotSatisfiedLocked(job)) {
                stopJobOnServiceContextLocked(job,
                        JobParameters.REASON_CONSTRAINTS_NOT_SATISFIED);
            }
        }

@@ -1439,6 +1445,7 @@ public final class JobSchedulerService extends com.android.server.SystemService

        noteJobsNonpending(mPendingJobs);
        mPendingJobs.clear();
        stopNonReadyActiveJobsLocked();
        mJobs.forEachJob(mMaybeQueueFunctor);
        mMaybeQueueFunctor.postProcess();
    }
@@ -1515,15 +1522,6 @@ public final class JobSchedulerService extends com.android.server.SystemService
        return componentPresent;
    }

    /**
     * Criteria for cancelling an active job:
     *      - It's not ready
     *      - It's running on a JSC.
     */
    private boolean areJobConstraintsNotSatisfiedLocked(JobStatus job) {
        return !job.isReady() && isCurrentlyActiveLocked(job);
    }

    /**
     * Reconcile jobs in the pending queue against available execution contexts.
     * A controller can force a job into the pending queue even if it's already running, but
@@ -2088,6 +2086,83 @@ public final class JobSchedulerService extends com.android.server.SystemService
        }
    }

    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(")");
                return JobSchedulerShellCommand.CMD_ERR_NO_PACKAGE;
            }

            synchronized (mLock) {
                final JobStatus js = mJobs.getJobByUidAndJobId(uid, jobId);
                if (DEBUG) Slog.d(TAG, "get-job-state " + uid + "/" + jobId + ": " + js);
                if (js == null) {
                    pw.print("unknown("); UserHandle.formatUid(pw, uid);
                    pw.print("/jid"); pw.print(jobId); pw.println(")");
                    return JobSchedulerShellCommand.CMD_ERR_NO_JOB;
                }

                boolean printed = false;
                if (mPendingJobs.contains(js)) {
                    pw.print("pending");
                    printed = true;
                }
                if (isCurrentlyActiveLocked(js)) {
                    if (printed) {
                        pw.print(" ");
                    }
                    printed = true;
                    pw.println("active");
                }
                if (!ArrayUtils.contains(mStartedUsers, js.getUserId())) {
                    if (printed) {
                        pw.print(" ");
                    }
                    printed = true;
                    pw.println("user-stopped");
                }
                if (mBackingUpUids.indexOfKey(js.getSourceUid()) >= 0) {
                    if (printed) {
                        pw.print(" ");
                    }
                    printed = true;
                    pw.println("backing-up");
                }
                boolean componentPresent = false;
                try {
                    componentPresent = (AppGlobals.getPackageManager().getServiceInfo(
                            js.getServiceComponent(),
                            PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
                            js.getUserId()) != null);
                } catch (RemoteException e) {
                }
                if (!componentPresent) {
                    if (printed) {
                        pw.print(" ");
                    }
                    printed = true;
                    pw.println("no-component");
                }
                if (js.isReady()) {
                    if (printed) {
                        pw.print(" ");
                    }
                    printed = true;
                    pw.println("ready");
                }
                if (!printed) {
                    pw.print("waiting");
                }
                pw.println();
            }
        } catch (RemoteException e) {
            // can't happen
        }
        return 0;
    }

    private String printContextIdToJobMap(JobStatus[] map, String initial) {
        StringBuilder s = new StringBuilder(initial + ": ");
        for (int i=0; i<map.length; i++) {
@@ -2152,7 +2227,8 @@ public final class JobSchedulerService extends com.android.server.SystemService
        }

        final int filterUidFinal = UserHandle.getAppId(filterUid);
        final long now = SystemClock.elapsedRealtime();
        final long nowElapsed = SystemClock.elapsedRealtime();
        final long nowUptime = SystemClock.uptimeMillis();
        synchronized (mLock) {
            mConstants.dump(pw);
            pw.println();
@@ -2184,7 +2260,7 @@ public final class JobSchedulerService extends com.android.server.SystemService
                        continue;
                    }

                    job.dump(pw, "    ", true, now);
                    job.dump(pw, "    ", true, nowElapsed);
                    pw.print("    Ready: ");
                    pw.print(isReadyToBeExecutedLocked(job));
                    pw.print(" (job=");
@@ -2254,14 +2330,14 @@ public final class JobSchedulerService extends com.android.server.SystemService
                JobStatus job = mPendingJobs.get(i);
                pw.print("  Pending #"); pw.print(i); pw.print(": ");
                pw.println(job.toShortString());
                job.dump(pw, "    ", false, now);
                job.dump(pw, "    ", false, nowElapsed);
                int priority = evaluateJobPriorityLocked(job);
                if (priority != JobInfo.PRIORITY_DEFAULT) {
                    pw.print("    Evaluated priority: "); pw.println(priority);
                }
                pw.print("    Tag: "); pw.println(job.getTag());
                pw.print("    Enq: ");
                TimeUtils.formatDuration(job.madePending - now, pw);
                TimeUtils.formatDuration(job.madePending - nowUptime, pw);
                pw.println();
            }
            pw.println();
@@ -2276,17 +2352,17 @@ public final class JobSchedulerService extends com.android.server.SystemService
                } else {
                    pw.println(job.toShortString());
                    pw.print("    Running for: ");
                    TimeUtils.formatDuration(now - jsc.getExecutionStartTimeElapsed(), pw);
                    TimeUtils.formatDuration(nowElapsed - jsc.getExecutionStartTimeElapsed(), pw);
                    pw.print(", timeout at: ");
                    TimeUtils.formatDuration(jsc.getTimeoutElapsed() - now, pw);
                    TimeUtils.formatDuration(jsc.getTimeoutElapsed() - nowElapsed, pw);
                    pw.println();
                    job.dump(pw, "    ", false, now);
                    job.dump(pw, "    ", false, nowElapsed);
                    int priority = evaluateJobPriorityLocked(jsc.getRunningJobLocked());
                    if (priority != JobInfo.PRIORITY_DEFAULT) {
                        pw.print("    Evaluated priority: "); pw.println(priority);
                    }
                    pw.print("    Active at ");
                    TimeUtils.formatDuration(job.madeActive - now, pw);
                    TimeUtils.formatDuration(job.madeActive - nowUptime, pw);
                    pw.print(", pending for ");
                    TimeUtils.formatDuration(job.madeActive - job.madePending, pw);
                    pw.println();
+97 −34
Original line number Diff line number Diff line
@@ -60,6 +60,8 @@ public class JobSchedulerShellCommand extends ShellCommand {
                    return getStorageSeq(pw);
                case "get-storage-not-low":
                    return getStorageNotLow(pw);
                case "get-job-state":
                    return getJobState(pw);
                default:
                    return handleDefaultCommands(cmd);
            }
@@ -83,6 +85,43 @@ public class JobSchedulerShellCommand extends ShellCommand {
        }
    }

    private boolean printError(int errCode, String pkgName, int userId, int jobId) {
        PrintWriter pw;
        switch (errCode) {
            case CMD_ERR_NO_PACKAGE:
                pw = getErrPrintWriter();
                pw.print("Package not found: ");
                pw.print(pkgName);
                pw.print(" / user ");
                pw.println(userId);
                return true;

            case CMD_ERR_NO_JOB:
                pw = getErrPrintWriter();
                pw.print("Could not find job ");
                pw.print(jobId);
                pw.print(" in package ");
                pw.print(pkgName);
                pw.print(" / user ");
                pw.println(userId);
                return true;

            case CMD_ERR_CONSTRAINTS:
                pw = getErrPrintWriter();
                pw.print("Job ");
                pw.print(jobId);
                pw.print(" in package ");
                pw.print(pkgName);
                pw.print(" / user ");
                pw.print(userId);
                pw.println(" has functional constraints but --force not specified");
                return true;

            default:
                return false;
        }
    }

    private int runJob(PrintWriter pw) throws Exception {
        checkPermission("force scheduled jobs");

@@ -114,42 +153,17 @@ public class JobSchedulerShellCommand extends ShellCommand {
        final long ident = Binder.clearCallingIdentity();
        try {
            int ret = mInternal.executeRunCommand(pkgName, userId, jobId, force);
            switch (ret) {
                case CMD_ERR_NO_PACKAGE:
                    pw.print("Package not found: ");
                    pw.print(pkgName);
                    pw.print(" / user ");
                    pw.println(userId);
                    break;

                case CMD_ERR_NO_JOB:
                    pw.print("Could not find job ");
                    pw.print(jobId);
                    pw.print(" in package ");
                    pw.print(pkgName);
                    pw.print(" / user ");
                    pw.println(userId);
                    break;

                case CMD_ERR_CONSTRAINTS:
                    pw.print("Job ");
                    pw.print(jobId);
                    pw.print(" in package ");
                    pw.print(pkgName);
                    pw.print(" / user ");
                    pw.print(userId);
                    pw.println(" has functional constraints but --force not specified");
                    break;
            if (printError(ret, pkgName, userId, jobId)) {
                return ret;
            }

                default:
            // success!
            pw.print("Running job");
            if (force) {
                pw.print(" [FORCED]");
            }
            pw.println();
                    break;
            }

            return ret;
        } finally {
            Binder.restoreCallingIdentity(ident);
@@ -244,6 +258,43 @@ public class JobSchedulerShellCommand extends ShellCommand {
        return 0;
    }

    private int getJobState(PrintWriter pw) throws Exception {
        checkPermission("force timeout jobs");

        int userId = UserHandle.USER_SYSTEM;

        String opt;
        while ((opt = getNextOption()) != null) {
            switch (opt) {
                case "-u":
                case "--user":
                    userId = UserHandle.parseUserArg(getNextArgRequired());
                    break;

                default:
                    pw.println("Error: unknown option '" + opt + "'");
                    return -1;
            }
        }

        if (userId == UserHandle.USER_CURRENT) {
            userId = ActivityManager.getCurrentUser();
        }

        final String pkgName = getNextArgRequired();
        final String jobIdStr = getNextArgRequired();
        final int jobId = Integer.parseInt(jobIdStr);

        final long ident = Binder.clearCallingIdentity();
        try {
            int ret = mInternal.getJobState(pw, pkgName, userId, jobId);
            printError(ret, pkgName, userId, jobId);
            return ret;
        } finally {
            Binder.restoreCallingIdentity(ident);
        }
    }

    @Override
    public void onHelp() {
        final PrintWriter pw = getOutPrintWriter();
@@ -277,6 +328,18 @@ public class JobSchedulerShellCommand extends ShellCommand {
        pw.println("    Return the last storage update sequence number that was received.");
        pw.println("  get-storage-not-low");
        pw.println("    Return whether storage is currently considered to not be low.");
        pw.println("  get-job-state [-u | --user USER_ID] PACKAGE JOB_ID");
        pw.println("    Return the current state of a job, may be any combination of:");
        pw.println("      pending: currently on the pending list, waiting to be active");
        pw.println("      active: job is actively running");
        pw.println("      user-stopped: job can't run because its user is stopped");
        pw.println("      backing-up: job can't run because app is currently backing up its data");
        pw.println("      no-component: job can't run because its component is not available");
        pw.println("      ready: job is ready to run (all constraints satisfied or bypassed)");
        pw.println("      waiting: if nothing else above is printed, job not ready to run");
        pw.println("    Options:");
        pw.println("      -u or --user: specify which user's job is to be run; the default is");
        pw.println("         the primary or system user");
        pw.println();
    }

+50 −49
Original line number Diff line number Diff line
@@ -93,14 +93,13 @@ public class BatteryController extends StateController {
        }
    }

    private void maybeReportNewChargingState() {
    private void maybeReportNewChargingStateLocked() {
        final boolean stablePower = mChargeTracker.isOnStablePower();
        final boolean batteryNotLow = mChargeTracker.isBatteryNotLow();
        if (DEBUG) {
            Slog.d(TAG, "maybeReportNewChargingState: " + stablePower);
            Slog.d(TAG, "maybeReportNewChargingStateLocked: " + stablePower);
        }
        boolean reportChange = false;
        synchronized (mLock) {
        for (int i = mTrackedTasks.size() - 1; i >= 0; i--) {
            final JobStatus ts = mTrackedTasks.valueAt(i);
            boolean previous = ts.setChargingConstraintSatisfied(stablePower);
@@ -112,15 +111,13 @@ public class BatteryController extends StateController {
                reportChange = true;
            }
        }
        }
        // Let the scheduler know that state has changed. This may or may not result in an
        // execution.
        if (reportChange) {
            mStateChangedListener.onControllerStateChanged();
        }
        // Also tell the scheduler that any ready jobs should be flushed.
        if (stablePower || batteryNotLow) {
            // If one of our conditions has been satisfied, always schedule any newly ready jobs.
            mStateChangedListener.onRunJobNow(null);
        } else if (reportChange) {
            // Otherwise, just let the job scheduler know the state has changed and take care of it
            // as it thinks is best.
            mStateChangedListener.onControllerStateChanged();
        }
    }

@@ -201,6 +198,7 @@ public class BatteryController extends StateController {

        @VisibleForTesting
        public void onReceiveInternal(Intent intent) {
            synchronized (mLock) {
                final String action = intent.getAction();
                if (Intent.ACTION_BATTERY_LOW.equals(action)) {
                    if (DEBUG) {
@@ -211,28 +209,31 @@ public class BatteryController extends StateController {
                    // there's no work to cancel. We track this variable for the case where it is
                    // charging, but hasn't been for long enough to be healthy.
                    mBatteryHealthy = false;
                    maybeReportNewChargingStateLocked();
                } else if (Intent.ACTION_BATTERY_OKAY.equals(action)) {
                    if (DEBUG) {
                        Slog.d(TAG, "Battery life healthy enough to do work. @ "
                                + SystemClock.elapsedRealtime());
                    }
                    mBatteryHealthy = true;
                maybeReportNewChargingState();
                    maybeReportNewChargingStateLocked();
                } else if (BatteryManager.ACTION_CHARGING.equals(action)) {
                    if (DEBUG) {
                        Slog.d(TAG, "Received charging intent, fired @ "
                                + SystemClock.elapsedRealtime());
                    }
                    mCharging = true;
                maybeReportNewChargingState();
                    maybeReportNewChargingStateLocked();
                } else if (BatteryManager.ACTION_DISCHARGING.equals(action)) {
                    if (DEBUG) {
                        Slog.d(TAG, "Disconnected from power.");
                    }
                    mCharging = false;
                maybeReportNewChargingState();
                    maybeReportNewChargingStateLocked();
                }
                mLastBatterySeq = intent.getIntExtra(BatteryManager.EXTRA_SEQUENCE,
                        mLastBatterySeq);
            }
            mLastBatterySeq = intent.getIntExtra(BatteryManager.EXTRA_SEQUENCE, mLastBatterySeq);
        }
    }