Merge "Add warnings for leaked receivers in tests" into rvc-dev am: eae6bb56e4 am: 51ebfd6055
Change-Id: I5d282324566a39e238545dbbc1287d5d0004488d
This commit is contained in:
@@ -94,7 +94,7 @@ open class BroadcastDispatcher @Inject constructor (
|
|||||||
@Deprecated(message = "Replacing Handler for Executor in SystemUI",
|
@Deprecated(message = "Replacing Handler for Executor in SystemUI",
|
||||||
replaceWith = ReplaceWith("registerReceiver(receiver, filter, executor, user)"))
|
replaceWith = ReplaceWith("registerReceiver(receiver, filter, executor, user)"))
|
||||||
@JvmOverloads
|
@JvmOverloads
|
||||||
fun registerReceiverWithHandler(
|
open fun registerReceiverWithHandler(
|
||||||
receiver: BroadcastReceiver,
|
receiver: BroadcastReceiver,
|
||||||
filter: IntentFilter,
|
filter: IntentFilter,
|
||||||
handler: Handler,
|
handler: Handler,
|
||||||
@@ -118,7 +118,7 @@ open class BroadcastDispatcher @Inject constructor (
|
|||||||
* categories or the filter has no actions.
|
* categories or the filter has no actions.
|
||||||
*/
|
*/
|
||||||
@JvmOverloads
|
@JvmOverloads
|
||||||
fun registerReceiver(
|
open fun registerReceiver(
|
||||||
receiver: BroadcastReceiver,
|
receiver: BroadcastReceiver,
|
||||||
filter: IntentFilter,
|
filter: IntentFilter,
|
||||||
executor: Executor? = context.mainExecutor,
|
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.
|
* @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()
|
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 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].
|
* @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)
|
handler.obtainMessage(MSG_REMOVE_RECEIVER_FOR_USER, user.identifier, 0, receiver)
|
||||||
.sendToTarget()
|
.sendToTarget()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
package com.android.systemui;
|
package com.android.systemui;
|
||||||
|
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.spy;
|
import static org.mockito.Mockito.spy;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
@@ -32,7 +33,10 @@ import androidx.test.InstrumentationRegistry;
|
|||||||
|
|
||||||
import com.android.keyguard.KeyguardUpdateMonitor;
|
import com.android.keyguard.KeyguardUpdateMonitor;
|
||||||
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
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.classifier.FalsingManagerFake;
|
||||||
|
import com.android.systemui.dump.DumpManager;
|
||||||
import com.android.systemui.plugins.FalsingManager;
|
import com.android.systemui.plugins.FalsingManager;
|
||||||
|
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
@@ -60,11 +64,14 @@ public abstract class SysuiTestCase {
|
|||||||
new DexmakerShareClassLoaderRule();
|
new DexmakerShareClassLoaderRule();
|
||||||
public TestableDependency mDependency;
|
public TestableDependency mDependency;
|
||||||
private Instrumentation mRealInstrumentation;
|
private Instrumentation mRealInstrumentation;
|
||||||
|
private FakeBroadcastDispatcher mFakeBroadcastDispatcher;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void SysuiSetup() throws Exception {
|
public void SysuiSetup() throws Exception {
|
||||||
SystemUIFactory.createFromConfig(mContext);
|
SystemUIFactory.createFromConfig(mContext);
|
||||||
mDependency = new TestableDependency(mContext);
|
mDependency = new TestableDependency(mContext);
|
||||||
|
mFakeBroadcastDispatcher = new FakeBroadcastDispatcher(mContext, mock(Handler.class),
|
||||||
|
mock(Looper.class), mock(DumpManager.class));
|
||||||
|
|
||||||
mRealInstrumentation = InstrumentationRegistry.getInstrumentation();
|
mRealInstrumentation = InstrumentationRegistry.getInstrumentation();
|
||||||
Instrumentation inst = spy(mRealInstrumentation);
|
Instrumentation inst = spy(mRealInstrumentation);
|
||||||
@@ -77,12 +84,18 @@ public abstract class SysuiTestCase {
|
|||||||
"SysUI Tests should use SysuiTestCase#getContext or SysuiTestCase#mContext");
|
"SysUI Tests should use SysuiTestCase#getContext or SysuiTestCase#mContext");
|
||||||
});
|
});
|
||||||
InstrumentationRegistry.registerInstance(inst, InstrumentationRegistry.getArguments());
|
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.
|
// A lot of tests get the FalsingManager, often via several layers of indirection.
|
||||||
// None of them actually need it.
|
// None of them actually need it.
|
||||||
mDependency.injectTestDependency(FalsingManager.class, new FalsingManagerFake());
|
mDependency.injectTestDependency(FalsingManager.class, new FalsingManagerFake());
|
||||||
mDependency.injectMockDependency(KeyguardUpdateMonitor.class);
|
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);
|
mDependency.injectMockDependency(LocalBluetoothManager.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,6 +108,8 @@ public abstract class SysuiTestCase {
|
|||||||
}
|
}
|
||||||
disallowTestableLooperAsMainThread();
|
disallowTestableLooperAsMainThread();
|
||||||
SystemUIFactory.cleanup();
|
SystemUIFactory.cleanup();
|
||||||
|
mContext.cleanUpReceivers(this.getClass().getSimpleName());
|
||||||
|
mFakeBroadcastDispatcher.cleanUpReceivers(this.getClass().getSimpleName());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -14,12 +14,24 @@
|
|||||||
|
|
||||||
package com.android.systemui;
|
package com.android.systemui;
|
||||||
|
|
||||||
|
import android.content.BroadcastReceiver;
|
||||||
import android.content.Context;
|
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.LeakCheck;
|
||||||
import android.testing.TestableContext;
|
import android.testing.TestableContext;
|
||||||
|
import android.util.ArraySet;
|
||||||
|
import android.util.Log;
|
||||||
import android.view.Display;
|
import android.view.Display;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
public class SysuiTestableContext extends TestableContext {
|
public class SysuiTestableContext extends TestableContext {
|
||||||
|
|
||||||
|
private Set<BroadcastReceiver> mRegisteredReceivers = new ArraySet<>();
|
||||||
|
|
||||||
public SysuiTestableContext(Context base) {
|
public SysuiTestableContext(Context base) {
|
||||||
super(base);
|
super(base);
|
||||||
setTheme(R.style.Theme_SystemUI);
|
setTheme(R.style.Theme_SystemUI);
|
||||||
@@ -40,4 +52,42 @@ public class SysuiTestableContext extends TestableContext {
|
|||||||
new SysuiTestableContext(getBaseContext().createDisplayContext(display));
|
new SysuiTestableContext(getBaseContext().createDisplayContext(display));
|
||||||
return context;
|
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