Skip to content

Commit 039f627

Browse files
committed
Add UserHandle and BinderChannelCredentials to BinderChannelBuilder to support cross-user ondevice server.
1 parent a685c7a commit 039f627

File tree

5 files changed

+56
-66
lines changed

5 files changed

+56
-66
lines changed

binder/src/main/java/io/grpc/binder/BinderChannelBuilder.java

Lines changed: 16 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,6 @@ public static BinderChannelBuilder forAddress(
7474
return new BinderChannelBuilder(
7575
checkNotNull(directAddress, "directAddress"),
7676
null,
77-
sourceContext,
7877
BinderChannelCredentials.forDefault(sourceContext));
7978
}
8079

@@ -91,17 +90,16 @@ public static BinderChannelBuilder forAddress(
9190
* resulting builder. They will not be shut down automatically.
9291
*
9392
* @param directAddress the {@link AndroidComponentAddress} referencing the service to bind to.
94-
* @param sourceContext the context to bind from (e.g. The current Activity or Application).
9593
* @param channelCredentials the arbitrary binder specific channel credentials to be used to
96-
* establish a binder connection.
94+
* establish a binder connection including the context to bind from (e.g. The current
95+
* Activity or Application).
9796
* @return a new builder
9897
*/
9998
public static BinderChannelBuilder forAddress(
10099
AndroidComponentAddress directAddress,
101-
Context sourceContext,
102100
BinderChannelCredentials channelCredentials) {
103101
return new BinderChannelBuilder(
104-
checkNotNull(directAddress, "directAddress"), null, sourceContext, channelCredentials);
102+
checkNotNull(directAddress, "directAddress"), null, channelCredentials);
105103
}
106104

107105
/**
@@ -125,7 +123,6 @@ public static BinderChannelBuilder forTarget(String target, Context sourceContex
125123
return new BinderChannelBuilder(
126124
null,
127125
checkNotNull(target, "target"),
128-
sourceContext,
129126
BinderChannelCredentials.forDefault(sourceContext));
130127
}
131128

@@ -144,14 +141,14 @@ public static BinderChannelBuilder forTarget(String target, Context sourceContex
144141
* @param target A target uri which should resolve into an {@link AndroidComponentAddress}
145142
* referencing the service to bind to.
146143
* @param channelCredentials the arbitrary binder specific channel credentials to be used to
147-
* establish a binder connection.
148-
* @param sourceContext the context to bind from (e.g. The current Activity or Application).
144+
* establish a binder connection including the context to bind from (e.g. The current
145+
* Activity or Application).
149146
* @return a new builder
150147
*/
151148
public static BinderChannelBuilder forTarget(
152-
String target, Context sourceContext, BinderChannelCredentials channelCredentials) {
149+
String target, BinderChannelCredentials channelCredentials) {
153150
return new BinderChannelBuilder(
154-
null, checkNotNull(target, "target"), sourceContext, channelCredentials);
151+
null, checkNotNull(target, "target"), channelCredentials);
155152
}
156153

