Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 522de715 authored by Fabian Kozynski's avatar Fabian Kozynski Committed by Automerger Merge Worker
Browse files

Merge "Add warnings for leaked receivers in tests" into rvc-dev am: eae6bb56

Change-Id: I231f66fc3431df7def02000b6692142dcf2325dd
parents 57e6a44d eae6bb56
Loading
Loading
Loading
Loading
+4 −4
Original line number Original line Diff line number Diff line
@@ -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()
    }
    }
+16 −1
Original line number Original line Diff line number Diff line
@@ -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());
    }
    }


    /**
    /**
+50 −0
Original line number Original line Diff line number Diff line
@@ -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);
    }
}
}
+71 −0
Original line number Original line Diff line number Diff line
/*
 * 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()
    }
}
 No newline at end of file