普通文本  |  251行  |  7.28 KB

/*
 * 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