2323
2424import android .app .Application ;
2525import android .content .ComponentName ;
26- import android .content .Intent ;
27- import android .os .IBinder ;
28- import android .os .Looper ;
29- import androidx .lifecycle .LifecycleService ;
3026import androidx .test .core .app .ApplicationProvider ;
3127import com .google .common .util .concurrent .Futures ;
3228import com .google .common .util .concurrent .ListenableFuture ;
4238import io .grpc .ServerServiceDefinition ;
4339import io .grpc .Status ;
4440import io .grpc .StatusRuntimeException ;
45- import io .grpc .binder .internal .MainThreadScheduledExecutorService ;
4641import io .grpc .protobuf .lite .ProtoLiteUtils ;
4742import io .grpc .stub .ClientCalls ;
4843import io .grpc .stub .ServerCalls ;
4944import java .io .IOException ;
5045import java .util .concurrent .ArrayBlockingQueue ;
51- import java .util .concurrent .ScheduledExecutorService ;
52- import javax .annotation .Nullable ;
5346import org .junit .After ;
5447import org .junit .Before ;
5548import org .junit .Test ;
5649import org .junit .runner .RunWith ;
57- import org .robolectric .Robolectric ;
5850import org .robolectric .RobolectricTestRunner ;
59- import org .robolectric .android .controller .ServiceController ;
51+ import org .robolectric .annotation .LooperMode ;
52+ import org .robolectric .annotation .LooperMode .Mode ;
6053
6154@ RunWith (RobolectricTestRunner .class )
55+ @ LooperMode (Mode .INSTRUMENTATION_TEST )
6256public final class RobolectricBinderSecurityTest {
6357
6458 private static final String SERVICE_NAME = "fake_service" ;
6559 private static final String FULL_METHOD_NAME = "fake_service/fake_method" ;
6660 private final Application context = ApplicationProvider .getApplicationContext ();
67- private ServiceController <SomeService > controller ;
68- private SomeService service ;
6961 private ManagedChannel channel ;
7062
7163 @ Before
7264 public void setUp () {
73- controller = Robolectric .buildService (SomeService .class );
74- service = controller .create ().get ();
75-
76- AndroidComponentAddress listenAddress = AndroidComponentAddress .forContext (service );
77- ScheduledExecutorService executor = service .getExecutor ();
65+ AndroidComponentAddress listenAddress = AndroidComponentAddress
66+ .forRemoteComponent (context .getPackageName (), "HostService" );
7867 channel =
7968 BinderChannelBuilder .forAddress (listenAddress , context )
80- .executor (executor )
81- .scheduledExecutorService (executor )
82- .offloadExecutor (executor )
8369 .build ();
84- idleLoopers ();
8570 }
8671
8772 @ After
8873 public void tearDown () {
8974 channel .shutdownNow ();
90- controller .destroy ();
9175 }
9276
9377 @ Test
9478 public void testAsyncServerSecurityPolicy_failed_returnsFailureStatus () throws Exception {
9579 ListenableFuture <Status > status = makeCall ();
96- service .setSecurityPolicyStatusWhenReady (Status .ALREADY_EXISTS );
97- idleLoopers ();
80+ statusesToSet .take ().set (Status .ALREADY_EXISTS );
9881
99- assertThat (Futures . getDone ( status ).getCode ()).isEqualTo (Status .Code .ALREADY_EXISTS );
82+ assertThat (status . get ( ).getCode ()).isEqualTo (Status .Code .ALREADY_EXISTS );
10083 }
10184
10285 @ Test
10386 public void testAsyncServerSecurityPolicy_failedFuture_failsWithCodeInternal () throws Exception {
10487 ListenableFuture <Status > status = makeCall ();
105- service .setSecurityPolicyFailed (new IllegalStateException ("oops" ));
106- idleLoopers ();
88+ statusesToSet .take ().setException (new IllegalStateException ("oops" ));
10789
108- assertThat (Futures . getDone ( status ).getCode ()).isEqualTo (Status .Code .INTERNAL );
90+ assertThat (status . get ( ).getCode ()).isEqualTo (Status .Code .INTERNAL );
10991 }
11092
11193 @ Test
11294 public void testAsyncServerSecurityPolicy_allowed_returnsOkStatus () throws Exception {
11395 ListenableFuture <Status > status = makeCall ();
114- service .setSecurityPolicyStatusWhenReady (Status .OK );
115- idleLoopers ();
96+ statusesToSet .take ().set (Status .OK );
11697
117- assertThat (Futures . getDone ( status ).getCode ()).isEqualTo (Status .Code .OK );
98+ assertThat (status . get ( ).getCode ()).isEqualTo (Status .Code .OK );
11899 }
119100
120101 private ListenableFuture <Status > makeCall () {
121102 ClientCall <Empty , Empty > call =
122- channel .newCall (
123- getMethodDescriptor (), CallOptions .DEFAULT .withExecutor (service .getExecutor ()));
103+ channel .newCall (getMethodDescriptor (), CallOptions .DEFAULT );
124104 ListenableFuture <Empty > responseFuture =
125105 ClientCalls .futureUnaryCall (call , Empty .getDefaultInstance ());
126106
127- idleLoopers ();
128-
129107 return Futures .catching (
130108 Futures .transform (responseFuture , unused -> Status .OK , directExecutor ()),
131109 StatusRuntimeException .class ,
132110 StatusRuntimeException ::getStatus ,
133111 directExecutor ());
134112 }
135113
136- private static void idleLoopers () {
137- shadowOf (Looper .getMainLooper ()).idle ();
138- }
139-
140114 private static MethodDescriptor <Empty , Empty > getMethodDescriptor () {
141115 MethodDescriptor .Marshaller <Empty > marshaller =
142116 ProtoLiteUtils .marshaller (Empty .getDefaultInstance ());
@@ -148,19 +122,13 @@ private static MethodDescriptor<Empty, Empty> getMethodDescriptor() {
148122 .build ();
149123 }
150124
151- private static class SomeService extends LifecycleService {
152-
153- private final IBinderReceiver binderReceiver = new IBinderReceiver ();
154- private final ArrayBlockingQueue <SettableFuture <Status >> statusesToSet =
155- new ArrayBlockingQueue <>(128 );
156- private Server server ;
157- private final ScheduledExecutorService scheduledExecutorService =
158- new MainThreadScheduledExecutorService ();
159-
160- @ Override
161- public void onCreate () {
162- super .onCreate ();
125+ private final IBinderReceiver binderReceiver = new IBinderReceiver ();
126+ private final ArrayBlockingQueue <SettableFuture <Status >> statusesToSet =
127+ new ArrayBlockingQueue <>(128 );
128+ private Server server ;
163129
130+ @ Before
131+ public void setupServer () {
164132 MethodDescriptor <Empty , Empty > methodDesc = getMethodDescriptor ();
165133 ServerCallHandler <Empty , Empty > callHandler =
166134 ServerCalls .asyncUnaryCall (
@@ -174,7 +142,7 @@ public void onCreate() {
174142 ServerServiceDefinition .builder (SERVICE_NAME ).addMethod (methodDef ).build ();
175143
176144 server =
177- BinderServerBuilder .forAddress (AndroidComponentAddress .forContext (this ), binderReceiver )
145+ BinderServerBuilder .forAddress (AndroidComponentAddress .forContext (context ), binderReceiver )
178146 .addService (def )
179147 .securityPolicy (
180148 ServerSecurityPolicy .newBuilder ()
@@ -183,70 +151,28 @@ public void onCreate() {
183151 new AsyncSecurityPolicy () {
184152 @ Override
185153 public ListenableFuture <Status > checkAuthorizationAsync (int uid ) {
186- return Futures .submitAsync (
187- () -> {
188154 SettableFuture <Status > status = SettableFuture .create ();
189155 statusesToSet .add (status );
190156 return status ;
191- },
192- getExecutor ());
157+ }
193158 }
194- } )
159+ )
195160 .build ())
196- .executor (getExecutor ())
197- .scheduledExecutorService (getExecutor ())
198161 .build ();
199162 try {
200163 server .start ();
201164 } catch (IOException e ) {
202165 throw new IllegalStateException (e );
203166 }
204167
205- Application context = ApplicationProvider .getApplicationContext ();
206- ComponentName componentName = new ComponentName (context , SomeService .class );
168+ ComponentName componentName = new ComponentName (context , "SomeService" );
207169 shadowOf (context )
208170 .setComponentNameAndServiceForBindService (
209171 componentName , checkNotNull (binderReceiver .get ()));
210172 }
211173
212- /**
213- * Returns an {@link ScheduledExecutorService} under which all of the gRPC computations run. The
214- * execution of any pending tasks on this executor can be triggered via {@link #idleLoopers()}.
215- */
216- ScheduledExecutorService getExecutor () {
217- return scheduledExecutorService ;
218- }
219-
220- void setSecurityPolicyStatusWhenReady (Status status ) {
221- getNextEnqueuedStatus ().set (status );
222- }
223-
224- void setSecurityPolicyFailed (Exception e ) {
225- getNextEnqueuedStatus ().setException (e );
226- }
227-
228- private SettableFuture <Status > getNextEnqueuedStatus () {
229- @ Nullable SettableFuture <Status > future = statusesToSet .poll ();
230- while (future == null ) {
231- // Keep idling until the future is available.
232- idleLoopers ();
233- future = statusesToSet .poll ();
234- }
235- return checkNotNull (future );
236- }
237-
238- @ Override
239- public IBinder onBind (Intent intent ) {
240- super .onBind (intent );
241- return checkNotNull (binderReceiver .get ());
242- }
243-
244- @ Override
245- public void onDestroy () {
246- super .onDestroy ();
247- server .shutdownNow ();
248- }
249-
250- /** A future representing a task submitted to a {@link Handler}. */
174+ @ After
175+ public void tearDownServer () {
176+ server .shutdownNow ();
251177 }
252178}
0 commit comments