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
67 // clang-format off
TimerCancelTest()68 TimerCancelTest::TimerCancelTest()
69 : Test(CHRE_API_VERSION_1_0),
70 mInMethod(false),
71 mStages{
72 // expectCallback:false ==> We're canceling before the timer fires.
73 // expectCallback:true ==> We'll cancel after the timer fires once.
74 //
75 // stage, oneShot, expectCallback
76 Stage(0, false, false),
77 Stage(1, true, false),
78 Stage(2, false, true ),
79 Stage(3, true, true )},
80 mFinishedBitmask(0) {}
81 // clang-format on
82
setUp(uint32_t messageSize,const void *)83 void TimerCancelTest::setUp(uint32_t messageSize, const void * /* message */) {
84 mInMethod = true;
85
86 if (messageSize != 0) {
87 sendFatalFailureToHost(
88 "TimerCancel message expects 0 additional bytes, got ", &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(
116 "Claimed success canceling one-shot after 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:", &stage->stage);
126 }
127 markSuccess(stage->stage);
128 }
129
handleEvent(uint32_t senderInstanceId,uint16_t eventType,const void * eventData)130 void TimerCancelTest::handleEvent(uint32_t senderInstanceId, uint16_t eventType,
131 const void *eventData) {
132 if (mInMethod) {
133 sendFatalFailureToHost(
134 "handleEvent invoked while another nanoapp method is running");
135 }
136 mInMethod = true;
137 if (senderInstanceId != CHRE_INSTANCE_ID) {
138 sendFatalFailureToHost("handleEvent got event from unexpected sender:",
139 &senderInstanceId);
140 }
141 if (eventType != CHRE_EVENT_TIMER) {
142 unexpectedEvent(eventType);
143 }
144 const Stage *stage = static_cast<const Stage *>(eventData);
145 if (stage->stage >= kStageCount) {
146 sendFatalFailureToHost("Invalid handleEvent data:", &stage->stage);
147 }
148 handleStageEvent(const_cast<Stage *>(stage));
149
150 mInMethod = false;
151 }
152
markSuccess(uint32_t stage)153 void TimerCancelTest::markSuccess(uint32_t stage) {
154 chreLog(CHRE_LOG_DEBUG, "Stage %" PRIu32 " succeeded", stage);
155 uint32_t finishedBit = (1 << stage);
156 if ((kAllFinished & finishedBit) == 0) {
157 sendFatalFailureToHost("markSuccess bad stage:", &stage);
158 }
159 if ((mFinishedBitmask & finishedBit) != 0) {
160 sendInternalFailureToHost("markSuccess multiple times:", &stage);
161 }
162 mFinishedBitmask |= finishedBit;
163 if (mFinishedBitmask == kAllFinished) {
164 sendSuccessToHost();
165 }
166 }
167
168 } // namespace general_test
169