aaudio: keep track of streams using strong pointers
Maintain strong pointer to service stream during service calls.
Use simple AAudioStreamTracker instead of complex HandleTracker.
Bug: 65280854
Test: affects all MMAP streams, run all CTS tests, etcetera
Change-Id: I3d2ed8b588ea39c216dacd4dea503b11c33f36f3
diff --git a/media/libaaudio/src/Android.mk b/media/libaaudio/src/Android.mk
index cfcf27a..6861248 100644
--- a/media/libaaudio/src/Android.mk
+++ b/media/libaaudio/src/Android.mk
@@ -36,7 +36,6 @@
legacy/AudioStreamLegacy.cpp \
legacy/AudioStreamRecord.cpp \
legacy/AudioStreamTrack.cpp \
- utility/HandleTracker.cpp \
utility/AAudioUtilities.cpp \
utility/FixedBlockAdapter.cpp \
utility/FixedBlockReader.cpp \
@@ -95,7 +94,6 @@
legacy/AudioStreamLegacy.cpp \
legacy/AudioStreamRecord.cpp \
legacy/AudioStreamTrack.cpp \
- utility/HandleTracker.cpp \
utility/AAudioUtilities.cpp \
utility/FixedBlockAdapter.cpp \
utility/FixedBlockReader.cpp \
diff --git a/media/libaaudio/src/binding/AAudioCommon.h b/media/libaaudio/src/binding/AAudioCommon.h
new file mode 100644
index 0000000..e3e9e82
--- /dev/null
+++ b/media/libaaudio/src/binding/AAudioCommon.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#ifndef ANDROID_AAUDIO_COMMON_H
+#define ANDROID_AAUDIO_COMMON_H
+
+#include <stdint.h>
+
+/*
+ * Internal header that is common to both client and server.
+ *
+ */
+namespace aaudio {
+
+typedef int32_t aaudio_handle_t;
+
+} /* namespace aaudio */
+
+#endif // ANDROID_AAUDIO_COMMON_H
diff --git a/media/libaaudio/src/binding/IAAudioClient.h b/media/libaaudio/src/binding/IAAudioClient.h
index 21cc33b..f21fd93 100644
--- a/media/libaaudio/src/binding/IAAudioClient.h
+++ b/media/libaaudio/src/binding/IAAudioClient.h
@@ -22,7 +22,7 @@
#include <aaudio/AAudio.h>
-#include "utility/HandleTracker.h"
+#include "binding/AAudioCommon.h"
namespace android {
@@ -33,7 +33,7 @@
DECLARE_META_INTERFACE(AAudioClient);
- virtual void onStreamChange(aaudio_handle_t handle, int32_t opcode, int32_t value) = 0;
+ virtual void onStreamChange(aaudio::aaudio_handle_t handle, int32_t opcode, int32_t value) = 0;
};
diff --git a/media/libaaudio/src/binding/IAAudioService.h b/media/libaaudio/src/binding/IAAudioService.h
index 30b3ead..6bdb826 100644
--- a/media/libaaudio/src/binding/IAAudioService.h
+++ b/media/libaaudio/src/binding/IAAudioService.h
@@ -24,12 +24,12 @@
#include <aaudio/AAudio.h>
+#include "binding/AAudioCommon.h"
#include "binding/AAudioServiceDefinitions.h"
-#include "binding/AudioEndpointParcelable.h"
-#include "binding/AAudioStreamRequest.h"
#include "binding/AAudioStreamConfiguration.h"
+#include "binding/AAudioStreamRequest.h"
+#include "binding/AudioEndpointParcelable.h"
#include "binding/IAAudioClient.h"
-#include "utility/HandleTracker.h"
namespace android {
@@ -51,7 +51,7 @@
* @param configuration contains information about the created stream
* @return handle to the stream or a negative error
*/
- virtual aaudio_handle_t openStream(const aaudio::AAudioStreamRequest &request,
+ virtual aaudio::aaudio_handle_t openStream(const aaudio::AAudioStreamRequest &request,
aaudio::AAudioStreamConfiguration &configurationOutput) = 0;
virtual aaudio_result_t closeStream(aaudio::aaudio_handle_t streamHandle) = 0;
@@ -89,11 +89,11 @@
/**
* Manage the specified thread as a low latency audio thread.
*/
- virtual aaudio_result_t registerAudioThread(aaudio_handle_t streamHandle,
+ virtual aaudio_result_t registerAudioThread(aaudio::aaudio_handle_t streamHandle,
pid_t clientThreadId,
int64_t periodNanoseconds) = 0;
- virtual aaudio_result_t unregisterAudioThread(aaudio_handle_t streamHandle,
+ virtual aaudio_result_t unregisterAudioThread(aaudio::aaudio_handle_t streamHandle,
pid_t clientThreadId) = 0;
};
diff --git a/media/libaaudio/src/core/AAudioAudio.cpp b/media/libaaudio/src/core/AAudioAudio.cpp
index 58966e0..1eaee81 100644
--- a/media/libaaudio/src/core/AAudioAudio.cpp
+++ b/media/libaaudio/src/core/AAudioAudio.cpp
@@ -24,15 +24,14 @@
#include <aaudio/AAudio.h>
#include <aaudio/AAudioTesting.h>
+#include "AudioClock.h"
#include "AudioStreamBuilder.h"
#include "AudioStream.h"
-#include "AudioClock.h"
+#include "binding/AAudioCommon.h"
#include "client/AudioStreamInternal.h"
-#include "HandleTracker.h"
using namespace aaudio;
-
// Macros for common code that includes a return.
// TODO Consider using do{}while(0) construct. I tried but it hung AndroidStudio
#define CONVERT_BUILDER_HANDLE_OR_RETURN() \
diff --git a/media/libaaudio/src/utility/HandleTracker.cpp b/media/libaaudio/src/utility/HandleTracker.cpp
deleted file mode 100644
index 35ce95a..0000000
--- a/media/libaaudio/src/utility/HandleTracker.cpp
+++ /dev/null
@@ -1,276 +0,0 @@
-/*
- * 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.
- *
- */
-
-#define LOG_TAG "AAudio"
-//#define LOG_NDEBUG 0
-#include <utils/Log.h>
-
-#include <assert.h>
-#include <functional>
-#include <iomanip>
-#include <new>
-#include <sstream>
-#include <stdint.h>
-#include <utils/Mutex.h>
-
-#include <aaudio/AAudio.h>
-#include "AAudioUtilities.h"
-#include "HandleTracker.h"
-
-using android::Mutex;
-
-// Handle format is: tgggiiii
-// where each letter is 4 bits, t=type, g=generation, i=index
-
-#define TYPE_SIZE 4
-#define GENERATION_SIZE 12
-#define INDEX_SIZE 16
-
-#define GENERATION_INVALID 0
-#define GENERATION_SHIFT INDEX_SIZE
-
-#define TYPE_MASK ((1 << TYPE_SIZE) - 1)
-#define GENERATION_MASK ((1 << GENERATION_SIZE) - 1)
-#define INDEX_MASK ((1 << INDEX_SIZE) - 1)
-
-#define SLOT_UNAVAILABLE (-1)
-
-// Error if handle is negative so type is limited to bottom half.
-#define HANDLE_INVALID_TYPE TYPE_MASK
-
-static_assert(HANDLE_TRACKER_MAX_TYPES == (1 << (TYPE_SIZE - 1)),
- "Mismatch between header and cpp.");
-static_assert(HANDLE_TRACKER_MAX_HANDLES == (1 << (INDEX_SIZE)),
- "Mismatch between header and cpp.");
-
-HandleTracker::HandleTracker(uint32_t maxHandles)
- : mMaxHandleCount(maxHandles)
- , mHandleHeaders(nullptr)
-{
- assert(maxHandles <= HANDLE_TRACKER_MAX_HANDLES);
- // Allocate arrays to hold addresses and validation info.
- mHandleAddresses = (handle_tracker_address_t *)
- new(std::nothrow) handle_tracker_address_t[maxHandles];
- if (mHandleAddresses != nullptr) {
- mHandleHeaders = new(std::nothrow) handle_tracker_header_t[maxHandles];
-
- if (mHandleHeaders != nullptr) {
- handle_tracker_header_t initialHeader = buildHeader(0, 1);
- // Initialize linked list of free nodes. nullptr terminated.
- for (uint32_t i = 0; i < (maxHandles - 1); i++) {
- mHandleAddresses[i] = &mHandleAddresses[i + 1]; // point to next node
- mHandleHeaders[i] = initialHeader;
- }
- mNextFreeAddress = &mHandleAddresses[0];
- mHandleAddresses[maxHandles - 1] = nullptr;
- mHandleHeaders[maxHandles - 1] = 0;
- } else {
- delete[] mHandleAddresses; // so the class appears uninitialized
- mHandleAddresses = nullptr;
- }
- }
-}
-
-HandleTracker::~HandleTracker()
-{
- Mutex::Autolock _l(mLock);
- delete[] mHandleAddresses;
- delete[] mHandleHeaders;
- mHandleAddresses = nullptr;
-}
-
-bool HandleTracker::isInitialized() const {
- return mHandleAddresses != nullptr;
-}
-
-
-
-std::string HandleTracker::dump() const {
- if (!isInitialized()) {
- return "HandleTracker is not initialized\n";
- }
-
- std::stringstream result;
- const bool isLocked = AAudio_tryUntilTrue(
- [this]()->bool { return mLock.tryLock(); } /* f */,
- 50 /* times */,
- 20 /* sleepMs */);
- if (!isLocked) {
- result << "HandleTracker may be deadlocked\n";
- }
-
- result << "HandleTracker:\n";
- result << " HandleHeaders:\n";
- // atLineStart() can be changed to support an arbitrary line breaking algorithm;
- // it should return true when a new line starts.
- // For simplicity, we will use a constant 16 items per line.
- const auto atLineStart = [](int index) -> bool {
- // Magic constant of 0xf used for mask to detect start every 16 items.
- return (index & 0xf) == 0; };
- const auto atLineEnd = [this, &atLineStart](int index) -> bool {
- return atLineStart(index + 1) || index == mMaxHandleCount - 1; };
-
- for (int i = 0; i < mMaxHandleCount; ++i) {
- if (atLineStart(i)) {
- result << " ";
- }
- result << std::hex << std::setw(4) << std::setfill('0') << mHandleHeaders[i]
- << (atLineEnd(i) ? "\n" : " ");
- }
-
- if (isLocked) {
- mLock.unlock();
- }
- return result.str();
-}
-
-handle_tracker_slot_t HandleTracker::allocateSlot_l() {
- void **allocated = mNextFreeAddress;
- if (allocated == nullptr) {
- return SLOT_UNAVAILABLE;
- }
- // Remove this slot from the head of the linked list.
- mNextFreeAddress = (void **) *allocated;
- return (allocated - mHandleAddresses);
-}
-
-handle_tracker_generation_t HandleTracker::nextGeneration_l(handle_tracker_slot_t index) {
- handle_tracker_generation_t generation = (mHandleHeaders[index] + 1) & GENERATION_MASK;
- // Avoid generation zero so that 0x0 is not a valid handle.
- if (generation == GENERATION_INVALID) {
- generation++;
- }
- return generation;
-}
-
-aaudio_handle_t HandleTracker::put(handle_tracker_type_t type, void *address)
-{
- if (type < 0 || type >= HANDLE_TRACKER_MAX_TYPES) {
- return static_cast<aaudio_handle_t>(AAUDIO_ERROR_OUT_OF_RANGE);
- }
- if (!isInitialized()) {
- return static_cast<aaudio_handle_t>(AAUDIO_ERROR_NO_MEMORY);
- }
-
- Mutex::Autolock _l(mLock);
-
- // Find an empty slot.
- handle_tracker_slot_t index = allocateSlot_l();
- if (index == SLOT_UNAVAILABLE) {
- ALOGE("HandleTracker::put() no room for more handles");
- return static_cast<aaudio_handle_t>(AAUDIO_ERROR_NO_FREE_HANDLES);
- }
-
- // Cycle the generation counter so stale handles can be detected.
- handle_tracker_generation_t generation = nextGeneration_l(index); // reads header table
- handle_tracker_header_t inputHeader = buildHeader(type, generation);
-
- // These two writes may need to be observed by other threads or cores during get().
- mHandleHeaders[index] = inputHeader;
- mHandleAddresses[index] = address;
- // TODO use store release to enforce memory order with get()
-
- // Generate a handle.
- aaudio_handle_t handle = buildHandle(inputHeader, index);
-
- ALOGV("HandleTracker::put(%p) returns 0x%08x", address, handle);
- return handle;
-}
-
-handle_tracker_slot_t HandleTracker::handleToIndex(handle_tracker_type_t type,
- aaudio_handle_t handle) const
-{
- // Validate the handle.
- handle_tracker_slot_t index = extractIndex(handle);
- if (index >= mMaxHandleCount) {
- ALOGE("HandleTracker::handleToIndex() invalid handle = 0x%08X", handle);
- return static_cast<aaudio_handle_t>(AAUDIO_ERROR_INVALID_HANDLE);
- }
- handle_tracker_generation_t handleGeneration = extractGeneration(handle);
- handle_tracker_header_t inputHeader = buildHeader(type, handleGeneration);
- // We do not need to synchronize this access to mHandleHeaders because it is constant for
- // the lifetime of the handle.
- if (inputHeader != mHandleHeaders[index]) {
- ALOGE("HandleTracker::handleToIndex() inputHeader = 0x%08x != mHandleHeaders[%d] = 0x%08x",
- inputHeader, index, mHandleHeaders[index]);
- return static_cast<aaudio_handle_t>(AAUDIO_ERROR_INVALID_HANDLE);
- }
- return index;
-}
-
-handle_tracker_address_t HandleTracker::get(handle_tracker_type_t type, aaudio_handle_t handle) const
-{
- if (!isInitialized()) {
- return nullptr;
- }
- handle_tracker_slot_t index = handleToIndex(type, handle);
- if (index >= 0) {
- // We do not need to synchronize this access to mHandleHeaders because this slot
- // is allocated and, therefore, not part of the linked list of free slots.
- return mHandleAddresses[index];
- } else {
- return nullptr;
- }
-}
-
-handle_tracker_address_t HandleTracker::remove(handle_tracker_type_t type, aaudio_handle_t handle) {
- if (!isInitialized()) {
- return nullptr;
- }
-
- Mutex::Autolock _l(mLock);
-
- handle_tracker_slot_t index = handleToIndex(type,handle);
- if (index >= 0) {
- handle_tracker_address_t address = mHandleAddresses[index];
-
- // Invalidate the header type but preserve the generation count.
- handle_tracker_generation_t generation = mHandleHeaders[index] & GENERATION_MASK;
- handle_tracker_header_t inputHeader = buildHeader(
- (handle_tracker_type_t) HANDLE_INVALID_TYPE, generation);
- mHandleHeaders[index] = inputHeader;
-
- // Add this slot to the head of the linked list.
- mHandleAddresses[index] = mNextFreeAddress;
- mNextFreeAddress = (handle_tracker_address_t *) &mHandleAddresses[index];
- return address;
- } else {
- return nullptr;
- }
-}
-
-aaudio_handle_t HandleTracker::buildHandle(handle_tracker_header_t typeGeneration,
- handle_tracker_slot_t index) {
- return (aaudio_handle_t)((typeGeneration << GENERATION_SHIFT) | (index & INDEX_MASK));
-}
-
-handle_tracker_header_t HandleTracker::buildHeader(handle_tracker_type_t type,
- handle_tracker_generation_t generation)
-{
- return (handle_tracker_header_t) (((type & TYPE_MASK) << GENERATION_SIZE)
- | (generation & GENERATION_MASK));
-}
-
-handle_tracker_slot_t HandleTracker::extractIndex(aaudio_handle_t handle)
-{
- return handle & INDEX_MASK;
-}
-
-handle_tracker_generation_t HandleTracker::extractGeneration(aaudio_handle_t handle)
-{
- return (handle >> GENERATION_SHIFT) & GENERATION_MASK;
-}
diff --git a/media/libaaudio/src/utility/HandleTracker.h b/media/libaaudio/src/utility/HandleTracker.h
deleted file mode 100644
index a4c51c0..0000000
--- a/media/libaaudio/src/utility/HandleTracker.h
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * Copyright 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.
- */
-
-#ifndef UTILITY_HANDLE_TRACKER_H
-#define UTILITY_HANDLE_TRACKER_H
-
-#include <stdint.h>
-#include <string>
-#include <utils/Mutex.h>
-
-typedef int32_t aaudio_handle_t;
-typedef int32_t handle_tracker_type_t; // what kind of handle
-typedef int32_t handle_tracker_slot_t; // index in allocation table
-typedef int32_t handle_tracker_generation_t; // incremented when slot used
-typedef uint16_t handle_tracker_header_t; // combines type and generation
-typedef void *handle_tracker_address_t; // address of something that is stored here
-
-#define HANDLE_TRACKER_MAX_TYPES (1 << 3)
-#define HANDLE_TRACKER_MAX_HANDLES (1 << 16)
-
-/**
- * Represent Objects using an integer handle that can be used with Java.
- * This also makes the 'C' ABI more robust.
- *
- * Note that this should only be called from a single thread.
- * If you call it from more than one thread then you need to use your own mutex.
- */
-class HandleTracker {
-
-public:
- /**
- * @param maxHandles cannot exceed HANDLE_TRACKER_MAX_HANDLES
- */
- HandleTracker(uint32_t maxHandles = 256);
- virtual ~HandleTracker();
-
- /**
- * Don't use if this returns false;
- * @return true if the internal allocation succeeded
- */
- bool isInitialized() const;
-
- /**
- * Returns HandleTracker information.
- *
- * Will attempt to get the object lock, but will proceed
- * even if it cannot.
- *
- * Each line of information ends with a newline.
- *
- * @return a string representing the HandleTracker info.
- */
- std::string dump() const;
-
- /**
- * Store a pointer and return a handle that can be used to retrieve the pointer.
- *
- * It is safe to call put() or remove() from multiple threads.
- *
- * @param expectedType the type of the object to be tracked
- * @param address pointer to be converted to a handle
- * @return a valid handle or a negative error
- */
- aaudio_handle_t put(handle_tracker_type_t expectedType, handle_tracker_address_t address);
-
- /**
- * Get the original pointer associated with the handle.
- * The handle will be validated to prevent stale handles from being reused.
- * Note that the validation is designed to prevent common coding errors and not
- * to prevent deliberate hacking.
- *
- * @param expectedType shouldmatch the type we passed to put()
- * @param handle to be converted to a pointer
- * @return address associated with handle or nullptr
- */
- handle_tracker_address_t get(handle_tracker_type_t expectedType, aaudio_handle_t handle) const;
-
- /**
- * Free up the storage associated with the handle.
- * Subsequent attempts to use the handle will fail.
- *
- * Do NOT remove() a handle while get() is being called for the same handle from another thread.
- *
- * @param expectedType shouldmatch the type we passed to put()
- * @param handle to be removed from tracking
- * @return address associated with handle or nullptr if not found
- */
- handle_tracker_address_t remove(handle_tracker_type_t expectedType, aaudio_handle_t handle);
-
-private:
- const int32_t mMaxHandleCount; // size of array
- // This address is const after initialization.
- handle_tracker_address_t * mHandleAddresses; // address of objects or a free linked list node
- // This address is const after initialization.
- handle_tracker_header_t * mHandleHeaders; // combination of type and generation
- // head of the linked list of free nodes in mHandleAddresses
- handle_tracker_address_t * mNextFreeAddress;
-
- // This Mutex protects the linked list of free nodes.
- // The list is managed using mHandleAddresses and mNextFreeAddress.
- // The data in mHandleHeaders is only changed by put() and remove().
- mutable android::Mutex mLock;
-
- /**
- * Pull slot off of a list of empty slots.
- * @return index or a negative error
- */
- handle_tracker_slot_t allocateSlot_l();
-
- /**
- * Increment the generation for the slot, avoiding zero.
- */
- handle_tracker_generation_t nextGeneration_l(handle_tracker_slot_t index);
-
- /**
- * Validate the handle and return the corresponding index.
- * @return slot index or a negative error
- */
- handle_tracker_slot_t handleToIndex(aaudio_handle_t handle, handle_tracker_type_t type) const;
-
- /**
- * Construct a handle from a header and an index.
- * @param header combination of a type and a generation
- * @param index slot index returned from allocateSlot
- * @return handle or a negative error
- */
- static aaudio_handle_t buildHandle(handle_tracker_header_t header, handle_tracker_slot_t index);
-
- /**
- * Combine a type and a generation field into a header.
- */
- static handle_tracker_header_t buildHeader(handle_tracker_type_t type,
- handle_tracker_generation_t generation);
-
- /**
- * Extract the index from a handle.
- * Does not validate the handle.
- * @return index associated with a handle
- */
- static handle_tracker_slot_t extractIndex(aaudio_handle_t handle);
-
- /**
- * Extract the generation from a handle.
- * Does not validate the handle.
- * @return generation associated with a handle
- */
- static handle_tracker_generation_t extractGeneration(aaudio_handle_t handle);
-
-};
-
-#endif //UTILITY_HANDLE_TRACKER_H