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