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; 18 19 import static org.junit.Assert.fail; 20 import static org.mockito.ArgumentMatchers.any; 21 import static org.mockito.ArgumentMatchers.anyInt; 22 import static org.mockito.ArgumentMatchers.anyString; 23 import static org.mockito.ArgumentMatchers.eq; 24 import static org.mockito.Mockito.doReturn; 25 import static org.mockito.Mockito.doThrow; 26 import static org.mockito.Mockito.spy; 27 import static org.mockito.Mockito.when; 28 29 import android.automotive.powerpolicy.internal.ICarPowerPolicyDelegate; 30 import android.car.Car; 31 import android.car.ICarResultReceiver; 32 import android.car.feature.Flags; 33 import android.content.Context; 34 import android.content.res.Resources; 35 import android.frameworks.automotive.powerpolicy.internal.ICarPowerPolicySystemNotification; 36 import android.os.Bundle; 37 import android.os.HandlerThread; 38 import android.os.IInterface; 39 import android.os.Looper; 40 import android.os.Process; 41 import android.os.UserHandle; 42 import android.os.UserManager; 43 import android.util.Log; 44 45 import androidx.test.platform.app.InstrumentationRegistry; 46 47 import com.android.car.garagemode.GarageModeService; 48 import com.android.car.hal.HalPropValueBuilder; 49 import com.android.car.hal.PowerHalService; 50 import com.android.car.internal.ICarServiceHelper; 51 import com.android.car.internal.StaticBinderInterface; 52 import com.android.car.os.CarPerformanceService; 53 import com.android.car.remoteaccess.CarRemoteAccessService; 54 import com.android.car.systeminterface.ActivityManagerInterface; 55 import com.android.car.systeminterface.DisplayInterface; 56 import com.android.car.systeminterface.IOInterface; 57 import com.android.car.systeminterface.StorageMonitoringInterface; 58 import com.android.car.systeminterface.SystemInterface; 59 import com.android.car.systeminterface.SystemStateInterface; 60 import com.android.car.systeminterface.TimeInterface; 61 import com.android.car.systeminterface.WakeLockInterface; 62 import com.android.car.telemetry.CarTelemetryService; 63 import com.android.car.test.utils.TemporaryDirectory; 64 import com.android.car.watchdog.CarWatchdogService; 65 66 import org.junit.After; 67 import org.junit.Before; 68 import org.junit.Test; 69 import org.junit.runner.RunWith; 70 import org.mockito.Mock; 71 import org.mockito.junit.MockitoJUnitRunner; 72 73 import java.io.File; 74 import java.io.IOException; 75 76 /** 77 * This class contains unit tests for the {@link ICarImpl}. 78 * 79 * <p>It tests that services started with {@link ICarImpl} are initialized properly. 80 * <p>The following mocks are used: 81 * <ol> 82 * <li>{@link ActivityManagerInterface} broadcasts intent for a user.</li> 83 * <li>{@link DisplayInterface} provides access to display operations.</li> 84 * <li>{@link IVehicle} provides access to vehicle properties.</li> 85 * <li>{@link StorageMonitoringInterface} provides access to storage monitoring operations.</li> 86 * <li>{@link SystemStateInterface} provides system statuses (booting, sleeping, ...).</li> 87 * <li>{@link TimeInterface} provides access to time operations.</li> 88 * <li>{@link TimeInterface} provides access to wake lock operations.</li> 89 * </ol> 90 */ 91 @RunWith(MockitoJUnitRunner.class) 92 public final class ICarImplTest { 93 private static final String TAG = ICarImplTest.class.getSimpleName(); 94 95 @Mock private ActivityManagerInterface mMockActivityManagerInterface; 96 @Mock private DisplayInterface mMockDisplayInterface; 97 @Mock private VehicleStub mMockVehicle; 98 @Mock private StorageMonitoringInterface mMockStorageMonitoringInterface; 99 @Mock private SystemStateInterface mMockSystemStateInterface; 100 @Mock private TimeInterface mMockTimeInterface; 101 @Mock private WakeLockInterface mMockWakeLockInterface; 102 @Mock private CarWatchdogService mMockCarWatchdogService; 103 @Mock private CarPerformanceService mMockCarPerformanceService; 104 @Mock private GarageModeService mMockGarageModeService; 105 @Mock private ICarPowerPolicySystemNotification.Stub mMockCarPowerPolicyDaemon; 106 @Mock private ICarPowerPolicyDelegate.Stub mMockRefactoredCarPowerPolicyDaemon; 107 @Mock private CarTelemetryService mMockCarTelemetryService; 108 @Mock private CarRemoteAccessService mMockCarRemoteAccessService; 109 @Mock private ICarServiceHelper mICarServiceHelper; 110 111 private Context mContext; 112 private SystemInterface mFakeSystemInterface; 113 private UserManager mUserManager; 114 115 private final MockIOInterface mMockIOInterface = new MockIOInterface(); 116 117 static final class CarServiceConnectedCallback extends ICarResultReceiver.Stub { 118 @Override send(int resultCode, Bundle resultData)119 public void send(int resultCode, Bundle resultData) { 120 Log.i(TAG, "CarServiceConnectedCallback.send(int resultCode, Bundle resultData)"); 121 } 122 } 123 124 /** 125 * Initialize all of the objects with the @Mock annotation. 126 */ 127 @Before setUp()128 public void setUp() throws Exception { 129 // InstrumentationTestRunner prepares a looper, but AndroidJUnitRunner does not. 130 // http://b/25897652. 131 if (Looper.myLooper() == null) { 132 Looper.prepare(); 133 } 134 135 mContext = spy(InstrumentationRegistry.getInstrumentation().getTargetContext()); 136 137 mUserManager = spy(mContext.getSystemService(UserManager.class)); 138 doReturn(mUserManager).when(mContext).getSystemService(eq(UserManager.class)); 139 doReturn(mUserManager).when(mContext).getSystemService(eq(Context.USER_SERVICE)); 140 141 Resources resources = spy(mContext.getResources()); 142 doReturn("").when(resources).getString( 143 eq(com.android.car.R.string.instrumentClusterRendererService)); 144 doReturn(false).when(resources).getBoolean( 145 eq(com.android.car.R.bool.audioUseDynamicRouting)); 146 doReturn(new String[0]).when(resources).getStringArray( 147 eq(com.android.car.R.array.config_earlyStartupServices)); 148 doReturn(resources).when(mContext).getResources(); 149 150 mFakeSystemInterface = SystemInterface.Builder.newSystemInterface() 151 .withSystemStateInterface(mMockSystemStateInterface) 152 .withActivityManagerInterface(mMockActivityManagerInterface) 153 .withDisplayInterface(mMockDisplayInterface) 154 .withIOInterface(mMockIOInterface) 155 .withStorageMonitoringInterface(mMockStorageMonitoringInterface) 156 .withTimeInterface(mMockTimeInterface) 157 .withWakeLockInterface(mMockWakeLockInterface).build(); 158 // ICarImpl will register new CarLocalServices services. 159 // This prevents one test failure in tearDown from triggering assertion failure for single 160 // CarLocalServices service. 161 CarLocalServices.removeAllServices(); 162 } 163 164 /** 165 * Clean up before running the next test. 166 */ 167 @After tearDown()168 public void tearDown() { 169 try { 170 if (mMockIOInterface != null) { 171 mMockIOInterface.tearDown(); 172 } 173 } finally { 174 CarLocalServices.removeAllServices(); 175 } 176 } 177 178 @Test testNoShardedPreferencesAccessedBeforeUserZeroUnlock()179 public void testNoShardedPreferencesAccessedBeforeUserZeroUnlock() throws Exception { 180 doReturn(true).when(mContext).isCredentialProtectedStorage(); 181 doReturn(false).when(mUserManager).isUserUnlockingOrUnlocked(anyInt()); 182 doReturn(false).when(mUserManager).isUserUnlocked(); 183 doReturn(false).when(mUserManager).isUserUnlocked(anyInt()); 184 doReturn(false).when(mUserManager).isUserUnlocked(any(UserHandle.class)); 185 doReturn(false).when(mUserManager).isUserUnlockingOrUnlocked(any(UserHandle.class)); 186 187 doThrow(new NullPointerException()).when(mContext).getSharedPrefsFile(anyString()); 188 doThrow(new NullPointerException()).when(mContext).getSharedPreferencesPath(any()); 189 doThrow(new NullPointerException()).when(mContext).getSharedPreferences( 190 anyString(), anyInt()); 191 doThrow(new NullPointerException()).when(mContext).getSharedPreferences( 192 any(File.class), anyInt()); 193 doThrow(new NullPointerException()).when(mContext).getDataDir(); 194 IInterface powerPolicyDaemon; 195 if (Flags.carPowerPolicyRefactoring()) { 196 powerPolicyDaemon = mMockRefactoredCarPowerPolicyDaemon; 197 } else { 198 powerPolicyDaemon = mMockCarPowerPolicyDaemon; 199 } 200 when(mMockVehicle.getHalPropValueBuilder()).thenReturn( 201 new HalPropValueBuilder(/*isAidl=*/true)); 202 ICarImpl carImpl = new ICarImpl.Builder() 203 .setServiceContext(mContext) 204 .setVehicle(mMockVehicle) 205 .setVehicleInterfaceName("MockedCar") 206 .setSystemInterface(mFakeSystemInterface) 207 .setCarWatchdogService(mMockCarWatchdogService) 208 .setCarPerformanceService(mMockCarPerformanceService) 209 .setCarTelemetryService(mMockCarTelemetryService) 210 .setCarRemoteAccessServiceConstructor(( 211 Context context, SystemInterface systemInterface, 212 PowerHalService powerHalService 213 ) -> mMockCarRemoteAccessService) 214 .setGarageModeService(mMockGarageModeService) 215 .setPowerPolicyDaemon(powerPolicyDaemon) 216 .setDoPriorityInitInConstruction(false) 217 .setTestStaticBinder(new StaticBinderInterface() { 218 @Override 219 public int getCallingUid() { 220 return Process.SYSTEM_UID; 221 } 222 223 @Override 224 public int getCallingPid() { 225 return 0; 226 } 227 }) 228 .build(); 229 230 carImpl.setSystemServerConnections(mICarServiceHelper, new CarServiceConnectedCallback()); 231 carImpl.init(); 232 Car mCar = new Car(mContext, carImpl, /* handler= */ null); 233 234 // Post tasks for Handler Threads to ensure all the tasks that will be queued inside init 235 // will be done. 236 for (Thread t : Thread.getAllStackTraces().keySet()) { 237 if (!HandlerThread.class.isInstance(t)) { 238 continue; 239 } 240 HandlerThread ht = (HandlerThread) t; 241 CarServiceUtils.runOnLooperSync(ht.getLooper(), () -> { 242 // Do nothing, just need to make sure looper finishes current task. 243 }); 244 } 245 246 mCar.disconnect(); 247 carImpl.release(); 248 } 249 250 static final class MockIOInterface implements IOInterface { 251 private TemporaryDirectory mFilesDir = null; 252 253 @Override getSystemCarDir()254 public File getSystemCarDir() { 255 if (mFilesDir == null) { 256 try { 257 mFilesDir = new TemporaryDirectory(TAG); 258 } catch (IOException e) { 259 Log.e(TAG, "failed to create temporary directory", e); 260 fail("failed to create temporary directory. exception was: " + e); 261 } 262 } 263 return mFilesDir.getDirectory(); 264 } 265 tearDown()266 public void tearDown() { 267 if (mFilesDir != null) { 268 try { 269 mFilesDir.close(); 270 } catch (Exception e) { 271 Log.w(TAG, "could not remove temporary directory", e); 272 } 273 } 274 } 275 } 276 } 277