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 cancel.");
91 }
92 }
93
TimerStressTest()94 TimerStressTest::TimerStressTest()
95 : Test(CHRE_API_VERSION_1_0),
96 mInMethod(false),
97 mFinishedBitmask(0),
98 mStage1CallbacksLeft(0) {}
99
setUp(uint32_t messageSize,const void *)100 void TimerStressTest::setUp(uint32_t messageSize, const void * /* message */) {
101 mInMethod = true;
102
103 if (messageSize != 0) {
104 sendFatalFailureToHost(
105 "TimerStress message expects 0 additional bytes, got ", &messageSize);
106 }
107
108 startStages();
109
110 mInMethod = false;
111 }
112
handleStageEvent(uint32_t index)113 void TimerStressTest::handleStageEvent(uint32_t index) {
114 switch (index) {
115 case 0:
116 sendFatalFailureToHost("Canceled timer fired:", &index);
117 break;
118
119 case 1:
120 --mStage1CallbacksLeft;
121 if (mStage1CallbacksLeft <= 0) {
122 markSuccess(index);
123 }
124 break;
125
126 case 2:
127 markSuccess(index);
128 break;
129
130 default:
131 sendFatalFailureToHost("Unexpected event stage:", &index);
132 }
133 }
134
handleEvent(uint32_t senderInstanceId,uint16_t eventType,const void * eventData)135 void TimerStressTest::handleEvent(uint32_t senderInstanceId, uint16_t eventType,
136 const void *eventData) {
137 if (mInMethod) {
138 sendFatalFailureToHost(
139 "handleEvent invoked while another nanoapp method is running");
140 }
141 mInMethod = true;
142 if (senderInstanceId != CHRE_INSTANCE_ID) {
143 sendFatalFailureToHost("handleEvent got event from unexpected sender:",
144 &senderInstanceId);
145 }
146 if (eventType != CHRE_EVENT_TIMER) {
147 unexpectedEvent(eventType);
148 }
149
150 const uint32_t *data = static_cast<const uint32_t *>(eventData);
151 handleStageEvent(*data);
152
153 mInMethod = false;
154 }
155
markSuccess(uint32_t stage)156 void TimerStressTest::markSuccess(uint32_t stage) {
157 chreLog(CHRE_LOG_DEBUG, "Stage %" PRIu32 " succeeded", stage);
158 uint32_t finishedBit = (1 << stage);
159 if ((kAllFinished & finishedBit) == 0) {
160 sendFatalFailureToHost("markSuccess bad stage:", &stage);
161 }
162 if ((mFinishedBitmask & finishedBit) != 0) {
163 sendFatalFailureToHost("timer over-triggered:", &stage);
164 }
165 mFinishedBitmask |= finishedBit;
166 if (mFinishedBitmask == kAllFinished) {
167 sendSuccessToHost();
168 }
169 }
170
171 } // namespace general_test
172