Move startAdvertising() logic into native code (1/3)
am: a90ebeafc1

Change-Id: I5cf2363eed2ed1b561dc676f10fbd4d5794106a5
diff --git a/include/hardware/audio.h b/include/hardware/audio.h
index 945492f..c95ad09 100644
--- a/include/hardware/audio.h
+++ b/include/hardware/audio.h
@@ -253,7 +253,8 @@
 /* type of asynchronous write callback events. Mutually exclusive */
 typedef enum {
     STREAM_CBK_EVENT_WRITE_READY, /* non blocking write completed */
-    STREAM_CBK_EVENT_DRAIN_READY  /* drain completed */
+    STREAM_CBK_EVENT_DRAIN_READY,  /* drain completed */
+    STREAM_CBK_EVENT_ERROR, /* stream hit some error, let AF take action */
 } stream_callback_event_t;
 
 typedef int (*stream_callback_t)(stream_callback_event_t event, void *param, void *cookie);
diff --git a/include/hardware/audio_effect.h b/include/hardware/audio_effect.h
index 41cd2e6..e49980d 100644
--- a/include/hardware/audio_effect.h
+++ b/include/hardware/audio_effect.h
@@ -150,6 +150,13 @@
 //  | Effect offload supported  | 22        | 0 The effect cannot be offloaded to an audio DSP
 //  |                           |           | 1 The effect can be offloaded to an audio DSP
 //  +---------------------------+-----------+-----------------------------------
+//  | Process function not      | 23        | 0 The effect implements a process function.
+//  | implemented               |           | 1 The effect does not implement a process function:
+//  |                           |           |   enabling the effect has no impact on latency or
+//  |                           |           |   CPU load.
+//  |                           |           |   Effect implementations setting this flag do not have
+//  |                           |           |   to implement a process function.
+//  +---------------------------+-----------+-----------------------------------
 
 // Insert mode
 #define EFFECT_FLAG_TYPE_SHIFT          0
@@ -240,6 +247,14 @@
                                           << EFFECT_FLAG_OFFLOAD_SHIFT)
 #define EFFECT_FLAG_OFFLOAD_SUPPORTED   (1 << EFFECT_FLAG_OFFLOAD_SHIFT)
 
+// Effect has no process indication
+#define EFFECT_FLAG_NO_PROCESS_SHIFT       (EFFECT_FLAG_OFFLOAD_SHIFT + \
+                                                    EFFECT_FLAG_OFFLOAD_SIZE)
+#define EFFECT_FLAG_NO_PROCESS_SIZE        1
+#define EFFECT_FLAG_NO_PROCESS_MASK        (((1 << EFFECT_FLAG_NO_PROCESS_SIZE) -1) \
+                                          << EFFECT_FLAG_NO_PROCESS_SHIFT)
+#define EFFECT_FLAG_NO_PROCESS          (1 << EFFECT_FLAG_NO_PROCESS_SHIFT)
+
 #define EFFECT_MAKE_API_VERSION(M, m)  (((M)<<16) | ((m) & 0xFFFF))
 #define EFFECT_API_VERSION_MAJOR(v)    ((v)>>16)
 #define EFFECT_API_VERSION_MINOR(v)    ((m) & 0xFFFF)
diff --git a/include/hardware/context_hub.h b/include/hardware/context_hub.h
index 3004494..aaa4274 100644
--- a/include/hardware/context_hub.h
+++ b/include/hardware/context_hub.h
@@ -358,6 +358,27 @@
  */
 
 /**
+ * CONTEXT_HUB_OS_REBOOT
+ * Reboots context hub OS, restarts all the nanoApps.
+ * No reboot notification is sent to nanoApps; reboot happens immediately and
+ * unconditionally; all volatile FW state and any data is lost as a result
+ *
+ * Payload : none
+ *
+ * Response : status_response_t
+ *            On receipt of a successful response, it is
+ *               expected that
+ *
+ *               i) system reboot has completed;
+ *                  status contains reboot reason code (platform-specific)
+ *
+ * Unsolicited response:
+ *            System may send unsolicited response at any time;
+ *            this should be interpreted as FW reboot, and necessary setup
+ *            has to be done (same or similar to the setup done on system boot)
+ */
+
+/**
  * All communication between the context hubs and the Context Hub Service is in
  * the form of messages. Some message types are distinguished and their
  * Semantics shall be well defined.
@@ -372,6 +393,7 @@
     CONTEXT_HUB_UNLOAD_APP   = 4, // Unload a specified app
     CONTEXT_HUB_QUERY_APPS   = 5, // Query for app(s) info on hub
     CONTEXT_HUB_QUERY_MEMORY = 6, // Query for memory info
+    CONTEXT_HUB_OS_REBOOT    = 7, // Request to reboot context HUB OS
 } hub_messages_e;
 
 #define CONTEXT_HUB_TYPE_PRIVATE_MSG_BASE 0x00400
diff --git a/include/hardware/gralloc.h b/include/hardware/gralloc.h
index f68b488..1b06ebf 100644
--- a/include/hardware/gralloc.h
+++ b/include/hardware/gralloc.h
@@ -379,6 +379,38 @@
     return device->common.close(&device->common);
 }
 
+/**
+ * map_usage_to_memtrack should be called after allocating a gralloc buffer.
+ *
+ * @param usage - it is the flag used when alloc function is called.
+ *
+ * This function maps the gralloc usage flags to appropriate memtrack bucket.
+ * GrallocHAL implementers and users should make an additional ION_IOCTL_TAG
+ * call using the memtrack tag returned by this function. This will help the
+ * in-kernel memtack to categorize the memory allocated by different processes
+ * according to their usage.
+ *
+ */
+static inline const char* map_usage_to_memtrack(uint32_t usage) {
+    usage &= GRALLOC_USAGE_ALLOC_MASK;
+
+    if ((usage & GRALLOC_USAGE_HW_CAMERA_WRITE) != 0) {
+        return "camera";
+    } else if ((usage & GRALLOC_USAGE_HW_VIDEO_ENCODER) != 0 ||
+            (usage & GRALLOC_USAGE_EXTERNAL_DISP) != 0) {
+        return "video";
+    } else if ((usage & GRALLOC_USAGE_HW_RENDER) != 0 ||
+            (usage & GRALLOC_USAGE_HW_TEXTURE) != 0) {
+        return "gl";
+    } else if ((usage & GRALLOC_USAGE_HW_CAMERA_READ) != 0) {
+        return "camera";
+    } else if ((usage & GRALLOC_USAGE_SW_READ_MASK) != 0 ||
+            (usage & GRALLOC_USAGE_SW_WRITE_MASK) != 0) {
+        return "cpu";
+    }
+    return "graphics";
+}
+
 __END_DECLS
 
 #endif  // ANDROID_GRALLOC_INTERFACE_H
