[DO NOT MERGE] Fix BroadcastDispatcher registering with CURRENT

When a BroadcastReceiver is registered with UserHandle.CURRENT, the
current user should be obtained. This has to be cached in order to not
call ActivityManager every time.

As it is done in the initializer the initial value caching will happen
before any other BroadcastReceiver is actually registered. The caching
and updating is all done in the background thread.

Also, remove unnecessary dependency.

Test: manual
Test: atest BroadcastDispatcher
Fixes: 158298581
Change-Id: Idfd2dc65f9079c57e971250aa7b0aef222da5af5
This commit is contained in:
Fabian Kozynski
2020-06-08 11:14:58 -04:00
parent ef24e2121d
commit e771b7529e
6 changed files with 62 additions and 24 deletions

View File

@@ -62,7 +62,7 @@ Acquire the dispatcher by using `@Inject` to obtain a `BroadcastDispatcher`. The
* @param executor An executor to dispatch [BroadcastReceiver.onReceive]. Pass null to use an
* executor in the main thread (default).
* @param user A user handle to determine which broadcast should be dispatched to this receiver.
* By default, it is the current user.
* By default, it is the user of the context (system user in SystemUI).
* @throws IllegalArgumentException if the filter has other constraints that are not actions or
* categories or the filter has no actions.
*/

View File

