Skip to content

Commit 5799feb

Browse files
authored
Add UserHandle and BinderChannelCredentials to BinderChannelBuilder to support cross-user communication through OnDeviceServer. (#10197)
Add UserHandle and BinderChannelCredentials to BinderChannelBuilder to support cross-user ondevice server.
1 parent 4d2c3aa commit 5799feb

File tree

8 files changed

+375
-12
lines changed

8 files changed

+375
-12
lines changed

binder/src/androidTest/java/io/grpc/binder/internal/BinderClientTransportTest.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import io.grpc.Status.Code;
3636
import io.grpc.binder.AndroidComponentAddress;
3737
import io.grpc.binder.BindServiceFlags;
38+
import io.grpc.binder.BinderChannelCredentials;
3839
import io.grpc.binder.BinderServerBuilder;
3940
import io.grpc.binder.HostServices;
4041
import io.grpc.binder.InboundParcelablePolicy;
@@ -146,7 +147,9 @@ public BinderClientTransportBuilder setSecurityPolicy(SecurityPolicy securityPol
146147
public BinderTransport.BinderClientTransport build() {
147148
return new BinderTransport.BinderClientTransport(
148149
appContext,
150+
BinderChannelCredentials.forDefault(),
149151
serverAddress,
152+
null,
150153
BindServiceFlags.DEFAULTS,
151154
ContextCompat.getMainExecutor(appContext),
152155
executorServicePool,

binder/src/androidTest/java/io/grpc/binder/internal/BinderTransportTest.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import io.grpc.ServerStreamTracer;
2525
import io.grpc.binder.AndroidComponentAddress;
2626
import io.grpc.binder.BindServiceFlags;
27+
import io.grpc.binder.BinderChannelCredentials;
2728
import io.grpc.binder.HostServices;
2829
import io.grpc.binder.InboundParcelablePolicy;
2930
import io.grpc.binder.SecurityPolicies;
@@ -95,7 +96,9 @@ protected ManagedClientTransport newClientTransport(InternalServer server) {
9596
AndroidComponentAddress addr = (AndroidComponentAddress) server.getListenSocketAddress();
9697
return new BinderTransport.BinderClientTransport(
9798
appContext,
99+
BinderChannelCredentials.forDefault(),
98100
addr,
101+
null,
99102
BindServiceFlags.DEFAULTS,
100103
ContextCompat.getMainExecutor(appContext),
101104
executorServicePool,

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

Lines changed: 94 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import static com.google.common.base.Preconditions.checkState;
2121

2222
import android.content.Context;
23+
import android.os.UserHandle;
2324
import androidx.core.content.ContextCompat;
2425
import com.google.errorprone.annotations.DoNotCall;
2526
import io.grpc.ChannelCredentials;
@@ -71,7 +72,37 @@ public final class BinderChannelBuilder
7172
public static BinderChannelBuilder forAddress(
7273
AndroidComponentAddress directAddress, Context sourceContext) {
7374
return new BinderChannelBuilder(
74-
checkNotNull(directAddress, "directAddress"), null, sourceContext);
75+
checkNotNull(directAddress, "directAddress"),
76+
null,
77+
sourceContext,
78+
BinderChannelCredentials.forDefault());
79+
}
80+
81+
/**
82+
* Creates a channel builder that will bind to a remote Android service with provided
83+
* BinderChannelCredentials.
84+
*
85+
* <p>The underlying Android binding will be torn down when the channel becomes idle. This happens
86+
* after 30 minutes without use by default but can be configured via {@link
87+
* ManagedChannelBuilder#idleTimeout(long, TimeUnit)} or triggered manually with {@link
88+
* ManagedChannel#enterIdle()}.
89+
*
90+
* <p>You the caller are responsible for managing the lifecycle of any channels built by the
91+
* resulting builder. They will not be shut down automatically.
92+
*
93+
* @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).
95+
* @param channelCredentials the arbitrary binder specific channel credentials to be used to
96+
* establish a binder connection.
97+
* @return a new builder
98+
*/
99+
@ExperimentalApi("https://github.com/grpc/grpc-java/issues/10173")
100+
public static BinderChannelBuilder forAddress(
101+
AndroidComponentAddress directAddress,
102+
Context sourceContext,
103+
BinderChannelCredentials channelCredentials) {
104+
return new BinderChannelBuilder(
105+
checkNotNull(directAddress, "directAddress"), null, sourceContext, channelCredentials);
75106
}
76107

77108
/**
@@ -92,7 +123,37 @@ public static BinderChannelBuilder forAddress(
92123
* @return a new builder
93124
*/
94125
public static BinderChannelBuilder forTarget(String target, Context sourceContext) {
95-
return new BinderChannelBuilder(null, checkNotNull(target, "target"), sourceContext);
126+
return new BinderChannelBuilder(
127+
null,
128+
checkNotNull(target, "target"),
129+
sourceContext,
130+
BinderChannelCredentials.forDefault());
131+
}
132+
133+
/**
134+
* Creates a channel builder that will bind to a remote Android service, via a string target name
135+
* which will be resolved.
136+
*
137+
* <p>The underlying Android binding will be torn down when the channel becomes idle. This happens
138+
* after 30 minutes without use by default but can be configured via {@link
139+
* ManagedChannelBuilder#idleTimeout(long, TimeUnit)} or triggered manually with {@link
140+
* ManagedChannel#enterIdle()}.
141+
*
142+
* <p>You the caller are responsible for managing the lifecycle of any channels built by the
143+
* resulting builder. They will not be shut down automatically.
144+
*
145+
* @param target A target uri which should resolve into an {@link AndroidComponentAddress}
146+
* referencing the service to bind to.
147+
* @param sourceContext the context to bind from (e.g. The current Activity or Application).
148+
* @param channelCredentials the arbitrary binder specific channel credentials to be used to
149+
* establish a binder connection.
150+
* @return a new builder
151+
*/
152+
@ExperimentalApi("https://github.com/grpc/grpc-java/issues/10173")
153+
public static BinderChannelBuilder forTarget(
154+
String target, Context sourceContext, BinderChannelCredentials channelCredentials) {
155+
return new BinderChannelBuilder(
156+
null, checkNotNull(target, "target"), sourceContext, channelCredentials);
96157
}
97158

98159
/**
@@ -121,12 +182,14 @@ public static BinderChannelBuilder forTarget(String target) {
121182
private SecurityPolicy securityPolicy;
122183
private InboundParcelablePolicy inboundParcelablePolicy;
123184
private BindServiceFlags bindServiceFlags;
185+
@Nullable private UserHandle targetUserHandle;
124186
private boolean strictLifecycleManagement;
125187

126188
private BinderChannelBuilder(
127189
@Nullable AndroidComponentAddress directAddress,
128190
@Nullable String target,
129-
Context sourceContext) {
191+
Context sourceContext,
192+
BinderChannelCredentials channelCredentials) {
130193
mainThreadExecutor =
131194
ContextCompat.getMainExecutor(checkNotNull(sourceContext, "sourceContext"));
132195
securityPolicy = SecurityPolicies.internalOnly();
@@ -139,10 +202,12 @@ final class BinderChannelTransportFactoryBuilder
139202
public ClientTransportFactory buildClientTransportFactory() {
140203
return new TransportFactory(
141204
sourceContext,
205+
channelCredentials,
142206
mainThreadExecutor,
143207
schedulerPool,
144208
managedChannelImplBuilder.getOffloadExecutorPool(),
145209
securityPolicy,
210+
targetUserHandle,
146211
bindServiceFlags,
147212
inboundParcelablePolicy);
148213
}
@@ -216,6 +281,23 @@ public BinderChannelBuilder securityPolicy(SecurityPolicy securityPolicy) {
216281
return this;
217282
}
218283

284+
/**
285+
* Provides the target {@UserHandle} of the remote Android service.
286+
*
287+
* <p>When targetUserHandle is set, Context.bindServiceAsUser will used and additional Android
288+
* permissions will be required. If your usage does not require cross-user communications, please
289+
* do not set this field. It is the caller's responsibility to make sure that it holds the
290+
* corresponding permissions.
291+
*
292+
* @param targetUserHandle the target user to bind into.
293+
* @return this
294+
*/
295+
@ExperimentalApi("https://github.com/grpc/grpc-java/issues/10173")
296+
public BinderChannelBuilder bindAsUser(UserHandle targetUserHandle) {
297+
this.targetUserHandle = targetUserHandle;
298+
return this;
299+
}
300+
219301
/** Sets the policy for inbound parcelable objects. */
220302
public BinderChannelBuilder inboundParcelablePolicy(
221303
InboundParcelablePolicy inboundParcelablePolicy) {
@@ -245,30 +327,36 @@ public BinderChannelBuilder idleTimeout(long value, TimeUnit unit) {
245327
/** Creates new binder transports. */
246328
private static final class TransportFactory implements ClientTransportFactory {
247329
private final Context sourceContext;
330+
private final BinderChannelCredentials channelCredentials;
248331
private final Executor mainThreadExecutor;
249332
private final ObjectPool<ScheduledExecutorService> scheduledExecutorPool;
250333
private final ObjectPool<? extends Executor> offloadExecutorPool;
251334
private final SecurityPolicy securityPolicy;
252-
private final InboundParcelablePolicy inboundParcelablePolicy;
335+
@Nullable private final UserHandle targetUserHandle;
253336
private final BindServiceFlags bindServiceFlags;
337+
private final InboundParcelablePolicy inboundParcelablePolicy;
254338

255339
private ScheduledExecutorService executorService;
256340
private Executor offloadExecutor;
257341
private boolean closed;
258342

259343
TransportFactory(
260344
Context sourceContext,
345+
BinderChannelCredentials channelCredentials,
261346
Executor mainThreadExecutor,
262347
ObjectPool<ScheduledExecutorService> scheduledExecutorPool,
263348
ObjectPool<? extends Executor> offloadExecutorPool,
264349
SecurityPolicy securityPolicy,
350+
@Nullable UserHandle targetUserHandle,
265351
BindServiceFlags bindServiceFlags,
266352
InboundParcelablePolicy inboundParcelablePolicy) {
267353
this.sourceContext = sourceContext;
354+
this.channelCredentials = channelCredentials;
268355
this.mainThreadExecutor = mainThreadExecutor;
269356
this.scheduledExecutorPool = scheduledExecutorPool;
270357
this.offloadExecutorPool = offloadExecutorPool;
271358
this.securityPolicy = securityPolicy;
359+
this.targetUserHandle = targetUserHandle;
272360
this.bindServiceFlags = bindServiceFlags;
273361
this.inboundParcelablePolicy = inboundParcelablePolicy;
274362

@@ -284,7 +372,9 @@ public ConnectionClientTransport newClientTransport(
284372
}
285373
return new BinderTransport.BinderClientTransport(
286374
sourceContext,
375+
channelCredentials,
287376
(AndroidComponentAddress) addr,
377+
targetUserHandle,
288378
bindServiceFlags,
289379
mainThreadExecutor,
290380
scheduledExecutorPool,
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/*
2+
* Copyright 2022 The gRPC Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.grpc.binder;
18+
19+
import static com.google.common.base.Preconditions.checkNotNull;
20+
21+
import android.content.ComponentName;
22+
import io.grpc.ChannelCredentials;
23+
import io.grpc.ExperimentalApi;
24+
import javax.annotation.Nullable;
25+
26+
/** Additional arbitrary arguments to establish a Android binder connection channel. */
27+
@ExperimentalApi("https://github.com/grpc/grpc-java/issues/10173")
28+
public final class BinderChannelCredentials extends ChannelCredentials {
29+
30+
/**
31+
* Creates the default BinderChannelCredentials.
32+
*
33+
* @return a BinderChannelCredentials
34+
*/
35+
public static BinderChannelCredentials forDefault() {
36+
return new BinderChannelCredentials(null);
37+
}
38+
39+
/**
40+
* Creates a BinderChannelCredentials to be used with DevicePolicyManager API.
41+
*
42+
* @param devicePolicyAdminComponentName the admin component to be specified with
43+
* DevicePolicyManager.bindDeviceAdminServiceAsUser API.
44+
* @return a BinderChannelCredentials
45+
*/
46+
public static BinderChannelCredentials forDevicePolicyAdmin(
47+
ComponentName devicePolicyAdminComponentName) {
48+
return new BinderChannelCredentials(devicePolicyAdminComponentName);
49+
}
50+
51+
@Nullable private final ComponentName devicePolicyAdminComponentName;
52+
53+
private BinderChannelCredentials(@Nullable ComponentName devicePolicyAdminComponentName) {
54+
this.devicePolicyAdminComponentName = devicePolicyAdminComponentName;
55+
}
56+
57+
@Override
58+
public ChannelCredentials withoutBearerTokens() {
59+
return this;
60+
}
61+
62+
/**
63+
* Returns the admin component to be specified with DevicePolicyManager
64+
* bindDeviceAdminServiceAsUser API.
65+
*/
66+
@Nullable
67+
public ComponentName getDevicePolicyAdminComponentName() {
68+
return devicePolicyAdminComponentName;
69+
}
70+
}

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import android.os.Process;
2929
import android.os.RemoteException;
3030
import android.os.TransactionTooLargeException;
31+
import android.os.UserHandle;
3132
import com.google.common.annotations.VisibleForTesting;
3233
import com.google.common.base.Ticker;
3334
import com.google.common.util.concurrent.ListenableFuture;
@@ -46,6 +47,7 @@
4647
import io.grpc.StatusException;
4748
import io.grpc.binder.AndroidComponentAddress;
4849
import io.grpc.binder.BindServiceFlags;
50+
import io.grpc.binder.BinderChannelCredentials;
4951
import io.grpc.binder.InboundParcelablePolicy;
5052
import io.grpc.binder.SecurityPolicy;
5153
import io.grpc.internal.ClientStream;
@@ -568,7 +570,9 @@ public static final class BinderClientTransport extends BinderTransport
568570

569571
public BinderClientTransport(
570572
Context sourceContext,
573+
BinderChannelCredentials channelCredentials,
571574
AndroidComponentAddress targetAddress,
575+
@Nullable UserHandle targetUserHandle,
572576
BindServiceFlags bindServiceFlags,
573577
Executor mainThreadExecutor,
574578
ObjectPool<ScheduledExecutorService> executorServicePool,
@@ -590,7 +594,9 @@ public BinderClientTransport(
590594
new ServiceBinding(
591595
mainThreadExecutor,
592596
sourceContext,
597+
channelCredentials,
593598
targetAddress.asBindIntent(),
599+
targetUserHandle,
594600
bindServiceFlags.toInteger(),
595601
this);
596602
}

0 commit comments

Comments
 (0)