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