Merge "Make AppOpsUidStateTracker callbacks more testable"
This commit is contained in:
committed by
Android (Google) Code Review
commit
f9309d8683
@@ -105,6 +105,7 @@ import android.os.Binder;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerExecutor;
|
||||
import android.os.IBinder;
|
||||
import android.os.PackageTagsList;
|
||||
import android.os.Process;
|
||||
@@ -374,10 +375,17 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch
|
||||
public AppOpsUidStateTracker getUidStateTracker() {
|
||||
if (mUidStateTracker == null) {
|
||||
mUidStateTracker = new AppOpsUidStateTrackerImpl(
|
||||
LocalServices.getService(ActivityManagerInternal.class), mHandler,
|
||||
LocalServices.getService(ActivityManagerInternal.class),
|
||||
mHandler,
|
||||
r -> {
|
||||
synchronized (AppOpsService.this) {
|
||||
r.run();
|
||||
}
|
||||
},
|
||||
Clock.SYSTEM_CLOCK, mConstants);
|
||||
|
||||
mUidStateTracker.addUidStateChangedCallback(mHandler, this::onUidStateChanged);
|
||||
mUidStateTracker.addUidStateChangedCallback(new HandlerExecutor(mHandler),
|
||||
this::onUidStateChanged);
|
||||
}
|
||||
return mUidStateTracker;
|
||||
}
|
||||
@@ -4809,6 +4817,8 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch
|
||||
pw.println(" Only output the watcher sections.");
|
||||
pw.println(" --history");
|
||||
pw.println(" Only output history.");
|
||||
pw.println(" --uid-state-change-logs");
|
||||
pw.println(" Include logs about uid state changes.");
|
||||
}
|
||||
|
||||
private void dumpStatesLocked(@NonNull PrintWriter pw, @Nullable String filterAttributionTag,
|
||||
@@ -4946,6 +4956,7 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch
|
||||
// TODO ntmyren: Remove the dumpHistory and dumpFilter
|
||||
boolean dumpHistory = false;
|
||||
boolean includeDiscreteOps = false;
|
||||
boolean dumpUidStateChangeLogs = false;
|
||||
int nDiscreteOps = 10;
|
||||
@HistoricalOpsRequestFilter int dumpFilter = 0;
|
||||
boolean dumpAll = false;
|
||||
@@ -5028,6 +5039,8 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch
|
||||
} else if (arg.length() > 0 && arg.charAt(0) == '-') {
|
||||
pw.println("Unknown option: " + arg);
|
||||
return;
|
||||
} else if ("--uid-state-change-logs".equals(arg)) {
|
||||
dumpUidStateChangeLogs = true;
|
||||
} else {
|
||||
pw.println("Unknown command: " + arg);
|
||||
return;
|
||||
@@ -5363,6 +5376,12 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch
|
||||
pw.println(" AppOps policy not set.");
|
||||
}
|
||||
}
|
||||
|
||||
if (dumpAll || dumpUidStateChangeLogs) {
|
||||
pw.println();
|
||||
pw.println("Uid State Changes Event Log:");
|
||||
getUidStateTracker().dumpEvents(pw);
|
||||
}
|
||||
}
|
||||
|
||||
// Must not hold the appops lock
|
||||
@@ -5375,14 +5394,6 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch
|
||||
mHistoricalRegistry.dumpDiscreteData(pw, dumpUid, dumpPackage, dumpAttributionTag,
|
||||
dumpFilter, dumpOp, sdf, date, " ", nDiscreteOps);
|
||||
}
|
||||
|
||||
if (dumpAll) {
|
||||
pw.println();
|
||||
pw.println("Uid State Changes Event Log:");
|
||||
if (mUidStateTracker != null) {
|
||||
mUidStateTracker.dumpEvents(pw);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -30,10 +30,11 @@ import static android.app.AppOpsManager.UID_STATE_FOREGROUND_SERVICE;
|
||||
import static android.app.AppOpsManager.UID_STATE_PERSISTENT;
|
||||
import static android.app.AppOpsManager.UID_STATE_TOP;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.annotation.CallbackExecutor;
|
||||
import android.util.SparseArray;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
interface AppOpsUidStateTracker {
|
||||
|
||||
@@ -95,7 +96,7 @@ interface AppOpsUidStateTracker {
|
||||
/**
|
||||
* Listen to changes in {@link android.app.AppOpsManager.UidState}
|
||||
*/
|
||||
void addUidStateChangedCallback(Handler handler,
|
||||
void addUidStateChangedCallback(@CallbackExecutor Executor executor,
|
||||
UidStateChangedCallback callback);
|
||||
|
||||
/**
|
||||
|
||||
@@ -44,17 +44,18 @@ import android.util.SparseIntArray;
|
||||
import android.util.SparseLongArray;
|
||||
import android.util.TimeUtils;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.os.Clock;
|
||||
import com.android.internal.util.function.pooled.PooledLambda;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
class AppOpsUidStateTrackerImpl implements AppOpsUidStateTracker {
|
||||
|
||||
private static final String LOG_TAG = AppOpsUidStateTrackerImpl.class.getSimpleName();
|
||||
|
||||
private final Handler mHandler;
|
||||
private final DelayableExecutor mExecutor;
|
||||
private final Clock mClock;
|
||||
private ActivityManagerInternal mActivityManagerInternal;
|
||||
private AppOpsService.Constants mConstants;
|
||||
@@ -68,18 +69,46 @@ class AppOpsUidStateTrackerImpl implements AppOpsUidStateTracker {
|
||||
private SparseLongArray mPendingCommitTime = new SparseLongArray();
|
||||
private SparseBooleanArray mPendingGone = new SparseBooleanArray();
|
||||
|
||||
private ArrayMap<UidStateChangedCallback, Handler> mUidStateChangedCallbacks = new ArrayMap<>();
|
||||
private ArrayMap<UidStateChangedCallback, Executor>
|
||||
mUidStateChangedCallbacks = new ArrayMap<>();
|
||||
|
||||
private final EventLog mEventLog;
|
||||
|
||||
@VisibleForTesting
|
||||
interface DelayableExecutor extends Executor {
|
||||
|
||||
void execute(Runnable runnable);
|
||||
|
||||
void executeDelayed(Runnable runnable, long delay);
|
||||
}
|
||||
|
||||
AppOpsUidStateTrackerImpl(ActivityManagerInternal activityManagerInternal,
|
||||
Handler handler, Clock clock, AppOpsService.Constants constants) {
|
||||
Handler handler, Executor lockingExecutor, Clock clock,
|
||||
AppOpsService.Constants constants) {
|
||||
|
||||
this(activityManagerInternal, new DelayableExecutor() {
|
||||
@Override
|
||||
public void execute(Runnable runnable) {
|
||||
handler.post(() -> lockingExecutor.execute(runnable));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void executeDelayed(Runnable runnable, long delay) {
|
||||
handler.postDelayed(() -> lockingExecutor.execute(runnable), delay);
|
||||
}
|
||||
}, clock, constants, handler.getLooper().getThread());
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
AppOpsUidStateTrackerImpl(ActivityManagerInternal activityManagerInternal,
|
||||
DelayableExecutor executor, Clock clock, AppOpsService.Constants constants,
|
||||
Thread executorThread) {
|
||||
mActivityManagerInternal = activityManagerInternal;
|
||||
mHandler = handler;
|
||||
mExecutor = executor;
|
||||
mClock = clock;
|
||||
mConstants = constants;
|
||||
|
||||
mEventLog = new EventLog(handler);
|
||||
mEventLog = new EventLog(executor, executorThread);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -157,11 +186,12 @@ class AppOpsUidStateTrackerImpl implements AppOpsUidStateTracker {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addUidStateChangedCallback(Handler handler, UidStateChangedCallback callback) {
|
||||
public void addUidStateChangedCallback(Executor executor, UidStateChangedCallback callback) {
|
||||
if (mUidStateChangedCallbacks.containsKey(callback)) {
|
||||
throw new IllegalStateException("Callback is already registered.");
|
||||
}
|
||||
mUidStateChangedCallbacks.put(callback, handler);
|
||||
|
||||
mUidStateChangedCallbacks.put(callback, executor);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -232,7 +262,7 @@ class AppOpsUidStateTrackerImpl implements AppOpsUidStateTracker {
|
||||
final long commitTime = mClock.elapsedRealtime() + settleTime;
|
||||
mPendingCommitTime.put(uid, commitTime);
|
||||
|
||||
mHandler.sendMessageDelayed(PooledLambda.obtainMessage(
|
||||
mExecutor.executeDelayed(PooledLambda.obtainRunnable(
|
||||
AppOpsUidStateTrackerImpl::updateUidPendingStateIfNeeded, this,
|
||||
uid), settleTime + 1);
|
||||
}
|
||||
@@ -323,10 +353,11 @@ class AppOpsUidStateTrackerImpl implements AppOpsUidStateTracker {
|
||||
|
||||
for (int i = 0; i < mUidStateChangedCallbacks.size(); i++) {
|
||||
UidStateChangedCallback cb = mUidStateChangedCallbacks.keyAt(i);
|
||||
Handler h = mUidStateChangedCallbacks.valueAt(i);
|
||||
Executor executor = mUidStateChangedCallbacks.valueAt(i);
|
||||
|
||||
h.sendMessage(PooledLambda.obtainMessage(UidStateChangedCallback::onUidStateChanged,
|
||||
cb, uid, pendingUidState, foregroundChange));
|
||||
executor.execute(PooledLambda.obtainRunnable(
|
||||
UidStateChangedCallback::onUidStateChanged, cb, uid, pendingUidState,
|
||||
foregroundChange));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -366,7 +397,8 @@ class AppOpsUidStateTrackerImpl implements AppOpsUidStateTracker {
|
||||
// Memory usage: 24 * size bytes
|
||||
private static final int EVAL_FOREGROUND_MODE_MAX_SIZE = 200;
|
||||
|
||||
private final Handler mHandler;
|
||||
private final DelayableExecutor mExecutor;
|
||||
private final Thread mExecutorThread;
|
||||
|
||||
private int[][] mUpdateUidProcStateLog = new int[UPDATE_UID_PROC_STATE_LOG_MAX_SIZE][3];
|
||||
private long[] mUpdateUidProcStateLogTimestamps =
|
||||
@@ -384,15 +416,16 @@ class AppOpsUidStateTrackerImpl implements AppOpsUidStateTracker {
|
||||
private int mEvalForegroundModeLogSize = 0;
|
||||
private int mEvalForegroundModeLogHead = 0;
|
||||
|
||||
EventLog(Handler handler) {
|
||||
mHandler = handler;
|
||||
EventLog(DelayableExecutor executor, Thread executorThread) {
|
||||
mExecutor = executor;
|
||||
mExecutorThread = executorThread;
|
||||
}
|
||||
|
||||
void logUpdateUidProcState(int uid, int procState, int capability) {
|
||||
if (UPDATE_UID_PROC_STATE_LOG_MAX_SIZE == 0) {
|
||||
return;
|
||||
}
|
||||
mHandler.sendMessage(PooledLambda.obtainMessage(EventLog::logUpdateUidProcStateAsync,
|
||||
mExecutor.execute(PooledLambda.obtainRunnable(EventLog::logUpdateUidProcStateAsync,
|
||||
this, System.currentTimeMillis(), uid, procState, capability));
|
||||
}
|
||||
|
||||
@@ -416,7 +449,7 @@ class AppOpsUidStateTrackerImpl implements AppOpsUidStateTracker {
|
||||
if (COMMIT_UID_STATE_LOG_MAX_SIZE == 0) {
|
||||
return;
|
||||
}
|
||||
mHandler.sendMessage(PooledLambda.obtainMessage(EventLog::logCommitUidStateAsync,
|
||||
mExecutor.execute(PooledLambda.obtainRunnable(EventLog::logCommitUidStateAsync,
|
||||
this, System.currentTimeMillis(), uid, uidState, capability, visible));
|
||||
}
|
||||
|
||||
@@ -442,7 +475,7 @@ class AppOpsUidStateTrackerImpl implements AppOpsUidStateTracker {
|
||||
if (EVAL_FOREGROUND_MODE_MAX_SIZE == 0) {
|
||||
return;
|
||||
}
|
||||
mHandler.sendMessage(PooledLambda.obtainMessage(EventLog::logEvalForegroundModeAsync,
|
||||
mExecutor.execute(PooledLambda.obtainRunnable(EventLog::logEvalForegroundModeAsync,
|
||||
this, System.currentTimeMillis(), uid, uidState, capability, code, result));
|
||||
}
|
||||
|
||||
@@ -466,22 +499,6 @@ class AppOpsUidStateTrackerImpl implements AppOpsUidStateTracker {
|
||||
}
|
||||
|
||||
void dumpEvents(PrintWriter pw) {
|
||||
if (Thread.currentThread() != mHandler.getLooper().getThread()) {
|
||||
// All operations are done on the handler's thread
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
mHandler.post(() -> {
|
||||
dumpEvents(pw);
|
||||
latch.countDown();
|
||||
});
|
||||
|
||||
try {
|
||||
latch.await();
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
int updateIdx = 0;
|
||||
int commitIdx = 0;
|
||||
int evalIdx = 0;
|
||||
@@ -536,13 +553,13 @@ class AppOpsUidStateTrackerImpl implements AppOpsUidStateTracker {
|
||||
pw.print(" UPDATE_UID_PROC_STATE");
|
||||
|
||||
pw.print(" uid=");
|
||||
pw.print(uid);
|
||||
pw.print(String.format("%-8d", uid));
|
||||
|
||||
pw.print(" procState=");
|
||||
pw.print(String.format("%-30s", ActivityManager.procStateToString(procState)));
|
||||
|
||||
pw.print(" capability=");
|
||||
pw.print(ActivityManager.getCapabilitiesSummary(capability));
|
||||
pw.print(ActivityManager.getCapabilitiesSummary(capability) + " ");
|
||||
|
||||
pw.println();
|
||||
}
|
||||
@@ -559,13 +576,13 @@ class AppOpsUidStateTrackerImpl implements AppOpsUidStateTracker {
|
||||
pw.print(" COMMIT_UID_STATE ");
|
||||
|
||||
pw.print(" uid=");
|
||||
pw.print(uid);
|
||||
pw.print(String.format("%-8d", uid));
|
||||
|
||||
pw.print(" uidState=");
|
||||
pw.print(String.format("%-30s", AppOpsManager.uidStateToString(uidState)));
|
||||
|
||||
pw.print(" capability=");
|
||||
pw.print(ActivityManager.getCapabilitiesSummary(capability));
|
||||
pw.print(ActivityManager.getCapabilitiesSummary(capability) + " ");
|
||||
|
||||
pw.print(" visibleAppWidget=");
|
||||
pw.print(visibleAppWidget);
|
||||
@@ -586,13 +603,13 @@ class AppOpsUidStateTrackerImpl implements AppOpsUidStateTracker {
|
||||
pw.print(" EVAL_FOREGROUND_MODE ");
|
||||
|
||||
pw.print(" uid=");
|
||||
pw.print(uid);
|
||||
pw.print(String.format("%-8d", uid));
|
||||
|
||||
pw.print(" uidState=");
|
||||
pw.print(String.format("%-30s", AppOpsManager.uidStateToString(uidState)));
|
||||
|
||||
pw.print(" capability=");
|
||||
pw.print(ActivityManager.getCapabilitiesSummary(capability));
|
||||
pw.print(ActivityManager.getCapabilitiesSummary(capability) + " ");
|
||||
|
||||
pw.print(" code=");
|
||||
pw.print(String.format("%-20s", AppOpsManager.opToName(code)));
|
||||
|
||||
@@ -34,12 +34,9 @@ import static android.app.AppOpsManager.UID_STATE_TOP;
|
||||
import static com.android.server.appop.AppOpsUidStateTracker.processStateToUidState;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyBoolean;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.atLeast;
|
||||
import static org.mockito.Mockito.atLeastOnce;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.never;
|
||||
@@ -49,25 +46,22 @@ import static org.mockito.Mockito.verify;
|
||||
import android.app.ActivityManager;
|
||||
import android.app.ActivityManagerInternal;
|
||||
import android.app.AppOpsManager;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.util.SparseArray;
|
||||
|
||||
import com.android.dx.mockito.inline.extended.ExtendedMockito;
|
||||
import com.android.dx.mockito.inline.extended.StaticMockitoSession;
|
||||
import com.android.internal.os.Clock;
|
||||
import com.android.server.appop.AppOpsUidStateTracker.UidStateChangedCallback;
|
||||
import com.android.server.appop.AppOpsUidStateTrackerImpl.DelayableExecutor;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.quality.Strictness;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.PriorityQueue;
|
||||
|
||||
public class AppOpsUidStateTrackerTest {
|
||||
|
||||
@@ -80,13 +74,12 @@ public class AppOpsUidStateTrackerTest {
|
||||
@Mock
|
||||
ActivityManagerInternal mAmi;
|
||||
|
||||
@Mock
|
||||
Handler mHandler;
|
||||
|
||||
@Mock
|
||||
AppOpsService.Constants mConstants;
|
||||
|
||||
AppOpsUidStateTrackerTestClock mClock = new AppOpsUidStateTrackerTestClock();
|
||||
AppOpsUidStateTrackerTestExecutor mExecutor = new AppOpsUidStateTrackerTestExecutor();
|
||||
|
||||
AppOpsUidStateTrackerTestClock mClock = new AppOpsUidStateTrackerTestClock(mExecutor);
|
||||
|
||||
AppOpsUidStateTracker mIntf;
|
||||
|
||||
@@ -101,7 +94,8 @@ public class AppOpsUidStateTrackerTest {
|
||||
mConstants.TOP_STATE_SETTLE_TIME = 10 * 1000L;
|
||||
mConstants.FG_SERVICE_STATE_SETTLE_TIME = 5 * 1000L;
|
||||
mConstants.BG_STATE_SETTLE_TIME = 1 * 1000L;
|
||||
mIntf = new AppOpsUidStateTrackerImpl(mAmi, mHandler, mClock, mConstants);
|
||||
mIntf = new AppOpsUidStateTrackerImpl(mAmi, mExecutor, mClock, mConstants,
|
||||
Thread.currentThread());
|
||||
}
|
||||
|
||||
@After
|
||||
@@ -263,18 +257,10 @@ public class AppOpsUidStateTrackerTest {
|
||||
// Still in foreground due to settle time
|
||||
assertForeground(UID);
|
||||
|
||||
AtomicReference<Message> messageAtomicReference = new AtomicReference<>();
|
||||
AtomicLong delayAtomicReference = new AtomicLong();
|
||||
mClock.advanceTime(mConstants.TOP_STATE_SETTLE_TIME - 1);
|
||||
assertForeground(UID);
|
||||
|
||||
getPostDelayedMessageArguments(messageAtomicReference, delayAtomicReference);
|
||||
Message message = messageAtomicReference.get();
|
||||
long delay = delayAtomicReference.get();
|
||||
|
||||
assertNotNull(message);
|
||||
assertEquals(mConstants.TOP_STATE_SETTLE_TIME + 1, delay);
|
||||
|
||||
mClock.advanceTime(mConstants.TOP_STATE_SETTLE_TIME + 1);
|
||||
message.getCallback().run();
|
||||
mClock.advanceTime(1);
|
||||
assertBackground(UID);
|
||||
}
|
||||
|
||||
@@ -291,18 +277,10 @@ public class AppOpsUidStateTrackerTest {
|
||||
// Still in foreground due to settle time
|
||||
assertForeground(UID);
|
||||
|
||||
AtomicReference<Message> messageAtomicReference = new AtomicReference<>();
|
||||
AtomicLong delayAtomicReference = new AtomicLong();
|
||||
mClock.advanceTime(mConstants.FG_SERVICE_STATE_SETTLE_TIME - 1);
|
||||
assertForeground(UID);
|
||||
|
||||
getPostDelayedMessageArguments(messageAtomicReference, delayAtomicReference);
|
||||
Message message = messageAtomicReference.get();
|
||||
long delay = delayAtomicReference.get();
|
||||
|
||||
assertNotNull(message);
|
||||
assertEquals(mConstants.FG_SERVICE_STATE_SETTLE_TIME + 1, delay);
|
||||
|
||||
mClock.advanceTime(mConstants.FG_SERVICE_STATE_SETTLE_TIME + 1);
|
||||
message.getCallback().run();
|
||||
mClock.advanceTime(1);
|
||||
assertBackground(UID);
|
||||
}
|
||||
|
||||
@@ -319,14 +297,8 @@ public class AppOpsUidStateTrackerTest {
|
||||
// Still in foreground due to settle time
|
||||
assertForeground(UID);
|
||||
|
||||
AtomicReference<Message> messageAtomicReference = new AtomicReference<>();
|
||||
|
||||
getPostDelayedMessageArguments(messageAtomicReference, null);
|
||||
Message message = messageAtomicReference.get();
|
||||
|
||||
// 1 ms short of settle time
|
||||
mClock.advanceTime(mConstants.FG_SERVICE_STATE_SETTLE_TIME - 1);
|
||||
message.getCallback().run();
|
||||
assertForeground(UID);
|
||||
}
|
||||
|
||||
@@ -471,8 +443,6 @@ public class AppOpsUidStateTrackerTest {
|
||||
.topState()
|
||||
.update();
|
||||
|
||||
getLatestPostMessageArgument().getCallback().run();
|
||||
|
||||
verify(cb).onUidStateChanged(eq(UID), eq(UID_STATE_TOP), eq(true));
|
||||
}
|
||||
|
||||
@@ -484,8 +454,6 @@ public class AppOpsUidStateTrackerTest {
|
||||
.foregroundServiceState()
|
||||
.update();
|
||||
|
||||
getLatestPostMessageArgument().getCallback().run();
|
||||
|
||||
verify(cb).onUidStateChanged(eq(UID), eq(UID_STATE_FOREGROUND_SERVICE), eq(true));
|
||||
}
|
||||
|
||||
@@ -497,8 +465,6 @@ public class AppOpsUidStateTrackerTest {
|
||||
.foregroundState()
|
||||
.update();
|
||||
|
||||
getLatestPostMessageArgument().getCallback().run();
|
||||
|
||||
verify(cb).onUidStateChanged(eq(UID), eq(UID_STATE_FOREGROUND), eq(true));
|
||||
}
|
||||
|
||||
@@ -510,8 +476,6 @@ public class AppOpsUidStateTrackerTest {
|
||||
.backgroundState()
|
||||
.update();
|
||||
|
||||
getLatestPostMessageArgument().getCallback().run();
|
||||
|
||||
verify(cb).onUidStateChanged(eq(UID), eq(UID_STATE_BACKGROUND), eq(false));
|
||||
}
|
||||
|
||||
@@ -679,7 +643,6 @@ public class AppOpsUidStateTrackerTest {
|
||||
.nonExistentState()
|
||||
.update();
|
||||
|
||||
verify(mHandler, never()).post(any());
|
||||
verify(cb, never()).onUidStateChanged(anyInt(), anyInt(), anyBoolean());
|
||||
}
|
||||
|
||||
@@ -695,7 +658,6 @@ public class AppOpsUidStateTrackerTest {
|
||||
.nonExistentState()
|
||||
.update();
|
||||
|
||||
getLatestPostMessageArgument().getCallback().run();
|
||||
verify(cb, atLeastOnce()).onUidStateChanged(eq(UID), eq(UID_STATE_CACHED), eq(false));
|
||||
}
|
||||
|
||||
@@ -711,7 +673,6 @@ public class AppOpsUidStateTrackerTest {
|
||||
.nonExistentState()
|
||||
.update();
|
||||
|
||||
getLatestPostMessageArgument().getCallback().run();
|
||||
verify(cb, atLeastOnce()).onUidStateChanged(eq(UID), eq(UID_STATE_CACHED), eq(true));
|
||||
}
|
||||
|
||||
@@ -727,7 +688,6 @@ public class AppOpsUidStateTrackerTest {
|
||||
.nonExistentState()
|
||||
.update();
|
||||
|
||||
getLatestPostMessageArgument().getCallback().run();
|
||||
verify(cb, atLeastOnce()).onUidStateChanged(eq(UID), eq(UID_STATE_CACHED), eq(true));
|
||||
}
|
||||
|
||||
@@ -743,10 +703,32 @@ public class AppOpsUidStateTrackerTest {
|
||||
.nonExistentState()
|
||||
.update();
|
||||
|
||||
getLatestPostMessageArgument().getCallback().run();
|
||||
verify(cb, atLeastOnce()).onUidStateChanged(eq(UID), eq(UID_STATE_CACHED), eq(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUidStateChangedBackgroundThenForegroundImmediately() {
|
||||
procStateBuilder(UID)
|
||||
.topState()
|
||||
.update();
|
||||
|
||||
UidStateChangedCallback cb = addUidStateChangeCallback();
|
||||
|
||||
procStateBuilder(UID)
|
||||
.backgroundState()
|
||||
.update();
|
||||
|
||||
mClock.advanceTime(mConstants.TOP_STATE_SETTLE_TIME - 1);
|
||||
|
||||
procStateBuilder(UID)
|
||||
.topState()
|
||||
.update();
|
||||
|
||||
mClock.advanceTime(1);
|
||||
|
||||
verify(cb, never()).onUidStateChanged(anyInt(), anyInt(), anyBoolean());
|
||||
}
|
||||
|
||||
public void testUidStateChangedCallback(int initialState, int finalState) {
|
||||
int initialUidState = processStateToUidState(initialState);
|
||||
int finalUidState = processStateToUidState(finalState);
|
||||
@@ -767,13 +749,9 @@ public class AppOpsUidStateTrackerTest {
|
||||
.update();
|
||||
|
||||
if (finalUidStateIsBackgroundAndLessImportant) {
|
||||
AtomicReference<Message> delayedMessage = new AtomicReference<>();
|
||||
getPostDelayedMessageArguments(delayedMessage, new AtomicLong());
|
||||
mClock.advanceTime(mConstants.TOP_STATE_SETTLE_TIME + 1);
|
||||
delayedMessage.get().getCallback().run();
|
||||
}
|
||||
|
||||
getLatestPostMessageArgument().getCallback().run();
|
||||
verify(cb, atLeastOnce())
|
||||
.onUidStateChanged(eq(UID), eq(finalUidState), eq(foregroundChange));
|
||||
}
|
||||
@@ -781,7 +759,7 @@ public class AppOpsUidStateTrackerTest {
|
||||
private UidStateChangedCallback addUidStateChangeCallback() {
|
||||
UidStateChangedCallback cb =
|
||||
Mockito.mock(UidStateChangedCallback.class);
|
||||
mIntf.addUidStateChangedCallback(mHandler, cb);
|
||||
mIntf.addUidStateChangedCallback(r -> r.run(), cb);
|
||||
return cb;
|
||||
}
|
||||
|
||||
@@ -795,30 +773,6 @@ public class AppOpsUidStateTrackerTest {
|
||||
assertEquals(MODE_IGNORED, mIntf.evalMode(uid, OP_NO_CAPABILITIES, MODE_FOREGROUND));
|
||||
}
|
||||
|
||||
private void getPostDelayedMessageArguments(AtomicReference<Message> message,
|
||||
AtomicLong delay) {
|
||||
|
||||
ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class);
|
||||
ArgumentCaptor<Long> delayCaptor = ArgumentCaptor.forClass(Long.class);
|
||||
|
||||
verify(mHandler).sendMessageDelayed(messageCaptor.capture(), delayCaptor.capture());
|
||||
|
||||
if (message != null) {
|
||||
message.set(messageCaptor.getValue());
|
||||
}
|
||||
if (delay != null) {
|
||||
delay.set(delayCaptor.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
private Message getLatestPostMessageArgument() {
|
||||
ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class);
|
||||
|
||||
verify(mHandler, atLeast(1)).sendMessage(messageCaptor.capture());
|
||||
|
||||
return messageCaptor.getValue();
|
||||
}
|
||||
|
||||
private UidProcStateUpdateBuilder procStateBuilder(int uid) {
|
||||
return new UidProcStateUpdateBuilder(mIntf, uid);
|
||||
}
|
||||
@@ -896,8 +850,14 @@ public class AppOpsUidStateTrackerTest {
|
||||
|
||||
private static class AppOpsUidStateTrackerTestClock extends Clock {
|
||||
|
||||
private AppOpsUidStateTrackerTestExecutor mExecutor;
|
||||
long mElapsedRealTime = 0x5f3759df;
|
||||
|
||||
AppOpsUidStateTrackerTestClock(AppOpsUidStateTrackerTestExecutor executor) {
|
||||
mExecutor = executor;
|
||||
executor.setUptime(mElapsedRealTime);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long elapsedRealtime() {
|
||||
return mElapsedRealTime;
|
||||
@@ -905,6 +865,53 @@ public class AppOpsUidStateTrackerTest {
|
||||
|
||||
void advanceTime(long time) {
|
||||
mElapsedRealTime += time;
|
||||
mExecutor.setUptime(mElapsedRealTime); // assume uptime == elapsedtime
|
||||
}
|
||||
}
|
||||
|
||||
private static class AppOpsUidStateTrackerTestExecutor implements DelayableExecutor {
|
||||
|
||||
private static class QueueElement implements Comparable<QueueElement> {
|
||||
|
||||
private long mExecutionTime;
|
||||
private Runnable mRunnable;
|
||||
|
||||
private QueueElement(long executionTime, Runnable runnable) {
|
||||
mExecutionTime = executionTime;
|
||||
mRunnable = runnable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(QueueElement queueElement) {
|
||||
return Long.compare(mExecutionTime, queueElement.mExecutionTime);
|
||||
}
|
||||
}
|
||||
|
||||
private long mUptime = 0;
|
||||
|
||||
private PriorityQueue<QueueElement> mDelayedMessages = new PriorityQueue();
|
||||
|
||||
@Override
|
||||
public void execute(Runnable runnable) {
|
||||
runnable.run();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void executeDelayed(Runnable runnable, long delay) {
|
||||
if (delay <= 0) {
|
||||
execute(runnable);
|
||||
}
|
||||
|
||||
mDelayedMessages.add(new QueueElement(mUptime + delay, runnable));
|
||||
}
|
||||
|
||||
private void setUptime(long uptime) {
|
||||
while (!mDelayedMessages.isEmpty()
|
||||
&& mDelayedMessages.peek().mExecutionTime <= uptime) {
|
||||
mDelayedMessages.poll().mRunnable.run();
|
||||
}
|
||||
|
||||
mUptime = uptime;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user