Handle bindService errors in ObservableServiceConnection

If the component doesn't exist, or if we don't have permission to bind
to it, a SecurityException is thrown. In this case, we should return
false instead of crashing the process.

Bug: 271997433
Test: atest ObservableServiceConnectionTest
Change-Id: I2869e3438ead888b20ab00f643ac37e4373e924e
This commit is contained in:
Lucas Silva
2023-03-07 08:51:16 -05:00
parent b85665b316
commit d64f7b0bc6
2 changed files with 29 additions and 6 deletions

View File

@@ -119,11 +119,11 @@ public class ObservableServiceConnection<T> implements ServiceConnection {
/**
* Default constructor for {@link ObservableServiceConnection}.
* @param context The context from which the service will be bound with.
* @param context The context from which the service will be bound with.
* @param serviceIntent The intent to bind service with.
* @param executor The executor for connection callbacks to be delivered on
* @param transformer A {@link ServiceTransformer} for transforming the resulting service
* into a desired type.
* @param executor The executor for connection callbacks to be delivered on
* @param transformer A {@link ServiceTransformer} for transforming the resulting service
* into a desired type.
*/
@Inject
public ObservableServiceConnection(Context context, Intent serviceIntent,
@@ -143,7 +143,13 @@ public class ObservableServiceConnection<T> implements ServiceConnection {
* @return {@code true} if initiating binding succeed, {@code false} otherwise.
*/
public boolean bind() {
final boolean bindResult = mContext.bindService(mServiceIntent, mFlags, mExecutor, this);
boolean bindResult = false;
try {
bindResult = mContext.bindService(mServiceIntent, mFlags, mExecutor, this);
} catch (SecurityException e) {
Log.d(TAG, "Could not bind to service", e);
mContext.unbindService(this);
}
mBoundCalled = true;
if (DEBUG) {
Log.d(TAG, "bind. bound:" + bindResult);
@@ -197,7 +203,7 @@ public class ObservableServiceConnection<T> implements ServiceConnection {
Log.d(TAG, "removeCallback:" + callback);
}
mExecutor.execute(()-> mCallbacks.removeIf(el -> el.get() == callback));
mExecutor.execute(() -> mCallbacks.removeIf(el-> el.get() == callback));
}
private void onDisconnected(@DisconnectReason int reason) {

View File

@@ -16,6 +16,8 @@
package com.android.systemui.util.service;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.clearInvocations;
@@ -169,4 +171,19 @@ public class ObservableServiceConnectionTest extends SysuiTestCase {
verify(mCallback).onDisconnected(eq(connection),
eq(ObservableServiceConnection.DISCONNECT_REASON_UNBIND));
}
@Test
public void testBindServiceThrowsError() {
ObservableServiceConnection<Foo> connection = new ObservableServiceConnection<>(mContext,
mIntent, mExecutor, mTransformer);
connection.addCallback(mCallback);
when(mContext.bindService(eq(mIntent), anyInt(), eq(mExecutor), eq(connection)))
.thenThrow(new SecurityException());
// Verify that the exception was caught and that bind returns false, and we properly
// unbind.
assertThat(connection.bind()).isFalse();
verify(mContext).unbindService(connection);
}
}