Home | History | Annotate | Download | only in atom
      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 package android.cts.statsd.atom;
     17 
     18 import android.net.wifi.WifiModeEnum;
     19 import android.os.WakeLockLevelEnum;
     20 import android.platform.test.annotations.RestrictedBuildTest;
     21 import android.server.ErrorSource;
     22 
     23 import com.android.internal.os.StatsdConfigProto.FieldMatcher;
     24 import com.android.internal.os.StatsdConfigProto.StatsdConfig;
     25 import com.android.os.AtomsProto;
     26 import com.android.os.AtomsProto.ANROccurred;
     27 import com.android.os.AtomsProto.AppCrashOccurred;
     28 import com.android.os.AtomsProto.AppStartOccurred;
     29 import com.android.os.AtomsProto.Atom;
     30 import com.android.os.AtomsProto.AttributionNode;
     31 import com.android.os.AtomsProto.AudioStateChanged;
     32 import com.android.os.AtomsProto.BinderCalls;
     33 import com.android.os.AtomsProto.BleScanResultReceived;
     34 import com.android.os.AtomsProto.BleScanStateChanged;
     35 import com.android.os.AtomsProto.CameraStateChanged;
     36 import com.android.os.AtomsProto.CpuActiveTime;
     37 import com.android.os.AtomsProto.DangerousPermissionState;
     38 import com.android.os.AtomsProto.DeviceCalculatedPowerBlameUid;
     39 import com.android.os.AtomsProto.FlashlightStateChanged;
     40 import com.android.os.AtomsProto.ForegroundServiceStateChanged;
     41 import com.android.os.AtomsProto.GpsScanStateChanged;
     42 import com.android.os.AtomsProto.HiddenApiUsed;
     43 import com.android.os.AtomsProto.LooperStats;
     44 import com.android.os.AtomsProto.LmkKillOccurred;
     45 import com.android.os.AtomsProto.MediaCodecStateChanged;
     46 import com.android.os.AtomsProto.NativeProcessMemoryState;
     47 import com.android.os.AtomsProto.OverlayStateChanged;
     48 import com.android.os.AtomsProto.PictureInPictureStateChanged;
     49 import com.android.os.AtomsProto.ProcessMemoryHighWaterMark;
     50 import com.android.os.AtomsProto.ProcessMemoryState;
     51 import com.android.os.AtomsProto.ScheduledJobStateChanged;
     52 import com.android.os.AtomsProto.SyncStateChanged;
     53 import com.android.os.AtomsProto.TestAtomReported;
     54 import com.android.os.AtomsProto.VibratorStateChanged;
     55 import com.android.os.AtomsProto.WakelockStateChanged;
     56 import com.android.os.AtomsProto.WakeupAlarmOccurred;
     57 import com.android.os.AtomsProto.WifiLockStateChanged;
     58 import com.android.os.AtomsProto.WifiMulticastLockStateChanged;
     59 import com.android.os.AtomsProto.WifiScanStateChanged;
     60 import com.android.os.StatsLog.EventMetricData;
     61 import com.android.tradefed.log.LogUtil;
     62 
     63 import java.util.Arrays;
     64 import java.util.HashSet;
     65 import java.util.List;
     66 import java.util.Set;
     67 
     68 /**
     69  * Statsd atom tests that are done via app, for atoms that report a uid.
     70  */
     71 public class UidAtomTests extends DeviceAtomTestCase {
     72 
     73     private static final String TAG = "Statsd.UidAtomTests";
     74 
     75     private static final boolean DAVEY_ENABLED = false;
     76 
     77     @Override
     78     protected void setUp() throws Exception {
     79         super.setUp();
     80     }
     81 
     82     @Override
     83     protected void tearDown() throws Exception {
     84         resetBatteryStatus();
     85         super.tearDown();
     86     }
     87 
     88     public void testLmkKillOccurred() throws Exception {
     89         if (statsdDisabled() || !"true".equals(getProperty("ro.lmk.log_stats"))) {
     90             return;
     91         }
     92 
     93         StatsdConfig.Builder conf = createConfigBuilder()
     94                 .addAllowedLogSource("AID_LMKD");
     95         final int atomTag = Atom.LMK_KILL_OCCURRED_FIELD_NUMBER;
     96         addAtomEvent(conf, atomTag, false);
     97         uploadConfig(conf);
     98 
     99         Thread.sleep(WAIT_TIME_SHORT);
    100 
    101         executeBackgroundService(ACTION_LMK);
    102         Thread.sleep(5_000);
    103 
    104         // Sorted list of events in order in which they occurred.
    105         List<EventMetricData> data = getEventMetricDataList();
    106 
    107         assertEquals(1, data.size());
    108         assertTrue(data.get(0).getAtom().hasLmkKillOccurred());
    109         LmkKillOccurred atom = data.get(0).getAtom().getLmkKillOccurred();
    110         assertEquals(getUid(), atom.getUid());
    111         assertEquals(DEVICE_SIDE_TEST_PACKAGE, atom.getProcessName());
    112         assertTrue(500 <= atom.getOomAdjScore());
    113     }
    114 
    115     public void testAppCrashOccurred() throws Exception {
    116         if (statsdDisabled()) {
    117             return;
    118         }
    119         final int atomTag = Atom.APP_CRASH_OCCURRED_FIELD_NUMBER;
    120         createAndUploadConfig(atomTag, false);
    121         Thread.sleep(WAIT_TIME_SHORT);
    122 
    123         runActivity("StatsdCtsForegroundActivity", "action", "action.crash");
    124 
    125         Thread.sleep(WAIT_TIME_SHORT);
    126         // Sorted list of events in order in which they occurred.
    127         List<EventMetricData> data = getEventMetricDataList();
    128 
    129         AppCrashOccurred atom = data.get(0).getAtom().getAppCrashOccurred();
    130         assertEquals("crash", atom.getEventType());
    131         assertEquals(AppCrashOccurred.InstantApp.FALSE_VALUE, atom.getIsInstantApp().getNumber());
    132         assertEquals(AppCrashOccurred.ForegroundState.FOREGROUND_VALUE,
    133                 atom.getForegroundState().getNumber());
    134         assertEquals("com.android.server.cts.device.statsd", atom.getPackageName());
    135     }
    136 
    137     public void testAppStartOccurred() throws Exception {
    138         if (statsdDisabled()) {
    139             return;
    140         }
    141         final int atomTag = Atom.APP_START_OCCURRED_FIELD_NUMBER;
    142 
    143         createAndUploadConfig(atomTag, false);
    144         Thread.sleep(WAIT_TIME_SHORT);
    145 
    146         runActivity("StatsdCtsForegroundActivity", "action", "action.sleep_top");
    147 
    148         // Sorted list of events in order in which they occurred.
    149         List<EventMetricData> data = getEventMetricDataList();
    150 
    151         AppStartOccurred atom = data.get(0).getAtom().getAppStartOccurred();
    152         assertEquals("com.android.server.cts.device.statsd", atom.getPkgName());
    153         assertEquals("com.android.server.cts.device.statsd.StatsdCtsForegroundActivity",
    154                 atom.getActivityName());
    155         assertFalse(atom.getIsInstantApp());
    156         assertTrue(atom.getActivityStartMillis() > 0);
    157         assertTrue(atom.getTransitionDelayMillis() > 0);
    158     }
    159 
    160     public void testAudioState() throws Exception {
    161         if (statsdDisabled()) {
    162             return;
    163         }
    164         if (!hasFeature(FEATURE_AUDIO_OUTPUT, true)) return;
    165 
    166         final int atomTag = Atom.AUDIO_STATE_CHANGED_FIELD_NUMBER;
    167         final String name = "testAudioState";
    168 
    169         Set<Integer> onState = new HashSet<>(
    170                 Arrays.asList(AudioStateChanged.State.ON_VALUE));
    171         Set<Integer> offState = new HashSet<>(
    172                 Arrays.asList(AudioStateChanged.State.OFF_VALUE));
    173 
    174         // Add state sets to the list in order.
    175         List<Set<Integer>> stateSet = Arrays.asList(onState, offState);
    176 
    177         createAndUploadConfig(atomTag, true);  // True: uses attribution.
    178         Thread.sleep(WAIT_TIME_SHORT);
    179 
    180         runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".AtomTests", name);
    181 
    182         Thread.sleep(WAIT_TIME_SHORT);
    183         // Sorted list of events in order in which they occurred.
    184         List<EventMetricData> data = getEventMetricDataList();
    185 
    186         // AudioStateChanged timestamp is fuzzed to 5min buckets
    187         assertStatesOccurred(stateSet, data, 0,
    188                 atom -> atom.getAudioStateChanged().getState().getNumber());
    189     }
    190 
    191     public void testBleScan() throws Exception {
    192         if (statsdDisabled()) {
    193             return;
    194         }
    195         if (!hasFeature(FEATURE_BLUETOOTH_LE, true)) return;
    196 
    197         final int atom = Atom.BLE_SCAN_STATE_CHANGED_FIELD_NUMBER;
    198         final int field = BleScanStateChanged.STATE_FIELD_NUMBER;
    199         final int stateOn = BleScanStateChanged.State.ON_VALUE;
    200         final int stateOff = BleScanStateChanged.State.OFF_VALUE;
    201         final int minTimeDiffMillis = 1_500;
    202         final int maxTimeDiffMillis = 3_000;
    203 
    204         List<EventMetricData> data = doDeviceMethodOnOff("testBleScanUnoptimized", atom, field,
    205                 stateOn, stateOff, minTimeDiffMillis, maxTimeDiffMillis, true);
    206 
    207         BleScanStateChanged a0 = data.get(0).getAtom().getBleScanStateChanged();
    208         BleScanStateChanged a1 = data.get(1).getAtom().getBleScanStateChanged();
    209         assertTrue(a0.getState().getNumber() == stateOn);
    210         assertTrue(a1.getState().getNumber() == stateOff);
    211     }
    212 
    213     public void testBleUnoptimizedScan() throws Exception {
    214         if (statsdDisabled()) {
    215             return;
    216         }
    217         if (!hasFeature(FEATURE_BLUETOOTH_LE, true)) return;
    218 
    219         final int atom = Atom.BLE_SCAN_STATE_CHANGED_FIELD_NUMBER;
    220         final int field = BleScanStateChanged.STATE_FIELD_NUMBER;
    221         final int stateOn = BleScanStateChanged.State.ON_VALUE;
    222         final int stateOff = BleScanStateChanged.State.OFF_VALUE;
    223         final int minTimeDiffMillis = 1_500;
    224         final int maxTimeDiffMillis = 3_000;
    225 
    226         List<EventMetricData> data = doDeviceMethodOnOff("testBleScanUnoptimized", atom, field,
    227                 stateOn, stateOff, minTimeDiffMillis, maxTimeDiffMillis, true);
    228 
    229         BleScanStateChanged a0 = data.get(0).getAtom().getBleScanStateChanged();
    230         assertTrue(a0.getState().getNumber() == stateOn);
    231         assertFalse(a0.getIsFiltered());
    232         assertFalse(a0.getIsFirstMatch());
    233         assertFalse(a0.getIsOpportunistic());
    234         BleScanStateChanged a1 = data.get(1).getAtom().getBleScanStateChanged();
    235         assertTrue(a1.getState().getNumber() == stateOff);
    236         assertFalse(a1.getIsFiltered());
    237         assertFalse(a1.getIsFirstMatch());
    238         assertFalse(a1.getIsOpportunistic());
    239 
    240 
    241         // Now repeat the test for opportunistic scanning and make sure it is reported correctly.
    242         data = doDeviceMethodOnOff("testBleScanOpportunistic", atom, field,
    243                 stateOn, stateOff, minTimeDiffMillis, maxTimeDiffMillis, true);
    244 
    245         a0 = data.get(0).getAtom().getBleScanStateChanged();
    246         assertTrue(a0.getState().getNumber() == stateOn);
    247         assertFalse(a0.getIsFiltered());
    248         assertFalse(a0.getIsFirstMatch());
    249         assertTrue(a0.getIsOpportunistic());  // This scan is opportunistic.
    250         a1 = data.get(1).getAtom().getBleScanStateChanged();
    251         assertTrue(a1.getState().getNumber() == stateOff);
    252         assertFalse(a1.getIsFiltered());
    253         assertFalse(a1.getIsFirstMatch());
    254         assertTrue(a1.getIsOpportunistic());
    255     }
    256 
    257     public void testBleScanResult() throws Exception {
    258         if (statsdDisabled()) {
    259             return;
    260         }
    261         if (!hasFeature(FEATURE_BLUETOOTH_LE, true)) return;
    262 
    263         final int atom = Atom.BLE_SCAN_RESULT_RECEIVED_FIELD_NUMBER;
    264         final int field = BleScanResultReceived.NUM_RESULTS_FIELD_NUMBER;
    265 
    266         StatsdConfig.Builder conf = createConfigBuilder();
    267         addAtomEvent(conf, atom, createFvm(field).setGteInt(0));
    268         List<EventMetricData> data = doDeviceMethod("testBleScanResult", conf);
    269 
    270         assertTrue(data.size() >= 1);
    271         BleScanResultReceived a0 = data.get(0).getAtom().getBleScanResultReceived();
    272         assertTrue(a0.getNumResults() >= 1);
    273     }
    274 
    275     public void testHiddenApiUsed() throws Exception {
    276         if (statsdDisabled()) {
    277             return;
    278         }
    279 
    280         String oldRate = getDevice().executeShellCommand(
    281                 "device_config get app_compat hidden_api_access_statslog_sampling_rate").trim();
    282 
    283         getDevice().executeShellCommand(
    284                 "device_config put app_compat hidden_api_access_statslog_sampling_rate 65536");
    285         try {
    286             final int atomTag = Atom.HIDDEN_API_USED_FIELD_NUMBER;
    287 
    288             createAndUploadConfig(atomTag, false);
    289 
    290             runActivity("HiddenApiUsedActivity", null, null);
    291 
    292 
    293             List<EventMetricData> data = getEventMetricDataList();
    294             assertTrue(data.size() == 1);
    295 
    296             HiddenApiUsed atom = data.get(0).getAtom().getHiddenApiUsed();
    297 
    298             int uid = getUid();
    299             assertEquals(uid, atom.getUid());
    300             assertFalse(atom.getAccessDenied());
    301             assertEquals("Landroid/app/Activity;->mWindow:Landroid/view/Window;",
    302                     atom.getSignature());
    303         } finally {
    304             if (!oldRate.equals("null")) {
    305                 getDevice().executeShellCommand(
    306                         "device_config put app_compat hidden_api_access_statslog_sampling_rate "
    307                         + oldRate);
    308             } else {
    309                 getDevice().executeShellCommand(
    310                         "device_config delete hidden_api_access_statslog_sampling_rate");
    311             }
    312         }
    313     }
    314 
    315     public void testCameraState() throws Exception {
    316         if (statsdDisabled()) {
    317             return;
    318         }
    319         if (!hasFeature(FEATURE_CAMERA, true) && !hasFeature(FEATURE_CAMERA_FRONT, true)) return;
    320 
    321         final int atomTag = Atom.CAMERA_STATE_CHANGED_FIELD_NUMBER;
    322         Set<Integer> cameraOn = new HashSet<>(Arrays.asList(CameraStateChanged.State.ON_VALUE));
    323         Set<Integer> cameraOff = new HashSet<>(Arrays.asList(CameraStateChanged.State.OFF_VALUE));
    324 
    325         // Add state sets to the list in order.
    326         List<Set<Integer>> stateSet = Arrays.asList(cameraOn, cameraOff);
    327 
    328         createAndUploadConfig(atomTag, true);  // True: uses attribution.
    329         runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".AtomTests", "testCameraState");
    330 
    331         // Sorted list of events in order in which they occurred.
    332         List<EventMetricData> data = getEventMetricDataList();
    333 
    334         // Assert that the events happened in the expected order.
    335         assertStatesOccurred(stateSet, data, WAIT_TIME_LONG,
    336                 atom -> atom.getCameraStateChanged().getState().getNumber());
    337     }
    338 
    339     public void testCpuTimePerUid() throws Exception {
    340         if (statsdDisabled()) {
    341             return;
    342         }
    343         if (!hasFeature(FEATURE_WATCH, false)) return;
    344         StatsdConfig.Builder config = getPulledConfig();
    345         addGaugeAtomWithDimensions(config, Atom.CPU_TIME_PER_UID_FIELD_NUMBER, null);
    346 
    347         uploadConfig(config);
    348 
    349         runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".AtomTests", "testSimpleCpu");
    350 
    351         Thread.sleep(WAIT_TIME_SHORT);
    352         setAppBreadcrumbPredicate();
    353         Thread.sleep(WAIT_TIME_LONG);
    354 
    355         List<Atom> atomList = getGaugeMetricDataList();
    356 
    357         // TODO: We don't have atom matching on gauge yet. Let's refactor this after that feature is
    358         // implemented.
    359         boolean found = false;
    360         int uid = getUid();
    361         for (Atom atom : atomList) {
    362             if (atom.getCpuTimePerUid().getUid() == uid) {
    363                 found = true;
    364                 assertTrue(atom.getCpuTimePerUid().getUserTimeMicros() > 0);
    365                 assertTrue(atom.getCpuTimePerUid().getSysTimeMicros() > 0);
    366             }
    367         }
    368         assertTrue("found uid " + uid, found);
    369     }
    370 
    371     @RestrictedBuildTest
    372     public void testCpuActiveTime() throws Exception {
    373         if (statsdDisabled()) {
    374             return;
    375         }
    376         if (!hasFeature(FEATURE_WATCH, false)) return;
    377         StatsdConfig.Builder config = getPulledConfig();
    378         FieldMatcher.Builder dimension = FieldMatcher.newBuilder()
    379                 .setField(Atom.CPU_ACTIVE_TIME_FIELD_NUMBER)
    380                 .addChild(FieldMatcher.newBuilder()
    381                         .setField(CpuActiveTime.UID_FIELD_NUMBER));
    382         addGaugeAtomWithDimensions(config, Atom.CPU_ACTIVE_TIME_FIELD_NUMBER, dimension);
    383 
    384         uploadConfig(config);
    385 
    386         Thread.sleep(WAIT_TIME_LONG);
    387         runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".AtomTests", "testSimpleCpu");
    388         Thread.sleep(WAIT_TIME_SHORT);
    389         setAppBreadcrumbPredicate();
    390         Thread.sleep(WAIT_TIME_LONG);
    391 
    392         List<Atom> atomList = getGaugeMetricDataList();
    393 
    394         boolean found = false;
    395         int uid = getUid();
    396         long timeSpent = 0;
    397         for (Atom atom : atomList) {
    398             if (atom.getCpuActiveTime().getUid() == uid) {
    399                 found = true;
    400                 timeSpent += atom.getCpuActiveTime().getTimeMillis();
    401             }
    402         }
    403         assertTrue(timeSpent > 0);
    404         assertTrue("found uid " + uid, found);
    405     }
    406 
    407     public void testDeviceCalculatedPowerUse() throws Exception {
    408         if (statsdDisabled()) {
    409             return;
    410         }
    411         if (!hasFeature(FEATURE_LEANBACK_ONLY, false)) return;
    412 
    413         StatsdConfig.Builder config = getPulledConfig();
    414         addGaugeAtomWithDimensions(config, Atom.DEVICE_CALCULATED_POWER_USE_FIELD_NUMBER, null);
    415         uploadConfig(config);
    416         unplugDevice();
    417 
    418         Thread.sleep(WAIT_TIME_LONG);
    419         runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".AtomTests", "testSimpleCpu");
    420         Thread.sleep(WAIT_TIME_SHORT);
    421         setAppBreadcrumbPredicate();
    422         Thread.sleep(WAIT_TIME_LONG);
    423 
    424         Atom atom = getGaugeMetricDataList().get(0);
    425         assertTrue(atom.getDeviceCalculatedPowerUse().getComputedPowerNanoAmpSecs() > 0);
    426     }
    427 
    428 
    429     public void testDeviceCalculatedPowerBlameUid() throws Exception {
    430         if (statsdDisabled()) {
    431             return;
    432         }
    433         if (!hasFeature(FEATURE_LEANBACK_ONLY, false)) return;
    434 
    435         StatsdConfig.Builder config = getPulledConfig();
    436         addGaugeAtomWithDimensions(config,
    437                 Atom.DEVICE_CALCULATED_POWER_BLAME_UID_FIELD_NUMBER, null);
    438         uploadConfig(config);
    439         unplugDevice();
    440 
    441         Thread.sleep(WAIT_TIME_LONG);
    442         runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".AtomTests", "testSimpleCpu");
    443         Thread.sleep(WAIT_TIME_SHORT);
    444         setAppBreadcrumbPredicate();
    445         Thread.sleep(WAIT_TIME_LONG);
    446 
    447         List<Atom> atomList = getGaugeMetricDataList();
    448         boolean uidFound = false;
    449         int uid = getUid();
    450         long uidPower = 0;
    451         for (Atom atom : atomList) {
    452             DeviceCalculatedPowerBlameUid item = atom.getDeviceCalculatedPowerBlameUid();
    453                 if (item.getUid() == uid) {
    454                 assertFalse("Found multiple power values for uid " + uid, uidFound);
    455                 uidFound = true;
    456                 uidPower = item.getPowerNanoAmpSecs();
    457             }
    458         }
    459         assertTrue("No power value for uid " + uid, uidFound);
    460         assertTrue("Non-positive power value for uid " + uid, uidPower > 0);
    461     }
    462 
    463     public void testDavey() throws Exception {
    464         if (statsdDisabled()) {
    465             return;
    466         }
    467         if (!DAVEY_ENABLED ) return;
    468         long MAX_DURATION = 2000;
    469         long MIN_DURATION = 750;
    470         final int atomTag = Atom.DAVEY_OCCURRED_FIELD_NUMBER;
    471         createAndUploadConfig(atomTag, false); // UID is logged without attribution node
    472 
    473         runActivity("DaveyActivity", null, null);
    474 
    475         List<EventMetricData> data = getEventMetricDataList();
    476         assertTrue(data.size() == 1);
    477         long duration = data.get(0).getAtom().getDaveyOccurred().getJankDurationMillis();
    478         assertTrue("Jank duration of " + duration + "ms was less than " + MIN_DURATION + "ms",
    479                 duration >= MIN_DURATION);
    480         assertTrue("Jank duration of " + duration + "ms was longer than " + MAX_DURATION + "ms",
    481                 duration <= MAX_DURATION);
    482     }
    483 
    484     public void testFlashlightState() throws Exception {
    485         if (statsdDisabled()) {
    486             return;
    487         }
    488         if (!hasFeature(FEATURE_CAMERA_FLASH, true)) return;
    489 
    490         final int atomTag = Atom.FLASHLIGHT_STATE_CHANGED_FIELD_NUMBER;
    491         final String name = "testFlashlight";
    492 
    493         Set<Integer> flashlightOn = new HashSet<>(
    494             Arrays.asList(FlashlightStateChanged.State.ON_VALUE));
    495         Set<Integer> flashlightOff = new HashSet<>(
    496             Arrays.asList(FlashlightStateChanged.State.OFF_VALUE));
    497 
    498         // Add state sets to the list in order.
    499         List<Set<Integer>> stateSet = Arrays.asList(flashlightOn, flashlightOff);
    500 
    501         createAndUploadConfig(atomTag, true);  // True: uses attribution.
    502         Thread.sleep(WAIT_TIME_SHORT);
    503 
    504         runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".AtomTests", name);
    505 
    506         // Sorted list of events in order in which they occurred.
    507         List<EventMetricData> data = getEventMetricDataList();
    508 
    509         // Assert that the events happened in the expected order.
    510         assertStatesOccurred(stateSet, data, WAIT_TIME_SHORT,
    511                 atom -> atom.getFlashlightStateChanged().getState().getNumber());
    512     }
    513 
    514     public void testForegroundServiceState() throws Exception {
    515         if (statsdDisabled()) {
    516             return;
    517         }
    518         final int atomTag = Atom.FOREGROUND_SERVICE_STATE_CHANGED_FIELD_NUMBER;
    519         final String name = "testForegroundService";
    520 
    521         Set<Integer> enterForeground = new HashSet<>(
    522                 Arrays.asList(ForegroundServiceStateChanged.State.ENTER_VALUE));
    523         Set<Integer> exitForeground = new HashSet<>(
    524                 Arrays.asList(ForegroundServiceStateChanged.State.EXIT_VALUE));
    525 
    526         // Add state sets to the list in order.
    527         List<Set<Integer>> stateSet = Arrays.asList(enterForeground, exitForeground);
    528 
    529         createAndUploadConfig(atomTag, false);
    530         Thread.sleep(WAIT_TIME_SHORT);
    531 
    532         runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".AtomTests", name);
    533 
    534         // Sorted list of events in order in which they occurred.
    535         List<EventMetricData> data = getEventMetricDataList();
    536 
    537         // Assert that the events happened in the expected order.
    538         assertStatesOccurred(stateSet, data, WAIT_TIME_SHORT,
    539                 atom -> atom.getForegroundServiceStateChanged().getState().getNumber());
    540     }
    541 
    542     public void testGpsScan() throws Exception {
    543         if (statsdDisabled()) {
    544             return;
    545         }
    546         if (!hasFeature(FEATURE_LOCATION_GPS, true)) return;
    547         // Whitelist this app against background location request throttling
    548         String origWhitelist = getDevice().executeShellCommand(
    549                 "settings get global location_background_throttle_package_whitelist").trim();
    550         getDevice().executeShellCommand(String.format(
    551                 "settings put global location_background_throttle_package_whitelist %s",
    552                 DEVICE_SIDE_TEST_PACKAGE));
    553 
    554         try {
    555             final int atom = Atom.GPS_SCAN_STATE_CHANGED_FIELD_NUMBER;
    556             final int key = GpsScanStateChanged.STATE_FIELD_NUMBER;
    557             final int stateOn = GpsScanStateChanged.State.ON_VALUE;
    558             final int stateOff = GpsScanStateChanged.State.OFF_VALUE;
    559             final int minTimeDiffMillis = 500;
    560             final int maxTimeDiffMillis = 60_000;
    561 
    562             List<EventMetricData> data = doDeviceMethodOnOff("testGpsScan", atom, key,
    563                     stateOn, stateOff, minTimeDiffMillis, maxTimeDiffMillis, true);
    564 
    565             GpsScanStateChanged a0 = data.get(0).getAtom().getGpsScanStateChanged();
    566             GpsScanStateChanged a1 = data.get(1).getAtom().getGpsScanStateChanged();
    567             assertTrue(a0.getState().getNumber() == stateOn);
    568             assertTrue(a1.getState().getNumber() == stateOff);
    569         } finally {
    570             if ("null".equals(origWhitelist) || "".equals(origWhitelist)) {
    571                 getDevice().executeShellCommand(
    572                         "settings delete global location_background_throttle_package_whitelist");
    573             } else {
    574                 getDevice().executeShellCommand(String.format(
    575                         "settings put global location_background_throttle_package_whitelist %s",
    576                         origWhitelist));
    577             }
    578         }
    579     }
    580 
    581     public void testMediaCodecActivity() throws Exception {
    582         if (statsdDisabled()) {
    583             return;
    584         }
    585         if (!hasFeature(FEATURE_WATCH, false)) return;
    586         final int atomTag = Atom.MEDIA_CODEC_STATE_CHANGED_FIELD_NUMBER;
    587 
    588         Set<Integer> onState = new HashSet<>(
    589                 Arrays.asList(MediaCodecStateChanged.State.ON_VALUE));
    590         Set<Integer> offState = new HashSet<>(
    591                 Arrays.asList(MediaCodecStateChanged.State.OFF_VALUE));
    592 
    593         // Add state sets to the list in order.
    594         List<Set<Integer>> stateSet = Arrays.asList(onState, offState);
    595 
    596         createAndUploadConfig(atomTag, true);  // True: uses attribution.
    597         Thread.sleep(WAIT_TIME_SHORT);
    598 
    599         runActivity("VideoPlayerActivity", "action", "action.play_video");
    600 
    601         // Sorted list of events in order in which they occurred.
    602         List<EventMetricData> data = getEventMetricDataList();
    603 
    604         // Assert that the events happened in the expected order.
    605         assertStatesOccurred(stateSet, data, WAIT_TIME_LONG,
    606                 atom -> atom.getMediaCodecStateChanged().getState().getNumber());
    607     }
    608 
    609     public void testOverlayState() throws Exception {
    610         if (statsdDisabled()) {
    611             return;
    612         }
    613         if (!hasFeature(FEATURE_WATCH, false)) return;
    614         final int atomTag = Atom.OVERLAY_STATE_CHANGED_FIELD_NUMBER;
    615 
    616         Set<Integer> entered = new HashSet<>(
    617                 Arrays.asList(OverlayStateChanged.State.ENTERED_VALUE));
    618         Set<Integer> exited = new HashSet<>(
    619                 Arrays.asList(OverlayStateChanged.State.EXITED_VALUE));
    620 
    621         // Add state sets to the list in order.
    622         List<Set<Integer>> stateSet = Arrays.asList(entered, exited);
    623 
    624         createAndUploadConfig(atomTag, false);
    625 
    626         runActivity("StatsdCtsForegroundActivity", "action", "action.show_application_overlay",
    627                 3_000);
    628 
    629         // Sorted list of events in order in which they occurred.
    630         List<EventMetricData> data = getEventMetricDataList();
    631 
    632         // Assert that the events happened in the expected order.
    633         // The overlay box should appear about 2sec after the app start
    634         assertStatesOccurred(stateSet, data, 0,
    635                 atom -> atom.getOverlayStateChanged().getState().getNumber());
    636     }
    637 
    638     public void testPictureInPictureState() throws Exception {
    639         if (statsdDisabled()) {
    640             return;
    641         }
    642         String supported = getDevice().executeShellCommand("am supports-multiwindow");
    643         if (!hasFeature(FEATURE_WATCH, false) ||
    644                 !hasFeature(FEATURE_PICTURE_IN_PICTURE, true) ||
    645                 !supported.contains("true")) {
    646             LogUtil.CLog.d("Skipping picture in picture atom test.");
    647             return;
    648         }
    649 
    650         final int atomTag = Atom.PICTURE_IN_PICTURE_STATE_CHANGED_FIELD_NUMBER;
    651 
    652         Set<Integer> entered = new HashSet<>(
    653                 Arrays.asList(PictureInPictureStateChanged.State.ENTERED_VALUE));
    654 
    655         // Add state sets to the list in order.
    656         List<Set<Integer>> stateSet = Arrays.asList(entered);
    657 
    658         createAndUploadConfig(atomTag, false);
    659 
    660         LogUtil.CLog.d("Playing video in Picture-in-Picture mode");
    661         runActivity("VideoPlayerActivity", "action", "action.play_video_picture_in_picture_mode");
    662 
    663         // Sorted list of events in order in which they occurred.
    664         List<EventMetricData> data = getEventMetricDataList();
    665 
    666         // Assert that the events happened in the expected order.
    667         assertStatesOccurred(stateSet, data, WAIT_TIME_LONG,
    668                 atom -> atom.getPictureInPictureStateChanged().getState().getNumber());
    669     }
    670 
    671     public void testScheduledJobState() throws Exception {
    672         if (statsdDisabled()) {
    673             return;
    674         }
    675         String expectedName = "com.android.server.cts.device.statsd/.StatsdJobService";
    676         final int atomTag = Atom.SCHEDULED_JOB_STATE_CHANGED_FIELD_NUMBER;
    677         Set<Integer> jobSchedule = new HashSet<>(
    678                 Arrays.asList(ScheduledJobStateChanged.State.SCHEDULED_VALUE));
    679         Set<Integer> jobOn = new HashSet<>(
    680                 Arrays.asList(ScheduledJobStateChanged.State.STARTED_VALUE));
    681         Set<Integer> jobOff = new HashSet<>(
    682                 Arrays.asList(ScheduledJobStateChanged.State.FINISHED_VALUE));
    683 
    684         // Add state sets to the list in order.
    685         List<Set<Integer>> stateSet = Arrays.asList(jobSchedule, jobOn, jobOff);
    686 
    687         createAndUploadConfig(atomTag, true);  // True: uses attribution.
    688         allowImmediateSyncs();
    689         runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".AtomTests", "testScheduledJob");
    690 
    691         // Sorted list of events in order in which they occurred.
    692         List<EventMetricData> data = getEventMetricDataList();
    693 
    694         assertStatesOccurred(stateSet, data, 0,
    695                 atom -> atom.getScheduledJobStateChanged().getState().getNumber());
    696 
    697         for (EventMetricData e : data) {
    698             assertTrue(e.getAtom().getScheduledJobStateChanged().getJobName().equals(expectedName));
    699         }
    700     }
    701 
    702     //Note: this test does not have uid, but must run on the device
    703     public void testScreenBrightness() throws Exception {
    704         if (statsdDisabled()) {
    705             return;
    706         }
    707         int initialBrightness = getScreenBrightness();
    708         boolean isInitialManual = isScreenBrightnessModeManual();
    709         setScreenBrightnessMode(true);
    710         setScreenBrightness(200);
    711         Thread.sleep(WAIT_TIME_LONG);
    712 
    713         final int atomTag = Atom.SCREEN_BRIGHTNESS_CHANGED_FIELD_NUMBER;
    714 
    715         Set<Integer> screenMin = new HashSet<>(Arrays.asList(47));
    716         Set<Integer> screen100 = new HashSet<>(Arrays.asList(100));
    717         Set<Integer> screen200 = new HashSet<>(Arrays.asList(198));
    718         // Set<Integer> screenMax = new HashSet<>(Arrays.asList(255));
    719 
    720         // Add state sets to the list in order.
    721         List<Set<Integer>> stateSet = Arrays.asList(screenMin, screen100, screen200);
    722 
    723         createAndUploadConfig(atomTag);
    724         Thread.sleep(WAIT_TIME_SHORT);
    725         runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".AtomTests", "testScreenBrightness");
    726 
    727         // Sorted list of events in order in which they occurred.
    728         List<EventMetricData> data = getEventMetricDataList();
    729 
    730         // Restore initial screen brightness
    731         setScreenBrightness(initialBrightness);
    732         setScreenBrightnessMode(isInitialManual);
    733 
    734         popUntilFind(data, screenMin, atom->atom.getScreenBrightnessChanged().getLevel());
    735         popUntilFindFromEnd(data, screen200, atom->atom.getScreenBrightnessChanged().getLevel());
    736         // Assert that the events happened in the expected order.
    737         assertStatesOccurred(stateSet, data, WAIT_TIME_SHORT,
    738             atom -> atom.getScreenBrightnessChanged().getLevel());
    739     }
    740     public void testSyncState() throws Exception {
    741         if (statsdDisabled()) {
    742             return;
    743         }
    744         final int atomTag = Atom.SYNC_STATE_CHANGED_FIELD_NUMBER;
    745         Set<Integer> syncOn = new HashSet<>(Arrays.asList(SyncStateChanged.State.ON_VALUE));
    746         Set<Integer> syncOff = new HashSet<>(Arrays.asList(SyncStateChanged.State.OFF_VALUE));
    747 
    748         // Add state sets to the list in order.
    749         List<Set<Integer>> stateSet = Arrays.asList(syncOn, syncOff, syncOn, syncOff);
    750 
    751         createAndUploadConfig(atomTag, true);
    752         allowImmediateSyncs();
    753         runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".AtomTests", "testSyncState");
    754 
    755         // Sorted list of events in order in which they occurred.
    756         List<EventMetricData> data = getEventMetricDataList();
    757 
    758         // Assert that the events happened in the expected order.
    759         assertStatesOccurred(stateSet, data, WAIT_TIME_SHORT,
    760                 atom -> atom.getSyncStateChanged().getState().getNumber());
    761     }
    762 
    763     public void testVibratorState() throws Exception {
    764         if (statsdDisabled()) {
    765             return;
    766         }
    767         if (!checkDeviceFor("checkVibratorSupported")) return;
    768 
    769         final int atomTag = Atom.VIBRATOR_STATE_CHANGED_FIELD_NUMBER;
    770         final String name = "testVibratorState";
    771 
    772         Set<Integer> onState = new HashSet<>(
    773                 Arrays.asList(VibratorStateChanged.State.ON_VALUE));
    774         Set<Integer> offState = new HashSet<>(
    775                 Arrays.asList(VibratorStateChanged.State.OFF_VALUE));
    776 
    777         // Add state sets to the list in order.
    778         List<Set<Integer>> stateSet = Arrays.asList(onState, offState);
    779 
    780         createAndUploadConfig(atomTag, true);  // True: uses attribution.
    781         Thread.sleep(WAIT_TIME_SHORT);
    782 
    783         runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".AtomTests", name);
    784 
    785         Thread.sleep(WAIT_TIME_LONG);
    786         // Sorted list of events in order in which they occurred.
    787         List<EventMetricData> data = getEventMetricDataList();
    788 
    789         assertStatesOccurred(stateSet, data, 300,
    790                 atom -> atom.getVibratorStateChanged().getState().getNumber());
    791     }
    792 
    793     public void testWakelockState() throws Exception {
    794         if (statsdDisabled()) {
    795             return;
    796         }
    797         final int atomTag = Atom.WAKELOCK_STATE_CHANGED_FIELD_NUMBER;
    798         Set<Integer> wakelockOn = new HashSet<>(Arrays.asList(
    799                 WakelockStateChanged.State.ACQUIRE_VALUE,
    800                 WakelockStateChanged.State.CHANGE_ACQUIRE_VALUE));
    801         Set<Integer> wakelockOff = new HashSet<>(Arrays.asList(
    802                 WakelockStateChanged.State.RELEASE_VALUE,
    803                 WakelockStateChanged.State.CHANGE_RELEASE_VALUE));
    804 
    805         final String EXPECTED_TAG = "StatsdPartialWakelock";
    806         final WakeLockLevelEnum EXPECTED_LEVEL = WakeLockLevelEnum.PARTIAL_WAKE_LOCK;
    807 
    808         // Add state sets to the list in order.
    809         List<Set<Integer>> stateSet = Arrays.asList(wakelockOn, wakelockOff);
    810 
    811         createAndUploadConfig(atomTag, true);  // True: uses attribution.
    812         runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".AtomTests", "testWakelockState");
    813 
    814         // Sorted list of events in order in which they occurred.
    815         List<EventMetricData> data = getEventMetricDataList();
    816 
    817         // Assert that the events happened in the expected order.
    818         assertStatesOccurred(stateSet, data, WAIT_TIME_SHORT,
    819             atom -> atom.getWakelockStateChanged().getState().getNumber());
    820 
    821         for (EventMetricData event: data) {
    822             String tag = event.getAtom().getWakelockStateChanged().getTag();
    823             WakeLockLevelEnum type = event.getAtom().getWakelockStateChanged().getType();
    824             assertTrue("Expected tag: " + EXPECTED_TAG + ", but got tag: " + tag,
    825                     tag.equals(EXPECTED_TAG));
    826             assertTrue("Expected wakelock type: " + EXPECTED_LEVEL  + ", but got level: " + type,
    827                     type == EXPECTED_LEVEL);
    828         }
    829     }
    830 
    831     public void testWakeupAlarm() throws Exception {
    832         if (statsdDisabled()) {
    833             return;
    834         }
    835         // For automotive, all wakeup alarm becomes normal alarm. So this
    836         // test does not work.
    837         if (!hasFeature(FEATURE_AUTOMOTIVE, false)) return;
    838         final int atomTag = Atom.WAKEUP_ALARM_OCCURRED_FIELD_NUMBER;
    839 
    840         StatsdConfig.Builder config = createConfigBuilder();
    841         addAtomEvent(config, atomTag, true);  // True: uses attribution.
    842 
    843         List<EventMetricData> data = doDeviceMethod("testWakeupAlarm", config);
    844         assertTrue(data.size() >= 1);
    845         for (int i = 0; i < data.size(); i++) {
    846             WakeupAlarmOccurred wao = data.get(i).getAtom().getWakeupAlarmOccurred();
    847             assertEquals("*walarm*:android.cts.statsd.testWakeupAlarm", wao.getTag());
    848             assertEquals(DEVICE_SIDE_TEST_PACKAGE, wao.getPackageName());
    849         }
    850     }
    851 
    852     public void testWifiLockHighPerf() throws Exception {
    853         if (statsdDisabled()) {
    854             return;
    855         }
    856         if (!hasFeature(FEATURE_WIFI, true)) return;
    857         if (!hasFeature(FEATURE_PC, false)) return;
    858 
    859         final int atomTag = Atom.WIFI_LOCK_STATE_CHANGED_FIELD_NUMBER;
    860         Set<Integer> lockOn = new HashSet<>(Arrays.asList(WifiLockStateChanged.State.ON_VALUE));
    861         Set<Integer> lockOff = new HashSet<>(Arrays.asList(WifiLockStateChanged.State.OFF_VALUE));
    862 
    863         // Add state sets to the list in order.
    864         List<Set<Integer>> stateSet = Arrays.asList(lockOn, lockOff);
    865 
    866         createAndUploadConfig(atomTag, true);  // True: uses attribution.
    867         runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".AtomTests", "testWifiLockHighPerf");
    868 
    869         // Sorted list of events in order in which they occurred.
    870         List<EventMetricData> data = getEventMetricDataList();
    871 
    872         // Assert that the events happened in the expected order.
    873         assertStatesOccurred(stateSet, data, WAIT_TIME_SHORT,
    874                 atom -> atom.getWifiLockStateChanged().getState().getNumber());
    875 
    876         for (EventMetricData event : data) {
    877             assertEquals(WifiModeEnum.WIFI_MODE_FULL_HIGH_PERF,
    878                          event.getAtom().getWifiLockStateChanged().getMode());
    879         }
    880     }
    881 
    882     public void testWifiLockLowLatency() throws Exception {
    883         if (statsdDisabled()) {
    884             return;
    885         }
    886         if (!hasFeature(FEATURE_WIFI, true)) return;
    887         if (!hasFeature(FEATURE_PC, false)) return;
    888 
    889         final int atomTag = Atom.WIFI_LOCK_STATE_CHANGED_FIELD_NUMBER;
    890         Set<Integer> lockOn = new HashSet<>(Arrays.asList(WifiLockStateChanged.State.ON_VALUE));
    891         Set<Integer> lockOff = new HashSet<>(Arrays.asList(WifiLockStateChanged.State.OFF_VALUE));
    892 
    893         // Add state sets to the list in order.
    894         List<Set<Integer>> stateSet = Arrays.asList(lockOn, lockOff);
    895 
    896         createAndUploadConfig(atomTag, true);  // True: uses attribution.
    897         runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".AtomTests", "testWifiLockLowLatency");
    898 
    899         // Sorted list of events in order in which they occurred.
    900         List<EventMetricData> data = getEventMetricDataList();
    901 
    902         // Assert that the events happened in the expected order.
    903         assertStatesOccurred(stateSet, data, WAIT_TIME_SHORT,
    904                 atom -> atom.getWifiLockStateChanged().getState().getNumber());
    905 
    906         for (EventMetricData event : data) {
    907             assertEquals(WifiModeEnum.WIFI_MODE_FULL_LOW_LATENCY,
    908                          event.getAtom().getWifiLockStateChanged().getMode());
    909         }
    910     }
    911 
    912     public void testWifiMulticastLock() throws Exception {
    913         if (statsdDisabled()) {
    914             return;
    915         }
    916         if (!hasFeature(FEATURE_WIFI, true)) return;
    917         if (!hasFeature(FEATURE_PC, false)) return;
    918 
    919         final int atomTag = Atom.WIFI_MULTICAST_LOCK_STATE_CHANGED_FIELD_NUMBER;
    920         Set<Integer> lockOn = new HashSet<>(
    921                 Arrays.asList(WifiMulticastLockStateChanged.State.ON_VALUE));
    922         Set<Integer> lockOff = new HashSet<>(
    923                 Arrays.asList(WifiMulticastLockStateChanged.State.OFF_VALUE));
    924 
    925         final String EXPECTED_TAG = "StatsdCTSMulticastLock";
    926 
    927         // Add state sets to the list in order.
    928         List<Set<Integer>> stateSet = Arrays.asList(lockOn, lockOff);
    929 
    930         createAndUploadConfig(atomTag, true);
    931         runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".AtomTests", "testWifiMulticastLock");
    932 
    933         // Sorted list of events in order in which they occurred.
    934         List<EventMetricData> data = getEventMetricDataList();
    935 
    936         // Assert that the events happened in the expected order.
    937         assertStatesOccurred(stateSet, data, WAIT_TIME_SHORT,
    938                 atom -> atom.getWifiMulticastLockStateChanged().getState().getNumber());
    939 
    940         for (EventMetricData event: data) {
    941             String tag = event.getAtom().getWifiMulticastLockStateChanged().getTag();
    942             assertEquals("Wrong tag.", EXPECTED_TAG, tag);
    943         }
    944     }
    945 
    946     public void testWifiScan() throws Exception {
    947         if (statsdDisabled()) {
    948             return;
    949         }
    950         if (!hasFeature(FEATURE_WIFI, true)) return;
    951 
    952         final int atom = Atom.WIFI_SCAN_STATE_CHANGED_FIELD_NUMBER;
    953         final int key = WifiScanStateChanged.STATE_FIELD_NUMBER;
    954         final int stateOn = WifiScanStateChanged.State.ON_VALUE;
    955         final int stateOff = WifiScanStateChanged.State.OFF_VALUE;
    956         final int minTimeDiffMillis = 250;
    957         final int maxTimeDiffMillis = 60_000;
    958         final boolean demandExactlyTwo = false; // Two scans are performed, so up to 4 atoms logged.
    959 
    960         List<EventMetricData> data = doDeviceMethodOnOff("testWifiScan", atom, key,
    961                 stateOn, stateOff, minTimeDiffMillis, maxTimeDiffMillis, demandExactlyTwo);
    962 
    963         assertTrue(data.size() >= 2);
    964         assertTrue(data.size() <= 4);
    965         WifiScanStateChanged a0 = data.get(0).getAtom().getWifiScanStateChanged();
    966         WifiScanStateChanged a1 = data.get(1).getAtom().getWifiScanStateChanged();
    967         assertTrue(a0.getState().getNumber() == stateOn);
    968         assertTrue(a1.getState().getNumber() == stateOff);
    969     }
    970 
    971     public void testBinderStats() throws Exception {
    972         if (statsdDisabled()) {
    973             return;
    974         }
    975         try {
    976             unplugDevice();
    977             Thread.sleep(WAIT_TIME_SHORT);
    978             enableBinderStats();
    979             binderStatsNoSampling();
    980             resetBinderStats();
    981             StatsdConfig.Builder config = getPulledConfig();
    982             addGaugeAtomWithDimensions(config, Atom.BINDER_CALLS_FIELD_NUMBER, null);
    983 
    984             uploadConfig(config);
    985             Thread.sleep(WAIT_TIME_SHORT);
    986 
    987             runActivity("StatsdCtsForegroundActivity", "action", "action.show_notification",3_000);
    988 
    989             setAppBreadcrumbPredicate();
    990             Thread.sleep(WAIT_TIME_SHORT);
    991 
    992             boolean found = false;
    993             int uid = getUid();
    994             List<Atom> atomList = getGaugeMetricDataList();
    995             for (Atom atom : atomList) {
    996                 BinderCalls calls = atom.getBinderCalls();
    997                 boolean classMatches = calls.getServiceClassName().contains(
    998                         "com.android.server.notification.NotificationManagerService");
    999                 boolean methodMatches = calls.getServiceMethodName()
   1000                         .equals("createNotificationChannels");
   1001 
   1002                 if (calls.getUid() == uid && classMatches && methodMatches) {
   1003                     found = true;
   1004                     assertTrue("Call count should not be negative or equal to 0.",
   1005                             calls.getRecordedCallCount() > 0);
   1006                     assertTrue("Call count should not be negative or equal to 0.",
   1007                             calls.getCallCount() > 0);
   1008                     assertTrue("Wrong latency",
   1009                             calls.getRecordedTotalLatencyMicros() > 0
   1010                             && calls.getRecordedTotalLatencyMicros() < 1000000);
   1011                     assertTrue("Wrong cpu usage",
   1012                             calls.getRecordedTotalCpuMicros() > 0
   1013                             && calls.getRecordedTotalCpuMicros() < 1000000);
   1014                 }
   1015             }
   1016 
   1017             assertTrue("Did not find a matching atom for uid " + uid, found);
   1018 
   1019         } finally {
   1020             disableBinderStats();
   1021             plugInAc();
   1022         }
   1023     }
   1024 
   1025     public void testLooperStats() throws Exception {
   1026         if (statsdDisabled()) {
   1027             return;
   1028         }
   1029         try {
   1030             unplugDevice();
   1031             setUpLooperStats();
   1032             StatsdConfig.Builder config = getPulledConfig();
   1033             addGaugeAtomWithDimensions(config, Atom.LOOPER_STATS_FIELD_NUMBER, null);
   1034             uploadConfig(config);
   1035             Thread.sleep(WAIT_TIME_SHORT);
   1036 
   1037             runActivity("StatsdCtsForegroundActivity", "action", "action.show_notification", 3_000);
   1038 
   1039             setAppBreadcrumbPredicate();
   1040             Thread.sleep(WAIT_TIME_SHORT);
   1041 
   1042             List<Atom> atomList = getGaugeMetricDataList();
   1043 
   1044             boolean found = false;
   1045             int uid = getUid();
   1046             for (Atom atom : atomList) {
   1047                 LooperStats stats = atom.getLooperStats();
   1048                 String notificationServiceFullName =
   1049                         "com.android.server.notification.NotificationManagerService";
   1050                 boolean handlerMatches =
   1051                         stats.getHandlerClassName().equals(
   1052                                 notificationServiceFullName + "$WorkerHandler");
   1053                 boolean messageMatches =
   1054                         stats.getMessageName().equals(
   1055                                 notificationServiceFullName + "$EnqueueNotificationRunnable");
   1056                 if (atom.getLooperStats().getUid() == uid && handlerMatches && messageMatches) {
   1057                     found = true;
   1058                     assertTrue(stats.getMessageCount() > 0);
   1059                     assertTrue("Message count should be non-negative.",
   1060                             stats.getMessageCount() > 0);
   1061                     assertTrue("Recorded message count should be non-negative.",
   1062                             stats.getRecordedMessageCount() > 0);
   1063                     assertTrue("Wrong latency",
   1064                             stats.getRecordedTotalLatencyMicros() > 0
   1065                                     && stats.getRecordedTotalLatencyMicros() < 1000000);
   1066                     assertTrue("Wrong cpu usage",
   1067                             stats.getRecordedTotalCpuMicros() > 0
   1068                                     && stats.getRecordedTotalCpuMicros() < 1000000);
   1069                     assertTrue("Wrong max latency",
   1070                             stats.getRecordedMaxLatencyMicros() > 0
   1071                                     && stats.getRecordedMaxLatencyMicros() < 1000000);
   1072                     assertTrue("Wrong max cpu usage",
   1073                             stats.getRecordedMaxCpuMicros() > 0
   1074                                     && stats.getRecordedMaxCpuMicros() < 1000000);
   1075                     assertTrue("Recorded delay message count should be non-negative.",
   1076                             stats.getRecordedDelayMessageCount() > 0);
   1077                     assertTrue("Wrong delay",
   1078                             stats.getRecordedTotalDelayMillis() >= 0
   1079                                     && stats.getRecordedTotalDelayMillis() < 5000);
   1080                     assertTrue("Wrong max delay",
   1081                             stats.getRecordedMaxDelayMillis() >= 0
   1082                                     && stats.getRecordedMaxDelayMillis() < 5000);
   1083                 }
   1084             }
   1085             assertTrue("Did not find a matching atom for uid " + uid, found);
   1086         } finally {
   1087             cleanUpLooperStats();
   1088             plugInAc();
   1089         }
   1090     }
   1091 
   1092     public void testProcessMemoryState() throws Exception {
   1093         if (statsdDisabled()) {
   1094             return;
   1095         }
   1096 
   1097         // Get ProcessMemoryState as a simple gauge metric.
   1098         StatsdConfig.Builder config = getPulledConfig();
   1099         addGaugeAtomWithDimensions(config, Atom.PROCESS_MEMORY_STATE_FIELD_NUMBER, null);
   1100         uploadConfig(config);
   1101         Thread.sleep(WAIT_TIME_SHORT);
   1102 
   1103         // Start test app.
   1104         try (AutoCloseable a = withActivity("StatsdCtsForegroundActivity", "action",
   1105                 "action.show_notification")) {
   1106             Thread.sleep(WAIT_TIME_SHORT);
   1107             // Trigger new pull.
   1108             setAppBreadcrumbPredicate();
   1109         }
   1110 
   1111         // Assert about ProcessMemoryState for the test app.
   1112         List<Atom> atoms = getGaugeMetricDataList();
   1113         int uid = getUid();
   1114         boolean found = false;
   1115         for (Atom atom : atoms) {
   1116             ProcessMemoryState state = atom.getProcessMemoryState();
   1117             if (state.getUid() != uid) {
   1118                 continue;
   1119             }
   1120             found = true;
   1121             assertEquals(DEVICE_SIDE_TEST_PACKAGE, state.getProcessName());
   1122             assertTrue("oom_score should not be negative", state.getOomAdjScore() >= 0);
   1123             assertTrue("page_fault should not be negative", state.getPageFault() >= 0);
   1124             assertTrue("page_major_fault should not be negative", state.getPageMajorFault() >= 0);
   1125             assertTrue("rss_in_bytes should be positive", state.getRssInBytes() > 0);
   1126             assertTrue("cache_in_bytes should not be negative", state.getCacheInBytes() >= 0);
   1127             assertTrue("swap_in_bytes should not be negative", state.getSwapInBytes() >= 0);
   1128             assertTrue("start_time_nanos should be positive", state.getStartTimeNanos() > 0);
   1129             assertTrue("start_time_nanos should be in the past",
   1130                     state.getStartTimeNanos() < System.nanoTime());
   1131         }
   1132         assertTrue("Did not find a matching atom for uid=" + uid, found);
   1133     }
   1134 
   1135     public void testNativeProcessMemoryState() throws Exception {
   1136         if (statsdDisabled()) {
   1137             return;
   1138         }
   1139 
   1140         // Get NativeProcessState as a simple gauge metric.
   1141         StatsdConfig.Builder config = getPulledConfig();
   1142         addGaugeAtomWithDimensions(config, Atom.NATIVE_PROCESS_MEMORY_STATE_FIELD_NUMBER, null);
   1143         uploadConfig(config);
   1144         Thread.sleep(WAIT_TIME_SHORT);
   1145 
   1146         // Trigger new pull.
   1147         setAppBreadcrumbPredicate();
   1148 
   1149         // Assert about NativeProcessMemoryState for statsd.
   1150         List<Atom> atoms = getGaugeMetricDataList();
   1151         boolean found = false;
   1152         for (Atom atom : atoms) {
   1153             NativeProcessMemoryState state = atom.getNativeProcessMemoryState();
   1154             if (!state.getProcessName().contains("/statsd")) {
   1155                 continue;
   1156             }
   1157             found = true;
   1158             assertTrue("uid is below 10000", state.getUid() < 10000);
   1159             assertTrue("page_fault should not be negative", state.getPageFault() >= 0);
   1160             assertTrue("page_major_fault should not be negative", state.getPageMajorFault() >= 0);
   1161             assertTrue("rss_in_bytes should be positive", state.getRssInBytes() > 0);
   1162             assertTrue("start_time_nanos should be positive", state.getStartTimeNanos() > 0);
   1163             assertTrue("start_time_nanos should be in the past",
   1164                     state.getStartTimeNanos() < System.nanoTime());
   1165         }
   1166         assertTrue("Did not find a matching atom for statsd", found);
   1167     }
   1168 
   1169     public void testProcessMemoryHighWaterMark() throws Exception {
   1170         if (statsdDisabled()) {
   1171             return;
   1172         }
   1173 
   1174         // Get ProcessMemoryState as a simple gauge metric.
   1175         StatsdConfig.Builder config = getPulledConfig();
   1176         addGaugeAtomWithDimensions(config, Atom.PROCESS_MEMORY_HIGH_WATER_MARK_FIELD_NUMBER, null);
   1177         uploadConfig(config);
   1178         Thread.sleep(WAIT_TIME_SHORT);
   1179 
   1180         // Start test app and trigger a pull while its running.
   1181         try (AutoCloseable a = withActivity("StatsdCtsForegroundActivity", "action",
   1182                 "action.show_notification")) {
   1183             setAppBreadcrumbPredicate();
   1184         }
   1185         Thread.sleep(WAIT_TIME_SHORT);
   1186 
   1187         // Assert about ProcessMemoryHighWaterMark for the test app, statsd and system server.
   1188         List<Atom> atoms = getGaugeMetricDataList();
   1189         int uid = getUid();
   1190         boolean foundTestApp = false;
   1191         boolean foundStatsd = false;
   1192         boolean foundSystemServer = false;
   1193         for (Atom atom : atoms) {
   1194             ProcessMemoryHighWaterMark state = atom.getProcessMemoryHighWaterMark();
   1195             if (state.getUid() == uid) {
   1196                 foundTestApp = true;
   1197                 assertEquals(DEVICE_SIDE_TEST_PACKAGE, state.getProcessName());
   1198                 assertTrue("rss_high_water_mark_in_bytes should be positive",
   1199                         state.getRssHighWaterMarkInBytes() > 0);
   1200             } else if (state.getProcessName().contains("/statsd")) {
   1201                 foundStatsd = true;
   1202                 assertTrue("rss_high_water_mark_in_bytes should be positive",
   1203                         state.getRssHighWaterMarkInBytes() > 0);
   1204             } else if (state.getProcessName().equals("system")) {
   1205                 foundSystemServer = true;
   1206                 assertTrue("rss_high_water_mark_in_bytes should be positive",
   1207                         state.getRssHighWaterMarkInBytes() > 0);
   1208             }
   1209         }
   1210         assertTrue("Did not find a matching atom for test app uid=" + uid, foundTestApp);
   1211         assertTrue("Did not find a matching atom for statsd", foundStatsd);
   1212         assertTrue("Did not find a matching atom for system server", foundSystemServer);
   1213     }
   1214 
   1215     /**
   1216      * The the app id from a uid.
   1217      *
   1218      * @param uid The uid of the app
   1219      *
   1220      * @return The app id of the app
   1221      *
   1222      * @see android.os.UserHandle#getAppId
   1223      */
   1224     private static int getAppId(int uid) {
   1225         return uid % 100000;
   1226     }
   1227 
   1228     public void testRoleHolder() throws Exception {
   1229         if (statsdDisabled()) {
   1230             return;
   1231         }
   1232 
   1233         // Make device side test package a role holder
   1234         String callScreenAppRole = "android.app.role.CALL_SCREENING";
   1235         getDevice().executeShellCommand(
   1236                 "cmd role add-role-holder " + callScreenAppRole + " " + DEVICE_SIDE_TEST_PACKAGE);
   1237 
   1238         // Set up what to collect
   1239         StatsdConfig.Builder config = getPulledConfig();
   1240         addGaugeAtomWithDimensions(config, Atom.ROLE_HOLDER_FIELD_NUMBER, null);
   1241         uploadConfig(config);
   1242         Thread.sleep(WAIT_TIME_SHORT);
   1243 
   1244         boolean verifiedKnowRoleState = false;
   1245 
   1246         // Pull a report
   1247         setAppBreadcrumbPredicate();
   1248         Thread.sleep(WAIT_TIME_SHORT);
   1249 
   1250         int testAppId = getAppId(getUid());
   1251 
   1252         for (Atom atom : getGaugeMetricDataList()) {
   1253             AtomsProto.RoleHolder roleHolder = atom.getRoleHolder();
   1254 
   1255             assertNotNull(roleHolder.getPackageName());
   1256             assertTrue(roleHolder.getUid() >= 0);
   1257             assertNotNull(roleHolder.getRole());
   1258 
   1259             if (roleHolder.getPackageName().equals(DEVICE_SIDE_TEST_PACKAGE)) {
   1260                 assertEquals(testAppId, getAppId(roleHolder.getUid()));
   1261                 assertEquals(DEVICE_SIDE_TEST_PACKAGE, roleHolder.getPackageName());
   1262                 assertEquals(callScreenAppRole, roleHolder.getRole());
   1263 
   1264                 verifiedKnowRoleState = true;
   1265             }
   1266         }
   1267 
   1268         assertTrue(verifiedKnowRoleState);
   1269     }
   1270 
   1271     public void testDangerousPermissionState() throws Exception {
   1272         if (statsdDisabled()) {
   1273             return;
   1274         }
   1275 
   1276         final int FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED =  1 << 8;
   1277         final int FLAG_PERMISSION_USER_SENSITIVE_WHEN_DENIED =  1 << 9;
   1278 
   1279         // Set up what to collect
   1280         StatsdConfig.Builder config = getPulledConfig();
   1281         addGaugeAtomWithDimensions(config, Atom.DANGEROUS_PERMISSION_STATE_FIELD_NUMBER, null);
   1282         uploadConfig(config);
   1283         Thread.sleep(WAIT_TIME_SHORT);
   1284 
   1285         boolean verifiedKnowPermissionState = false;
   1286 
   1287         // Pull a report
   1288         setAppBreadcrumbPredicate();
   1289         Thread.sleep(WAIT_TIME_SHORT);
   1290 
   1291         int testAppId = getAppId(getUid());
   1292 
   1293         for (Atom atom : getGaugeMetricDataList()) {
   1294             DangerousPermissionState permissionState = atom.getDangerousPermissionState();
   1295 
   1296             assertNotNull(permissionState.getPermissionName());
   1297             assertTrue(permissionState.getUid() >= 0);
   1298             assertNotNull(permissionState.getPackageName());
   1299 
   1300             if (permissionState.getPackageName().equals(DEVICE_SIDE_TEST_PACKAGE)) {
   1301                 assertEquals(testAppId, getAppId(permissionState.getUid()));
   1302 
   1303                 if (permissionState.getPermissionName().equals(
   1304                         "android.permission.ACCESS_FINE_LOCATION")) {
   1305                     assertTrue(permissionState.getIsGranted());
   1306                     assertEquals(0, permissionState.getPermissionFlags() & (~(
   1307                             FLAG_PERMISSION_USER_SENSITIVE_WHEN_DENIED
   1308                                     | FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED)));
   1309 
   1310                     verifiedKnowPermissionState = true;
   1311                 }
   1312             }
   1313         }
   1314 
   1315         assertTrue(verifiedKnowPermissionState);
   1316     }
   1317 
   1318     public void testANROccurred() throws Exception {
   1319         if (statsdDisabled()) {
   1320             return;
   1321         }
   1322         final int atomTag = Atom.ANR_OCCURRED_FIELD_NUMBER;
   1323         createAndUploadConfig(atomTag, false);
   1324         Thread.sleep(WAIT_TIME_SHORT);
   1325 
   1326         try (AutoCloseable a = withActivity("ANRActivity", null, null)) {
   1327             Thread.sleep(WAIT_TIME_SHORT);
   1328             getDevice().executeShellCommand(
   1329                     "am broadcast -a action_anr -p " + DEVICE_SIDE_TEST_PACKAGE);
   1330             Thread.sleep(11_000);
   1331         }
   1332 
   1333         // Sorted list of events in order in which they occurred.
   1334         List<EventMetricData> data = getEventMetricDataList();
   1335 
   1336         assertEquals(1, data.size());
   1337         assertTrue(data.get(0).getAtom().hasAnrOccurred());
   1338         ANROccurred atom = data.get(0).getAtom().getAnrOccurred();
   1339         assertEquals(ANROccurred.InstantApp.FALSE_VALUE, atom.getIsInstantApp().getNumber());
   1340         assertEquals(ANROccurred.ForegroundState.FOREGROUND_VALUE,
   1341                 atom.getForegroundState().getNumber());
   1342         assertEquals(ErrorSource.DATA_APP, atom.getErrorSource());
   1343         assertEquals(DEVICE_SIDE_TEST_PACKAGE, atom.getPackageName());
   1344     }
   1345 
   1346     public void testWriteRawTestAtom() throws Exception {
   1347         if (statsdDisabled()) {
   1348             return;
   1349         }
   1350         final int atomTag = Atom.TEST_ATOM_REPORTED_FIELD_NUMBER;
   1351         createAndUploadConfig(atomTag, true);
   1352         Thread.sleep(WAIT_TIME_SHORT);
   1353 
   1354         runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".AtomTests", "testWriteRawTestAtom");
   1355 
   1356         Thread.sleep(WAIT_TIME_SHORT);
   1357         // Sorted list of events in order in which they occurred.
   1358         List<EventMetricData> data = getEventMetricDataList();
   1359         assertEquals(data.size(), 4);
   1360 
   1361         TestAtomReported atom = data.get(0).getAtom().getTestAtomReported();
   1362         List<AttributionNode> attrChain = atom.getAttributionNodeList();
   1363         assertEquals(2, attrChain.size());
   1364         assertEquals(1234, attrChain.get(0).getUid());
   1365         assertEquals("tag1", attrChain.get(0).getTag());
   1366         assertEquals(getUid(), attrChain.get(1).getUid());
   1367         assertEquals("tag2", attrChain.get(1).getTag());
   1368 
   1369         assertEquals(42, atom.getIntField());
   1370         assertEquals(Long.MAX_VALUE, atom.getLongField());
   1371         assertEquals(3.14f, atom.getFloatField());
   1372         assertEquals("This is a basic test!", atom.getStringField());
   1373         assertEquals(false, atom.getBooleanField());
   1374         assertEquals(TestAtomReported.State.ON_VALUE, atom.getState().getNumber());
   1375         List<Long> expIds = atom.getBytesField().getExperimentIdList();
   1376         assertEquals(3, expIds.size());
   1377         assertEquals(1L, (long) expIds.get(0));
   1378         assertEquals(2L, (long) expIds.get(1));
   1379         assertEquals(3L, (long) expIds.get(2));
   1380 
   1381         atom = data.get(1).getAtom().getTestAtomReported();
   1382         attrChain = atom.getAttributionNodeList();
   1383         assertEquals(2, attrChain.size());
   1384         assertEquals(9999, attrChain.get(0).getUid());
   1385         assertEquals("tag9999", attrChain.get(0).getTag());
   1386         assertEquals(getUid(), attrChain.get(1).getUid());
   1387         assertEquals("", attrChain.get(1).getTag());
   1388 
   1389         assertEquals(100, atom.getIntField());
   1390         assertEquals(Long.MIN_VALUE, atom.getLongField());
   1391         assertEquals(-2.5f, atom.getFloatField());
   1392         assertEquals("Test null uid", atom.getStringField());
   1393         assertEquals(true, atom.getBooleanField());
   1394         assertEquals(TestAtomReported.State.UNKNOWN_VALUE, atom.getState().getNumber());
   1395         expIds = atom.getBytesField().getExperimentIdList();
   1396         assertEquals(3, expIds.size());
   1397         assertEquals(1L, (long) expIds.get(0));
   1398         assertEquals(2L, (long) expIds.get(1));
   1399         assertEquals(3L, (long) expIds.get(2));
   1400 
   1401         atom = data.get(2).getAtom().getTestAtomReported();
   1402         attrChain = atom.getAttributionNodeList();
   1403         assertEquals(1, attrChain.size());
   1404         assertEquals(getUid(), attrChain.get(0).getUid());
   1405         assertEquals("tag1", attrChain.get(0).getTag());
   1406 
   1407         assertEquals(-256, atom.getIntField());
   1408         assertEquals(-1234567890L, atom.getLongField());
   1409         assertEquals(42.01f, atom.getFloatField());
   1410         assertEquals("Test non chained", atom.getStringField());
   1411         assertEquals(true, atom.getBooleanField());
   1412         assertEquals(TestAtomReported.State.OFF_VALUE, atom.getState().getNumber());
   1413         expIds = atom.getBytesField().getExperimentIdList();
   1414         assertEquals(3, expIds.size());
   1415         assertEquals(1L, (long) expIds.get(0));
   1416         assertEquals(2L, (long) expIds.get(1));
   1417         assertEquals(3L, (long) expIds.get(2));
   1418 
   1419         atom = data.get(3).getAtom().getTestAtomReported();
   1420         attrChain = atom.getAttributionNodeList();
   1421         assertEquals(1, attrChain.size());
   1422         assertEquals(getUid(), attrChain.get(0).getUid());
   1423         assertEquals("", attrChain.get(0).getTag());
   1424 
   1425         assertEquals(0, atom.getIntField());
   1426         assertEquals(0L, atom.getLongField());
   1427         assertEquals(0f, atom.getFloatField());
   1428         assertEquals("", atom.getStringField());
   1429         assertEquals(true, atom.getBooleanField());
   1430         assertEquals(TestAtomReported.State.OFF_VALUE, atom.getState().getNumber());
   1431         expIds = atom.getBytesField().getExperimentIdList();
   1432         assertEquals(0, expIds.size());
   1433     }
   1434 
   1435 }
   1436