OSDN Git Service

aaudio: keep track of streams using strong pointers
authorPhil Burk <philburk@google.com>
Wed, 13 Sep 2017 20:03:08 +0000 (13:03 -0700)
committerPhil Burk <philburk@google.com>
Fri, 15 Sep 2017 20:29:26 +0000 (13:29 -0700)
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

25 files changed:
media/libaaudio/Doxyfile
media/libaaudio/src/Android.mk
media/libaaudio/src/binding/AAudioCommon.h [new file with mode: 0644]
media/libaaudio/src/binding/IAAudioClient.h
media/libaaudio/src/binding/IAAudioService.h
media/libaaudio/src/core/AAudioAudio.cpp
media/libaaudio/src/utility/HandleTracker.cpp [deleted file]
media/libaaudio/src/utility/HandleTracker.h [deleted file]
media/libaaudio/tests/Android.mk
media/libaaudio/tests/test_handle_tracker.cpp [deleted file]
services/oboeservice/AAudioEndpointManager.cpp
services/oboeservice/AAudioService.cpp
services/oboeservice/AAudioService.h
services/oboeservice/AAudioServiceEndpoint.cpp
services/oboeservice/AAudioServiceEndpointCapture.cpp
services/oboeservice/AAudioServiceEndpointPlay.cpp
services/oboeservice/AAudioServiceStreamBase.cpp
services/oboeservice/AAudioServiceStreamBase.h
services/oboeservice/AAudioServiceStreamMMAP.cpp
services/oboeservice/AAudioServiceStreamMMAP.h
services/oboeservice/AAudioServiceStreamShared.cpp
services/oboeservice/AAudioServiceStreamShared.h
services/oboeservice/AAudioStreamTracker.cpp [new file with mode: 0644]
services/oboeservice/AAudioStreamTracker.h [new file with mode: 0644]
services/oboeservice/Android.mk

index e2c4960..7298d11 100644 (file)
@@ -744,12 +744,12 @@ WARN_LOGFILE           =
 # Note: If this tag is empty the current directory is searched.
 
 INPUT                  = include/aaudio/AAudio.h \
+                         src/binding/AAudioCommon.h \
                          src/legacy/AudioStreamTrack.h \
                          src/legacy/AudioStreamRecord.h \
                          src/legacy/AAudioLegacy.h \
                          src/core/AudioStreamBuilder.h \
                          src/core/AudioStream.h \
-                         src/utility/HandleTracker.h \
                          src/utility/MonotonicCounter.h \
                          src/utility/AudioClock.h \
                          src/utility/AAudioUtilities.h
index cfcf27a..6861248 100644 (file)
@@ -36,7 +36,6 @@ LOCAL_SRC_FILES = \
     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 @@ LOCAL_SRC_FILES = core/AudioStream.cpp \
     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 (file)
index 0000000..e3e9e82
--- /dev/null
@@ -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
index 21cc33b..f21fd93 100644 (file)
@@ -22,7 +22,7 @@
 
 #include <aaudio/AAudio.h>
 
-#include "utility/HandleTracker.h"
+#include "binding/AAudioCommon.h"
 
 namespace android {
 
@@ -33,7 +33,7 @@ public:
 
     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;
 
 };
 
