Merge "Remove cancel listeners from pending intent alarms" into qt-qpr1-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
c2ce0ac905
@@ -1257,7 +1257,12 @@ public final class PendingIntent implements Parcelable {
|
||||
return b != null ? new PendingIntent(b, in.getClassCookie(PendingIntent.class)) : null;
|
||||
}
|
||||
|
||||
/*package*/ PendingIntent(IIntentSender target) {
|
||||
/**
|
||||
* Creates a PendingIntent with the given target.
|
||||
* @param target the backing IIntentSender
|
||||
* @hide
|
||||
*/
|
||||
public PendingIntent(IIntentSender target) {
|
||||
mTarget = target;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package com.android.server;
|
||||
|
||||
import android.app.PendingIntent;
|
||||
|
||||
public interface AlarmManagerInternal {
|
||||
// Some other components in the system server need to know about
|
||||
// broadcast alarms currently in flight
|
||||
@@ -30,4 +32,10 @@ public interface AlarmManagerInternal {
|
||||
boolean isIdling();
|
||||
public void removeAlarmsForUid(int uid);
|
||||
public void registerInFlightListener(InFlightListener callback);
|
||||
|
||||
/**
|
||||
* Removes any alarm with the given pending intent with equality determined using
|
||||
* {@link android.app.PendingIntent#equals(java.lang.Object) PendingIntent.equals}
|
||||
*/
|
||||
void remove(PendingIntent rec);
|
||||
}
|
||||
|
||||
@@ -210,7 +210,6 @@ class AlarmManagerService extends SystemService {
|
||||
IAlarmListener mTimeTickTrigger;
|
||||
PendingIntent mDateChangeSender;
|
||||
Random mRandom;
|
||||
PendingIntent.CancelListener mOperationCancelListener;
|
||||
boolean mInteractive = true;
|
||||
long mNonInteractiveStartTime;
|
||||
long mNonInteractiveTime;
|
||||
@@ -1498,7 +1497,6 @@ class AlarmManagerService extends SystemService {
|
||||
|
||||
synchronized (mLock) {
|
||||
mHandler = new AlarmHandler();
|
||||
mOperationCancelListener = (intent) -> removeImpl(intent, null);
|
||||
mConstants = new Constants(mHandler);
|
||||
mAppWakeupHistory = new AppWakeupHistory(Constants.DEFAULT_APP_STANDBY_WINDOW);
|
||||
|
||||
@@ -1750,9 +1748,6 @@ class AlarmManagerService extends SystemService {
|
||||
} else {
|
||||
maxElapsed = triggerElapsed + windowLength;
|
||||
}
|
||||
if (operation != null) {
|
||||
operation.registerCancelListener(mOperationCancelListener);
|
||||
}
|
||||
synchronized (mLock) {
|
||||
if (DEBUG_BATCH) {
|
||||
Slog.v(TAG, "set(" + operation + ") : type=" + type
|
||||
@@ -1765,8 +1760,6 @@ class AlarmManagerService extends SystemService {
|
||||
"Maximum limit of concurrent alarms " + mConstants.MAX_ALARMS_PER_UID
|
||||
+ " reached for uid: " + UserHandle.formatUid(callingUid)
|
||||
+ ", callingPackage: " + callingPackage;
|
||||
mHandler.obtainMessage(AlarmHandler.UNREGISTER_CANCEL_LISTENER,
|
||||
operation).sendToTarget();
|
||||
Slog.w(TAG, errorMsg);
|
||||
throw new IllegalStateException(errorMsg);
|
||||
}
|
||||
@@ -1787,8 +1780,6 @@ class AlarmManagerService extends SystemService {
|
||||
if (ActivityManager.getService().isAppStartModeDisabled(callingUid, callingPackage)) {
|
||||
Slog.w(TAG, "Not setting alarm from " + callingUid + ":" + a
|
||||
+ " -- package not allowed to start");
|
||||
mHandler.obtainMessage(AlarmHandler.UNREGISTER_CANCEL_LISTENER,
|
||||
operation).sendToTarget();
|
||||
return;
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
@@ -2041,6 +2032,11 @@ class AlarmManagerService extends SystemService {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(PendingIntent pi) {
|
||||
mHandler.obtainMessage(AlarmHandler.REMOVE_FOR_CANCELED, pi).sendToTarget();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerInFlightListener(InFlightListener callback) {
|
||||
synchronized (mLock) {
|
||||
@@ -2146,8 +2142,6 @@ class AlarmManagerService extends SystemService {
|
||||
synchronized (mLock) {
|
||||
removeLocked(operation, listener);
|
||||
}
|
||||
mHandler.obtainMessage(AlarmHandler.UNREGISTER_CANCEL_LISTENER,
|
||||
operation).sendToTarget();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -4151,7 +4145,7 @@ class AlarmManagerService extends SystemService {
|
||||
public static final int APP_STANDBY_BUCKET_CHANGED = 5;
|
||||
public static final int APP_STANDBY_PAROLE_CHANGED = 6;
|
||||
public static final int REMOVE_FOR_STOPPED = 7;
|
||||
public static final int UNREGISTER_CANCEL_LISTENER = 8;
|
||||
public static final int REMOVE_FOR_CANCELED = 8;
|
||||
|
||||
AlarmHandler() {
|
||||
super(Looper.myLooper());
|
||||
@@ -4234,10 +4228,10 @@ class AlarmManagerService extends SystemService {
|
||||
}
|
||||
break;
|
||||
|
||||
case UNREGISTER_CANCEL_LISTENER:
|
||||
final PendingIntent pi = (PendingIntent) msg.obj;
|
||||
if (pi != null) {
|
||||
pi.unregisterCancelListener(mOperationCancelListener);
|
||||
case REMOVE_FOR_CANCELED:
|
||||
final PendingIntent operation = (PendingIntent) msg.obj;
|
||||
synchronized (mLock) {
|
||||
removeLocked(operation, null);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -4696,11 +4690,6 @@ class AlarmManagerService extends SystemService {
|
||||
Intent.EXTRA_ALARM_COUNT, alarm.count),
|
||||
mDeliveryTracker, mHandler, null,
|
||||
allowWhileIdle ? mIdleOptions : null);
|
||||
if (alarm.repeatInterval == 0) {
|
||||
// Keep the listener for repeating alarms until they get cancelled
|
||||
mHandler.obtainMessage(AlarmHandler.UNREGISTER_CANCEL_LISTENER,
|
||||
alarm.operation).sendToTarget();
|
||||
}
|
||||
} catch (PendingIntent.CanceledException e) {
|
||||
if (alarm.repeatInterval > 0) {
|
||||
// This IntentSender is no longer valid, but this
|
||||
|
||||
@@ -43,6 +43,7 @@ import android.util.Slog;
|
||||
|
||||
import com.android.internal.os.IResultReceiver;
|
||||
import com.android.internal.util.function.pooled.PooledLambda;
|
||||
import com.android.server.AlarmManagerInternal;
|
||||
import com.android.server.LocalServices;
|
||||
import com.android.server.wm.ActivityTaskManagerInternal;
|
||||
import com.android.server.wm.SafeActivityOptions;
|
||||
@@ -293,6 +294,8 @@ public class PendingIntentController {
|
||||
PendingIntentController::handlePendingIntentCancelled, this, callbacks);
|
||||
mH.sendMessage(m);
|
||||
}
|
||||
final AlarmManagerInternal ami = LocalServices.getService(AlarmManagerInternal.class);
|
||||
ami.remove(new PendingIntent(rec));
|
||||
}
|
||||
|
||||
private void handlePendingIntentCancelled(RemoteCallbackList<IResultReceiver> callbacks) {
|
||||
|
||||
@@ -24,6 +24,7 @@ import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_FREQUENT;
|
||||
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_RARE;
|
||||
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_WORKING_SET;
|
||||
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doCallRealMethod;
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doThrow;
|
||||
@@ -35,6 +36,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
|
||||
import static com.android.server.AlarmManagerService.ACTIVE_INDEX;
|
||||
import static com.android.server.AlarmManagerService.AlarmHandler.APP_STANDBY_BUCKET_CHANGED;
|
||||
import static com.android.server.AlarmManagerService.AlarmHandler.APP_STANDBY_PAROLE_CHANGED;
|
||||
import static com.android.server.AlarmManagerService.AlarmHandler.REMOVE_FOR_CANCELED;
|
||||
import static com.android.server.AlarmManagerService.Constants.KEY_ALLOW_WHILE_IDLE_LONG_TIME;
|
||||
import static com.android.server.AlarmManagerService.Constants.KEY_ALLOW_WHILE_IDLE_SHORT_TIME;
|
||||
import static com.android.server.AlarmManagerService.Constants.KEY_ALLOW_WHILE_IDLE_WHITELIST_DURATION;
|
||||
@@ -79,9 +81,9 @@ import android.provider.Settings;
|
||||
import android.util.Log;
|
||||
import android.util.SparseArray;
|
||||
|
||||
import androidx.test.filters.FlakyTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import com.android.dx.mockito.inline.extended.MockedVoidMethod;
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
|
||||
import org.junit.After;
|
||||
@@ -166,7 +168,6 @@ public class AlarmManagerServiceTest {
|
||||
}
|
||||
|
||||
public class Injector extends AlarmManagerService.Injector {
|
||||
boolean mIsAutomotiveOverride;
|
||||
|
||||
Injector(Context context) {
|
||||
super(context);
|
||||
@@ -256,6 +257,9 @@ public class AlarmManagerServiceTest {
|
||||
.when(() -> LocalServices.getService(DeviceIdleController.LocalService.class));
|
||||
doReturn(mUsageStatsManagerInternal).when(
|
||||
() -> LocalServices.getService(UsageStatsManagerInternal.class));
|
||||
doCallRealMethod().when((MockedVoidMethod) () ->
|
||||
LocalServices.addService(eq(AlarmManagerInternal.class), any()));
|
||||
doCallRealMethod().when(() -> LocalServices.getService(AlarmManagerInternal.class));
|
||||
when(mUsageStatsManagerInternal.getAppStandbyBucket(eq(TEST_CALLING_PACKAGE),
|
||||
eq(UserHandle.getUserId(TEST_CALLING_UID)), anyLong()))
|
||||
.thenReturn(STANDBY_BUCKET_ACTIVE);
|
||||
@@ -443,7 +447,6 @@ public class AlarmManagerServiceTest {
|
||||
assertEquals(expectedTriggerTime, mTestTimer.getElapsed());
|
||||
}
|
||||
|
||||
@FlakyTest(bugId = 130313408)
|
||||
@Test
|
||||
public void testEarliestAlarmSet() {
|
||||
final PendingIntent pi6 = getNewMockPendingIntent();
|
||||
@@ -661,11 +664,15 @@ public class AlarmManagerServiceTest {
|
||||
anyLong())).thenReturn(bucket);
|
||||
mAppStandbyListener.onAppIdleStateChanged(TEST_CALLING_PACKAGE,
|
||||
UserHandle.getUserId(TEST_CALLING_UID), false, bucket, 0);
|
||||
assertAndHandleMessageSync(APP_STANDBY_BUCKET_CHANGED);
|
||||
}
|
||||
|
||||
private void assertAndHandleMessageSync(int what) {
|
||||
final ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class);
|
||||
verify(mService.mHandler, atLeastOnce()).sendMessage(messageCaptor.capture());
|
||||
final Message lastMessage = messageCaptor.getValue();
|
||||
assertEquals("Unexpected message send to handler", lastMessage.what,
|
||||
APP_STANDBY_BUCKET_CHANGED);
|
||||
what);
|
||||
mService.mHandler.handleMessage(lastMessage);
|
||||
}
|
||||
|
||||
@@ -725,12 +732,7 @@ public class AlarmManagerServiceTest {
|
||||
|
||||
private void assertAndHandleParoleChanged(boolean parole) {
|
||||
mAppStandbyListener.onParoleStateChanged(parole);
|
||||
final ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class);
|
||||
verify(mService.mHandler, atLeastOnce()).sendMessage(messageCaptor.capture());
|
||||
final Message lastMessage = messageCaptor.getValue();
|
||||
assertEquals("Unexpected message send to handler", lastMessage.what,
|
||||
APP_STANDBY_PAROLE_CHANGED);
|
||||
mService.mHandler.handleMessage(lastMessage);
|
||||
assertAndHandleMessageSync(APP_STANDBY_PAROLE_CHANGED);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -1033,12 +1035,13 @@ public class AlarmManagerServiceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void alarmCountOnPendingIntentCancel() {
|
||||
public void alarmCountOnRemoveForCanceled() {
|
||||
final AlarmManagerInternal ami = LocalServices.getService(AlarmManagerInternal.class);
|
||||
final PendingIntent pi = getNewMockPendingIntent();
|
||||
setTestAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 123, pi);
|
||||
verify(pi).registerCancelListener(mService.mOperationCancelListener);
|
||||
setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + 12345, pi);
|
||||
assertEquals(1, mService.mAlarmsPerUid.get(TEST_CALLING_UID));
|
||||
mService.mOperationCancelListener.onCancelled(pi);
|
||||
ami.remove(pi);
|
||||
assertAndHandleMessageSync(REMOVE_FOR_CANCELED);
|
||||
assertEquals(0, mService.mAlarmsPerUid.get(TEST_CALLING_UID));
|
||||
}
|
||||
|
||||
@@ -1047,5 +1050,6 @@ public class AlarmManagerServiceTest {
|
||||
if (mMockingSession != null) {
|
||||
mMockingSession.finishMocking();
|
||||
}
|
||||
LocalServices.removeServiceForTest(AlarmManagerInternal.class);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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.am;
|
||||
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.app.ActivityManagerInternal;
|
||||
import android.app.AppGlobals;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.IPackageManager;
|
||||
import android.os.Looper;
|
||||
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import com.android.server.AlarmManagerInternal;
|
||||
import com.android.server.LocalServices;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoSession;
|
||||
import org.mockito.quality.Strictness;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class PendingIntentControllerTest {
|
||||
private static final String TEST_PACKAGE_NAME = "test-package-1";
|
||||
private static final int TEST_CALLING_UID = android.os.Process.myUid();
|
||||
private static final Intent[] TEST_INTENTS = new Intent[]{new Intent("com.test.intent")};
|
||||
|
||||
@Mock
|
||||
private UserController mUserController;
|
||||
@Mock
|
||||
private AlarmManagerInternal mAlarmManagerInternal;
|
||||
@Mock
|
||||
private ActivityManagerInternal mActivityManagerInternal;
|
||||
@Mock
|
||||
private IPackageManager mIPackageManager;
|
||||
|
||||
private MockitoSession mMockingSession;
|
||||
private PendingIntentController mPendingIntentController;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
mMockingSession = mockitoSession()
|
||||
.initMocks(this)
|
||||
.mockStatic(LocalServices.class)
|
||||
.mockStatic(AppGlobals.class)
|
||||
.strictness(Strictness.LENIENT) // Needed to stub LocalServices.getService twice
|
||||
.startMocking();
|
||||
doReturn(mAlarmManagerInternal).when(
|
||||
() -> LocalServices.getService(AlarmManagerInternal.class));
|
||||
doReturn(mActivityManagerInternal).when(
|
||||
() -> LocalServices.getService(ActivityManagerInternal.class));
|
||||
doReturn(mIPackageManager).when(() -> AppGlobals.getPackageManager());
|
||||
when(mIPackageManager.getPackageUid(eq(TEST_PACKAGE_NAME), anyInt(), anyInt())).thenReturn(
|
||||
TEST_CALLING_UID);
|
||||
mPendingIntentController = new PendingIntentController(Looper.getMainLooper(),
|
||||
mUserController);
|
||||
mPendingIntentController.onActivityManagerInternalAdded();
|
||||
}
|
||||
|
||||
private PendingIntentRecord createPendingIntentRecord(int flags) {
|
||||
return mPendingIntentController.getIntentSender(ActivityManager.INTENT_SENDER_BROADCAST,
|
||||
TEST_PACKAGE_NAME, TEST_CALLING_UID, 0, null, null, 0, TEST_INTENTS, null, flags,
|
||||
null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void alarmsRemovedOnCancel() {
|
||||
final PendingIntentRecord pir = createPendingIntentRecord(0);
|
||||
mPendingIntentController.cancelIntentSender(pir);
|
||||
final ArgumentCaptor<PendingIntent> piCaptor = ArgumentCaptor.forClass(PendingIntent.class);
|
||||
verify(mAlarmManagerInternal).remove(piCaptor.capture());
|
||||
assertEquals("Wrong target for pending intent passed to alarm manager", pir,
|
||||
piCaptor.getValue().getTarget());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void alarmsRemovedOnRecreateWithCancelCurrent() {
|
||||
final PendingIntentRecord pir = createPendingIntentRecord(0);
|
||||
createPendingIntentRecord(PendingIntent.FLAG_CANCEL_CURRENT);
|
||||
final ArgumentCaptor<PendingIntent> piCaptor = ArgumentCaptor.forClass(PendingIntent.class);
|
||||
verify(mAlarmManagerInternal).remove(piCaptor.capture());
|
||||
assertEquals("Wrong target for pending intent passed to alarm manager", pir,
|
||||
piCaptor.getValue().getTarget());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void alarmsRemovedOnSendingOneShot() {
|
||||
final PendingIntentRecord pir = createPendingIntentRecord(PendingIntent.FLAG_ONE_SHOT);
|
||||
pir.send(0, null, null, null, null, null, null);
|
||||
final ArgumentCaptor<PendingIntent> piCaptor = ArgumentCaptor.forClass(PendingIntent.class);
|
||||
verify(mAlarmManagerInternal).remove(piCaptor.capture());
|
||||
assertEquals("Wrong target for pending intent passed to alarm manager", pir,
|
||||
piCaptor.getValue().getTarget());
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
if (mMockingSession != null) {
|
||||
mMockingSession.finishMocking();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user