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/heap_exhaustion_stability_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::kOneSecondInNanoseconds;
29 using nanoapp_testing::sendFailureToHost;
30 using nanoapp_testing::sendFatalFailureToHost;
31 using nanoapp_testing::sendSuccessToHost;
32
33 /*
34 * We set an "exhaustion timer" to go off when we're ready for the test to
35 * be over. Then we exhaust the heap.
36 *
37 * We try a series of chre*() calls with the heap exhausted. For many of
38 * these calls, we're less interested in them succeeding than in the system
39 * just not crashing. However, for things which claim success, we require
40 * they succeed.
41 *
42 * To track the things which claim success, we have two "stages", kTimerStage
43 * and kEventStage.
44 *
45 * When the "exhaustion timer" fires, we free our memory, and make sure our
46 * stages have all succeeded.
47 */
48
49 namespace general_test {
50
51 // Note: We use pointers to the 'duration' to serve as our timer event data.
52 // Thus we make this "static const" instead of "constexpr", as we expect
53 // them to have backing memory.
54
55 static const uint64_t kExhaustionDuration = 5 * kOneSecondInNanoseconds;
56 static const uint64_t kShortDuration = 10 * kOneMillisecondInNanoseconds;
57
58 constexpr uint16_t kEventType = CHRE_EVENT_FIRST_USER_VALUE;
59
60 constexpr uint32_t kTimerStage = 0;
61 constexpr uint32_t kEventStage = 1;
62
exhaustHeap()63 void HeapExhaustionStabilityTest::exhaustHeap() {
64 constexpr size_t kNumPtrs = 256;
65 mExhaustionPtrs = reinterpret_cast<void**>(
66 chreHeapAlloc(kNumPtrs * sizeof(*mExhaustionPtrs)));
67 if (mExhaustionPtrs == nullptr) {
68 // Oh, the irony.
69 sendFatalFailureToHost(
70 "Insufficient free heap to exhaust the heap.");
71 }
72
73 // We start by trying to allocate massive sizes (256MB to start).
74 // When we're not able to allocate massive sizes, we cut the size in
75 // half. We repeat until we've either done kNumPtrs allocations,
76 // or reduced our allocation size below 16 bytes.
77 uint32_t allocSize = 1024 * 1024 * 256;
78 for (mExhaustionPtrCount = 0;
79 mExhaustionPtrCount < kNumPtrs;
80 mExhaustionPtrCount++) {
81 void *ptr = chreHeapAlloc(allocSize);
82 while (ptr == nullptr) {
83 allocSize /= 2;
84 if (allocSize < 4) {
85 break;
86 }
87 ptr = chreHeapAlloc(allocSize);
88 }
89 if (ptr == nullptr) {
90 break;
91 }
92 mExhaustionPtrs[mExhaustionPtrCount] = ptr;
93 }
94 if (mExhaustionPtrCount == 0) {
95 sendFatalFailureToHost(
96 "Failed to allocate anything for heap exhaustion");
97 }
98 }
99
freeMemory()100 void HeapExhaustionStabilityTest::freeMemory() {
101 for (size_t i = 0; i < mExhaustionPtrCount; i++) {
102 chreHeapFree(mExhaustionPtrs[i]);
103 }
104 chreHeapFree(mExhaustionPtrs);
105 }
106
HeapExhaustionStabilityTest()107 HeapExhaustionStabilityTest::HeapExhaustionStabilityTest()
108 : Test(CHRE_API_VERSION_1_0) {
109 }
110
setUp(uint32_t messageSize,const void *)111 void HeapExhaustionStabilityTest::setUp(uint32_t messageSize,
112 const void * /* message */) {
113 mInMethod = true;
114 if (messageSize != 0) {
115 sendFatalFailureToHost(
116 "HeapExhaustionStability message expects 0 additional bytes, "
117 "got ", &messageSize);
118 }
119
120 if (chreTimerSet(kExhaustionDuration, &kExhaustionDuration, true) ==
121 CHRE_TIMER_INVALID) {
122 sendFatalFailureToHost("Unable to set initial timer");
123 }
124
125 exhaustHeap();
126
127 testLog(messageSize);
128 testSetTimer();
129 testSendEvent();
130 testSensor();
131 // TODO(b/32114261): This method currently doesn't test anything.
132 testMessageToHost();
133
134 // Some of the above 'test' methods might trigger events. Even if they
135 // don't, the kExhaustionDuration timer we set earlier should trigger
136 // eventually, and that's when we'll conclude the test.
137 mInMethod = false;
138 }
139
testLog(uint32_t zero)140 void HeapExhaustionStabilityTest::testLog(uint32_t zero) {
141 // This doesn't need to land in the log (and indeed we have no automated
142 // means of checking that right now anyway), but it shouldn't crash.
143 chreLog(CHRE_LOG_INFO, "Test log %s, zero: %" PRId32, "message", zero);
144 }
145
testSetTimer()146 void HeapExhaustionStabilityTest::testSetTimer() {
147 if (chreTimerSet(kShortDuration, &kShortDuration, true) !=
148 CHRE_TIMER_INVALID) {
149 // CHRE claims we were able to set this timer. We'll
150 // mark this stage a success when the timer fires.
151 } else {
152 // CHRE was not able to set this timer. That's okay, since we're
153 // out of heap. We'll mark this stage as a success.
154 markSuccess(kTimerStage);
155 }
156 }
157
testSendEvent()158 void HeapExhaustionStabilityTest::testSendEvent() {
159 if (chreSendEvent(kEventType, nullptr, nullptr, chreGetInstanceId())) {
160 // CHRE claims we were able to send this event. We'll make
161 // this stage a success when the event is received.
162 } else {
163 // CHRE was not able to send this event. That's okay, since we're
164 // out of heap. We'll mark this stage as a success.
165 markSuccess(kEventStage);
166 }
167 }
168
testSensor()169 void HeapExhaustionStabilityTest::testSensor() {
170 static constexpr uint8_t kSensorType = CHRE_SENSOR_TYPE_ACCELEROMETER;
171 uint32_t handle;
172 if (!chreSensorFindDefault(kSensorType, &handle)) {
173 // We still expect this to succeed without any heap left.
174 sendFatalFailureToHost("chreSensorFindDefault failed");
175 }
176 chreSensorInfo info;
177 if (!chreGetSensorInfo(handle, &info)) {
178 // We still expect this to succeed, since we're supplying the memory.
179 sendFatalFailureToHost("chreGetSensorInfo failed");
180 }
181 if (info.sensorType != kSensorType) {
182 sendFatalFailureToHost("Invalid sensor info provided");
183 }
184
185 chreSensorSamplingStatus samplingStatus;
186 if (!chreGetSensorSamplingStatus(handle, &samplingStatus)) {
187 // We still expect this to succeed, since we're supplying the memory.
188 sendFatalFailureToHost("chreGetSensorSamplingStatus failed");
189 }
190
191 // TODO: We might want to consider calling chreSensorConfigure() for a
192 // more robust test of this. However, we don't expect sensor events to
193 // necessarily get delivered under heap exhaustion, so it's unclear
194 // how we'd make sure we eventually tell the system we're DONE with
195 // the sensor (setting a timer isn't assured to work at this point).
196 }
197
testMessageToHost()198 void HeapExhaustionStabilityTest::testMessageToHost() {
199 // TODO(b/32114261): We should invoke sendMessageToHost() here.
200 // Unfortunately, this is a real pain due to this bug, as we need to
201 // duplicate much of the contents of shared/send_message.cc to
202 // add the hack-around bytes (the method itself will internally
203 // fail if the send attempt fails, but we're in a state where
204 // we'll allow a failed send attempt). Or we need to take this
205 // off of the General test infrastructure to allow raw byte sending.
206 // That seems not worth the effort for NYC, and just easier to wait
207 // until OMC when this is much easier to implement.
208 // OMC Note: When we've fixed this bug, and added a send here, we'll
209 // need to make this no longer Simple protocol, since this nanoapp
210 // might send a message.
211 }
212
handleEvent(uint32_t senderInstanceId,uint16_t eventType,const void * eventData)213 void HeapExhaustionStabilityTest::handleEvent(uint32_t senderInstanceId,
214 uint16_t eventType,
215 const void* eventData) {
216 if (mInMethod) {
217 sendFatalFailureToHost("handleEvent invoked while another nanoapp "
218 "method is running");
219 }
220 mInMethod = true;
221
222 if (eventType == CHRE_EVENT_TIMER) {
223 handleTimer(senderInstanceId, eventData);
224 } else if (eventType == kEventType) {
225 handleSelfEvent(senderInstanceId, eventData);
226 } else {
227 unexpectedEvent(eventType);
228 }
229 mInMethod = false;
230 }
231
handleTimer(uint32_t senderInstanceId,const void * eventData)232 void HeapExhaustionStabilityTest::handleTimer(uint32_t senderInstanceId,
233 const void *eventData) {
234 if (senderInstanceId != CHRE_INSTANCE_ID) {
235 sendFatalFailureToHost("handleTimer with unexpected sender:",
236 &senderInstanceId);
237 }
238 if (eventData == &kShortDuration) {
239 // This was the timer we triggered while the heap was exhausted.
240 markSuccess(kTimerStage);
241
242 } else if (eventData == &kExhaustionDuration) {
243 // Our test is done.
244 freeMemory();
245 if (mFinishedBitmask != kAllFinished) {
246 sendFatalFailureToHost("Done with test, but not all stages "
247 "done.", &mFinishedBitmask);
248 }
249 sendSuccessToHost();
250
251 } else {
252 sendFatalFailureToHost("Unexpected timer eventData");
253 }
254 }
255
handleSelfEvent(uint32_t senderInstanceId,const void * eventData)256 void HeapExhaustionStabilityTest::handleSelfEvent(uint32_t senderInstanceId,
257 const void *eventData) {
258 if (senderInstanceId != chreGetInstanceId()) {
259 sendFatalFailureToHost("handleSelfEvent with unexpected sender:",
260 &senderInstanceId);
261 }
262 if (eventData != nullptr) {
263 sendFatalFailureToHost("Unexpected data for event to self");
264 }
265 markSuccess(kEventStage);
266 }
267
markSuccess(uint32_t stage)268 void HeapExhaustionStabilityTest::markSuccess(uint32_t stage) {
269 chreLog(CHRE_LOG_DEBUG, "Stage %" PRIu32 " succeeded", stage);
270 uint32_t finishedBit = (1 << stage);
271 if ((kAllFinished & finishedBit) == 0) {
272 sendFatalFailureToHost("markSuccess bad stage", &stage);
273 }
274 if ((mFinishedBitmask & finishedBit) != 0) {
275 // This could be when a timer/event method returned 'false', but
276 // actually did end up triggering an event.
277 sendFatalFailureToHost("markSuccess stage triggered twice", &stage);
278 }
279 mFinishedBitmask |= finishedBit;
280 // Note that unlike many markSuccess() implementations, we do not
281 // check against kAllFinished here. That happens when the
282 // timer for kExhaustionDuration fires.
283 }
284
285
286 } // namespace general_test
287