diff --git a/include/hardware/keymaster_defs.h b/include/hardware/keymaster_defs.h
index b45e785..0f9bc27 100644
--- a/include/hardware/keymaster_defs.h
+++ b/include/hardware/keymaster_defs.h
@@ -518,7 +518,7 @@
 
 #define KEYMASTER_SIMPLE_COMPARE(a, b) (a < b) ? -1 : ((a > b) ? 1 : 0)
 inline int keymaster_param_compare(const keymaster_key_param_t* a, const keymaster_key_param_t* b) {
-    int retval = KEYMASTER_SIMPLE_COMPARE(a->tag, b->tag);
+    int retval = KEYMASTER_SIMPLE_COMPARE((uint32_t)a->tag, (uint32_t)b->tag);
     if (retval != 0)
         return retval;
 
diff --git a/include/hardware/power.h b/include/hardware/power.h
index c451d67..bd8216e 100644
--- a/include/hardware/power.h
+++ b/include/hardware/power.h
@@ -63,7 +63,9 @@
     POWER_HINT_VIDEO_DECODE = 0x00000004,
     POWER_HINT_LOW_POWER = 0x00000005,
     POWER_HINT_SUSTAINED_PERFORMANCE = 0x00000006,
-    POWER_HINT_VR_MODE = 0x00000007
+    POWER_HINT_VR_MODE = 0x00000007,
+    POWER_HINT_LAUNCH = 0x00000008,
+    POWER_HINT_DISABLE_TOUCH = 0x00000009
 } power_hint_t;
 
 typedef enum {
@@ -247,6 +249,14 @@
      *     device can sustain it. The data parameter is non-zero when the mode
      *     is activated and zero when deactivated.
      *
+     * POWER_HINT_DISABLE_TOUCH
+     *
+     *     When device enters some special modes, e.g. theater mode in Android
+     *     Wear, there is no touch interaction expected between device and user.
+     *     Touch controller could be disabled in those modes to save power.
+     *     The data parameter is non-zero when touch could be disabled, and zero
+     *     when touch needs to be re-enabled.
+     *
      * A particular platform may choose to ignore any hint.
      *
      * availability: version 0.2
diff --git a/modules/audio/audio_hw.c b/modules/audio/audio_hw.c
index e1cca2e..35901e4 100644
--- a/modules/audio/audio_hw.c
+++ b/modules/audio/audio_hw.c
@@ -35,10 +35,12 @@
 
 struct stub_stream_out {
     struct audio_stream_out stream;
+    int64_t last_write_time_us;
 };
 
 struct stub_stream_in {
     struct audio_stream_in stream;
+    int64_t last_read_time_us;
 };
 
 static uint32_t out_get_sample_rate(const struct audio_stream *stream)
@@ -79,7 +81,7 @@
 static int out_standby(struct audio_stream *stream)
 {
     ALOGV("out_standby");
-
+    // out->last_write_time_us = 0; unnecessary as a stale write time has same effect
     return 0;
 }
 
@@ -118,9 +120,31 @@
                          size_t bytes)
 {
     ALOGV("out_write: bytes: %zu", bytes);
+
     /* XXX: fake timing for audio output */
-    usleep((int64_t)bytes * 1000000 / audio_stream_out_frame_size(stream) /
-           out_get_sample_rate(&stream->common));
+    struct stub_stream_out *out = (struct stub_stream_out *)stream;
+    struct timespec t = { .tv_sec = 0, .tv_nsec = 0 };
+    clock_gettime(CLOCK_MONOTONIC, &t);
+    const int64_t now = (t.tv_sec * 1000000000LL + t.tv_nsec) / 1000;
+    const int64_t elapsed_time_since_last_write = now - out->last_write_time_us;
+    int64_t sleep_time = bytes * 1000000LL / audio_stream_out_frame_size(stream) /
+               out_get_sample_rate(&stream->common) - elapsed_time_since_last_write;
+    if (sleep_time > 0) {
+        usleep(sleep_time);
+    } else {
+        // we don't sleep when we exit standby (this is typical for a real alsa buffer).
+        sleep_time = 0;
+    }
+    out->last_write_time_us = now + sleep_time;
+    // last_write_time_us is an approximation of when the (simulated) alsa
+    // buffer is believed completely full. The usleep above waits for more space
+    // in the buffer, but by the end of the sleep the buffer is considered
+    // topped-off.
+    //
+    // On the subsequent out_write(), we measure the elapsed time spent in
+    // the mixer. This is subtracted from the sleep estimate based on frames,
+    // thereby accounting for drain in the alsa buffer during mixing.
+    // This is a crude approximation; we don't handle underruns precisely.
     return bytes;
 }
 
@@ -189,6 +213,8 @@
 
 static int in_standby(struct audio_stream *stream)
 {
+    struct stub_stream_in *in = (struct stub_stream_in *)stream;
+    in->last_read_time_us = 0;
     return 0;
 }
 
