Merge "Add warnings for leaked receivers in tests" into rvc-dev am: eae6bb56e4
Change-Id: Ia8d7fe37e466c58c7bebd9cdc7fb07745cfe0063
This commit is contained in:
@@ -94,7 +94,7 @@ open class BroadcastDispatcher @Inject constructor (
|
||||
@Deprecated(message = "Replacing Handler for Executor in SystemUI",
|
||||
replaceWith = ReplaceWith("registerReceiver(receiver, filter, executor, user)"))
|
||||
@JvmOverloads
|
||||
fun registerReceiverWithHandler(
|
||||
open fun registerReceiverWithHandler(
|
||||
receiver: BroadcastReceiver,
|
||||
filter: IntentFilter,
|
||||
handler: Handler,
|
||||
@@ -118,7 +118,7 @@ open class BroadcastDispatcher @Inject constructor (
|
||||
* categories or the filter has no actions.
|
||||
*/
|
||||
@JvmOverloads
|
||||
fun registerReceiver(
|
||||
open fun registerReceiver(
|
||||
receiver: BroadcastReceiver,
|
||||
filter: IntentFilter,
|
||||
executor: Executor? = context.mainExecutor,
|
||||
@@ -149,7 +149,7 @@ open class BroadcastDispatcher @Inject constructor (
|
||||
*
|
||||
* @param receiver The receiver to unregister. It will be unregistered for all users.
|
||||
*/
|
||||
fun unregisterReceiver(receiver: BroadcastReceiver) {
|
||||
open fun unregisterReceiver(receiver: BroadcastReceiver) {
|
||||
handler.obtainMessage(MSG_REMOVE_RECEIVER, receiver).sendToTarget()
|
||||
}
|
||||
|
||||
@@ -159,7 +159,7 @@ open class BroadcastDispatcher @Inject constructor (
|
||||
* @param receiver The receiver to unregister. It will be unregistered for all users.
|
||||
* @param user The user associated to the registered [receiver]. It can be [UserHandle.ALL].
|
||||
*/
|
||||
fun unregisterReceiverForUser(receiver: BroadcastReceiver, user: UserHandle) {
|
||||
open fun unregisterReceiverForUser(receiver: BroadcastReceiver, user: UserHandle) {
|
||||
handler.obtainMessage(MSG_REMOVE_RECEIVER_FOR_USER, user.identifier, 0, receiver)
|
||||
.sendToTarget()
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.android.systemui;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@@ -32,7 +33,10 @@ import androidx.test.InstrumentationRegistry;
|
||||
|
||||
import com.android.keyguard.KeyguardUpdateMonitor;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
||||
import com.android.systemui.broadcast.BroadcastDispatcher;
|
||||
import com.android.systemui.broadcast.FakeBroadcastDispatcher;
|
||||
import com.android.systemui.classifier.FalsingManagerFake;
|
||||
import com.android.systemui.dump.DumpManager;
|
||||
import com.android.systemui.plugins.FalsingManager;
|
||||
|
||||
import org.junit.After;
|
||||
@@ -60,11 +64,14 @@ public abstract class SysuiTestCase {
|
||||
new DexmakerShareClassLoaderRule();
|
||||
public TestableDependency mDependency;
|
||||
private Instrumentation mRealInstrumentation;
|
||||
private FakeBroadcastDispatcher mFakeBroadcastDispatcher;
|
||||
|
||||
@Before
|
||||
public void SysuiSetup() throws Exception {
|
||||
SystemUIFactory.createFromConfig(mContext);
|
||||
mDependency = new TestableDependency(mContext);
|
||||
mFakeBroadcastDispatcher = new FakeBroadcastDispatcher(mContext, mock(Handler.class),
|
||||
mock(Looper.class), mock(DumpManager.class));
|
||||
|
||||
mRealInstrumentation = InstrumentationRegistry.getInstrumentation();
|
||||
Instrumentation inst = spy(mRealInstrumentation);
|
||||
@@ -77,12 +84,18 @@ public abstract class SysuiTestCase {
|
||||
"SysUI Tests should use SysuiTestCase#getContext or SysuiTestCase#mContext");
|
||||
});
|
||||
InstrumentationRegistry.registerInstance(inst, InstrumentationRegistry.getArguments());
|
||||
// Many tests end up creating a BroadcastDispatcher. Instead, give them a fake that will
|
||||
// record receivers registered. They are not actually leaked as they are kept just as a weak
|
||||
// reference and are never sent to the Context. This will also prevent a real
|
||||
// BroadcastDispatcher from actually registering receivers.
|
||||
mDependency.injectTestDependency(BroadcastDispatcher.class, mFakeBroadcastDispatcher);
|
||||
// A lot of tests get the FalsingManager, often via several layers of indirection.
|
||||
// None of them actually need it.
|
||||
mDependency.injectTestDependency(FalsingManager.class, new FalsingManagerFake());
|
||||
mDependency.injectMockDependency(KeyguardUpdateMonitor.class);
|
||||
|
||||
// TODO: b/151614195 investigate root cause of needing this mock dependency
|
||||
// A lot of tests get the LocalBluetoothManager, often via several layers of indirection.
|
||||
// None of them actually need it.
|
||||
mDependency.injectMockDependency(LocalBluetoothManager.class);
|
||||
}
|
||||
|
||||
@@ -95,6 +108,8 @@ public abstract class SysuiTestCase {
|
||||
}
|
||||
disallowTestableLooperAsMainThread();
|
||||
SystemUIFactory.cleanup();
|
||||
mContext.cleanUpReceivers(this.getClass().getSimpleName());
|
||||
mFakeBroadcastDispatcher.cleanUpReceivers(this.getClass().getSimpleName());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -14,12 +14,24 @@
|
||||
|
||||
package com.android.systemui;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.os.Handler;
|
||||
import android.os.UserHandle;
|
||||
import android.testing.LeakCheck;
|
||||
import android.testing.TestableContext;
|
||||
import android.util.ArraySet;
|
||||
import android.util.Log;
|
||||
import android.view.Display;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
public class SysuiTestableContext extends TestableContext {
|
||||
|
||||
private Set<BroadcastReceiver> mRegisteredReceivers = new ArraySet<>();
|
||||
|
||||
public SysuiTestableContext(Context base) {
|
||||
super(base);
|
||||
setTheme(R.style.Theme_SystemUI);
|
||||
@@ -40,4 +52,42 @@ public class SysuiTestableContext extends TestableContext {
|
||||
new SysuiTestableContext(getBaseContext().createDisplayContext(display));
|
||||
return context;
|
||||
}
|
||||
|
||||
public void cleanUpReceivers(String testName) {
|
||||
Set<BroadcastReceiver> copy = new ArraySet<>(mRegisteredReceivers);
|
||||
for (BroadcastReceiver r : copy) {
|
||||
try {
|
||||
unregisterReceiver(r);
|
||||
Log.w(testName, "Receiver not unregistered from Context: " + r);
|
||||
} catch (IllegalArgumentException e) {
|
||||
// Nothing to do here. Somehow it got unregistered.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
|
||||
mRegisteredReceivers.add(receiver);
|
||||
return super.registerReceiver(receiver, filter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
|
||||
String broadcastPermission, Handler scheduler) {
|
||||
mRegisteredReceivers.add(receiver);
|
||||
return super.registerReceiver(receiver, filter, broadcastPermission, scheduler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Intent registerReceiverAsUser(BroadcastReceiver receiver, UserHandle user,
|
||||
IntentFilter filter, String broadcastPermission, Handler scheduler) {
|
||||
mRegisteredReceivers.add(receiver);
|
||||
return super.registerReceiverAsUser(receiver, user, filter, broadcastPermission, scheduler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterReceiver(BroadcastReceiver receiver) {
|
||||
mRegisteredReceivers.remove(receiver);
|
||||
super.unregisterReceiver(receiver);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.systemui.broadcast
|
||||
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.IntentFilter
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.os.UserHandle
|
||||
import android.util.ArraySet
|
||||
import android.util.Log
|
||||
import com.android.systemui.SysuiTestableContext
|
||||
import com.android.systemui.dump.DumpManager
|
||||
import java.util.concurrent.Executor
|
||||
|
||||
class FakeBroadcastDispatcher(
|
||||
context: SysuiTestableContext,
|
||||
handler: Handler,
|
||||
looper: Looper,
|
||||
dumpManager: DumpManager
|
||||
) : BroadcastDispatcher(context, handler, looper, dumpManager) {
|
||||
|
||||
private val registeredReceivers = ArraySet<BroadcastReceiver>()
|
||||
|
||||
override fun registerReceiverWithHandler(
|
||||
receiver: BroadcastReceiver,
|
||||
filter: IntentFilter,
|
||||
handler: Handler,
|
||||
user: UserHandle
|
||||
) {
|
||||
registeredReceivers.add(receiver)
|
||||
}
|
||||
|
||||
override fun registerReceiver(
|
||||
receiver: BroadcastReceiver,
|
||||
filter: IntentFilter,
|
||||
executor: Executor?,
|
||||
user: UserHandle
|
||||
) {
|
||||
registeredReceivers.add(receiver)
|
||||
}
|
||||
|
||||
override fun unregisterReceiver(receiver: BroadcastReceiver) {
|
||||
registeredReceivers.remove(receiver)
|
||||
}
|
||||
|
||||
override fun unregisterReceiverForUser(receiver: BroadcastReceiver, user: UserHandle) {
|
||||
registeredReceivers.remove(receiver)
|
||||
}
|
||||
|
||||
fun cleanUpReceivers(testName: String) {
|
||||
registeredReceivers.forEach {
|
||||
Log.i(testName, "Receiver not unregistered from dispatcher: $it")
|
||||
}
|
||||
registeredReceivers.clear()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user