1 /*
2  * Copyright (C) 2021 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.tests.scheduling.host;
18 
19 import static com.google.common.truth.Truth.assertThat;
20 
21 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
22 import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
23 
24 import org.junit.Test;
25 import org.junit.runner.RunWith;
26 
27 import java.util.Scanner;
28 import java.util.concurrent.TimeUnit;
29 
30 /**
31  * Host side tests for Reboot Readiness detection.
32  */
33 @RunWith(DeviceJUnit4ClassRunner.class)
34 public class RebootReadinessHostTest extends BaseHostJUnit4Test {
35 
36     private static final String METRIC_TIME_TO_REBOOT_READY = "rebootReadyMs";
37     private static final String METRIC_TIME_TO_FIRST_UNLOCK = "timeUntilFirstUnlockMs";
38     private static final String METRIC_BLOCKED_BY_INTERACTIVITY = "blockedByInteractivity";
39     private static final String METRIC_BLOCKED_BY_COMPONENTS = "blockedBySubsystems";
40     private static final String METRIC_BLOCKED_BY_APP_ACTIVITY = "blockedByAppActivity";
41 
runPhase(String methodName)42     private void runPhase(String methodName) throws Exception {
43         assertThat(runDeviceTests("com.android.tests.scheduling",
44                 "com.android.tests.scheduling.RebootReadinessTest",
45                 methodName)).isTrue();
46     }
47 
48     /**
49      * Ensures that the correct metric is logged when the device is in a reboot-ready state
50      * immediately.
51      */
52     @Test
testUnattendedRebootMetrics_Basic()53     public void testUnattendedRebootMetrics_Basic() throws Exception {
54         runPhase("testRebootReadyBroadcastReceived");
55 
56         getDevice().reboot();
57         getDevice().executeAdbCommand("logcat", "-c");
58 
59         // This command will unlock the device, which will cause the metric to be logged
60         getDevice().executeShellCommand("wm dismiss-keyguard");
61 
62         // Wait a small amount of time for the metrics to be logged, before querying logcat
63         Thread.sleep(2000);
64         String logs = getDevice().executeAdbCommand(
65                 "logcat", "-v", "brief", "-d", "RebootReadinessLogger:I", "*:S");
66         UnattendedRebootMetricEvent event = null;
67         Scanner in = new Scanner(logs);
68         while (in.hasNextLine()) {
69             String line = in.nextLine();
70             if (line.contains("UnattendedRebootOccurred")) {
71                 event = parseUnattendedRebootEvent(line);
72                 break;
73             }
74         }
75         in.close();
76 
77         assertThat(event).isNotNull();
78         assertThat(event.mTimesBlockedByAppActivity).isEqualTo(0);
79         assertThat(event.mTimesBlockedByComponents).isEqualTo(0);
80         assertThat(event.mTimesBlockedByInteractivity).isEqualTo(0);
81         assertThat(event.mTimeToFirstUnlockMs).isAtLeast(0);
82         assertThat(event.mTimeToFirstUnlockMs).isLessThan(TimeUnit.MINUTES.toMillis(1));
83         assertThat(event.mTimeToRebootReadyMs).isAtLeast(0);
84         assertThat(event.mTimeToRebootReadyMs).isLessThan(TimeUnit.MINUTES.toMillis(1));
85     }
86 
parseUnattendedRebootEvent(String line)87     private UnattendedRebootMetricEvent parseUnattendedRebootEvent(String line) {
88         String[] metricFields = line.split("UnattendedRebootOccurred")[1].trim().split(" ");
89         UnattendedRebootMetricEvent event = new UnattendedRebootMetricEvent();
90         for (String metric: metricFields) {
91             // Each key-value pair will be of the form "key=value"
92             event.setField(metric.split("=")[0], metric.split("=")[1]);
93         }
94         return event;
95     }
96 
97 
98     private static final class UnattendedRebootMetricEvent {
99 
100         long mTimeToFirstUnlockMs = -1;
101         long mTimeToRebootReadyMs = -1;
102         int mTimesBlockedByInteractivity = -1;
103         int mTimesBlockedByComponents = -1;
104         int mTimesBlockedByAppActivity = -1;
105 
UnattendedRebootMetricEvent()106         UnattendedRebootMetricEvent() {
107         }
108 
setField(String value, String key)109         void setField(String value, String key) {
110             switch (value) {
111                 case METRIC_TIME_TO_REBOOT_READY:
112                     mTimeToRebootReadyMs = Long.parseLong(key);
113                     break;
114                 case METRIC_TIME_TO_FIRST_UNLOCK:
115                     mTimeToFirstUnlockMs = Long.parseLong(key);
116                     break;
117                 case METRIC_BLOCKED_BY_INTERACTIVITY:
118                     mTimesBlockedByInteractivity = Integer.parseInt(key);
119                     break;
120                 case METRIC_BLOCKED_BY_COMPONENTS:
121                     mTimesBlockedByComponents = Integer.parseInt(key);
122                     break;
123                 case METRIC_BLOCKED_BY_APP_ACTIVITY:
124                     mTimesBlockedByAppActivity = Integer.parseInt(key);
125                     break;
126                 default:
127                     break;
128             }
129         }
130     }
131 
132 }
133