• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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.internal.os;
18 
19 import static org.junit.Assert.assertNotNull;
20 import static org.junit.Assert.assertTrue;
21 import static org.junit.Assume.assumeTrue;
22 
23 import android.app.ActivityManager;
24 import android.app.IActivityManager;
25 import android.app.IStopUserCallback;
26 import android.content.Context;
27 import android.content.pm.UserInfo;
28 import android.os.RemoteException;
29 import android.os.UserHandle;
30 import android.os.UserManager;
31 import android.support.test.uiautomator.UiDevice;
32 import android.util.ArraySet;
33 
34 import androidx.test.InstrumentationRegistry;
35 import androidx.test.filters.LargeTest;
36 import androidx.test.runner.AndroidJUnit4;
37 
38 import org.junit.After;
39 import org.junit.Before;
40 import org.junit.BeforeClass;
41 import org.junit.Test;
42 import org.junit.runner.RunWith;
43 
44 import java.util.concurrent.CountDownLatch;
45 import java.util.concurrent.TimeUnit;
46 
47 @LargeTest
48 @RunWith(AndroidJUnit4.class)
49 public class BatteryStatsUserLifecycleTests {
50 
51     private static final long POLL_INTERVAL_MS = 500;
52     private static final long USER_REMOVE_TIMEOUT_MS = 5_000;
53     private static final long STOP_USER_TIMEOUT_MS = 10_000;
54     private static final long BATTERYSTATS_POLLING_TIMEOUT_MS = 5_000;
55 
56     private static final String CPU_DATA_TAG = "cpu";
57     private static final String CPU_FREQ_DATA_TAG = "ctf";
58 
59     private int mTestUserId = UserHandle.USER_NULL;
60     private Context mContext;
61     private UserManager mUm;
62     private IActivityManager mIam;
63 
64     @BeforeClass
setUpOnce()65     public static void setUpOnce() {
66         assumeTrue(UserManager.getMaxSupportedUsers() > 1);
67     }
68 
69     @Before
setUp()70     public void setUp() throws Exception {
71         mContext = InstrumentationRegistry.getTargetContext();
72         mUm = UserManager.get(mContext);
73         mIam = ActivityManager.getService();
74         final UserInfo user = mUm.createUser("Test_user_" + System.currentTimeMillis() / 1000, 0);
75         assertNotNull("Unable to create test user", user);
76         mTestUserId = user.id;
77         batteryOnScreenOff();
78     }
79 
80     @Test
81     @SkipPresubmit("b/180015146")
testNoCpuDataForRemovedUser()82     public void testNoCpuDataForRemovedUser() throws Exception {
83         mIam.startUserInBackground(mTestUserId);
84         waitUntilTrue("No uids for started user " + mTestUserId,
85                 () -> getNumberOfUidsInBatteryStats() > 0, BATTERYSTATS_POLLING_TIMEOUT_MS);
86 
87         CountDownLatch stopUserLatch = new CountDownLatch(1);
88         mIam.stopUser(mTestUserId, true, new IStopUserCallback.Stub() {
89             @Override
90             public void userStopped(int userId) throws RemoteException {
91                 stopUserLatch.countDown();
92             }
93 
94             @Override
95             public void userStopAborted(int userId) throws RemoteException {
96             }
97         });
98         assertTrue("User " + mTestUserId + " could not be stopped",
99                 stopUserLatch.await(STOP_USER_TIMEOUT_MS, TimeUnit.MILLISECONDS));
100 
101         mUm.removeUser(mTestUserId);
102         waitUntilTrue("Unable to remove user " + mTestUserId, () -> {
103             for (UserInfo user : mUm.getUsers()) {
104                 if (user.id == mTestUserId) {
105                     return false;
106                 }
107             }
108             return true;
109         }, USER_REMOVE_TIMEOUT_MS);
110         waitUntilTrue("Uids still found for removed user " + mTestUserId,
111                 () -> getNumberOfUidsInBatteryStats() == 0, BATTERYSTATS_POLLING_TIMEOUT_MS);
112     }
113 
114     @After
tearDown()115     public void tearDown() throws Exception {
116         batteryOffScreenOn();
117         if (mTestUserId != UserHandle.USER_NULL) {
118             mUm.removeUser(mTestUserId);
119         }
120     }
121 
getNumberOfUidsInBatteryStats()122     private int getNumberOfUidsInBatteryStats() throws Exception {
123         ArraySet<Integer> uids = new ArraySet<>();
124         final String dumpsys = executeShellCommand("dumpsys batterystats --checkin");
125         for (String line : dumpsys.split("\n")) {
126             final String[] parts = line.trim().split(",");
127             if (parts.length < 5 ||
128                     (!parts[3].equals(CPU_DATA_TAG) && !parts[3].equals(CPU_FREQ_DATA_TAG))) {
129                 continue;
130             }
131             try {
132                 final int uid = Integer.parseInt(parts[1]);
133                 if (UserHandle.getUserId(uid) == mTestUserId) {
134                     uids.add(uid);
135                 }
136             } catch (NumberFormatException nexc) {
137                 // ignore
138             }
139         }
140         return uids.size();
141     }
142 
batteryOnScreenOff()143     protected void batteryOnScreenOff() throws Exception {
144         executeShellCommand("dumpsys battery unplug");
145         executeShellCommand("dumpsys batterystats enable pretend-screen-off");
146     }
147 
batteryOffScreenOn()148     protected void batteryOffScreenOn() throws Exception {
149         executeShellCommand("dumpsys battery reset");
150         executeShellCommand("dumpsys batterystats disable pretend-screen-off");
151     }
152 
executeShellCommand(String cmd)153     private String executeShellCommand(String cmd) throws Exception {
154         return UiDevice.getInstance(
155                 InstrumentationRegistry.getInstrumentation()).executeShellCommand(cmd);
156     }
157 
waitUntilTrue(String message, Condition condition, long timeout)158     private void waitUntilTrue(String message, Condition condition, long timeout) throws Exception {
159         final long deadLine = System.currentTimeMillis() + timeout;
160         while (System.currentTimeMillis() <= deadLine && !condition.isTrue()) {
161             Thread.sleep(POLL_INTERVAL_MS);
162         }
163         assertTrue(message, condition.isTrue());
164     }
165 
166     private interface Condition {
isTrue()167         boolean isTrue() throws Exception;
168     }
169 }
170