index 30b3ead..6bdb826 100644 (file)
 
 #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 @@ public:
      * @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 @@ public:
     /**
      * 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;
 };
 
index 58966e0..1eaee81 100644 (file)
 #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 (file)
index 35ce95a..0000000
+++ /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 (file)
index a4c51c0..0000000
+++ /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
index 4402919..37b010d 100644 (file)
@@ -5,16 +5,6 @@ LOCAL_C_INCLUDES := \
     $(call include-path-for, audio-utils) \
     frameworks/av/media/libaaudio/include \
     frameworks/av/media/libaaudio/src
-LOCAL_SRC_FILES:= test_handle_tracker.cpp
-LOCAL_SHARED_LIBRARIES := libaaudio
-LOCAL_MODULE := test_handle_tracker
-include $(BUILD_NATIVE_TEST)
-
-include $(CLEAR_VARS)
-LOCAL_C_INCLUDES := \
-    $(call include-path-for, audio-utils) \
-    frameworks/av/media/libaaudio/include \
-    frameworks/av/media/libaaudio/src
 LOCAL_SRC_FILES:= test_marshalling.cpp
 LOCAL_SHARED_LIBRARIES := libaaudio libbinder libcutils libutils
 LOCAL_MODULE := test_aaudio_marshalling
diff --git a/media/libaaudio/tests/test_handle_tracker.cpp b/media/libaaudio/tests/test_handle_tracker.cpp
deleted file mode 100644 (file)
index c4db47a..0000000
+++ /dev/null
@@ -1,117 +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.
- */
-
-// Unit tests for AAudio Handle Tracker
-
-#include <stdlib.h>
-#include <math.h>
-
-#include <gtest/gtest.h>
-
-#include <aaudio/AAudio.h>
-#include "utility/HandleTracker.h"
-
-// Test adding one address.
-TEST(test_handle_tracker, aaudio_handle_tracker) {
-    const int MAX_HANDLES = 4;
-    HandleTracker tracker(MAX_HANDLES);
-    handle_tracker_type_t type = 3; // arbitrary generic type
-    int data; // something that has an address we can use
-    handle_tracker_address_t found;
-
-    // repeat the test several times to see if it breaks
-    const int SEVERAL = 5; // arbitrary
-    for (int i = 0; i < SEVERAL; i++) {
-        // should fail to find a bogus handle
-        found = tracker.get(type, 0);  // bad handle
-        EXPECT_EQ(nullptr, found);
-
-        // create a valid handle and use it to lookup the object again
-        aaudio_handle_t dataHandle = tracker.put(type, &data);
-        ASSERT_TRUE(dataHandle > 0);
-        found = tracker.get(type, dataHandle);
-        EXPECT_EQ(&data, found);
-        found = tracker.get(type, 0); // bad handle
-        EXPECT_EQ(nullptr, found);
-
-        // wrong type
-        found = tracker.get(type+1, dataHandle);
-        EXPECT_EQ(nullptr, found);
-
-        // remove from storage
-        found = tracker.remove(type, dataHandle);
-        EXPECT_EQ(&data, found);
-        // should fail the second time
-        found = tracker.remove(type, dataHandle);
-        EXPECT_EQ(nullptr, found);
-    }
-}
-
-// Test filling the tracker.
-TEST(test_handle_tracker, aaudio_full_up) {
-    const int MAX_HANDLES = 5;
-    HandleTracker tracker(MAX_HANDLES);
-    handle_tracker_type_t type = 4; // arbitrary generic type
-    int data[MAX_HANDLES];
-    aaudio_handle_t handles[MAX_HANDLES];
-    handle_tracker_address_t found;
-
-    // repeat the test several times to see if it breaks
-    const int SEVERAL = 5; // arbitrary
-    for (int i = 0; i < SEVERAL; i++) {
-        for (int i = 0; i < MAX_HANDLES; i++) {
-            // add a handle
-            handles[i] = tracker.put(type, &data[i]);
-            ASSERT_TRUE(handles[i] > 0);
-            found = tracker.get(type, handles[i]);
-            EXPECT_EQ(&data[i], found);
-        }
-
-        // Now that it is full, try to add one more.
-        aaudio_handle_t handle = tracker.put(type, &data[0]);
-        EXPECT_TRUE(handle < 0);
-
-        for (int i = 0; i < MAX_HANDLES; i++) {
-            // look up each handle
-            found = tracker.get(type, handles[i]);
-            EXPECT_EQ(&data[i], found);
-        }
-
-        // remove one from storage
-        found = tracker.remove(type, handles[2]);
-        EXPECT_EQ(&data[2], found);
-        // now try to look up the same handle and fail
-        found = tracker.get(type, handles[2]);
-        EXPECT_EQ(nullptr, found);
-
-        // add that same one back
-        handle = tracker.put(type, &data[2]);
-        ASSERT_TRUE(handle > 0);
-        found = tracker.get(type, handle);
-        EXPECT_EQ(&data[2], found);
-        // now use a stale handle again with a valid index and fail
-        found = tracker.get(type, handles[2]);
-        EXPECT_EQ(nullptr, found);
-
-        // remove them all
-        handles[2] = handle;
-        for (int i = 0; i < MAX_HANDLES; i++) {
-            // look up each handle
-            found = tracker.remove(type, handles[i]);
-            EXPECT_EQ(&data[i], found);
-        }
-    }
-}
index f41219e..f996f74 100644 (file)
@@ -102,7 +102,7 @@ sp<AAudioServiceEndpoint> AAudioEndpointManager::findExclusiveEndpoint_l(
         }
     }
 
-    ALOGD("AAudioEndpointManager.findExclusiveEndpoint_l(), found %p for device = %d",
+    ALOGV("AAudioEndpointManager.findExclusiveEndpoint_l(), found %p for device = %d",
           endpoint.get(), configuration.getDeviceId());
     return endpoint;
 }
@@ -118,7 +118,7 @@ sp<AAudioServiceEndpointShared> AAudioEndpointManager::findSharedEndpoint_l(
         }
     }
 
-    ALOGD("AAudioEndpointManager.findSharedEndpoint_l(), found %p for device = %d",
+    ALOGV("AAudioEndpointManager.findSharedEndpoint_l(), found %p for device = %d",
           endpoint.get(), configuration.getDeviceId());
     return endpoint;
 }
