diff options
author | android-build-team Robot <android-build-team-robot@google.com> | 2018-07-27 03:14:14 +0000 |
---|---|---|
committer | android-build-team Robot <android-build-team-robot@google.com> | 2018-07-27 03:14:14 +0000 |
commit | 621755a388e6ded47e2491db86503e58ee996cc9 (patch) | |
tree | 1c67e7ac8e5bb9e12c8cd4331b8b383a2fb137b7 | |
parent | c930185044792763ac0913812b1c35e245ce1761 (diff) | |
parent | 0d57e45baf0ed16f49241cae369aa119f7d7f270 (diff) | |
download | chre-pie-qpr1-s2-release.tar.gz |
Snap for 4916303 from 0d57e45baf0ed16f49241cae369aa119f7d7f270 to pi-qpr1-releaseandroid-9.0.0_r30android-9.0.0_r22android-9.0.0_r21android-9.0.0_r20android-9.0.0_r19android-9.0.0_r16pie-qpr1-s3-releasepie-qpr1-s2-releasepie-qpr1-s1-releasepie-qpr1-release
Change-Id: Ic33c334b6bc8520076c4048c329f884801f18ce0
-rw-r--r-- | Android.bp | 20 | ||||
-rw-r--r-- | apps/audio_stress_test/Makefile | 37 | ||||
-rw-r--r-- | apps/audio_stress_test/audio_stress_test.cc | 242 | ||||
-rw-r--r-- | host/common/audio_stress_test/audio_stress_test.cc | 126 | ||||
-rw-r--r-- | util/include/chre/util/nanoapp/app_id.h | 25 |
5 files changed, 438 insertions, 12 deletions
@@ -59,6 +59,26 @@ cc_test { gtest: false, } +cc_test { + name: "audio_stress_test", + vendor: true, + local_include_dirs: [ + "chre_api/include/chre_api", + "util/include", + ], + srcs: [ + "host/common/audio_stress_test/audio_stress_test.cc", + ], + cflags: ["-Wall", "-Werror"], + shared_libs: [ + "libcutils", + "liblog", + "libutils", + ], + static_libs: ["chre_client"], + gtest: false, +} + cc_library_shared { name: "android.hardware.contexthub@1.0-impl.generic", vendor: true, diff --git a/apps/audio_stress_test/Makefile b/apps/audio_stress_test/Makefile new file mode 100644 index 00000000..74214789 --- /dev/null +++ b/apps/audio_stress_test/Makefile @@ -0,0 +1,37 @@ +# +# Audio Stress Test Nanoapp Makefile +# + +# Environment Checks ########################################################### + +ifeq ($(CHRE_PREFIX),) +ifneq ($(ANDROID_BUILD_TOP),) +CHRE_PREFIX = $(ANDROID_BUILD_TOP)/system/chre +else +$(error "You must run 'lunch' to setup ANDROID_BUILD_TOP, or explicitly define \ + the CHRE_PREFIX environment variable to point to the CHRE root \ + directory.") +endif +endif + +# Nanoapp Configuration ######################################################## + +NANOAPP_NAME_STRING = \"Audio\ Stress\ Test\" +NANOAPP_NAME = audio_stress_test +NANOAPP_ID = 0x012345678900000e +NANOAPP_VERSION = 0x00000001 + +# Common Compiler Flags ######################################################## + +# Defines. +COMMON_CFLAGS += -DCHRE_NANOAPP_DISABLE_BACKCOMPAT +COMMON_CFLAGS += -DNANOAPP_MINIMUM_LOG_LEVEL=CHRE_LOG_LEVEL_DEBUG + +# Common Source Files ########################################################## + +COMMON_SRCS += audio_stress_test.cc +COMMON_SRCS += $(CHRE_PREFIX)/util/nanoapp/audio.cc + +# Makefile Includes ############################################################ + +include $(CHRE_PREFIX)/build/nanoapp/app.mk diff --git a/apps/audio_stress_test/audio_stress_test.cc b/apps/audio_stress_test/audio_stress_test.cc new file mode 100644 index 00000000..86c5dfbe --- /dev/null +++ b/apps/audio_stress_test/audio_stress_test.cc @@ -0,0 +1,242 @@ +/* + * 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 <chre.h> +#include <cinttypes> + +#include "chre/util/macros.h" +#include "chre/util/nanoapp/audio.h" +#include "chre/util/nanoapp/log.h" +#include "chre/util/time.h" + +#define LOG_TAG "[AudioStress]" + +/** + * @file + * + * This nanoapp is designed to subscribe to audio for varying durations of + * time and verify that audio data is delivered when it is expected to be. + */ + +using chre::Milliseconds; +using chre::Nanoseconds; +using chre::Seconds; + +namespace { + +//! The required buffer size for the stress test. +constexpr Nanoseconds kBufferDuration = Nanoseconds(Seconds(2)); + +//! The required sample format for the stress test. +constexpr uint8_t kBufferFormat = CHRE_AUDIO_DATA_FORMAT_16_BIT_SIGNED_PCM; + +//! The required sample rate for the stress test. +constexpr uint32_t kBufferSampleRate = 16000; + +//! The maximum amount of time that audio will not be delivered for. +constexpr Seconds kMaxAudioGap = Seconds(300); + +//! The list of durations to subscribe to audio for. Even durations are for when +//! audio is enabled and odd is for when audio is disabled. +constexpr Milliseconds kStressPlan[] = { + // Enabled, Disabled + Milliseconds(20000), Milliseconds(20000), + Milliseconds(30000), Milliseconds(200), + Milliseconds(10000), Milliseconds(1000), + Milliseconds(10000), Milliseconds(1999), + Milliseconds(8000), Milliseconds(60000), + Milliseconds(1000), Milliseconds(1000), + Milliseconds(1000), Milliseconds(1000), + Milliseconds(1000), Milliseconds(1000), + Milliseconds(1000), Milliseconds(1000), + Milliseconds(1000), Milliseconds(1000), + Milliseconds(1000), Milliseconds(1000), + Milliseconds(1000), Milliseconds(1000), + Milliseconds(1000), Milliseconds(1000), +}; + +//! The discovered audio handle found at startup. +uint32_t gAudioHandle; + +//! The current position in the stress plan. +size_t gTestPosition = 0; + +//! The timer handle to advance through the stress test. +uint32_t gTimerHandle; + +//! Whether or not audio is currently suspended. If audio is delivered when this +//! is set to true, this is considered a test failure. +bool gAudioIsSuspended = true; + +//! The timestamp of the last audio data event. +Nanoseconds gLastAudioTimestamp; + +/** + * @return true when the current test phase is expecting audio data events to be + * delivered. + */ +bool audioIsExpected() { + // Even test intervals are expected to return audio events. The current test + // interval is gTestPosition - 1 so there is no need to invert the bit. + return (gTestPosition % 2); +} + +/** + * Discovers an audio source to use for the stress test. The gAudioHandle will + * be set if the audio source was found. + * + * @return true if a matching source was discovered successfully. + */ +bool discoverAudioHandle() { + bool success = false; + struct chreAudioSource source; + for (uint32_t i = 0; !success && chreAudioGetSource(i, &source); i++) { + LOGI("Found audio source '%s' with %" PRIu32 "Hz %s data", + source.name, source.sampleRate, + chre::getChreAudioFormatString(source.format)); + LOGI(" buffer duration: [%" PRIu64 "ns, %" PRIu64 "ns]", + source.minBufferDuration, source.maxBufferDuration); + + if (source.sampleRate == kBufferSampleRate + && source.minBufferDuration <= kBufferDuration.toRawNanoseconds() + && source.maxBufferDuration >= kBufferDuration.toRawNanoseconds() + && source.format == kBufferFormat) { + gAudioHandle = i; + success = true; + } + } + + if (!success) { + LOGW("Failed to find suitable audio source"); + } + + return success; +} + +void checkTestPassing() { + auto lastAudioDuration = Nanoseconds(chreGetTime()) - gLastAudioTimestamp; + if (lastAudioDuration > kMaxAudioGap) { + LOGE("Test fail - audio not received for %" PRIu64 "ns", + lastAudioDuration.toRawNanoseconds()); + chreAbort(-1); + } +} + +bool requestAudioForCurrentTestState(const Nanoseconds& testStateDuration) { + bool success = false; + LOGD("Test stage %zu", gTestPosition); + if (audioIsExpected()) { + if (!chreAudioConfigureSource(gAudioHandle, true, kBufferDuration.toRawNanoseconds(), + kBufferDuration.toRawNanoseconds())) { + LOGE("Failed to enable audio"); + } else { + LOGI("Enabled audio for %" PRIu64, testStateDuration.toRawNanoseconds()); + success = true; + } + } else { + if (!chreAudioConfigureSource(0, false, 0, 0)) { + LOGE("Failed to disable audio"); + } else { + LOGI("Disabled audio for %" PRIu64, testStateDuration.toRawNanoseconds()); + success = true; + } + } + + return success; +} + +bool advanceTestPosition() { + checkTestPassing(); + gTimerHandle = chreTimerSet(kStressPlan[gTestPosition].toRawNanoseconds(), + nullptr, true /* oneShot */); + bool success = (gTimerHandle != CHRE_TIMER_INVALID); + if (!success) { + LOGE("Failed to set timer"); + } else { + // Grab the duration prior to incrementing the test position. + Nanoseconds timerDuration = kStressPlan[gTestPosition++]; + if (gTestPosition >= ARRAY_SIZE(kStressPlan)) { + gTestPosition = 0; + } + + success = requestAudioForCurrentTestState(timerDuration); + } + + return success; +} + +void handleTimerEvent() { + if (!advanceTestPosition()) { + LOGE("Test fail"); + } +} + +void handleAudioDataEvent(const chreAudioDataEvent *audioDataEvent) { + LOGI("Handling audio data event"); + gLastAudioTimestamp = Nanoseconds(audioDataEvent->timestamp); + + if (gAudioIsSuspended) { + LOGE("Test fail - received audio when suspended"); + } else if (!audioIsExpected()) { + LOGE("Test fail - received audio unexpectedly"); + } else { + LOGI("Test passing - received audio when expected"); + } +} + +void handleAudioSamplingChangeEvent( + const chreAudioSourceStatusEvent *audioSourceStatusEvent) { + LOGI("Handling audio sampling change event - suspended: %d", + audioSourceStatusEvent->status.suspended); + gAudioIsSuspended = audioSourceStatusEvent->status.suspended; +} + +} // namespace + + +bool nanoappStart() { + LOGI("start"); + gLastAudioTimestamp = Nanoseconds(chreGetTime()); + return (discoverAudioHandle() && advanceTestPosition()); +} + +void nanoappHandleEvent(uint32_t senderInstanceId, + uint16_t eventType, + const void *eventData) { + switch (eventType) { + case CHRE_EVENT_TIMER: + handleTimerEvent(); + break; + + case CHRE_EVENT_AUDIO_DATA: + handleAudioDataEvent( + static_cast<const chreAudioDataEvent *>(eventData)); + break; + + case CHRE_EVENT_AUDIO_SAMPLING_CHANGE: + handleAudioSamplingChangeEvent( + static_cast<const chreAudioSourceStatusEvent *>(eventData)); + break; + + default: + LOGW("Unexpected event %" PRIu16, eventType); + break; + } +} + +void nanoappEnd() { + LOGI("stop"); +} diff --git a/host/common/audio_stress_test/audio_stress_test.cc b/host/common/audio_stress_test/audio_stress_test.cc new file mode 100644 index 00000000..fbef0c8c --- /dev/null +++ b/host/common/audio_stress_test/audio_stress_test.cc @@ -0,0 +1,126 @@ +/* + * 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 "chre/util/nanoapp/app_id.h" +#include "chre_host/host_protocol_host.h" +#include "chre_host/log.h" +#include "chre_host/socket_client.h" + +#include <inttypes.h> +#include <sys/socket.h> +#include <sys/types.h> + +#include <fstream> +#include <thread> + +#include <cutils/sockets.h> +#include <utils/StrongPointer.h> + +/** + * @file + * A test utility that loads the audio stress test nanoapp and quits. + */ + +using android::sp; +using android::chre::getStringFromByteVector; +using android::chre::FragmentedLoadTransaction; +using android::chre::HostProtocolHost; +using android::chre::IChreMessageHandlers; +using android::chre::SocketClient; +using flatbuffers::FlatBufferBuilder; + +// Aliased for consistency with the way these symbols are referenced in +// CHRE-side code +namespace fbs = ::chre::fbs; + +namespace { + +class SocketCallbacks : public SocketClient::ICallbacks, + public IChreMessageHandlers { + public: + void onMessageReceived(const void *data, size_t length) override { + if (!HostProtocolHost::decodeMessageFromChre(data, length, *this)) { + LOGE("Failed to decode message"); + } + } + + void onConnected() override { + LOGI("Socket (re)connected"); + } + + void onConnectionAborted() override { + LOGI("Socket (re)connection aborted"); + } + + void onDisconnected() override { + LOGI("Socket disconnected"); + } + + void handleLoadNanoappResponse(const fbs::LoadNanoappResponseT& response) + override { + LOGI("Got load nanoapp response, transaction ID 0x%" PRIx32 " result %d", + response.transaction_id, response.success); + } +}; + +void sendLoadNanoappRequest(SocketClient& client, const char *filename, + uint64_t appId, uint32_t appVersion) { + std::ifstream file(filename, std::ios::binary | std::ios::ate); + if (!file) { + LOGE("Couldn't open file '%s': %s", filename, strerror(errno)); + return; + } + ssize_t size = file.tellg(); + file.seekg(0, std::ios::beg); + + std::vector<uint8_t> buffer(size); + if (!file.read(reinterpret_cast<char *>(buffer.data()), size)) { + LOGE("Couldn't read from file: %s", strerror(errno)); + return; + } + + // Perform loading with 1 fragment for simplicity + FlatBufferBuilder builder(size + 128); + FragmentedLoadTransaction transaction = FragmentedLoadTransaction( + 1 /* transactionId */, appId, appVersion, + 0x01000000 /* targetApiVersion */, buffer, + buffer.size() /* fragmentSize */); + HostProtocolHost::encodeFragmentedLoadNanoappRequest( + builder, transaction.getNextRequest()); + + LOGI("Sending load nanoapp request (%" PRIu32 " bytes total w/%zu bytes of " + "payload)", builder.GetSize(), buffer.size()); + if (!client.sendMessage(builder.GetBufferPointer(), builder.GetSize())) { + LOGE("Failed to send message"); + } +} + +} // anonymous namespace + +int main() { + SocketClient client; + sp<SocketCallbacks> callbacks = new SocketCallbacks(); + + if (!client.connect("chre", callbacks)) { + LOGE("Couldn't connect to socket"); + } else { + sendLoadNanoappRequest(client, "/data/audio_stress_test.so", + chre::kAudioStressTestAppId, + 1 /* appVersion */); + } + + return 0; +} diff --git a/util/include/chre/util/nanoapp/app_id.h b/util/include/chre/util/nanoapp/app_id.h index 9ee7b18e..7057954e 100644 --- a/util/include/chre/util/nanoapp/app_id.h +++ b/util/include/chre/util/nanoapp/app_id.h @@ -65,19 +65,20 @@ constexpr uint64_t makeGoogleNanoappId(uint32_t appNumber) { return makeNanoappId(CHRE_VENDOR_ID_GOOGLE, appNumber); } -constexpr uint64_t kHelloWorldAppId = makeExampleNanoappId(1); -constexpr uint64_t kMessageWorldAppId = makeExampleNanoappId(2); -constexpr uint64_t kTimerWorldAppId = makeExampleNanoappId(3); -constexpr uint64_t kSensorWorldAppId = makeExampleNanoappId(4); -constexpr uint64_t kGnssWorldAppId = makeExampleNanoappId(5); -constexpr uint64_t kWifiWorldAppId = makeExampleNanoappId(6); -constexpr uint64_t kWwanWorldAppId = makeExampleNanoappId(7); +constexpr uint64_t kHelloWorldAppId = makeExampleNanoappId(1); +constexpr uint64_t kMessageWorldAppId = makeExampleNanoappId(2); +constexpr uint64_t kTimerWorldAppId = makeExampleNanoappId(3); +constexpr uint64_t kSensorWorldAppId = makeExampleNanoappId(4); +constexpr uint64_t kGnssWorldAppId = makeExampleNanoappId(5); +constexpr uint64_t kWifiWorldAppId = makeExampleNanoappId(6); +constexpr uint64_t kWwanWorldAppId = makeExampleNanoappId(7); // 8 = reserved (previously used by ImuCal) -constexpr uint64_t kSpammerAppId = makeExampleNanoappId(9); -constexpr uint64_t kUnloadTesterAppId = makeExampleNanoappId(10); -constexpr uint64_t kAshWorldAppId = makeExampleNanoappId(11); -constexpr uint64_t kAudioWorldAppId = makeExampleNanoappId(12); -constexpr uint64_t kHostAwakeWorldAppId = makeExampleNanoappId(13); +constexpr uint64_t kSpammerAppId = makeExampleNanoappId(9); +constexpr uint64_t kUnloadTesterAppId = makeExampleNanoappId(10); +constexpr uint64_t kAshWorldAppId = makeExampleNanoappId(11); +constexpr uint64_t kAudioWorldAppId = makeExampleNanoappId(12); +constexpr uint64_t kHostAwakeWorldAppId = makeExampleNanoappId(13); +constexpr uint64_t kAudioStressTestAppId = makeExampleNanoappId(14); } // namespace chre |