Loading apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java +34 −20 Original line number Diff line number Diff line Loading @@ -804,11 +804,21 @@ class JobConcurrencyManager { @WorkType final int workType) { final List<StateController> controllers = mService.mControllers; final int numControllers = controllers.size(); final PowerManager.WakeLock wl = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, jobStatus.getTag()); wl.setWorkSource(mService.deriveWorkSource( jobStatus.getSourceUid(), jobStatus.getSourcePackageName())); wl.setReferenceCounted(false); // Since the quota controller will start counting from the time prepareForExecutionLocked() // is called, hold a wakelock to make sure the CPU doesn't suspend between that call and // when the service actually starts. wl.acquire(); try { for (int ic = 0; ic < numControllers; ic++) { controllers.get(ic).prepareForExecutionLocked(jobStatus); } final PackageStats packageStats = getPkgStatsLocked(jobStatus.getSourceUserId(), jobStatus.getSourcePackageName()); final PackageStats packageStats = getPkgStatsLocked( jobStatus.getSourceUserId(), jobStatus.getSourcePackageName()); packageStats.adjustStagedCount(false, jobStatus.shouldTreatAsExpeditedJob()); if (!worker.executeRunnableJob(jobStatus, workType)) { Slog.e(TAG, "Error executing " + jobStatus); Loading @@ -821,12 +831,16 @@ class JobConcurrencyManager { mWorkCountTracker.onJobStarted(workType); packageStats.adjustRunningCount(true, jobStatus.shouldTreatAsExpeditedJob()); mActivePkgStats.add( jobStatus.getSourceUserId(), jobStatus.getSourcePackageName(), packageStats); jobStatus.getSourceUserId(), jobStatus.getSourcePackageName(), packageStats); } final List<JobStatus> pendingJobs = mService.mPendingJobs; if (pendingJobs.remove(jobStatus)) { mService.mJobPackageTracker.noteNonpending(jobStatus); } } finally { wl.release(); } } @GuardedBy("mLock") Loading apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java +12 −2 Original line number Diff line number Diff line Loading @@ -917,8 +917,18 @@ public class JobSchedulerService extends com.android.server.SystemService return mConstants; } public boolean isChainedAttributionEnabled() { return WorkSource.isChainedBatteryAttributionEnabled(getContext()); @NonNull public WorkSource deriveWorkSource(int sourceUid, @Nullable String sourcePackageName) { if (WorkSource.isChainedBatteryAttributionEnabled(getContext())) { WorkSource ws = new WorkSource(); ws.createWorkChain() .addNode(sourceUid, sourcePackageName) .addNode(Process.SYSTEM_UID, "JobScheduler"); return ws; } else { return sourcePackageName == null ? new WorkSource(sourceUid) : new WorkSource(sourceUid, sourcePackageName); } } @Nullable Loading apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java +9 −33 Original line number Diff line number Diff line Loading @@ -42,7 +42,6 @@ import android.os.Message; import android.os.PowerManager; import android.os.RemoteException; import android.os.UserHandle; import android.os.WorkSource; import android.util.EventLog; import android.util.IndentingPrintWriter; import android.util.Slog; Loading Loading @@ -109,6 +108,7 @@ public final class JobServiceContext implements ServiceConnection { private final Object mLock; private final IBatteryStats mBatteryStats; private final JobPackageTracker mJobPackageTracker; private final PowerManager mPowerManager; private PowerManager.WakeLock mWakeLock; // Execution state. Loading Loading @@ -205,6 +205,7 @@ public final class JobServiceContext implements ServiceConnection { mCallbackHandler = new JobServiceHandler(looper); mJobConcurrencyManager = concurrencyManager; mCompletedListener = service; mPowerManager = mContext.getSystemService(PowerManager.class); mAvailable = true; mVerb = VERB_FINISHED; mPreferredUid = NO_PREFERRED_UID; Loading Loading @@ -271,6 +272,12 @@ public final class JobServiceContext implements ServiceConnection { // it was inflated from disk with not-yet-coherent delay/deadline bounds. job.clearPersistedUtcTimes(); mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, job.getTag()); mWakeLock.setWorkSource( mService.deriveWorkSource(job.getSourceUid(), job.getSourcePackageName())); mWakeLock.setReferenceCounted(false); mWakeLock.acquire(); mVerb = VERB_BINDING; scheduleOpTimeOutLocked(); final Intent intent = new Intent().setComponent(job.getServiceComponent()); Loading Loading @@ -306,6 +313,7 @@ public final class JobServiceContext implements ServiceConnection { mRunningCallback = null; mParams = null; mExecutionStartTimeElapsed = 0L; mWakeLock.release(); mVerb = VERB_FINISHED; removeOpTimeOutLocked(); return false; Loading Loading @@ -495,42 +503,10 @@ public final class JobServiceContext implements ServiceConnection { return; } this.service = IJobService.Stub.asInterface(service); final PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, runningJob.getTag()); wl.setWorkSource(deriveWorkSource(runningJob)); wl.setReferenceCounted(false); wl.acquire(); // We use a new wakelock instance per job. In rare cases there is a race between // teardown following job completion/cancellation and new job service spin-up // such that if we simply assign mWakeLock to be the new instance, we orphan // the currently-live lock instead of cleanly replacing it. Watch for this and // explicitly fast-forward the release if we're in that situation. if (mWakeLock != null) { Slog.w(TAG, "Bound new job " + runningJob + " but live wakelock " + mWakeLock + " tag=" + mWakeLock.getTag()); mWakeLock.release(); } mWakeLock = wl; doServiceBoundLocked(); } } private WorkSource deriveWorkSource(JobStatus runningJob) { final int jobUid = runningJob.getSourceUid(); if (WorkSource.isChainedBatteryAttributionEnabled(mContext)) { WorkSource workSource = new WorkSource(); workSource.createWorkChain() .addNode(jobUid, null) .addNode(android.os.Process.SYSTEM_UID, "JobScheduler"); return workSource; } else { return new WorkSource(jobUid); } } /** If the client service crashes we reschedule this job and clean up. */ @Override public void onServiceDisconnected(ComponentName name) { Loading apex/jobscheduler/service/java/com/android/server/job/controllers/TimeController.java +6 −22 Original line number Diff line number Diff line Loading @@ -18,11 +18,9 @@ package com.android.server.job.controllers; import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock; import android.annotation.Nullable; import android.app.AlarmManager; import android.app.AlarmManager.OnAlarmListener; import android.content.Context; import android.os.Process; import android.os.UserHandle; import android.os.WorkSource; import android.util.IndentingPrintWriter; Loading Loading @@ -62,8 +60,6 @@ public final class TimeController extends StateController { private long mNextDelayExpiredElapsedMillis; private volatile long mLastFiredDelayExpiredElapsedMillis; private final boolean mChainedAttributionEnabled; private AlarmManager mAlarmService = null; /** List of tracked jobs, sorted asc. by deadline */ private final List<JobStatus> mTrackedJobs = new LinkedList<>(); Loading @@ -73,7 +69,6 @@ public final class TimeController extends StateController { mNextJobExpiredElapsedMillis = Long.MAX_VALUE; mNextDelayExpiredElapsedMillis = Long.MAX_VALUE; mChainedAttributionEnabled = mService.isChainedAttributionEnabled(); } /** Loading Loading @@ -117,7 +112,8 @@ public final class TimeController extends StateController { it.add(job); job.setTrackingController(JobStatus.TRACKING_TIME); WorkSource ws = deriveWorkSource(job.getSourceUid(), job.getSourcePackageName()); WorkSource ws = mService.deriveWorkSource(job.getSourceUid(), job.getSourcePackageName()); // Only update alarms if the job would be ready with the relevant timing constraint // satisfied. Loading Loading @@ -165,7 +161,7 @@ public final class TimeController extends StateController { } else if (wouldBeReadyWithConstraintLocked(job, JobStatus.CONSTRAINT_DEADLINE)) { // This job's deadline is earlier than the current set alarm. Update the alarm. setDeadlineExpiredAlarmLocked(job.getLatestRunTimeElapsed(), deriveWorkSource(job.getSourceUid(), job.getSourcePackageName())); mService.deriveWorkSource(job.getSourceUid(), job.getSourcePackageName())); } } if (job.hasTimingDelayConstraint() Loading @@ -177,7 +173,7 @@ public final class TimeController extends StateController { && wouldBeReadyWithConstraintLocked(job, JobStatus.CONSTRAINT_TIMING_DELAY)) { // This job's delay is earlier than the current set alarm. Update the alarm. setDelayExpiredAlarmLocked(job.getEarliestRunTime(), deriveWorkSource(job.getSourceUid(), job.getSourcePackageName())); mService.deriveWorkSource(job.getSourceUid(), job.getSourcePackageName())); } } } Loading Loading @@ -248,7 +244,7 @@ public final class TimeController extends StateController { } } setDeadlineExpiredAlarmLocked(nextExpiryTime, deriveWorkSource(nextExpiryUid, nextExpiryPackageName)); mService.deriveWorkSource(nextExpiryUid, nextExpiryPackageName)); } } Loading Loading @@ -312,19 +308,7 @@ public final class TimeController extends StateController { mStateChangedListener.onControllerStateChanged(); } setDelayExpiredAlarmLocked(nextDelayTime, deriveWorkSource(nextDelayUid, nextDelayPackageName)); } } private WorkSource deriveWorkSource(int uid, @Nullable String packageName) { if (mChainedAttributionEnabled) { WorkSource ws = new WorkSource(); ws.createWorkChain() .addNode(uid, packageName) .addNode(Process.SYSTEM_UID, "JobScheduler"); return ws; } else { return packageName == null ? new WorkSource(uid) : new WorkSource(uid, packageName); mService.deriveWorkSource(nextDelayUid, nextDelayPackageName)); } } Loading services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java +0 −5 Original line number Diff line number Diff line Loading @@ -90,11 +90,6 @@ public class JobSchedulerServiceTest { super(context); mAppStateTracker = mock(AppStateTrackerImpl.class); } @Override public boolean isChainedAttributionEnabled() { return false; } } @Before Loading Loading
apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java +34 −20 Original line number Diff line number Diff line Loading @@ -804,11 +804,21 @@ class JobConcurrencyManager { @WorkType final int workType) { final List<StateController> controllers = mService.mControllers; final int numControllers = controllers.size(); final PowerManager.WakeLock wl = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, jobStatus.getTag()); wl.setWorkSource(mService.deriveWorkSource( jobStatus.getSourceUid(), jobStatus.getSourcePackageName())); wl.setReferenceCounted(false); // Since the quota controller will start counting from the time prepareForExecutionLocked() // is called, hold a wakelock to make sure the CPU doesn't suspend between that call and // when the service actually starts. wl.acquire(); try { for (int ic = 0; ic < numControllers; ic++) { controllers.get(ic).prepareForExecutionLocked(jobStatus); } final PackageStats packageStats = getPkgStatsLocked(jobStatus.getSourceUserId(), jobStatus.getSourcePackageName()); final PackageStats packageStats = getPkgStatsLocked( jobStatus.getSourceUserId(), jobStatus.getSourcePackageName()); packageStats.adjustStagedCount(false, jobStatus.shouldTreatAsExpeditedJob()); if (!worker.executeRunnableJob(jobStatus, workType)) { Slog.e(TAG, "Error executing " + jobStatus); Loading @@ -821,12 +831,16 @@ class JobConcurrencyManager { mWorkCountTracker.onJobStarted(workType); packageStats.adjustRunningCount(true, jobStatus.shouldTreatAsExpeditedJob()); mActivePkgStats.add( jobStatus.getSourceUserId(), jobStatus.getSourcePackageName(), packageStats); jobStatus.getSourceUserId(), jobStatus.getSourcePackageName(), packageStats); } final List<JobStatus> pendingJobs = mService.mPendingJobs; if (pendingJobs.remove(jobStatus)) { mService.mJobPackageTracker.noteNonpending(jobStatus); } } finally { wl.release(); } } @GuardedBy("mLock") Loading
apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java +12 −2 Original line number Diff line number Diff line Loading @@ -917,8 +917,18 @@ public class JobSchedulerService extends com.android.server.SystemService return mConstants; } public boolean isChainedAttributionEnabled() { return WorkSource.isChainedBatteryAttributionEnabled(getContext()); @NonNull public WorkSource deriveWorkSource(int sourceUid, @Nullable String sourcePackageName) { if (WorkSource.isChainedBatteryAttributionEnabled(getContext())) { WorkSource ws = new WorkSource(); ws.createWorkChain() .addNode(sourceUid, sourcePackageName) .addNode(Process.SYSTEM_UID, "JobScheduler"); return ws; } else { return sourcePackageName == null ? new WorkSource(sourceUid) : new WorkSource(sourceUid, sourcePackageName); } } @Nullable Loading
apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java +9 −33 Original line number Diff line number Diff line Loading @@ -42,7 +42,6 @@ import android.os.Message; import android.os.PowerManager; import android.os.RemoteException; import android.os.UserHandle; import android.os.WorkSource; import android.util.EventLog; import android.util.IndentingPrintWriter; import android.util.Slog; Loading Loading @@ -109,6 +108,7 @@ public final class JobServiceContext implements ServiceConnection { private final Object mLock; private final IBatteryStats mBatteryStats; private final JobPackageTracker mJobPackageTracker; private final PowerManager mPowerManager; private PowerManager.WakeLock mWakeLock; // Execution state. Loading Loading @@ -205,6 +205,7 @@ public final class JobServiceContext implements ServiceConnection { mCallbackHandler = new JobServiceHandler(looper); mJobConcurrencyManager = concurrencyManager; mCompletedListener = service; mPowerManager = mContext.getSystemService(PowerManager.class); mAvailable = true; mVerb = VERB_FINISHED; mPreferredUid = NO_PREFERRED_UID; Loading Loading @@ -271,6 +272,12 @@ public final class JobServiceContext implements ServiceConnection { // it was inflated from disk with not-yet-coherent delay/deadline bounds. job.clearPersistedUtcTimes(); mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, job.getTag()); mWakeLock.setWorkSource( mService.deriveWorkSource(job.getSourceUid(), job.getSourcePackageName())); mWakeLock.setReferenceCounted(false); mWakeLock.acquire(); mVerb = VERB_BINDING; scheduleOpTimeOutLocked(); final Intent intent = new Intent().setComponent(job.getServiceComponent()); Loading Loading @@ -306,6 +313,7 @@ public final class JobServiceContext implements ServiceConnection { mRunningCallback = null; mParams = null; mExecutionStartTimeElapsed = 0L; mWakeLock.release(); mVerb = VERB_FINISHED; removeOpTimeOutLocked(); return false; Loading Loading @@ -495,42 +503,10 @@ public final class JobServiceContext implements ServiceConnection { return; } this.service = IJobService.Stub.asInterface(service); final PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, runningJob.getTag()); wl.setWorkSource(deriveWorkSource(runningJob)); wl.setReferenceCounted(false); wl.acquire(); // We use a new wakelock instance per job. In rare cases there is a race between // teardown following job completion/cancellation and new job service spin-up // such that if we simply assign mWakeLock to be the new instance, we orphan // the currently-live lock instead of cleanly replacing it. Watch for this and // explicitly fast-forward the release if we're in that situation. if (mWakeLock != null) { Slog.w(TAG, "Bound new job " + runningJob + " but live wakelock " + mWakeLock + " tag=" + mWakeLock.getTag()); mWakeLock.release(); } mWakeLock = wl; doServiceBoundLocked(); } } private WorkSource deriveWorkSource(JobStatus runningJob) { final int jobUid = runningJob.getSourceUid(); if (WorkSource.isChainedBatteryAttributionEnabled(mContext)) { WorkSource workSource = new WorkSource(); workSource.createWorkChain() .addNode(jobUid, null) .addNode(android.os.Process.SYSTEM_UID, "JobScheduler"); return workSource; } else { return new WorkSource(jobUid); } } /** If the client service crashes we reschedule this job and clean up. */ @Override public void onServiceDisconnected(ComponentName name) { Loading
apex/jobscheduler/service/java/com/android/server/job/controllers/TimeController.java +6 −22 Original line number Diff line number Diff line Loading @@ -18,11 +18,9 @@ package com.android.server.job.controllers; import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock; import android.annotation.Nullable; import android.app.AlarmManager; import android.app.AlarmManager.OnAlarmListener; import android.content.Context; import android.os.Process; import android.os.UserHandle; import android.os.WorkSource; import android.util.IndentingPrintWriter; Loading Loading @@ -62,8 +60,6 @@ public final class TimeController extends StateController { private long mNextDelayExpiredElapsedMillis; private volatile long mLastFiredDelayExpiredElapsedMillis; private final boolean mChainedAttributionEnabled; private AlarmManager mAlarmService = null; /** List of tracked jobs, sorted asc. by deadline */ private final List<JobStatus> mTrackedJobs = new LinkedList<>(); Loading @@ -73,7 +69,6 @@ public final class TimeController extends StateController { mNextJobExpiredElapsedMillis = Long.MAX_VALUE; mNextDelayExpiredElapsedMillis = Long.MAX_VALUE; mChainedAttributionEnabled = mService.isChainedAttributionEnabled(); } /** Loading Loading @@ -117,7 +112,8 @@ public final class TimeController extends StateController { it.add(job); job.setTrackingController(JobStatus.TRACKING_TIME); WorkSource ws = deriveWorkSource(job.getSourceUid(), job.getSourcePackageName()); WorkSource ws = mService.deriveWorkSource(job.getSourceUid(), job.getSourcePackageName()); // Only update alarms if the job would be ready with the relevant timing constraint // satisfied. Loading Loading @@ -165,7 +161,7 @@ public final class TimeController extends StateController { } else if (wouldBeReadyWithConstraintLocked(job, JobStatus.CONSTRAINT_DEADLINE)) { // This job's deadline is earlier than the current set alarm. Update the alarm. setDeadlineExpiredAlarmLocked(job.getLatestRunTimeElapsed(), deriveWorkSource(job.getSourceUid(), job.getSourcePackageName())); mService.deriveWorkSource(job.getSourceUid(), job.getSourcePackageName())); } } if (job.hasTimingDelayConstraint() Loading @@ -177,7 +173,7 @@ public final class TimeController extends StateController { && wouldBeReadyWithConstraintLocked(job, JobStatus.CONSTRAINT_TIMING_DELAY)) { // This job's delay is earlier than the current set alarm. Update the alarm. setDelayExpiredAlarmLocked(job.getEarliestRunTime(), deriveWorkSource(job.getSourceUid(), job.getSourcePackageName())); mService.deriveWorkSource(job.getSourceUid(), job.getSourcePackageName())); } } } Loading Loading @@ -248,7 +244,7 @@ public final class TimeController extends StateController { } } setDeadlineExpiredAlarmLocked(nextExpiryTime, deriveWorkSource(nextExpiryUid, nextExpiryPackageName)); mService.deriveWorkSource(nextExpiryUid, nextExpiryPackageName)); } } Loading Loading @@ -312,19 +308,7 @@ public final class TimeController extends StateController { mStateChangedListener.onControllerStateChanged(); } setDelayExpiredAlarmLocked(nextDelayTime, deriveWorkSource(nextDelayUid, nextDelayPackageName)); } } private WorkSource deriveWorkSource(int uid, @Nullable String packageName) { if (mChainedAttributionEnabled) { WorkSource ws = new WorkSource(); ws.createWorkChain() .addNode(uid, packageName) .addNode(Process.SYSTEM_UID, "JobScheduler"); return ws; } else { return packageName == null ? new WorkSource(uid) : new WorkSource(uid, packageName); mService.deriveWorkSource(nextDelayUid, nextDelayPackageName)); } } Loading
services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java +0 −5 Original line number Diff line number Diff line Loading @@ -90,11 +90,6 @@ public class JobSchedulerServiceTest { super(context); mAppStateTracker = mock(AppStateTrackerImpl.class); } @Override public boolean isChainedAttributionEnabled() { return false; } } @Before Loading