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/macros.h>
23 #include <shared/send_message.h>
24 #include <shared/time_util.h>
25
26 #include "chre/util/nanoapp/log.h"
27 #include "chre_api/chre.h"
28
29 #define LOG_TAG "[HeapExhaustionStabilityTest]"
30
31 using nanoapp_testing::kOneMillisecondInNanoseconds;
32 using nanoapp_testing::kOneSecondInNanoseconds;
33 using nanoapp_testing::sendFailureToHost;
34
35 using nanoapp_testing::sendSuccessToHost;
36
37 /*
38 * We set an "exhaustion timer" to go off when we're ready for the test to
39 * be over. Then we exhaust the heap.
40 *
41 * We try a series of chre*() calls with the heap exhausted. For many of
42 * these calls, we're less interested in them succeeding than in the system
43 * just not crashing. However, for things which claim success, we require
44 * they succeed.
45 *
46 * To track the things which claim success, we have two "stages", kTimerStage
47 * and kEventStage.
48 *
49 * When the "exhaustion timer" fires, we free our memory, and make sure our
50 * stages have all succeeded.
51 */
52
53 namespace general_test {
54
55 // Note: We use pointers to the 'duration' to serve as our timer event data.
56 // Thus we make this "static const" instead of "constexpr", as we expect
57 // them to have backing memory.
58
59 static const uint64_t kExhaustionDuration = 5 * kOneSecondInNanoseconds;
60 static const uint64_t kShortDuration = 10 * kOneMillisecondInNanoseconds;
61
62 constexpr uint16_t kEventType = CHRE_EVENT_FIRST_USER_VALUE;
63
64 constexpr uint32_t kTimerStage = 0;
65 constexpr uint32_t kEventStage = 1;
66
exhaustHeap()67 void HeapExhaustionStabilityTest::exhaustHeap() {
68 constexpr size_t kNumPtrs = 256;
69 mExhaustionPtrs = reinterpret_cast<void **>(
70 chreHeapAlloc(kNumPtrs * sizeof(*mExhaustionPtrs)));
71 if (mExhaustionPtrs == nullptr) {
72 // Oh, the irony.
73 EXPECT_FAIL_RETURN("Insufficient free heap to exhaust the heap.");
74 }
75
76 // We start by trying to allocate massive sizes (256MB to start).
77 // When we're not able to allocate massive sizes, we cut the size in
78 // half. We repeat until we've either done kNumPtrs allocations,
79 // or reduced our allocation size below 16 bytes.
80 uint32_t allocSize = 1024 * 1024 * 256;
81 for (mExhaustionPtrCount = 0; mExhaustionPtrCount < kNumPtrs;
82 mExhaustionPtrCount++) {
83 void *ptr = chreHeapAlloc(allocSize);
84 while (ptr == nullptr) {
85 allocSize /= 2;
86 if (allocSize < 4) {
87 break;
88 }
89 ptr = chreHeapAlloc(allocSize);
90 }
91 if (ptr == nullptr) {
92 break;
93 }
94 mExhaustionPtrs[mExhaustionPtrCount] = ptr;
95 }
96 if (mExhaustionPtrCount == 0) {
97 EXPECT_FAIL_RETURN("Failed to allocate anything for heap exhaustion");
98 }
99 }
100
freeMemory()101 void HeapExhaustionStabilityTest::freeMemory() {
102 for (size_t i = 0; i < mExhaustionPtrCount; i++) {
103 chreHeapFree(mExhaustionPtrs[i]);
104 }
105 chreHeapFree(mExhaustionPtrs);
106 }
107
HeapExhaustionStabilityTest()108 HeapExhaustionStabilityTest::HeapExhaustionStabilityTest()
109 : Test(CHRE_API_VERSION_1_0) {}
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 EXPECT_FAIL_RETURN(
116 "HeapExhaustionStability message expects 0 additional bytes, got ",
117 &messageSize);
118 }
119
120 if (chreTimerSet(kExhaustionDuration, &kExhaustionDuration, true) ==
121 CHRE_TIMER_INVALID) {
122 EXPECT_FAIL_RETURN("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 LOGI("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 EXPECT_FAIL_RETURN("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 EXPECT_FAIL_RETURN("chreGetSensorInfo failed");
180 }
181 if (info.sensorType != kSensorType) {
182 EXPECT_FAIL_RETURN("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 EXPECT_FAIL_RETURN("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 EXPECT_FAIL_RETURN(
218 "handleEvent invoked while another nanoapp 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 EXPECT_FAIL_RETURN("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 EXPECT_FAIL_RETURN("Done with test, but not all stages done.",
247 &mFinishedBitmask);
248 }
249 sendSuccessToHost();
250
251 } else {
252 EXPECT_FAIL_RETURN("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 EXPECT_FAIL_RETURN("handleSelfEvent with unexpected sender:",
260 &senderInstanceId);
261 }
262 if (eventData != nullptr) {
263 EXPECT_FAIL_RETURN("Unexpected data for event to self");
264 }
265 markSuccess(kEventStage);
266 }
267
markSuccess(uint32_t stage)268 void HeapExhaustionStabilityTest::markSuccess(uint32_t stage) {
269 LOGD("Stage %" PRIu32 " succeeded", stage);
270 uint32_t finishedBit = (1 << stage);
271 if ((kAllFinished & finishedBit) == 0) {
272 EXPECT_FAIL_RETURN("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 EXPECT_FAIL_RETURN("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 } // namespace general_test
286