blob: 0b744d87860c89b1d2dec2412f7851fa8eadf9cb [file] [log] [blame]
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.car.cts;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
import static org.hamcrest.CoreMatchers.containsStringIgnoringCase;
import static org.junit.Assume.assumeThat;
import static org.testng.Assert.fail;
import android.app.UiAutomation;
import android.car.Car;
import android.car.user.CarUserManager;
import android.car.user.CarUserManager.UserLifecycleEvent;
import android.car.user.CarUserManager.UserLifecycleListener;
import android.os.NewUserRequest;
import android.os.NewUserResponse;
import android.os.ParcelFileDescriptor;
import android.os.SystemClock;
import android.os.UserManager;
import android.util.Log;
import androidx.test.filters.FlakyTest;
import androidx.test.InstrumentationRegistry;
import com.android.compatibility.common.util.SystemUtil;
import org.junit.Before;
import org.junit.Test;
import java.io.BufferedReader;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
public final class CarServiceHelperServiceUpdatableTest extends CarApiTestBase {
private static final String TAG = CarServiceHelperServiceUpdatableTest.class.getSimpleName();
private static final int TIMEOUT_MS = 60_000;
private static final int WAIT_TIME_MS = 1_000;
@Before
public void setUp() throws Exception {
super.setUp();
SystemUtil.runShellCommand("logcat -b all -c");
}
@Test
public void testCarServiceHelperServiceDump() throws Exception {
assumeThat("System_server_dumper not implemented.",
executeShellCommand("service check system_server_dumper"),
containsStringIgnoringCase("system_server_dumper: found"));
assertWithMessage("System server dumper")
.that(executeShellCommand("dumpsys system_server_dumper --list"))
.contains("CarServiceHelper");
assertWithMessage("CarServiceHelperService dump")
.that(executeShellCommand("dumpsys system_server_dumper --name CarServiceHelper"))
.contains("CarServiceProxy");
// Test setSafeMode
try {
executeShellCommand("cmd car_service emulate-driving-state drive");
assertWithMessage("CarServiceHelperService dump")
.that(executeShellCommand(
"dumpsys system_server_dumper --name CarServiceHelper"))
.contains("Safe to run device policy operations: false");
} finally {
executeShellCommand("cmd car_service emulate-driving-state park");
}
assertWithMessage("CarServiceHelperService dump")
.that(executeShellCommand("dumpsys system_server_dumper --name CarServiceHelper"))
.contains("Safe to run device policy operations: true");
// Test dumpServiceStacks
assertWithMessage("CarServiceHelperService dump")
.that(executeShellCommand("dumpsys system_server_dumper --name CarServiceHelper"
+ " --dump-service-stacks"))
.contains("dumpServiceStacks ANR file path=/data/anr/anr_");
}
@FlakyTest(bugId = 222167696)
@Test
public void testSendUserLifecycleEventAndOnUserRemoved() throws Exception {
// Add listener to check if user started
CarUserManager carUserManager = (CarUserManager) getCar()
.getCarManager(Car.CAR_USER_SERVICE);
LifecycleListener listener = new LifecycleListener();
carUserManager.addListener(Runnable::run, listener);
NewUserResponse response = null;
UserManager userManager = null;
boolean userRemoved = false;
try {
// get create User permissions
InstrumentationRegistry.getInstrumentation().getUiAutomation()
.adoptShellPermissionIdentity(android.Manifest.permission.CREATE_USERS);
// CreateUser
userManager = mContext.getSystemService(UserManager.class);
response = userManager.createUser(new NewUserRequest.Builder().build());
assertThat(response.isSuccessful()).isTrue();
int userId = response.getUser().getIdentifier();
startUser(userId);
listener.assertEventReceived(userId, CarUserManager.USER_LIFECYCLE_EVENT_TYPE_STARTING);
// TestOnUserRemoved call
userRemoved = userManager.removeUser(response.getUser());
// check the dump stack
assertLastUserRemoved(userId);
} finally {
if (!userRemoved && response != null && response.isSuccessful()) {
userManager.removeUser(response.getUser());
}
carUserManager.removeListener(listener);
InstrumentationRegistry.getInstrumentation().getUiAutomation()
.dropShellPermissionIdentity();
}
}
private void assertLastUserRemoved(int userId) throws Exception {
// check for the logcat
// TODO(b/210874444): Use logcat helper from
// cts/tests/tests/car_builtin/src/android/car/cts/builtin/util/LogcatHelper.java
String match = "car_service_on_user_removed: " + userId;
long timeout = 60_000;
long startTime = SystemClock.elapsedRealtime();
UiAutomation automation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
String command = "logcat -b events";
ParcelFileDescriptor output = automation.executeShellCommand(command);
FileDescriptor fd = output.getFileDescriptor();
FileInputStream fileInputStream = new FileInputStream(fd);
try (BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(fileInputStream))) {
String line;
while ((line = bufferedReader.readLine()) != null) {
if (line.contains(match)) {
return;
}
if ((SystemClock.elapsedRealtime() - startTime) > timeout) {
fail("match '" + match + "' was not found, Timeout: " + timeout + " ms");
}
}
} catch (IOException e) {
fail("match '" + match + "' was not found, IO exception: " + e);
}
}
// TODO(214100537): Improve listener by removing sleep.
private final class LifecycleListener implements UserLifecycleListener {
private final List<UserLifecycleEvent> mEvents =
new ArrayList<CarUserManager.UserLifecycleEvent>();
private final Object mLock = new Object();
@Override
public void onEvent(UserLifecycleEvent event) {
Log.d(TAG, "Event received: " + event);
synchronized (mLock) {
mEvents.add(event);
}
}
public void assertEventReceived(int userId, int eventType)
throws InterruptedException {
long startTime = SystemClock.elapsedRealtime();
while (SystemClock.elapsedRealtime() - startTime < TIMEOUT_MS) {
boolean result = checkEvent(userId, eventType);
if (result) return;
Thread.sleep(WAIT_TIME_MS);
}
fail("Event" + eventType + " was not received within timeoutMs: " + TIMEOUT_MS);
}
private boolean checkEvent(int userId, int eventType) {
synchronized (mLock) {
for (int i = 0; i < mEvents.size(); i++) {
if (mEvents.get(i).getUserHandle().getIdentifier() == userId
&& mEvents.get(i).getEventType() == eventType) {
return true;
}
}
}
return false;
}
}
}