blob: 5fecde510ef507ab979241f5712ee1cdce99952c [file] [log] [blame]
/*
* Copyright (C) 2017 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.cts.statsd.atom;
import android.app.ProcessStateEnum; // From enums.proto for atoms.proto's UidProcessStateChanged.
import com.android.os.AtomsProto.Atom;
import com.android.os.StatsLog.EventMetricData;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* Statsd atom tests that are done via app, for atoms that report a uid.
*/
public class ProcStateAtomTests extends ProcStateTestCase {
private static final String TAG = "Statsd.ProcStateAtomTests";
private static final int WAIT_TIME_FOR_CONFIG_UPDATE_MS = 200;
// ActivityManager can take a while to register screen state changes, mandating an extra delay.
private static final int WAIT_TIME_FOR_CONFIG_AND_SCREEN_MS = 1_000;
private static final int EXTRA_WAIT_TIME_MS = 1_000; // as buffer when proc state changing.
private static final int STATSD_REPORT_WAIT_TIME_MS = 500; // make sure statsd finishes log.
private static final String FEATURE_WATCH = "android.hardware.type.watch";
// The tests here are using the BatteryStats definition of 'background'.
private static final Set<Integer> BG_STATES = new HashSet<>(
Arrays.asList(
ProcessStateEnum.PROCESS_STATE_IMPORTANT_BACKGROUND_VALUE,
ProcessStateEnum.PROCESS_STATE_TRANSIENT_BACKGROUND_VALUE,
ProcessStateEnum.PROCESS_STATE_BACKUP_VALUE,
ProcessStateEnum.PROCESS_STATE_SERVICE_VALUE,
ProcessStateEnum.PROCESS_STATE_RECEIVER_VALUE,
ProcessStateEnum.PROCESS_STATE_HEAVY_WEIGHT_VALUE
));
// Using the BatteryStats definition of 'cached', which is why HOME (etc) are considered cached.
private static final Set<Integer> CACHED_STATES = new HashSet<>(
Arrays.asList(
ProcessStateEnum.PROCESS_STATE_HOME_VALUE,
ProcessStateEnum.PROCESS_STATE_LAST_ACTIVITY_VALUE,
ProcessStateEnum.PROCESS_STATE_CACHED_ACTIVITY_VALUE,
ProcessStateEnum.PROCESS_STATE_CACHED_ACTIVITY_CLIENT_VALUE,
ProcessStateEnum.PROCESS_STATE_CACHED_RECENT_VALUE,
ProcessStateEnum.PROCESS_STATE_CACHED_EMPTY_VALUE
));
private static final Set<Integer> MISC_STATES = new HashSet<>(
Arrays.asList(
ProcessStateEnum.PROCESS_STATE_PERSISTENT_VALUE, // TODO: untested
ProcessStateEnum.PROCESS_STATE_PERSISTENT_UI_VALUE, // TODO: untested
ProcessStateEnum.PROCESS_STATE_TOP_VALUE,
ProcessStateEnum.PROCESS_STATE_BOUND_TOP_VALUE, // TODO: untested
ProcessStateEnum.PROCESS_STATE_BOUND_FOREGROUND_SERVICE_VALUE, // TODO: untested
ProcessStateEnum.PROCESS_STATE_FOREGROUND_SERVICE_VALUE,
ProcessStateEnum.PROCESS_STATE_IMPORTANT_FOREGROUND_VALUE,
ProcessStateEnum.PROCESS_STATE_TOP_SLEEPING_VALUE,
ProcessStateEnum.PROCESS_STATE_UNKNOWN_VALUE,
ProcessStateEnum.PROCESS_STATE_NONEXISTENT_VALUE
));
private static final Set<Integer> ALL_STATES = Stream.of(MISC_STATES, CACHED_STATES, BG_STATES)
.flatMap(s -> s.stream()).collect(Collectors.toSet());
private static final Function<Atom, Integer> PROC_STATE_FUNCTION =
atom -> atom.getUidProcessStateChanged().getState().getNumber();
private static final int PROC_STATE_ATOM_TAG = Atom.UID_PROCESS_STATE_CHANGED_FIELD_NUMBER;
@Override
protected void setUp() throws Exception {
super.setUp();
}
public void testForegroundService() throws Exception {
if (statsdDisabled()) {
return;
}
Set<Integer> onStates = new HashSet<>(Arrays.asList(
ProcessStateEnum.PROCESS_STATE_FOREGROUND_SERVICE_VALUE));
Set<Integer> offStates = complement(onStates);
List<Set<Integer>> stateSet = Arrays.asList(onStates, offStates); // state sets, in order
createAndUploadConfig(PROC_STATE_ATOM_TAG, false); // False: does not use attribution.
Thread.sleep(WAIT_TIME_FOR_CONFIG_UPDATE_MS);
executeForegroundService();
final int waitTime = SLEEP_OF_FOREGROUND_SERVICE + EXTRA_WAIT_TIME_MS;
Thread.sleep(waitTime + STATSD_REPORT_WAIT_TIME_MS);
List<EventMetricData> data = getEventMetricDataList();
popUntilFind(data, onStates, PROC_STATE_FUNCTION); // clear out initial proc states.
assertStatesOccurred(stateSet, data, waitTime, PROC_STATE_FUNCTION);
}
public void testForeground() throws Exception {
if (statsdDisabled()) {
return;
}
Set<Integer> onStates = new HashSet<>(Arrays.asList(
ProcessStateEnum.PROCESS_STATE_IMPORTANT_FOREGROUND_VALUE));
// There are no offStates, since the app remains in foreground until killed.
List<Set<Integer>> stateSet = Arrays.asList(onStates); // state sets, in order
createAndUploadConfig(PROC_STATE_ATOM_TAG, false); // False: does not use attribution.
Thread.sleep(WAIT_TIME_FOR_CONFIG_AND_SCREEN_MS);
executeForegroundActivity(ACTION_SHOW_APPLICATION_OVERLAY);
final int waitTime = EXTRA_WAIT_TIME_MS + 5_000; // Overlay may need to sit there a while.
Thread.sleep(waitTime + STATSD_REPORT_WAIT_TIME_MS);
List<EventMetricData> data = getEventMetricDataList();
popUntilFind(data, onStates, PROC_STATE_FUNCTION); // clear out initial proc states.
assertStatesOccurred(stateSet, data, 0, PROC_STATE_FUNCTION);
}
public void testBackground() throws Exception {
if (statsdDisabled()) {
return;
}
Set<Integer> onStates = BG_STATES;
Set<Integer> offStates = complement(onStates);
List<Set<Integer>> stateSet = Arrays.asList(onStates, offStates); // state sets, in order
createAndUploadConfig(PROC_STATE_ATOM_TAG, false); // False: does not use attribution.
Thread.sleep(WAIT_TIME_FOR_CONFIG_UPDATE_MS);
executeBackgroundService(ACTION_BACKGROUND_SLEEP);
final int waitTime = SLEEP_OF_ACTION_BACKGROUND_SLEEP + EXTRA_WAIT_TIME_MS;
Thread.sleep(waitTime + STATSD_REPORT_WAIT_TIME_MS);
List<EventMetricData> data = getEventMetricDataList();
popUntilFind(data, onStates, PROC_STATE_FUNCTION); // clear out initial proc states.
assertStatesOccurred(stateSet, data, waitTime, PROC_STATE_FUNCTION);
}
public void testTop() throws Exception {
if (statsdDisabled()) {
return;
}
Set<Integer> onStates = new HashSet<>(Arrays.asList(
ProcessStateEnum.PROCESS_STATE_TOP_VALUE));
Set<Integer> offStates = complement(onStates);
List<Set<Integer>> stateSet = Arrays.asList(onStates, offStates); // state sets, in order
createAndUploadConfig(PROC_STATE_ATOM_TAG, false); // False: does not use attribution.
Thread.sleep(WAIT_TIME_FOR_CONFIG_AND_SCREEN_MS);
executeForegroundActivity(ACTION_SLEEP_WHILE_TOP);
final int waitTime = SLEEP_OF_ACTION_SLEEP_WHILE_TOP + EXTRA_WAIT_TIME_MS;
Thread.sleep(waitTime + STATSD_REPORT_WAIT_TIME_MS);
List<EventMetricData> data = getEventMetricDataList();
popUntilFind(data, onStates, PROC_STATE_FUNCTION); // clear out initial proc states.
assertStatesOccurred(stateSet, data, waitTime, PROC_STATE_FUNCTION);
}
public void testTopSleeping() throws Exception {
if (statsdDisabled()) {
return;
}
if (!hasFeature(FEATURE_WATCH, false)) return;
Set<Integer> onStates = new HashSet<>(Arrays.asList(
ProcessStateEnum.PROCESS_STATE_TOP_SLEEPING_VALUE));
Set<Integer> offStates = complement(onStates);
List<Set<Integer>> stateSet = Arrays.asList(onStates, offStates); // state sets, in order
createAndUploadConfig(PROC_STATE_ATOM_TAG, false); //False: does not use attribution.
turnScreenOn();
Thread.sleep(WAIT_TIME_FOR_CONFIG_AND_SCREEN_MS);
executeForegroundActivity(ACTION_SLEEP_WHILE_TOP);
// ASAP, turn off the screen to make proc state -> top_sleeping.
turnScreenOff();
final int waitTime = SLEEP_OF_ACTION_SLEEP_WHILE_TOP + EXTRA_WAIT_TIME_MS;
Thread.sleep(waitTime + STATSD_REPORT_WAIT_TIME_MS);
List<EventMetricData> data = getEventMetricDataList();
popUntilFind(data, new HashSet<>(Arrays.asList(ProcessStateEnum.PROCESS_STATE_TOP_VALUE)),
PROC_STATE_FUNCTION); // clear out anything prior to it entering TOP.
popUntilFind(data, onStates, PROC_STATE_FUNCTION); // clear out TOP itself.
// reset screen back on
turnScreenOn();
// Don't check the wait time, since it's up to the system how long top sleeping persists.
assertStatesOccurred(stateSet, data, 0, PROC_STATE_FUNCTION);
}
public void testCached() throws Exception {
if (statsdDisabled()) {
return;
}
Set<Integer> onStates = CACHED_STATES;
Set<Integer> offStates = complement(onStates);
List<Set<Integer>> stateSet = Arrays.asList(onStates, offStates); // state sets, in order
createAndUploadConfig(PROC_STATE_ATOM_TAG, false); // False: des not use attribution.
Thread.sleep(WAIT_TIME_FOR_CONFIG_UPDATE_MS);
// The schedule is as follows
// #1. The system may do anything it wants, such as moving the app into a cache state.
// #2. We move the app into the background.
// #3. The background process ends, so the app definitely moves to a cache state
// (this is the ultimate goal of the test).
// #4. We start a foreground activity, moving the app out of cache.
// Start extremely short-lived activity, so app goes into cache state (#1 - #3 above).
executeBackgroundService(ACTION_END_IMMEDIATELY);
final int cacheTime = 2_000; // process should be in cached state for up to this long
Thread.sleep(cacheTime);
// Now forcibly bring the app out of cache (#4 above).
executeForegroundActivity(ACTION_SHOW_APPLICATION_OVERLAY);
// Now check the data *before* the app enters cache again (to avoid another cache event).
List<EventMetricData> data = getEventMetricDataList();
// First, clear out any incidental cached states of step #1, prior to step #2.
popUntilFind(data, BG_STATES, PROC_STATE_FUNCTION);
// Now clear out the bg state from step #2 (since we are interested in the cache after it).
popUntilFind(data, onStates, PROC_STATE_FUNCTION);
// The result is that data should start at step #3, definitively in a cached state.
assertStatesOccurred(stateSet, data, 1_000, PROC_STATE_FUNCTION);
}
public void testValidityOfStates() throws Exception {
if (statsdDisabled()) {
return;
}
assertFalse("UNKNOWN_TO_PROTO should not be a valid state",
ALL_STATES.contains(ProcessStateEnum.PROCESS_STATE_UNKNOWN_TO_PROTO_VALUE));
}
/** Returns the a set containing elements of a that are not elements of b. */
private Set<Integer> difference(Set<Integer> a, Set<Integer> b) {
Set<Integer> result = new HashSet<Integer>(a);
result.removeAll(b);
return result;
}
/** Returns the set of all states that are not in set. */
private Set<Integer> complement(Set<Integer> set) {
return difference(ALL_STATES, set);
}
}