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