Merge "Consolidate launch time change notifications." into tm-dev

This commit is contained in:
TreeHugger Robot
2022-04-08 00:16:38 +00:00
committed by Android (Google) Code Review
3 changed files with 147 additions and 51 deletions

View File

@@ -62,6 +62,19 @@ public class SparseSetArray<T> {
return true;
}
/**
* Add a set of values for key n.
*/
public void addAll(int n, ArraySet<T> values) {
ArraySet<T> set = mData.get(n);
if (set == null) {
set = new ArraySet<>(values);
mData.put(n, set);
return;
}
set.addAll(values);
}
/**
* Removes all mappings from this SparseSetArray.
*/
@@ -109,6 +122,7 @@ public class SparseSetArray<T> {
public void remove(int n) {
mData.remove(n);
}
public int size() {
return mData.size();
}

View File

@@ -0,0 +1,52 @@
/*
* Copyright (C) 2022 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 android.util;
import static com.google.common.truth.Truth.assertThat;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
/**
* Tests for {@link SparseSetArray}.
*/
@SmallTest
@RunWith(AndroidJUnit4.class)
public class SparseSetArrayTest {
@Test
public void testAddAll() {
final SparseSetArray<Integer> sparseSetArray = new SparseSetArray<>();
for (int i = 0; i < 5; ++i) {
final ArraySet<Integer> array = new ArraySet<>();
for (int j = 100; j < 110; ++j) {
array.add(j);
// Test that addAll with some duplicates won't result in duplicates inside the
// data structure.
if (i % 2 == 0) {
sparseSetArray.add(i, j);
}
}
sparseSetArray.addAll(i, array);
assertThat(sparseSetArray.get(i)).isEqualTo(array);
}
assertThat(sparseSetArray.size()).isEqualTo(5);
}
}

View File

@@ -95,6 +95,7 @@ import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseIntArray;
import android.util.SparseSetArray;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
@@ -183,8 +184,7 @@ public class UsageStatsService extends SystemService implements
static final int MSG_PACKAGE_REMOVED = 6;
static final int MSG_ON_START = 7;
static final int MSG_HANDLE_LAUNCH_TIME_ON_USER_UNLOCK = 8;
static final int MSG_NOTIFY_ESTIMATED_LAUNCH_TIME_CHANGED = 9;
static final int MSG_NOTIFY_ESTIMATED_LAUNCH_TIMES_CHANGED = 10;
static final int MSG_NOTIFY_ESTIMATED_LAUNCH_TIMES_CHANGED = 9;
private final Object mLock = new Object();
Handler mHandler;
@@ -225,6 +225,8 @@ public class UsageStatsService extends SystemService implements
new ArraySet<>();
private final CopyOnWriteArraySet<UsageStatsManagerInternal.EstimatedLaunchTimeChangedListener>
mEstimatedLaunchTimeChangedListeners = new CopyOnWriteArraySet<>();
@GuardedBy("mPendingLaunchTimeChangePackages")
private final SparseSetArray<String> mPendingLaunchTimeChangePackages = new SparseSetArray<>();
private BroadcastResponseStatsTracker mResponseStatsTracker;
@@ -233,6 +235,7 @@ public class UsageStatsService extends SystemService implements
private final String mTaskRootClass;
private final String mUsageSourcePackage;
public int lastEvent = Event.NONE;
private ActivityData(String taskRootPackage, String taskRootClass, String sourcePackage) {
mTaskRootPackage = taskRootPackage;
mTaskRootClass = taskRootClass;
@@ -537,9 +540,10 @@ public class UsageStatsService extends SystemService implements
+ expired.toString());
}
if (expired.size() > 0) {
mHandler.obtainMessage(
MSG_NOTIFY_ESTIMATED_LAUNCH_TIMES_CHANGED, mUserId, 0, expired)
.sendToTarget();
synchronized (mPendingLaunchTimeChangePackages) {
mPendingLaunchTimeChangePackages.addAll(mUserId, expired);
}
mHandler.sendEmptyMessage(MSG_NOTIFY_ESTIMATED_LAUNCH_TIMES_CHANGED);
}
}
}
@@ -1058,9 +1062,9 @@ public class UsageStatsService extends SystemService implements
+ " app launch resetting future launch estimate");
}
mAppStandby.setEstimatedLaunchTime(event.mPackage, userId, 0);
mHandler.obtainMessage(
MSG_NOTIFY_ESTIMATED_LAUNCH_TIME_CHANGED, userId, 0, event.mPackage)
.sendToTarget();
if (stageChangedEstimatedLaunchTime(userId, event.mPackage)) {
mHandler.sendEmptyMessage(MSG_NOTIFY_ESTIMATED_LAUNCH_TIMES_CHANGED);
}
}
break;
case Event.ACTIVITY_PAUSED:
@@ -1212,7 +1216,7 @@ public class UsageStatsService extends SystemService implements
}
/**
* Called by the Binder stub.
* Called by the Handler for message MSG_USER_REMOVED.
*/
void onUserRemoved(int userId) {
synchronized (mLock) {
@@ -1225,6 +1229,11 @@ public class UsageStatsService extends SystemService implements
mLaunchTimeAlarmQueues.remove(userId);
}
}
// Since this is only called from the Handler, we don't have to worry about modifying the
// pending change list while the handler is iterating to notify listeners.
synchronized (mPendingLaunchTimeChangePackages) {
mPendingLaunchTimeChangePackages.remove(userId);
}
mAppStandby.onUserRemoved(userId);
// Cancel any scheduled jobs for this user since the user is being removed.
UsageStatsIdleService.cancelJob(getContext(), userId);
@@ -1235,6 +1244,15 @@ public class UsageStatsService extends SystemService implements
* Called by the Handler for message MSG_PACKAGE_REMOVED.
*/
private void onPackageRemoved(int userId, String packageName) {
// Since this is only called from the Handler, we don't have to worry about modifying the
// pending change list while the handler is iterating to notify listeners.
synchronized (mPendingLaunchTimeChangePackages) {
final ArraySet<String> pkgNames = mPendingLaunchTimeChangePackages.get(userId);
if (pkgNames != null) {
pkgNames.remove(packageName);
}
}
final int tokenRemoved;
synchronized (mLock) {
final long timeRemoved = System.currentTimeMillis();
@@ -1547,7 +1565,7 @@ public class UsageStatsService extends SystemService implements
userId, getContext(), BackgroundThread.get().getLooper());
mLaunchTimeAlarmQueues.put(userId, alarmQueue);
}
final ArraySet<String> changedTimes = new ArraySet<>();
boolean changedTimes = false;
for (boolean unprocessedEvent = events.getNextEvent(event); unprocessedEvent;
unprocessedEvent = events.getNextEvent(event)) {
final String packageName = event.getPackageName();
@@ -1577,15 +1595,13 @@ public class UsageStatsService extends SystemService implements
Slog.d(TAG, "User " + userId + " unlock resulting in"
+ " estimated launch time change for " + packageName);
}
changedTimes.add(packageName);
changedTimes |= stageChangedEstimatedLaunchTime(userId, packageName);
}
alarmQueue.addAlarm(packageName, nowElapsed + (estimatedLaunchTime - now));
}
}
if (changedTimes.size() > 0) {
mHandler.obtainMessage(
MSG_NOTIFY_ESTIMATED_LAUNCH_TIMES_CHANGED, userId, 0, changedTimes)
.sendToTarget();
if (changedTimes) {
mHandler.sendEmptyMessage(MSG_NOTIFY_ESTIMATED_LAUNCH_TIMES_CHANGED);
}
}
}
@@ -1603,14 +1619,14 @@ public class UsageStatsService extends SystemService implements
final long oldEstimatedLaunchTime = mAppStandby.getEstimatedLaunchTime(packageName, userId);
if (estimatedLaunchTime != oldEstimatedLaunchTime) {
mAppStandby.setEstimatedLaunchTime(packageName, userId, estimatedLaunchTime);
mHandler.obtainMessage(
MSG_NOTIFY_ESTIMATED_LAUNCH_TIME_CHANGED, userId, 0, packageName)
.sendToTarget();
if (stageChangedEstimatedLaunchTime(userId, packageName)) {
mHandler.sendEmptyMessage(MSG_NOTIFY_ESTIMATED_LAUNCH_TIMES_CHANGED);
}
}
}
private void setEstimatedLaunchTimes(int userId, List<AppLaunchEstimateInfo> launchEstimates) {
final ArraySet<String> changedTimes = new ArraySet<>();
boolean changedTimes = false;
final long now = System.currentTimeMillis();
for (int i = launchEstimates.size() - 1; i >= 0; --i) {
AppLaunchEstimateInfo estimate = launchEstimates.get(i);
@@ -1626,13 +1642,17 @@ public class UsageStatsService extends SystemService implements
if (estimate.estimatedLaunchTime != oldEstimatedLaunchTime) {
mAppStandby.setEstimatedLaunchTime(
estimate.packageName, userId, estimate.estimatedLaunchTime);
changedTimes.add(estimate.packageName);
changedTimes |= stageChangedEstimatedLaunchTime(userId, estimate.packageName);
}
}
if (changedTimes.size() > 0) {
mHandler.obtainMessage(
MSG_NOTIFY_ESTIMATED_LAUNCH_TIMES_CHANGED, userId, 0, changedTimes)
.sendToTarget();
if (changedTimes) {
mHandler.sendEmptyMessage(MSG_NOTIFY_ESTIMATED_LAUNCH_TIMES_CHANGED);
}
}
private boolean stageChangedEstimatedLaunchTime(int userId, String packageName) {
synchronized (mPendingLaunchTimeChangePackages) {
return mPendingLaunchTimeChangePackages.add(userId, packageName);
}
}
@@ -1946,35 +1966,45 @@ public class UsageStatsService extends SystemService implements
handleEstimatedLaunchTimesOnUserUnlock(userId);
}
break;
case MSG_NOTIFY_ESTIMATED_LAUNCH_TIME_CHANGED: {
final int userId = msg.arg1;
final String pkgName = (String) msg.obj;
final long nextEstimatedLaunchTime =
getEstimatedPackageLaunchTime(userId, pkgName);
if (DEBUG) {
Slog.d(TAG, "Notifying listener for " + userId + ":" + pkgName);
}
for (UsageStatsManagerInternal.EstimatedLaunchTimeChangedListener listener :
mEstimatedLaunchTimeChangedListeners) {
listener.onEstimatedLaunchTimeChanged(
userId, pkgName, nextEstimatedLaunchTime);
}
}
break;
case MSG_NOTIFY_ESTIMATED_LAUNCH_TIMES_CHANGED: {
final int userId = msg.arg1;
final ArraySet<String> pkgNames = (ArraySet<String>) msg.obj;
if (DEBUG) {
Slog.d(TAG, "Notifying listeners for " + userId + "-->" + pkgNames);
removeMessages(MSG_NOTIFY_ESTIMATED_LAUNCH_TIMES_CHANGED);
// Note that this method of getting the list's size outside and then using it
// for iteration outside of the lock implies possible issue if the set is
// modified during iteration. However, at the time of implementation, this is
// not an issue.
// For addition (increasing the size): if something is added after we get the
// size, then there will be a new MSG_NOTIFY_ESTIMATED_LAUNCH_TIMES_CHANGED
// message in the handler's queue, which means we will iterate over the list
// once again and process the addition
// For removal (decreasing the size): removals only ever happen via the handler,
// which means this iteration code cannot happen at the same time as a removal.
// We go through hoops to avoid holding locks when calling out to listeners.
final int numUsers;
final ArraySet<String> pkgNames = new ArraySet();
synchronized (mPendingLaunchTimeChangePackages) {
numUsers = mPendingLaunchTimeChangePackages.size();
}
for (int p = pkgNames.size() - 1; p >= 0; --p) {
final String pkgName = pkgNames.valueAt(p);
final long nextEstimatedLaunchTime =
getEstimatedPackageLaunchTime(userId, pkgName);
for (UsageStatsManagerInternal.EstimatedLaunchTimeChangedListener listener :
mEstimatedLaunchTimeChangedListeners) {
listener.onEstimatedLaunchTimeChanged(
userId, pkgName, nextEstimatedLaunchTime);
for (int u = numUsers - 1; u >= 0; --u) {
pkgNames.clear();
final int userId;
synchronized (mPendingLaunchTimeChangePackages) {
userId = mPendingLaunchTimeChangePackages.keyAt(u);
pkgNames.addAll(mPendingLaunchTimeChangePackages.get(userId));
mPendingLaunchTimeChangePackages.remove(userId);
}
if (DEBUG) {
Slog.d(TAG, "Notifying listeners for " + userId + "-->" + pkgNames);
}
for (int p = pkgNames.size() - 1; p >= 0; --p) {
final String pkgName = pkgNames.valueAt(p);
final long nextEstimatedLaunchTime =
getEstimatedPackageLaunchTime(userId, pkgName);
for (UsageStatsManagerInternal.EstimatedLaunchTimeChangedListener
listener : mEstimatedLaunchTimeChangedListeners) {
listener.onEstimatedLaunchTimeChanged(
userId, pkgName, nextEstimatedLaunchTime);
}
}
}
}