diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java index c053b2ed5adbe..92068e516207e 100644 --- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java +++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java @@ -673,9 +673,6 @@ public class AlarmManagerService extends SystemService { private static final String KEY_APP_STANDBY_RESTRICTED_WINDOW = "app_standby_restricted_window"; - @VisibleForTesting - static final String KEY_LAZY_BATCHING = "lazy_batching"; - private static final String KEY_TIME_TICK_ALLOWED_WHILE_IDLE = "time_tick_allowed_while_idle"; @@ -725,7 +722,6 @@ public class AlarmManagerService extends SystemService { private static final int DEFAULT_APP_STANDBY_RESTRICTED_QUOTA = 1; private static final long DEFAULT_APP_STANDBY_RESTRICTED_WINDOW = INTERVAL_DAY; - private static final boolean DEFAULT_LAZY_BATCHING = true; private static final boolean DEFAULT_TIME_TICK_ALLOWED_WHILE_IDLE = true; /** @@ -772,7 +768,6 @@ public class AlarmManagerService extends SystemService { public int APP_STANDBY_RESTRICTED_QUOTA = DEFAULT_APP_STANDBY_RESTRICTED_QUOTA; public long APP_STANDBY_RESTRICTED_WINDOW = DEFAULT_APP_STANDBY_RESTRICTED_WINDOW; - public boolean LAZY_BATCHING = DEFAULT_LAZY_BATCHING; public boolean TIME_TICK_ALLOWED_WHILE_IDLE = DEFAULT_TIME_TICK_ALLOWED_WHILE_IDLE; public int ALLOW_WHILE_IDLE_QUOTA = DEFAULT_ALLOW_WHILE_IDLE_QUOTA; @@ -976,14 +971,6 @@ public class AlarmManagerService extends SystemService { case KEY_APP_STANDBY_RESTRICTED_WINDOW: updateStandbyWindowsLocked(); break; - case KEY_LAZY_BATCHING: - final boolean oldLazyBatching = LAZY_BATCHING; - LAZY_BATCHING = properties.getBoolean( - KEY_LAZY_BATCHING, DEFAULT_LAZY_BATCHING); - if (oldLazyBatching != LAZY_BATCHING) { - migrateAlarmsToNewStoreLocked(); - } - break; case KEY_TIME_TICK_ALLOWED_WHILE_IDLE: TIME_TICK_ALLOWED_WHILE_IDLE = properties.getBoolean( KEY_TIME_TICK_ALLOWED_WHILE_IDLE, @@ -1094,15 +1081,6 @@ public class AlarmManagerService extends SystemService { } } - private void migrateAlarmsToNewStoreLocked() { - final AlarmStore newStore = LAZY_BATCHING ? new LazyAlarmStore() - : new BatchingAlarmStore(); - final ArrayList allAlarms = mAlarmStore.remove((unused) -> true); - newStore.addAll(allAlarms); - mAlarmStore = newStore; - mAlarmStore.setAlarmClockRemovalListener(mAlarmClockUpdater); - } - private void updateDeviceIdleFuzzBoundaries() { final DeviceConfig.Properties properties = DeviceConfig.getProperties( DeviceConfig.NAMESPACE_ALARM_MANAGER, @@ -1240,9 +1218,6 @@ public class AlarmManagerService extends SystemService { TimeUtils.formatDuration(APP_STANDBY_RESTRICTED_WINDOW, pw); pw.println(); - pw.print(KEY_LAZY_BATCHING, LAZY_BATCHING); - pw.println(); - pw.print(KEY_TIME_TICK_ALLOWED_WHILE_IDLE, TIME_TICK_ALLOWED_WHILE_IDLE); pw.println(); @@ -1878,8 +1853,7 @@ public class AlarmManagerService extends SystemService { mHandler = new AlarmHandler(); mConstants = new Constants(mHandler); - mAlarmStore = mConstants.LAZY_BATCHING ? new LazyAlarmStore() - : new BatchingAlarmStore(); + mAlarmStore = new LazyAlarmStore(); mAlarmStore.setAlarmClockRemovalListener(mAlarmClockUpdater); mAppWakeupHistory = new AppWakeupHistory(Constants.DEFAULT_APP_STANDBY_WINDOW); diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/BatchingAlarmStore.java b/apex/jobscheduler/service/java/com/android/server/alarm/BatchingAlarmStore.java deleted file mode 100644 index 1a4efb8ffcd9d..0000000000000 --- a/apex/jobscheduler/service/java/com/android/server/alarm/BatchingAlarmStore.java +++ /dev/null @@ -1,408 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.alarm; - -import static com.android.server.alarm.AlarmManagerService.DEBUG_BATCH; -import static com.android.server.alarm.AlarmManagerService.clampPositive; -import static com.android.server.alarm.AlarmManagerService.dumpAlarmList; -import static com.android.server.alarm.AlarmManagerService.isTimeTickAlarm; - -import android.app.AlarmManager; -import android.util.IndentingPrintWriter; -import android.util.Slog; -import android.util.proto.ProtoOutputStream; - -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.StatLogger; - -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.function.Predicate; - -/** - * Batching implementation of an Alarm Store. - * This keeps the alarms in batches, which are sorted on the start time of their delivery window. - */ -public class BatchingAlarmStore implements AlarmStore { - @VisibleForTesting - static final String TAG = BatchingAlarmStore.class.getSimpleName(); - - private final ArrayList mAlarmBatches = new ArrayList<>(); - private int mSize; - private Runnable mOnAlarmClockRemoved; - - interface Stats { - int REBATCH_ALL_ALARMS = 0; - int GET_COUNT = 1; - } - - final StatLogger mStatLogger = new StatLogger(TAG + " stats", new String[]{ - "REBATCH_ALL_ALARMS", - "GET_COUNT", - }); - - private static final Comparator sBatchOrder = Comparator.comparingLong(b -> b.mStart); - - private static final Comparator sIncreasingTimeOrder = Comparator.comparingLong( - Alarm::getWhenElapsed); - - @Override - public void add(Alarm a) { - insertAndBatchAlarm(a); - mSize++; - } - - @Override - public void addAll(ArrayList alarms) { - if (alarms == null) { - return; - } - for (final Alarm a : alarms) { - add(a); - } - } - - @Override - public ArrayList remove(Predicate whichAlarms) { - final ArrayList removed = new ArrayList<>(); - for (int i = mAlarmBatches.size() - 1; i >= 0; i--) { - final Batch b = mAlarmBatches.get(i); - removed.addAll(b.remove(whichAlarms)); - if (b.size() == 0) { - mAlarmBatches.remove(i); - } - } - if (!removed.isEmpty()) { - mSize -= removed.size(); - // Not needed if only whole batches were removed, but keeping existing behavior. - rebatchAllAlarms(); - } - return removed; - } - - @Override - public void setAlarmClockRemovalListener(Runnable listener) { - mOnAlarmClockRemoved = listener; - } - - @Override - public Alarm getNextWakeFromIdleAlarm() { - for (final Batch batch : mAlarmBatches) { - if ((batch.mFlags & AlarmManager.FLAG_WAKE_FROM_IDLE) == 0) { - continue; - } - for (int i = 0; i < batch.size(); i++) { - final Alarm a = batch.get(i); - if ((a.flags & AlarmManager.FLAG_WAKE_FROM_IDLE) != 0) { - return a; - } - } - } - return null; - } - - private void rebatchAllAlarms() { - final long start = mStatLogger.getTime(); - final ArrayList oldBatches = (ArrayList) mAlarmBatches.clone(); - mAlarmBatches.clear(); - for (final Batch batch : oldBatches) { - for (int i = 0; i < batch.size(); i++) { - insertAndBatchAlarm(batch.get(i)); - } - } - mStatLogger.logDurationStat(Stats.REBATCH_ALL_ALARMS, start); - } - - @Override - public int size() { - return mSize; - } - - @Override - public long getNextWakeupDeliveryTime() { - for (Batch b : mAlarmBatches) { - if (b.hasWakeups()) { - return b.mStart; - } - } - return 0; - } - - @Override - public long getNextDeliveryTime() { - if (mAlarmBatches.size() > 0) { - return mAlarmBatches.get(0).mStart; - } - return 0; - } - - @Override - public ArrayList removePendingAlarms(long nowElapsed) { - final ArrayList removedAlarms = new ArrayList<>(); - while (mAlarmBatches.size() > 0) { - final Batch batch = mAlarmBatches.get(0); - if (batch.mStart > nowElapsed) { - break; - } - mAlarmBatches.remove(0); - for (int i = 0; i < batch.size(); i++) { - removedAlarms.add(batch.get(i)); - } - } - mSize -= removedAlarms.size(); - return removedAlarms; - } - - @Override - public boolean updateAlarmDeliveries(AlarmDeliveryCalculator deliveryCalculator) { - boolean changed = false; - for (final Batch b : mAlarmBatches) { - for (int i = 0; i < b.size(); i++) { - changed |= deliveryCalculator.updateAlarmDelivery(b.get(i)); - } - } - if (changed) { - rebatchAllAlarms(); - } - return changed; - } - - @Override - public ArrayList asList() { - final ArrayList allAlarms = new ArrayList<>(); - for (final Batch batch : mAlarmBatches) { - for (int i = 0; i < batch.size(); i++) { - allAlarms.add(batch.get(i)); - } - } - return allAlarms; - } - - @Override - public void dump(IndentingPrintWriter ipw, long nowElapsed, SimpleDateFormat sdf) { - ipw.print("Pending alarm batches: "); - ipw.println(mAlarmBatches.size()); - for (Batch b : mAlarmBatches) { - ipw.print(b); - ipw.println(':'); - ipw.increaseIndent(); - dumpAlarmList(ipw, b.mAlarms, nowElapsed, sdf); - ipw.decreaseIndent(); - } - mStatLogger.dump(ipw); - } - - @Override - public void dumpProto(ProtoOutputStream pos, long nowElapsed) { - for (Batch b : mAlarmBatches) { - b.dumpDebug(pos, AlarmManagerServiceDumpProto.PENDING_ALARM_BATCHES, nowElapsed); - } - } - - @Override - public String getName() { - return TAG; - } - - @Override - public int getCount(Predicate condition) { - long start = mStatLogger.getTime(); - - int count = 0; - for (Batch b : mAlarmBatches) { - for (int i = 0; i < b.size(); i++) { - if (condition.test(b.get(i))) { - count++; - } - } - } - mStatLogger.logDurationStat(Stats.GET_COUNT, start); - return count; - } - - private void insertAndBatchAlarm(Alarm alarm) { - final int whichBatch = ((alarm.flags & AlarmManager.FLAG_STANDALONE) != 0) ? -1 - : attemptCoalesce(alarm.getWhenElapsed(), alarm.getMaxWhenElapsed()); - - if (whichBatch < 0) { - addBatch(mAlarmBatches, new Batch(alarm)); - } else { - final Batch batch = mAlarmBatches.get(whichBatch); - if (batch.add(alarm)) { - // The start time of this batch advanced, so batch ordering may - // have just been broken. Move it to where it now belongs. - mAlarmBatches.remove(whichBatch); - addBatch(mAlarmBatches, batch); - } - } - } - - static void addBatch(ArrayList list, Batch newBatch) { - int index = Collections.binarySearch(list, newBatch, sBatchOrder); - if (index < 0) { - index = 0 - index - 1; - } - list.add(index, newBatch); - } - - // Return the index of the matching batch, or -1 if none found. - private int attemptCoalesce(long whenElapsed, long maxWhen) { - final int n = mAlarmBatches.size(); - for (int i = 0; i < n; i++) { - Batch b = mAlarmBatches.get(i); - if ((b.mFlags & AlarmManager.FLAG_STANDALONE) == 0 && b.canHold(whenElapsed, maxWhen)) { - return i; - } - } - return -1; - } - - final class Batch { - long mStart; // These endpoints are always in ELAPSED - long mEnd; - int mFlags; // Flags for alarms, such as FLAG_STANDALONE. - - final ArrayList mAlarms = new ArrayList<>(); - - Batch(Alarm seed) { - mStart = seed.getWhenElapsed(); - mEnd = clampPositive(seed.getMaxWhenElapsed()); - mFlags = seed.flags; - mAlarms.add(seed); - } - - int size() { - return mAlarms.size(); - } - - Alarm get(int index) { - return mAlarms.get(index); - } - - boolean canHold(long whenElapsed, long maxWhen) { - return (mEnd >= whenElapsed) && (mStart <= maxWhen); - } - - boolean add(Alarm alarm) { - boolean newStart = false; - // narrows the batch if necessary; presumes that canHold(alarm) is true - int index = Collections.binarySearch(mAlarms, alarm, sIncreasingTimeOrder); - if (index < 0) { - index = 0 - index - 1; - } - mAlarms.add(index, alarm); - if (DEBUG_BATCH) { - Slog.v(TAG, "Adding " + alarm + " to " + this); - } - if (alarm.getWhenElapsed() > mStart) { - mStart = alarm.getWhenElapsed(); - newStart = true; - } - if (alarm.getMaxWhenElapsed() < mEnd) { - mEnd = alarm.getMaxWhenElapsed(); - } - mFlags |= alarm.flags; - - if (DEBUG_BATCH) { - Slog.v(TAG, " => now " + this); - } - return newStart; - } - - ArrayList remove(Predicate predicate) { - final ArrayList removed = new ArrayList<>(); - long newStart = 0; // recalculate endpoints as we go - long newEnd = Long.MAX_VALUE; - int newFlags = 0; - for (int i = 0; i < mAlarms.size(); ) { - Alarm alarm = mAlarms.get(i); - if (predicate.test(alarm)) { - removed.add(mAlarms.remove(i)); - if (alarm.alarmClock != null && mOnAlarmClockRemoved != null) { - mOnAlarmClockRemoved.run(); - } - if (isTimeTickAlarm(alarm)) { - // This code path is not invoked when delivering alarms, only when removing - // alarms due to the caller cancelling it or getting uninstalled, etc. - Slog.wtf(TAG, "Removed TIME_TICK alarm"); - } - } else { - if (alarm.getWhenElapsed() > newStart) { - newStart = alarm.getWhenElapsed(); - } - if (alarm.getMaxWhenElapsed() < newEnd) { - newEnd = alarm.getMaxWhenElapsed(); - } - newFlags |= alarm.flags; - i++; - } - } - if (!removed.isEmpty()) { - // commit the new batch bounds - mStart = newStart; - mEnd = newEnd; - mFlags = newFlags; - } - return removed; - } - - boolean hasWakeups() { - final int n = mAlarms.size(); - for (int i = 0; i < n; i++) { - Alarm a = mAlarms.get(i); - if (a.wakeup) { - return true; - } - } - return false; - } - - @Override - public String toString() { - StringBuilder b = new StringBuilder(40); - b.append("Batch{"); - b.append(Integer.toHexString(this.hashCode())); - b.append(" num="); - b.append(size()); - b.append(" start="); - b.append(mStart); - b.append(" end="); - b.append(mEnd); - if (mFlags != 0) { - b.append(" flgs=0x"); - b.append(Integer.toHexString(mFlags)); - } - b.append('}'); - return b.toString(); - } - - public void dumpDebug(ProtoOutputStream proto, long fieldId, long nowElapsed) { - final long token = proto.start(fieldId); - - proto.write(BatchProto.START_REALTIME, mStart); - proto.write(BatchProto.END_REALTIME, mEnd); - proto.write(BatchProto.FLAGS, mFlags); - for (Alarm a : mAlarms) { - a.dumpDebug(proto, BatchProto.ALARMS, nowElapsed); - } - - proto.end(token); - } - } -} diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java index 2d0ef405b9d79..c8c87075eda29 100644 --- a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java @@ -74,7 +74,6 @@ import static com.android.server.alarm.AlarmManagerService.Constants.KEY_ALLOW_W import static com.android.server.alarm.AlarmManagerService.Constants.KEY_ALLOW_WHILE_IDLE_WHITELIST_DURATION; import static com.android.server.alarm.AlarmManagerService.Constants.KEY_ALLOW_WHILE_IDLE_WINDOW; import static com.android.server.alarm.AlarmManagerService.Constants.KEY_EXACT_ALARM_DENY_LIST; -import static com.android.server.alarm.AlarmManagerService.Constants.KEY_LAZY_BATCHING; import static com.android.server.alarm.AlarmManagerService.Constants.KEY_LISTENER_TIMEOUT; import static com.android.server.alarm.AlarmManagerService.Constants.KEY_MAX_DEVICE_IDLE_FUZZ; import static com.android.server.alarm.AlarmManagerService.Constants.KEY_MAX_INTERVAL; @@ -3093,37 +3092,6 @@ public class AlarmManagerServiceTest { optionsSentOnExpiration(false, null); } - @Test - public void alarmStoreMigration() { - setDeviceConfigBoolean(KEY_LAZY_BATCHING, false); - final int numAlarms = 10; - final PendingIntent[] pis = new PendingIntent[numAlarms]; - for (int i = 0; i < numAlarms; i++) { - pis[i] = getNewMockPendingIntent(); - setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + i + 1, pis[i]); - } - - final ArrayList alarmsBefore = mService.mAlarmStore.asList(); - assertEquals(numAlarms, alarmsBefore.size()); - for (int i = 0; i < numAlarms; i++) { - final PendingIntent pi = pis[i]; - assertTrue(i + "th PendingIntent missing: ", - alarmsBefore.removeIf(a -> a.matches(pi, null))); - } - assertEquals(BatchingAlarmStore.TAG, mService.mAlarmStore.getName()); - - setDeviceConfigBoolean(KEY_LAZY_BATCHING, true); - - final ArrayList alarmsAfter = mService.mAlarmStore.asList(); - assertEquals(numAlarms, alarmsAfter.size()); - for (int i = 0; i < numAlarms; i++) { - final PendingIntent pi = pis[i]; - assertTrue(i + "th PendingIntent missing: ", - alarmsAfter.removeIf(a -> a.matches(pi, null))); - } - assertEquals(LazyAlarmStore.TAG, mService.mAlarmStore.getName()); - } - private void registerAppIds(String[] packages, Integer[] ids) { assertEquals(packages.length, ids.length); diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmStoreTest.java b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmStoreTest.java index ba0e555020ac6..7dab1c854625e 100644 --- a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmStoreTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmStoreTest.java @@ -56,7 +56,6 @@ public class AlarmStoreTest { public static Object[] stores() { return new AlarmStore[]{ new LazyAlarmStore(), - new BatchingAlarmStore(), }; }