Looper_test.cpp revision 54e1cdacd2b132997fdca5e5b90e45855c7a2a95
1//
2// Copyright 2010 The Android Open Source Project
3//
4
5#include <utils/Looper.h>
6#include <utils/Timers.h>
7#include <utils/StopWatch.h>
8#include <gtest/gtest.h>
9#include <unistd.h>
10#include <time.h>
11
12#include "TestHelpers.h"
13
14// # of milliseconds to fudge stopwatch measurements
15#define TIMING_TOLERANCE_MS 25
16
17namespace android {
18
19class DelayedWake : public DelayedTask {
20    sp<Looper> mLooper;
21
22public:
23    DelayedWake(int delayMillis, const sp<Looper> looper) :
24        DelayedTask(delayMillis), mLooper(looper) {
25    }
26
27protected:
28    virtual void doTask() {
29        mLooper->wake();
30    }
31};
32
33class DelayedWriteSignal : public DelayedTask {
34    Pipe* mPipe;
35
36public:
37    DelayedWriteSignal(int delayMillis, Pipe* pipe) :
38        DelayedTask(delayMillis), mPipe(pipe) {
39    }
40
41protected:
42    virtual void doTask() {
43        mPipe->writeSignal();
44    }
45};
46
47class CallbackHandler {
48public:
49    void setCallback(const sp<Looper>& looper, int fd, int events) {
50        looper->addFd(fd, 0, events, staticHandler, this);
51    }
52
53protected:
54    virtual ~CallbackHandler() { }
55
56    virtual int handler(int fd, int events) = 0;
57
58private:
59    static int staticHandler(int fd, int events, void* data) {
60        return static_cast<CallbackHandler*>(data)->handler(fd, events);
61    }
62};
63
64class StubCallbackHandler : public CallbackHandler {
65public:
66    int nextResult;
67    int callbackCount;
68
69    int fd;
70    int events;
71
72    StubCallbackHandler(int nextResult) : nextResult(nextResult),
73            callbackCount(0), fd(-1), events(-1) {
74    }
75
76protected:
77    virtual int handler(int fd, int events) {
78        callbackCount += 1;
79        this->fd = fd;
80        this->events = events;
81        return nextResult;
82    }
83};
84
85class LooperTest : public testing::Test {
86protected:
87    sp<Looper> mLooper;
88
89    virtual void SetUp() {
90        mLooper = new Looper(true);
91    }
92
93    virtual void TearDown() {
94        mLooper.clear();
95    }
96};
97
98
99TEST_F(LooperTest, PollOnce_WhenNonZeroTimeoutAndNotAwoken_WaitsForTimeout) {
100    StopWatch stopWatch("pollOnce");
101    int result = mLooper->pollOnce(100);
102    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
103
104    EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS)
105            << "elapsed time should approx. equal timeout";
106    EXPECT_EQ(ALOOPER_POLL_TIMEOUT, result)
107            << "pollOnce result should be ALOOPER_POLL_TIMEOUT";
108}
109
110TEST_F(LooperTest, PollOnce_WhenNonZeroTimeoutAndAwokenBeforeWaiting_ImmediatelyReturns) {
111    mLooper->wake();
112
113    StopWatch stopWatch("pollOnce");
114    int result = mLooper->pollOnce(1000);
115    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
116
117    EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
118            << "elapsed time should approx. zero because wake() was called before waiting";
119    EXPECT_EQ(ALOOPER_POLL_WAKE, result)
120            << "pollOnce result should be ALOOPER_POLL_CALLBACK because loop was awoken";
121}
122
123TEST_F(LooperTest, PollOnce_WhenNonZeroTimeoutAndAwokenWhileWaiting_PromptlyReturns) {
124    sp<DelayedWake> delayedWake = new DelayedWake(100, mLooper);
125    delayedWake->run();
126
127    StopWatch stopWatch("pollOnce");
128    int result = mLooper->pollOnce(1000);
129    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
130
131    EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS)
132            << "elapsed time should approx. equal wake delay";
133    EXPECT_EQ(ALOOPER_POLL_WAKE, result)
134            << "pollOnce result should be ALOOPER_POLL_CALLBACK because loop was awoken";
135}
136
137TEST_F(LooperTest, PollOnce_WhenZeroTimeoutAndNoRegisteredFDs_ImmediatelyReturns) {
138    StopWatch stopWatch("pollOnce");
139    int result = mLooper->pollOnce(0);
140    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
141
142    EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
143            << "elapsed time should be approx. zero";
144    EXPECT_EQ(ALOOPER_POLL_TIMEOUT, result)
145            << "pollOnce result should be ALOOPER_POLL_TIMEOUT";
146}
147
148TEST_F(LooperTest, PollOnce_WhenZeroTimeoutAndNoSignalledFDs_ImmediatelyReturns) {
149    Pipe pipe;
150    StubCallbackHandler handler(true);
151
152    handler.setCallback(mLooper, pipe.receiveFd, ALOOPER_EVENT_INPUT);
153
154    StopWatch stopWatch("pollOnce");
155    int result = mLooper->pollOnce(0);
156    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
157
158    EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
159            << "elapsed time should be approx. zero";
160    EXPECT_EQ(ALOOPER_POLL_TIMEOUT, result)
161            << "pollOnce result should be ALOOPER_POLL_TIMEOUT";
162    EXPECT_EQ(0, handler.callbackCount)
163            << "callback should not have been invoked because FD was not signalled";
164}
165
166TEST_F(LooperTest, PollOnce_WhenZeroTimeoutAndSignalledFD_ImmediatelyInvokesCallbackAndReturns) {
167    Pipe pipe;
168    StubCallbackHandler handler(true);
169
170    ASSERT_EQ(OK, pipe.writeSignal());
171    handler.setCallback(mLooper, pipe.receiveFd, ALOOPER_EVENT_INPUT);
172
173    StopWatch stopWatch("pollOnce");
174    int result = mLooper->pollOnce(0);
175    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
176
177    EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
178            << "elapsed time should be approx. zero";
179    EXPECT_EQ(ALOOPER_POLL_CALLBACK, result)
180            << "pollOnce result should be ALOOPER_POLL_CALLBACK because FD was signalled";
181    EXPECT_EQ(1, handler.callbackCount)
182            << "callback should be invoked exactly once";
183    EXPECT_EQ(pipe.receiveFd, handler.fd)
184            << "callback should have received pipe fd as parameter";
185    EXPECT_EQ(ALOOPER_EVENT_INPUT, handler.events)
186            << "callback should have received ALOOPER_EVENT_INPUT as events";
187}
188
189TEST_F(LooperTest, PollOnce_WhenNonZeroTimeoutAndNoSignalledFDs_WaitsForTimeoutAndReturns) {
190    Pipe pipe;
191    StubCallbackHandler handler(true);
192
193    handler.setCallback(mLooper, pipe.receiveFd, ALOOPER_EVENT_INPUT);
194
195    StopWatch stopWatch("pollOnce");
196    int result = mLooper->pollOnce(100);
197    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
198
199    EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS)
200            << "elapsed time should approx. equal timeout";
201    EXPECT_EQ(ALOOPER_POLL_TIMEOUT, result)
202            << "pollOnce result should be ALOOPER_POLL_TIMEOUT";
203    EXPECT_EQ(0, handler.callbackCount)
204            << "callback should not have been invoked because FD was not signalled";
205}
206
207TEST_F(LooperTest, PollOnce_WhenNonZeroTimeoutAndSignalledFDBeforeWaiting_ImmediatelyInvokesCallbackAndReturns) {
208    Pipe pipe;
209    StubCallbackHandler handler(true);
210
211    pipe.writeSignal();
212    handler.setCallback(mLooper, pipe.receiveFd, ALOOPER_EVENT_INPUT);
213
214    StopWatch stopWatch("pollOnce");
215    int result = mLooper->pollOnce(100);
216    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
217
218    ASSERT_EQ(OK, pipe.readSignal())
219            << "signal should actually have been written";
220    EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
221            << "elapsed time should be approx. zero";
222    EXPECT_EQ(ALOOPER_POLL_CALLBACK, result)
223            << "pollOnce result should be ALOOPER_POLL_CALLBACK because FD was signalled";
224    EXPECT_EQ(1, handler.callbackCount)
225            << "callback should be invoked exactly once";
226    EXPECT_EQ(pipe.receiveFd, handler.fd)
227            << "callback should have received pipe fd as parameter";
228    EXPECT_EQ(ALOOPER_EVENT_INPUT, handler.events)
229            << "callback should have received ALOOPER_EVENT_INPUT as events";
230}
231
232TEST_F(LooperTest, PollOnce_WhenNonZeroTimeoutAndSignalledFDWhileWaiting_PromptlyInvokesCallbackAndReturns) {
233    Pipe pipe;
234    StubCallbackHandler handler(true);
235    sp<DelayedWriteSignal> delayedWriteSignal = new DelayedWriteSignal(100, & pipe);
236
237    handler.setCallback(mLooper, pipe.receiveFd, ALOOPER_EVENT_INPUT);
238    delayedWriteSignal->run();
239
240    StopWatch stopWatch("pollOnce");
241    int result = mLooper->pollOnce(1000);
242    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
243
244    ASSERT_EQ(OK, pipe.readSignal())
245            << "signal should actually have been written";
246    EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS)
247            << "elapsed time should approx. equal signal delay";
248    EXPECT_EQ(ALOOPER_POLL_CALLBACK, result)
249            << "pollOnce result should be ALOOPER_POLL_CALLBACK because FD was signalled";
250    EXPECT_EQ(1, handler.callbackCount)
251            << "callback should be invoked exactly once";
252    EXPECT_EQ(pipe.receiveFd, handler.fd)
253            << "callback should have received pipe fd as parameter";
254    EXPECT_EQ(ALOOPER_EVENT_INPUT, handler.events)
255            << "callback should have received ALOOPER_EVENT_INPUT as events";
256}
257
258TEST_F(LooperTest, PollOnce_WhenCallbackAddedThenRemoved_CallbackShouldNotBeInvoked) {
259    Pipe pipe;
260    StubCallbackHandler handler(true);
261
262    handler.setCallback(mLooper, pipe.receiveFd, ALOOPER_EVENT_INPUT);
263    pipe.writeSignal(); // would cause FD to be considered signalled
264    mLooper->removeFd(pipe.receiveFd);
265
266    StopWatch stopWatch("pollOnce");
267    int result = mLooper->pollOnce(100);
268    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
269
270    ASSERT_EQ(OK, pipe.readSignal())
271            << "signal should actually have been written";
272    EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS)
273            << "elapsed time should approx. equal timeout because FD was no longer registered";
274    EXPECT_EQ(ALOOPER_POLL_TIMEOUT, result)
275            << "pollOnce result should be ALOOPER_POLL_TIMEOUT";
276    EXPECT_EQ(0, handler.callbackCount)
277            << "callback should not be invoked";
278}
279
280TEST_F(LooperTest, PollOnce_WhenCallbackReturnsFalse_CallbackShouldNotBeInvokedAgainLater) {
281    Pipe pipe;
282    StubCallbackHandler handler(false);
283
284    handler.setCallback(mLooper, pipe.receiveFd, ALOOPER_EVENT_INPUT);
285
286    // First loop: Callback is registered and FD is signalled.
287    pipe.writeSignal();
288
289    StopWatch stopWatch("pollOnce");
290    int result = mLooper->pollOnce(0);
291    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
292
293    ASSERT_EQ(OK, pipe.readSignal())
294            << "signal should actually have been written";
295    EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
296            << "elapsed time should approx. equal zero because FD was already signalled";
297    EXPECT_EQ(ALOOPER_POLL_CALLBACK, result)
298            << "pollOnce result should be ALOOPER_POLL_CALLBACK because FD was signalled";
299    EXPECT_EQ(1, handler.callbackCount)
300            << "callback should be invoked";
301
302    // Second loop: Callback is no longer registered and FD is signalled.
303    pipe.writeSignal();
304
305    stopWatch.reset();
306    result = mLooper->pollOnce(0);
307    elapsedMillis = ns2ms(stopWatch.elapsedTime());
308
309    ASSERT_EQ(OK, pipe.readSignal())
310            << "signal should actually have been written";
311    EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
312            << "elapsed time should approx. equal zero because timeout was zero";
313    EXPECT_EQ(ALOOPER_POLL_TIMEOUT, result)
314            << "pollOnce result should be ALOOPER_POLL_TIMEOUT";
315    EXPECT_EQ(1, handler.callbackCount)
316            << "callback should not be invoked this time";
317}
318
319TEST_F(LooperTest, PollOnce_WhenNonCallbackFdIsSignalled_ReturnsIdent) {
320    const int expectedIdent = 5;
321    void* expectedData = this;
322
323    Pipe pipe;
324
325    pipe.writeSignal();
326    mLooper->addFd(pipe.receiveFd, expectedIdent, ALOOPER_EVENT_INPUT, NULL, expectedData);
327
328    StopWatch stopWatch("pollOnce");
329    int fd;
330    int events;
331    void* data;
332    int result = mLooper->pollOnce(100, &fd, &events, &data);
333    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
334
335    ASSERT_EQ(OK, pipe.readSignal())
336            << "signal should actually have been written";
337    EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
338            << "elapsed time should be approx. zero";
339    EXPECT_EQ(expectedIdent, result)
340            << "pollOnce result should be the ident of the FD that was signalled";
341    EXPECT_EQ(pipe.receiveFd, fd)
342            << "pollOnce should have returned the received pipe fd";
343    EXPECT_EQ(ALOOPER_EVENT_INPUT, events)
344            << "pollOnce should have returned ALOOPER_EVENT_INPUT as events";
345    EXPECT_EQ(expectedData, data)
346            << "pollOnce should have returned the data";
347}
348
349TEST_F(LooperTest, AddFd_WhenCallbackAdded_ReturnsOne) {
350    Pipe pipe;
351    int result = mLooper->addFd(pipe.receiveFd, 0, ALOOPER_EVENT_INPUT, NULL, NULL);
352
353    EXPECT_EQ(1, result)
354            << "addFd should return 1 because FD was added";
355}
356
357TEST_F(LooperTest, AddFd_WhenIdentIsNegativeAndCallbackIsNull_ReturnsError) {
358    Pipe pipe;
359    int result = mLooper->addFd(pipe.receiveFd, -1, ALOOPER_EVENT_INPUT, NULL, NULL);
360
361    EXPECT_EQ(-1, result)
362            << "addFd should return -1 because arguments were invalid";
363}
364
365TEST_F(LooperTest, AddFd_WhenNoCallbackAndAllowNonCallbacksIsFalse_ReturnsError) {
366    Pipe pipe;
367    sp<Looper> looper = new Looper(false /*allowNonCallbacks*/);
368    int result = looper->addFd(pipe.receiveFd, 0, 0, NULL, NULL);
369
370    EXPECT_EQ(-1, result)
371            << "addFd should return -1 because arguments were invalid";
372}
373
374TEST_F(LooperTest, RemoveFd_WhenCallbackNotAdded_ReturnsZero) {
375    int result = mLooper->removeFd(1);
376
377    EXPECT_EQ(0, result)
378            << "removeFd should return 0 because FD not registered";
379}
380
381TEST_F(LooperTest, RemoveFd_WhenCallbackAddedThenRemovedTwice_ReturnsOnceFirstTimeAndReturnsZeroSecondTime) {
382    Pipe pipe;
383    StubCallbackHandler handler(false);
384    handler.setCallback(mLooper, pipe.receiveFd, ALOOPER_EVENT_INPUT);
385
386    // First time.
387    int result = mLooper->removeFd(pipe.receiveFd);
388
389    EXPECT_EQ(1, result)
390            << "removeFd should return 1 first time because FD was registered";
391
392    // Second time.
393    result = mLooper->removeFd(pipe.receiveFd);
394
395    EXPECT_EQ(0, result)
396            << "removeFd should return 0 second time because FD was no longer registered";
397}
398
399TEST_F(LooperTest, PollOnce_WhenCallbackAddedTwice_OnlySecondCallbackShouldBeInvoked) {
400    Pipe pipe;
401    StubCallbackHandler handler1(true);
402    StubCallbackHandler handler2(true);
403
404    handler1.setCallback(mLooper, pipe.receiveFd, ALOOPER_EVENT_INPUT);
405    handler2.setCallback(mLooper, pipe.receiveFd, ALOOPER_EVENT_INPUT); // replace it
406    pipe.writeSignal(); // would cause FD to be considered signalled
407
408    StopWatch stopWatch("pollOnce");
409    int result = mLooper->pollOnce(100);
410    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
411
412    ASSERT_EQ(OK, pipe.readSignal())
413            << "signal should actually have been written";
414    EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
415            << "elapsed time should approx. zero because FD was already signalled";
416    EXPECT_EQ(ALOOPER_POLL_CALLBACK, result)
417            << "pollOnce result should be ALOOPER_POLL_CALLBACK because FD was signalled";
418    EXPECT_EQ(0, handler1.callbackCount)
419            << "original handler callback should not be invoked because it was replaced";
420    EXPECT_EQ(1, handler2.callbackCount)
421            << "replacement handler callback should be invoked";
422}
423
424
425} // namespace android
426