157154
/**
@@ -173,42 +170,39 @@ public static BinderChannelBuilder forTarget(String target) {
173170
}
174171

175172
private final ManagedChannelImplBuilder managedChannelImplBuilder;
176-
private final BinderChannelCredentials channelCredentials;
177173

178174
private Executor mainThreadExecutor;
179175
private ObjectPool<ScheduledExecutorService> schedulerPool =
180176
SharedResourcePool.forResource(GrpcUtil.TIMER_SERVICE);
181177
private SecurityPolicy securityPolicy;
182178
private InboundParcelablePolicy inboundParcelablePolicy;
183179
private BindServiceFlags bindServiceFlags;
184-
@Nullable private UserHandle userHandle;
180+
@Nullable private UserHandle targetUserHandle;
185181
private boolean strictLifecycleManagement;
186182

187183
private BinderChannelBuilder(
188184
@Nullable AndroidComponentAddress directAddress,
189185
@Nullable String target,
190-
Context sourceContext,
191186
BinderChannelCredentials channelCredentials) {
192187
mainThreadExecutor =
193-
ContextCompat.getMainExecutor(checkNotNull(sourceContext, "sourceContext"));
188+
ContextCompat.getMainExecutor(
189+
checkNotNull(channelCredentials.getSourceContext(), "sourceContext"));
194190
securityPolicy = SecurityPolicies.internalOnly();
195191
inboundParcelablePolicy = InboundParcelablePolicy.DEFAULT;
196192
bindServiceFlags = BindServiceFlags.DEFAULTS;
197-
this.channelCredentials = channelCredentials;
198193

199194
final class BinderChannelTransportFactoryBuilder
200195
implements ClientTransportFactoryBuilder {
201196
@Override
202197
public ClientTransportFactory buildClientTransportFactory() {
203198
return new TransportFactory(
204-
sourceContext,
199+
channelCredentials,
205200
mainThreadExecutor,
206201
schedulerPool,
207202
managedChannelImplBuilder.getOffloadExecutorPool(),
208203
securityPolicy,
209204
bindServiceFlags,
210205
inboundParcelablePolicy,
211-
channelCredentials,
212206
targetUserHandle);
213207
}
214208
}
@@ -325,36 +319,35 @@ public BinderChannelBuilder idleTimeout(long value, TimeUnit unit) {
325319

326320
/** Creates new binder transports. */
327321
private static final class TransportFactory implements ClientTransportFactory {
328-
private final Context sourceContext;
322+
private final BinderChannelCredentials channelCredentials;
329323
private final Executor mainThreadExecutor;
330324
private final ObjectPool<ScheduledExecutorService> scheduledExecutorPool;
331325
private final ObjectPool<? extends Executor> offloadExecutorPool;
332326
private final SecurityPolicy securityPolicy;
333327
private final InboundParcelablePolicy inboundParcelablePolicy;
334328
private final BindServiceFlags bindServiceFlags;
329+
@Nullable private final UserHandle targetUserHandle;
335330

336331
private ScheduledExecutorService executorService;
337332
private Executor offloadExecutor;
338333
private boolean closed;
339334

340335
TransportFactory(
341-
Context sourceContext,
336+
BinderChannelCredentials channelCredentials,
342337
Executor mainThreadExecutor,
343338
ObjectPool<ScheduledExecutorService> scheduledExecutorPool,
344339
ObjectPool<? extends Executor> offloadExecutorPool,
345340
SecurityPolicy securityPolicy,
346341
BindServiceFlags bindServiceFlags,
347342
InboundParcelablePolicy inboundParcelablePolicy,
348-
BinderChannelCredentials channelCredentials,
349343
@Nullable UserHandle targetUserHandle) {
350-
this.sourceContext = sourceContext;
344+
this.channelCredentials = channelCredentials;
351345
this.mainThreadExecutor = mainThreadExecutor;
352346
this.scheduledExecutorPool = scheduledExecutorPool;
353347
this.offloadExecutorPool = offloadExecutorPool;
354348
this.securityPolicy = securityPolicy;
355349
this.bindServiceFlags = bindServiceFlags;
356350
this.inboundParcelablePolicy = inboundParcelablePolicy;
357-
this.channelCredentials = channelCredentials;
358351
this.targetUserHandle = targetUserHandle;
359352

360353
executorService = scheduledExecutorPool.getObject();
@@ -368,7 +361,7 @@ public ConnectionClientTransport newClientTransport(
368361
throw new IllegalStateException("The transport factory is closed.");
369362
}
370363
return new BinderTransport.BinderClientTransport(
371-
sourceContext,
364+
channelCredentials,
372365
(AndroidComponentAddress) addr,
373366
bindServiceFlags,
374367
mainThreadExecutor,
@@ -377,7 +370,6 @@ public ConnectionClientTransport newClientTransport(
377370
securityPolicy,
378371
inboundParcelablePolicy,
379372
options.getEagAttributes(),
380-
channelCredentials,
381373
targetUserHandle);
382374
}
383375

binder/src/main/java/io/grpc/binder/BinderChannelCredentials.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@ public ChannelCredentials withoutBearerTokens() {
4848
return this;
4949
}
5050

51+
public Context getSourceContext() {
52+
return sourceContext;
53+
}
54+
5155
@Nullable
5256
public ComponentName getDevicePolicyAdminComponentName() {
5357
return devicePolicyAdminComponentName;

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

Lines changed: 5 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -569,31 +569,7 @@ public static final class BinderClientTransport extends BinderTransport
569569
private int latestCallId = FIRST_CALL_ID;
570570

571571
public BinderClientTransport(
572-
Context sourceContext,
573-
AndroidComponentAddress targetAddress,
574-
BindServiceFlags bindServiceFlags,
575-
Executor mainThreadExecutor,
576-
ObjectPool<ScheduledExecutorService> executorServicePool,
577-
ObjectPool<? extends Executor> offloadExecutorPool,
578-
SecurityPolicy securityPolicy,
579-
InboundParcelablePolicy inboundParcelablePolicy,
580-
Attributes eagAttrs) {
581-
this(
582-
sourceContext,
583-
targetAddress,
584-
bindServiceFlags,
585-
mainThreadExecutor,
586-
executorServicePool,
587-
offloadExecutorPool,
588-
securityPolicy,
589-
inboundParcelablePolicy,
590-
eagAttrs,
591-
BinderChannelCredentials.forDefault(sourceContext),
592-
null);
593-
}
594-
595-
public BinderClientTransport(
596-
Context sourceContext,
572+
BinderChannelCredentials channelCredentials,
597573
AndroidComponentAddress targetAddress,
598574
BindServiceFlags bindServiceFlags,
599575
Executor mainThreadExecutor,
@@ -602,12 +578,12 @@ public BinderClientTransport(
602578
SecurityPolicy securityPolicy,
603579
InboundParcelablePolicy inboundParcelablePolicy,
604580
Attributes eagAttrs,
605-
BinderChannelCredentials channelCredentials,
606581
@Nullable UserHandle targetUserHandle) {
607582
super(
608583
executorServicePool,
609-
buildClientAttributes(eagAttrs, sourceContext, targetAddress, inboundParcelablePolicy),
610-
buildLogId(sourceContext, targetAddress));
584+
buildClientAttributes(
585+
eagAttrs, channelCredentials.getSourceContext(), targetAddress, inboundParcelablePolicy),
586+
buildLogId(channelCredentials.getSourceContext(), targetAddress));
611587
this.offloadExecutorPool = offloadExecutorPool;
612588
this.securityPolicy = securityPolicy;
613589
this.offloadExecutor = offloadExecutorPool.getObject();
@@ -617,10 +593,9 @@ public BinderClientTransport(
617593
serviceBinding =
618594
new ServiceBinding(
619595
mainThreadExecutor,
620-
sourceContext,
596+
channelCredentials,
621597
targetAddress.asBindIntent(),
622598
bindServiceFlags.toInteger(),
623-
channelCredentials,
624599
targetUserHandle,
625600
this);
626601
}

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

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -82,10 +82,9 @@ private enum State {
8282
@AnyThread
8383
ServiceBinding(
8484
Executor mainThreadExecutor,
85-
Context sourceContext,
85+
BinderChannelCredentials channelCredentials,
8686
Intent bindIntent,
8787
int bindFlags,
88-
BinderChannelCredentials channelCredentials,
8988
@Nullable UserHandle targetUserHandle,
9089
Observer observer) {
9190
// We need to synchronize here ensure other threads see all
@@ -94,9 +93,9 @@ private enum State {
9493
this.bindIntent = bindIntent;
9594
this.bindFlags = bindFlags;
9695
this.observer = observer;
97-
this.sourceContext = sourceContext;
98-
this.mainThreadExecutor = mainThreadExecutor;
9996
this.channelCredentials = channelCredentials;
97+
this.sourceContext = channelCredentials.getSourceContext();
98+
this.mainThreadExecutor = mainThreadExecutor;
10099
this.targetUserHandle = targetUserHandle;
101100
state = State.NOT_BINDING;
102101
reportedState = State.NOT_BINDING;
@@ -130,9 +129,9 @@ public synchronized void bind() {
130129
state = State.BINDING;
131130
Status bindResult =
132131
bindInternal(
133-
sourceContext, bindIntent, this, bindFlags, channelCredentials, targetUserHandle);
132+
sourceContext, channelCredentials, bindIntent, this, bindFlags, targetUserHandle);
134133
if (!bindResult.isOk()) {
135-
handleBindServiceFailure(sourceContext, this);
134+
handleBindServiceFailure(channelCredentials.getSourceContext(), this);
136135
state = State.UNBOUND;
137136
mainThreadExecutor.execute(() -> notifyUnbound(bindResult));
138137
}
@@ -141,10 +140,10 @@ public synchronized void bind() {
141140

142141
private static Status bindInternal(
143142
Context context,
143+
BinderChannelCredentials channelCredentials,
144144
Intent bindIntent,
145145
ServiceConnection conn,
146146
int flags,
147-
BinderChannelCredentials channelCredentials,
148147
@Nullable UserHandle targetUserHandle) {
149148
String methodName = "bindService";
150149
try {
@@ -161,7 +160,7 @@ private static Status bindInternal(
161160
if (channelCredentials.getDevicePolicyAdminComponentName() != null) {
162161
methodName = "DevicePolicyManager.bindDeviceAdminServiceAsUser";
163162
DevicePolicyManager devicePolicyManager =
164-
context.getSystemService(DevicePolicyManager.class);
163+
(DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
165164
if (!devicePolicyManager.bindDeviceAdminServiceAsUser(
166165
channelCredentials.getDevicePolicyAdminComponentName(),
167166
bindIntent,

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

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,16 @@
2929
import android.content.Context;
3030
import android.content.Intent;
3131
import android.os.IBinder;
32+
import android.os.Parcel;
33+
import android.os.UserHandle;
3234
import androidx.core.content.ContextCompat;
3335
import androidx.test.core.app.ApplicationProvider;
3436
import io.grpc.Status;
3537
import io.grpc.Status.Code;
3638
import io.grpc.binder.BinderChannelCredentials;
3739
import io.grpc.binder.internal.Bindable.Observer;
40+
import java.util.Arrays;
41+
import javax.annotation.Nullable;
3842
import org.junit.Before;
3943
import org.junit.Rule;
4044
import org.junit.Test;
@@ -260,9 +264,10 @@ public void testCallsAfterUnbindDontCrash() throws Exception {
260264
}
261265

262266
@Test
267+
@Config(sdk = 30)
263268
public void testBindWithTargetUserHandle() throws Exception {
264269
binding =
265-
newBuilder().setTargetUserHandle(UserHandle.getUserHandleForUid(/* userId= */ 0)).build();
270+
newBuilder().setTargetUserHandle(generateUserHandle(/* userId= */ 0)).build();
266271
shadowOf(getMainLooper()).idle();
267272

268273
binding.bind();
@@ -276,13 +281,15 @@ public void testBindWithTargetUserHandle() throws Exception {
276281
}
277282

278283
@Test
284+
@Config(sdk = 30)
279285
public void testBindWithDeviceAdmin() throws Exception {
280286
String deviceAdminClassName = "DevicePolicyAdmin";
281287
ComponentName adminComponent = new ComponentName(appContext, deviceAdminClassName);
282288
allowBindDeviceAdminForUser(appContext, adminComponent, /* userId= */ 0);
283289
binding =
284290
newBuilder()
285291
.setTargetUserHandle(UserHandle.getUserHandleForUid(/* userId= */ 0))
292+
.setTargetUserHandle(generateUserHandle(/* userId= */ 0))
286293
.setChannelCredentials(
287294
BinderChannelCredentials.forDevicePolicyAdmin(appContext, adminComponent))
288295
.build();
@@ -316,6 +323,20 @@ private static void allowBindDeviceAdminForUser(Context context, ComponentName a
316323
devicePolicyManager.setDeviceOwner(admin);
317324
devicePolicyManager.setBindDeviceAdminTargetUsers(
318325
Arrays.asList(UserHandle.getUserHandleForUid(userId)));
326+
shadowOf((DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE));
327+
devicePolicyManager.setDeviceOwner(admin);
328+
devicePolicyManager.setBindDeviceAdminTargetUsers(
329+
Arrays.asList(generateUserHandle(userId)));
330+
}
331+
332+
/** Generate UserHandles the hard way. */
333+
private static UserHandle generateUserHandle(int userId) {
334+
Parcel userParcel = Parcel.obtain();
335+
userParcel.writeInt(userId);
336+
userParcel.setDataPosition(0);
337+
UserHandle userHandle = new UserHandle(userParcel);
338+
userParcel.recycle();
339+
return userHandle;
319340
}
320341

321342
private class TestObserver implements Bindable.Observer {
@@ -344,7 +365,6 @@ public void onUnbound(Status reason) {
344365
}
345366

346367
private static class ServiceBindingBuilder {
347-
private Context sourceContext;
348368
private Observer observer;
349369
private Intent bindIntent = new Intent();
350370
private int bindServiceFlags;
@@ -390,8 +410,8 @@ public ServiceBindingBuilder setChannelCredentials(
390410

391411
public ServiceBinding build() {
392412
return new ServiceBinding(
393-
ContextCompat.getMainExecutor(sourceContext),
394-
sourceContext,
413+
ContextCompat.getMainExecutor(channelCredentials.getSourceContext()),
414+
channelCredentials,
395415
bindIntent,
396416
bindServiceFlags,
397417
channelCredentials,

0 commit comments

Comments
 (0)