@@ -238,8 +238,6 @@ void AAudioEndpointManager::closeExclusiveEndpoint(sp<AAudioServiceEndpoint> ser
     std::lock_guard<std::mutex> lock(mExclusiveLock);
     int32_t newRefCount = serviceEndpoint->getOpenCount() - 1;
     serviceEndpoint->setOpenCount(newRefCount);
-    ALOGD("AAudioEndpointManager::closeExclusiveEndpoint(%p) newRefCount = %d",
-          serviceEndpoint.get(), newRefCount);
 
     // If no longer in use then close and delete it.
     if (newRefCount <= 0) {
@@ -262,8 +260,6 @@ void AAudioEndpointManager::closeSharedEndpoint(sp<AAudioServiceEndpoint> servic
     std::lock_guard<std::mutex> lock(mSharedLock);
     int32_t newRefCount = serviceEndpoint->getOpenCount() - 1;
     serviceEndpoint->setOpenCount(newRefCount);
-    ALOGD("AAudioEndpointManager::closeSharedEndpoint(%p) newRefCount = %d",
-          serviceEndpoint.get(), newRefCount);
 
     // If no longer in use then close and delete it.
     if (newRefCount <= 0) {
index 5b34895..5a3488d 100644 (file)
@@ -18,9 +18,9 @@
 //#define LOG_NDEBUG 0
 #include <utils/Log.h>
 
+#include <iomanip>
+#include <iostream>
 #include <sstream>
-//#include <time.h>
-//#include <pthread.h>
 
 #include <aaudio/AAudio.h>
 #include <mediautils/SchedulingPolicyService.h>
 #include "AAudioServiceStreamMMAP.h"
 #include "binding/IAAudioService.h"
 #include "ServiceUtilities.h"
-#include "utility/HandleTracker.h"
 
 using namespace android;
 using namespace aaudio;
 
 #define MAX_STREAMS_PER_PROCESS   8
 
-typedef enum
-{
-    AAUDIO_HANDLE_TYPE_STREAM
-} aaudio_service_handle_type_t;
-static_assert(AAUDIO_HANDLE_TYPE_STREAM < HANDLE_TRACKER_MAX_TYPES, "Too many handle types.");
+using android::AAudioService;
 
 android::AAudioService::AAudioService()
     : BnAAudioService() {
@@ -70,7 +65,8 @@ status_t AAudioService::dump(int fd, const Vector<String16>& args) {
         result = ss.str();
         ALOGW("%s", result.c_str());
     } else {
-        result = mHandleTracker.dump()
+        result = "------------ AAudio Service ------------\n"
+                 + mStreamTracker.dump()
                  + AAudioClientTracker::getInstance().dump()
                  + AAudioEndpointManager::getInstance().dump();
     }
@@ -125,7 +121,7 @@ aaudio_handle_t AAudioService::openStream(const aaudio::AAudioStreamRequest &req
 
     // if SHARED requested or if EXCLUSIVE failed
     if (sharingMode == AAUDIO_SHARING_MODE_SHARED
-         || (serviceStream == nullptr && !sharingModeMatchRequired)) {
+         || (serviceStream.get() == nullptr && !sharingModeMatchRequired)) {
         serviceStream =  new AAudioServiceStreamShared(*this);
         result = serviceStream->open(request);
     }
@@ -136,18 +132,12 @@ aaudio_handle_t AAudioService::openStream(const aaudio::AAudioStreamRequest &req
               result, AAudio_convertResultToText(result));
         return result;
     } else {
-        aaudio_handle_t handle = mHandleTracker.put(AAUDIO_HANDLE_TYPE_STREAM, serviceStream.get());
-        if (handle < 0) {
-            ALOGE("AAudioService::openStream(): handle table full");
-            serviceStream->close();
-            serviceStream.clear();
-        } else {
-            ALOGD("AAudioService::openStream(): handle = 0x%08X", handle);
-            serviceStream->setHandle(handle);
-            pid_t pid = request.getProcessId();
-            AAudioClientTracker::getInstance().registerClientStream(pid, serviceStream);
-            configurationOutput.copyFrom(*serviceStream);
-        }
+        aaudio_handle_t handle = mStreamTracker.addStreamForHandle(serviceStream.get());
+        ALOGD("AAudioService::openStream(): handle = 0x%08X", handle);
+        serviceStream->setHandle(handle);
+        pid_t pid = request.getProcessId();
+        AAudioClientTracker::getInstance().registerClientStream(pid, serviceStream);
+        configurationOutput.copyFrom(*serviceStream);
         return handle;
     }
 }
@@ -155,30 +145,32 @@ aaudio_handle_t AAudioService::openStream(const aaudio::AAudioStreamRequest &req
 aaudio_result_t AAudioService::closeStream(aaudio_handle_t streamHandle) {
     // Check permission and ownership first.
     sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
-    if (serviceStream == nullptr) {
-        ALOGE("AAudioService::startStream(), illegal stream handle = 0x%0x", streamHandle);
+    if (serviceStream.get() == nullptr) {
+        ALOGE("AAudioService::closeStream(0x%0x), illegal stream handle", streamHandle);
         return AAUDIO_ERROR_INVALID_HANDLE;
     }
 
     ALOGD("AAudioService.closeStream(0x%08X)", streamHandle);
     // Remove handle from tracker so that we cannot look up the raw address any more.
-    serviceStream = (AAudioServiceStreamBase *)
-            mHandleTracker.remove(AAUDIO_HANDLE_TYPE_STREAM,
-                                  streamHandle);
-    if (serviceStream != nullptr) {
+    // removeStreamByHandle() uses a lock so that if there are two simultaneous closes
+    // then only one will get the pointer and do the close.
+    serviceStream = mStreamTracker.removeStreamByHandle(streamHandle);
+    if (serviceStream.get() != nullptr) {
         serviceStream->close();
         pid_t pid = serviceStream->getOwnerProcessId();
         AAudioClientTracker::getInstance().unregisterClientStream(pid, serviceStream);
         return AAUDIO_OK;
+    } else {
+        ALOGW("AAudioService::closeStream(0x%0x) being handled by another thread", streamHandle);
+        return AAUDIO_ERROR_INVALID_HANDLE;
     }
-    return AAUDIO_ERROR_INVALID_HANDLE;
 }
 
-AAudioServiceStreamBase *AAudioService::convertHandleToServiceStream(
-        aaudio_handle_t streamHandle) const {
-    AAudioServiceStreamBase *serviceStream = (AAudioServiceStreamBase *)
-            mHandleTracker.get(AAUDIO_HANDLE_TYPE_STREAM, (aaudio_handle_t)streamHandle);
-    if (serviceStream != nullptr) {
+
+sp<AAudioServiceStreamBase> AAudioService::convertHandleToServiceStream(
+        aaudio_handle_t streamHandle) {
+    sp<AAudioServiceStreamBase> serviceStream = mStreamTracker.getStreamByHandle(streamHandle);
+    if (serviceStream.get() != nullptr) {
         // Only allow owner or the aaudio service to access the stream.
         const uid_t callingUserId = IPCThreadState::self()->getCallingUid();
         const uid_t ownerUserId = serviceStream->getOwnerUserId();
@@ -198,19 +190,20 @@ AAudioServiceStreamBase *AAudioService::convertHandleToServiceStream(
 aaudio_result_t AAudioService::getStreamDescription(
                 aaudio_handle_t streamHandle,
                 aaudio::AudioEndpointParcelable &parcelable) {
-    AAudioServiceStreamBase *serviceStream = convertHandleToServiceStream(streamHandle);
-    if (serviceStream == nullptr) {
+    sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
+    if (serviceStream.get() == nullptr) {
         ALOGE("AAudioService::getStreamDescription(), illegal stream handle = 0x%0x", streamHandle);
         return AAUDIO_ERROR_INVALID_HANDLE;
     }
+
     aaudio_result_t result = serviceStream->getDescription(parcelable);
     // parcelable.dump();
     return result;
 }
 
 aaudio_result_t AAudioService::startStream(aaudio_handle_t streamHandle) {
-    AAudioServiceStreamBase *serviceStream = convertHandleToServiceStream(streamHandle);
-    if (serviceStream == nullptr) {
+    sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
+    if (serviceStream.get() == nullptr) {
         ALOGE("AAudioService::startStream(), illegal stream handle = 0x%0x", streamHandle);
         return AAUDIO_ERROR_INVALID_HANDLE;
     }
@@ -219,8 +212,8 @@ aaudio_result_t AAudioService::startStream(aaudio_handle_t streamHandle) {
 }
 
 aaudio_result_t AAudioService::pauseStream(aaudio_handle_t streamHandle) {
-    AAudioServiceStreamBase *serviceStream = convertHandleToServiceStream(streamHandle);
-    if (serviceStream == nullptr) {
+    sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
+    if (serviceStream.get() == nullptr) {
         ALOGE("AAudioService::pauseStream(), illegal stream handle = 0x%0x", streamHandle);
         return AAUDIO_ERROR_INVALID_HANDLE;
     }
@@ -229,9 +222,9 @@ aaudio_result_t AAudioService::pauseStream(aaudio_handle_t streamHandle) {
 }
 
 aaudio_result_t AAudioService::stopStream(aaudio_handle_t streamHandle) {
-    AAudioServiceStreamBase *serviceStream = convertHandleToServiceStream(streamHandle);
-    if (serviceStream == nullptr) {
-        ALOGE("AAudioService::pauseStream(), illegal stream handle = 0x%0x", streamHandle);
+    sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
+    if (serviceStream.get() == nullptr) {
+        ALOGE("AAudioService::stopStream(), illegal stream handle = 0x%0x", streamHandle);
         return AAUDIO_ERROR_INVALID_HANDLE;
     }
     aaudio_result_t result = serviceStream->stop();
@@ -239,8 +232,8 @@ aaudio_result_t AAudioService::stopStream(aaudio_handle_t streamHandle) {
 }
 
 aaudio_result_t AAudioService::flushStream(aaudio_handle_t streamHandle) {
-    AAudioServiceStreamBase *serviceStream = convertHandleToServiceStream(streamHandle);
-    if (serviceStream == nullptr) {
+    sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
+    if (serviceStream.get() == nullptr) {
         ALOGE("AAudioService::flushStream(), illegal stream handle = 0x%0x", streamHandle);
         return AAUDIO_ERROR_INVALID_HANDLE;
     }
@@ -250,8 +243,8 @@ aaudio_result_t AAudioService::flushStream(aaudio_handle_t streamHandle) {
 aaudio_result_t AAudioService::registerAudioThread(aaudio_handle_t streamHandle,
                                                    pid_t clientThreadId,
                                                    int64_t periodNanoseconds) {
-    AAudioServiceStreamBase *serviceStream = convertHandleToServiceStream(streamHandle);
-    if (serviceStream == nullptr) {
+    sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
+    if (serviceStream.get() == nullptr) {
         ALOGE("AAudioService::registerAudioThread(), illegal stream handle = 0x%0x", streamHandle);
         return AAUDIO_ERROR_INVALID_HANDLE;
     }
@@ -275,8 +268,8 @@ aaudio_result_t AAudioService::registerAudioThread(aaudio_handle_t streamHandle,
 
 aaudio_result_t AAudioService::unregisterAudioThread(aaudio_handle_t streamHandle,
                                                      pid_t clientThreadId) {
-    AAudioServiceStreamBase *serviceStream = convertHandleToServiceStream(streamHandle);
-    if (serviceStream == nullptr) {
+    sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
+    if (serviceStream.get() == nullptr) {
         ALOGE("AAudioService::unregisterAudioThread(), illegal stream handle = 0x%0x",
               streamHandle);
         return AAUDIO_ERROR_INVALID_HANDLE;
@@ -292,8 +285,8 @@ aaudio_result_t AAudioService::unregisterAudioThread(aaudio_handle_t streamHandl
 aaudio_result_t AAudioService::startClient(aaudio_handle_t streamHandle,
                                   const android::AudioClient& client,
                                   audio_port_handle_t *clientHandle) {
-    AAudioServiceStreamBase *serviceStream = convertHandleToServiceStream(streamHandle);
-    if (serviceStream == nullptr) {
+    sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
+    if (serviceStream.get() == nullptr) {
         ALOGE("AAudioService::startClient(), illegal stream handle = 0x%0x",
               streamHandle);
         return AAUDIO_ERROR_INVALID_HANDLE;
@@ -303,8 +296,8 @@ aaudio_result_t AAudioService::startClient(aaudio_handle_t streamHandle,
 
 aaudio_result_t AAudioService::stopClient(aaudio_handle_t streamHandle,
                                           audio_port_handle_t clientHandle) {
-    AAudioServiceStreamBase *serviceStream = convertHandleToServiceStream(streamHandle);
-    if (serviceStream == nullptr) {
+    sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
+    if (serviceStream.get() == nullptr) {
         ALOGE("AAudioService::stopClient(), illegal stream handle = 0x%0x",
               streamHandle);
         return AAUDIO_ERROR_INVALID_HANDLE;
index ffaf538..eef0824 100644 (file)
 #include <media/AudioClient.h>
 
 #include <aaudio/AAudio.h>
-#include "utility/HandleTracker.h"
-#include "binding/IAAudioService.h"
+
+#include "binding/AAudioCommon.h"
 #include "binding/AAudioServiceInterface.h"
+#include "binding/IAAudioService.h"
 
-namespace aaudio {
-    class AAudioServiceStreamBase;
-};
+#include "AAudioServiceStreamBase.h"
+#include "AAudioStreamTracker.h"
 
 namespace android {
 
@@ -51,45 +51,53 @@ public:
 
     virtual void            registerClient(const sp<IAAudioClient>& client);
 
-    virtual aaudio_handle_t openStream(const aaudio::AAudioStreamRequest &request,
-                                     aaudio::AAudioStreamConfiguration &configurationOutput);
+    aaudio::aaudio_handle_t openStream(const aaudio::AAudioStreamRequest &request,
+                                       aaudio::AAudioStreamConfiguration &configurationOutput)
+                                       override;
 
-    virtual aaudio_result_t closeStream(aaudio_handle_t streamHandle);
+    aaudio_result_t closeStream(aaudio::aaudio_handle_t streamHandle) override;
 
-    virtual aaudio_result_t getStreamDescription(
-                aaudio_handle_t streamHandle,
-                aaudio::AudioEndpointParcelable &parcelable);
+    aaudio_result_t getStreamDescription(
+                aaudio::aaudio_handle_t streamHandle,
+                aaudio::AudioEndpointParcelable &parcelable) override;
 
-    virtual aaudio_result_t startStream(aaudio_handle_t streamHandle);
+    aaudio_result_t startStream(aaudio::aaudio_handle_t streamHandle) override;
 
-    virtual aaudio_result_t pauseStream(aaudio_handle_t streamHandle);
+    aaudio_result_t pauseStream(aaudio::aaudio_handle_t streamHandle) override;
 
-    virtual aaudio_result_t stopStream(aaudio_handle_t streamHandle);
+    aaudio_result_t stopStream(aaudio::aaudio_handle_t streamHandle) override;
 
-    virtual aaudio_result_t flushStream(aaudio_handle_t streamHandle);
+    aaudio_result_t flushStream(aaudio::aaudio_handle_t streamHandle) override;
 
-    virtual aaudio_result_t registerAudioThread(aaudio_handle_t streamHandle,
+    aaudio_result_t registerAudioThread(aaudio::aaudio_handle_t streamHandle,
                                                 pid_t tid,
-                                                int64_t periodNanoseconds) ;
+                                                int64_t periodNanoseconds) override;
 
-    virtual aaudio_result_t unregisterAudioThread(aaudio_handle_t streamHandle,
-                                                  pid_t tid);
+    aaudio_result_t unregisterAudioThread(aaudio::aaudio_handle_t streamHandle,
+                                                  pid_t tid) override;
 
-    virtual aaudio_result_t startClient(aaudio_handle_t streamHandle,
+    aaudio_result_t startClient(aaudio::aaudio_handle_t streamHandle,
                                       const android::AudioClient& client,
-                                      audio_port_handle_t *clientHandle);
+                                      audio_port_handle_t *clientHandle) override;
 
-    virtual aaudio_result_t stopClient(aaudio_handle_t streamHandle,
-                                       audio_port_handle_t clientHandle);
+    aaudio_result_t stopClient(aaudio::aaudio_handle_t streamHandle,
+                                       audio_port_handle_t clientHandle) override;
 
 private:
 
-    aaudio::AAudioServiceStreamBase *convertHandleToServiceStream(aaudio_handle_t streamHandle) const;
+    /**
+     * Lookup stream and then validate access to the stream.
+     * @param streamHandle
+     * @return
+     */
+    sp<aaudio::AAudioServiceStreamBase> convertHandleToServiceStream(
+            aaudio::aaudio_handle_t streamHandle);
 
-    HandleTracker mHandleTracker;
 
     android::AudioClient mAudioClient;
 
+    aaudio::AAudioStreamTracker                 mStreamTracker;
+
     enum constants {
         DEFAULT_AUDIO_PRIORITY = 2
     };
index cba5bc8..3095bc9 100644 (file)
@@ -60,7 +60,7 @@ std::string AAudioServiceEndpoint::dump() const {
     result << "    Reference Count:      " << mOpenCount << "\n";
     result << "    Requested Device Id:  " << mRequestedDeviceId << "\n";
     result << "    Device Id:            " << getDeviceId() << "\n";
-    result << "    Registered Streams:  " << "\n";
+    result << "    Registered Streams:" << "\n";
     result << AAudioServiceStreamShared::dumpHeader() << "\n";
     for (const auto stream : mRegisteredStreams) {
         result << stream->dump() << "\n";
index 97558ca..c7d9b8e 100644 (file)
@@ -84,30 +84,42 @@ void *AAudioServiceEndpointCapture::callbackLoop() {
             std::lock_guard <std::mutex> lock(mLockStreams);
             for (const auto clientStream : mRegisteredStreams) {
                 if (clientStream->isRunning()) {
-                    AAudioServiceStreamShared *streamShared =
+                    int64_t clientFramesWritten = 0;
+                    sp<AAudioServiceStreamShared> streamShared =
                             static_cast<AAudioServiceStreamShared *>(clientStream.get());
 
-                    FifoBuffer *fifo = streamShared->getDataFifoBuffer();
-
-                    // Determine offset between framePosition in client's stream vs the underlying
-                    // MMAP stream.
-                    int64_t clientFramesWritten = fifo->getWriteCounter();
-                    // There are two indices that refer to the same frame.
-                    int64_t positionOffset = mmapFramesRead - clientFramesWritten;
-                    streamShared->setTimestampPositionOffset(positionOffset);
+                    {
+                        // Lock the AudioFifo to protect against close.
+                        std::lock_guard <std::mutex> lock(streamShared->getAudioDataQueueLock());
+
+                        FifoBuffer *fifo = streamShared->getAudioDataFifoBuffer_l();
+                        if (fifo != nullptr) {
+
+                            // Determine offset between framePosition in client's stream
+                            // vs the underlying MMAP stream.
+                            clientFramesWritten = fifo->getWriteCounter();
+                            // There are two indices that refer to the same frame.
+                            int64_t positionOffset = mmapFramesRead - clientFramesWritten;
+                            streamShared->setTimestampPositionOffset(positionOffset);
+
+                            if (fifo->getFifoControllerBase()->getEmptyFramesAvailable() <
+                                getFramesPerBurst()) {
+                                underflowCount++;
+                            } else {
+                                fifo->write(mDistributionBuffer, getFramesPerBurst());
+                            }
+                            clientFramesWritten = fifo->getWriteCounter();
+                        }
+                    }
 
-                    if (fifo->getFifoControllerBase()->getEmptyFramesAvailable() <
-                        getFramesPerBurst()) {
-                        underflowCount++;
-                    } else {
-                        fifo->write(mDistributionBuffer, getFramesPerBurst());
+                    if (clientFramesWritten > 0) {
+                        // This timestamp represents the completion of data being written into the
+                        // client buffer. It is sent to the client and used in the timing model
+                        // to decide when data will be available to read.
+                        Timestamp timestamp(clientFramesWritten, AudioClock::getNanoseconds());
+                        streamShared->markTransferTime(timestamp);
                     }
 
-                    // This timestamp represents the completion of data being written into the
-                    // client buffer. It is sent to the client and used in the timing model
-                    // to decide when data will be available to read.
-                    Timestamp timestamp(fifo->getWriteCounter(), AudioClock::getNanoseconds());
-                    streamShared->markTransferTime(timestamp);
                 }
             }
         }
index c42a6e2..9b1833a 100644 (file)
@@ -81,32 +81,44 @@ void *AAudioServiceEndpointPlay::callbackLoop() {
 
             std::lock_guard <std::mutex> lock(mLockStreams);
             for (const auto clientStream : mRegisteredStreams) {
+                int64_t clientFramesRead = 0;
+
                 if (!clientStream->isRunning()) {
                     continue;
                 }
 
-                AAudioServiceStreamShared *streamShared =
+                sp<AAudioServiceStreamShared> streamShared =
                         static_cast<AAudioServiceStreamShared *>(clientStream.get());
 
-                FifoBuffer *fifo = streamShared->getDataFifoBuffer();
-                // Determine offset between framePosition in client's stream vs the underlying
-                // MMAP stream.
-                int64_t clientFramesRead = fifo->getReadCounter();
-                // These two indices refer to the same frame.
-                int64_t positionOffset = mmapFramesWritten - clientFramesRead;
-                streamShared->setTimestampPositionOffset(positionOffset);
-
-                float volume = 1.0; // to match legacy volume
-                bool underflowed = mMixer.mix(index, fifo, volume);
-
-                // This timestamp represents the completion of data being read out of the
-                // client buffer. It is sent to the client and used in the timing model
-                // to decide when the client has room to write more data.
-                Timestamp timestamp(fifo->getReadCounter(), AudioClock::getNanoseconds());
-                streamShared->markTransferTime(timestamp);
-
-                if (underflowed) {
-                    streamShared->incrementXRunCount();
+                {
+                    // Lock the AudioFifo to protect against close.
+                    std::lock_guard <std::mutex> lock(streamShared->getAudioDataQueueLock());
+
+                    FifoBuffer *fifo = streamShared->getAudioDataFifoBuffer_l();
+                    if (fifo != nullptr) {
+
+                        // Determine offset between framePosition in client's stream
+                        // vs the underlying MMAP stream.
+                        clientFramesRead = fifo->getReadCounter();
+                        // These two indices refer to the same frame.
+                        int64_t positionOffset = mmapFramesWritten - clientFramesRead;
+                        streamShared->setTimestampPositionOffset(positionOffset);
+
+                        float volume = 1.0; // to match legacy volume
+                        bool underflowed = mMixer.mix(index, fifo, volume);
+                        if (underflowed) {
+                            streamShared->incrementXRunCount();
+                        }
+                        clientFramesRead = fifo->getReadCounter();
+                    }
+                }
+
+                if (clientFramesRead > 0) {
+                    // This timestamp represents the completion of data being read out of the
+                    // client buffer. It is sent to the client and used in the timing model
+                    // to decide when the client has room to write more data.
+                    Timestamp timestamp(clientFramesRead, AudioClock::getNanoseconds());
+                    streamShared->markTransferTime(timestamp);
                 }
 
                 index++; // just used for labelling tracks in systrace
index ca7b528..e670129 100644 (file)
@@ -365,10 +365,17 @@ aaudio_result_t AAudioServiceStreamBase::sendCurrentTimestamp() {
  * used to communicate with the underlying HAL or Service.
  */
 aaudio_result_t AAudioServiceStreamBase::getDescription(AudioEndpointParcelable &parcelable) {
-    // Gather information on the message queue.
-    mUpMessageQueue->fillParcelable(parcelable,
-                                    parcelable.mUpMessageQueueParcelable);
-    return getDownDataDescription(parcelable);
+    {
+        std::lock_guard<std::mutex> lock(mUpMessageQueueLock);
+        if (mUpMessageQueue == nullptr) {
+            ALOGE("getDescription(): mUpMessageQueue null! - stream not open");
+            return AAUDIO_ERROR_NULL;
+        }
+        // Gather information on the message queue.
+        mUpMessageQueue->fillParcelable(parcelable,
+                                        parcelable.mUpMessageQueueParcelable);
+    }
+    return getAudioDataDescription(parcelable);
 }
 
 void AAudioServiceStreamBase::onVolumeChanged(float volume) {
index 6f61401..af435b4 100644 (file)
 
 #include "SharedRingBuffer.h"
 #include "AAudioThread.h"
-#include "AAudioService.h"
+
+namespace android {
+    class AAudioService;
+}
 
 namespace aaudio {
 
@@ -210,7 +213,7 @@ protected:
 
     virtual aaudio_result_t getHardwareTimestamp(int64_t *positionFrames, int64_t *timeNanos) = 0;
 
-    virtual aaudio_result_t getDownDataDescription(AudioEndpointParcelable &parcelable) = 0;
+    virtual aaudio_result_t getAudioDataDescription(AudioEndpointParcelable &parcelable) = 0;
 
     aaudio_stream_state_t   mState = AAUDIO_STREAM_STATE_UNINITIALIZED;
 
index a629ed6..44ba1ca 100644 (file)
@@ -168,7 +168,8 @@ aaudio_result_t AAudioServiceStreamMMAP::getHardwareTimestamp(int64_t *positionF
 /**
  * Get an immutable description of the data queue from the HAL.
  */
-aaudio_result_t AAudioServiceStreamMMAP::getDownDataDescription(AudioEndpointParcelable &parcelable)
+aaudio_result_t AAudioServiceStreamMMAP::getAudioDataDescription(
+        AudioEndpointParcelable &parcelable)
 {
     sp<AAudioServiceEndpointMMAP> serviceEndpointMMAP{
             static_cast<AAudioServiceEndpointMMAP *>(mServiceEndpoint.get())};
index 83cd2ef..e2415d0 100644 (file)
@@ -75,7 +75,7 @@ public:
 
 protected:
 
-    aaudio_result_t getDownDataDescription(AudioEndpointParcelable &parcelable) override;
+    aaudio_result_t getAudioDataDescription(AudioEndpointParcelable &parcelable) override;
 
     aaudio_result_t getFreeRunningPosition(int64_t *positionFrames, int64_t *timeNanos) override;
 
index 348d407..084f996 100644 (file)
@@ -167,14 +167,17 @@ aaudio_result_t AAudioServiceStreamShared::open(const aaudio::AAudioStreamReques
         goto error;
     }
 
-    // Create audio data shared memory buffer for client.
-    mAudioDataQueue = new SharedRingBuffer();
-    result = mAudioDataQueue->allocate(calculateBytesPerFrame(), getBufferCapacity());
-    if (result != AAUDIO_OK) {
-        ALOGE("AAudioServiceStreamShared::open() could not allocate FIFO with %d frames",
-              getBufferCapacity());
-        result = AAUDIO_ERROR_NO_MEMORY;
-        goto error;
+    {
+        std::lock_guard<std::mutex> lock(mAudioDataQueueLock);
+        // Create audio data shared memory buffer for client.
+        mAudioDataQueue = new SharedRingBuffer();
+        result = mAudioDataQueue->allocate(calculateBytesPerFrame(), getBufferCapacity());
+        if (result != AAUDIO_OK) {
+            ALOGE("AAudioServiceStreamShared::open() could not allocate FIFO with %d frames",
+                  getBufferCapacity());
+            result = AAUDIO_ERROR_NO_MEMORY;
+            goto error;
+        }
     }
 
     ALOGD("AAudioServiceStreamShared::open() actual rate = %d, channels = %d, deviceId = %d",
@@ -197,8 +200,11 @@ error:
 aaudio_result_t AAudioServiceStreamShared::close()  {
     aaudio_result_t result = AAudioServiceStreamBase::close();
 
-    delete mAudioDataQueue;
-    mAudioDataQueue = nullptr;
+    {
+        std::lock_guard<std::mutex> lock(mAudioDataQueueLock);
+        delete mAudioDataQueue;
+        mAudioDataQueue = nullptr;
+    }
 
     return result;
 }
@@ -206,8 +212,14 @@ aaudio_result_t AAudioServiceStreamShared::close()  {
 /**
  * Get an immutable description of the data queue created by this service.
  */
-aaudio_result_t AAudioServiceStreamShared::getDownDataDescription(AudioEndpointParcelable &parcelable)
+aaudio_result_t AAudioServiceStreamShared::getAudioDataDescription(
+        AudioEndpointParcelable &parcelable)
 {
+    std::lock_guard<std::mutex> lock(mAudioDataQueueLock);
+    if (mAudioDataQueue == nullptr) {
+        ALOGE("getAudioDataDescription(): mUpMessageQueue null! - stream not open");
+        return AAUDIO_ERROR_NULL;
+    }
     // Gather information on the data queue.
     mAudioDataQueue->fillParcelable(parcelable,
                                     parcelable.mDownDataQueueParcelable);
index bc86dcc..8499ea5 100644 (file)
@@ -54,7 +54,21 @@ public:
 
     aaudio_result_t close() override;
 
-    android::FifoBuffer *getDataFifoBuffer() { return mAudioDataQueue->getFifoBuffer(); }
+    /**
+     * This must be locked when calling getAudioDataFifoBuffer_l() and while
+     * using the FifoBuffer it returns.
+     */
+    std::mutex &getAudioDataQueueLock() {
+        return mAudioDataQueueLock;
+    }
+
+    /**
+     * This must only be call under getAudioDataQueueLock().
+     * @return
+     */
+    android::FifoBuffer *getAudioDataFifoBuffer_l() { return (mAudioDataQueue == nullptr)
+                                                      ? nullptr
+                                                      : mAudioDataQueue->getFifoBuffer(); }
 
     /* Keep a record of when a buffer transfer completed.
      * This allows for a more accurate timing model.
@@ -75,7 +89,7 @@ public:
 
 protected:
 
-    aaudio_result_t getDownDataDescription(AudioEndpointParcelable &parcelable) override;
+    aaudio_result_t getAudioDataDescription(AudioEndpointParcelable &parcelable) override;
 
     aaudio_result_t getFreeRunningPosition(int64_t *positionFrames, int64_t *timeNanos) override;
 
@@ -90,7 +104,8 @@ protected:
                                             int32_t framesPerBurst);
 
 private:
-    SharedRingBuffer        *mAudioDataQueue = nullptr;
+    SharedRingBuffer        *mAudioDataQueue = nullptr; // protected by mAudioDataQueueLock
+    std::mutex               mAudioDataQueueLock;
 
     std::atomic<int64_t>     mTimestampPositionOffset;
     std::atomic<int32_t>     mXRunCount;
diff --git a/services/oboeservice/AAudioStreamTracker.cpp b/services/oboeservice/AAudioStreamTracker.cpp
new file mode 100644 (file)
index 0000000..ef88b34
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * 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 "AAudioStreamTracker"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include <iomanip>
+#include <iostream>
+#include <sstream>
+
+#include <aaudio/AAudio.h>
+#include <utils/String16.h>
+
+#include "AAudioStreamTracker.h"
+
+using namespace android;
+using namespace aaudio;
+
+sp<AAudioServiceStreamBase> AAudioStreamTracker::removeStreamByHandle(
+        aaudio_handle_t streamHandle) {
+    std::lock_guard<std::mutex> lock(mHandleLock);
+    sp<AAudioServiceStreamBase> serviceStream;
+    auto it = mStreamsByHandle.find(streamHandle);
+    if (it != mStreamsByHandle.end()) {
+        serviceStream = it->second;
+        mStreamsByHandle.erase(it);
+    }
+    return serviceStream;
+}
+
+sp<AAudioServiceStreamBase> AAudioStreamTracker::getStreamByHandle(
+        aaudio_handle_t streamHandle) {
+    std::lock_guard<std::mutex> lock(mHandleLock);
+    sp<AAudioServiceStreamBase> serviceStream;
+    auto it = mStreamsByHandle.find(streamHandle);
+    if (it != mStreamsByHandle.end()) {
+        serviceStream = it->second;
+    }
+    return serviceStream;
+}
+
+// advance to next legal handle value
+__attribute__((no_sanitize("integer")))
+aaudio_handle_t AAudioStreamTracker::bumpHandle(aaudio_handle_t handle) {
+    handle++;
+    // Only use positive integers.
+    if (handle <= 0) {
+        handle = 1;
+    }
+    return handle;
+}
+
+aaudio_handle_t AAudioStreamTracker::addStreamForHandle(sp<AAudioServiceStreamBase> serviceStream) {
+    std::lock_guard<std::mutex> lock(mHandleLock);
+    aaudio_handle_t handle = mPreviousHandle.load();
+    // Assign a unique handle.
+    while (true) {
+        handle = bumpHandle(handle);
+        sp<AAudioServiceStreamBase> oldServiceStream = mStreamsByHandle[handle];
+        // Is this an unused handle? It would be extremely unlikely to wrap
+        // around and collide with a very old handle. But just in case.
+        if (oldServiceStream.get() == nullptr) {
+            mStreamsByHandle[handle] = serviceStream;
+            break;
+        }
+    }
+    mPreviousHandle.store(handle);
+    return handle;
+}
+
+std::string AAudioStreamTracker::dump() const {
+    std::stringstream result;
+    const bool isLocked = AAudio_tryUntilTrue(
+            [this]()->bool { return mHandleLock.try_lock(); } /* f */,
+            50 /* times */,
+            20 /* sleepMs */);
+    if (!isLocked) {
+        result << "AAudioStreamTracker may be deadlocked\n";
+    } else {
+        result << "Stream Handles:\n";
+        for (const auto&  it : mStreamsByHandle) {
+            aaudio_handle_t handle = it.second->getHandle();
+            result << "    0x" << std::setfill('0') << std::setw(8) << std::hex << handle
+                   << std::dec << std::setfill(' ') << "\n";
+        }
+
+        mHandleLock.unlock();
+    }
+    return result.str();
+}
diff --git a/services/oboeservice/AAudioStreamTracker.h b/services/oboeservice/AAudioStreamTracker.h
new file mode 100644 (file)
index 0000000..70d440d
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * 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.
+ */
+
+#ifndef AAUDIO_AAUDIO_STREAM_TRACKER_H
+#define AAUDIO_AAUDIO_STREAM_TRACKER_H
+
+#include <time.h>
+#include <pthread.h>
+
+#include <aaudio/AAudio.h>
+
+#include "binding/AAudioCommon.h"
+
+#include "AAudioServiceStreamBase.h"
+
+namespace aaudio {
+
+class AAudioStreamTracker {
+
+public:
+    /**
+     * Remove the stream associated with the handle.
+     * @param streamHandle
+     * @return strong pointer to the stream if found or to nullptr
+     */
+    android::sp<AAudioServiceStreamBase> removeStreamByHandle(aaudio_handle_t streamHandle);
+
+    /**
+     * Look up a stream based on the handle.
+     * @param streamHandle
+     * @return strong pointer to the stream if found or to nullptr
+     */
+    android::sp<aaudio::AAudioServiceStreamBase> getStreamByHandle(aaudio_handle_t streamHandle);
+
+    /**
+     * Store a strong pointer to the stream and return a unique handle for future reference.
+     * The handle is guaranteed not to collide with an existing stream.
+     * @param serviceStream
+     * @return handle for identifying the stream
+     */
+    aaudio_handle_t addStreamForHandle(android::sp<AAudioServiceStreamBase> serviceStream);
+
+    /**
+     * @return string that can be added to dumpsys
+     */
+    std::string dump() const;
+
+private:
+    static aaudio_handle_t bumpHandle(aaudio_handle_t handle);
+
+    // Track stream using a unique handle that wraps. Only use positive half.
+    mutable std::mutex                mHandleLock;
+    std::atomic<aaudio_handle_t>      mPreviousHandle{0};
+    std::map<aaudio_handle_t, android::sp<aaudio::AAudioServiceStreamBase>> mStreamsByHandle;
+};
+
+
+} /* namespace aaudio */
+
+#endif /* AAUDIO_AAUDIO_STREAM_TRACKER_H */
index 1b74ad3..584b2ef 100644 (file)
@@ -22,7 +22,6 @@ LOCAL_C_INCLUDES := \
     $(TOP)/frameworks/av/media/libaaudio/src
 
 LOCAL_SRC_FILES += \
-    $(LIBAAUDIO_SRC_DIR)/utility/HandleTracker.cpp \
     SharedMemoryProxy.cpp \
     SharedRingBuffer.cpp \
     AAudioClientTracker.cpp \
@@ -37,6 +36,7 @@ LOCAL_SRC_FILES += \
     AAudioServiceStreamBase.cpp \
     AAudioServiceStreamMMAP.cpp \
     AAudioServiceStreamShared.cpp \
+    AAudioStreamTracker.cpp \
     TimestampScheduler.cpp \
     AAudioThread.cpp