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

Commit 019feaac authored by Matt Pietal's avatar Matt Pietal
Browse files

Controls UI service cleanup

Make sure to unsusbscribe() when global actions goes away in call
cases. Rely on less state for service connections, which would get out
of sync in cases where the service process dies unexpectedly.

Bug: 148207527
Test: atest SystemUITests
Change-Id: I1b0a8143cdbd949549ab7165d1822e0ce22d03b5
parent c62ab875
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -170,7 +170,7 @@ open class ControlsBindingControllerImpl @Inject constructor(
    override fun bindServices(components: List<ComponentName>) {
        components.forEach {
            val provider = retrieveLifecycleManager(it)
            backgroundExecutor.execute { provider.bindPermanently() }
            backgroundExecutor.execute { provider.bindService() }
        }
    }

@@ -233,7 +233,7 @@ open class ControlsBindingControllerImpl @Inject constructor(
            provider.lastLoadCallback?.invoke(list) ?: run {
                Log.w(TAG, "Null callback")
            }
            provider.maybeUnbindAndRemoveCallback()
            provider.unbindService()
        }
    }

+25 −43
Original line number Diff line number Diff line
@@ -56,9 +56,7 @@ class ControlsProviderLifecycleManager(
    val token: IBinder = Binder()
    @GuardedBy("subscriptions")
    private val subscriptions = mutableListOf<IControlsSubscription>()
    private var unbindImmediate = false
    private var requiresBound = false
    private var isBound = false
    @GuardedBy("queuedMessages")
    private val queuedMessages: MutableSet<Message> = ArraySet()
    private var wrapper: ServiceWrapper? = null
@@ -98,30 +96,22 @@ class ControlsProviderLifecycleManager(
            }
            bindTryCount++
            try {
                isBound = context.bindServiceAsUser(intent, serviceConnection, BIND_FLAGS, user)
                context.bindServiceAsUser(intent, serviceConnection, BIND_FLAGS, user)
            } catch (e: SecurityException) {
                Log.e(TAG, "Failed to bind to service", e)
                isBound = false
            }
        } else {
            if (DEBUG) {
                Log.d(TAG, "Unbinding service $intent")
            }
            bindTryCount = 0
            wrapper = null
            if (isBound) {
            wrapper?.run {
                context.unbindService(serviceConnection)
                isBound = false
            }
            wrapper = null
        }
    }

    fun bindPermanently() {
        unbindImmediate = false
        unqueueMessage(Message.Unbind)
        bindService(true)
    }

    private val serviceConnection = object : ServiceConnection {
        override fun onServiceConnected(name: ComponentName, service: IBinder) {
            if (DEBUG) Log.d(TAG, "onServiceConnected $name")
@@ -135,7 +125,7 @@ class ControlsProviderLifecycleManager(

        override fun onServiceDisconnected(name: ComponentName?) {
            if (DEBUG) Log.d(TAG, "onServiceDisconnected $name")
            isBound = false
            wrapper = null
            bindService(false)
        }
    }
@@ -197,6 +187,15 @@ class ControlsProviderLifecycleManager(
        }
    }

    private fun invokeOrQueue(f: () -> Unit, msg: Message) {
        wrapper?.run {
            f()
        } ?: run {
            queueMessage(msg)
            bindService(true)
        }
    }

    fun maybeBindAndLoad(callback: LoadCallback) {
        unqueueMessage(Message.Unbind)
        lastLoadCallback = callback
@@ -205,22 +204,12 @@ class ControlsProviderLifecycleManager(
            Log.d(TAG, "Timeout waiting onLoad for $componentName")
            loadCallbackService.accept(token, emptyList())
        }, LOAD_TIMEOUT, TimeUnit.MILLISECONDS)
        if (isBound) {
            load()
        } else {
            queueMessage(Message.Load)
            unbindImmediate = true
            bindService(true)
        }

        invokeOrQueue(::load, Message.Load)
    }

    fun maybeBindAndSubscribe(controlIds: List<String>) {
        if (isBound) {
            subscribe(controlIds)
        } else {
            queueMessage(Message.Subscribe(controlIds))
            bindService(true)
        }
        invokeOrQueue({ subscribe(controlIds) }, Message.Subscribe(controlIds))
    }

    private fun subscribe(controlIds: List<String>) {
@@ -234,12 +223,7 @@ class ControlsProviderLifecycleManager(
    }

    fun maybeBindAndSendAction(controlId: String, action: ControlAction) {
        if (isBound) {
            action(controlId, action)
        } else {
            queueMessage(Message.Action(controlId, action))
            bindService(true)
        }
        invokeOrQueue({ action(controlId, action) }, Message.Action(controlId, action))
    }

    private fun action(controlId: String, action: ControlAction) {
@@ -276,25 +260,23 @@ class ControlsProviderLifecycleManager(
        }
    }

    fun maybeUnbindAndRemoveCallback() {
    fun bindService() {
        unqueueMessage(Message.Unbind)
        bindService(true)
    }

    fun unbindService() {
        lastLoadCallback = null
        onLoadCanceller?.run()
        onLoadCanceller = null
        if (unbindImmediate) {
            bindService(false)
        }
    }

    fun unbindService() {
        unbindImmediate = true
        maybeUnbindAndRemoveCallback()
        bindService(false)
    }

    override fun toString(): String {
        return StringBuilder("ControlsProviderLifecycleManager(").apply {
            append("component=$componentName")
            append(", user=$user")
            append(", bound=$isBound")
            append(")")
        }.toString()
    }
+1 −0
Original line number Diff line number Diff line
@@ -1801,6 +1801,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,

        void dismissImmediately() {
            mShowing = false;
            if (mControlsUiController != null) mControlsUiController.hide();
            dismissPanel();
            resetOrientation();
            completeDismiss();
+2 −2
Original line number Diff line number Diff line
@@ -103,7 +103,7 @@ class ControlsBindingControllerTest : SysuiTestCase() {
        assertEquals(setOf(TEST_COMPONENT_NAME_1, TEST_COMPONENT_NAME_2),
                providers.map { it.componentName }.toSet())
        providers.forEach {
            verify(it).bindPermanently()
            verify(it).bindService()
        }
    }

+3 −3
Original line number Diff line number Diff line
@@ -99,13 +99,13 @@ class ControlsProviderLifecycleManagerTest : SysuiTestCase() {

    @Test
    fun testBindService() {
        manager.bindPermanently()
        manager.bindService()
        assertTrue(mContext.isBound(componentName))
    }

    @Test
    fun testUnbindService() {
        manager.bindPermanently()
        manager.bindService()
        manager.unbindService()
        assertFalse(mContext.isBound(componentName))
    }
@@ -125,7 +125,7 @@ class ControlsProviderLifecycleManagerTest : SysuiTestCase() {
    fun testMaybeUnbind_bindingAndCallback() {
        manager.maybeBindAndLoad {}

        manager.maybeUnbindAndRemoveCallback()
        manager.unbindService()
        assertFalse(mContext.isBound(componentName))
        assertNull(manager.lastLoadCallback)
    }