• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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.garagemode;
18 
19 import static com.android.car.garagemode.GarageMode.ACTION_GARAGE_MODE_OFF;
20 import static com.android.car.garagemode.GarageMode.ACTION_GARAGE_MODE_ON;
21 import static com.android.car.power.CarPowerManagementService.INVALID_TIMEOUT;
22 
23 import static com.google.common.truth.Truth.assertThat;
24 import static com.google.common.truth.Truth.assertWithMessage;
25 
26 import static org.mockito.ArgumentMatchers.any;
27 import static org.mockito.ArgumentMatchers.eq;
28 import static org.mockito.Mockito.clearInvocations;
29 import static org.mockito.Mockito.doNothing;
30 import static org.mockito.Mockito.doReturn;
31 import static org.mockito.Mockito.mock;
32 import static org.mockito.Mockito.never;
33 import static org.mockito.Mockito.timeout;
34 import static org.mockito.Mockito.times;
35 import static org.mockito.Mockito.verify;
36 import static org.mockito.Mockito.when;
37 
38 import android.car.hardware.power.CarPowerManager;
39 import android.content.Context;
40 import android.content.Intent;
41 import android.content.res.Resources;
42 import android.os.Handler;
43 import android.os.HandlerThread;
44 import android.os.Looper;
45 import android.os.UserHandle;
46 import android.util.Log;
47 
48 import androidx.test.ext.junit.runners.AndroidJUnit4;
49 import androidx.test.filters.SmallTest;
50 
51 import com.android.car.CarLocalServices;
52 import com.android.car.power.CarPowerManagementService;
53 import com.android.car.systeminterface.SystemInterface;
54 import com.android.car.user.CarUserService;
55 
56 import org.junit.After;
57 import org.junit.Before;
58 import org.junit.Rule;
59 import org.junit.Test;
60 import org.junit.runner.RunWith;
61 import org.mockito.ArgumentCaptor;
62 import org.mockito.Captor;
63 import org.mockito.Mock;
64 import org.mockito.junit.MockitoJUnit;
65 import org.mockito.junit.MockitoRule;
66 
67 import java.io.File;
68 import java.io.IOException;
69 import java.nio.file.Files;
70 import java.util.ArrayList;
71 import java.util.List;
72 import java.util.concurrent.Executor;
73 
74 @RunWith(AndroidJUnit4.class)
75 @SmallTest
76 public class GarageModeControllerTest {
77 
78     private static final String TAG = "GarageModeControllerTest";
79     private static final int DEFAULT_TIMEOUT_MS = 1000;
80 
81     @Rule public final MockitoRule rule = MockitoJUnit.rule();
82 
83     @Mock private Context mContextMock;
84     @Mock private CarUserService mCarUserServiceMock;
85     @Mock private SystemInterface mSystemInterfaceMock;
86     @Mock private CarPowerManagementService mCarPowerManagementServiceMock;
87     private CarUserService mCarUserServiceOriginal;
88     private CarPowerManagementService mCarPowerManagementServiceOriginal;
89     @Captor private ArgumentCaptor<Intent> mIntentCaptor;
90 
91     private GarageModeController mController;
92     private File mTempTestDir;
93     private HandlerThread mHandlerThread;
94     private Handler mHandler;
95     private Looper mLooper;
96 
97     @Before
setUp()98     public void setUp() throws IOException {
99         mHandlerThread = new HandlerThread("ControllerTest");
100         mHandlerThread.start();
101         mLooper = mHandlerThread.getLooper();
102         mHandler = new Handler(mLooper);
103         mCarUserServiceOriginal = CarLocalServices.getService(CarUserService.class);
104         mCarPowerManagementServiceOriginal = CarLocalServices.getService(
105                 CarPowerManagementService.class);
106         CarLocalServices.removeServiceForTest(CarUserService.class);
107         CarLocalServices.addService(CarUserService.class, mCarUserServiceMock);
108         CarLocalServices.removeServiceForTest(SystemInterface.class);
109         CarLocalServices.addService(SystemInterface.class, mSystemInterfaceMock);
110         CarLocalServices.removeServiceForTest(CarPowerManagementService.class);
111         CarLocalServices.addService(CarPowerManagementService.class,
112                 mCarPowerManagementServiceMock);
113 
114         mTempTestDir = Files.createTempDirectory("garagemode_test").toFile();
115         when(mSystemInterfaceMock.getSystemCarDir()).thenReturn(mTempTestDir);
116         Log.v(TAG, "Using temp dir: %s " + mTempTestDir.getAbsolutePath());
117 
118         mController = new GarageModeController(mContextMock, mLooper, mHandler,
119                 /* garageMode= */ null);
120 
121         doReturn(new ArrayList<Integer>()).when(mCarUserServiceMock)
122                 .startAllBackgroundUsersInGarageMode();
123         doNothing().when(mSystemInterfaceMock)
124                 .sendBroadcastAsUser(any(Intent.class), any(UserHandle.class));
125         mController.init();
126     }
127 
128     @After
tearDown()129     public void tearDown() throws Exception {
130         mHandlerThread.quitSafely();
131         mHandlerThread.join();
132 
133         CarLocalServices.removeServiceForTest(CarUserService.class);
134         CarLocalServices.addService(CarUserService.class, mCarUserServiceOriginal);
135         CarLocalServices.removeServiceForTest(SystemInterface.class);
136         CarLocalServices.removeServiceForTest(CarPowerManagementService.class);
137         CarLocalServices.addService(CarPowerManagementService.class,
138                 mCarPowerManagementServiceOriginal);
139     }
140 
141     @Test
testOnShutdownPrepare_shouldInitiateGarageMode()142     public void testOnShutdownPrepare_shouldInitiateGarageMode() {
143         // Sending notification that state has changed
144         mController.onStateChanged(CarPowerManager.STATE_SHUTDOWN_PREPARE, INVALID_TIMEOUT);
145 
146         // Assert that GarageMode has been started
147         verify(mSystemInterfaceMock, timeout(DEFAULT_TIMEOUT_MS))
148                 .sendBroadcastAsUser(mIntentCaptor.capture(), eq(UserHandle.ALL));
149         assertThat(mController.isGarageModeActive()).isTrue();
150         verifyGarageModeBroadcast(mIntentCaptor.getAllValues(), 1, ACTION_GARAGE_MODE_ON);
151     }
152 
153     @Test
testOnShutdownCancelled_shouldCancelGarageMode()154     public void testOnShutdownCancelled_shouldCancelGarageMode() {
155         Looper looper = Looper.getMainLooper();
156         mController = new GarageModeController(mContextMock, looper);
157         mController.init();
158         // Sending notification that state has changed
159         mController.onStateChanged(CarPowerManager.STATE_SHUTDOWN_PREPARE, INVALID_TIMEOUT);
160 
161         // Sending shutdown cancelled signal to controller, GarageMode should wrap up and stop
162         mController.onStateChanged(CarPowerManager.STATE_SHUTDOWN_CANCELLED, INVALID_TIMEOUT);
163 
164         // Verify that OFF signal broadcasted to JobScheduler
165         verify(mSystemInterfaceMock, timeout(DEFAULT_TIMEOUT_MS).times(2))
166                 .sendBroadcastAsUser(mIntentCaptor.capture(), eq(UserHandle.ALL));
167         verifyGarageModeBroadcast(mIntentCaptor.getAllValues(), 1, ACTION_GARAGE_MODE_ON);
168         verifyGarageModeBroadcast(mIntentCaptor.getAllValues(), 2, ACTION_GARAGE_MODE_OFF);
169 
170         // Verify that listener is completed due to the cancellation.
171         verify(mCarPowerManagementServiceMock, timeout(DEFAULT_TIMEOUT_MS))
172                 .completeHandlingPowerStateChange(
173                         eq(CarPowerManager.STATE_SHUTDOWN_PREPARE), eq(mController));
174     }
175 
176     @Test
testInitAndRelease()177     public void testInitAndRelease() {
178         Executor mockExecutor = mock(Executor.class);
179         when(mContextMock.getMainExecutor()).thenReturn(mockExecutor);
180         GarageMode garageMode = mock(GarageMode.class);
181         var controller = new GarageModeController(mContextMock, mLooper, mHandler, garageMode);
182 
183         controller.init();
184         controller.release();
185 
186         verify(garageMode).init();
187         verify(garageMode).release();
188     }
189 
190     @Test
testConstructor()191     public void testConstructor() {
192         Resources resourcesMock = mock(Resources.class);
193         when(mContextMock.getResources()).thenReturn(resourcesMock);
194 
195         var controller = new GarageModeController(mContextMock, mLooper);
196 
197         assertThat(controller).isNotNull();
198     }
199 
200     @Test
testOnStateChanged()201     public void testOnStateChanged() {
202         GarageMode garageMode = mock(GarageMode.class);
203         var controller = new GarageModeController(mContextMock, mLooper, mHandler, garageMode);
204         controller.init();
205 
206         controller.onStateChanged(CarPowerManager.STATE_SHUTDOWN_CANCELLED, INVALID_TIMEOUT);
207         verify(garageMode, timeout(DEFAULT_TIMEOUT_MS)).cancel(any());
208 
209         clearInvocations(garageMode);
210         controller.onStateChanged(CarPowerManager.STATE_SHUTDOWN_ENTER, INVALID_TIMEOUT);
211         verify(garageMode, timeout(DEFAULT_TIMEOUT_MS)).cancel(any());
212 
213         clearInvocations(garageMode);
214         controller.onStateChanged(CarPowerManager.STATE_SUSPEND_ENTER, INVALID_TIMEOUT);
215         verify(garageMode, timeout(DEFAULT_TIMEOUT_MS)).cancel(any());
216 
217         clearInvocations(garageMode);
218         controller.onStateChanged(CarPowerManager.STATE_HIBERNATION_ENTER, INVALID_TIMEOUT);
219         verify(garageMode, timeout(DEFAULT_TIMEOUT_MS)).cancel(any());
220 
221         clearInvocations(garageMode);
222         controller.onStateChanged(CarPowerManager.STATE_INVALID , INVALID_TIMEOUT);
223         verify(garageMode, never()).cancel(any());
224     }
225 
verifyGarageModeBroadcast(List<Intent> intents, int times, String action)226     private void verifyGarageModeBroadcast(List<Intent> intents, int times, String action) {
227         // Capture sent intent and verify that it is correct
228         assertWithMessage("no of intents").that(intents.size()).isAtLeast(times);
229         Intent i = intents.get(times - 1);
230         assertWithMessage("intent action on %s", i).that(i.getAction())
231                 .isEqualTo(action);
232 
233         // Verify that additional critical flags are bundled as well
234         int flags = Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_NO_ABORT;
235         boolean areRequiredFlagsSet = ((flags & i.getFlags()) == flags);
236         assertThat(areRequiredFlagsSet).isTrue();
237     }
238 }
239