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_stress_test.h>
18
19 #include <cinttypes>
20 #include <cstddef>
21
22 #include <shared/send_message.h>
23
24 #include <chre.h>
25
26 using nanoapp_testing::sendFatalFailureToHost;
27 using nanoapp_testing::sendInternalFailureToHost;
28 using nanoapp_testing::sendSuccessToHost;
29
30 /*
31 * We stress the system by setting more and more timers until the system
32 * runs out. We then cancel one (CT) and set a new timer post-cancel (NT).
33 * We make sure all the timers we set fire.
34 *
35 * Our stages are:
36 * Stage 0: Successfully cancel CT.
37 * Stage 1: All of our "exhaustion" timers fire.
38 * Stage 2: The new timer, NT, fires.
39 *
40 * After all of our stages have succeeded, we send success to the host. Note
41 * there is no system requirement that Stage 2 happens after Stage 1, so
42 * we use markSuccess() to track this.
43 */
44
45 // Allow 1000ms to create the large number of timers specified below. This
46 // equates to approximately 1ms per timer which should give ample time for
47 // timer creation to complete.
48 constexpr uint64_t kDuration = UINT64_C(1000000000);
49
50 // If the system keeps claiming it can set more timers, we don't let it
51 // continue forever. Instead, we'll cut it off at this limit. And then
52 // we'll call its bluff, and make sure that all of these timers legitimately
53 // fire. While it won't be an actual exhaustion test (we never took the
54 // system down to no more timers available), it will still give us confidence
55 // that this CHRE can properly handle any semi-reasonable timer load properly.
56 // 1030 is an arbitrary number, slightly over 2^10. The hope is this
57 // balances between catching incorrect behavior and the test taking too long.
58 constexpr int32_t kMaxTimersToSet = INT32_C(1030);
59
60 namespace general_test {
61
62 namespace {
63
64 const uint32_t kCookies[] = {0, 1, 2};
65
66 } // anonymous namespace
67
startStages()68 void TimerStressTest::startStages() {
69 uint32_t cancelId = chreTimerSet(kDuration, &kCookies[0], true);
70 if (cancelId == CHRE_TIMER_INVALID) {
71 sendFatalFailureToHost("No timers available");
72 }
73
74 mStage1CallbacksLeft = 0;
75 // We anticipate most CHREs will not reach kMaxTimersToSet.
76 while (mStage1CallbacksLeft < kMaxTimersToSet) {
77 if (chreTimerSet(kDuration, &kCookies[1], true) == CHRE_TIMER_INVALID) {
78 break;
79 }
80 mStage1CallbacksLeft++;
81 }
82 if (mStage1CallbacksLeft == 0) {
83 sendFatalFailureToHost("Insufficient timers available");
84 }
85 if (!chreTimerCancel(cancelId)) {
86 sendFatalFailureToHost("Unable to cancel timer");
87 }
88 markSuccess(0);
89 if (chreTimerSet(kDuration, &kCookies[2], true) == CHRE_TIMER_INVALID) {
90 sendFatalFailureToHost("Unable to set new timer after successful "
91 "cancel.");
92 }
93 }
94
TimerStressTest()95 TimerStressTest::TimerStressTest()
96 : Test(CHRE_API_VERSION_1_0),
97 mInMethod(false),
98 mFinishedBitmask(0),
99 mStage1CallbacksLeft(0) {
100 }
101
setUp(uint32_t messageSize,const void *)102 void TimerStressTest::setUp(uint32_t messageSize, const void * /* message */) {
103 mInMethod = true;
104
105 if (messageSize != 0) {
106 sendFatalFailureToHost(
107 "TimerStress message expects 0 additional bytes, got ",
108 &messageSize);
109 }
110
111 startStages();
112
113 mInMethod = false;
114 }
115
handleStageEvent(uint32_t index)116 void TimerStressTest::handleStageEvent(uint32_t index) {
117 switch (index) {
118 case 0:
119 sendFatalFailureToHost("Canceled timer fired:", &index);
120 break;
121
122 case 1:
123 --mStage1CallbacksLeft;
124 if (mStage1CallbacksLeft <= 0) {
125 markSuccess(index);
126 }
127 break;
128
129 case 2:
130 markSuccess(index);
131 break;
132
133 default:
134 sendFatalFailureToHost("Unexpected event stage:", &index);
135 }
136 }
137
handleEvent(uint32_t senderInstanceId,uint16_t eventType,const void * eventData)138 void TimerStressTest::handleEvent(uint32_t senderInstanceId,
139 uint16_t eventType, const void* eventData) {
140 if (mInMethod) {
141 sendFatalFailureToHost("handleEvent invoked while another nanoapp "
142 "method is running");
143 }
144 mInMethod = true;
145 if (senderInstanceId != CHRE_INSTANCE_ID) {
146 sendFatalFailureToHost("handleEvent got event from unexpected sender:",
147 &senderInstanceId);
148 }
149 if (eventType != CHRE_EVENT_TIMER) {
150 unexpectedEvent(eventType);
151 }
152
153 const uint32_t *data = static_cast<const uint32_t *>(eventData);
154 handleStageEvent(*data);
155
156 mInMethod = false;
157 }
158
markSuccess(uint32_t stage)159 void TimerStressTest::markSuccess(uint32_t stage) {
160 chreLog(CHRE_LOG_DEBUG, "Stage %" PRIu32 " succeeded", stage);
161 uint32_t finishedBit = (1 << stage);
162 if ((kAllFinished & finishedBit) == 0) {
163 sendFatalFailureToHost("markSuccess bad stage:", &stage);
164 }
165 if ((mFinishedBitmask & finishedBit) != 0) {
166 sendFatalFailureToHost("timer over-triggered:", &stage);
167 }
168 mFinishedBitmask |= finishedBit;
169 if (mFinishedBitmask == kAllFinished) {
170 sendSuccessToHost();
171 }
172 }
173
174
175 } // namespace general_test
176