@@ -217,9 +243,31 @@
                        size_t bytes)
 {
     ALOGV("in_read: bytes %zu", bytes);
+
     /* XXX: fake timing for audio input */
-    usleep((int64_t)bytes * 1000000 / audio_stream_in_frame_size(stream) /
-           in_get_sample_rate(&stream->common));
+    struct stub_stream_in *in = (struct stub_stream_in *)stream;
+    struct timespec t = { .tv_sec = 0, .tv_nsec = 0 };
+    clock_gettime(CLOCK_MONOTONIC, &t);
+    const int64_t now = (t.tv_sec * 1000000000LL + t.tv_nsec) / 1000;
+
+    // we do a full sleep when exiting standby.
+    const bool standby = in->last_read_time_us == 0;
+    const int64_t elapsed_time_since_last_read = standby ?
+            0 : now - in->last_read_time_us;
+    int64_t sleep_time = bytes * 1000000LL / audio_stream_in_frame_size(stream) /
+            in_get_sample_rate(&stream->common) - elapsed_time_since_last_read;
+    if (sleep_time > 0) {
+        usleep(sleep_time);
+    } else {
+        sleep_time = 0;
+    }
+    in->last_read_time_us = now + sleep_time;
+    // last_read_time_us is an approximation of when the (simulated) alsa
+    // buffer is drained by the read, and is empty.
+    //
+    // On the subsequent in_read(), we measure the elapsed time spent in
+    // the recording thread. This is subtracted from the sleep estimate based on frames,
+    // thereby accounting for fill in the alsa buffer during the interim.
     memset(buffer, 0, bytes);
     return bytes;
 }
diff --git a/modules/sensors/multihal.cpp b/modules/sensors/multihal.cpp
index 0edbc2d..7044551 100644
--- a/modules/sensors/multihal.cpp
+++ b/modules/sensors/multihal.cpp
@@ -155,7 +155,11 @@
         ALOGV("writerTask before poll() - bufferSize = %d", bufferSize);
         eventsPolled = device->poll(device, buffer, bufferSize);
         ALOGV("writerTask poll() got %d events.", eventsPolled);
-        if (eventsPolled == 0) {
+        if (eventsPolled <= 0) {
+            if (eventsPolled < 0) {
+                ALOGV("writerTask ignored error %d from %s", eventsPolled, device->common.module->name);
+                ALOGE("ERROR: Fix %s so it does not return error from poll()", device->common.module->name);
+            }
             continue;
         }
         pthread_mutex_lock(&queue_mutex);
diff --git a/modules/usbaudio/audio_hal.c b/modules/usbaudio/audio_hal.c
index fe4a88e..6a3c5da 100644
--- a/modules/usbaudio/audio_hal.c
+++ b/modules/usbaudio/audio_hal.c
@@ -25,6 +25,7 @@
 #include <sys/time.h>
 
 #include <log/log.h>
+#include <cutils/list.h>
 #include <cutils/str_parms.h>
 #include <cutils/properties.h>
 
@@ -38,17 +39,6 @@
 
 #include <audio_utils/channels.h>
 
-/* FOR TESTING:
- * Set k_force_channels to force the number of channels to present to AudioFlinger.
- *   0 disables (this is default: present the device channels to AudioFlinger).
- *   2 forces to legacy stereo mode.
- *
- * Others values can be tried (up to 8).
- * TODO: AudioFlinger cannot support more than 8 active output channels
- * at this time, so limiting logic needs to be put here or communicated from above.
- */
-static const unsigned k_force_channels = 0;
-
 #include "alsa_device_profile.h"
 #include "alsa_device_proxy.h"
 #include "alsa_logging.h"
@@ -65,9 +55,11 @@
 
     /* output */
     alsa_device_profile out_profile;
+    struct listnode output_stream_list;
 
     /* input */
     alsa_device_profile in_profile;
+    struct listnode input_stream_list;
 
     /* lock input & output sample rates */
     /*FIXME - How do we address multiple output streams? */
@@ -78,14 +70,19 @@
     bool standby;
 };
 
