Loading Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -326,6 +326,7 @@ java_defaults { "tv_tuner_resource_manager_aidl_interface-java", "soundtrigger_middleware-aidl-java", "modules-utils-os", "framework-permission-aidl-java", ], } Loading apex/jobscheduler/framework/java/android/os/PowerExemptionManager.java +24 −1 Original line number Diff line number Diff line Loading @@ -236,7 +236,21 @@ public class PowerExemptionManager { * @hide */ public static final int REASON_BLUETOOTH_BROADCAST = 203; /** * Broadcast {@link android.content.Intent#ACTION_TIMEZONE_CHANGED} * @hide */ public static final int REASON_TIMEZONE_CHANGED = 204; /** * Broadcast {@link android.content.Intent#ACTION_TIME_CHANGED} * @hide */ public static final int REASON_TIME_CHANGED = 205; /** * Broadcast {@link android.content.Intent#ACTION_LOCALE_CHANGED} * @hide */ public static final int REASON_LOCALE_CHANGED = 206; /* Reason code range 300-399 are reserved for other internal reasons */ /** * Device idle system allow list, including EXCEPT-IDLE Loading Loading @@ -369,6 +383,9 @@ public class PowerExemptionManager { REASON_PRE_BOOT_COMPLETED, REASON_LOCKED_BOOT_COMPLETED, REASON_BLUETOOTH_BROADCAST, REASON_TIMEZONE_CHANGED, REASON_TIME_CHANGED, REASON_LOCALE_CHANGED, REASON_SYSTEM_ALLOW_LISTED, REASON_ALARM_MANAGER_ALARM_CLOCK, REASON_ALARM_MANAGER_WHILE_IDLE, Loading Loading @@ -641,6 +658,12 @@ public class PowerExemptionManager { return "LOCKED_BOOT_COMPLETED"; case REASON_BLUETOOTH_BROADCAST: return "BLUETOOTH_BROADCAST"; case REASON_TIMEZONE_CHANGED: return "TIMEZONE_CHANGED"; case REASON_TIME_CHANGED: return "TIME_CHANGED"; case REASON_LOCALE_CHANGED: return "LOCALE_CHANGED"; case REASON_SYSTEM_ALLOW_LISTED: return "SYSTEM_ALLOW_LISTED"; case REASON_ALARM_MANAGER_ALARM_CLOCK: Loading apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java +26 −6 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ import static android.app.AlarmManager.INTERVAL_HOUR; import static android.app.AlarmManager.RTC; import static android.app.AlarmManager.RTC_WAKEUP; import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY; import static android.os.PowerExemptionManager.TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED; import static android.os.PowerWhitelistManager.REASON_ALARM_MANAGER_WHILE_IDLE; import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED; import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED; Loading Loading @@ -81,6 +82,7 @@ import android.os.IBinder; import android.os.Looper; import android.os.Message; import android.os.ParcelableException; import android.os.PowerExemptionManager; import android.os.PowerManager; import android.os.Process; import android.os.RemoteException; Loading Loading @@ -118,6 +120,7 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.IAppOpsCallback; import com.android.internal.app.IAppOpsService; import com.android.internal.os.BinderDeathDispatcher; import com.android.internal.util.DumpUtils; import com.android.internal.util.FrameworkStatsLog; import com.android.internal.util.LocalLog; Loading Loading @@ -202,6 +205,8 @@ public class AlarmManagerService extends SystemService { .addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); private static final BinderDeathDispatcher<IAlarmListener> sListenerDeathDispatcher = new BinderDeathDispatcher<>(); final LocalLog mLog = new LocalLog(TAG); AppOpsManager mAppOps; Loading Loading @@ -292,6 +297,7 @@ public class AlarmManagerService extends SystemService { BroadcastOptions mOptsWithFgs = BroadcastOptions.makeBasic(); BroadcastOptions mOptsWithoutFgs = BroadcastOptions.makeBasic(); BroadcastOptions mOptsTimeBroadcast = BroadcastOptions.makeBasic(); // TODO(b/172085676): Move inside alarm store. private final SparseArray<AlarmManager.AlarmClockInfo> mNextAlarmClockForUser = Loading Loading @@ -1786,7 +1792,12 @@ public class AlarmManagerService extends SystemService { | Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT | Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS); intent.putExtra(Intent.EXTRA_TIMEZONE, zone.getID()); getContext().sendBroadcastAsUser(intent, UserHandle.ALL); mOptsTimeBroadcast.setTemporaryAppAllowlist( mActivityManagerInternal.getBootTimeTempAllowListDuration(), TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED, PowerExemptionManager.REASON_TIMEZONE_CHANGED, ""); getContext().sendBroadcastAsUser(intent, UserHandle.ALL, null /* receiverPermission */, mOptsTimeBroadcast.toBundle()); } } Loading @@ -1809,9 +1820,8 @@ public class AlarmManagerService extends SystemService { } if (directReceiver != null) { try { directReceiver.asBinder().linkToDeath(mListenerDeathRecipient, 0); } catch (RemoteException e) { if (sListenerDeathDispatcher.linkToDeath(directReceiver, mListenerDeathRecipient) <= 0) { Slog.w(TAG, "Dropping unreachable alarm listener " + listenerTag); return; } Loading Loading @@ -2824,6 +2834,12 @@ public class AlarmManagerService extends SystemService { pw.println(); } pw.println("Listener death dispatcher state:"); pw.increaseIndent(); sListenerDeathDispatcher.dump(pw); pw.println(); pw.decreaseIndent(); if (mLog.dump(pw, "Recent problems:")) { pw.println(); } Loading Loading @@ -3929,8 +3945,12 @@ public class AlarmManagerService extends SystemService { | Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND | Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS); getContext().sendBroadcastAsUser(intent, UserHandle.ALL); mOptsTimeBroadcast.setTemporaryAppAllowlist( mActivityManagerInternal.getBootTimeTempAllowListDuration(), TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED, PowerExemptionManager.REASON_TIME_CHANGED, ""); getContext().sendBroadcastAsUser(intent, UserHandle.ALL, null /* receiverPermission */, mOptsTimeBroadcast.toBundle()); // The world has changed on us, so we need to re-evaluate alarms // regardless of whether the kernel has told us one went off. result |= IS_WAKEUP_MASK; Loading apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java +52 −66 Original line number Diff line number Diff line Loading @@ -621,6 +621,7 @@ public final class QuotaController extends StateController { } @Override @GuardedBy("mLock") public void maybeStartTrackingJobLocked(JobStatus jobStatus, JobStatus lastJob) { final long nowElapsed = sElapsedRealtimeClock.millis(); final int userId = jobStatus.getSourceUserId(); Loading Loading @@ -648,6 +649,7 @@ public final class QuotaController extends StateController { } @Override @GuardedBy("mLock") public void prepareForExecutionLocked(JobStatus jobStatus) { if (DEBUG) { Slog.d(TAG, "Prepping for " + jobStatus.toShortString()); Loading Loading @@ -676,6 +678,7 @@ public final class QuotaController extends StateController { } @Override @GuardedBy("mLock") public void unprepareFromExecutionLocked(JobStatus jobStatus) { Timer timer = mPkgTimers.get(jobStatus.getSourceUserId(), jobStatus.getSourcePackageName()); if (timer != null) { Loading @@ -691,6 +694,7 @@ public final class QuotaController extends StateController { } @Override @GuardedBy("mLock") public void maybeStopTrackingJobLocked(JobStatus jobStatus, JobStatus incomingJob, boolean forUpdate) { if (jobStatus.clearTrackingController(JobStatus.TRACKING_QUOTA)) { Loading Loading @@ -796,10 +800,12 @@ public final class QuotaController extends StateController { } /** Returns the maximum amount of time this job could run for. */ @GuardedBy("mLock") public long getMaxJobExecutionTimeMsLocked(@NonNull final JobStatus jobStatus) { if (!jobStatus.shouldTreatAsExpeditedJob()) { // If quota is currently "free", then the job can run for the full amount of time. if (mChargeTracker.isCharging() // If quota is currently "free", then the job can run for the full amount of time, // regardless of bucket (hence using charging instead of isQuotaFreeLocked()). if (mChargeTracker.isChargingLocked() || mTopAppCache.get(jobStatus.getSourceUid()) || isTopStartedJobLocked(jobStatus) || isUidInForeground(jobStatus.getSourceUid())) { Loading @@ -810,7 +816,7 @@ public final class QuotaController extends StateController { } // Expedited job. if (mChargeTracker.isCharging()) { if (mChargeTracker.isChargingLocked()) { return mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS; } if (mTopAppCache.get(jobStatus.getSourceUid()) || isTopStartedJobLocked(jobStatus)) { Loading @@ -828,8 +834,9 @@ public final class QuotaController extends StateController { } /** @return true if the job is within expedited job quota. */ @GuardedBy("mLock") public boolean isWithinEJQuotaLocked(@NonNull final JobStatus jobStatus) { if (isQuotaFree(jobStatus.getEffectiveStandbyBucket())) { if (isQuotaFreeLocked(jobStatus.getEffectiveStandbyBucket())) { return true; } // A job is within quota if one of the following is true: Loading Loading @@ -887,9 +894,10 @@ public final class QuotaController extends StateController { jobStatus.getSourceUserId(), jobStatus.getSourcePackageName(), standbyBucket); } private boolean isQuotaFree(final int standbyBucket) { @GuardedBy("mLock") private boolean isQuotaFreeLocked(final int standbyBucket) { // Quota constraint is not enforced while charging. if (mChargeTracker.isCharging()) { if (mChargeTracker.isChargingLocked()) { // Restricted jobs require additional constraints when charging, so don't immediately // mark quota as free when charging. return standbyBucket != RESTRICTED_INDEX; Loading @@ -898,11 +906,12 @@ public final class QuotaController extends StateController { } @VisibleForTesting @GuardedBy("mLock") boolean isWithinQuotaLocked(final int userId, @NonNull final String packageName, final int standbyBucket) { if (standbyBucket == NEVER_INDEX) return false; if (isQuotaFree(standbyBucket)) return true; if (isQuotaFreeLocked(standbyBucket)) return true; ExecutionStats stats = getExecutionStatsLocked(userId, packageName, standbyBucket); return getRemainingExecutionTimeLocked(stats) > 0 Loading Loading @@ -1493,14 +1502,13 @@ public final class QuotaController extends StateController { /** Schedule a cleanup alarm if necessary and there isn't already one scheduled. */ @VisibleForTesting void maybeScheduleCleanupAlarmLocked() { final long nowElapsed = sElapsedRealtimeClock.millis(); if (mNextCleanupTimeElapsed > nowElapsed) { if (mNextCleanupTimeElapsed > sElapsedRealtimeClock.millis()) { // There's already an alarm scheduled. Just stick with that one. There's no way we'll // end up scheduling an earlier alarm. if (DEBUG) { Slog.v(TAG, "Not scheduling cleanup since there's already one at " + mNextCleanupTimeElapsed + " (in " + (mNextCleanupTimeElapsed - nowElapsed) + "ms)"); + mNextCleanupTimeElapsed + " (in " + (mNextCleanupTimeElapsed - sElapsedRealtimeClock.millis()) + "ms)"); } return; } Loading @@ -1522,7 +1530,7 @@ public final class QuotaController extends StateController { if (nextCleanupElapsed - mNextCleanupTimeElapsed <= 10 * MINUTE_IN_MILLIS) { // No need to clean up too often. Delay the alarm if the next cleanup would be too soon // after it. nextCleanupElapsed = mNextCleanupTimeElapsed + 10 * MINUTE_IN_MILLIS; nextCleanupElapsed += 10 * MINUTE_IN_MILLIS; } mNextCleanupTimeElapsed = nextCleanupElapsed; mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, nextCleanupElapsed, ALARM_TAG_CLEANUP, Loading Loading @@ -1557,9 +1565,9 @@ public final class QuotaController extends StateController { private void handleNewChargingStateLocked() { mTimerChargingUpdateFunctor.setStatus(sElapsedRealtimeClock.millis(), mChargeTracker.isCharging()); mChargeTracker.isChargingLocked()); if (DEBUG) { Slog.d(TAG, "handleNewChargingStateLocked: " + mChargeTracker.isCharging()); Slog.d(TAG, "handleNewChargingStateLocked: " + mChargeTracker.isChargingLocked()); } // Deal with Timers first. mEJPkgTimers.forEach(mTimerChargingUpdateFunctor); Loading Loading @@ -1828,6 +1836,7 @@ public final class QuotaController extends StateController { * Track whether we're charging. This has a slightly different definition than that of * BatteryController. */ @GuardedBy("mLock") private boolean mCharging; ChargingTracker() { Loading @@ -1847,7 +1856,8 @@ public final class QuotaController extends StateController { mCharging = batteryManagerInternal.isPowered(BatteryManager.BATTERY_PLUGGED_ANY); } public boolean isCharging() { @GuardedBy("mLock") public boolean isChargingLocked() { return mCharging; } Loading Loading @@ -2056,9 +2066,12 @@ public final class QuotaController extends StateController { } return; } if (mRunningBgJobs.remove(jobStatus) && !mChargeTracker.isCharging() && mRunningBgJobs.size() == 0) { emitSessionLocked(sElapsedRealtimeClock.millis()); final long nowElapsed = sElapsedRealtimeClock.millis(); final int standbyBucket = JobSchedulerService.standbyBucketForPackage( mPkg.packageName, mPkg.userId, nowElapsed); if (mRunningBgJobs.remove(jobStatus) && mRunningBgJobs.size() == 0 && !isQuotaFreeLocked(standbyBucket)) { emitSessionLocked(nowElapsed); cancelCutoff(); } } Loading @@ -2078,6 +2091,7 @@ public final class QuotaController extends StateController { cancelCutoff(); } @GuardedBy("mLock") private void emitSessionLocked(long nowElapsed) { if (mBgJobCount <= 0) { // Nothing to emit. Loading Loading @@ -2122,6 +2136,7 @@ public final class QuotaController extends StateController { } } @GuardedBy("mLock") private boolean shouldTrackLocked() { final long nowElapsed = sElapsedRealtimeClock.millis(); final int standbyBucket = JobSchedulerService.standbyBucketForPackage(mPkg.packageName, Loading @@ -2133,7 +2148,7 @@ public final class QuotaController extends StateController { final long topAppGracePeriodEndElapsed = mTopAppGraceCache.get(mUid); final boolean hasTopAppExemption = !mRegularJobTimer && (mTopAppCache.get(mUid) || nowElapsed < topAppGracePeriodEndElapsed); return (standbyBucket == RESTRICTED_INDEX || !mChargeTracker.isCharging()) return !isQuotaFreeLocked(standbyBucket) && !mForegroundUids.get(mUid) && !hasTempAllowlistExemption && !hasTopAppExemption; } Loading Loading @@ -2463,60 +2478,30 @@ public final class QuotaController extends StateController { } } private static final class TimingSessionTooOldPredicate implements Predicate<TimingSession> { private long mNowElapsed; private void updateNow() { mNowElapsed = sElapsedRealtimeClock.millis(); } @Override private final class DeleteTimingSessionsFunctor implements Consumer<List<TimingSession>> { private final Predicate<TimingSession> mTooOld = new Predicate<TimingSession>() { public boolean test(TimingSession ts) { return ts.endTimeElapsed <= mNowElapsed - MAX_PERIOD_MS; } return ts.endTimeElapsed <= sElapsedRealtimeClock.millis() - MAX_PERIOD_MS; } }; private final TimingSessionTooOldPredicate mTimingSessionTooOld = new TimingSessionTooOldPredicate(); private final Consumer<List<TimingSession>> mDeleteOldSessionsFunctor = sessions -> { @Override public void accept(List<TimingSession> sessions) { if (sessions != null) { // Remove everything older than MAX_PERIOD_MS time ago. sessions.removeIf(mTimingSessionTooOld); sessions.removeIf(mTooOld); } }; } } private final DeleteTimingSessionsFunctor mDeleteOldSessionsFunctor = new DeleteTimingSessionsFunctor(); @VisibleForTesting void deleteObsoleteSessionsLocked() { mTimingSessionTooOld.updateNow(); // Regular sessions mTimingSessions.forEach(mDeleteOldSessionsFunctor); // EJ sessions for (int uIdx = 0; uIdx < mEJTimingSessions.numMaps(); ++uIdx) { final int userId = mEJTimingSessions.keyAt(uIdx); for (int pIdx = 0; pIdx < mEJTimingSessions.numElementsForKey(userId); ++pIdx) { final String packageName = mEJTimingSessions.keyAt(uIdx, pIdx); final ShrinkableDebits debits = getEJDebitsLocked(userId, packageName); final List<TimingSession> sessions = mEJTimingSessions.get(userId, packageName); if (sessions == null) { continue; } while (sessions.size() > 0) { final TimingSession ts = sessions.get(0); if (mTimingSessionTooOld.test(ts)) { // Stale sessions may still be factored into tally. Remove them. final long duration = ts.endTimeElapsed - ts.startTimeElapsed; debits.transactLocked(-duration); sessions.remove(0); } else { break; } } } } // Don't delete EJ timing sessions here. They'll be removed in // getRemainingEJExecutionTimeLocked(). } private class QcHandler extends Handler { Loading Loading @@ -4085,7 +4070,7 @@ public final class QuotaController extends StateController { @Override public void dumpControllerStateLocked(final IndentingPrintWriter pw, final Predicate<JobStatus> predicate) { pw.println("Is charging: " + mChargeTracker.isCharging()); pw.println("Is charging: " + mChargeTracker.isChargingLocked()); pw.println("Current elapsed time: " + sElapsedRealtimeClock.millis()); pw.println(); Loading Loading @@ -4262,7 +4247,8 @@ public final class QuotaController extends StateController { final long token = proto.start(fieldId); final long mToken = proto.start(StateControllerProto.QUOTA); proto.write(StateControllerProto.QuotaController.IS_CHARGING, mChargeTracker.isCharging()); proto.write(StateControllerProto.QuotaController.IS_CHARGING, mChargeTracker.isChargingLocked()); proto.write(StateControllerProto.QuotaController.ELAPSED_REALTIME, sElapsedRealtimeClock.millis()); Loading apex/jobscheduler/service/java/com/android/server/job/controllers/idle/DeviceIdlenessTracker.java +3 −3 Original line number Diff line number Diff line Loading @@ -56,7 +56,7 @@ public final class DeviceIdlenessTracker extends BroadcastReceiver implements Id private boolean mDockIdle; private boolean mProjectionActive; private IdlenessListener mIdleListener; private final UiModeManager.OnProjectionStateChangeListener mOnProjectionStateChangeListener = private final UiModeManager.OnProjectionStateChangedListener mOnProjectionStateChangedListener = this::onProjectionStateChanged; private AlarmManager.OnAlarmListener mIdleAlarmListener = () -> { Loading Loading @@ -105,9 +105,9 @@ public final class DeviceIdlenessTracker extends BroadcastReceiver implements Id // TODO(b/172579710): Move the callbacks off the main executor and on to // JobSchedulerBackgroundThread.getExecutor() once synchronization is fixed in this class. context.getSystemService(UiModeManager.class).addOnProjectionStateChangeListener( context.getSystemService(UiModeManager.class).addOnProjectionStateChangedListener( UiModeManager.PROJECTION_TYPE_ALL, context.getMainExecutor(), mOnProjectionStateChangeListener); mOnProjectionStateChangedListener); } private void onProjectionStateChanged(@UiModeManager.ProjectionType int activeProjectionTypes, Loading Loading
Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -326,6 +326,7 @@ java_defaults { "tv_tuner_resource_manager_aidl_interface-java", "soundtrigger_middleware-aidl-java", "modules-utils-os", "framework-permission-aidl-java", ], } Loading
apex/jobscheduler/framework/java/android/os/PowerExemptionManager.java +24 −1 Original line number Diff line number Diff line Loading @@ -236,7 +236,21 @@ public class PowerExemptionManager { * @hide */ public static final int REASON_BLUETOOTH_BROADCAST = 203; /** * Broadcast {@link android.content.Intent#ACTION_TIMEZONE_CHANGED} * @hide */ public static final int REASON_TIMEZONE_CHANGED = 204; /** * Broadcast {@link android.content.Intent#ACTION_TIME_CHANGED} * @hide */ public static final int REASON_TIME_CHANGED = 205; /** * Broadcast {@link android.content.Intent#ACTION_LOCALE_CHANGED} * @hide */ public static final int REASON_LOCALE_CHANGED = 206; /* Reason code range 300-399 are reserved for other internal reasons */ /** * Device idle system allow list, including EXCEPT-IDLE Loading Loading @@ -369,6 +383,9 @@ public class PowerExemptionManager { REASON_PRE_BOOT_COMPLETED, REASON_LOCKED_BOOT_COMPLETED, REASON_BLUETOOTH_BROADCAST, REASON_TIMEZONE_CHANGED, REASON_TIME_CHANGED, REASON_LOCALE_CHANGED, REASON_SYSTEM_ALLOW_LISTED, REASON_ALARM_MANAGER_ALARM_CLOCK, REASON_ALARM_MANAGER_WHILE_IDLE, Loading Loading @@ -641,6 +658,12 @@ public class PowerExemptionManager { return "LOCKED_BOOT_COMPLETED"; case REASON_BLUETOOTH_BROADCAST: return "BLUETOOTH_BROADCAST"; case REASON_TIMEZONE_CHANGED: return "TIMEZONE_CHANGED"; case REASON_TIME_CHANGED: return "TIME_CHANGED"; case REASON_LOCALE_CHANGED: return "LOCALE_CHANGED"; case REASON_SYSTEM_ALLOW_LISTED: return "SYSTEM_ALLOW_LISTED"; case REASON_ALARM_MANAGER_ALARM_CLOCK: Loading
apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java +26 −6 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ import static android.app.AlarmManager.INTERVAL_HOUR; import static android.app.AlarmManager.RTC; import static android.app.AlarmManager.RTC_WAKEUP; import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY; import static android.os.PowerExemptionManager.TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED; import static android.os.PowerWhitelistManager.REASON_ALARM_MANAGER_WHILE_IDLE; import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED; import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED; Loading Loading @@ -81,6 +82,7 @@ import android.os.IBinder; import android.os.Looper; import android.os.Message; import android.os.ParcelableException; import android.os.PowerExemptionManager; import android.os.PowerManager; import android.os.Process; import android.os.RemoteException; Loading Loading @@ -118,6 +120,7 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.IAppOpsCallback; import com.android.internal.app.IAppOpsService; import com.android.internal.os.BinderDeathDispatcher; import com.android.internal.util.DumpUtils; import com.android.internal.util.FrameworkStatsLog; import com.android.internal.util.LocalLog; Loading Loading @@ -202,6 +205,8 @@ public class AlarmManagerService extends SystemService { .addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); private static final BinderDeathDispatcher<IAlarmListener> sListenerDeathDispatcher = new BinderDeathDispatcher<>(); final LocalLog mLog = new LocalLog(TAG); AppOpsManager mAppOps; Loading Loading @@ -292,6 +297,7 @@ public class AlarmManagerService extends SystemService { BroadcastOptions mOptsWithFgs = BroadcastOptions.makeBasic(); BroadcastOptions mOptsWithoutFgs = BroadcastOptions.makeBasic(); BroadcastOptions mOptsTimeBroadcast = BroadcastOptions.makeBasic(); // TODO(b/172085676): Move inside alarm store. private final SparseArray<AlarmManager.AlarmClockInfo> mNextAlarmClockForUser = Loading Loading @@ -1786,7 +1792,12 @@ public class AlarmManagerService extends SystemService { | Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT | Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS); intent.putExtra(Intent.EXTRA_TIMEZONE, zone.getID()); getContext().sendBroadcastAsUser(intent, UserHandle.ALL); mOptsTimeBroadcast.setTemporaryAppAllowlist( mActivityManagerInternal.getBootTimeTempAllowListDuration(), TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED, PowerExemptionManager.REASON_TIMEZONE_CHANGED, ""); getContext().sendBroadcastAsUser(intent, UserHandle.ALL, null /* receiverPermission */, mOptsTimeBroadcast.toBundle()); } } Loading @@ -1809,9 +1820,8 @@ public class AlarmManagerService extends SystemService { } if (directReceiver != null) { try { directReceiver.asBinder().linkToDeath(mListenerDeathRecipient, 0); } catch (RemoteException e) { if (sListenerDeathDispatcher.linkToDeath(directReceiver, mListenerDeathRecipient) <= 0) { Slog.w(TAG, "Dropping unreachable alarm listener " + listenerTag); return; } Loading Loading @@ -2824,6 +2834,12 @@ public class AlarmManagerService extends SystemService { pw.println(); } pw.println("Listener death dispatcher state:"); pw.increaseIndent(); sListenerDeathDispatcher.dump(pw); pw.println(); pw.decreaseIndent(); if (mLog.dump(pw, "Recent problems:")) { pw.println(); } Loading Loading @@ -3929,8 +3945,12 @@ public class AlarmManagerService extends SystemService { | Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND | Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS); getContext().sendBroadcastAsUser(intent, UserHandle.ALL); mOptsTimeBroadcast.setTemporaryAppAllowlist( mActivityManagerInternal.getBootTimeTempAllowListDuration(), TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED, PowerExemptionManager.REASON_TIME_CHANGED, ""); getContext().sendBroadcastAsUser(intent, UserHandle.ALL, null /* receiverPermission */, mOptsTimeBroadcast.toBundle()); // The world has changed on us, so we need to re-evaluate alarms // regardless of whether the kernel has told us one went off. result |= IS_WAKEUP_MASK; Loading
apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java +52 −66 Original line number Diff line number Diff line Loading @@ -621,6 +621,7 @@ public final class QuotaController extends StateController { } @Override @GuardedBy("mLock") public void maybeStartTrackingJobLocked(JobStatus jobStatus, JobStatus lastJob) { final long nowElapsed = sElapsedRealtimeClock.millis(); final int userId = jobStatus.getSourceUserId(); Loading Loading @@ -648,6 +649,7 @@ public final class QuotaController extends StateController { } @Override @GuardedBy("mLock") public void prepareForExecutionLocked(JobStatus jobStatus) { if (DEBUG) { Slog.d(TAG, "Prepping for " + jobStatus.toShortString()); Loading Loading @@ -676,6 +678,7 @@ public final class QuotaController extends StateController { } @Override @GuardedBy("mLock") public void unprepareFromExecutionLocked(JobStatus jobStatus) { Timer timer = mPkgTimers.get(jobStatus.getSourceUserId(), jobStatus.getSourcePackageName()); if (timer != null) { Loading @@ -691,6 +694,7 @@ public final class QuotaController extends StateController { } @Override @GuardedBy("mLock") public void maybeStopTrackingJobLocked(JobStatus jobStatus, JobStatus incomingJob, boolean forUpdate) { if (jobStatus.clearTrackingController(JobStatus.TRACKING_QUOTA)) { Loading Loading @@ -796,10 +800,12 @@ public final class QuotaController extends StateController { } /** Returns the maximum amount of time this job could run for. */ @GuardedBy("mLock") public long getMaxJobExecutionTimeMsLocked(@NonNull final JobStatus jobStatus) { if (!jobStatus.shouldTreatAsExpeditedJob()) { // If quota is currently "free", then the job can run for the full amount of time. if (mChargeTracker.isCharging() // If quota is currently "free", then the job can run for the full amount of time, // regardless of bucket (hence using charging instead of isQuotaFreeLocked()). if (mChargeTracker.isChargingLocked() || mTopAppCache.get(jobStatus.getSourceUid()) || isTopStartedJobLocked(jobStatus) || isUidInForeground(jobStatus.getSourceUid())) { Loading @@ -810,7 +816,7 @@ public final class QuotaController extends StateController { } // Expedited job. if (mChargeTracker.isCharging()) { if (mChargeTracker.isChargingLocked()) { return mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS; } if (mTopAppCache.get(jobStatus.getSourceUid()) || isTopStartedJobLocked(jobStatus)) { Loading @@ -828,8 +834,9 @@ public final class QuotaController extends StateController { } /** @return true if the job is within expedited job quota. */ @GuardedBy("mLock") public boolean isWithinEJQuotaLocked(@NonNull final JobStatus jobStatus) { if (isQuotaFree(jobStatus.getEffectiveStandbyBucket())) { if (isQuotaFreeLocked(jobStatus.getEffectiveStandbyBucket())) { return true; } // A job is within quota if one of the following is true: Loading Loading @@ -887,9 +894,10 @@ public final class QuotaController extends StateController { jobStatus.getSourceUserId(), jobStatus.getSourcePackageName(), standbyBucket); } private boolean isQuotaFree(final int standbyBucket) { @GuardedBy("mLock") private boolean isQuotaFreeLocked(final int standbyBucket) { // Quota constraint is not enforced while charging. if (mChargeTracker.isCharging()) { if (mChargeTracker.isChargingLocked()) { // Restricted jobs require additional constraints when charging, so don't immediately // mark quota as free when charging. return standbyBucket != RESTRICTED_INDEX; Loading @@ -898,11 +906,12 @@ public final class QuotaController extends StateController { } @VisibleForTesting @GuardedBy("mLock") boolean isWithinQuotaLocked(final int userId, @NonNull final String packageName, final int standbyBucket) { if (standbyBucket == NEVER_INDEX) return false; if (isQuotaFree(standbyBucket)) return true; if (isQuotaFreeLocked(standbyBucket)) return true; ExecutionStats stats = getExecutionStatsLocked(userId, packageName, standbyBucket); return getRemainingExecutionTimeLocked(stats) > 0 Loading Loading @@ -1493,14 +1502,13 @@ public final class QuotaController extends StateController { /** Schedule a cleanup alarm if necessary and there isn't already one scheduled. */ @VisibleForTesting void maybeScheduleCleanupAlarmLocked() { final long nowElapsed = sElapsedRealtimeClock.millis(); if (mNextCleanupTimeElapsed > nowElapsed) { if (mNextCleanupTimeElapsed > sElapsedRealtimeClock.millis()) { // There's already an alarm scheduled. Just stick with that one. There's no way we'll // end up scheduling an earlier alarm. if (DEBUG) { Slog.v(TAG, "Not scheduling cleanup since there's already one at " + mNextCleanupTimeElapsed + " (in " + (mNextCleanupTimeElapsed - nowElapsed) + "ms)"); + mNextCleanupTimeElapsed + " (in " + (mNextCleanupTimeElapsed - sElapsedRealtimeClock.millis()) + "ms)"); } return; } Loading @@ -1522,7 +1530,7 @@ public final class QuotaController extends StateController { if (nextCleanupElapsed - mNextCleanupTimeElapsed <= 10 * MINUTE_IN_MILLIS) { // No need to clean up too often. Delay the alarm if the next cleanup would be too soon // after it. nextCleanupElapsed = mNextCleanupTimeElapsed + 10 * MINUTE_IN_MILLIS; nextCleanupElapsed += 10 * MINUTE_IN_MILLIS; } mNextCleanupTimeElapsed = nextCleanupElapsed; mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, nextCleanupElapsed, ALARM_TAG_CLEANUP, Loading Loading @@ -1557,9 +1565,9 @@ public final class QuotaController extends StateController { private void handleNewChargingStateLocked() { mTimerChargingUpdateFunctor.setStatus(sElapsedRealtimeClock.millis(), mChargeTracker.isCharging()); mChargeTracker.isChargingLocked()); if (DEBUG) { Slog.d(TAG, "handleNewChargingStateLocked: " + mChargeTracker.isCharging()); Slog.d(TAG, "handleNewChargingStateLocked: " + mChargeTracker.isChargingLocked()); } // Deal with Timers first. mEJPkgTimers.forEach(mTimerChargingUpdateFunctor); Loading Loading @@ -1828,6 +1836,7 @@ public final class QuotaController extends StateController { * Track whether we're charging. This has a slightly different definition than that of * BatteryController. */ @GuardedBy("mLock") private boolean mCharging; ChargingTracker() { Loading @@ -1847,7 +1856,8 @@ public final class QuotaController extends StateController { mCharging = batteryManagerInternal.isPowered(BatteryManager.BATTERY_PLUGGED_ANY); } public boolean isCharging() { @GuardedBy("mLock") public boolean isChargingLocked() { return mCharging; } Loading Loading @@ -2056,9 +2066,12 @@ public final class QuotaController extends StateController { } return; } if (mRunningBgJobs.remove(jobStatus) && !mChargeTracker.isCharging() && mRunningBgJobs.size() == 0) { emitSessionLocked(sElapsedRealtimeClock.millis()); final long nowElapsed = sElapsedRealtimeClock.millis(); final int standbyBucket = JobSchedulerService.standbyBucketForPackage( mPkg.packageName, mPkg.userId, nowElapsed); if (mRunningBgJobs.remove(jobStatus) && mRunningBgJobs.size() == 0 && !isQuotaFreeLocked(standbyBucket)) { emitSessionLocked(nowElapsed); cancelCutoff(); } } Loading @@ -2078,6 +2091,7 @@ public final class QuotaController extends StateController { cancelCutoff(); } @GuardedBy("mLock") private void emitSessionLocked(long nowElapsed) { if (mBgJobCount <= 0) { // Nothing to emit. Loading Loading @@ -2122,6 +2136,7 @@ public final class QuotaController extends StateController { } } @GuardedBy("mLock") private boolean shouldTrackLocked() { final long nowElapsed = sElapsedRealtimeClock.millis(); final int standbyBucket = JobSchedulerService.standbyBucketForPackage(mPkg.packageName, Loading @@ -2133,7 +2148,7 @@ public final class QuotaController extends StateController { final long topAppGracePeriodEndElapsed = mTopAppGraceCache.get(mUid); final boolean hasTopAppExemption = !mRegularJobTimer && (mTopAppCache.get(mUid) || nowElapsed < topAppGracePeriodEndElapsed); return (standbyBucket == RESTRICTED_INDEX || !mChargeTracker.isCharging()) return !isQuotaFreeLocked(standbyBucket) && !mForegroundUids.get(mUid) && !hasTempAllowlistExemption && !hasTopAppExemption; } Loading Loading @@ -2463,60 +2478,30 @@ public final class QuotaController extends StateController { } } private static final class TimingSessionTooOldPredicate implements Predicate<TimingSession> { private long mNowElapsed; private void updateNow() { mNowElapsed = sElapsedRealtimeClock.millis(); } @Override private final class DeleteTimingSessionsFunctor implements Consumer<List<TimingSession>> { private final Predicate<TimingSession> mTooOld = new Predicate<TimingSession>() { public boolean test(TimingSession ts) { return ts.endTimeElapsed <= mNowElapsed - MAX_PERIOD_MS; } return ts.endTimeElapsed <= sElapsedRealtimeClock.millis() - MAX_PERIOD_MS; } }; private final TimingSessionTooOldPredicate mTimingSessionTooOld = new TimingSessionTooOldPredicate(); private final Consumer<List<TimingSession>> mDeleteOldSessionsFunctor = sessions -> { @Override public void accept(List<TimingSession> sessions) { if (sessions != null) { // Remove everything older than MAX_PERIOD_MS time ago. sessions.removeIf(mTimingSessionTooOld); sessions.removeIf(mTooOld); } }; } } private final DeleteTimingSessionsFunctor mDeleteOldSessionsFunctor = new DeleteTimingSessionsFunctor(); @VisibleForTesting void deleteObsoleteSessionsLocked() { mTimingSessionTooOld.updateNow(); // Regular sessions mTimingSessions.forEach(mDeleteOldSessionsFunctor); // EJ sessions for (int uIdx = 0; uIdx < mEJTimingSessions.numMaps(); ++uIdx) { final int userId = mEJTimingSessions.keyAt(uIdx); for (int pIdx = 0; pIdx < mEJTimingSessions.numElementsForKey(userId); ++pIdx) { final String packageName = mEJTimingSessions.keyAt(uIdx, pIdx); final ShrinkableDebits debits = getEJDebitsLocked(userId, packageName); final List<TimingSession> sessions = mEJTimingSessions.get(userId, packageName); if (sessions == null) { continue; } while (sessions.size() > 0) { final TimingSession ts = sessions.get(0); if (mTimingSessionTooOld.test(ts)) { // Stale sessions may still be factored into tally. Remove them. final long duration = ts.endTimeElapsed - ts.startTimeElapsed; debits.transactLocked(-duration); sessions.remove(0); } else { break; } } } } // Don't delete EJ timing sessions here. They'll be removed in // getRemainingEJExecutionTimeLocked(). } private class QcHandler extends Handler { Loading Loading @@ -4085,7 +4070,7 @@ public final class QuotaController extends StateController { @Override public void dumpControllerStateLocked(final IndentingPrintWriter pw, final Predicate<JobStatus> predicate) { pw.println("Is charging: " + mChargeTracker.isCharging()); pw.println("Is charging: " + mChargeTracker.isChargingLocked()); pw.println("Current elapsed time: " + sElapsedRealtimeClock.millis()); pw.println(); Loading Loading @@ -4262,7 +4247,8 @@ public final class QuotaController extends StateController { final long token = proto.start(fieldId); final long mToken = proto.start(StateControllerProto.QUOTA); proto.write(StateControllerProto.QuotaController.IS_CHARGING, mChargeTracker.isCharging()); proto.write(StateControllerProto.QuotaController.IS_CHARGING, mChargeTracker.isChargingLocked()); proto.write(StateControllerProto.QuotaController.ELAPSED_REALTIME, sElapsedRealtimeClock.millis()); Loading
apex/jobscheduler/service/java/com/android/server/job/controllers/idle/DeviceIdlenessTracker.java +3 −3 Original line number Diff line number Diff line Loading @@ -56,7 +56,7 @@ public final class DeviceIdlenessTracker extends BroadcastReceiver implements Id private boolean mDockIdle; private boolean mProjectionActive; private IdlenessListener mIdleListener; private final UiModeManager.OnProjectionStateChangeListener mOnProjectionStateChangeListener = private final UiModeManager.OnProjectionStateChangedListener mOnProjectionStateChangedListener = this::onProjectionStateChanged; private AlarmManager.OnAlarmListener mIdleAlarmListener = () -> { Loading Loading @@ -105,9 +105,9 @@ public final class DeviceIdlenessTracker extends BroadcastReceiver implements Id // TODO(b/172579710): Move the callbacks off the main executor and on to // JobSchedulerBackgroundThread.getExecutor() once synchronization is fixed in this class. context.getSystemService(UiModeManager.class).addOnProjectionStateChangeListener( context.getSystemService(UiModeManager.class).addOnProjectionStateChangedListener( UiModeManager.PROJECTION_TYPE_ALL, context.getMainExecutor(), mOnProjectionStateChangeListener); mOnProjectionStateChangedListener); } private void onProjectionStateChanged(@UiModeManager.ProjectionType int activeProjectionTypes, Loading