Skip to content

Commit 741ef76

Browse files
committed
ServiceBinding docs/tests
1 parent b2b006b commit 741ef76

2 files changed

Lines changed: 29 additions & 5 deletions

File tree

binder/src/main/java/io/grpc/binder/internal/Bindable.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,16 @@ interface Observer {
4848
void onUnbound(Status reason);
4949
}
5050

51-
/** Fetches details about the remote service from PackageManager *before* binding to it. */
51+
/**
52+
* Fetches details about the remote service from PackageManager without binding to it.
53+
*
54+
* <p>Resolving an untrusted address before binding to it lets you "screen" out problematic
55+
* servers before giving them a chance to run. However, note that the identity/existence of the
56+
* resolved Service can change between the time this method returns and the time you actually
57+
* bind/connect to it. For example, suppose the target package gets uninstalled right after this
58+
* method returns. In {@link Observer#onBound}, you should verify that the server you resolved is
59+
* the same one you connected to.
60+
*/
5261
@AnyThread
5362
ServiceInfo resolve() throws StatusException;
5463

binder/src/test/java/io/grpc/binder/internal/ServiceBindingTest.java

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import static android.content.Context.BIND_AUTO_CREATE;
2020
import static android.os.Looper.getMainLooper;
2121
import static com.google.common.truth.Truth.assertThat;
22+
import static org.junit.Assert.assertThrows;
2223
import static org.junit.Assert.fail;
2324
import static org.robolectric.Shadows.shadowOf;
2425

@@ -35,6 +36,7 @@
3536
import androidx.test.core.app.ApplicationProvider;
3637
import io.grpc.Status;
3738
import io.grpc.Status.Code;
39+
import io.grpc.StatusException;
3840
import io.grpc.binder.BinderChannelCredentials;
3941
import io.grpc.binder.internal.Bindable.Observer;
4042
import java.util.Arrays;
@@ -79,6 +81,7 @@ public void setUp() {
7981

8082
// Don't call onServiceDisconnected() upon unbindService(), just like the real Android doesn't.
8183
shadowApplication.setUnbindServiceCallsOnServiceDisconnected(false);
84+
shadowApplication.setBindServiceCallsOnServiceConnectedDirectly(false);
8285

8386
binding = newBuilder().build();
8487
shadowOf(getMainLooper()).idle();
@@ -283,18 +286,30 @@ public void testBindWithTargetUserHandle() throws Exception {
283286

284287
@Test
285288
public void testResolve() throws Exception {
289+
serviceInfo.processName = "x"; // ServiceInfo has no equals() so look for one distinctive field.
290+
shadowOf(appContext.getPackageManager()).addOrUpdateService(serviceInfo);
286291
ServiceInfo resolvedServiceInfo = binding.resolve();
287-
assertThat(resolvedServiceInfo.packageName).isEqualTo(serviceInfo.packageName);
288-
assertThat(resolvedServiceInfo.name).isEqualTo(serviceInfo.name);
292+
assertThat(resolvedServiceInfo.processName).isEqualTo(serviceInfo.processName);
289293
}
290294

291295
@Test
292296
@Config(sdk = 33)
293297
public void testResolveWithTargetUserHandle() throws Exception {
298+
serviceInfo.processName = "x"; // ServiceInfo has no equals() so look for one distinctive field.
299+
// Robolectric just ignores the user arg to resolveServiceAsUser() so this is all we can do.
300+
shadowOf(appContext.getPackageManager()).addOrUpdateService(serviceInfo);
294301
binding = newBuilder().setTargetUserHandle(generateUserHandle(/* userId= */ 0)).build();
295302
ServiceInfo resolvedServiceInfo = binding.resolve();
296-
assertThat(resolvedServiceInfo.packageName).isEqualTo(serviceInfo.packageName);
297-
assertThat(resolvedServiceInfo.name).isEqualTo(serviceInfo.name);
303+
assertThat(resolvedServiceInfo.processName).isEqualTo(serviceInfo.processName);
304+
}
305+
306+
@Test
307+
public void testResolveNonExistentServiceThrows() throws Exception {
308+
ComponentName doesNotExistService = new ComponentName("does.not.exist", "NoService");
309+
binding = newBuilder().setTargetComponent(doesNotExistService).build();
310+
StatusException statusException = assertThrows(StatusException.class, binding::resolve);
311+
assertThat(statusException.getStatus().getCode()).isEqualTo(Code.UNIMPLEMENTED);
312+
assertThat(statusException.getStatus().getDescription()).contains("does.not.exist");
298313
}
299314

300315
@Test

0 commit comments

Comments
 (0)