+struct stream_lock {
+    pthread_mutex_t lock;               /* see note below on mutex acquisition order */
+    pthread_mutex_t pre_lock;           /* acquire before lock to avoid DOS by playback thread */
+};
+
 struct stream_out {
     struct audio_stream_out stream;
 
-    pthread_mutex_t lock;               /* see note below on mutex acquisition order */
-    pthread_mutex_t pre_lock;           /* acquire before lock to avoid DOS by playback thread */
+    struct stream_lock  lock;
+
     bool standby;
 
-    struct audio_device *dev;           /* hardware information - only using this for the lock */
+    struct audio_device *adev;           /* hardware information - only using this for the lock */
 
     alsa_device_profile * profile;      /* Points to the alsa_device_profile in the audio_device */
     alsa_device_proxy proxy;            /* state of the stream */
@@ -95,7 +92,13 @@
                                          * the device is not compatible with AudioFlinger
                                          * capabilities, e.g. exposes too many channels or
                                          * too few channels. */
-    audio_channel_mask_t hal_channel_mask;   /* channel mask exposed to AudioFlinger. */
+    audio_channel_mask_t hal_channel_mask;  /* USB devices deal in channel counts, not masks
+                                             * so the proxy doesn't have a channel_mask, but
+                                             * audio HALs need to talk about channel masks
+                                             * so expose the one calculated by
+                                             * adev_open_output_stream */
+
+    struct listnode list_node;
 
     void * conversion_buffer;           /* any conversions are put into here
                                          * they could come from here too if
@@ -106,11 +109,11 @@
 struct stream_in {
     struct audio_stream_in stream;
 
-    pthread_mutex_t lock;               /* see note below on mutex acquisition order */
-    pthread_mutex_t pre_lock;           /* acquire before lock to avoid DOS by capture thread */
+    struct stream_lock  lock;
+
     bool standby;
 
-    struct audio_device *dev;           /* hardware information - only using this for the lock */
+    struct audio_device *adev;           /* hardware information - only using this for the lock */
 
     alsa_device_profile * profile;      /* Points to the alsa_device_profile in the audio_device */
     alsa_device_proxy proxy;            /* state of the stream */
@@ -120,7 +123,13 @@
                                          * the device is not compatible with AudioFlinger
                                          * capabilities, e.g. exposes too many channels or
                                          * too few channels. */
-    audio_channel_mask_t hal_channel_mask;   /* channel mask exposed to AudioFlinger. */
+    audio_channel_mask_t hal_channel_mask;  /* USB devices deal in channel counts, not masks
+                                             * so the proxy doesn't have a channel_mask, but
+                                             * audio HALs need to talk about channel masks
+                                             * so expose the one calculated by
+                                             * adev_open_input_stream */
+
+    struct listnode list_node;
 
     /* We may need to read more data from the device in order to data reduce to 16bit, 4chan */
     void * conversion_buffer;           /* any conversions are put into here
@@ -130,12 +139,63 @@
 };
 
 /*
+ * Locking Helpers
+ */
+/*
  * NOTE: when multiple mutexes have to be acquired, always take the
  * stream_in or stream_out mutex first, followed by the audio_device mutex.
  * stream pre_lock is always acquired before stream lock to prevent starvation of control thread by
  * higher priority playback or capture thread.
  */
 
+static void stream_lock_init(struct stream_lock *lock) {
+    pthread_mutex_init(&lock->lock, (const pthread_mutexattr_t *) NULL);
+    pthread_mutex_init(&lock->pre_lock, (const pthread_mutexattr_t *) NULL);
+}
+
+static void stream_lock(struct stream_lock *lock) {
+    pthread_mutex_lock(&lock->pre_lock);
+    pthread_mutex_lock(&lock->lock);
+    pthread_mutex_unlock(&lock->pre_lock);
+}
+
+static void stream_unlock(struct stream_lock *lock) {
+    pthread_mutex_unlock(&lock->lock);
+}
+
+static void device_lock(struct audio_device *adev) {
+    pthread_mutex_lock(&adev->lock);
+}
+
+static int device_try_lock(struct audio_device *adev) {
+    return pthread_mutex_trylock(&adev->lock);
+}
+
+static void device_unlock(struct audio_device *adev) {
+    pthread_mutex_unlock(&adev->lock);
+}
+
+/*
+ * streams list management
+ */
+static void adev_add_stream_to_list(
+    struct audio_device* adev, struct listnode* list, struct listnode* stream_node) {
+    device_lock(adev);
+
+    list_add_tail(list, stream_node);
+
+    device_unlock(adev);
+}
+
+static void adev_remove_stream_from_list(
+    struct audio_device* adev, struct listnode* stream_node) {
+    device_lock(adev);
+
+    list_remove(stream_node);
+
+    device_unlock(adev);
+}
+
 /*
  * Extract the card and device numbers from the supplied key/value pairs.
  *   kvpairs    A null-terminated string containing the key/value pairs or card and device.
@@ -214,20 +274,6 @@
     return result_str;
 }
 
-void lock_input_stream(struct stream_in *in)
-{
-    pthread_mutex_lock(&in->pre_lock);
-    pthread_mutex_lock(&in->lock);
-    pthread_mutex_unlock(&in->pre_lock);
-}
-
-void lock_output_stream(struct stream_out *out)
-{
-    pthread_mutex_lock(&out->pre_lock);
-    pthread_mutex_lock(&out->lock);
-    pthread_mutex_unlock(&out->pre_lock);
-}
-
 /*
  * HAl Functions
  */
@@ -285,20 +331,28 @@
 {
     struct stream_out *out = (struct stream_out *)stream;
 
-    lock_output_stream(out);
+    stream_lock(&out->lock);
     if (!out->standby) {
-        pthread_mutex_lock(&out->dev->lock);
+        device_lock(out->adev);
         proxy_close(&out->proxy);
-        pthread_mutex_unlock(&out->dev->lock);
+        device_unlock(out->adev);
         out->standby = true;
     }
-    pthread_mutex_unlock(&out->lock);
-
+    stream_unlock(&out->lock);
     return 0;
 }
 
-static int out_dump(const struct audio_stream *stream, int fd)
-{
+static int out_dump(const struct audio_stream *stream, int fd) {
+    const struct stream_out* out_stream = (const struct stream_out*) stream;
+
+    if (out_stream != NULL) {
+        dprintf(fd, "Output Profile:\n");
+        profile_dump(out_stream->profile, fd);
+
+        dprintf(fd, "Output Proxy:\n");
+        proxy_dump(&out_stream->proxy, fd);
+    }
+
     return 0;
 }
 
@@ -318,9 +372,9 @@
         return ret_value;
     }
 
-    lock_output_stream(out);
+    stream_lock(&out->lock);
     /* Lock the device because that is where the profile lives */
-    pthread_mutex_lock(&out->dev->lock);
+    device_lock(out->adev);
 
     if (!profile_is_cached_for(out->profile, card, device)) {
         /* cannot read pcm device info if playback is active */
@@ -339,8 +393,8 @@
         }
     }
 
-    pthread_mutex_unlock(&out->dev->lock);
-    pthread_mutex_unlock(&out->lock);
+    device_unlock(out->adev);
+    stream_unlock(&out->lock);
 
     return ret_value;
 }
