Merge "Remove cancel listeners from pending intent alarms" into qt-qpr1-dev

This commit is contained in:
TreeHugger Robot
2019-11-18 21:53:31 +00:00
committed by Android (Google) Code Review
6 changed files with 175 additions and 36 deletions

View File

@@ -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;
}

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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) {

View File

@@ -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);
}
}

View File

@@ -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();
}
}
}