Loading services/core/java/com/android/server/attention/AttentionManagerService.java +56 −13 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import static android.service.attention.AttentionService.ATTENTION_FAILURE_CANCE import static android.service.attention.AttentionService.ATTENTION_FAILURE_UNKNOWN; import android.Manifest; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; import android.attention.AttentionManagerInternal; Loading Loading @@ -85,6 +86,10 @@ public class AttentionManagerService extends SystemService { /** If the check attention called within that period - cached value will be returned. */ private static final long STALE_AFTER_MILLIS = 5_000; /** The size of the buffer that stores recent attention check results. */ @VisibleForTesting protected static final int ATTENTION_CACHE_BUFFER_SIZE = 5; /** DeviceConfig flag name, if {@code true}, enables AttentionManagerService features. */ private static final String SERVICE_ENABLED = "service_enabled"; private static String sTestAttentionServicePackage; Loading Loading @@ -192,7 +197,8 @@ public class AttentionManagerService extends SystemService { userState.bindLocked(); // throttle frequent requests final AttentionCheckCache cache = userState.mAttentionCheckCache; final AttentionCheckCache cache = userState.mAttentionCheckCacheBuffer == null ? null : userState.mAttentionCheckCacheBuffer.getLast(); if (cache != null && now < cache.mLastComputed + STALE_AFTER_MILLIS) { callbackInternal.onSuccess(cache.mResult, cache.mTimestamp); return true; Loading Loading @@ -236,9 +242,11 @@ public class AttentionManagerService extends SystemService { } synchronized (mLock) { userState.mAttentionCheckCache = new AttentionCheckCache( SystemClock.uptimeMillis(), result, timestamp); if (userState.mAttentionCheckCacheBuffer == null) { userState.mAttentionCheckCacheBuffer = new AttentionCheckCacheBuffer(); } userState.mAttentionCheckCacheBuffer.add( new AttentionCheckCache(SystemClock.uptimeMillis(), result, timestamp)); } StatsLog.write( StatsLog.ATTENTION_MANAGER_SERVICE_RESULT_REPORTED, Loading Loading @@ -421,7 +429,41 @@ public class AttentionManagerService extends SystemService { } } private static final class AttentionCheckCache { @VisibleForTesting protected static final class AttentionCheckCacheBuffer { private final AttentionCheckCache[] mQueue; private int mStartIndex; private int mSize; AttentionCheckCacheBuffer() { mQueue = new AttentionCheckCache[ATTENTION_CACHE_BUFFER_SIZE]; mStartIndex = 0; mSize = 0; } public AttentionCheckCache getLast() { int lastIdx = (mStartIndex + mSize - 1) % ATTENTION_CACHE_BUFFER_SIZE; return mSize == 0 ? null : mQueue[lastIdx]; } public void add(@NonNull AttentionCheckCache cache) { int nextIndex = (mStartIndex + mSize) % ATTENTION_CACHE_BUFFER_SIZE; mQueue[nextIndex] = cache; if (mSize == ATTENTION_CACHE_BUFFER_SIZE) { mStartIndex++; } else { mSize++; } } public AttentionCheckCache get(int offset) { return offset >= mSize ? null : mQueue[(mStartIndex + offset) % ATTENTION_CACHE_BUFFER_SIZE]; } } @VisibleForTesting protected static final class AttentionCheckCache { private final long mLastComputed; private final int mResult; private final long mTimestamp; Loading Loading @@ -463,7 +505,7 @@ public class AttentionManagerService extends SystemService { @GuardedBy("mLock") AttentionCheck mCurrentAttentionCheck; @GuardedBy("mLock") AttentionCheckCache mAttentionCheckCache; AttentionCheckCacheBuffer mAttentionCheckCacheBuffer; @GuardedBy("mLock") private boolean mBinding; Loading Loading @@ -532,16 +574,17 @@ public class AttentionManagerService extends SystemService { pw.println("is fulfilled:=" + mCurrentAttentionCheck.mIsFulfilled); pw.decreaseIndent(); } if (mAttentionCheckCacheBuffer != null) { pw.println("attention check cache:"); if (mAttentionCheckCache != null) { for (int i = 0; i < mAttentionCheckCacheBuffer.mSize; i++) { pw.increaseIndent(); pw.println("last computed=" + mAttentionCheckCache.mLastComputed); pw.println("timestamp=" + mAttentionCheckCache.mTimestamp); pw.println("result=" + mAttentionCheckCache.mResult); pw.println("timestamp=" + mAttentionCheckCacheBuffer.get(i).mTimestamp); pw.println("result=" + mAttentionCheckCacheBuffer.get(i).mResult); pw.decreaseIndent(); } } } } private class AttentionServiceConnection implements ServiceConnection { @Override Loading services/tests/servicestests/src/com/android/server/attention/AttentionManagerServiceTest.java +47 −5 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package com.android.server.attention; import static com.android.server.attention.AttentionManagerService.ATTENTION_CACHE_BUFFER_SIZE; import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; Loading @@ -39,6 +41,8 @@ import android.service.attention.IAttentionService; import androidx.test.filters.SmallTest; import com.android.server.attention.AttentionManagerService.AttentionCheck; import com.android.server.attention.AttentionManagerService.AttentionCheckCache; import com.android.server.attention.AttentionManagerService.AttentionCheckCacheBuffer; import com.android.server.attention.AttentionManagerService.AttentionHandler; import com.android.server.attention.AttentionManagerService.UserState; Loading @@ -56,11 +60,16 @@ public class AttentionManagerServiceTest { private AttentionManagerService mSpyAttentionManager; private UserState mSpyUserState; private final int mTimeout = 1000; @Mock private AttentionCallbackInternal mMockAttentionCallbackInternal; @Mock private AttentionHandler mMockHandler; @Mock private IAttentionCallback mMockIAttentionCallback; @Mock private IPowerManager mMockIPowerManager; @Mock Context mContext; @Mock private AttentionCallbackInternal mMockAttentionCallbackInternal; @Mock private AttentionHandler mMockHandler; @Mock private IAttentionCallback mMockIAttentionCallback; @Mock private IPowerManager mMockIPowerManager; @Mock Context mContext; @Before public void setUp() throws RemoteException { Loading Loading @@ -140,12 +149,45 @@ public class AttentionManagerServiceTest { mSpyAttentionManager.onSwitchUser(userId); } @Test public void testAttentionCheckCacheBuffer_getLast_returnTheLastElement() { AttentionCheckCacheBuffer buffer = new AttentionCheckCacheBuffer(); buffer.add(new AttentionCheckCache(0, 0, 1L)); AttentionCheckCache cache = new AttentionCheckCache(0, 0, 2L); buffer.add(cache); assertThat(buffer.getLast()).isEqualTo(cache); } @Test public void testAttentionCheckCacheBuffer_get_returnNullWhenOutOfBoundary() { AttentionCheckCacheBuffer buffer = new AttentionCheckCacheBuffer(); assertThat(buffer.get(1)).isNull(); } @Test public void testAttentionCheckCacheBuffer_get_handleCircularIndexing() { AttentionCheckCacheBuffer buffer = new AttentionCheckCacheBuffer(); AttentionCheckCache cache = new AttentionCheckCache(0L, 0, 1L); // Insert SIZE+1 elements. for (int i = 0; i <= ATTENTION_CACHE_BUFFER_SIZE; i++) { if (i == 1) { buffer.add(cache); } else { buffer.add(new AttentionCheckCache(0L, 0, i)); } } // The element that was at index 1 should be at index 0 after inserting SIZE + 1 elements. assertThat(buffer.get(0)).isEqualTo(cache); } private class MockIAttentionService implements IAttentionService { public void checkAttention(IAttentionCallback callback) throws RemoteException { callback.onSuccess(0, 0); } public void cancelAttentionCheck(IAttentionCallback callback) { } public IBinder asBinder() { return null; } Loading Loading
services/core/java/com/android/server/attention/AttentionManagerService.java +56 −13 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import static android.service.attention.AttentionService.ATTENTION_FAILURE_CANCE import static android.service.attention.AttentionService.ATTENTION_FAILURE_UNKNOWN; import android.Manifest; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; import android.attention.AttentionManagerInternal; Loading Loading @@ -85,6 +86,10 @@ public class AttentionManagerService extends SystemService { /** If the check attention called within that period - cached value will be returned. */ private static final long STALE_AFTER_MILLIS = 5_000; /** The size of the buffer that stores recent attention check results. */ @VisibleForTesting protected static final int ATTENTION_CACHE_BUFFER_SIZE = 5; /** DeviceConfig flag name, if {@code true}, enables AttentionManagerService features. */ private static final String SERVICE_ENABLED = "service_enabled"; private static String sTestAttentionServicePackage; Loading Loading @@ -192,7 +197,8 @@ public class AttentionManagerService extends SystemService { userState.bindLocked(); // throttle frequent requests final AttentionCheckCache cache = userState.mAttentionCheckCache; final AttentionCheckCache cache = userState.mAttentionCheckCacheBuffer == null ? null : userState.mAttentionCheckCacheBuffer.getLast(); if (cache != null && now < cache.mLastComputed + STALE_AFTER_MILLIS) { callbackInternal.onSuccess(cache.mResult, cache.mTimestamp); return true; Loading Loading @@ -236,9 +242,11 @@ public class AttentionManagerService extends SystemService { } synchronized (mLock) { userState.mAttentionCheckCache = new AttentionCheckCache( SystemClock.uptimeMillis(), result, timestamp); if (userState.mAttentionCheckCacheBuffer == null) { userState.mAttentionCheckCacheBuffer = new AttentionCheckCacheBuffer(); } userState.mAttentionCheckCacheBuffer.add( new AttentionCheckCache(SystemClock.uptimeMillis(), result, timestamp)); } StatsLog.write( StatsLog.ATTENTION_MANAGER_SERVICE_RESULT_REPORTED, Loading Loading @@ -421,7 +429,41 @@ public class AttentionManagerService extends SystemService { } } private static final class AttentionCheckCache { @VisibleForTesting protected static final class AttentionCheckCacheBuffer { private final AttentionCheckCache[] mQueue; private int mStartIndex; private int mSize; AttentionCheckCacheBuffer() { mQueue = new AttentionCheckCache[ATTENTION_CACHE_BUFFER_SIZE]; mStartIndex = 0; mSize = 0; } public AttentionCheckCache getLast() { int lastIdx = (mStartIndex + mSize - 1) % ATTENTION_CACHE_BUFFER_SIZE; return mSize == 0 ? null : mQueue[lastIdx]; } public void add(@NonNull AttentionCheckCache cache) { int nextIndex = (mStartIndex + mSize) % ATTENTION_CACHE_BUFFER_SIZE; mQueue[nextIndex] = cache; if (mSize == ATTENTION_CACHE_BUFFER_SIZE) { mStartIndex++; } else { mSize++; } } public AttentionCheckCache get(int offset) { return offset >= mSize ? null : mQueue[(mStartIndex + offset) % ATTENTION_CACHE_BUFFER_SIZE]; } } @VisibleForTesting protected static final class AttentionCheckCache { private final long mLastComputed; private final int mResult; private final long mTimestamp; Loading Loading @@ -463,7 +505,7 @@ public class AttentionManagerService extends SystemService { @GuardedBy("mLock") AttentionCheck mCurrentAttentionCheck; @GuardedBy("mLock") AttentionCheckCache mAttentionCheckCache; AttentionCheckCacheBuffer mAttentionCheckCacheBuffer; @GuardedBy("mLock") private boolean mBinding; Loading Loading @@ -532,16 +574,17 @@ public class AttentionManagerService extends SystemService { pw.println("is fulfilled:=" + mCurrentAttentionCheck.mIsFulfilled); pw.decreaseIndent(); } if (mAttentionCheckCacheBuffer != null) { pw.println("attention check cache:"); if (mAttentionCheckCache != null) { for (int i = 0; i < mAttentionCheckCacheBuffer.mSize; i++) { pw.increaseIndent(); pw.println("last computed=" + mAttentionCheckCache.mLastComputed); pw.println("timestamp=" + mAttentionCheckCache.mTimestamp); pw.println("result=" + mAttentionCheckCache.mResult); pw.println("timestamp=" + mAttentionCheckCacheBuffer.get(i).mTimestamp); pw.println("result=" + mAttentionCheckCacheBuffer.get(i).mResult); pw.decreaseIndent(); } } } } private class AttentionServiceConnection implements ServiceConnection { @Override Loading
services/tests/servicestests/src/com/android/server/attention/AttentionManagerServiceTest.java +47 −5 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package com.android.server.attention; import static com.android.server.attention.AttentionManagerService.ATTENTION_CACHE_BUFFER_SIZE; import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; Loading @@ -39,6 +41,8 @@ import android.service.attention.IAttentionService; import androidx.test.filters.SmallTest; import com.android.server.attention.AttentionManagerService.AttentionCheck; import com.android.server.attention.AttentionManagerService.AttentionCheckCache; import com.android.server.attention.AttentionManagerService.AttentionCheckCacheBuffer; import com.android.server.attention.AttentionManagerService.AttentionHandler; import com.android.server.attention.AttentionManagerService.UserState; Loading @@ -56,11 +60,16 @@ public class AttentionManagerServiceTest { private AttentionManagerService mSpyAttentionManager; private UserState mSpyUserState; private final int mTimeout = 1000; @Mock private AttentionCallbackInternal mMockAttentionCallbackInternal; @Mock private AttentionHandler mMockHandler; @Mock private IAttentionCallback mMockIAttentionCallback; @Mock private IPowerManager mMockIPowerManager; @Mock Context mContext; @Mock private AttentionCallbackInternal mMockAttentionCallbackInternal; @Mock private AttentionHandler mMockHandler; @Mock private IAttentionCallback mMockIAttentionCallback; @Mock private IPowerManager mMockIPowerManager; @Mock Context mContext; @Before public void setUp() throws RemoteException { Loading Loading @@ -140,12 +149,45 @@ public class AttentionManagerServiceTest { mSpyAttentionManager.onSwitchUser(userId); } @Test public void testAttentionCheckCacheBuffer_getLast_returnTheLastElement() { AttentionCheckCacheBuffer buffer = new AttentionCheckCacheBuffer(); buffer.add(new AttentionCheckCache(0, 0, 1L)); AttentionCheckCache cache = new AttentionCheckCache(0, 0, 2L); buffer.add(cache); assertThat(buffer.getLast()).isEqualTo(cache); } @Test public void testAttentionCheckCacheBuffer_get_returnNullWhenOutOfBoundary() { AttentionCheckCacheBuffer buffer = new AttentionCheckCacheBuffer(); assertThat(buffer.get(1)).isNull(); } @Test public void testAttentionCheckCacheBuffer_get_handleCircularIndexing() { AttentionCheckCacheBuffer buffer = new AttentionCheckCacheBuffer(); AttentionCheckCache cache = new AttentionCheckCache(0L, 0, 1L); // Insert SIZE+1 elements. for (int i = 0; i <= ATTENTION_CACHE_BUFFER_SIZE; i++) { if (i == 1) { buffer.add(cache); } else { buffer.add(new AttentionCheckCache(0L, 0, i)); } } // The element that was at index 1 should be at index 0 after inserting SIZE + 1 elements. assertThat(buffer.get(0)).isEqualTo(cache); } private class MockIAttentionService implements IAttentionService { public void checkAttention(IAttentionCallback callback) throws RemoteException { callback.onSuccess(0, 0); } public void cancelAttentionCheck(IAttentionCallback callback) { } public IBinder asBinder() { return null; } Loading