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