普通文本  |  297行  |  10.55 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 <cstddef>  // max_align_t
#include <cstdint>
#include <new>  // placement new

#include <chre.h>

#include <general_test/basic_audio_test.h>
#include <general_test/basic_gnss_test.h>
#include <general_test/basic_sensor_tests.h>
#include <general_test/basic_wifi_test.h>
#include <general_test/estimated_host_time_test.h>
#include <general_test/event_between_apps_test.h>
#include <general_test/get_time_test.h>
#include <general_test/gnss_capabilities_test.h>
#include <general_test/heap_alloc_stress_test.h>
#include <general_test/heap_exhaustion_stability_test.h>
#include <general_test/hello_world_test.h>
#include <general_test/host_awake_suspend_test.h>
#include <general_test/logging_sanity_test.h>
#include <general_test/nanoapp_info_by_app_id_test.h>
#include <general_test/nanoapp_info_by_instance_id_test.h>
#include <general_test/nanoapp_info_events_test_observer.h>
#include <general_test/nanoapp_info_events_test_performer.h>
#include <general_test/send_event_test.h>
#include <general_test/send_event_stress_test.h>
#include <general_test/send_message_to_host_test.h>
#include <general_test/sensor_info_test.h>
#include <general_test/simple_heap_alloc_test.h>
#include <general_test/test.h>
#include <general_test/test_names.h>
#include <general_test/timer_cancel_test.h>
#include <general_test/timer_set_test.h>
#include <general_test/timer_stress_test.h>
#include <general_test/version_sanity_test.h>
#include <general_test/wifi_capabilities_test.h>
#include <general_test/wwan_capabilities_test.h>
#include <general_test/wwan_cell_info_test.h>
#include <shared/abort.h>
#include <shared/nano_endian.h>
#include <shared/nano_string.h>
#include <shared/send_message.h>

using nanoapp_testing::AbortBlame;
using nanoapp_testing::MessageType;
using nanoapp_testing::sendFatalFailureToHost;
using nanoapp_testing::sendInternalFailureToHost;


namespace general_test {

// The size of this array is checked at compile time by the static_assert
// in getNew().
alignas(alignof(max_align_t)) static uint8_t gGetNewBackingMemory[128];

template<typename N>
static N *getNew() {
  // We intentionally avoid using chreHeapAlloc() to reduce dependencies
  // for our tests, especially things like HelloWorld.  This obviously
  // cannot be called more than once, but our usage doesn't require it.
  static_assert(sizeof(gGetNewBackingMemory) >= sizeof(N),
                "getNew() backing memory is undersized");

  return new(gGetNewBackingMemory) N();
}

// TODO(b/32114261): Remove this variable.
bool gUseNycMessageHack = true;

class App {
 public:
  App() : mConstructionCookie(kConstructed),
          mCurrentTest(nullptr) {}

  ~App() {
    // Yes, it's very odd to actively set a value in our destructor.
    // However, since we're making a static instance of this class,
    // the space for this class will stick around (unlike heap memory
    // which might get reused), so we can still use this to perform
    // some testing.
    mConstructionCookie = kDestructed;
  }

  bool wasConstructed() const { return mConstructionCookie == kConstructed; }
  bool wasDestructed() const { return mConstructionCookie == kDestructed; }

  void handleEvent(uint32_t senderInstanceId, uint16_t eventType,
                   const void *eventData);

  void createTest(const void *eventData);
  void freeTest();

 private:
  uint32_t mConstructionCookie;
  Test *mCurrentTest;

  static constexpr uint32_t kConstructed = UINT32_C(0x51501984);
  static constexpr uint32_t kDestructed = UINT32_C(0x19845150);

