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