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 */
16package com.android.statsd.loadtest;
17
18import android.util.Log;
19import android.util.StatsLog;
20
21import java.util.ArrayList;
22import java.util.List;
23
24/**
25 * Manages the pushing of atoms into logd for loadtesting.
26 * We rely on small number of pushed atoms, and a config with metrics based on those atoms.
27 * The atoms are:
28 * <ul>
29 *   <li> BatteryLevelChanged   - For EventMetric, CountMetric and GaugeMetric (no dimensions).
30 *   <li> BleScanResultReceived - For CountMetric and ValueMetric, sliced by uid.
31 *   <li> ChargingStateChanged  - For DurationMetric (no dimension).
32 *   <li> GpsScanStateChanged   - For DurationMetric, sliced by uid.
33 *   <li> ScreenStateChanged    - For Conditions with no dimensions.
34 *   <li> AudioStateChanged     - For Conditions with dimensions (uid).
35 * </ul>
36 * The sequence is played over and over at a given frequency.
37 */
38public class SequencePusher {
39    private static final String TAG = "SequencePusher";
40
41    /** Some atoms are pushed in burst of {@code mBurst} events. */
42    private final int mBurst;
43
44    /** If this is true, we don't log anything in logd. */
45    private final boolean mPlacebo;
46
47    /** Current state in the automaton. */
48    private int mCursor = 0;
49
50  public SequencePusher(int burst, boolean placebo) {
51        mBurst = burst;
52        mPlacebo = placebo;
53    }
54
55    /**
56     * Pushes the next atom to logd.
57     * This follows a small automaton which makes the right events and conditions overlap:
58     *   (0)  Push a burst of BatteryLevelChanged atoms.
59     *   (1)  Push a burst of BleScanResultReceived atoms.
60     *   (2)  Push ChargingStateChanged with BATTERY_STATUS_CHARGING once.
61     *   (3)  Push a burst of GpsScanStateChanged atoms with ON, with a different uid each time.
62     *   (4)  Push ChargingStateChanged with BATTERY_STATUS_NOT_CHARGING once.
63     *   (5)  Push a burst GpsScanStateChanged atoms with OFF, with a different uid each time.
64     *   (6)  Push ScreenStateChanged with STATE_ON once.
65     *   (7)  Push a burst of AudioStateChanged with ON, with a different uid each time.
66     *   (8)  Repeat steps (0)-(5).
67     *   (9)  Push ScreenStateChanged with STATE_OFF once.
68     *   (10) Push a burst of AudioStateChanged with OFF, with a different uid each time.
69     * and repeat.
70     */
71    public void next() {
72        Log.d(TAG, "Next step: " + mCursor);
73        if (mPlacebo) {
74            return;
75        }
76        switch (mCursor) {
77            case 0:
78            case 8:
79                for (int i = 0; i < mBurst; i++) {
80                    StatsLog.write(StatsLog.BATTERY_LEVEL_CHANGED, 50 + i /* battery_level */);
81                }
82                break;
83            case 1:
84            case 9:
85                for (int i = 0; i < mBurst; i++) {
86                    StatsLog.write(StatsLog.BLE_SCAN_RESULT_RECEIVED, i /* uid */,
87                        100 /* num_of_results */);
88                }
89                break;
90            case 2:
91            case 10:
92                StatsLog.write(StatsLog.CHARGING_STATE_CHANGED,
93                    StatsLog.CHARGING_STATE_CHANGED__STATE__BATTERY_STATUS_CHARGING
94                    /* charging_state */);
95                break;
96            case 3:
97            case 11:
98                for (int i = 0; i < mBurst; i++) {
99                    StatsLog.write(StatsLog.GPS_SCAN_STATE_CHANGED, i /* uid */,
100                        StatsLog.GPS_SCAN_STATE_CHANGED__STATE__ON /* state */);
101                }
102                break;
103            case 4:
104            case 12:
105                StatsLog.write(StatsLog.CHARGING_STATE_CHANGED,
106                    StatsLog.CHARGING_STATE_CHANGED__STATE__BATTERY_STATUS_NOT_CHARGING
107                    /* charging_state */);
108                break;
109            case 5:
110            case 13:
111                for (int i = 0; i < mBurst; i++) {
112                    StatsLog.write(StatsLog.GPS_SCAN_STATE_CHANGED, i /* uid */,
113                        StatsLog.GPS_SCAN_STATE_CHANGED__STATE__OFF /* state */);
114                }
115                break;
116            case 6:
117                StatsLog.write(StatsLog.SCREEN_STATE_CHANGED,
118                    StatsLog.SCREEN_STATE_CHANGED__STATE__DISPLAY_STATE_ON /* display_state */);
119                break;
120            case 7:
121                for (int i = 0; i < mBurst; i++) {
122                    StatsLog.write(StatsLog.AUDIO_STATE_CHANGED, i /* uid */,
123                        StatsLog.AUDIO_STATE_CHANGED__STATE__ON /* state */);
124                }
125                break;
126            case 14:
127                StatsLog.write(StatsLog.SCREEN_STATE_CHANGED,
128                    StatsLog.SCREEN_STATE_CHANGED__STATE__DISPLAY_STATE_OFF /* display_state */);
129                break;
130            case 15:
131                for (int i = 0; i < mBurst; i++) {
132                    StatsLog.write(StatsLog.AUDIO_STATE_CHANGED, i /* uid */,
133                        StatsLog.AUDIO_STATE_CHANGED__STATE__OFF /* state */);
134                }
135                break;
136            default:
137        }
138        mCursor++;
139        if (mCursor > 15) {
140            mCursor = 0;
141        }
142    }
143
144    /**
145     * Properly finishes in order to be close all conditions and durations.
146     */
147    public void finish() {
148        // Screen goes back to off. This will ensure that conditions get back to false.
149        StatsLog.write(StatsLog.SCREEN_STATE_CHANGED,
150            StatsLog.SCREEN_STATE_CHANGED__STATE__DISPLAY_STATE_OFF /* display_state */);
151        for (int i = 0; i < mBurst; i++) {
152          StatsLog.write(StatsLog.AUDIO_STATE_CHANGED, i /* uid */,
153              StatsLog.AUDIO_STATE_CHANGED__STATE__OFF /* state */);
154        }
155        // Stop charging, to ensure the corresponding durations are closed.
156        StatsLog.write(StatsLog.CHARGING_STATE_CHANGED,
157            StatsLog.CHARGING_STATE_CHANGED__STATE__BATTERY_STATUS_NOT_CHARGING
158            /* charging_state */);
159        // Stop scanning GPS, to ensure the corresponding conditions get back to false.
160        for (int i = 0; i < mBurst; i++) {
161          StatsLog.write(StatsLog.GPS_SCAN_STATE_CHANGED, i /* uid */,
162              StatsLog.GPS_SCAN_STATE_CHANGED__STATE__OFF /* state */);
163        }
164    }
165}
166