@@ -348,14 +402,13 @@
 static char * out_get_parameters(const struct audio_stream *stream, const char *keys)
 {
     struct stream_out *out = (struct stream_out *)stream;
-    lock_output_stream(out);
-    pthread_mutex_lock(&out->dev->lock);
+    stream_lock(&out->lock);
+    device_lock(out->adev);
 
     char * params_str =  device_get_parameters(out->profile, keys);
 
-    pthread_mutex_unlock(&out->lock);
-    pthread_mutex_unlock(&out->dev->lock);
-
+    device_unlock(out->adev);
+    stream_unlock(&out->lock);
     return params_str;
 }
 
@@ -383,11 +436,11 @@
     int ret;
     struct stream_out *out = (struct stream_out *)stream;
 
-    lock_output_stream(out);
+    stream_lock(&out->lock);
     if (out->standby) {
-        pthread_mutex_lock(&out->dev->lock);
+        device_lock(out->adev);
         ret = start_output_stream(out);
-        pthread_mutex_unlock(&out->dev->lock);
+        device_unlock(out->adev);
         if (ret != 0) {
             goto err;
         }
@@ -422,12 +475,12 @@
         proxy_write(&out->proxy, write_buff, num_write_buff_bytes);
     }
 
-    pthread_mutex_unlock(&out->lock);
+    stream_unlock(&out->lock);
 
     return bytes;
 
 err:
-    pthread_mutex_unlock(&out->lock);
+    stream_unlock(&out->lock);
     if (ret != 0) {
         usleep(bytes * 1000000 / audio_stream_out_frame_size(stream) /
                out_get_sample_rate(&stream->common));
@@ -445,12 +498,12 @@
                                          uint64_t *frames, struct timespec *timestamp)
 {
     struct stream_out *out = (struct stream_out *)stream; // discard const qualifier
-    lock_output_stream(out);
+    stream_lock(&out->lock);
 
     const alsa_device_proxy *proxy = &out->proxy;
     const int ret = proxy_get_presentation_position(proxy, frames, timestamp);
 
-    pthread_mutex_unlock(&out->lock);
+    stream_unlock(&out->lock);
     return ret;
 }
 
@@ -469,24 +522,23 @@
     return -EINVAL;
 }
 
