/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <general_test/send_event_test.h>
#include <cstddef>
#include <shared/abort.h>
#include <shared/array_length.h>
#include <shared/send_message.h>
#include <chre.h>
using nanoapp_testing::sendFatalFailureToHost;
using nanoapp_testing::sendSuccessToHost;
/*
* In a properly running test, we'll invoke chreSendEvent() a total of 12 times.
* We initially send eight events upon startup. And then for each of our four
* events which has a non-nullptr completeCallback, we call chreSendEvent()
* from that callback.
*
* For our first eight events, they will either be kEventType0 or kEventType1.
* They will either use completeCallback0 or completeCallback1. They have
* various data. This table describes them all:
*
* num | eventType | data | Callback
* ----|-----------|------------|---------
* 0 | 0 | ptr to num | 0
* 1 | 0 | ptr to num | 1
* 2 | 1 | ptr to num | 0
* 3 | 1 | ptr to num | 1
* 4 | 0 | ptr to num | nullptr
* 5 | 1 | ptr to num | nullptr
* 6 | 0 | nullptr | nullptr
* 7 | 1 | kOddData | nullptr
*
* The other four events are all kEventTypeCallback with nullptr data and
* nullptr callback.
*/
constexpr uint16_t kEventType0 = CHRE_EVENT_FIRST_USER_VALUE + 0;
constexpr uint16_t kEventType1 = CHRE_EVENT_FIRST_USER_VALUE + 1;
constexpr uint16_t kEventTypeCallback = CHRE_EVENT_FIRST_USER_VALUE + 2;
// NOTE: This is not allowed to be constexpr, even if some version of g++/clang
// allow it.
static void *kOddData = reinterpret_cast<void*>(-1);
namespace general_test {
bool SendEventTest::sInMethod = false;
uint8_t SendEventTest::sCallbacksInvoked = 0;
template<uint8_t kCallbackIndex>
void SendEventTest::completeCallback(uint16_t eventType, void *data) {
if (sInMethod) {
sendFatalFailureToHost("completeCallback called while another nanoapp "
"method is running.");
}
sInMethod = true;
if ((data == nullptr) || (data == kOddData)) {
sendFatalFailureToHost(
"completeCallback called with nullptr or odd data.");
}
uint32_t num = *(reinterpret_cast<uint32_t*>(data));
uint16_t expectedEventType = 0xFFFF;
uint8_t expectedCallbackIndex = 0xFF;
switch (num) {
case 0:
expectedEventType = kEventType0;
expectedCallbackIndex = 0;
break;
case 1:
expectedEventType = kEventType0;
expectedCallbackIndex = 1;
break;
case 2:
expectedEventType = kEventType1;
expectedCallbackIndex = 0;
break;
case 3:
expectedEventType = kEventType1;
expectedCallbackIndex = 1;
break;
default:
sendFatalFailureToHost("completeCallback given bad data.", &num);
}
if (expectedEventType != eventType) {
sendFatalFailureToHost("completeCallback bad/eventType mismatch.");
}
if (expectedCallbackIndex != kCallbackIndex) {
sendFatalFailureToHost("Incorrect callback function called.");
}
uint8_t mask = static_cast<uint8_t>(1 << num);
if ((sCallbacksInvoked & mask) != 0) {
sendFatalFailureToHost("Complete callback invoked multiple times for ",
&num);
}
sCallbacksInvoked |= mask;
if (!chreSendEvent(kEventTypeCallback, nullptr, nullptr,
chreGetInstanceId())) {
sendFatalFailureToHost("Failed chreSendEvent in callback.");
}
sInMethod = false;
}
void SendEventTest::completeCallback0(uint16_t eventType, void *data) {
completeCallback<0>(eventType, data);
}
void SendEventTest::completeCallback1(uint16_t eventType, void *data) {
completeCallback<1>(eventType, data);
}
SendEventTest::SendEventTest()
: Test(CHRE_API_VERSION_1_0) , mNextNum(0) {
}
void SendEventTest::setUp(uint32_t messageSize, const void * /* message */) {
sInMethod = true;
if (messageSize != 0) {
sendFatalFailureToHost(
"SendEvent message expects 0 additional bytes, got ",
&messageSize);
}
const uint32_t id = chreGetInstanceId();
for (uint32_t i = 0; i < arrayLength(mData); i++) {
mData[i] = i;
}
// num: 0
if (!chreSendEvent(kEventType0, &mData[0], completeCallback0, id)) {
sendFatalFailureToHost("Failed chreSendEvent num 0");
}
// num: 1
if (!chreSendEvent(kEventType0, &mData[1], completeCallback1, id)) {
sendFatalFailureToHost("Failed chreSendEvent num 1");
}
// num: 2
if (!chreSendEvent(kEventType1, &mData[2], completeCallback0, id)) {
sendFatalFailureToHost("Failed chreSendEvent num 2");
}
// num: 3
if (!chreSendEvent(kEventType1, &mData[3], completeCallback1, id)) {
sendFatalFailureToHost("Failed chreSendEvent num 3");
}
// num: 4
if (!chreSendEvent(kEventType0, &mData[4], nullptr, id)) {
sendFatalFailureToHost("Failed chreSendEvent num 4");
}
// num: 5
if (!chreSendEvent(kEventType1, &mData[5], nullptr, id)) {
sendFatalFailureToHost("Failed chreSendEvent num 5");
}
// num: 6
if (!chreSendEvent(kEventType0, nullptr, nullptr, id)) {
sendFatalFailureToHost("Failed chreSendEvent num 6");
}
// num: 7
if (!chreSendEvent(kEventType1, kOddData, nullptr, id)) {
sendFatalFailureToHost("Failed chreSendEvent num 7");
}
sInMethod = false;
}
void SendEventTest::handleEvent(uint32_t senderInstanceId,
uint16_t eventType, const void* eventData) {
if (sInMethod) {
sendFatalFailureToHost("handleEvent invoked while another nanoapp "
"method is running");
}
sInMethod = true;
if (senderInstanceId != chreGetInstanceId()) {
sendFatalFailureToHost("handleEvent got event from unexpected sender:",
&senderInstanceId);
}
if (mNextNum < 8) {
void *expectedData;
if (mNextNum < 6) {
expectedData = &mData[mNextNum];
} else if (mNextNum == 6) {
expectedData = nullptr;
} else {
expectedData = kOddData;
}
uint16_t expectedEventType = 0xFFFF;
switch (mNextNum) {
case 0:
case 1:
case 4:
case 6:
expectedEventType = kEventType0;
break;
case 2:
case 3:
case 5:
case 7:
expectedEventType = kEventType1;
break;
}
if (expectedEventType != eventType) {
sendFatalFailureToHost("Incorrect event type sent for num ",
&mNextNum);
}
if (expectedData != eventData) {
sendFatalFailureToHost("Incorrect data sent for num ", &mNextNum);
}
} else {
if (eventType != kEventTypeCallback) {
sendFatalFailureToHost("Unexpected event type for num ", &mNextNum);
}
if (mNextNum == 11) {
// This was our last callback. Everything is good.
sendSuccessToHost();
}
}
mNextNum++;
sInMethod = false;
}
} // namespace general_test