  // TODO(b/32114261): Remove this method.
  chreMessageFromHostData
      adjustHostMessageForNYC(const chreMessageFromHostData *data);
};


// In the NYC version of the CHRE, the "reservedMessageType" isn't
// assured to be sent correctly from the host.  But we want our
// tests to be written using this field (it's cleaner).  So in NYC
// the host prefixes this value in the first four bytes of 'message',
// and here we reconstruct the message to be correct.
// TODO(b/32114261): Remove this method.
chreMessageFromHostData
App::adjustHostMessageForNYC(const chreMessageFromHostData *data) {
  if (!gUseNycMessageHack) {
    return *data;
  }
  chreMessageFromHostData ret;

  if (data->messageSize < sizeof(uint32_t)) {
    sendFatalFailureToHost("Undersized message in adjustHostMessageForNYC");
  }
  const uint8_t *messageBytes = static_cast<const uint8_t*>(data->message);
  nanoapp_testing::memcpy(&(ret.reservedMessageType), messageBytes,
                          sizeof(ret.reservedMessageType));
  ret.reservedMessageType =
      nanoapp_testing::littleEndianToHost(ret.reservedMessageType);
  ret.messageSize = data->messageSize - sizeof(ret.reservedMessageType);
  ret.message = messageBytes + sizeof(ret.reservedMessageType);
  return ret;
}


void App::handleEvent(uint32_t senderInstanceId, uint16_t eventType,
                      const void* eventData) {
  // TODO: When we get an API that fixes the reservedMessageType,
  //       then we should only use our adjustedData hack on APIs
  //       prior to it being fixed.  Eventually, we should remove
  //       this altogether.
  chreMessageFromHostData adjustedData;
  if (eventType == CHRE_EVENT_MESSAGE_FROM_HOST) {
    auto data = static_cast<const chreMessageFromHostData *>(eventData);
    adjustedData = adjustHostMessageForNYC(data);
    eventData = &adjustedData;
  }

  if (mCurrentTest != nullptr) {
    // Our test is in progress, so let it take control.
    mCurrentTest->testHandleEvent(senderInstanceId, eventType, eventData);
    return;
  }

  // No test in progress, so we expect this message to be the host telling
  // us which test to run.  We fail if it's anything else.
  if (eventType != CHRE_EVENT_MESSAGE_FROM_HOST) {
    uint32_t localEventType = eventType;
    sendFatalFailureToHost(
        "Unexpected event type with no established test:",
        &localEventType);
  }
  if (senderInstanceId != CHRE_INSTANCE_ID) {
    sendFatalFailureToHost(
        "Got MESSAGE_FROM_HOST not from CHRE_INSTANCE_ID:",
        &senderInstanceId);
  }
  createTest(eventData);
}

void App::createTest(const void *eventData) {
  if (mCurrentTest != nullptr) {
    sendInternalFailureToHost(
        "Got to createTest() with non-null mCurrentTest");
  }

  auto data = static_cast<const chreMessageFromHostData *>(eventData);
  switch (static_cast<TestNames>(data->reservedMessageType)) {
    using namespace general_test;

#define CASE(testName, className) \
    case TestNames::testName: \
         mCurrentTest = getNew<className>(); \
         break;

    CASE(kHelloWorld, HelloWorldTest);
    CASE(kSimpleHeapAlloc, SimpleHeapAllocTest);
    CASE(kHeapAllocStress, HeapAllocStressTest);
    CASE(kGetTime, GetTimeTest);
    CASE(kEventBetweenApps0, EventBetweenApps0);
    CASE(kEventBetweenApps1, EventBetweenApps1);
    CASE(kSendEvent, SendEventTest);
    CASE(kBasicAccelerometer, BasicAccelerometerTest);
    CASE(kBasicInstantMotionDetect, BasicInstantMotionDetectTest);
    CASE(kBasicStationaryDetect, BasicStationaryDetectTest);
    CASE(kBasicGyroscope, BasicGyroscopeTest);
    CASE(kBasicMagnetometer, BasicMagnetometerTest);
    CASE(kBasicBarometer, BasicBarometerTest);
    CASE(kBasicLightSensor, BasicLightSensorTest);
    CASE(kBasicProximity, BasicProximityTest);
    CASE(kVersionSanity, VersionSanityTest);
    CASE(kLoggingSanity, LoggingSanityTest);
    CASE(kSendMessageToHost, SendMessageToHostTest);
    CASE(kTimerSet, TimerSetTest);
    CASE(kTimerCancel, TimerCancelTest);
    CASE(kTimerStress, TimerStressTest);
    CASE(kSendEventStress, SendEventStressTest);
    CASE(kHeapExhaustionStability, HeapExhaustionStabilityTest);
    CASE(kGnssCapabilities, GnssCapabilitiesTest);
    CASE(kWifiCapabilities, WifiCapabilitiesTest);
    CASE(kWwanCapabilities, WwanCapabilitiesTest);
    CASE(kSensorInfo, SensorInfoTest);
    CASE(kWwanCellInfoTest, WwanCellInfoTest);
    CASE(kEstimatedHostTime, EstimatedHostTimeTest);
    CASE(kNanoappInfoByAppId, NanoappInfoByAppIdTest);
    CASE(kNanoappInfoByInstanceId, NanoappInfoByInstanceIdTest);
    CASE(kNanoAppInfoEventsPerformer, NanoAppInfoEventsTestPerformer);
    CASE(kNanoAppInfoEventsObserver, NanoAppInfoEventsTestObserver);
    CASE(kBasicAudioTest, BasicAudioTest);
    CASE(kHostAwakeSuspend, HostAwakeSuspendTest);
    CASE(kBasicGnssTest, BasicGnssTest);
    CASE(kBasicWifiTest, BasicWifiTest);

#undef CASE

    default:
    sendFatalFailureToHost("Unexpected message type:",
                           &(data->reservedMessageType));
  }

  if (mCurrentTest != nullptr) {
    mCurrentTest->testSetUp(data->messageSize, data->message);
  } else {
    sendInternalFailureToHost("createTest() ended with null mCurrentTest");
  }
}

void App::freeTest() {
  if (mCurrentTest == nullptr) {
    sendInternalFailureToHost("Nanoapp unloading without running any test");
  }
  mCurrentTest->~Test();
}

}  // namespace general_test

static general_test::App gApp;


extern "C" void nanoappHandleEvent(uint32_t senderInstanceId,
                                   uint16_t eventType,
                                   const void* eventData) {
  gApp.handleEvent(senderInstanceId, eventType, eventData);
}

static uint32_t zeroedBytes[13];

extern "C" bool nanoappStart(void) {
  // zeroedBytes is in the BSS and needs to be zero'd out.
  for (size_t i = 0; i < sizeof(zeroedBytes)/sizeof(zeroedBytes[0]); i++) {
    if (zeroedBytes[i] != 0) {
      return false;
    }
  }

  // A CHRE is required to call the constructor of our class prior to
  // reaching this point.
  return gApp.wasConstructed();
}

extern "C" void nanoappEnd(void) {
  if (gApp.wasDestructed()) {
    // It's not legal for us to send a message from here.  The best
    // we can do is abort, although there's no means for the end user
    // to see such a failure.
    // TODO: Figure out how to have this failure noticed.
    nanoapp_testing::abort(AbortBlame::kChreInNanoappEnd);
  }
  gApp.freeTest();

  // TODO: Unclear how we can test the global destructor being called,
  //     but that would be good to test.  Since it's supposed to happen
  //     after this call completes, it's difficult to test.
}