• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 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.car.pm;
18 
19 import static com.google.common.truth.Truth.assertThat;
20 
21 import static org.mockito.ArgumentMatchers.any;
22 import static org.mockito.ArgumentMatchers.anyInt;
23 import static org.mockito.Mockito.when;
24 
25 import android.app.ActivityManager;
26 import android.car.userlib.CarUserManagerHelper;
27 import android.content.ComponentName;
28 import android.content.Context;
29 import android.content.ContextWrapper;
30 import android.content.Intent;
31 import android.content.ServiceConnection;
32 import android.content.res.Resources;
33 import android.os.Handler;
34 import android.os.Looper;
35 import android.os.UserHandle;
36 import android.os.UserManager;
37 
38 import androidx.test.core.app.ApplicationProvider;
39 import androidx.test.runner.AndroidJUnit4;
40 
41 import com.android.car.CarLocalServices;
42 import com.android.car.user.CarUserService;
43 
44 import org.junit.After;
45 import org.junit.Before;
46 import org.junit.Rule;
47 import org.junit.Test;
48 import org.junit.runner.RunWith;
49 import org.mockito.Mock;
50 import org.mockito.Mockito;
51 import org.mockito.junit.MockitoJUnit;
52 import org.mockito.junit.MockitoRule;
53 
54 import java.util.ArrayList;
55 import java.util.List;
56 
57 @RunWith(AndroidJUnit4.class)
58 public class VendorServiceControllerTest {
59     private VendorServiceController mController;
60     private static final Long DEFAULT_TIMEOUT_MS = 1000L;
61 
62     private static final int FG_USER_ID = 13;
63 
64     private static final String SERVICE_BIND_ALL_USERS_ASAP = "com.andorid.car/.AllUsersService";
65     private static final String SERVICE_BIND_FG_USER_UNLOCKED = "com.andorid.car/.ForegroundUsers";
66     private static final String SERVICE_START_SYSTEM_UNLOCKED = "com.andorid.car/.SystemUser";
67 
68     private static final String[] FAKE_SERVICES = new String[] {
69             SERVICE_BIND_ALL_USERS_ASAP + "#bind=bind,user=all,trigger=asap",
70             SERVICE_BIND_FG_USER_UNLOCKED + "#bind=bind,user=foreground,trigger=userUnlocked",
71             SERVICE_START_SYSTEM_UNLOCKED + "#bind=start,user=system,trigger=userUnlocked"
72     };
73 
74     @Rule
75     public MockitoRule rule = MockitoJUnit.rule();
76 
77     @Mock
78     private Resources mResources;
79 
80     @Mock
81     private UserManager mUserManager;
82 
83     private ServiceLauncherContext mContext;
84 
85     private CarUserManagerHelper mUserManagerHelper;
86     private CarUserService mCarUserService;
87 
88     @Before
setUp()89     public void setUp() {
90         mContext = new ServiceLauncherContext(ApplicationProvider.getApplicationContext());
91         mUserManagerHelper = Mockito.spy(new CarUserManagerHelper(mContext));
92         mCarUserService = new CarUserService(mContext, mUserManagerHelper,
93                 ActivityManager.getService(), 2 /* max running users */);
94         CarLocalServices.addService(CarUserService.class, mCarUserService);
95 
96         mController = new VendorServiceController(mContext,
97                 Looper.getMainLooper(), mUserManagerHelper);
98 
99         when(mUserManagerHelper.isPersistentUser(anyInt())).thenReturn(true);
100         // Let's pretend system is not fully loaded, current user is system.
101         when(mUserManagerHelper.getCurrentForegroundUserId()).thenReturn(UserHandle.USER_SYSTEM);
102         // ..and by default all users are locked
103         mockUserUnlock(UserHandle.USER_ALL, false /* unlock */);
104         when(mResources.getStringArray(com.android.car.R.array.config_earlyStartupServices))
105                 .thenReturn(FAKE_SERVICES);
106     }
107 
108     @After
tearDown()109     public void tearDown() {
110         CarLocalServices.removeServiceForTest(CarUserService.class);
111     }
112 
113     @Test
init_nothingConfigured()114     public void init_nothingConfigured() {
115         when(mResources.getStringArray(com.android.car.R.array.config_earlyStartupServices))
116                 .thenReturn(new String[0]);
117 
118         mController.init();
119 
120         mContext.verifyNoMoreServiceLaunches();
121     }
122 
123     @Test
init_systemUser()124     public void init_systemUser() throws InterruptedException {
125         mController.init();
126 
127         Thread.sleep(100);
128 
129         mContext.assertBoundService(SERVICE_BIND_ALL_USERS_ASAP);
130         mContext.verifyNoMoreServiceLaunches();
131     }
132 
133     @Test
systemUserUnlocked()134     public void systemUserUnlocked() {
135         mController.init();
136         mContext.reset();
137 
138         // Unlock system user
139         mockUserUnlock(UserHandle.USER_SYSTEM, true);
140         runOnMainThread(() -> mCarUserService.setUserLockStatus(UserHandle.USER_SYSTEM, true));
141 
142         mContext.assertStartedService(SERVICE_START_SYSTEM_UNLOCKED);
143         mContext.verifyNoMoreServiceLaunches();
144     }
145 
146     @Test
fgUserUnlocked()147     public void fgUserUnlocked() {
148         mController.init();
149         mContext.reset();
150 
151         // Switch user to foreground
152         when(mUserManagerHelper.getCurrentForegroundUserId()).thenReturn(FG_USER_ID);
153         runOnMainThread(() -> mCarUserService.onSwitchUser(FG_USER_ID));
154 
155         // Expect only services with ASAP trigger to be started
156         mContext.assertBoundService(SERVICE_BIND_ALL_USERS_ASAP);
157         mContext.verifyNoMoreServiceLaunches();
158 
159         // Unlock foreground user
160         mockUserUnlock(FG_USER_ID, true);
161         runOnMainThread(() -> mCarUserService.setUserLockStatus(FG_USER_ID, true));
162 
163         mContext.assertBoundService(SERVICE_BIND_FG_USER_UNLOCKED);
164         mContext.verifyNoMoreServiceLaunches();
165     }
166 
runOnMainThread(Runnable r)167     private void runOnMainThread(Runnable r) {
168         Handler.getMain().runWithScissors(r, DEFAULT_TIMEOUT_MS);
169     }
170 
mockUserUnlock(int userId, boolean unlock)171     private void mockUserUnlock(int userId, boolean unlock) {
172         if (UserHandle.USER_ALL == userId) {
173             when(mUserManager.isUserUnlockingOrUnlocked(any())).thenReturn(unlock);
174             when(mUserManager.isUserUnlockingOrUnlocked(anyInt())).thenReturn(unlock);
175         } else {
176             when(mUserManager.isUserUnlockingOrUnlocked(userId)).thenReturn(unlock);
177             when(mUserManager.isUserUnlockingOrUnlocked(UserHandle.of(userId))).thenReturn(unlock);
178         }
179     }
180 
181     /** Overrides framework behavior to succeed on binding/starting processes. */
182     public class ServiceLauncherContext extends ContextWrapper {
183         private List<Intent> mBoundIntents = new ArrayList<>();
184         private List<Intent> mStartedServicesIntents = new ArrayList<>();
185 
ServiceLauncherContext(Context base)186         ServiceLauncherContext(Context base) {
187             super(base);
188         }
189 
190         @Override
startServiceAsUser(Intent service, UserHandle user)191         public ComponentName startServiceAsUser(Intent service, UserHandle user) {
192             mStartedServicesIntents.add(service);
193             return service.getComponent();
194         }
195 
196         @Override
bindServiceAsUser(Intent service, ServiceConnection conn, int flags, Handler handler, UserHandle user)197         public boolean bindServiceAsUser(Intent service, ServiceConnection conn, int flags,
198                 Handler handler, UserHandle user) {
199             mBoundIntents.add(service);
200             conn.onServiceConnected(service.getComponent(), null);
201             return true;
202         }
203 
204         @Override
bindServiceAsUser(Intent service, ServiceConnection conn, int flags, UserHandle user)205         public boolean bindServiceAsUser(Intent service, ServiceConnection conn,
206                 int flags, UserHandle user) {
207             return bindServiceAsUser(service, conn, flags, null, user);
208         }
209 
210         @Override
getResources()211         public Resources getResources() {
212             return mResources;
213         }
214 
assertBoundService(String service)215         void assertBoundService(String service) {
216             assertThat(mBoundIntents).hasSize(1);
217             assertThat(mBoundIntents.get(0).getComponent())
218                     .isEqualTo(ComponentName.unflattenFromString(service));
219             mBoundIntents.clear();
220         }
221 
assertStartedService(String service)222         void assertStartedService(String service) {
223             assertThat(mStartedServicesIntents).hasSize(1);
224             assertThat(mStartedServicesIntents.get(0).getComponent())
225                     .isEqualTo(ComponentName.unflattenFromString(service));
226             mStartedServicesIntents.clear();
227         }
228 
verifyNoMoreServiceLaunches()229         void verifyNoMoreServiceLaunches() {
230             assertThat(mStartedServicesIntents).isEmpty();
231             assertThat(mBoundIntents).isEmpty();
232         }
233 
reset()234         void reset() {
235             mStartedServicesIntents.clear();
236             mBoundIntents.clear();
237 
238         }
239 
240         @Override
getSystemService(String name)241         public Object getSystemService(String name) {
242             if (Context.USER_SERVICE.equals(name)) {
243                 return mUserManager;
244             } else {
245                 return super.getSystemService(name);
246             }
247         }
248     }
249 }
250