1 /*
2  * Copyright (C) 2009 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.server;
18 
19 import static org.junit.Assert.assertEquals;
20 import static org.mockito.Mockito.mock;
21 import static org.mockito.Mockito.verify;
22 import static org.mockito.Mockito.verifyNoMoreInteractions;
23 
24 import android.os.Handler;
25 import android.os.SimpleClock;
26 
27 import androidx.test.runner.AndroidJUnit4;
28 
29 import com.android.server.Watchdog.HandlerChecker;
30 
31 import org.junit.Before;
32 import org.junit.Test;
33 import org.junit.runner.RunWith;
34 
35 import java.time.ZoneOffset;
36 
37 /** Test class for {@link Watchdog}. */
38 @RunWith(AndroidJUnit4.class)
39 public class WatchdogTest {
40     private static final int TIMEOUT_MS = 10;
41 
42     private TestClock mClock;
43     private Handler mHandler;
44     private HandlerChecker mChecker;
45 
46     @Before
setUp()47     public void setUp() {
48         mClock = new TestClock();
49         mHandler = mock(Handler.class);
50         mChecker =
51                 new HandlerChecker(mHandler, "monitor thread", new Object(), mClock) {
52                     @Override
53                     public boolean isHandlerPolling() {
54                         return false;
55                     }
56                 };
57     }
58 
59     @Test
checkerPausedUntilResume()60     public void checkerPausedUntilResume() {
61         Watchdog.Monitor monitor = mock(Watchdog.Monitor.class);
62         mChecker.addMonitorLocked(monitor);
63 
64         mChecker.pauseLocked("pausing");
65         mChecker.scheduleCheckLocked(TIMEOUT_MS);
66         verifyNoMoreInteractions(mHandler);
67         assertEquals(Watchdog.COMPLETED, mChecker.getCompletionStateLocked());
68 
69         mChecker.resumeLocked("resuming");
70         mChecker.scheduleCheckLocked(10);
71         assertEquals(Watchdog.WAITING, mChecker.getCompletionStateLocked());
72     }
73 
74     @Test
checkerPausedUntilDeadline()75     public void checkerPausedUntilDeadline() {
76         Watchdog.Monitor monitor = mock(Watchdog.Monitor.class);
77         mChecker.addMonitorLocked(monitor);
78 
79         mChecker.pauseForLocked(10, "pausing");
80         mChecker.scheduleCheckLocked(TIMEOUT_MS);
81         verifyNoMoreInteractions(mHandler);
82         assertEquals(Watchdog.COMPLETED, mChecker.getCompletionStateLocked());
83 
84         mClock.advanceBy(5);
85         verifyNoMoreInteractions(mHandler);
86         assertEquals(Watchdog.COMPLETED, mChecker.getCompletionStateLocked());
87 
88         // Above the 10s timeout. Watchdog should not be paused anymore.
89         mClock.advanceBy(6);
90         mChecker.scheduleCheckLocked(TIMEOUT_MS);
91         assertEquals(Watchdog.WAITING, mChecker.getCompletionStateLocked());
92     }
93 
94     @Test
checkerPausedDuringScheduledRun()95     public void checkerPausedDuringScheduledRun() {
96         Watchdog.Monitor monitor = mock(Watchdog.Monitor.class);
97         mChecker.addMonitorLocked(monitor);
98 
99         mChecker.scheduleCheckLocked(TIMEOUT_MS);
100         mClock.advanceBy(5);
101         mChecker.pauseForLocked(10, "pausing");
102         verifyNoMoreInteractions(mHandler);
103         assertEquals(Watchdog.COMPLETED, mChecker.getCompletionStateLocked());
104 
105         // Above the 10s timeout. Watchdog should not be paused anymore.
106         mClock.advanceBy(11);
107         mChecker.scheduleCheckLocked(TIMEOUT_MS);
108         assertEquals(Watchdog.WAITING, mChecker.getCompletionStateLocked());
109     }
110 
111     @Test
blockedThread()112     public void blockedThread() {
113         mChecker.scheduleCheckLocked(TIMEOUT_MS);
114         assertEquals(mChecker.getCompletionStateLocked(), Watchdog.WAITING);
115 
116         mClock.advanceBy(6);
117         assertEquals(Watchdog.WAITED_UNTIL_PRE_WATCHDOG, mChecker.getCompletionStateLocked());
118 
119         // Above the 10s timeout.
120         mClock.advanceBy(6);
121         assertEquals(Watchdog.OVERDUE, mChecker.getCompletionStateLocked());
122     }
123 
124     @Test
checkNothingBlocked()125     public void checkNothingBlocked() {
126         Watchdog.Monitor monitor = mock(Watchdog.Monitor.class);
127         mChecker.addMonitorLocked(monitor);
128 
129         mChecker.scheduleCheckLocked(TIMEOUT_MS);
130         // scheduleCheckLocked calls #postAtFrontOfQueue which will call mChecker.run().
131         mChecker.run();
132         assertEquals(Watchdog.COMPLETED, mChecker.getCompletionStateLocked());
133         verify(monitor).monitor();
134     }
135 
136     private static class TestClock extends SimpleClock {
137         long mNowMillis = 1;
138 
TestClock()139         TestClock() {
140             super(ZoneOffset.UTC);
141         }
142 
143         @Override
millis()144         public long millis() {
145             return mNowMillis;
146         }
147 
advanceBy(long millis)148         public void advanceBy(long millis) {
149             mNowMillis += millis;
150         }
151     }
152 }
153