• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 The Android Open Source Project
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 com.android.internal.infra;
18 
19 import static com.google.common.truth.Truth.assertThat;
20 
21 import static java.util.Objects.requireNonNull;
22 
23 import android.annotation.Nullable;
24 import android.app.Service;
25 import android.content.Context;
26 import android.content.Intent;
27 import android.os.IBinder;
28 import android.os.Process;
29 import android.os.UserHandle;
30 
31 import androidx.annotation.NonNull;
32 import androidx.test.platform.app.InstrumentationRegistry;
33 import androidx.test.runner.AndroidJUnit4;
34 
35 import com.android.frameworks.coretests.aidl.ITestServiceConnectorService;
36 import com.android.internal.infra.ServiceConnectorTest.CapturingServiceLifecycleCallbacks.ServiceLifeCycleEvent;
37 
38 import org.junit.Before;
39 import org.junit.Test;
40 import org.junit.runner.RunWith;
41 
42 import java.util.ArrayList;
43 import java.util.concurrent.CancellationException;
44 import java.util.concurrent.ExecutionException;
45 import java.util.concurrent.TimeUnit;
46 import java.util.concurrent.TimeoutException;
47 
48 /**
49  * Unit tests for {@link ServiceConnector}
50  */
51 @RunWith(AndroidJUnit4.class)
52 public class ServiceConnectorTest {
53 
54     private final CapturingServiceLifecycleCallbacks mCapturingServiceLifecycleCallbacks =
55             new CapturingServiceLifecycleCallbacks();
56     private ServiceConnector<ITestServiceConnectorService> mServiceConnector;
57 
58     @Before
setup()59     public void setup() {
60         Context context = InstrumentationRegistry.getInstrumentation().getContext();
61         Intent testServiceConnectorServiceIntent = new Intent(TestService.ACTION_TEST_SERVICE);
62         testServiceConnectorServiceIntent.setPackage(context.getPackageName());
63 
64         ServiceConnector.Impl<ITestServiceConnectorService> serviceConnector =
65                 new ServiceConnector.Impl<ITestServiceConnectorService>(
66                         context,
67                         testServiceConnectorServiceIntent,
68                         /* bindingFlags= */ 0,
69                         UserHandle.myUserId(),
70                         ITestServiceConnectorService.Stub::asInterface);
71         serviceConnector.setServiceLifecycleCallbacks(mCapturingServiceLifecycleCallbacks);
72         mServiceConnector = serviceConnector;
73     }
74 
75     @Test
connect_invokesLifecycleCallbacks()76     public void connect_invokesLifecycleCallbacks() throws Exception {
77         connectAndWaitForDone();
78 
79         assertThat(mCapturingServiceLifecycleCallbacks.getCapturedLifecycleEvents())
80                 .containsExactly(ServiceLifeCycleEvent.ON_CONNECTED)
81                 .inOrder();
82     }
83 
84     @Test
connect_alreadyConnected_invokesLifecycleCallbacksOnce()85     public void connect_alreadyConnected_invokesLifecycleCallbacksOnce() throws Exception {
86         connectAndWaitForDone();
87         connectAndWaitForDone();
88 
89         assertThat(mCapturingServiceLifecycleCallbacks.getCapturedLifecycleEvents())
90                 .containsExactly(ServiceLifeCycleEvent.ON_CONNECTED)
91                 .inOrder();
92     }
93 
94     @Test
unbind_neverConnected_noLifecycleCallbacks()95     public void unbind_neverConnected_noLifecycleCallbacks() {
96         unbindAndWaitForDone();
97 
98         assertThat(mCapturingServiceLifecycleCallbacks.getCapturedLifecycleEvents())
99                 .isEmpty();
100     }
101 
102     @Test
unbind_whileConnected_invokesLifecycleCallbacks()103     public void unbind_whileConnected_invokesLifecycleCallbacks() throws Exception {
104         connectAndWaitForDone();
105         unbindAndWaitForDone();
106 
107         assertThat(mCapturingServiceLifecycleCallbacks.getCapturedLifecycleEvents())
108                 .containsExactly(
109                         ServiceLifeCycleEvent.ON_CONNECTED,
110                         ServiceLifeCycleEvent.ON_DISCONNECTED)
111                 .inOrder();
112     }
113 
114 
115     @Test
unbind_alreadyUnbound_invokesLifecycleCallbacks()116     public void unbind_alreadyUnbound_invokesLifecycleCallbacks() throws Exception {
117         connectAndWaitForDone();
118         unbindAndWaitForDone();
119         unbindAndWaitForDone();
120 
121         assertThat(mCapturingServiceLifecycleCallbacks.getCapturedLifecycleEvents())
122                 .containsExactly(
123                         ServiceLifeCycleEvent.ON_CONNECTED,
124                         ServiceLifeCycleEvent.ON_DISCONNECTED)
125                 .inOrder();
126     }
127 
128     @Test
binds_connectsAndUnbindsMultipleTimes_invokesLifecycleCallbacks()129     public void binds_connectsAndUnbindsMultipleTimes_invokesLifecycleCallbacks() throws Exception {
130         connectAndWaitForDone();
131         unbindAndWaitForDone();
132         connectAndWaitForDone();
133         unbindAndWaitForDone();
134         connectAndWaitForDone();
135 
136         assertThat(mCapturingServiceLifecycleCallbacks.getCapturedLifecycleEvents())
137                 .containsExactly(
138                         ServiceLifeCycleEvent.ON_CONNECTED,
139                         ServiceLifeCycleEvent.ON_DISCONNECTED,
140                         ServiceLifeCycleEvent.ON_CONNECTED,
141                         ServiceLifeCycleEvent.ON_DISCONNECTED,
142                         ServiceLifeCycleEvent.ON_CONNECTED)
143                 .inOrder();
144     }
145 
146     @Test
processCrashes_whileConnected_invokesLifecycleCallbacks()147     public void processCrashes_whileConnected_invokesLifecycleCallbacks() throws Exception {
148         connectAndWaitForDone();
149         waitForDone(mServiceConnector.post(service -> service.crashProcess()));
150 
151         assertThat(mCapturingServiceLifecycleCallbacks.getCapturedLifecycleEvents())
152                 .containsExactly(
153                         ServiceLifeCycleEvent.ON_CONNECTED,
154                         ServiceLifeCycleEvent.ON_BINDER_DIED)
155                 .inOrder();
156     }
157 
connectAndWaitForDone()158     private void connectAndWaitForDone() {
159         waitForDone(mServiceConnector.connect());
160     }
161 
unbindAndWaitForDone()162     private void unbindAndWaitForDone() {
163         mServiceConnector.unbind();
164         InstrumentationRegistry.getInstrumentation().waitForIdleSync();
165     }
166 
waitForDone(AndroidFuture<?> androidFuture)167     private static void waitForDone(AndroidFuture<?> androidFuture) {
168         if (androidFuture.isDone()) {
169             return;
170         }
171 
172         try {
173             androidFuture.get(10, TimeUnit.SECONDS);
174         } catch (InterruptedException | TimeoutException ex) {
175             throw new RuntimeException(ex);
176         } catch (ExecutionException | CancellationException ex) {
177             // Failed and canceled futures are completed
178             return;
179         }
180     }
181 
182     public static final class CapturingServiceLifecycleCallbacks implements
183             ServiceConnector.ServiceLifecycleCallbacks<ITestServiceConnectorService> {
184         public enum ServiceLifeCycleEvent {
185             ON_CONNECTED,
186             ON_DISCONNECTED,
187             ON_BINDER_DIED,
188         }
189 
190         private final ArrayList<ServiceLifeCycleEvent> mCapturedLifecycleEventServices =
191                 new ArrayList<>();
192 
getCapturedLifecycleEvents()193         public ArrayList<ServiceLifeCycleEvent> getCapturedLifecycleEvents() {
194             return mCapturedLifecycleEventServices;
195         }
196 
197         @Override
onConnected(@onNull ITestServiceConnectorService service)198         public void onConnected(@NonNull ITestServiceConnectorService service) {
199             requireNonNull(service);
200             mCapturedLifecycleEventServices.add(ServiceLifeCycleEvent.ON_CONNECTED);
201         }
202 
203         @Override
onDisconnected(@onNull ITestServiceConnectorService service)204         public void onDisconnected(@NonNull ITestServiceConnectorService service) {
205             requireNonNull(service);
206             mCapturedLifecycleEventServices.add(ServiceLifeCycleEvent.ON_DISCONNECTED);
207         }
208 
209         @Override
onBinderDied()210         public void onBinderDied() {
211             mCapturedLifecycleEventServices.add(ServiceLifeCycleEvent.ON_BINDER_DIED);
212         }
213     }
214 
215     public static final class TestService extends Service {
216 
217         public static String ACTION_TEST_SERVICE = "android.intent.action.BIND_TEST_SERVICE";
218 
219         @Nullable
220         @Override
onBind(@ullable Intent intent)221         public IBinder onBind(@Nullable Intent intent) {
222             if (intent == null) {
223                 return null;
224             }
225 
226             if (!intent.getAction().equals(ACTION_TEST_SERVICE)) {
227                 return null;
228             }
229 
230             return new TestServiceConnectorService().asBinder();
231         }
232     }
233 
234     private static final class TestServiceConnectorService extends
235             ITestServiceConnectorService.Stub {
236         @Override
crashProcess()237         public void crashProcess() {
238             Process.killProcess(Process.myPid());
239         }
240     }
241 }
242 
243