1 /*
2  * Copyright (C) 2021 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.server.app;
18 
19 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
20 
21 import static com.google.common.truth.Truth.assertThat;
22 
23 import static org.mockito.Mockito.any;
24 import static org.mockito.Mockito.spy;
25 import static org.mockito.Mockito.verify;
26 import static org.mockito.Mockito.verifyNoMoreInteractions;
27 import static org.mockito.Mockito.when;
28 
29 import android.content.BroadcastReceiver;
30 import android.content.ComponentName;
31 import android.content.Context;
32 import android.content.Intent;
33 import android.content.pm.UserInfo;
34 import android.net.Uri;
35 import android.os.UserHandle;
36 import android.platform.test.annotations.Presubmit;
37 
38 import androidx.test.filters.SmallTest;
39 import androidx.test.runner.AndroidJUnit4;
40 
41 import com.android.internal.util.ConcurrentUtils;
42 import com.android.server.SystemService;
43 import com.android.server.app.GameServiceConfiguration.GameServiceComponentConfiguration;
44 
45 import org.junit.After;
46 import org.junit.Before;
47 import org.junit.Test;
48 import org.junit.runner.RunWith;
49 import org.mockito.ArgumentCaptor;
50 import org.mockito.InOrder;
51 import org.mockito.Mock;
52 import org.mockito.Mockito;
53 import org.mockito.MockitoSession;
54 import org.mockito.quality.Strictness;
55 
56 
57 /** Unit tests for {@link GameServiceController}. */
58 @RunWith(AndroidJUnit4.class)
59 @SmallTest
60 @Presubmit
61 public final class GameServiceControllerTest {
62     private static final UserHandle USER_HANDLE_10 = new UserHandle(10);
63     private static final UserHandle USER_HANDLE_11 = new UserHandle(11);
64     private static final SystemService.TargetUser USER_10 = user(10);
65     private static final SystemService.TargetUser USER_11 = user(11);
66     private static final String PROVIDER_A_PACKAGE_NAME = "com.provider.a";
67     private static final ComponentName PROVIDER_A_SERVICE_A =
68             new ComponentName(PROVIDER_A_PACKAGE_NAME, "com.provider.a.ServiceA");
69     private static final ComponentName PROVIDER_A_SERVICE_B =
70             new ComponentName(PROVIDER_A_PACKAGE_NAME, "com.provider.a.ServiceB");
71     private static final ComponentName PROVIDER_A_SERVICE_C =
72             new ComponentName(PROVIDER_A_PACKAGE_NAME, "com.provider.a.ServiceC");
73 
74     private MockitoSession mMockingSession;
75     private GameServiceController mGameServiceManager;
76     @Mock
77     private Context mMockContext;
78     @Mock
79     private GameServiceProviderSelector mMockGameServiceProviderSelector;
80     @Mock
81     private GameServiceProviderInstanceFactory mMockGameServiceProviderInstanceFactory;
82 
83     @Before
setUp()84     public void setUp() throws Exception {
85         mMockingSession = mockitoSession()
86                 .initMocks(this)
87                 .strictness(Strictness.LENIENT)
88                 .startMocking();
89 
90         mGameServiceManager = new GameServiceController(
91                 mMockContext, ConcurrentUtils.DIRECT_EXECUTOR,
92                 mMockGameServiceProviderSelector,
93                 mMockGameServiceProviderInstanceFactory);
94     }
95 
96     @After
tearDown()97     public void tearDown() {
98         mMockingSession.finishMocking();
99     }
100 
101     @Test
notifyUserStarted_hasNotCompletedBoot_doesNothing()102     public void notifyUserStarted_hasNotCompletedBoot_doesNothing() {
103         mGameServiceManager.notifyUserStarted(USER_10);
104 
105         verifyNoMoreInteractions(mMockGameServiceProviderInstanceFactory);
106     }
107 
108     @Test
notifyUserStarted_createsAndStartsNewInstance()109     public void notifyUserStarted_createsAndStartsNewInstance() {
110         GameServiceConfiguration configurationA =
111                 new GameServiceConfiguration(PROVIDER_A_PACKAGE_NAME,
112                         new GameServiceComponentConfiguration(USER_HANDLE_10,
113                                 PROVIDER_A_SERVICE_A,
114                                 PROVIDER_A_SERVICE_B));
115         FakeGameServiceProviderInstance instanceA =
116                 seedConfigurationForUser(USER_10, configurationA);
117 
118         mGameServiceManager.onBootComplete();
119         mGameServiceManager.notifyUserStarted(USER_10);
120 
121         verify(mMockGameServiceProviderInstanceFactory).create(
122                 configurationA.getGameServiceComponentConfiguration());
123         verifyNoMoreInteractions(mMockGameServiceProviderInstanceFactory);
124         assertThat(instanceA.getIsRunning()).isTrue();
125     }
126 
127     @Test
notifyUserStarted_sameUser_doesNotCreateNewInstance()128     public void notifyUserStarted_sameUser_doesNotCreateNewInstance() {
129         GameServiceConfiguration configurationA =
130                 new GameServiceConfiguration(PROVIDER_A_PACKAGE_NAME,
131                         new GameServiceComponentConfiguration(USER_HANDLE_10,
132                                 PROVIDER_A_SERVICE_A,
133                                 PROVIDER_A_SERVICE_B));
134         FakeGameServiceProviderInstance instanceA =
135                 seedConfigurationForUser(USER_10, configurationA);
136 
137         mGameServiceManager.onBootComplete();
138         mGameServiceManager.notifyUserStarted(USER_10);
139         mGameServiceManager.notifyUserStarted(USER_10);
140 
141         verify(mMockGameServiceProviderInstanceFactory).create(
142                 configurationA.getGameServiceComponentConfiguration());
143         verifyNoMoreInteractions(mMockGameServiceProviderInstanceFactory);
144         assertThat(instanceA.getIsRunning()).isTrue();
145     }
146 
147     @Test
notifyUserUnlocking_noForegroundUser_ignores()148     public void notifyUserUnlocking_noForegroundUser_ignores() {
149         GameServiceConfiguration configurationA =
150                 new GameServiceConfiguration(PROVIDER_A_PACKAGE_NAME,
151                         new GameServiceComponentConfiguration(USER_HANDLE_10,
152                                 PROVIDER_A_SERVICE_A,
153                                 PROVIDER_A_SERVICE_B));
154         FakeGameServiceProviderInstance instanceA =
155                 seedConfigurationForUser(USER_10, configurationA);
156 
157         mGameServiceManager.onBootComplete();
158         mGameServiceManager.notifyUserUnlocking(USER_10);
159 
160         verifyNoMoreInteractions(mMockGameServiceProviderInstanceFactory);
161         assertThat(instanceA.getIsRunning()).isFalse();
162     }
163 
164     @Test
notifyUserUnlocking_sameAsForegroundUser_evaluatesProvider()165     public void notifyUserUnlocking_sameAsForegroundUser_evaluatesProvider() {
166         GameServiceConfiguration configurationA =
167                 new GameServiceConfiguration(PROVIDER_A_PACKAGE_NAME,
168                         new GameServiceComponentConfiguration(USER_HANDLE_10,
169                                 PROVIDER_A_SERVICE_A,
170                                 PROVIDER_A_SERVICE_B));
171         seedNoConfigurationForUser(USER_10);
172 
173         mGameServiceManager.onBootComplete();
174         mGameServiceManager.notifyUserStarted(USER_10);
175         FakeGameServiceProviderInstance instanceA =
176                 seedConfigurationForUser(USER_10, configurationA);
177         mGameServiceManager.notifyUserUnlocking(USER_10);
178 
179         verify(mMockGameServiceProviderInstanceFactory).create(
180                 configurationA.getGameServiceComponentConfiguration());
181         verifyNoMoreInteractions(mMockGameServiceProviderInstanceFactory);
182         assertThat(instanceA.getIsRunning()).isTrue();
183     }
184 
185     @Test
notifyUserUnlocking_differentFromForegroundUser_ignores()186     public void notifyUserUnlocking_differentFromForegroundUser_ignores() {
187         GameServiceConfiguration configurationA =
188                 new GameServiceConfiguration(PROVIDER_A_PACKAGE_NAME,
189                         new GameServiceComponentConfiguration(USER_HANDLE_10,
190                                 PROVIDER_A_SERVICE_A,
191                                 PROVIDER_A_SERVICE_B));
192         seedNoConfigurationForUser(USER_10);
193 
194         mGameServiceManager.onBootComplete();
195         mGameServiceManager.notifyUserStarted(USER_10);
196         FakeGameServiceProviderInstance instanceA =
197                 seedConfigurationForUser(USER_11, configurationA);
198         mGameServiceManager.notifyUserUnlocking(USER_11);
199 
200         verifyNoMoreInteractions(mMockGameServiceProviderInstanceFactory);
201         assertThat(instanceA.getIsRunning()).isFalse();
202     }
203 
204     @Test
205     public void
notifyNewForegroundUser_differentUser_stopsPreviousInstanceAndThenStartsNewInstance()206             notifyNewForegroundUser_differentUser_stopsPreviousInstanceAndThenStartsNewInstance() {
207         GameServiceConfiguration configurationA =
208                 new GameServiceConfiguration(PROVIDER_A_PACKAGE_NAME,
209                         new GameServiceComponentConfiguration(USER_HANDLE_10,
210                                 PROVIDER_A_SERVICE_A,
211                                 PROVIDER_A_SERVICE_B));
212         FakeGameServiceProviderInstance instanceA =
213                 seedConfigurationForUser(USER_10, configurationA);
214         GameServiceConfiguration configurationB =
215                 new GameServiceConfiguration(PROVIDER_A_PACKAGE_NAME,
216                         new GameServiceComponentConfiguration(USER_HANDLE_11,
217                                 PROVIDER_A_SERVICE_A,
218                                 PROVIDER_A_SERVICE_B));
219         FakeGameServiceProviderInstance instanceB = seedConfigurationForUser(USER_11,
220                 configurationB);
221         InOrder instancesInOrder = Mockito.inOrder(instanceA, instanceB);
222 
223         mGameServiceManager.onBootComplete();
224         mGameServiceManager.notifyUserStarted(USER_10);
225         mGameServiceManager.notifyNewForegroundUser(USER_11);
226 
227         verify(mMockGameServiceProviderInstanceFactory).create(
228                 configurationA.getGameServiceComponentConfiguration());
229         verify(mMockGameServiceProviderInstanceFactory).create(
230                 configurationB.getGameServiceComponentConfiguration());
231         instancesInOrder.verify(instanceA).start();
232         instancesInOrder.verify(instanceA).stop();
233         instancesInOrder.verify(instanceB).start();
234         verifyNoMoreInteractions(mMockGameServiceProviderInstanceFactory);
235         assertThat(instanceA.getIsRunning()).isFalse();
236         assertThat(instanceB.getIsRunning()).isTrue();
237     }
238 
239     @Test
packageChanges_reevaluatesGameServiceProvider()240     public void packageChanges_reevaluatesGameServiceProvider() {
241         GameServiceConfiguration configurationA =
242                 new GameServiceConfiguration(PROVIDER_A_PACKAGE_NAME,
243                         new GameServiceComponentConfiguration(USER_HANDLE_10,
244                                 PROVIDER_A_SERVICE_A,
245                                 PROVIDER_A_SERVICE_B));
246         FakeGameServiceProviderInstance instanceA =
247                 seedConfigurationForUser(USER_10, configurationA);
248 
249         mGameServiceManager.onBootComplete();
250         mGameServiceManager.notifyUserStarted(USER_10);
251         ArgumentCaptor<BroadcastReceiver> broadcastReceiverArgumentCaptor =
252                 ArgumentCaptor.forClass(BroadcastReceiver.class);
253         verify(mMockContext).registerReceiver(broadcastReceiverArgumentCaptor.capture(), any());
254 
255         GameServiceConfiguration configurationB =
256                 new GameServiceConfiguration(PROVIDER_A_PACKAGE_NAME,
257                         new GameServiceComponentConfiguration(USER_HANDLE_10,
258                                 PROVIDER_A_SERVICE_A,
259                                 PROVIDER_A_SERVICE_C));
260         FakeGameServiceProviderInstance instanceB =
261                 seedConfigurationForUser(USER_10, configurationB);
262         Intent intent = new Intent();
263         intent.setData(Uri.parse("package:" + PROVIDER_A_PACKAGE_NAME));
264         broadcastReceiverArgumentCaptor.getValue().onReceive(mMockContext, intent);
265 
266         InOrder instancesInOrder = Mockito.inOrder(instanceA, instanceB);
267         verify(mMockGameServiceProviderInstanceFactory).create(
268                 configurationA.getGameServiceComponentConfiguration());
269         verify(mMockGameServiceProviderInstanceFactory).create(
270                 configurationB.getGameServiceComponentConfiguration());
271         instancesInOrder.verify(instanceA).start();
272         instancesInOrder.verify(instanceA).stop();
273         instancesInOrder.verify(instanceB).start();
274         verifyNoMoreInteractions(mMockGameServiceProviderInstanceFactory);
275         assertThat(instanceA.getIsRunning()).isFalse();
276         assertThat(instanceB.getIsRunning()).isTrue();
277     }
278 
seedNoConfigurationForUser(SystemService.TargetUser user)279     private void seedNoConfigurationForUser(SystemService.TargetUser user) {
280         when(mMockGameServiceProviderSelector.get(user, null)).thenReturn(null);
281     }
282 
seedConfigurationForUser(SystemService.TargetUser user, GameServiceConfiguration configuration)283     private FakeGameServiceProviderInstance seedConfigurationForUser(SystemService.TargetUser user,
284             GameServiceConfiguration configuration) {
285         when(mMockGameServiceProviderSelector.get(user, null)).thenReturn(configuration);
286         FakeGameServiceProviderInstance instanceForConfiguration =
287                 spy(new FakeGameServiceProviderInstance());
288         when(mMockGameServiceProviderInstanceFactory.create(
289                 configuration.getGameServiceComponentConfiguration()))
290                 .thenReturn(instanceForConfiguration);
291 
292         return instanceForConfiguration;
293     }
294 
user(int userId)295     private static SystemService.TargetUser user(int userId) {
296         UserInfo userInfo = new UserInfo(userId, "", "", UserInfo.FLAG_FULL);
297         return new SystemService.TargetUser(userInfo);
298     }
299 }
300