-static int adev_open_output_stream(struct audio_hw_device *dev,
+static int adev_open_output_stream(struct audio_hw_device *hw_dev,
                                    audio_io_handle_t handle,
-                                   audio_devices_t devices,
+                                   audio_devices_t devicesSpec __unused,
                                    audio_output_flags_t flags,
                                    struct audio_config *config,
                                    struct audio_stream_out **stream_out,
                                    const char *address /*__unused*/)
 {
-    ALOGV("adev_open_output_stream() handle:0x%X, device:0x%X, flags:0x%X, addr:%s",
-          handle, devices, flags, address);
-
-    struct audio_device *adev = (struct audio_device *)dev;
+    ALOGV("adev_open_output_stream() handle:0x%X, devicesSpec:0x%X, flags:0x%X, addr:%s",
+          handle, devicesSpec, flags, address);
 
     struct stream_out *out;
 
     out = (struct stream_out *)calloc(1, sizeof(struct stream_out));
-    if (!out)
+    if (out == NULL) {
         return -ENOMEM;
+    }
 
     /* setup function pointers */
     out->stream.common.get_sample_rate = out_get_sample_rate;
@@ -508,12 +560,11 @@
     out->stream.get_presentation_position = out_get_presentation_position;
     out->stream.get_next_write_timestamp = out_get_next_write_timestamp;
 
-    pthread_mutex_init(&out->lock, (const pthread_mutexattr_t *) NULL);
-    pthread_mutex_init(&out->pre_lock, (const pthread_mutexattr_t *) NULL);
+    stream_lock_init(&out->lock);
 
-    out->dev = adev;
-    pthread_mutex_lock(&adev->lock);
-    out->profile = &adev->out_profile;
+    out->adev = (struct audio_device *)hw_dev;
+    device_lock(out->adev);
+    out->profile = &out->adev->out_profile;
 
     // build this to hand to the alsa_device_proxy
     struct pcm_config proxy_config;
@@ -536,8 +587,8 @@
         ret = -EINVAL;
     }
 
-    out->dev->device_sample_rate = config->sample_rate;
-    pthread_mutex_unlock(&adev->lock);
+    out->adev->device_sample_rate = config->sample_rate;
+    device_unlock(out->adev);
 
     /* Format */
     if (config->format == AUDIO_FORMAT_DEFAULT) {
@@ -555,33 +606,38 @@
     }
 
     /* Channels */
-    unsigned proposed_channel_count = 0;
-    if (k_force_channels) {
-        proposed_channel_count = k_force_channels;
-    } else if (config->channel_mask == AUDIO_CHANNEL_NONE) {
-        proposed_channel_count =  profile_get_default_channel_count(out->profile);
-    }
-
-    if (proposed_channel_count != 0) {
-        if (proposed_channel_count <= FCC_2) {
-            // use channel position mask for mono and stereo
-            config->channel_mask = audio_channel_out_mask_from_count(proposed_channel_count);
-        } else {
-            // use channel index mask for multichannel
-            config->channel_mask =
-                    audio_channel_mask_for_index_assignment_from_count(proposed_channel_count);
-        }
+    bool calc_mask = false;
+    if (config->channel_mask == AUDIO_CHANNEL_NONE) {
+        /* query case */
+        out->hal_channel_count = profile_get_default_channel_count(out->profile);
+        calc_mask = true;
     } else {
-        proposed_channel_count = audio_channel_count_from_out_mask(config->channel_mask);
+        /* explicit case */
+        out->hal_channel_count = audio_channel_count_from_out_mask(config->channel_mask);
     }
-    out->hal_channel_count = proposed_channel_count;
 
-    /* we can expose any channel mask, and emulate internally based on channel count. */
+    /* The Framework is currently limited to no more than this number of channels */
+    if (out->hal_channel_count > FCC_8) {
+        out->hal_channel_count = FCC_8;
+        calc_mask = true;
+    }
+
+    if (calc_mask) {
+        /* need to calculate the mask from channel count either because this is the query case
+         * or the specified mask isn't valid for this device, or is more then the FW can handle */
+        config->channel_mask = out->hal_channel_count <= FCC_2
+            /* position mask for mono and stereo*/
+            ? audio_channel_out_mask_from_count(out->hal_channel_count)
+            /* otherwise indexed */
+            : audio_channel_mask_for_index_assignment_from_count(out->hal_channel_count);
+    }
+
     out->hal_channel_mask = config->channel_mask;
 
-    /* no validity checks are needed as proxy_prepare() forces channel_count to be valid.
-     * and we emulate any channel count discrepancies in out_write(). */
-    proxy_config.channels = out->hal_channel_count;
+    // Validate the "logical" channel count against support in the "actual" profile.
+    // if they differ, choose the "actual" number of channels *closest* to the "logical".
+    // and store THAT in proxy_config.channels
+    proxy_config.channels = profile_get_closest_channel_count(out->profile, out->hal_channel_count);
     proxy_prepare(&out->proxy, out->profile, &proxy_config);
 
     /* TODO The retry mechanism isn't implemented in AudioPolicyManager/AudioFlinger. */
@@ -592,6 +648,9 @@
 
     out->standby = true;
 
+    /* Save the stream for adev_dump() */
+    adev_add_stream_to_list(out->adev, &out->adev->output_stream_list, &out->list_node);
+
     *stream_out = &out->stream;
 
     return ret;
@@ -602,12 +661,14 @@
     return -ENOSYS;
 }
 
-static void adev_close_output_stream(struct audio_hw_device *dev,
+static void adev_close_output_stream(struct audio_hw_device *hw_dev,
                                      struct audio_stream_out *stream)
 {
     struct stream_out *out = (struct stream_out *)stream;
     ALOGV("adev_close_output_stream(c:%d d:%d)", out->profile->card, out->profile->device);
 
+    adev_remove_stream_from_list(out->adev, &out->list_node);
+
     /* Close the pcm device */
     out_standby(&stream->common);
 
@@ -616,14 +677,14 @@
     out->conversion_buffer = NULL;
     out->conversion_buffer_size = 0;
 
-    pthread_mutex_lock(&out->dev->lock);
-    out->dev->device_sample_rate = 0;
-    pthread_mutex_unlock(&out->dev->lock);
+    device_lock(out->adev);
+    out->adev->device_sample_rate = 0;
+    device_unlock(out->adev);
 
     free(stream);
 }
 
-static size_t adev_get_input_buffer_size(const struct audio_hw_device *dev,
+static size_t adev_get_input_buffer_size(const struct audio_hw_device *hw_dev,
                                          const struct audio_config *config)
 {
     /* TODO This needs to be calculated based on format/channels/rate */
@@ -676,22 +737,31 @@
 {
     struct stream_in *in = (struct stream_in *)stream;
 
-    lock_input_stream(in);
+    stream_lock(&in->lock);
     if (!in->standby) {
-        pthread_mutex_lock(&in->dev->lock);
+        device_lock(in->adev);
         proxy_close(&in->proxy);
-        pthread_mutex_unlock(&in->dev->lock);
+        device_unlock(in->adev);
         in->standby = true;
     }
 
-    pthread_mutex_unlock(&in->lock);
+    stream_unlock(&in->lock);
 
     return 0;
 }
 
 static int in_dump(const struct audio_stream *stream, int fd)
 {
-    return 0;
+  const struct stream_in* in_stream = (const struct stream_in*)stream;
+  if (in_stream != NULL) {
+      dprintf(fd, "Input Profile:\n");
+      profile_dump(in_stream->profile, fd);
+
+      dprintf(fd, "Input Proxy:\n");
+      proxy_dump(&in_stream->proxy, fd);
+  }
+
+  return 0;
 }
 
 static int in_set_parameters(struct audio_stream *stream, const char *kvpairs)
@@ -712,8 +782,8 @@
         return ret_value;
     }
 
-    lock_input_stream(in);
-    pthread_mutex_lock(&in->dev->lock);
+    stream_lock(&in->lock);
+    device_lock(in->adev);
 
     if (card >= 0 && device >= 0 && !profile_is_cached_for(in->profile, card, device)) {
         /* cannot read pcm device info if playback is active */
@@ -732,8 +802,8 @@
         }
     }
 
-    pthread_mutex_unlock(&in->dev->lock);
-    pthread_mutex_unlock(&in->lock);
+    device_unlock(in->adev);
+    stream_unlock(&in->lock);
 
     return ret_value;
 }
@@ -742,13 +812,13 @@
 {
     struct stream_in *in = (struct stream_in *)stream;
 
-    lock_input_stream(in);
-    pthread_mutex_lock(&in->dev->lock);
+    stream_lock(&in->lock);
+    device_lock(in->adev);
 
     char * params_str =  device_get_parameters(in->profile, keys);
 
-    pthread_mutex_unlock(&in->dev->lock);
-    pthread_mutex_unlock(&in->lock);
+    device_unlock(in->adev);
+    stream_unlock(&in->lock);
 
     return params_str;
 }
@@ -786,11 +856,11 @@
 
     struct stream_in * in = (struct stream_in *)stream;
 
-    lock_input_stream(in);
+    stream_lock(&in->lock);
     if (in->standby) {
-        pthread_mutex_lock(&in->dev->lock);
+        device_lock(in->adev);
         ret = start_input_stream(in);
-        pthread_mutex_unlock(&in->dev->lock);
+        device_unlock(in->adev);
         if (ret != 0) {
             goto err;
         }
@@ -840,16 +910,15 @@
             }
         }
 