@@ -16,8 +16,10 @@
package com.android.systemui.broadcast
import android.app.ActivityManager
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.os.Handler
import android.os.HandlerExecutor
@@ -29,14 +31,10 @@ import android.util.SparseArray
import com.android.internal.annotations.VisibleForTesting
import com.android.systemui.Dumpable
import com.android.systemui.broadcast.logging.BroadcastDispatcherLogger
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.dump.DumpManager
import java.io.FileDescriptor
import java.io.PrintWriter
import java.util.concurrent.Executor
import javax.inject.Inject
import javax.inject.Singleton
data class ReceiverData(
val receiver: BroadcastReceiver,
@@ -48,6 +46,8 @@ data class ReceiverData(
private const val MSG_ADD_RECEIVER = 0
private const val MSG_REMOVE_RECEIVER = 1
private const val MSG_REMOVE_RECEIVER_FOR_USER = 2
private const val MSG_USER_SWITCH = 3
private const val MSG_SET_STARTING_USER = 99
private const val TAG = "BroadcastDispatcher"
private const val DEBUG = true
@@ -62,21 +62,27 @@ private const val DEBUG = true
* permissions, schemes, data types, data authorities or priority different than 0.
* Cannot be used for getting sticky broadcasts (either as return of registering or as re-delivery).
*/
@Singleton
open class BroadcastDispatcher @Inject constructor (
open class BroadcastDispatcher constructor (
private val context: Context,
@Main private val mainHandler: Handler,
@Background private val bgLooper: Looper,
dumpManager: DumpManager,
private val bgLooper: Looper,
private val dumpManager: DumpManager,
private val logger: BroadcastDispatcherLogger
) : Dumpable {
) : Dumpable, BroadcastReceiver() {
// Only modify in BG thread
private val receiversByUser = SparseArray<UserBroadcastDispatcher>(20)
init {
// TODO: Don't do this in the constructor
fun initialize() {
dumpManager.registerDumpable(javaClass.name, this)
handler.sendEmptyMessage(MSG_SET_STARTING_USER)
registerReceiver(this, IntentFilter(Intent.ACTION_USER_SWITCHED), null, UserHandle.ALL)
}
override fun onReceive(context: Context, intent: Intent) {
if (intent.action == Intent.ACTION_USER_SWITCHED) {
val user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL)
handler.obtainMessage(MSG_USER_SWITCH, user, 0).sendToTarget()
}
}
/**
@@ -88,7 +94,7 @@ open class BroadcastDispatcher @Inject constructor (
* have at least one action.
* @param handler A handler to dispatch [BroadcastReceiver.onReceive].
* @param user A user handle to determine which broadcast should be dispatched to this receiver.
* By default, it is the current user.
* By default, it is the user of the context (system user in SystemUI).
* @throws IllegalArgumentException if the filter has other constraints that are not actions or
* categories or the filter has no actions.
*/
@@ -114,7 +120,7 @@ open class BroadcastDispatcher @Inject constructor (
* @param executor An executor to dispatch [BroadcastReceiver.onReceive]. Pass null to use an
* executor in the main thread (default).
* @param user A user handle to determine which broadcast should be dispatched to this receiver.
* By default, it is the current user.
* By default, it is the user of the context (system user in SystemUI).
* @throws IllegalArgumentException if the filter has other constraints that are not actions or
* categories or the filter has no actions.
*/
@@ -171,6 +177,7 @@ open class BroadcastDispatcher @Inject constructor (
override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) {
pw.println("Broadcast dispatcher:")
pw.println(" Current user: ${handler.currentUser}")
for (index in 0 until receiversByUser.size()) {
pw.println(" User ${receiversByUser.keyAt(index)}")
receiversByUser.valueAt(index).dump(fd, pw, args)
@@ -178,6 +185,8 @@ open class BroadcastDispatcher @Inject constructor (
}
private val handler = object : Handler(bgLooper) {
var currentUser = UserHandle.USER_SYSTEM
override fun handleMessage(msg: Message) {
when (msg.what) {
MSG_ADD_RECEIVER -> {
@@ -185,7 +194,7 @@ open class BroadcastDispatcher @Inject constructor (
// If the receiver asked to be registered under the current user, we register
// under the actual current user.
val userId = if (data.user.identifier == UserHandle.USER_CURRENT) {
context.userId
currentUser
} else {
data.user.identifier
}
@@ -208,6 +217,13 @@ open class BroadcastDispatcher @Inject constructor (
receiversByUser.get(msg.arg1)?.unregisterReceiver(msg.obj as BroadcastReceiver)
}
MSG_USER_SWITCH -> {
currentUser = msg.arg1
}
MSG_SET_STARTING_USER -> {
currentUser = ActivityManager.getCurrentUser()
}
else -> super.handleMessage(msg)
}
}

View File

@@ -25,6 +25,7 @@ import android.hardware.display.AmbientDisplayConfiguration;
import android.hardware.display.NightDisplayListener;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.ServiceManager;
import android.util.DisplayMetrics;
import android.view.Choreographer;
@@ -39,9 +40,12 @@ import com.android.internal.util.NotificationMessagingUtil;
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.ViewMediatorCallback;
import com.android.systemui.Prefs;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.broadcast.logging.BroadcastDispatcherLogger;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.doze.AlwaysOnDisplayPolicy;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.plugins.PluginInitializerImpl;
import com.android.systemui.shared.plugins.PluginManager;
@@ -178,6 +182,21 @@ public class DependencyProvider {
return ActivityManagerWrapper.getInstance();
}
/** Provides and initializes the {#link BroadcastDispatcher} for SystemUI */
@Singleton
@Provides
public BroadcastDispatcher providesBroadcastDispatcher(
Context context,
@Background Looper backgroundLooper,
DumpManager dumpManager,
BroadcastDispatcherLogger logger
) {
BroadcastDispatcher bD =
new BroadcastDispatcher(context, backgroundLooper, dumpManager, logger);
bD.initialize();
return bD;
}
@Singleton
@Provides
public DevicePolicyManagerWrapper provideDevicePolicyManagerWrapper() {

View File

@@ -73,8 +73,8 @@ public abstract class SysuiTestCase {
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), mock(BroadcastDispatcherLogger.class));
mFakeBroadcastDispatcher = new FakeBroadcastDispatcher(mContext, mock(Looper.class),
mock(DumpManager.class), mock(BroadcastDispatcherLogger.class));
mRealInstrumentation = InstrumentationRegistry.getInstrumentation();
Instrumentation inst = spy(mRealInstrumentation);

View File

@@ -18,6 +18,7 @@ package com.android.systemui.broadcast
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.os.Handler
import android.os.Looper
@@ -96,7 +97,6 @@ class BroadcastDispatcherTest : SysuiTestCase() {
broadcastDispatcher = TestBroadcastDispatcher(
mockContext,
Handler(testableLooper.looper),
testableLooper.looper,
mock(DumpManager::class.java),
logger,
@@ -177,7 +177,12 @@ class BroadcastDispatcherTest : SysuiTestCase() {
@Test
fun testRegisterCurrentAsActualUser() {
setUserMock(mockContext, user1)
val intent = Intent(Intent.ACTION_USER_SWITCHED).apply {
putExtra(Intent.EXTRA_USER_HANDLE, user1.identifier)
}
broadcastDispatcher.onReceive(mockContext, intent)
testableLooper.processAllMessages()
broadcastDispatcher.registerReceiverWithHandler(broadcastReceiver, intentFilter,
mockHandler, UserHandle.CURRENT)
@@ -240,12 +245,11 @@ class BroadcastDispatcherTest : SysuiTestCase() {
private class TestBroadcastDispatcher(
context: Context,
mainHandler: Handler,
bgLooper: Looper,
dumpManager: DumpManager,
logger: BroadcastDispatcherLogger,
var mockUBRMap: Map<Int, UserBroadcastDispatcher>
) : BroadcastDispatcher(context, mainHandler, bgLooper, dumpManager, logger) {
) : BroadcastDispatcher(context, bgLooper, dumpManager, logger) {
override fun createUBRForUser(userId: Int): UserBroadcastDispatcher {
return mockUBRMap.getOrDefault(userId, mock(UserBroadcastDispatcher::class.java))
}

View File

@@ -30,11 +30,10 @@ import java.util.concurrent.Executor
class FakeBroadcastDispatcher(
context: SysuiTestableContext,
handler: Handler,
looper: Looper,
dumpManager: DumpManager,
logger: BroadcastDispatcherLogger
) : BroadcastDispatcher(context, handler, looper, dumpManager, logger) {
) : BroadcastDispatcher(context, looper, dumpManager, logger) {
private val registeredReceivers = ArraySet<BroadcastReceiver>()