1 /*
2 * Copyright (C) 2016 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 #include <general_test/timer_cancel_test.h>
18
19 #include <cinttypes>
20 #include <cstddef>
21
22 #include <shared/send_message.h>
23 #include <shared/time_util.h>
24
25 #include <chre.h>
26
27 using nanoapp_testing::kOneMillisecondInNanoseconds;
28 using nanoapp_testing::sendFatalFailureToHost;
29 using nanoapp_testing::sendInternalFailureToHost;
30 using nanoapp_testing::sendSuccessToHost;
31
32 /*
33 * This test has four stages where we cancel one-shot and recurring timers,
34 * before and after they're triggered.
35 *
36 * See the TimerCancelTest constructor to see which stage tests which setup.
37 *
38 * When all of our stages have succeeded, then we send success to the host.
39 */
40
41 static uint64_t kDuration = 10 * kOneMillisecondInNanoseconds;
42
43 namespace general_test {
44
startStages()45 void TimerCancelTest::startStages() {
46 for (uint32_t i = 0; i < kStageCount; i++) {
47 Stage *stage = &mStages[i];
48 stage->timerId = chreTimerSet(kDuration, stage, stage->oneShot);
49 if (stage->timerId == CHRE_TIMER_INVALID) {
50 sendFatalFailureToHost("Unable to set timer:", &i);
51 }
52 if (stage->expectCallback) {
53 // Go on to the next stage. Note this stage will markSuccess()
54 // in handleStageEvent().
55 continue;
56 }
57 if (!chreTimerCancel(stage->timerId)) {
58 sendFatalFailureToHost("Unable to cancel timer:", &i);
59 }
60 if (chreTimerCancel(stage->timerId)) {
61 sendFatalFailureToHost("Claimed success in second cancel:", &i);
62 }
63 markSuccess(i);
64 }
65 }
66
TimerCancelTest()67 TimerCancelTest::TimerCancelTest()
68 : Test(CHRE_API_VERSION_1_0),
69 mInMethod(false),
70 mStages{
71 // expectCallback:false ==> We're canceling before the timer fires.
72 // expectCallback:true ==> We'll cancel after the timer fires once.
73 //
74 // stage, oneShot, expectCallback
75 Stage(0, false, false),
76 Stage(1, true, false),
77 Stage(2, false, true ),
78 Stage(3, true, true )},
79 mFinishedBitmask(0) {
80 }
81
setUp(uint32_t messageSize,const void *)82 void TimerCancelTest::setUp(uint32_t messageSize, const void * /* message */) {
83 mInMethod = true;
84
85 if (messageSize != 0) {
86 sendFatalFailureToHost(
87 "TimerCancel message expects 0 additional bytes, got ",
88 &messageSize);
89 }
90
91 constexpr uint32_t kUnownedTimer = 0;
92 static_assert((kUnownedTimer != CHRE_TIMER_INVALID), "Bad test");
93 if (chreTimerCancel(kUnownedTimer)) {
94 sendFatalFailureToHost("Claimed success canceling timer we don't own");
95 }
96
97 startStages();
98
99 // Now we wait for some events from the timers to fire.
100
101 mInMethod = false;
102 }
103
handleStageEvent(Stage * stage)104 void TimerCancelTest::handleStageEvent(Stage *stage) {
105 if (!stage->expectCallback) {
106 sendFatalFailureToHost("Timer didn't cancel:", &stage->stage);
107 }
108 // Now we're going to cancel the timer, so we don't expect an
109 // additional call.
110 stage->expectCallback = false;
111
112 bool cancelSucceeded = chreTimerCancel(stage->timerId);
113 if (stage->oneShot) {
114 if (cancelSucceeded) {
115 sendFatalFailureToHost("Claimed success canceling one-shot after "
116 "it fired:", &stage->stage);
117 }
118 } else {
119 if (!cancelSucceeded) {
120 sendFatalFailureToHost("Unable to cancel recurring timer:",
121 &stage->stage);
122 }
123 }
124 if (chreTimerCancel(stage->timerId)) {
125 sendFatalFailureToHost("Claimed success in second cancel:",
126 &stage->stage);
127 }
128 markSuccess(stage->stage);
129 }
130
handleEvent(uint32_t senderInstanceId,uint16_t eventType,const void * eventData)131 void TimerCancelTest::handleEvent(uint32_t senderInstanceId,
132 uint16_t eventType, const void* eventData) {
133 if (mInMethod) {
134 sendFatalFailureToHost("handleEvent invoked while another nanoapp "
135 "method is running");
136 }
137 mInMethod = true;
138 if (senderInstanceId != CHRE_INSTANCE_ID) {
139 sendFatalFailureToHost("handleEvent got event from unexpected sender:",
140 &senderInstanceId);
141 }
142 if (eventType != CHRE_EVENT_TIMER) {
143 unexpectedEvent(eventType);
144 }
145 const Stage *stage = static_cast<const Stage*>(eventData);
146 if (stage->stage >= kStageCount) {
147 sendFatalFailureToHost("Invalid handleEvent data:", &stage->stage);
148 }
149 handleStageEvent(const_cast<Stage *>(stage));
150
151 mInMethod = false;
152 }
153
markSuccess(uint32_t stage)154 void TimerCancelTest::markSuccess(uint32_t stage) {
155 chreLog(CHRE_LOG_DEBUG, "Stage %" PRIu32 " succeeded", stage);
156 uint32_t finishedBit = (1 << stage);
157 if ((kAllFinished & finishedBit) == 0) {
158 sendFatalFailureToHost("markSuccess bad stage:", &stage);
159 }
160 if ((mFinishedBitmask & finishedBit) != 0) {
161 sendInternalFailureToHost("markSuccess multiple times:", &stage);
162 }
163 mFinishedBitmask |= finishedBit;
164 if (mFinishedBitmask == kAllFinished) {
165 sendSuccessToHost();
166 }
167 }
168
169 } // namespace general_test
170