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