-        /* no need to acquire in->dev->lock to read mic_muted here as we don't change its state */
-        if (num_read_buff_bytes > 0 && in->dev->mic_muted)
+        /* no need to acquire in->adev->lock to read mic_muted here as we don't change its state */
+        if (num_read_buff_bytes > 0 && in->adev->mic_muted)
             memset(buffer, 0, num_read_buff_bytes);
     } else {
         num_read_buff_bytes = 0; // reset the value after USB headset is unplugged
     }
 
 err:
-    pthread_mutex_unlock(&in->lock);
-
+    stream_unlock(&in->lock);
     return num_read_buff_bytes;
 }
 
@@ -858,9 +927,9 @@
     return 0;
 }
 
-static int adev_open_input_stream(struct audio_hw_device *dev,
+static int adev_open_input_stream(struct audio_hw_device *hw_dev,
                                   audio_io_handle_t handle,
-                                  audio_devices_t devices,
+                                  audio_devices_t devicesSpec __unused,
                                   struct audio_config *config,
                                   struct audio_stream_in **stream_in,
                                   audio_input_flags_t flags __unused,
@@ -873,8 +942,9 @@
     struct stream_in *in = (struct stream_in *)calloc(1, sizeof(struct stream_in));
     int ret = 0;
 
-    if (in == NULL)
+    if (in == NULL) {
         return -ENOMEM;
+    }
 
     /* setup function pointers */
     in->stream.common.get_sample_rate = in_get_sample_rate;
@@ -894,13 +964,12 @@
     in->stream.read = in_read;
     in->stream.get_input_frames_lost = in_get_input_frames_lost;
 
-    pthread_mutex_init(&in->lock, (const pthread_mutexattr_t *) NULL);
-    pthread_mutex_init(&in->pre_lock, (const pthread_mutexattr_t *) NULL);
+    stream_lock_init(&in->lock);
 
-    in->dev = (struct audio_device *)dev;
-    pthread_mutex_lock(&in->dev->lock);
+    in->adev = (struct audio_device *)hw_dev;
+    device_lock(in->adev);
 
-    in->profile = &in->dev->in_profile;
+    in->profile = &in->adev->in_profile;
 
     struct pcm_config proxy_config;
     memset(&proxy_config, 0, sizeof(proxy_config));
@@ -915,17 +984,17 @@
         config->sample_rate = profile_get_default_sample_rate(in->profile);
     }
 
-    if (in->dev->device_sample_rate != 0 &&                 /* we are playing, so lock the rate */
-        in->dev->device_sample_rate >= RATELOCK_THRESHOLD) {/* but only for high sample rates */
-        ret = config->sample_rate != in->dev->device_sample_rate ? -EINVAL : 0;
-        proxy_config.rate = config->sample_rate = in->dev->device_sample_rate;
+    if (in->adev->device_sample_rate != 0 &&                 /* we are playing, so lock the rate */
+        in->adev->device_sample_rate >= RATELOCK_THRESHOLD) {/* but only for high sample rates */
+        ret = config->sample_rate != in->adev->device_sample_rate ? -EINVAL : 0;
+        proxy_config.rate = config->sample_rate = in->adev->device_sample_rate;
     } else if (profile_is_sample_rate_valid(in->profile, config->sample_rate)) {
-        in->dev->device_sample_rate = proxy_config.rate = config->sample_rate;
+        in->adev->device_sample_rate = proxy_config.rate = config->sample_rate;
     } else {
         proxy_config.rate = config->sample_rate = profile_get_default_sample_rate(in->profile);
         ret = -EINVAL;
     }
-    pthread_mutex_unlock(&in->dev->lock);
+    device_unlock(in->adev);
 
     /* Format */
     if (config->format == AUDIO_FORMAT_DEFAULT) {
@@ -943,40 +1012,75 @@
     }
 
     /* Channels */
-    unsigned proposed_channel_count = 0;
-    if (k_force_channels) {
-        proposed_channel_count = k_force_channels;
-    } else if (config->channel_mask == AUDIO_CHANNEL_NONE) {
-        proposed_channel_count = profile_get_default_channel_count(in->profile);
-    }
-    if (proposed_channel_count != 0) {
-        config->channel_mask = audio_channel_in_mask_from_count(proposed_channel_count);
-        if (config->channel_mask == AUDIO_CHANNEL_INVALID)
-            config->channel_mask =
-                    audio_channel_mask_for_index_assignment_from_count(proposed_channel_count);
-        in->hal_channel_count = proposed_channel_count;
+    bool calc_mask = false;
+    if (config->channel_mask == AUDIO_CHANNEL_NONE) {
+        /* query case */
+        in->hal_channel_count = profile_get_default_channel_count(in->profile);
+        calc_mask = true;
     } else {
+        /* explicit case */
         in->hal_channel_count = audio_channel_count_from_in_mask(config->channel_mask);
     }
-    /* we can expose any channel mask, and emulate internally based on channel count. */
-    in->hal_channel_mask = config->channel_mask;
 
-    proxy_config.channels = profile_get_default_channel_count(in->profile);
-    proxy_prepare(&in->proxy, in->profile, &proxy_config);
+    /* The Framework is currently limited to no more than this number of channels */
+    if (in->hal_channel_count > FCC_8) {
+        in->hal_channel_count = FCC_8;
+        calc_mask = true;
+    }
 
-    in->standby = true;
+    if (calc_mask) {
+        /* need to calculate the mask from channel count either because this is the query case
+         * or the specified mask isn't valid for this device, or is more then the FW can handle */
+        in->hal_channel_mask = in->hal_channel_count <= FCC_2
+            /* position mask for mono & stereo */
+            ? audio_channel_in_mask_from_count(in->hal_channel_count)
+            /* otherwise indexed */
+            : audio_channel_mask_for_index_assignment_from_count(in->hal_channel_count);
 
-    in->conversion_buffer = NULL;
-    in->conversion_buffer_size = 0;
+        // if we change the mask...
+        if (in->hal_channel_mask != config->channel_mask &&
+            config->channel_mask != AUDIO_CHANNEL_NONE) {
+            config->channel_mask = in->hal_channel_mask;
+            ret = -EINVAL;
+        }
+    } else {
+        in->hal_channel_mask = config->channel_mask;
+    }
 
-    *stream_in = &in->stream;
+    if (ret == 0) {
+        // Validate the "logical" channel count against support in the "actual" profile.
+        // if they differ, choose the "actual" number of channels *closest* to the "logical".
+        // and store THAT in proxy_config.channels
+        proxy_config.channels =
+                profile_get_closest_channel_count(in->profile, in->hal_channel_count);
+        proxy_prepare(&in->proxy, in->profile, &proxy_config);
+
+        in->standby = true;
+
+        in->conversion_buffer = NULL;
+        in->conversion_buffer_size = 0;
+
+        *stream_in = &in->stream;
+
+        /* Save this for adev_dump() */
+        adev_add_stream_to_list(in->adev, &in->adev->input_stream_list, &in->list_node);
+    } else {
+        // Deallocate this stream on error, because AudioFlinger won't call
+        // adev_close_input_stream() in this case.
+        *stream_in = NULL;
+        free(in);
+    }
 
     return ret;
 }
 
-static void adev_close_input_stream(struct audio_hw_device *dev, struct audio_stream_in *stream)
+static void adev_close_input_stream(struct audio_hw_device *hw_dev,
+                                    struct audio_stream_in *stream)
 {
     struct stream_in *in = (struct stream_in *)stream;
+    ALOGV("adev_close_input_stream(c:%d d:%d)", in->profile->card, in->profile->device);
+
+    adev_remove_stream_from_list(in->adev, &in->list_node);
 
     /* Close the pcm device */
     in_standby(&stream->common);
@@ -989,52 +1093,94 @@
 /*
  * ADEV Functions
  */
-static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs)
+static int adev_set_parameters(struct audio_hw_device *hw_dev, const char *kvpairs)
 {
     return 0;
 }
 
-static char * adev_get_parameters(const struct audio_hw_device *dev, const char *keys)
+static char * adev_get_parameters(const struct audio_hw_device *hw_dev, const char *keys)
 {
     return strdup("");
 }
 
-static int adev_init_check(const struct audio_hw_device *dev)
+static int adev_init_check(const struct audio_hw_device *hw_dev)
 {
     return 0;
 }
 
-static int adev_set_voice_volume(struct audio_hw_device *dev, float volume)
+static int adev_set_voice_volume(struct audio_hw_device *hw_dev, float volume)
 {
     return -ENOSYS;
 }
 
-static int adev_set_master_volume(struct audio_hw_device *dev, float volume)
+static int adev_set_master_volume(struct audio_hw_device *hw_dev, float volume)
 {
     return -ENOSYS;
 }
 
-static int adev_set_mode(struct audio_hw_device *dev, audio_mode_t mode)
+static int adev_set_mode(struct audio_hw_device *hw_dev, audio_mode_t mode)
 {
     return 0;
 }
 
-static int adev_set_mic_mute(struct audio_hw_device *dev, bool state)
+static int adev_set_mic_mute(struct audio_hw_device *hw_dev, bool state)
 {
-    struct audio_device * adev = (struct audio_device *)dev;
-    pthread_mutex_lock(&adev->lock);
+    struct audio_device * adev = (struct audio_device *)hw_dev;
+    device_lock(adev);
     adev->mic_muted = state;
-    pthread_mutex_unlock(&adev->lock);
+    device_unlock(adev);
     return -ENOSYS;
 }
 
-static int adev_get_mic_mute(const struct audio_hw_device *dev, bool *state)
+static int adev_get_mic_mute(const struct audio_hw_device *hw_dev, bool *state)
 {
     return -ENOSYS;
 }
 
-static int adev_dump(const audio_hw_device_t *device, int fd)
+static int adev_dump(const struct audio_hw_device *device, int fd)
 {
+    dprintf(fd, "\nUSB audio module:\n");
+
+    struct audio_device* adev = (struct audio_device*)device;
+    const int kNumRetries = 3;
+    const int kSleepTimeMS = 500;
+
+    // use device_try_lock() in case we dumpsys during a deadlock
+    int retry = kNumRetries;
+    while (retry > 0 && device_try_lock(adev) != 0) {
+      sleep(kSleepTimeMS);
+      retry--;
+    }
+
+    if (retry > 0) {
+        if (list_empty(&adev->output_stream_list)) {
+            dprintf(fd, "  No output streams.\n");
+        } else {
+            struct listnode* node;
+            list_for_each(node, &adev->output_stream_list) {
+                struct audio_stream* stream =
+                        (struct audio_stream *)node_to_item(node, struct stream_out, list_node);
+                out_dump(stream, fd);
+            }
+        }
+
+        if (list_empty(&adev->input_stream_list)) {
+            dprintf(fd, "\n  No input streams.\n");
+        } else {
+            struct listnode* node;
+            list_for_each(node, &adev->input_stream_list) {
+                struct audio_stream* stream =
+                        (struct audio_stream *)node_to_item(node, struct stream_in, list_node);
+                in_dump(stream, fd);
+            }
+        }
+
+        device_unlock(adev);
+    } else {
+        // Couldn't lock
+        dprintf(fd, "  Could not obtain device lock.\n");
+    }
+
     return 0;
 }
 
@@ -1058,6 +1204,9 @@
     profile_init(&adev->out_profile, PCM_OUT);
     profile_init(&adev->in_profile, PCM_IN);
 
+    list_init(&adev->output_stream_list);
+    list_init(&adev->input_stream_list);
+
     adev->hw_device.common.tag = HARDWARE_DEVICE_TAG;
     adev->hw_device.common.version = AUDIO_DEVICE_API_VERSION_2_0;
     adev->hw_device.common.module = (struct hw_module_t *)module;