1 /*
2  * Copyright (C) 2016 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 android.host.accounts;
17 
18 import static org.junit.Assert.fail;
19 
20 import com.android.tradefed.device.CollectingOutputReceiver;
21 import com.android.tradefed.device.DeviceNotAvailableException;
22 import com.android.tradefed.device.ITestDevice;
23 import com.android.tradefed.log.LogUtil.CLog;
24 import com.android.tradefed.testtype.IDeviceTest;
25 
26 import org.junit.After;
27 import org.junit.Before;
28 
29 import java.io.IOException;
30 import java.util.ArrayList;
31 import java.util.concurrent.TimeUnit;
32 
33 /**
34  * Base class for multi user tests.
35  */
36 public class BaseMultiUserTest implements IDeviceTest {
37 
38     /** Guest flag value from android/content/pm/UserInfo.java */
39     private static final int FLAG_GUEST = 0x00000004;
40 
41     /**
42      * Feature flag for automotive devices
43      * https://source.android.com/compatibility/android-cdd#2_5_automotive_requirements
44      */
45     private static final String FEATURE_AUTOMOTIVE = "feature:android.hardware.type.automotive";
46     private static final String FEATURE_MANAGED_USERS = "android.software.managed_users";
47 
48     /** Whether multi-user is supported. */
49     protected boolean mSupportsMultiUser;
50     protected boolean mSupportsManagedUsers;
51     protected int mInitialUserId;
52     protected int mPrimaryUserId;
53 
54     /** Users we shouldn't delete in the tests. */
55     private ArrayList<Integer> mFixedUsers;
56 
57     private ITestDevice mDevice;
58 
59     @Before
setUp()60     public void setUp() throws Exception {
61         mSupportsMultiUser = getDevice().getMaxNumberOfUsersSupported() > 1;
62         mSupportsManagedUsers = getDevice().hasFeature(FEATURE_MANAGED_USERS);
63 
64         mInitialUserId = getDevice().getCurrentUser();
65         mPrimaryUserId = getDevice().getPrimaryUserId();
66 
67         // Test should not modify / remove any of the existing users.
68         mFixedUsers = getDevice().listUsers();
69     }
70 
71     @After
tearDown()72     public void tearDown() throws Exception {
73         if (getDevice().getCurrentUser() != mInitialUserId) {
74             CLog.w("User changed during test. Switching back to " + mInitialUserId);
75             getDevice().switchUser(mInitialUserId);
76         }
77         // Remove the users created during this test.
78         removeTestUsers();
79     }
80 
81     @Override
setDevice(ITestDevice device)82     public void setDevice(ITestDevice device) {
83         mDevice = device;
84     }
85 
86     @Override
getDevice()87     public ITestDevice getDevice() {
88         return mDevice;
89     }
90 
91     /**
92      * @param userId the userId of the parent for this profile
93      * @return the userId of the created user
94      */
createRestrictedProfile(int userId)95     protected int createRestrictedProfile(int userId)
96             throws DeviceNotAvailableException, IllegalStateException {
97         return createUser("--profileOf " + userId + " --restricted");
98     }
99 
100     /**
101      * @param userId the userId of the parent for this profile
102      * @return the userId of the created user
103      */
createProfile(int userId)104     protected int createProfile(int userId)
105             throws DeviceNotAvailableException, IllegalStateException {
106         return createUser("--profileOf " + userId + " --managed");
107     }
108 
109     /**
110      * @return the userid of the created user
111      */
createUser()112     protected int createUser()
113             throws DeviceNotAvailableException, IllegalStateException {
114         return createUser("");
115     }
116 
createUser(String extraParam)117     private int createUser(String extraParam)
118             throws DeviceNotAvailableException, IllegalStateException {
119         final String command =
120                 "pm create-user " + extraParam + " TestUser_" + System.currentTimeMillis();
121         CLog.d("Starting command: " + command);
122         final String output = getDevice().executeShellCommand(command);
123         CLog.d("Output for command " + command + ": " + output);
124 
125         if (output.startsWith("Success")) {
126             try {
127                 return Integer.parseInt(output.substring(output.lastIndexOf(" ")).trim());
128             } catch (NumberFormatException e) {
129                 throw new IllegalStateException("Failed to parse result: " + output);
130             }
131         }
132 
133         throw new IllegalStateException("Failed to create user: " + output);
134     }
135 
createGuestUser()136     protected int createGuestUser() throws Exception {
137         return mDevice.createUser(
138                 "TestUser_" + System.currentTimeMillis() /* name */,
139                 true /* guest */,
140                 false /* ephemeral */);
141     }
142 
getGuestUser()143     protected int getGuestUser() throws Exception {
144         for (int userId : mDevice.listUsers()) {
145             if ((mDevice.getUserFlags(userId) & FLAG_GUEST) != 0) {
146                 return userId;
147             }
148         }
149         return -1;
150     }
151 
isAutomotiveDevice()152     protected boolean isAutomotiveDevice() throws Exception {
153         return getDevice().hasFeature(FEATURE_AUTOMOTIVE);
154     }
155 
removeTestUsers()156     private void removeTestUsers() throws Exception {
157         for (int userId : getDevice().listUsers()) {
158             if (!mFixedUsers.contains(userId)) {
159                 getDevice().removeUser(userId);
160             }
161         }
162     }
163 
waitForBroadcastIdle()164     protected void waitForBroadcastIdle() throws DeviceNotAvailableException, IOException {
165         final CollectingOutputReceiver receiver = new CollectingOutputReceiver();
166         // We allow 8min for the command to complete and 4min for the command to start to
167         // output something.
168         getDevice().executeShellCommand(
169                 "am wait-for-broadcast-idle", receiver, 8, 4, TimeUnit.MINUTES, 0);
170         final String output = receiver.getOutput();
171         if (!output.contains("All broadcast queues are idle!")) {
172             CLog.e("Output from 'am wait-for-broadcast-idle': %s", output);
173             fail("'am wait-for-broadcase-idle' did not complete.");
174         }
175     }
176 }
177