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