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

Commit fee8c7b4 authored by Jeff Sharkey's avatar Jeff Sharkey
Browse files

Mechanical refactoring to improve job dumping.

First, JobStatusFunctor was really Consumer<JobStatus> before we
had the java.util.function APIs, so switch everyone over.  Replace
most usages with lambdas; no additional runtime cost, since existing
code was already creating classes.

Move dump() to accept Predicate<JobStatus> for their filtering
behavior, enabling more future advanced filtering using any
attributes of JobStatus.  Also move dump() to IndentingPrintWriter
to avoid passing around tedious prefix information.  Makes it much
easier to print sane-looking output.

Add IndentingPrintWriter support for initial prefix values.

Test: manual dumpsys output looks sane
Bug: 73019091
Change-Id: I4c2398443b42dfb48135ab900d4331ff6d2bb5c4
parent 01bb5302
Loading
Loading
Loading
Loading
+25 −5
Original line number Diff line number Diff line
@@ -57,26 +57,46 @@ public class IndentingPrintWriter extends PrintWriter {
        mWrapLength = wrapLength;
    }

    public void increaseIndent() {
    public IndentingPrintWriter setIndent(String indent) {
        mIndentBuilder.setLength(0);
        mIndentBuilder.append(indent);
        mCurrentIndent = null;
        return this;
    }

    public IndentingPrintWriter setIndent(int indent) {
        mIndentBuilder.setLength(0);
        for (int i = 0; i < indent; i++) {
            increaseIndent();
        }
        return this;
    }

    public IndentingPrintWriter increaseIndent() {
        mIndentBuilder.append(mSingleIndent);
        mCurrentIndent = null;
        return this;
    }

    public void decreaseIndent() {
    public IndentingPrintWriter decreaseIndent() {
        mIndentBuilder.delete(0, mSingleIndent.length());
        mCurrentIndent = null;
        return this;
    }

    public void printPair(String key, Object value) {
    public IndentingPrintWriter printPair(String key, Object value) {
        print(key + "=" + String.valueOf(value) + " ");
        return this;
    }

    public void printPair(String key, Object[] value) {
    public IndentingPrintWriter printPair(String key, Object[] value) {
        print(key + "=" + Arrays.toString(value) + " ");
        return this;
    }

    public void printHexPair(String key, int value) {
    public IndentingPrintWriter printHexPair(String key, int value) {
        print(key + "=0x" + Integer.toHexString(value) + " ");
        return this;
    }

    @Override
+15 −19
Original line number Diff line number Diff line
@@ -53,6 +53,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IAppOpsCallback;
import com.android.internal.app.IAppOpsService;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
import com.android.server.ForceAppStandbyTrackerProto.ExemptedPackage;
import com.android.server.ForceAppStandbyTrackerProto.RunAnyInBackgroundRestrictedPackages;
@@ -1182,72 +1183,67 @@ public class AppStateTracker {
        }
    }

    public void dump(PrintWriter pw, String indent) {
    @Deprecated
    public void dump(PrintWriter pw, String prefix) {
        dump(new IndentingPrintWriter(pw, "  ").setIndent(prefix));
    }

    public void dump(IndentingPrintWriter pw) {
        synchronized (mLock) {
            pw.print(indent);
            pw.println("Forced App Standby Feature enabled: " + mForcedAppStandbyEnabled);

            pw.print(indent);
            pw.print("Force all apps standby: ");
            pw.println(isForceAllAppsStandbyEnabled());

            pw.print(indent);
            pw.print("Small Battery Device: ");
            pw.println(isSmallBatteryDevice());

            pw.print(indent);
            pw.print("Force all apps standby for small battery device: ");
            pw.println(mForceAllAppStandbyForSmallBattery);

            pw.print(indent);
            pw.print("Plugged In: ");
            pw.println(mIsPluggedIn);

            pw.print(indent);
            pw.print("Active uids: ");
            dumpUids(pw, mActiveUids);

            pw.print(indent);
            pw.print("Foreground uids: ");
            dumpUids(pw, mForegroundUids);

            pw.print(indent);
            pw.print("Whitelist appids: ");
            pw.println(Arrays.toString(mPowerWhitelistedAllAppIds));

            pw.print(indent);
            pw.print("Temp whitelist appids: ");
            pw.println(Arrays.toString(mTempWhitelistedAppIds));

            pw.print(indent);
            pw.println("Exempted packages:");
            pw.increaseIndent();
            for (int i = 0; i < mExemptedPackages.size(); i++) {
                pw.print(indent);
                pw.print("User ");
                pw.print(mExemptedPackages.keyAt(i));
                pw.println();

                pw.increaseIndent();
                for (int j = 0; j < mExemptedPackages.sizeAt(i); j++) {
                    pw.print(indent);
                    pw.print("    ");
                    pw.print(mExemptedPackages.valueAt(i, j));
                    pw.println();
                }
                pw.decreaseIndent();
            }
            pw.decreaseIndent();
            pw.println();

            pw.print(indent);
            pw.println("Restricted packages:");
            pw.increaseIndent();
            for (Pair<Integer, String> uidAndPackage : mRunAnyRestrictedPackages) {
                pw.print(indent);
                pw.print("  ");
                pw.print(UserHandle.formatUid(uidAndPackage.first));
                pw.print(" ");
                pw.print(uidAndPackage.second);
                pw.println();
            }
            pw.decreaseIndent();

            mStatLogger.dump(pw, indent);
            mStatLogger.dump(pw);
        }
    }

+8 −3
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import android.util.Slog;
import android.util.proto.ProtoOutputStream;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.StatLoggerProto.Event;

import java.io.PrintWriter;
@@ -78,19 +79,23 @@ public class StatLogger {
        }
    }

    @Deprecated
    public void dump(PrintWriter pw, String prefix) {
        dump(new IndentingPrintWriter(pw, "  ").setIndent(prefix));
    }

    public void dump(IndentingPrintWriter pw) {
        synchronized (mLock) {
            pw.print(prefix);
            pw.println("Stats:");
            pw.increaseIndent();
            for (int i = 0; i < SIZE; i++) {
                pw.print(prefix);
                pw.print("  ");
                final int count = mCountStats[i];
                final double durationMs = mDurationStats[i] / 1000.0;
                pw.println(String.format("%s: count=%d, total=%.1fms, avg=%.3fms",
                        mLabels[i], count, durationMs,
                        (count == 0 ? 0 : ((double) durationMs) / count)));
            }
            pw.decreaseIndent();
        }
    }

+34 −27
Original line number Diff line number Diff line
@@ -79,6 +79,7 @@ import com.android.internal.app.procstats.ProcessStats;
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
import com.android.server.AppStateTracker;
import com.android.server.DeviceIdleController;
@@ -86,7 +87,6 @@ import com.android.server.FgThread;
import com.android.server.LocalServices;
import com.android.server.job.JobSchedulerServiceDumpProto.ActiveJob;
import com.android.server.job.JobSchedulerServiceDumpProto.PendingJob;
import com.android.server.job.JobStore.JobStatusFunctor;
import com.android.server.job.controllers.AppIdleController;
import com.android.server.job.controllers.BackgroundJobsController;
import com.android.server.job.controllers.BatteryController;
@@ -110,6 +110,7 @@ import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Predicate;

/**
@@ -1227,14 +1228,11 @@ public final class JobSchedulerService extends com.android.server.SystemService
                                    getContext().getMainLooper()));
                }
                // Attach jobs to their controllers.
                mJobs.forEachJob(new JobStatusFunctor() {
                    @Override
                    public void process(JobStatus job) {
                mJobs.forEachJob((job) -> {
                    for (int controller = 0; controller < mControllers.size(); controller++) {
                        final StateController sc = mControllers.get(controller);
                        sc.maybeStartTrackingJobLocked(job, null);
                    }
                    }
                });
                // GO GO GO!
                mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget();
@@ -1602,11 +1600,11 @@ public final class JobSchedulerService extends com.android.server.SystemService
        }
    }

    final class ReadyJobQueueFunctor implements JobStatusFunctor {
    final class ReadyJobQueueFunctor implements Consumer<JobStatus> {
        ArrayList<JobStatus> newReadyJobs;

        @Override
        public void process(JobStatus job) {
        public void accept(JobStatus job) {
            if (isReadyToBeExecutedLocked(job)) {
                if (DEBUG) {
                    Slog.d(TAG, "    queued " + job.toShortString());
@@ -1640,7 +1638,7 @@ public final class JobSchedulerService extends com.android.server.SystemService
     * If more than 4 jobs total are ready we send them all off.
     * TODO: It would be nice to consolidate these sort of high-level policies somewhere.
     */
    final class MaybeReadyJobQueueFunctor implements JobStatusFunctor {
    final class MaybeReadyJobQueueFunctor implements Consumer<JobStatus> {
        int chargingCount;
        int batteryNotLowCount;
        int storageNotLowCount;
@@ -1656,7 +1654,7 @@ public final class JobSchedulerService extends com.android.server.SystemService

        // Functor method invoked for each job via JobStore.forEachJob()
        @Override
        public void process(JobStatus job) {
        public void accept(JobStatus job) {
            if (isReadyToBeExecutedLocked(job)) {
                try {
                    if (ActivityManager.getService().isAppStartModeDisabled(job.getUid(),
@@ -2173,13 +2171,10 @@ public final class JobSchedulerService extends com.android.server.SystemService
        public List<JobInfo> getSystemScheduledPendingJobs() {
            synchronized (mLock) {
                final List<JobInfo> pendingJobs = new ArrayList<JobInfo>();
                mJobs.forEachJob(Process.SYSTEM_UID, new JobStatusFunctor() {
                    @Override
                    public void process(JobStatus job) {
                mJobs.forEachJob(Process.SYSTEM_UID, (job) -> {
                    if (job.getJob().isPeriodic() || !isCurrentlyActiveLocked(job)) {
                        pendingJobs.add(job.getJob());
                    }
                    }
                });
                return pendingJobs;
            }
@@ -2307,7 +2302,7 @@ public final class JobSchedulerService extends com.android.server.SystemService
        }
    }

    static class DeferredJobCounter implements JobStatusFunctor {
    static class DeferredJobCounter implements Consumer<JobStatus> {
        private int mDeferred = 0;

        public int numDeferred() {
@@ -2315,7 +2310,7 @@ public final class JobSchedulerService extends com.android.server.SystemService
        }

        @Override
        public void process(JobStatus job) {
        public void accept(JobStatus job) {
            if (job.getWhenStandbyDeferred() > 0) {
                mDeferred++;
            }
@@ -2596,12 +2591,13 @@ public final class JobSchedulerService extends com.android.server.SystemService
                }
            }

            long identityToken = Binder.clearCallingIdentity();
            final long identityToken = Binder.clearCallingIdentity();
            try {
                if (proto) {
                    JobSchedulerService.this.dumpInternalProto(fd, filterUid);
                } else {
                    JobSchedulerService.this.dumpInternal(pw, filterUid);
                    JobSchedulerService.this.dumpInternal(new IndentingPrintWriter(pw, "  "),
                            filterUid);
                }
            } finally {
                Binder.restoreCallingIdentity(identityToken);
@@ -2900,10 +2896,14 @@ public final class JobSchedulerService extends com.android.server.SystemService
        });
    }

    void dumpInternal(final PrintWriter pw, int filterUid) {
    void dumpInternal(final IndentingPrintWriter pw, int filterUid) {
        final int filterUidFinal = UserHandle.getAppId(filterUid);
        final long nowElapsed = sElapsedRealtimeClock.millis();
        final long nowUptime = sUptimeMillisClock.millis();
        final Predicate<JobStatus> predicate = (js) -> {
            return filterUidFinal == -1 || UserHandle.getAppId(js.getUid()) == filterUidFinal
                    || UserHandle.getAppId(js.getSourceUid()) == filterUidFinal;
        };
        synchronized (mLock) {
            mConstants.dump(pw);
            pw.println();
@@ -2919,7 +2919,7 @@ public final class JobSchedulerService extends com.android.server.SystemService
                    pw.println(job.toShortStringExceptUniqueId());

                    // Skip printing details if the caller requested a filter
                    if (!job.shouldDump(filterUidFinal)) {
                    if (!predicate.test(job)) {
                        continue;
                    }

@@ -2953,7 +2953,10 @@ public final class JobSchedulerService extends com.android.server.SystemService
            }
            for (int i=0; i<mControllers.size(); i++) {
                pw.println();
                mControllers.get(i).dumpControllerStateLocked(pw, filterUidFinal);
                pw.println(mControllers.get(i).getClass().getSimpleName() + ":");
                pw.increaseIndent();
                mControllers.get(i).dumpControllerStateLocked(pw, predicate);
                pw.decreaseIndent();
            }
            pw.println();
            pw.println("Uid priority overrides:");
@@ -3056,6 +3059,10 @@ public final class JobSchedulerService extends com.android.server.SystemService
        final int filterUidFinal = UserHandle.getAppId(filterUid);
        final long nowElapsed = sElapsedRealtimeClock.millis();
        final long nowUptime = sUptimeMillisClock.millis();
        final Predicate<JobStatus> predicate = (js) -> {
            return filterUidFinal == -1 || UserHandle.getAppId(js.getUid()) == filterUidFinal
                    || UserHandle.getAppId(js.getSourceUid()) == filterUidFinal;
        };

        synchronized (mLock) {
            mConstants.dump(proto, JobSchedulerServiceDumpProto.SETTINGS);
@@ -3070,7 +3077,7 @@ public final class JobSchedulerService extends com.android.server.SystemService
                    job.writeToShortProto(proto, JobSchedulerServiceDumpProto.RegisteredJob.INFO);

                    // Skip printing details if the caller requested a filter
                    if (!job.shouldDump(filterUidFinal)) {
                    if (!predicate.test(job)) {
                        continue;
                    }

@@ -3103,7 +3110,7 @@ public final class JobSchedulerService extends com.android.server.SystemService
            }
            for (StateController controller : mControllers) {
                controller.dumpControllerStateLocked(
                        proto, JobSchedulerServiceDumpProto.CONTROLLERS, filterUidFinal);
                        proto, JobSchedulerServiceDumpProto.CONTROLLERS, predicate);
            }
            for (int i=0; i< mUidPriorityOverride.size(); i++) {
                int uid = mUidPriorityOverride.keyAt(i);
+24 −20
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.server.job;
import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
import static com.android.server.job.JobSchedulerService.sSystemClock;

import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.IActivityManager;
import android.app.job.JobInfo;
@@ -62,6 +63,7 @@ import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Predicate;

/**
@@ -286,20 +288,21 @@ public final class JobStore {
     * transient unified collections for them to iterate over and then discard, or creating
     * iterators every time a client needs to perform a sweep.
     */
    public void forEachJob(JobStatusFunctor functor) {
        mJobSet.forEachJob(functor);
    public void forEachJob(Consumer<JobStatus> functor) {
        mJobSet.forEachJob(null, functor);
    }

    public void forEachJob(int uid, JobStatusFunctor functor) {
        mJobSet.forEachJob(uid, functor);
    public void forEachJob(@Nullable Predicate<JobStatus> filterPredicate,
            Consumer<JobStatus> functor) {
        mJobSet.forEachJob(filterPredicate, functor);
    }

    public void forEachJobForSourceUid(int sourceUid, JobStatusFunctor functor) {
        mJobSet.forEachJobForSourceUid(sourceUid, functor);
    public void forEachJob(int uid, Consumer<JobStatus> functor) {
        mJobSet.forEachJob(uid, functor);
    }

    public interface JobStatusFunctor {
        public void process(JobStatus jobStatus);
    public void forEachJobForSourceUid(int sourceUid, Consumer<JobStatus> functor) {
        mJobSet.forEachJobForSourceUid(sourceUid, functor);
    }

    /** Version of the db schema. */
@@ -342,13 +345,10 @@ public final class JobStore {
            final List<JobStatus> storeCopy = new ArrayList<JobStatus>();
            synchronized (mLock) {
                // Clone the jobs so we can release the lock before writing.
                mJobSet.forEachJob(new JobStatusFunctor() {
                    @Override
                    public void process(JobStatus job) {
                mJobSet.forEachJob(null, (job) -> {
                    if (job.isPersisted()) {
                        storeCopy.add(new JobStatus(job));
                    }
                    }
                });
            }
            writeJobsMapImpl(storeCopy);
@@ -1184,31 +1184,35 @@ public final class JobStore {
            return total;
        }

        public void forEachJob(JobStatusFunctor functor) {
        public void forEachJob(@Nullable Predicate<JobStatus> filterPredicate,
                Consumer<JobStatus> functor) {
            for (int uidIndex = mJobs.size() - 1; uidIndex >= 0; uidIndex--) {
                ArraySet<JobStatus> jobs = mJobs.valueAt(uidIndex);
                if (jobs != null) {
                    for (int i = jobs.size() - 1; i >= 0; i--) {
                        functor.process(jobs.valueAt(i));
                        final JobStatus jobStatus = jobs.valueAt(i);
                        if ((filterPredicate == null) || filterPredicate.test(jobStatus)) {
                            functor.accept(jobStatus);
                        }
                    }
                }
            }
        }

        public void forEachJob(int callingUid, JobStatusFunctor functor) {
        public void forEachJob(int callingUid, Consumer<JobStatus> functor) {
            ArraySet<JobStatus> jobs = mJobs.get(callingUid);
            if (jobs != null) {
                for (int i = jobs.size() - 1; i >= 0; i--) {
                    functor.process(jobs.valueAt(i));
                    functor.accept(jobs.valueAt(i));
                }
            }
        }

        public void forEachJobForSourceUid(int sourceUid, JobStatusFunctor functor) {
        public void forEachJobForSourceUid(int sourceUid, Consumer<JobStatus> functor) {
            final ArraySet<JobStatus> jobs = mJobsPerSourceUid.get(sourceUid);
            if (jobs != null) {
                for (int i = jobs.size() - 1; i >= 0; i--) {
                    functor.process(jobs.valueAt(i));
                    functor.accept(jobs.valueAt(i));
                }
            }
        }
Loading