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