• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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 package com.android.tradefed.targetprep;
17 
18 import static com.android.tradefed.targetprep.UserHelper.RUN_TESTS_AS_USER_KEY;
19 
20 import com.android.annotations.VisibleForTesting;
21 import com.android.tradefed.config.Option;
22 import com.android.tradefed.config.OptionClass;
23 import com.android.tradefed.device.DeviceNotAvailableException;
24 import com.android.tradefed.device.ITestDevice;
25 import com.android.tradefed.invoker.TestInformation;
26 import com.android.tradefed.log.LogUtil.CLog;
27 
28 import java.util.Iterator;
29 import java.util.Set;
30 
31 import javax.annotation.Nullable;
32 
33 /** Target preparer for running tests in a user that is started in the visible in the background. */
34 @OptionClass(alias = "visible-background-user-preparer")
35 public class VisibleBackgroundUserPreparer extends BaseTargetPreparer {
36 
37     @VisibleForTesting public static final int INVALID_DISPLAY = -1; // same as android.view.Display
38     @VisibleForTesting public static final int DEFAULT_DISPLAY = 0; // same as android.view.Display
39 
40     /**
41      * Property used to indicate whether to install test apk for all users.
42      * TODO: b/367468564 - Remove this property once we have fixed the tests so that
43      * installation for the system user is no longer required
44      */
45     static final String INSTALL_TEST_APK_FOR_ALL_USERS = "INSTALL_TEST_APK_FOR_ALL_USERS";
46 
47     @Option(
48             name = "reuse-test-user",
49             description =
50                     "Whether or not to reuse already created tradefed test user, or remove them "
51                             + " and re-create them between module runs.")
52     private boolean mReuseTestUser;
53 
54     @Option(name = "display-id", description = "Which display to start the user visible on")
55     private int mDisplayId = INVALID_DISPLAY;
56 
57     private Integer mUserId;
58     private boolean mUserAlreadyVisible;
59 
60     @Override
setUp(TestInformation testInfo)61     public void setUp(TestInformation testInfo)
62             throws TargetSetupError, BuildError, DeviceNotAvailableException {
63         ITestDevice device = testInfo.getDevice();
64         if (!device.isVisibleBackgroundUsersSupported()) {
65             throw new TargetSetupError("feature not supported", device.getDeviceDescriptor());
66         }
67         CLog.i("setUp(): mReuseTestUser=%b, mDisplayId=%d", mReuseTestUser, mDisplayId);
68 
69         mUserId = UserHelper.createUser(device, mReuseTestUser);
70 
71         startUserVisibleOnBackground(testInfo, device, mUserId);
72 
73         device.waitForDeviceAvailable();
74         device.postBootSetup();
75     }
76 
setDisplayId(int displayId)77     public void setDisplayId(int displayId) {
78         if (displayId == INVALID_DISPLAY) {
79             throw new IllegalArgumentException(
80                     "Cannot set it as INVALID_DISPLAY (" + INVALID_DISPLAY + ")");
81         }
82         mDisplayId = displayId;
83     }
84 
85     @VisibleForTesting
getDisplayId()86     public @Nullable Integer getDisplayId() {
87         return mDisplayId;
88     }
89 
startUserVisibleOnBackground( TestInformation testInfo, ITestDevice device, int userId)90     private void startUserVisibleOnBackground(
91             TestInformation testInfo, ITestDevice device, int userId)
92             throws TargetSetupError, DeviceNotAvailableException {
93         int displayId = mDisplayId;
94         if (displayId == INVALID_DISPLAY) {
95             // If display is not explicitly set (by option / setter), get the first available one
96             Set<Integer> displays = device.listDisplayIdsForStartingVisibleBackgroundUsers();
97             CLog.d("Displays: %s", displays);
98             if (displays.isEmpty()) {
99                 throw new TargetSetupError(
100                         String.format("No display available to start to user '%d'", userId),
101                         device.getDeviceDescriptor());
102             }
103             Iterator<Integer> iterator = displays.iterator();
104             displayId = iterator.next();
105             if (displayId == DEFAULT_DISPLAY
106                     && device.isVisibleBackgroundUsersOnDefaultDisplaySupported()) {
107                 // Ignore default display - it's a special case where the display id should have
108                 // been passed directly
109                 CLog.d(
110                         "Ignoring DEFAULT_DISPLAY because device supports background users on"
111                                 + " default display");
112                 if (!iterator.hasNext()) {
113                     throw new TargetSetupError(
114                             String.format(
115                                     "Only DEFAULT_DISPLAY available to start to user '%d'", userId),
116                             device.getDeviceDescriptor());
117                 }
118                 displayId = iterator.next();
119             }
120         }
121 
122         mUserAlreadyVisible = device.isUserVisibleOnDisplay(userId, displayId);
123         if (mUserAlreadyVisible) {
124             CLog.d(
125                     "startUserVisibleOnBackground(): user %d already visible on display %d",
126                     userId, displayId);
127         } else {
128             CLog.d(
129                     "startUserVisibleOnBackground(): starting user %d visible on display %d",
130                     userId, displayId);
131 
132             if (!device.startVisibleBackgroundUser(userId, displayId, /* waitFlag= */ true)) {
133                 throw new TargetSetupError(
134                         String.format(
135                                 "Failed to start to user '%s' on display %d", mUserId, displayId),
136                         device.getDeviceDescriptor());
137             }
138         }
139 
140         CLog.i("Setting test property %s=%d", RUN_TESTS_AS_USER_KEY, mUserId);
141         testInfo.properties().put(RUN_TESTS_AS_USER_KEY, Integer.toString(mUserId));
142         // TODO: b/367468564 - Remove this property once we have fixed the tests so that
143         // installation for the system user is no longer required
144         testInfo.properties().put(INSTALL_TEST_APK_FOR_ALL_USERS, "true");
145     }
146 
147     @Override
tearDown(TestInformation testInfo, Throwable e)148     public void tearDown(TestInformation testInfo, Throwable e) throws DeviceNotAvailableException {
149         if (mUserId == null) {
150             CLog.d("Skipping teardown because no user was created or reused");
151             return;
152         }
153         // Clean property at teardown
154         testInfo.properties().remove(RUN_TESTS_AS_USER_KEY);
155         if (e instanceof DeviceNotAvailableException) {
156             CLog.d("Skipping teardown due to dnae: %s", e.getMessage());
157             return;
158         }
159         ITestDevice device = testInfo.getDevice();
160 
161         stopTestUser(device);
162 
163         if (!mReuseTestUser) {
164             device.removeUser(mUserId);
165         }
166     }
167 
stopTestUser(ITestDevice device)168     private void stopTestUser(ITestDevice device) throws DeviceNotAvailableException {
169         if (mUserAlreadyVisible) {
170             CLog.d("stopTestUser(): user %d was already visible on start", mUserId);
171             return;
172         }
173         CLog.d("stopTestUser(): stopping user %d ", mUserId);
174         if (!device.stopUser(mUserId, /* waitFlag= */ true, /* forceFlag= */ true)) {
175             CLog.e("Failed to stop user '%d'", mUserId);
176         }
177     }
178 }
179