普通文本  |  347行  |  12.16 KB

/*
 * Copyright (C) 2018 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/basic_wifi_test.h>

#include <chre.h>
#include <shared/send_message.h>
#include <shared/time_util.h>

using nanoapp_testing::kOneMillisecondInNanoseconds;
using nanoapp_testing::sendFatalFailureToHost;
using nanoapp_testing::sendFatalFailureToHostUint8;
using nanoapp_testing::sendSuccessToHost;

/*
 * Test to check expected functionality of the CHRE WiFi APIs.
 *
 * 1. If scan monitor is not supported, skip to 5;
 *    otherwise enables scan monitor.
 * 2. Checks async result of enabling scan monitor.
 * 3. Disables scan monitor.
 * 4. Checks async result of disabling scan monitor.
 * 5. If on demand WiFi scan is not supported, skip to end;
 *    otherwise sends default scan request.
 * 6. Checks the result of on demand WiFi scan.
 */
namespace general_test {

namespace {

//! A dummy cookie to pass into the enable
//! configure scan monitoring async request.
constexpr uint32_t kEnableScanMonitoringCookie = 0x1337;

//! A dummy cookie to pass into the disable
//! configure scan monitoring async request.
constexpr uint32_t kDisableScanMonitoringCookie = 0x1338;

//! A dummy cookie to pass into request scan async.
constexpr uint32_t kOnDemandScanCookie = 0xcafe;

//! Starting frequency of band 2.4 GHz
constexpr uint32_t kWifiBandStartFreq_2_4_GHz = 2407;

//! Starting frequency of band 5 GHz
constexpr uint32_t kWifiBandStartFreq_5_GHz = 5000;

//! Frequency of channel 14
constexpr uint32_t kWifiBandFreqOfChannel_14 = 2484;

/**
 * Calls API testConfigureScanMonitorAsync. Sends fatal failure to host
 * if API call fails.
 *
 * @param enable Set to true to enable monitoring scan results,
 *        false to disable.
 * @param cookie An opaque value that will be included in the chreAsyncResult
 *        sent in relation to this request.
 */
void testConfigureScanMonitorAsync(bool enable, const void * cookie) {
  if (!chreWifiConfigureScanMonitorAsync(enable, cookie)) {
    if (enable) {
      sendFatalFailureToHost("Failed to request to enable scan monitor.");
    } else {
      sendFatalFailureToHost("Failed to request to disable scan monitor.");
    }
  }
}

/**
 * Calls API chreWifiRequestScanAsyncDefault. Sends fatal failure to host
 * if API call fails.
 */
void testRequestScanAsync() {
  if (!chreWifiRequestScanAsyncDefault(&kOnDemandScanCookie)) {
    sendFatalFailureToHost("Failed to request for on-demand WiFi scan.");
  }
}

/**
 * Validates primaryChannel and sends fatal failure to host if failing.
 * 1. (primaryChannel - start frequecny) is a multiple of 5.
 * 2. primaryChannelNumber is multiple of 5 and between [1, maxChannelNumber].
 *
 * @param primaryChannel primary channel of a WiFi scan result.
 * @param startFrequency start frequency of band 2.4/5 GHz.
 * @param maxChannelNumber max channel number of band 2.4/5 GHz.
 */
void validatePrimaryChannel(uint32_t primaryChannel,
                            uint32_t startFrequency,
                            uint8_t maxChannelNumber) {
  if ((primaryChannel - startFrequency) % 5 != 0) {
    chreLog(CHRE_LOG_ERROR,
            "primaryChannel - %d must be a multiple of 5,"
            "got primaryChannel: %d",
            startFrequency, primaryChannel);
  }

  uint32_t primaryChannelNumber = (primaryChannel - startFrequency) / 5;
  if (primaryChannelNumber < 1 || primaryChannelNumber > maxChannelNumber) {
    chreLog(CHRE_LOG_ERROR,
            "primaryChannelNumber must be between 1 and %d,"
            "got primaryChannel: %d",
            maxChannelNumber, primaryChannel);
  }
}

/**
 * Validates primaryChannel for band 2.4/5 GHz.
 *
 * primaryChannelNumber of band 2.4 GHz is between 1 and 13,
 * plus a special case for channel 14 (primaryChannel == 2484);
 * primaryChannelNumber of band 5 GHz is between 1 and 200,
 * ref: IEEE Std 802.11-2016, 19.3.15.2.
 * Also, (primaryChannel - start frequecny) is a multiple of 5,
 * except channel 14 of 2.4 GHz.
 *
 * @param result WiFi scan result.
 */
void validatePrimaryChannel(const chreWifiScanResult& result) {
  // channel 14 (primaryChannel = 2484) is not applicable for this test.
  if (result.band == CHRE_WIFI_BAND_2_4_GHZ &&
      result.primaryChannel != kWifiBandFreqOfChannel_14) {
    validatePrimaryChannel(result.primaryChannel,
                           kWifiBandStartFreq_2_4_GHz,
                           13);
  } else if (result.band == CHRE_WIFI_BAND_5_GHZ) {
    validatePrimaryChannel(result.primaryChannel,
                           kWifiBandStartFreq_5_GHz,
                           200);
  }
}

/**
 * Validates centerFreqPrimary and centerFreqSecondary
 * TODO (jacksun) add test when channelWidth is 20, 40, 80, or 160 MHz
 */
void validateCenterFreq(const chreWifiScanResult& result) {
  if (result.channelWidth != CHRE_WIFI_CHANNEL_WIDTH_80_PLUS_80_MHZ
      && result.centerFreqSecondary != 0) {
    // TODO (jacksun) Format the centerFreqSecondary into the message
    // after redesigning of sendFatalFailureToHost()
    sendFatalFailureToHost(
        "centerFreqSecondary must be 0 if channelWidth is not 80+80MHZ");
  }
}

} // anonymous namespace

BasicWifiTest::BasicWifiTest()
    : Test(CHRE_API_VERSION_1_1) {
}

void BasicWifiTest::setUp(
    uint32_t messageSize, const void * /* message */) {
  if (messageSize != 0) {
    sendFatalFailureToHost(
        "Expected 0 byte message, got more bytes:", &messageSize);
  } else {
    mWifiCapabilities = chreWifiGetCapabilities();
    startScanMonitorTestStage();
  }
}

void BasicWifiTest::handleEvent(uint32_t /* senderInstanceId */,
                                uint16_t eventType,
                                const void *eventData) {
  if (eventData == nullptr) {
    sendFatalFailureToHost("Received null eventData");
  }
  switch (eventType) {
    case CHRE_EVENT_WIFI_ASYNC_RESULT:
      handleChreWifiAsyncEvent(
          static_cast<const chreAsyncResult *>(eventData));
      break;
    case CHRE_EVENT_WIFI_SCAN_RESULT:
      {
        const auto *result = static_cast<const chreWifiScanEvent *>(eventData);
        if (isActiveWifiScanType(result)) {
          // The first chreWifiScanResult is expected to come immediately,
          // but a long delay is possible if it's implemented incorrectly,
          // e.g. the async result comes right away (before the scan is actually
          // completed), then there's a long delay to the scan result.
          if (mStartTimestampNs != 0
              && chreGetTime() - mStartTimestampNs >
                  50 * kOneMillisecondInNanoseconds) {
            sendFatalFailureToHost(
                "Did not receive chreWifiScanResult within 50 milliseconds.");
          }
          mStartTimestampNs = 0;
          validateWifiScanEvent(result);
        }
      }
      break;
    default:
      unexpectedEvent(eventType);
      break;
  }
}

void BasicWifiTest::handleChreWifiAsyncEvent(const chreAsyncResult *result) {
  if (!mCurrentWifiRequest.has_value()) {
    nanoapp_testing::sendFailureToHost("Unexpected async result");
  }
  validateChreAsyncResult(result, mCurrentWifiRequest.value());

  switch (result->requestType) {
    case CHRE_WIFI_REQUEST_TYPE_REQUEST_SCAN:
      mStartTimestampNs = chreGetTime();
      break;
    case CHRE_WIFI_REQUEST_TYPE_CONFIGURE_SCAN_MONITOR:
      if (mCurrentWifiRequest->cookie == &kDisableScanMonitoringCookie) {
        mTestSuccessMarker.markStageAndSuccessOnFinish(
            BASIC_WIFI_TEST_STAGE_SCAN_MONITOR);
        startScanAsyncTestStage();
      } else {
        testConfigureScanMonitorAsync(false /* enable */,
                                      &kDisableScanMonitoringCookie);
        resetCurrentWifiRequest(&kDisableScanMonitoringCookie,
                                CHRE_WIFI_REQUEST_TYPE_CONFIGURE_SCAN_MONITOR,
                                CHRE_ASYNC_RESULT_TIMEOUT_NS);
      }
      break;
    default:
      sendFatalFailureToHostUint8(
          "Received unexpected requestType %d", result->requestType);
      break;
  }
}

bool BasicWifiTest::isActiveWifiScanType(const chreWifiScanEvent *eventData) {
  return (eventData->scanType == CHRE_WIFI_SCAN_TYPE_ACTIVE);
}

void BasicWifiTest::startScanMonitorTestStage() {
  if (mWifiCapabilities & CHRE_WIFI_CAPABILITIES_SCAN_MONITORING) {
    testConfigureScanMonitorAsync(true /* enable */,
                                  &kEnableScanMonitoringCookie);
    resetCurrentWifiRequest(&kEnableScanMonitoringCookie,
                            CHRE_WIFI_REQUEST_TYPE_CONFIGURE_SCAN_MONITOR,
                            CHRE_ASYNC_RESULT_TIMEOUT_NS);
  } else {
    mTestSuccessMarker.markStageAndSuccessOnFinish(
        BASIC_WIFI_TEST_STAGE_SCAN_MONITOR);
    startScanAsyncTestStage();
  }
}

void BasicWifiTest::startScanAsyncTestStage() {
  if (mWifiCapabilities & CHRE_WIFI_CAPABILITIES_ON_DEMAND_SCAN) {
    testRequestScanAsync();
    resetCurrentWifiRequest(&kOnDemandScanCookie,
                            CHRE_WIFI_REQUEST_TYPE_REQUEST_SCAN,
                            CHRE_WIFI_SCAN_RESULT_TIMEOUT_NS);
  } else {
    mTestSuccessMarker.markStageAndSuccessOnFinish(
        BASIC_WIFI_TEST_STAGE_SCAN_ASYNC);
  }
}

void BasicWifiTest::resetCurrentWifiRequest(const void *cookie,
                                            uint8_t requestType,
                                            uint64_t timeoutNs) {
  chreAsyncRequest request = {
    .cookie = cookie,
    .requestType = requestType,
    .requestTimeNs = chreGetTime(),
    .timeoutNs = timeoutNs
  };
  mCurrentWifiRequest = request;
}

void BasicWifiTest::validateWifiScanEvent(const chreWifiScanEvent *eventData) {
  if (eventData->version != CHRE_WIFI_SCAN_EVENT_VERSION) {
    sendFatalFailureToHostUint8(
        "Got unexpected scan event version %d", eventData->version);
  }

  if (mNextExpectedIndex != eventData->eventIndex) {
    chreLog(CHRE_LOG_ERROR, "Expected index: %d, received index: %d",
            mNextExpectedIndex, eventData->eventIndex);
    sendFatalFailureToHost("Received out-of-order events");
  }
  mNextExpectedIndex++;

  if (eventData->eventIndex == 0) {
    mWiFiScanResultRemaining = eventData->resultTotal;
  }
  if (mWiFiScanResultRemaining < eventData->resultCount) {
    chreLog(CHRE_LOG_ERROR, "Remaining scan results %d, received %d",
            mWiFiScanResultRemaining, eventData->resultCount);
    sendFatalFailureToHost("Received too many WiFi scan results");
  }
  mWiFiScanResultRemaining -= eventData->resultCount;

  validateWifiScanResult(eventData->resultCount, eventData->results);
  if (mWiFiScanResultRemaining == 0) {
    mNextExpectedIndex = 0;
    mTestSuccessMarker.markStageAndSuccessOnFinish(
        BASIC_WIFI_TEST_STAGE_SCAN_ASYNC);
  }
}

void BasicWifiTest::validateWifiScanResult(
    uint8_t count, const chreWifiScanResult *results) {
  for (uint8_t i = 0; i < count; ++i) {
    if (results[i].ssidLen > CHRE_WIFI_SSID_MAX_LEN) {
      sendFatalFailureToHostUint8(
          "Got unexpected ssidLen %d", results[i].ssidLen);
    }

    // TODO: Enable fatal failures on band, RSSI, and primary channel
    //       validations when proper error waiver is implemented in CHQTS.
    if (results[i].band != CHRE_WIFI_BAND_2_4_GHZ
        && results[i].band != CHRE_WIFI_BAND_5_GHZ) {
      chreLog(CHRE_LOG_ERROR, "Got unexpected band %d", results[i].band);
    }

    // It's possible for WiFi RSSI be positive if the phone is placed
    // right next to a high-power AP (e.g. transmitting at 20 dBm),
    // in which case RSSI will be < 20 dBm. Place a high threshold to check
    // against values likely to be erroneous (36 dBm/4W).
    if (results[i].rssi >= 36) {
      chreLog(CHRE_LOG_ERROR, "RSSI should be less than 36, got: %d",
              results[i].rssi);
    }

    validatePrimaryChannel(results[i]);
    validateCenterFreq(results[i]);
  }
}

} // namespace general_test