aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorandroid-build-team Robot <android-build-team-robot@google.com>2018-07-27 03:14:14 +0000
committerandroid-build-team Robot <android-build-team-robot@google.com>2018-07-27 03:14:14 +0000
commit621755a388e6ded47e2491db86503e58ee996cc9 (patch)
tree1c67e7ac8e5bb9e12c8cd4331b8b383a2fb137b7
parentc930185044792763ac0913812b1c35e245ce1761 (diff)
parent0d57e45baf0ed16f49241cae369aa119f7d7f270 (diff)
downloadchre-pie-qpr1-s2-release.tar.gz
Change-Id: Ic33c334b6bc8520076c4048c329f884801f18ce0
-rw-r--r--Android.bp20
-rw-r--r--apps/audio_stress_test/Makefile37
-rw-r--r--apps/audio_stress_test/audio_stress_test.cc242
-rw-r--r--host/common/audio_stress_test/audio_stress_test.cc126
-rw-r--r--util/include/chre/util/nanoapp/app_id.h25
5 files changed, 438 insertions, 12 deletions
diff --git a/Android.bp b/Android.bp
index 4ffb2dab..c99a3ab2 100644
--- a/Android.bp
+++ b/Android.bp
@@ -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