Project import
diff --git a/libhardware_legacy/Android.mk b/libhardware_legacy/Android.mk
new file mode 100644
index 0000000..b0254f5
--- /dev/null
+++ b/libhardware_legacy/Android.mk
@@ -0,0 +1,54 @@
+# Copyright 2006 The Android Open Source Project
+
+# Setting LOCAL_PATH will mess up all-subdir-makefiles, so do it beforehand.
+legacy_modules := power uevent wifi 
+
+SAVE_MAKEFILES := $(call all-named-subdir-makefiles,$(legacy_modules))
+LEGACY_AUDIO_MAKEFILES := $(call all-named-subdir-makefiles,audio)
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SHARED_LIBRARIES := libcutils liblog libmedia
+
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+
+LOCAL_CFLAGS  += -DQEMU_HARDWARE -Wno-unused-parameter -Wno-gnu-designator
+QEMU_HARDWARE := true
+
+LOCAL_SHARED_LIBRARIES += libdl
+
+include $(SAVE_MAKEFILES)
+
+LOCAL_MODULE:= libhardware_legacy
+
+include $(BUILD_SHARED_LIBRARY)
+
+# static library for librpc
+include $(CLEAR_VARS)
+
+LOCAL_MODULE:= libpower
+
+LOCAL_SRC_FILES += power/power.c
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+
+include $(BUILD_STATIC_LIBRARY)
+
+# shared library for various HALs
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libpower
+
+LOCAL_SRC_FILES := power/power.c
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+
+LOCAL_SHARED_LIBRARIES := libcutils
+
+include $(BUILD_SHARED_LIBRARY)
+
+# legacy_audio builds it's own set of libraries that aren't linked into
+# hardware_legacy
+include $(LEGACY_AUDIO_MAKEFILES)
diff --git a/libhardware_legacy/CleanSpec.mk b/libhardware_legacy/CleanSpec.mk
new file mode 100644
index 0000000..56193a9
--- /dev/null
+++ b/libhardware_legacy/CleanSpec.mk
@@ -0,0 +1,51 @@
+# Copyright (C) 2007 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.
+#
+
+# If you don't need to do a full clean build but would like to touch
+# a file or delete some intermediate files, add a clean step to the end
+# of the list.  These steps will only be run once, if they haven't been
+# run before.
+#
+# E.g.:
+#     $(call add-clean-step, touch -c external/sqlite/sqlite3.h)
+#     $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates)
+#
+# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with
+# files that are missing or have been moved.
+#
+# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory.
+# Use $(OUT_DIR) to refer to the "out" directory.
+#
+# If you need to re-do something that's already mentioned, just copy
+# the command and add it to the bottom of the list.  E.g., if a change
+# that you made last week required touching a file and a change you
+# made today requires touching the same file, just copy the old
+# touch step and add it to the end of the list.
+#
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
+
+# For example:
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates)
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates)
+#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
+#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
+
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libhardware_legacy_intermediates/)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libhardware_legacy_intermediates/)
\ No newline at end of file
diff --git a/libhardware_legacy/MODULE_LICENSE_APACHE2 b/libhardware_legacy/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/libhardware_legacy/MODULE_LICENSE_APACHE2
diff --git a/libhardware_legacy/NOTICE b/libhardware_legacy/NOTICE
new file mode 100644
index 0000000..c5b1efa
--- /dev/null
+++ b/libhardware_legacy/NOTICE
@@ -0,0 +1,190 @@
+
+   Copyright (c) 2005-2008, 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.
+
+   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.
+
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
diff --git a/libhardware_legacy/audio/A2dpAudioInterface.cpp b/libhardware_legacy/audio/A2dpAudioInterface.cpp
new file mode 100644
index 0000000..50708ba
--- /dev/null
+++ b/libhardware_legacy/audio/A2dpAudioInterface.cpp
@@ -0,0 +1,500 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <math.h>
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "A2dpAudioInterface"
+#include <utils/Log.h>
+#include <utils/String8.h>
+#include <utils/Timers.h>
+
+#include "A2dpAudioInterface.h"
+#include "audio/liba2dp.h"
+#include <hardware_legacy/power.h>
+
+
+namespace android_audio_legacy {
+
+static const char *sA2dpWakeLock = "A2dpOutputStream";
+#define MAX_WRITE_RETRIES  5
+
+// ----------------------------------------------------------------------------
+
+//AudioHardwareInterface* A2dpAudioInterface::createA2dpInterface()
+//{
+//    AudioHardwareInterface* hw = 0;
+//
+//    hw = AudioHardwareInterface::create();
+//    ALOGD("new A2dpAudioInterface(hw: %p)", hw);
+//    hw = new A2dpAudioInterface(hw);
+//    return hw;
+//}
+
+A2dpAudioInterface::A2dpAudioInterface(AudioHardwareInterface* hw) :
+    mOutput(0), mHardwareInterface(hw), mBluetoothEnabled(true), mSuspended(false)
+{
+}
+
+A2dpAudioInterface::~A2dpAudioInterface()
+{
+    closeOutputStream((AudioStreamOut *)mOutput);
+    delete mHardwareInterface;
+}
+
+status_t A2dpAudioInterface::initCheck()
+{
+    if (mHardwareInterface == 0) return NO_INIT;
+    return mHardwareInterface->initCheck();
+}
+
+AudioStreamOut* A2dpAudioInterface::openOutputStream(
+        uint32_t devices, int *format, uint32_t *channels, uint32_t *sampleRate, status_t *status)
+{
+    if (!audio_is_a2dp_out_device(devices)) {
+        ALOGV("A2dpAudioInterface::openOutputStream() open HW device: %x", devices);
+        return mHardwareInterface->openOutputStream(devices, format, channels, sampleRate, status);
+    }
+
+    status_t err = 0;
+
+    // only one output stream allowed
+    if (mOutput) {
+        if (status)
+            *status = -1;
+        return NULL;
+    }
+
+    // create new output stream
+    A2dpAudioStreamOut* out = new A2dpAudioStreamOut();
+    if ((err = out->set(devices, format, channels, sampleRate)) == NO_ERROR) {
+        mOutput = out;
+        mOutput->setBluetoothEnabled(mBluetoothEnabled);
+        mOutput->setSuspended(mSuspended);
+    } else {
+        delete out;
+    }
+
+    if (status)
+        *status = err;
+    return mOutput;
+}
+
+void A2dpAudioInterface::closeOutputStream(AudioStreamOut* out) {
+    if (mOutput == 0 || mOutput != out) {
+        mHardwareInterface->closeOutputStream(out);
+    }
+    else {
+        delete mOutput;
+        mOutput = 0;
+    }
+}
+
+
+AudioStreamIn* A2dpAudioInterface::openInputStream(
+        uint32_t devices, int *format, uint32_t *channels, uint32_t *sampleRate, status_t *status,
+        AudioSystem::audio_in_acoustics acoustics)
+{
+    return mHardwareInterface->openInputStream(devices, format, channels, sampleRate, status, acoustics);
+}
+
+void A2dpAudioInterface::closeInputStream(AudioStreamIn* in)
+{
+    return mHardwareInterface->closeInputStream(in);
+}
+
+status_t A2dpAudioInterface::setMode(int mode)
+{
+    return mHardwareInterface->setMode(mode);
+}
+
+status_t A2dpAudioInterface::setMicMute(bool state)
+{
+    return mHardwareInterface->setMicMute(state);
+}
+
+status_t A2dpAudioInterface::getMicMute(bool* state)
+{
+    return mHardwareInterface->getMicMute(state);
+}
+
+status_t A2dpAudioInterface::setParameters(const String8& keyValuePairs)
+{
+    AudioParameter param = AudioParameter(keyValuePairs);
+    String8 value;
+    String8 key;
+    status_t status = NO_ERROR;
+
+    ALOGV("setParameters() %s", keyValuePairs.string());
+
+    key = "bluetooth_enabled";
+    if (param.get(key, value) == NO_ERROR) {
+        mBluetoothEnabled = (value == "true");
+        if (mOutput) {
+            mOutput->setBluetoothEnabled(mBluetoothEnabled);
+        }
+        param.remove(key);
+    }
+    key = String8("A2dpSuspended");
+    if (param.get(key, value) == NO_ERROR) {
+        mSuspended = (value == "true");
+        if (mOutput) {
+            mOutput->setSuspended(mSuspended);
+        }
+        param.remove(key);
+    }
+
+    if (param.size()) {
+        status_t hwStatus = mHardwareInterface->setParameters(param.toString());
+        if (status == NO_ERROR) {
+            status = hwStatus;
+        }
+    }
+
+    return status;
+}
+
+String8 A2dpAudioInterface::getParameters(const String8& keys)
+{
+    AudioParameter param = AudioParameter(keys);
+    AudioParameter a2dpParam = AudioParameter();
+    String8 value;
+    String8 key;
+
+    key = "bluetooth_enabled";
+    if (param.get(key, value) == NO_ERROR) {
+        value = mBluetoothEnabled ? "true" : "false";
+        a2dpParam.add(key, value);
+        param.remove(key);
+    }
+    key = "A2dpSuspended";
+    if (param.get(key, value) == NO_ERROR) {
+        value = mSuspended ? "true" : "false";
+        a2dpParam.add(key, value);
+        param.remove(key);
+    }
+
+    String8 keyValuePairs  = a2dpParam.toString();
+
+    if (param.size()) {
+        if (keyValuePairs != "") {
+            keyValuePairs += ";";
+        }
+        keyValuePairs += mHardwareInterface->getParameters(param.toString());
+    }
+
+    ALOGV("getParameters() %s", keyValuePairs.string());
+    return keyValuePairs;
+}
+
+size_t A2dpAudioInterface::getInputBufferSize(uint32_t sampleRate, int format, int channelCount)
+{
+    return mHardwareInterface->getInputBufferSize(sampleRate, format, channelCount);
+}
+
+status_t A2dpAudioInterface::setVoiceVolume(float v)
+{
+    return mHardwareInterface->setVoiceVolume(v);
+}
+
+status_t A2dpAudioInterface::setMasterVolume(float v)
+{
+    return mHardwareInterface->setMasterVolume(v);
+}
+
+status_t A2dpAudioInterface::dump(int fd, const Vector<String16>& args)
+{
+    return mHardwareInterface->dumpState(fd, args);
+}
+
+// ----------------------------------------------------------------------------
+
+A2dpAudioInterface::A2dpAudioStreamOut::A2dpAudioStreamOut() :
+    mFd(-1), mStandby(true), mStartCount(0), mRetryCount(0), mData(NULL),
+    // assume BT enabled to start, this is safe because its only the
+    // enabled->disabled transition we are worried about
+    mBluetoothEnabled(true), mDevice(0), mClosing(false), mSuspended(false)
+{
+    // use any address by default
+    strcpy(mA2dpAddress, "00:00:00:00:00:00");
+    init();
+}
+
+status_t A2dpAudioInterface::A2dpAudioStreamOut::set(
+        uint32_t device, int *pFormat, uint32_t *pChannels, uint32_t *pRate)
+{
+    int lFormat = pFormat ? *pFormat : 0;
+    uint32_t lChannels = pChannels ? *pChannels : 0;
+    uint32_t lRate = pRate ? *pRate : 0;
+
+    ALOGD("A2dpAudioStreamOut::set %x, %d, %d, %d\n", device, lFormat, lChannels, lRate);
+
+    // fix up defaults
+    if (lFormat == 0) lFormat = format();
+    if (lChannels == 0) lChannels = channels();
+    if (lRate == 0) lRate = sampleRate();
+
+    // check values
+    if ((lFormat != format()) ||
+            (lChannels != channels()) ||
+            (lRate != sampleRate())){
+        if (pFormat) *pFormat = format();
+        if (pChannels) *pChannels = channels();
+        if (pRate) *pRate = sampleRate();
+        return BAD_VALUE;
+    }
+
+    if (pFormat) *pFormat = lFormat;
+    if (pChannels) *pChannels = lChannels;
+    if (pRate) *pRate = lRate;
+
+    mDevice = device;
+    mBufferDurationUs = ((bufferSize() * 1000 )/ frameSize() / sampleRate()) * 1000;
+    return NO_ERROR;
+}
+
+A2dpAudioInterface::A2dpAudioStreamOut::~A2dpAudioStreamOut()
+{
+    ALOGV("A2dpAudioStreamOut destructor");
+    close();
+    ALOGV("A2dpAudioStreamOut destructor returning from close()");
+}
+
+ssize_t A2dpAudioInterface::A2dpAudioStreamOut::write(const void* buffer, size_t bytes)
+{
+    status_t status = -1;
+    {
+        Mutex::Autolock lock(mLock);
+
+        size_t remaining = bytes;
+
+        if (!mBluetoothEnabled || mClosing || mSuspended) {
+            ALOGV("A2dpAudioStreamOut::write(), but bluetooth disabled \
+                   mBluetoothEnabled %d, mClosing %d, mSuspended %d",
+                    mBluetoothEnabled, mClosing, mSuspended);
+            goto Error;
+        }
+
+        if (mStandby) {
+            acquire_wake_lock (PARTIAL_WAKE_LOCK, sA2dpWakeLock);
+            mStandby = false;
+            mLastWriteTime = systemTime();
+        }
+
+        status = init();
+        if (status < 0)
+            goto Error;
+
+        int retries = MAX_WRITE_RETRIES;
+        while (remaining > 0 && retries) {
+            status = a2dp_write(mData, buffer, remaining);
+            if (status < 0) {
+                ALOGE("a2dp_write failed err: %d\n", status);
+                goto Error;
+            }
+            if (status == 0) {
+                retries--;
+            }
+            remaining -= status;
+            buffer = (char *)buffer + status;
+        }
+
+        // if A2DP sink runs abnormally fast, sleep a little so that audioflinger mixer thread
+        // does no spin and starve other threads.
+        // NOTE: It is likely that the A2DP headset is being disconnected
+        nsecs_t now = systemTime();
+        if ((uint32_t)ns2us(now - mLastWriteTime) < (mBufferDurationUs >> 2)) {
+            ALOGV("A2DP sink runs too fast");
+            usleep(mBufferDurationUs - (uint32_t)ns2us(now - mLastWriteTime));
+        }
+        mLastWriteTime = now;
+        return bytes;
+
+    }
+Error:
+
+    standby();
+
+    // Simulate audio output timing in case of error
+    usleep(mBufferDurationUs);
+
+    return status;
+}
+
+status_t A2dpAudioInterface::A2dpAudioStreamOut::init()
+{
+    if (!mData) {
+        status_t status = a2dp_init(44100, 2, &mData);
+        if (status < 0) {
+            ALOGE("a2dp_init failed err: %d\n", status);
+            mData = NULL;
+            return status;
+        }
+        a2dp_set_sink(mData, mA2dpAddress);
+    }
+
+    return 0;
+}
+
+status_t A2dpAudioInterface::A2dpAudioStreamOut::standby()
+{
+    Mutex::Autolock lock(mLock);
+    return standby_l();
+}
+
+status_t A2dpAudioInterface::A2dpAudioStreamOut::standby_l()
+{
+    int result = NO_ERROR;
+
+    if (!mStandby) {
+        ALOGV_IF(mClosing || !mBluetoothEnabled, "Standby skip stop: closing %d enabled %d",
+                mClosing, mBluetoothEnabled);
+        if (!mClosing && mBluetoothEnabled) {
+            result = a2dp_stop(mData);
+        }
+        release_wake_lock(sA2dpWakeLock);
+        mStandby = true;
+    }
+
+    return result;
+}
+
+status_t A2dpAudioInterface::A2dpAudioStreamOut::setParameters(const String8& keyValuePairs)
+{
+    AudioParameter param = AudioParameter(keyValuePairs);
+    String8 value;
+    String8 key = String8("a2dp_sink_address");
+    status_t status = NO_ERROR;
+    int device;
+    ALOGV("A2dpAudioStreamOut::setParameters() %s", keyValuePairs.string());
+
+    if (param.get(key, value) == NO_ERROR) {
+        if (value.length() != strlen("00:00:00:00:00:00")) {
+            status = BAD_VALUE;
+        } else {
+            setAddress(value.string());
+        }
+        param.remove(key);
+    }
+    key = String8("closing");
+    if (param.get(key, value) == NO_ERROR) {
+        mClosing = (value == "true");
+        if (mClosing) {
+            standby();
+        }
+        param.remove(key);
+    }
+    key = AudioParameter::keyRouting;
+    if (param.getInt(key, device) == NO_ERROR) {
+        if (audio_is_a2dp_out_device(device)) {
+            mDevice = device;
+            status = NO_ERROR;
+        } else {
+            status = BAD_VALUE;
+        }
+        param.remove(key);
+    }
+
+    if (param.size()) {
+        status = BAD_VALUE;
+    }
+    return status;
+}
+
+String8 A2dpAudioInterface::A2dpAudioStreamOut::getParameters(const String8& keys)
+{
+    AudioParameter param = AudioParameter(keys);
+    String8 value;
+    String8 key = String8("a2dp_sink_address");
+
+    if (param.get(key, value) == NO_ERROR) {
+        value = mA2dpAddress;
+        param.add(key, value);
+    }
+    key = AudioParameter::keyRouting;
+    if (param.get(key, value) == NO_ERROR) {
+        param.addInt(key, (int)mDevice);
+    }
+
+    ALOGV("A2dpAudioStreamOut::getParameters() %s", param.toString().string());
+    return param.toString();
+}
+
+status_t A2dpAudioInterface::A2dpAudioStreamOut::setAddress(const char* address)
+{
+    Mutex::Autolock lock(mLock);
+
+    if (strlen(address) != strlen("00:00:00:00:00:00"))
+        return -EINVAL;
+
+    strcpy(mA2dpAddress, address);
+    if (mData)
+        a2dp_set_sink(mData, mA2dpAddress);
+
+    return NO_ERROR;
+}
+
+status_t A2dpAudioInterface::A2dpAudioStreamOut::setBluetoothEnabled(bool enabled)
+{
+    ALOGD("setBluetoothEnabled %d", enabled);
+
+    Mutex::Autolock lock(mLock);
+
+    mBluetoothEnabled = enabled;
+    if (!enabled) {
+        return close_l();
+    }
+    return NO_ERROR;
+}
+
+status_t A2dpAudioInterface::A2dpAudioStreamOut::setSuspended(bool onOff)
+{
+    ALOGV("setSuspended %d", onOff);
+    mSuspended = onOff;
+    standby();
+    return NO_ERROR;
+}
+
+status_t A2dpAudioInterface::A2dpAudioStreamOut::close()
+{
+    Mutex::Autolock lock(mLock);
+    ALOGV("A2dpAudioStreamOut::close() calling close_l()");
+    return close_l();
+}
+
+status_t A2dpAudioInterface::A2dpAudioStreamOut::close_l()
+{
+    standby_l();
+    if (mData) {
+        ALOGV("A2dpAudioStreamOut::close_l() calling a2dp_cleanup(mData)");
+        a2dp_cleanup(mData);
+        mData = NULL;
+    }
+    return NO_ERROR;
+}
+
+status_t A2dpAudioInterface::A2dpAudioStreamOut::dump(int fd, const Vector<String16>& args)
+{
+    return NO_ERROR;
+}
+
+status_t A2dpAudioInterface::A2dpAudioStreamOut::getRenderPosition(uint32_t *driverFrames)
+{
+    //TODO: enable when supported by driver
+    return INVALID_OPERATION;
+}
+
+}; // namespace android
diff --git a/libhardware_legacy/audio/A2dpAudioInterface.h b/libhardware_legacy/audio/A2dpAudioInterface.h
new file mode 100644
index 0000000..8fe9745
--- /dev/null
+++ b/libhardware_legacy/audio/A2dpAudioInterface.h
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2008 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 A2DP_AUDIO_HARDWARE_H
+#define A2DP_AUDIO_HARDWARE_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/threads.h>
+
+#include <hardware_legacy/AudioHardwareBase.h>
+
+
+namespace android_audio_legacy {
+    using android::Mutex;
+
+class A2dpAudioInterface : public AudioHardwareBase
+{
+    class A2dpAudioStreamOut;
+
+public:
+                        A2dpAudioInterface(AudioHardwareInterface* hw);
+    virtual             ~A2dpAudioInterface();
+    virtual status_t    initCheck();
+
+    virtual status_t    setVoiceVolume(float volume);
+    virtual status_t    setMasterVolume(float volume);
+
+    virtual status_t    setMode(int mode);
+
+    // mic mute
+    virtual status_t    setMicMute(bool state);
+    virtual status_t    getMicMute(bool* state);
+
+    virtual status_t    setParameters(const String8& keyValuePairs);
+    virtual String8     getParameters(const String8& keys);
+
+    virtual size_t      getInputBufferSize(uint32_t sampleRate, int format, int channelCount);
+
+    // create I/O streams
+    virtual AudioStreamOut* openOutputStream(
+                                uint32_t devices,
+                                int *format=0,
+                                uint32_t *channels=0,
+                                uint32_t *sampleRate=0,
+                                status_t *status=0);
+    virtual    void        closeOutputStream(AudioStreamOut* out);
+
+    virtual AudioStreamIn* openInputStream(
+                                uint32_t devices,
+                                int *format,
+                                uint32_t *channels,
+                                uint32_t *sampleRate,
+                                status_t *status,
+                                AudioSystem::audio_in_acoustics acoustics);
+    virtual    void        closeInputStream(AudioStreamIn* in);
+//    static AudioHardwareInterface* createA2dpInterface();
+
+protected:
+    virtual status_t    dump(int fd, const Vector<String16>& args);
+
+private:
+    class A2dpAudioStreamOut : public AudioStreamOut {
+    public:
+                            A2dpAudioStreamOut();
+        virtual             ~A2dpAudioStreamOut();
+                status_t    set(uint32_t device,
+                                int *pFormat,
+                                uint32_t *pChannels,
+                                uint32_t *pRate);
+        virtual uint32_t    sampleRate() const { return 44100; }
+        // SBC codec wants a multiple of 512
+        virtual size_t      bufferSize() const { return 512 * 20; }
+        virtual uint32_t    channels() const { return AudioSystem::CHANNEL_OUT_STEREO; }
+        virtual int         format() const { return AudioSystem::PCM_16_BIT; }
+        virtual uint32_t    latency() const { return ((1000*bufferSize())/frameSize())/sampleRate() + 200; }
+        virtual status_t    setVolume(float left, float right) { return INVALID_OPERATION; }
+        virtual ssize_t     write(const void* buffer, size_t bytes);
+                status_t    standby();
+        virtual status_t    dump(int fd, const Vector<String16>& args);
+        virtual status_t    setParameters(const String8& keyValuePairs);
+        virtual String8     getParameters(const String8& keys);
+        virtual status_t    getRenderPosition(uint32_t *dspFrames);
+
+    private:
+        friend class A2dpAudioInterface;
+                status_t    init();
+                status_t    close();
+                status_t    close_l();
+                status_t    setAddress(const char* address);
+                status_t    setBluetoothEnabled(bool enabled);
+                status_t    setSuspended(bool onOff);
+                status_t    standby_l();
+
+    private:
+                int         mFd;
+                bool        mStandby;
+                int         mStartCount;
+                int         mRetryCount;
+                char        mA2dpAddress[20];
+                void*       mData;
+                Mutex       mLock;
+                bool        mBluetoothEnabled;
+                uint32_t    mDevice;
+                bool        mClosing;
+                bool        mSuspended;
+                nsecs_t     mLastWriteTime;
+                uint32_t    mBufferDurationUs;
+    };
+
+    friend class A2dpAudioStreamOut;
+
+    A2dpAudioStreamOut*     mOutput;
+    AudioHardwareInterface  *mHardwareInterface;
+    char        mA2dpAddress[20];
+    bool        mBluetoothEnabled;
+    bool        mSuspended;
+};
+
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // A2DP_AUDIO_HARDWARE_H
diff --git a/libhardware_legacy/audio/Android.mk b/libhardware_legacy/audio/Android.mk
new file mode 100644
index 0000000..d9d2d6a
--- /dev/null
+++ b/libhardware_legacy/audio/Android.mk
@@ -0,0 +1,89 @@
+# Copyright 2011 The Android Open Source Project
+
+#AUDIO_POLICY_TEST := true
+#ENABLE_AUDIO_DUMP := true
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+    AudioHardwareInterface.cpp \
+    audio_hw_hal.cpp
+
+LOCAL_MODULE := libaudiohw_legacy
+LOCAL_SHARED_LIBRARIES := libmedia
+LOCAL_STATIC_LIBRARIES := libmedia_helper
+LOCAL_CFLAGS := -Wno-unused-parameter -Wno-gnu-designator
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/../include
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/../include
+
+include $(BUILD_STATIC_LIBRARY)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+    AudioPolicyManagerBase.cpp \
+    AudioPolicyCompatClient.cpp \
+    audio_policy_hal.cpp
+
+ifeq ($(AUDIO_POLICY_TEST),true)
+  LOCAL_CFLAGS += -DAUDIO_POLICY_TEST
+endif
+
+LOCAL_SHARED_LIBRARIES := libmedia
+LOCAL_STATIC_LIBRARIES := libmedia_helper
+LOCAL_MODULE := libaudiopolicy_legacy
+LOCAL_CFLAGS += -Wno-unused-parameter
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/../include
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/../include
+
+include $(BUILD_STATIC_LIBRARY)
+
+# The default audio policy, for now still implemented on top of legacy
+# policy code
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+    AudioPolicyManagerDefault.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+    libcutils \
+    libmedia \
+    libutils \
+    liblog
+
+LOCAL_STATIC_LIBRARIES := \
+    libmedia_helper
+
+LOCAL_WHOLE_STATIC_LIBRARIES := \
+    libaudiopolicy_legacy
+
+LOCAL_MODULE := audio_policy.default
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_CFLAGS := -Wno-unused-parameter
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/../include
+
+include $(BUILD_SHARED_LIBRARY)
+
+#ifeq ($(ENABLE_AUDIO_DUMP),true)
+#  LOCAL_SRC_FILES += AudioDumpInterface.cpp
+#  LOCAL_CFLAGS += -DENABLE_AUDIO_DUMP
+#endif
+#
+#ifeq ($(strip $(BOARD_USES_GENERIC_AUDIO)),true)
+#  LOCAL_CFLAGS += -D GENERIC_AUDIO
+#endif
+
+#ifeq ($(BOARD_HAVE_BLUETOOTH),true)
+#  LOCAL_SRC_FILES += A2dpAudioInterface.cpp
+#  LOCAL_SHARED_LIBRARIES += liba2dp
+#  LOCAL_C_INCLUDES += $(call include-path-for, bluez)
+#
+#  LOCAL_CFLAGS += \
+#      -DWITH_BLUETOOTH \
+#endif
+#
+#include $(BUILD_SHARED_LIBRARY)
+
+#    AudioHardwareGeneric.cpp \
+#    AudioHardwareStub.cpp \
diff --git a/libhardware_legacy/audio/AudioDumpInterface.cpp b/libhardware_legacy/audio/AudioDumpInterface.cpp
new file mode 100644
index 0000000..62fdbd6
--- /dev/null
+++ b/libhardware_legacy/audio/AudioDumpInterface.cpp
@@ -0,0 +1,573 @@
+/* //device/servers/AudioFlinger/AudioDumpInterface.cpp
+**
+** Copyright 2008, 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 "AudioFlingerDump"
+//#define LOG_NDEBUG 0
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <utils/Log.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "AudioDumpInterface.h"
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+AudioDumpInterface::AudioDumpInterface(AudioHardwareInterface* hw)
+    : mPolicyCommands(String8("")), mFileName(String8(""))
+{
+    if(hw == 0) {
+        ALOGE("Dump construct hw = 0");
+    }
+    mFinalInterface = hw;
+    ALOGV("Constructor %p, mFinalInterface %p", this, mFinalInterface);
+}
+
+
+AudioDumpInterface::~AudioDumpInterface()
+{
+    for (size_t i = 0; i < mOutputs.size(); i++) {
+        closeOutputStream((AudioStreamOut *)mOutputs[i]);
+    }
+
+    for (size_t i = 0; i < mInputs.size(); i++) {
+        closeInputStream((AudioStreamIn *)mInputs[i]);
+    }
+
+    if(mFinalInterface) delete mFinalInterface;
+}
+
+
+AudioStreamOut* AudioDumpInterface::openOutputStream(
+        uint32_t devices, int *format, uint32_t *channels, uint32_t *sampleRate, status_t *status)
+{
+    AudioStreamOut* outFinal = NULL;
+    int lFormat = AudioSystem::PCM_16_BIT;
+    uint32_t lChannels = AudioSystem::CHANNEL_OUT_STEREO;
+    uint32_t lRate = 44100;
+
+
+    outFinal = mFinalInterface->openOutputStream(devices, format, channels, sampleRate, status);
+    if (outFinal != 0) {
+        lFormat = outFinal->format();
+        lChannels = outFinal->channels();
+        lRate = outFinal->sampleRate();
+    } else {
+        if (format != 0) {
+            if (*format != 0) {
+                lFormat = *format;
+            } else {
+                *format = lFormat;
+            }
+        }
+        if (channels != 0) {
+            if (*channels != 0) {
+                lChannels = *channels;
+            } else {
+                *channels = lChannels;
+            }
+        }
+        if (sampleRate != 0) {
+            if (*sampleRate != 0) {
+                lRate = *sampleRate;
+            } else {
+                *sampleRate = lRate;
+            }
+        }
+        if (status) *status = NO_ERROR;
+    }
+    ALOGV("openOutputStream(), outFinal %p", outFinal);
+
+    AudioStreamOutDump *dumOutput = new AudioStreamOutDump(this, mOutputs.size(), outFinal,
+            devices, lFormat, lChannels, lRate);
+    mOutputs.add(dumOutput);
+
+    return dumOutput;
+}
+
+void AudioDumpInterface::closeOutputStream(AudioStreamOut* out)
+{
+    AudioStreamOutDump *dumpOut = (AudioStreamOutDump *)out;
+
+    if (mOutputs.indexOf(dumpOut) < 0) {
+        ALOGW("Attempt to close invalid output stream");
+        return;
+    }
+
+    ALOGV("closeOutputStream() output %p", out);
+
+    dumpOut->standby();
+    if (dumpOut->finalStream() != NULL) {
+        mFinalInterface->closeOutputStream(dumpOut->finalStream());
+    }
+
+    mOutputs.remove(dumpOut);
+    delete dumpOut;
+}
+
+AudioStreamIn* AudioDumpInterface::openInputStream(uint32_t devices, int *format, uint32_t *channels,
+        uint32_t *sampleRate, status_t *status, AudioSystem::audio_in_acoustics acoustics)
+{
+    AudioStreamIn* inFinal = NULL;
+    int lFormat = AudioSystem::PCM_16_BIT;
+    uint32_t lChannels = AudioSystem::CHANNEL_IN_MONO;
+    uint32_t lRate = 8000;
+
+    inFinal = mFinalInterface->openInputStream(devices, format, channels, sampleRate, status, acoustics);
+    if (inFinal != 0) {
+        lFormat = inFinal->format();
+        lChannels = inFinal->channels();
+        lRate = inFinal->sampleRate();
+    } else {
+        if (format != 0) {
+            if (*format != 0) {
+                lFormat = *format;
+            } else {
+                *format = lFormat;
+            }
+        }
+        if (channels != 0) {
+            if (*channels != 0) {
+                lChannels = *channels;
+            } else {
+                *channels = lChannels;
+            }
+        }
+        if (sampleRate != 0) {
+            if (*sampleRate != 0) {
+                lRate = *sampleRate;
+            } else {
+                *sampleRate = lRate;
+            }
+        }
+        if (status) *status = NO_ERROR;
+    }
+    ALOGV("openInputStream(), inFinal %p", inFinal);
+
+    AudioStreamInDump *dumInput = new AudioStreamInDump(this, mInputs.size(), inFinal,
+            devices, lFormat, lChannels, lRate);
+    mInputs.add(dumInput);
+
+    return dumInput;
+}
+void AudioDumpInterface::closeInputStream(AudioStreamIn* in)
+{
+    AudioStreamInDump *dumpIn = (AudioStreamInDump *)in;
+
+    if (mInputs.indexOf(dumpIn) < 0) {
+        ALOGW("Attempt to close invalid input stream");
+        return;
+    }
+    dumpIn->standby();
+    if (dumpIn->finalStream() != NULL) {
+        mFinalInterface->closeInputStream(dumpIn->finalStream());
+    }
+
+    mInputs.remove(dumpIn);
+    delete dumpIn;
+}
+
+
+status_t AudioDumpInterface::setParameters(const String8& keyValuePairs)
+{
+    AudioParameter param = AudioParameter(keyValuePairs);
+    String8 value;
+    int valueInt;
+    ALOGV("setParameters %s", keyValuePairs.string());
+
+    if (param.get(String8("test_cmd_file_name"), value) == NO_ERROR) {
+        mFileName = value;
+        param.remove(String8("test_cmd_file_name"));
+    }
+    if (param.get(String8("test_cmd_policy"), value) == NO_ERROR) {
+        Mutex::Autolock _l(mLock);
+        param.remove(String8("test_cmd_policy"));
+        mPolicyCommands = param.toString();
+        ALOGV("test_cmd_policy command %s written", mPolicyCommands.string());
+        return NO_ERROR;
+    }
+
+    if (mFinalInterface != 0 ) return mFinalInterface->setParameters(keyValuePairs);
+    return NO_ERROR;
+}
+
+String8 AudioDumpInterface::getParameters(const String8& keys)
+{
+    AudioParameter param = AudioParameter(keys);
+    AudioParameter response;
+    String8 value;
+
+//    ALOGV("getParameters %s", keys.string());
+    if (param.get(String8("test_cmd_policy"), value) == NO_ERROR) {
+        Mutex::Autolock _l(mLock);
+        if (mPolicyCommands.length() != 0) {
+            response = AudioParameter(mPolicyCommands);
+            response.addInt(String8("test_cmd_policy"), 1);
+        } else {
+            response.addInt(String8("test_cmd_policy"), 0);
+        }
+        param.remove(String8("test_cmd_policy"));
+//        ALOGV("test_cmd_policy command %s read", mPolicyCommands.string());
+    }
+
+    if (param.get(String8("test_cmd_file_name"), value) == NO_ERROR) {
+        response.add(String8("test_cmd_file_name"), mFileName);
+        param.remove(String8("test_cmd_file_name"));
+    }
+
+    String8 keyValuePairs = response.toString();
+
+    if (param.size() && mFinalInterface != 0 ) {
+        keyValuePairs += ";";
+        keyValuePairs += mFinalInterface->getParameters(param.toString());
+    }
+
+    return keyValuePairs;
+}
+
+status_t AudioDumpInterface::setMode(int mode)
+{
+    return mFinalInterface->setMode(mode);
+}
+
+size_t AudioDumpInterface::getInputBufferSize(uint32_t sampleRate, int format, int channelCount)
+{
+    return mFinalInterface->getInputBufferSize(sampleRate, format, channelCount);
+}
+
+// ----------------------------------------------------------------------------
+
+AudioStreamOutDump::AudioStreamOutDump(AudioDumpInterface *interface,
+                                        int id,
+                                        AudioStreamOut* finalStream,
+                                        uint32_t devices,
+                                        int format,
+                                        uint32_t channels,
+                                        uint32_t sampleRate)
+    : mInterface(interface), mId(id),
+      mSampleRate(sampleRate), mFormat(format), mChannels(channels), mLatency(0), mDevice(devices),
+      mBufferSize(1024), mFinalStream(finalStream), mFile(0), mFileCount(0)
+{
+    ALOGV("AudioStreamOutDump Constructor %p, mInterface %p, mFinalStream %p", this, mInterface, mFinalStream);
+}
+
+
+AudioStreamOutDump::~AudioStreamOutDump()
+{
+    ALOGV("AudioStreamOutDump destructor");
+    Close();
+}
+
+ssize_t AudioStreamOutDump::write(const void* buffer, size_t bytes)
+{
+    ssize_t ret;
+
+    if (mFinalStream) {
+        ret = mFinalStream->write(buffer, bytes);
+    } else {
+        usleep((((bytes * 1000) / frameSize()) / sampleRate()) * 1000);
+        ret = bytes;
+    }
+    if(!mFile) {
+        if (mInterface->fileName() != "") {
+            char name[255];
+            sprintf(name, "%s_out_%d_%d.pcm", mInterface->fileName().string(), mId, ++mFileCount);
+            mFile = fopen(name, "wb");
+            ALOGV("Opening dump file %s, fh %p", name, mFile);
+        }
+    }
+    if (mFile) {
+        fwrite(buffer, bytes, 1, mFile);
+    }
+    return ret;
+}
+
+status_t AudioStreamOutDump::standby()
+{
+    ALOGV("AudioStreamOutDump standby(), mFile %p, mFinalStream %p", mFile, mFinalStream);
+
+    Close();
+    if (mFinalStream != 0 ) return mFinalStream->standby();
+    return NO_ERROR;
+}
+
+uint32_t AudioStreamOutDump::sampleRate() const
+{
+    if (mFinalStream != 0 ) return mFinalStream->sampleRate();
+    return mSampleRate;
+}
+
+size_t AudioStreamOutDump::bufferSize() const
+{
+    if (mFinalStream != 0 ) return mFinalStream->bufferSize();
+    return mBufferSize;
+}
+
+uint32_t AudioStreamOutDump::channels() const
+{
+    if (mFinalStream != 0 ) return mFinalStream->channels();
+    return mChannels;
+}
+int AudioStreamOutDump::format() const
+{
+    if (mFinalStream != 0 ) return mFinalStream->format();
+    return mFormat;
+}
+uint32_t AudioStreamOutDump::latency() const
+{
+    if (mFinalStream != 0 ) return mFinalStream->latency();
+    return 0;
+}
+status_t AudioStreamOutDump::setVolume(float left, float right)
+{
+    if (mFinalStream != 0 ) return mFinalStream->setVolume(left, right);
+    return NO_ERROR;
+}
+status_t AudioStreamOutDump::setParameters(const String8& keyValuePairs)
+{
+    ALOGV("AudioStreamOutDump::setParameters %s", keyValuePairs.string());
+
+    if (mFinalStream != 0 ) {
+        return mFinalStream->setParameters(keyValuePairs);
+    }
+
+    AudioParameter param = AudioParameter(keyValuePairs);
+    String8 value;
+    int valueInt;
+    status_t status = NO_ERROR;
+
+    if (param.getInt(String8("set_id"), valueInt) == NO_ERROR) {
+        mId = valueInt;
+    }
+
+    if (param.getInt(String8("format"), valueInt) == NO_ERROR) {
+        if (mFile == 0) {
+            mFormat = valueInt;
+        } else {
+            status = INVALID_OPERATION;
+        }
+    }
+    if (param.getInt(String8("channels"), valueInt) == NO_ERROR) {
+        if (valueInt == AudioSystem::CHANNEL_OUT_STEREO || valueInt == AudioSystem::CHANNEL_OUT_MONO) {
+            mChannels = valueInt;
+        } else {
+            status = BAD_VALUE;
+        }
+    }
+    if (param.getInt(String8("sampling_rate"), valueInt) == NO_ERROR) {
+        if (valueInt > 0 && valueInt <= 48000) {
+            if (mFile == 0) {
+                mSampleRate = valueInt;
+            } else {
+                status = INVALID_OPERATION;
+            }
+        } else {
+            status = BAD_VALUE;
+        }
+    }
+    return status;
+}
+
+String8 AudioStreamOutDump::getParameters(const String8& keys)
+{
+    if (mFinalStream != 0 ) return mFinalStream->getParameters(keys);
+
+    AudioParameter param = AudioParameter(keys);
+    return param.toString();
+}
+
+status_t AudioStreamOutDump::dump(int fd, const Vector<String16>& args)
+{
+    if (mFinalStream != 0 ) return mFinalStream->dump(fd, args);
+    return NO_ERROR;
+}
+
+void AudioStreamOutDump::Close()
+{
+    if(mFile) {
+        fclose(mFile);
+        mFile = 0;
+    }
+}
+
+status_t AudioStreamOutDump::getRenderPosition(uint32_t *dspFrames)
+{
+    if (mFinalStream != 0 ) return mFinalStream->getRenderPosition(dspFrames);
+    return INVALID_OPERATION;
+}
+
+// ----------------------------------------------------------------------------
+
+AudioStreamInDump::AudioStreamInDump(AudioDumpInterface *interface,
+                                        int id,
+                                        AudioStreamIn* finalStream,
+                                        uint32_t devices,
+                                        int format,
+                                        uint32_t channels,
+                                        uint32_t sampleRate)
+    : mInterface(interface), mId(id),
+      mSampleRate(sampleRate), mFormat(format), mChannels(channels), mDevice(devices),
+      mBufferSize(1024), mFinalStream(finalStream), mFile(0), mFileCount(0)
+{
+    ALOGV("AudioStreamInDump Constructor %p, mInterface %p, mFinalStream %p", this, mInterface, mFinalStream);
+}
+
+
+AudioStreamInDump::~AudioStreamInDump()
+{
+    Close();
+}
+
+ssize_t AudioStreamInDump::read(void* buffer, ssize_t bytes)
+{
+    ssize_t ret;
+
+    if (mFinalStream) {
+        ret = mFinalStream->read(buffer, bytes);
+        if(!mFile) {
+            if (mInterface->fileName() != "") {
+                char name[255];
+                sprintf(name, "%s_in_%d_%d.pcm", mInterface->fileName().string(), mId, ++mFileCount);
+                mFile = fopen(name, "wb");
+                ALOGV("Opening input dump file %s, fh %p", name, mFile);
+            }
+        }
+        if (mFile) {
+            fwrite(buffer, bytes, 1, mFile);
+        }
+    } else {
+        usleep((((bytes * 1000) / frameSize()) / sampleRate()) * 1000);
+        ret = bytes;
+        if(!mFile) {
+            char name[255];
+            strcpy(name, "/sdcard/music/sine440");
+            if (channels() == AudioSystem::CHANNEL_IN_MONO) {
+                strcat(name, "_mo");
+            } else {
+                strcat(name, "_st");
+            }
+            if (format() == AudioSystem::PCM_16_BIT) {
+                strcat(name, "_16b");
+            } else {
+                strcat(name, "_8b");
+            }
+            if (sampleRate() < 16000) {
+                strcat(name, "_8k");
+            } else if (sampleRate() < 32000) {
+                strcat(name, "_22k");
+            } else if (sampleRate() < 48000) {
+                strcat(name, "_44k");
+            } else {
+                strcat(name, "_48k");
+            }
+            strcat(name, ".wav");
+            mFile = fopen(name, "rb");
+            ALOGV("Opening input read file %s, fh %p", name, mFile);
+            if (mFile) {
+                fseek(mFile, AUDIO_DUMP_WAVE_HDR_SIZE, SEEK_SET);
+            }
+        }
+        if (mFile) {
+            ssize_t bytesRead = fread(buffer, bytes, 1, mFile);
+            if (bytesRead >=0 && bytesRead < bytes) {
+                fseek(mFile, AUDIO_DUMP_WAVE_HDR_SIZE, SEEK_SET);
+                fread((uint8_t *)buffer+bytesRead, bytes-bytesRead, 1, mFile);
+            }
+        }
+    }
+
+    return ret;
+}
+
+status_t AudioStreamInDump::standby()
+{
+    ALOGV("AudioStreamInDump standby(), mFile %p, mFinalStream %p", mFile, mFinalStream);
+
+    Close();
+    if (mFinalStream != 0 ) return mFinalStream->standby();
+    return NO_ERROR;
+}
+
+status_t AudioStreamInDump::setGain(float gain)
+{
+    if (mFinalStream != 0 ) return mFinalStream->setGain(gain);
+    return NO_ERROR;
+}
+
+uint32_t AudioStreamInDump::sampleRate() const
+{
+    if (mFinalStream != 0 ) return mFinalStream->sampleRate();
+    return mSampleRate;
+}
+
+size_t AudioStreamInDump::bufferSize() const
+{
+    if (mFinalStream != 0 ) return mFinalStream->bufferSize();
+    return mBufferSize;
+}
+
+uint32_t AudioStreamInDump::channels() const
+{
+    if (mFinalStream != 0 ) return mFinalStream->channels();
+    return mChannels;
+}
+
+int AudioStreamInDump::format() const
+{
+    if (mFinalStream != 0 ) return mFinalStream->format();
+    return mFormat;
+}
+
+status_t AudioStreamInDump::setParameters(const String8& keyValuePairs)
+{
+    ALOGV("AudioStreamInDump::setParameters()");
+    if (mFinalStream != 0 ) return mFinalStream->setParameters(keyValuePairs);
+    return NO_ERROR;
+}
+
+String8 AudioStreamInDump::getParameters(const String8& keys)
+{
+    if (mFinalStream != 0 ) return mFinalStream->getParameters(keys);
+
+    AudioParameter param = AudioParameter(keys);
+    return param.toString();
+}
+
+unsigned int AudioStreamInDump::getInputFramesLost() const
+{
+    if (mFinalStream != 0 ) return mFinalStream->getInputFramesLost();
+    return 0;
+}
+
+status_t AudioStreamInDump::dump(int fd, const Vector<String16>& args)
+{
+    if (mFinalStream != 0 ) return mFinalStream->dump(fd, args);
+    return NO_ERROR;
+}
+
+void AudioStreamInDump::Close()
+{
+    if(mFile) {
+        fclose(mFile);
+        mFile = 0;
+    }
+}
+}; // namespace android
diff --git a/libhardware_legacy/audio/AudioDumpInterface.h b/libhardware_legacy/audio/AudioDumpInterface.h
new file mode 100644
index 0000000..814ce5f
--- /dev/null
+++ b/libhardware_legacy/audio/AudioDumpInterface.h
@@ -0,0 +1,170 @@
+/* //device/servers/AudioFlinger/AudioDumpInterface.h
+**
+** Copyright 2008, 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_AUDIO_DUMP_INTERFACE_H
+#define ANDROID_AUDIO_DUMP_INTERFACE_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <utils/String8.h>
+#include <utils/SortedVector.h>
+
+#include <hardware_legacy/AudioHardwareBase.h>
+
+namespace android {
+
+#define AUDIO_DUMP_WAVE_HDR_SIZE 44
+
+class AudioDumpInterface;
+
+class AudioStreamOutDump : public AudioStreamOut {
+public:
+                        AudioStreamOutDump(AudioDumpInterface *interface,
+                                            int id,
+                                            AudioStreamOut* finalStream,
+                                            uint32_t devices,
+                                            int format,
+                                            uint32_t channels,
+                                            uint32_t sampleRate);
+                        ~AudioStreamOutDump();
+
+    virtual ssize_t     write(const void* buffer, size_t bytes);
+    virtual uint32_t    sampleRate() const;
+    virtual size_t      bufferSize() const;
+    virtual uint32_t    channels() const;
+    virtual int         format() const;
+    virtual uint32_t    latency() const;
+    virtual status_t    setVolume(float left, float right);
+    virtual status_t    standby();
+    virtual status_t    setParameters(const String8& keyValuePairs);
+    virtual String8     getParameters(const String8& keys);
+    virtual status_t    dump(int fd, const Vector<String16>& args);
+    void                Close(void);
+    AudioStreamOut*     finalStream() { return mFinalStream; }
+    uint32_t            device() { return mDevice; }
+    int                 getId()  { return mId; }
+    virtual status_t    getRenderPosition(uint32_t *dspFrames);
+
+private:
+    AudioDumpInterface *mInterface;
+    int                  mId;
+    uint32_t mSampleRate;               //
+    uint32_t mFormat;                   //
+    uint32_t mChannels;                 // output configuration
+    uint32_t mLatency;                  //
+    uint32_t mDevice;                   // current device this output is routed to
+    size_t  mBufferSize;
+    AudioStreamOut      *mFinalStream;
+    FILE                *mFile;      // output file
+    int                 mFileCount;
+};
+
+class AudioStreamInDump : public AudioStreamIn {
+public:
+                        AudioStreamInDump(AudioDumpInterface *interface,
+                                            int id,
+                                            AudioStreamIn* finalStream,
+                                            uint32_t devices,
+                                            int format,
+                                            uint32_t channels,
+                                            uint32_t sampleRate);
+                        ~AudioStreamInDump();
+
+    virtual uint32_t    sampleRate() const;
+    virtual size_t      bufferSize() const;
+    virtual uint32_t    channels() const;
+    virtual int         format() const;
+
+    virtual status_t    setGain(float gain);
+    virtual ssize_t     read(void* buffer, ssize_t bytes);
+    virtual status_t    standby();
+    virtual status_t    setParameters(const String8& keyValuePairs);
+    virtual String8     getParameters(const String8& keys);
+    virtual unsigned int  getInputFramesLost() const;
+    virtual status_t    dump(int fd, const Vector<String16>& args);
+    void                Close(void);
+    AudioStreamIn*     finalStream() { return mFinalStream; }
+    uint32_t            device() { return mDevice; }
+
+private:
+    AudioDumpInterface *mInterface;
+    int                  mId;
+    uint32_t mSampleRate;               //
+    uint32_t mFormat;                   //
+    uint32_t mChannels;                 // output configuration
+    uint32_t mDevice;                   // current device this output is routed to
+    size_t  mBufferSize;
+    AudioStreamIn      *mFinalStream;
+    FILE                *mFile;      // output file
+    int                 mFileCount;
+};
+
+class AudioDumpInterface : public AudioHardwareBase
+{
+
+public:
+                        AudioDumpInterface(AudioHardwareInterface* hw);
+    virtual AudioStreamOut* openOutputStream(
+                                uint32_t devices,
+                                int *format=0,
+                                uint32_t *channels=0,
+                                uint32_t *sampleRate=0,
+                                status_t *status=0);
+    virtual    void        closeOutputStream(AudioStreamOut* out);
+
+    virtual             ~AudioDumpInterface();
+
+    virtual status_t    initCheck()
+                            {return mFinalInterface->initCheck();}
+    virtual status_t    setVoiceVolume(float volume)
+                            {return mFinalInterface->setVoiceVolume(volume);}
+    virtual status_t    setMasterVolume(float volume)
+                            {return mFinalInterface->setMasterVolume(volume);}
+
+    virtual status_t    setMode(int mode);
+
+    // mic mute
+    virtual status_t    setMicMute(bool state)
+                            {return mFinalInterface->setMicMute(state);}
+    virtual status_t    getMicMute(bool* state)
+                            {return mFinalInterface->getMicMute(state);}
+
+    virtual status_t    setParameters(const String8& keyValuePairs);
+    virtual String8     getParameters(const String8& keys);
+
+    virtual size_t      getInputBufferSize(uint32_t sampleRate, int format, int channelCount);
+
+    virtual AudioStreamIn* openInputStream(uint32_t devices, int *format, uint32_t *channels,
+            uint32_t *sampleRate, status_t *status, AudioSystem::audio_in_acoustics acoustics);
+    virtual    void        closeInputStream(AudioStreamIn* in);
+
+    virtual status_t    dump(int fd, const Vector<String16>& args) { return mFinalInterface->dumpState(fd, args); }
+
+            String8     fileName() const { return mFileName; }
+protected:
+
+    AudioHardwareInterface          *mFinalInterface;
+    SortedVector<AudioStreamOutDump *>   mOutputs;
+    SortedVector<AudioStreamInDump *>    mInputs;
+    Mutex                           mLock;
+    String8                         mPolicyCommands;
+    String8                         mFileName;
+};
+
+}; // namespace android
+
+#endif // ANDROID_AUDIO_DUMP_INTERFACE_H
diff --git a/libhardware_legacy/audio/AudioHardwareGeneric.cpp b/libhardware_legacy/audio/AudioHardwareGeneric.cpp
new file mode 100644
index 0000000..a2b00f8
--- /dev/null
+++ b/libhardware_legacy/audio/AudioHardwareGeneric.cpp
@@ -0,0 +1,413 @@
+/*
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sched.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+
+#define LOG_TAG "AudioHardware"
+#include <utils/Log.h>
+#include <utils/String8.h>
+
+#include "AudioHardwareGeneric.h"
+#include <media/AudioRecord.h>
+
+#include <hardware_legacy/AudioSystemLegacy.h>
+
+namespace android_audio_legacy {
+
+// ----------------------------------------------------------------------------
+
+static char const * const kAudioDeviceName = "/dev/eac";
+
+// ----------------------------------------------------------------------------
+
+AudioHardwareGeneric::AudioHardwareGeneric()
+    : mOutput(0), mInput(0),  mFd(-1), mMicMute(false)
+{
+    mFd = ::open(kAudioDeviceName, O_RDWR);
+}
+
+AudioHardwareGeneric::~AudioHardwareGeneric()
+{
+    if (mFd >= 0) ::close(mFd);
+    closeOutputStream((AudioStreamOut *)mOutput);
+    closeInputStream((AudioStreamIn *)mInput);
+}
+
+status_t AudioHardwareGeneric::initCheck()
+{
+    if (mFd >= 0) {
+        if (::access(kAudioDeviceName, O_RDWR) == NO_ERROR)
+            return NO_ERROR;
+    }
+    return NO_INIT;
+}
+
+AudioStreamOut* AudioHardwareGeneric::openOutputStream(
+        uint32_t devices, int *format, uint32_t *channels, uint32_t *sampleRate, status_t *status)
+{
+    AutoMutex lock(mLock);
+
+    // only one output stream allowed
+    if (mOutput) {
+        if (status) {
+            *status = INVALID_OPERATION;
+        }
+        return 0;
+    }
+
+    // create new output stream
+    AudioStreamOutGeneric* out = new AudioStreamOutGeneric();
+    status_t lStatus = out->set(this, mFd, devices, format, channels, sampleRate);
+    if (status) {
+        *status = lStatus;
+    }
+    if (lStatus == NO_ERROR) {
+        mOutput = out;
+    } else {
+        delete out;
+    }
+    return mOutput;
+}
+
+void AudioHardwareGeneric::closeOutputStream(AudioStreamOut* out) {
+    if (mOutput && out == mOutput) {
+        delete mOutput;
+        mOutput = 0;
+    }
+}
+
+AudioStreamIn* AudioHardwareGeneric::openInputStream(
+        uint32_t devices, int *format, uint32_t *channels, uint32_t *sampleRate,
+        status_t *status, AudioSystem::audio_in_acoustics acoustics)
+{
+    // check for valid input source
+    if (!AudioSystem::isInputDevice((AudioSystem::audio_devices)devices)) {
+        return 0;
+    }
+
+    AutoMutex lock(mLock);
+
+    // only one input stream allowed
+    if (mInput) {
+        if (status) {
+            *status = INVALID_OPERATION;
+        }
+        return 0;
+    }
+
+    // create new output stream
+    AudioStreamInGeneric* in = new AudioStreamInGeneric();
+    status_t lStatus = in->set(this, mFd, devices, format, channels, sampleRate, acoustics);
+    if (status) {
+        *status = lStatus;
+    }
+    if (lStatus == NO_ERROR) {
+        mInput = in;
+    } else {
+        delete in;
+    }
+    return mInput;
+}
+
+void AudioHardwareGeneric::closeInputStream(AudioStreamIn* in) {
+    if (mInput && in == mInput) {
+        delete mInput;
+        mInput = 0;
+    }
+}
+
+status_t AudioHardwareGeneric::setVoiceVolume(float v)
+{
+    // Implement: set voice volume
+    return NO_ERROR;
+}
+
+status_t AudioHardwareGeneric::setMasterVolume(float v)
+{
+    // Implement: set master volume
+    // return error - software mixer will handle it
+    return INVALID_OPERATION;
+}
+
+status_t AudioHardwareGeneric::setMicMute(bool state)
+{
+    mMicMute = state;
+    return NO_ERROR;
+}
+
+status_t AudioHardwareGeneric::getMicMute(bool* state)
+{
+    *state = mMicMute;
+    return NO_ERROR;
+}
+
+status_t AudioHardwareGeneric::dumpInternals(int fd, const Vector<String16>& args)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+    result.append("AudioHardwareGeneric::dumpInternals\n");
+    snprintf(buffer, SIZE, "\tmFd: %d mMicMute: %s\n",  mFd, mMicMute? "true": "false");
+    result.append(buffer);
+    ::write(fd, result.string(), result.size());
+    return NO_ERROR;
+}
+
+status_t AudioHardwareGeneric::dump(int fd, const Vector<String16>& args)
+{
+    dumpInternals(fd, args);
+    if (mInput) {
+        mInput->dump(fd, args);
+    }
+    if (mOutput) {
+        mOutput->dump(fd, args);
+    }
+    return NO_ERROR;
+}
+
+// ----------------------------------------------------------------------------
+
+status_t AudioStreamOutGeneric::set(
+        AudioHardwareGeneric *hw,
+        int fd,
+        uint32_t devices,
+        int *pFormat,
+        uint32_t *pChannels,
+        uint32_t *pRate)
+{
+    int lFormat = pFormat ? *pFormat : 0;
+    uint32_t lChannels = pChannels ? *pChannels : 0;
+    uint32_t lRate = pRate ? *pRate : 0;
+
+    // fix up defaults
+    if (lFormat == 0) lFormat = format();
+    if (lChannels == 0) lChannels = channels();
+    if (lRate == 0) lRate = sampleRate();
+
+    // check values
+    if ((lFormat != format()) ||
+            (lChannels != channels()) ||
+            (lRate != sampleRate())) {
+        if (pFormat) *pFormat = format();
+        if (pChannels) *pChannels = channels();
+        if (pRate) *pRate = sampleRate();
+        return BAD_VALUE;
+    }
+
+    if (pFormat) *pFormat = lFormat;
+    if (pChannels) *pChannels = lChannels;
+    if (pRate) *pRate = lRate;
+
+    mAudioHardware = hw;
+    mFd = fd;
+    mDevice = devices;
+    return NO_ERROR;
+}
+
+AudioStreamOutGeneric::~AudioStreamOutGeneric()
+{
+}
+
+ssize_t AudioStreamOutGeneric::write(const void* buffer, size_t bytes)
+{
+    Mutex::Autolock _l(mLock);
+    return ssize_t(::write(mFd, buffer, bytes));
+}
+
+status_t AudioStreamOutGeneric::standby()
+{
+    // Implement: audio hardware to standby mode
+    return NO_ERROR;
+}
+
+status_t AudioStreamOutGeneric::dump(int fd, const Vector<String16>& args)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+    snprintf(buffer, SIZE, "AudioStreamOutGeneric::dump\n");
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tsample rate: %d\n", sampleRate());
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tbuffer size: %d\n", bufferSize());
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tchannels: %d\n", channels());
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tformat: %d\n", format());
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tdevice: %d\n", mDevice);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tmAudioHardware: %p\n", mAudioHardware);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tmFd: %d\n", mFd);
+    result.append(buffer);
+    ::write(fd, result.string(), result.size());
+    return NO_ERROR;
+}
+
+status_t AudioStreamOutGeneric::setParameters(const String8& keyValuePairs)
+{
+    AudioParameter param = AudioParameter(keyValuePairs);
+    String8 key = String8(AudioParameter::keyRouting);
+    status_t status = NO_ERROR;
+    int device;
+    ALOGV("setParameters() %s", keyValuePairs.string());
+
+    if (param.getInt(key, device) == NO_ERROR) {
+        mDevice = device;
+        param.remove(key);
+    }
+
+    if (param.size()) {
+        status = BAD_VALUE;
+    }
+    return status;
+}
+
+String8 AudioStreamOutGeneric::getParameters(const String8& keys)
+{
+    AudioParameter param = AudioParameter(keys);
+    String8 value;
+    String8 key = String8(AudioParameter::keyRouting);
+
+    if (param.get(key, value) == NO_ERROR) {
+        param.addInt(key, (int)mDevice);
+    }
+
+    ALOGV("getParameters() %s", param.toString().string());
+    return param.toString();
+}
+
+status_t AudioStreamOutGeneric::getRenderPosition(uint32_t *dspFrames)
+{
+    return INVALID_OPERATION;
+}
+
+// ----------------------------------------------------------------------------
+
+// record functions
+status_t AudioStreamInGeneric::set(
+        AudioHardwareGeneric *hw,
+        int fd,
+        uint32_t devices,
+        int *pFormat,
+        uint32_t *pChannels,
+        uint32_t *pRate,
+        AudioSystem::audio_in_acoustics acoustics)
+{
+    if (pFormat == 0 || pChannels == 0 || pRate == 0) return BAD_VALUE;
+    ALOGV("AudioStreamInGeneric::set(%p, %d, %d, %d, %u)", hw, fd, *pFormat, *pChannels, *pRate);
+    // check values
+    if ((*pFormat != format()) ||
+        (*pChannels != channels()) ||
+        (*pRate != sampleRate())) {
+        ALOGE("Error opening input channel");
+        *pFormat = format();
+        *pChannels = channels();
+        *pRate = sampleRate();
+        return BAD_VALUE;
+    }
+
+    mAudioHardware = hw;
+    mFd = fd;
+    mDevice = devices;
+    return NO_ERROR;
+}
+
+AudioStreamInGeneric::~AudioStreamInGeneric()
+{
+}
+
+ssize_t AudioStreamInGeneric::read(void* buffer, ssize_t bytes)
+{
+    AutoMutex lock(mLock);
+    if (mFd < 0) {
+        ALOGE("Attempt to read from unopened device");
+        return NO_INIT;
+    }
+    return ::read(mFd, buffer, bytes);
+}
+
+status_t AudioStreamInGeneric::dump(int fd, const Vector<String16>& args)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+    snprintf(buffer, SIZE, "AudioStreamInGeneric::dump\n");
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tsample rate: %d\n", sampleRate());
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tbuffer size: %d\n", bufferSize());
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tchannels: %d\n", channels());
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tformat: %d\n", format());
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tdevice: %d\n", mDevice);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tmAudioHardware: %p\n", mAudioHardware);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tmFd: %d\n", mFd);
+    result.append(buffer);
+    ::write(fd, result.string(), result.size());
+    return NO_ERROR;
+}
+
+status_t AudioStreamInGeneric::setParameters(const String8& keyValuePairs)
+{
+    AudioParameter param = AudioParameter(keyValuePairs);
+    String8 key = String8(AudioParameter::keyRouting);
+    status_t status = NO_ERROR;
+    int device;
+    ALOGV("setParameters() %s", keyValuePairs.string());
+
+    if (param.getInt(key, device) == NO_ERROR) {
+        mDevice = device;
+        param.remove(key);
+    }
+
+    if (param.size()) {
+        status = BAD_VALUE;
+    }
+    return status;
+}
+
+String8 AudioStreamInGeneric::getParameters(const String8& keys)
+{
+    AudioParameter param = AudioParameter(keys);
+    String8 value;
+    String8 key = String8(AudioParameter::keyRouting);
+
+    if (param.get(key, value) == NO_ERROR) {
+        param.addInt(key, (int)mDevice);
+    }
+
+    ALOGV("getParameters() %s", param.toString().string());
+    return param.toString();
+}
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libhardware_legacy/audio/AudioHardwareGeneric.h b/libhardware_legacy/audio/AudioHardwareGeneric.h
new file mode 100644
index 0000000..55498dc
--- /dev/null
+++ b/libhardware_legacy/audio/AudioHardwareGeneric.h
@@ -0,0 +1,156 @@
+/*
+**
+** Copyright 2007, 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_AUDIO_HARDWARE_GENERIC_H
+#define ANDROID_AUDIO_HARDWARE_GENERIC_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/threads.h>
+
+#include <hardware_legacy/AudioSystemLegacy.h>
+#include <hardware_legacy/AudioHardwareBase.h>
+
+namespace android_audio_legacy {
+    using android::Mutex;
+    using android::AutoMutex;
+
+// ----------------------------------------------------------------------------
+
+class AudioHardwareGeneric;
+
+class AudioStreamOutGeneric : public AudioStreamOut {
+public:
+                        AudioStreamOutGeneric() : mAudioHardware(0), mFd(-1) {}
+    virtual             ~AudioStreamOutGeneric();
+
+    virtual status_t    set(
+            AudioHardwareGeneric *hw,
+            int mFd,
+            uint32_t devices,
+            int *pFormat,
+            uint32_t *pChannels,
+            uint32_t *pRate);
+
+    virtual uint32_t    sampleRate() const { return 44100; }
+    virtual size_t      bufferSize() const { return 4096; }
+    virtual uint32_t    channels() const { return AudioSystem::CHANNEL_OUT_STEREO; }
+    virtual int         format() const { return AudioSystem::PCM_16_BIT; }
+    virtual uint32_t    latency() const { return 20; }
+    virtual status_t    setVolume(float left, float right) { return INVALID_OPERATION; }
+    virtual ssize_t     write(const void* buffer, size_t bytes);
+    virtual status_t    standby();
+    virtual status_t    dump(int fd, const Vector<String16>& args);
+    virtual status_t    setParameters(const String8& keyValuePairs);
+    virtual String8     getParameters(const String8& keys);
+    virtual status_t    getRenderPosition(uint32_t *dspFrames);
+
+private:
+    AudioHardwareGeneric *mAudioHardware;
+    Mutex   mLock;
+    int     mFd;
+    uint32_t mDevice;
+};
+
+class AudioStreamInGeneric : public AudioStreamIn {
+public:
+                        AudioStreamInGeneric() : mAudioHardware(0), mFd(-1) {}
+    virtual             ~AudioStreamInGeneric();
+
+    virtual status_t    set(
+            AudioHardwareGeneric *hw,
+            int mFd,
+            uint32_t devices,
+            int *pFormat,
+            uint32_t *pChannels,
+            uint32_t *pRate,
+            AudioSystem::audio_in_acoustics acoustics);
+
+    virtual uint32_t    sampleRate() const { return 8000; }
+    virtual size_t      bufferSize() const { return 320; }
+    virtual uint32_t    channels() const { return AudioSystem::CHANNEL_IN_MONO; }
+    virtual int         format() const { return AudioSystem::PCM_16_BIT; }
+    virtual status_t    setGain(float gain) { return INVALID_OPERATION; }
+    virtual ssize_t     read(void* buffer, ssize_t bytes);
+    virtual status_t    dump(int fd, const Vector<String16>& args);
+    virtual status_t    standby() { return NO_ERROR; }
+    virtual status_t    setParameters(const String8& keyValuePairs);
+    virtual String8     getParameters(const String8& keys);
+    virtual unsigned int  getInputFramesLost() const { return 0; }
+    virtual status_t addAudioEffect(effect_handle_t effect) { return NO_ERROR; }
+    virtual status_t removeAudioEffect(effect_handle_t effect) { return NO_ERROR; }
+
+private:
+    AudioHardwareGeneric *mAudioHardware;
+    Mutex   mLock;
+    int     mFd;
+    uint32_t mDevice;
+};
+
+
+class AudioHardwareGeneric : public AudioHardwareBase
+{
+public:
+                        AudioHardwareGeneric();
+    virtual             ~AudioHardwareGeneric();
+    virtual status_t    initCheck();
+    virtual status_t    setVoiceVolume(float volume);
+    virtual status_t    setMasterVolume(float volume);
+
+    // mic mute
+    virtual status_t    setMicMute(bool state);
+    virtual status_t    getMicMute(bool* state);
+
+    // create I/O streams
+    virtual AudioStreamOut* openOutputStream(
+            uint32_t devices,
+            int *format=0,
+            uint32_t *channels=0,
+            uint32_t *sampleRate=0,
+            status_t *status=0);
+    virtual    void        closeOutputStream(AudioStreamOut* out);
+
+    virtual AudioStreamIn* openInputStream(
+            uint32_t devices,
+            int *format,
+            uint32_t *channels,
+            uint32_t *sampleRate,
+            status_t *status,
+            AudioSystem::audio_in_acoustics acoustics);
+    virtual    void        closeInputStream(AudioStreamIn* in);
+
+            void            closeOutputStream(AudioStreamOutGeneric* out);
+            void            closeInputStream(AudioStreamInGeneric* in);
+protected:
+    virtual status_t        dump(int fd, const Vector<String16>& args);
+
+private:
+    status_t                dumpInternals(int fd, const Vector<String16>& args);
+
+    Mutex                   mLock;
+    AudioStreamOutGeneric   *mOutput;
+    AudioStreamInGeneric    *mInput;
+    int                     mFd;
+    bool                    mMicMute;
+};
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_AUDIO_HARDWARE_GENERIC_H
diff --git a/libhardware_legacy/audio/AudioHardwareInterface.cpp b/libhardware_legacy/audio/AudioHardwareInterface.cpp
new file mode 100644
index 0000000..dbf6f33
--- /dev/null
+++ b/libhardware_legacy/audio/AudioHardwareInterface.cpp
@@ -0,0 +1,164 @@
+/*
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#include <cutils/properties.h>
+#include <string.h>
+#include <unistd.h>
+//#define LOG_NDEBUG 0
+
+#define LOG_TAG "AudioHardwareInterface"
+#include <utils/Log.h>
+#include <utils/String8.h>
+
+#include "AudioHardwareStub.h"
+#include "AudioHardwareGeneric.h"
+
+#ifdef ENABLE_AUDIO_DUMP
+#include "AudioDumpInterface.h"
+#endif
+
+
+// change to 1 to log routing calls
+#define LOG_ROUTING_CALLS 1
+
+namespace android_audio_legacy {
+
+#if LOG_ROUTING_CALLS
+static const char* routingModeStrings[] =
+{
+    "OUT OF RANGE",
+    "INVALID",
+    "CURRENT",
+    "NORMAL",
+    "RINGTONE",
+    "IN_CALL",
+    "IN_COMMUNICATION"
+};
+
+static const char* routeNone = "NONE";
+
+static const char* displayMode(int mode)
+{
+    if ((mode < AudioSystem::MODE_INVALID) || (mode >= AudioSystem::NUM_MODES))
+        return routingModeStrings[0];
+    return routingModeStrings[mode+3];
+}
+#endif
+
+// ----------------------------------------------------------------------------
+
+AudioHardwareInterface* AudioHardwareInterface::create()
+{
+    return NULL;
+}
+
+AudioStreamOut::~AudioStreamOut()
+{
+}
+
+// default implementation is unsupported
+status_t AudioStreamOut::getNextWriteTimestamp(int64_t *timestamp)
+{
+    return INVALID_OPERATION;
+}
+
+AudioStreamIn::~AudioStreamIn() {}
+
+AudioHardwareBase::AudioHardwareBase()
+{
+    mMode = 0;
+}
+
+status_t AudioHardwareBase::setMode(int mode)
+{
+#if LOG_ROUTING_CALLS
+    ALOGD("setMode(%s)", displayMode(mode));
+#endif
+    if ((mode < 0) || (mode >= AudioSystem::NUM_MODES))
+        return BAD_VALUE;
+    if (mMode == mode)
+        return ALREADY_EXISTS;
+    mMode = mode;
+    return NO_ERROR;
+}
+
+// default implementation
+status_t AudioHardwareBase::setParameters(const String8& keyValuePairs)
+{
+    return NO_ERROR;
+}
+
+// default implementation
+String8 AudioHardwareBase::getParameters(const String8& keys)
+{
+    AudioParameter param = AudioParameter(keys);
+    return param.toString();
+}
+
+// default implementation
+size_t AudioHardwareBase::getInputBufferSize(uint32_t sampleRate, int format, int channelCount)
+{
+    if (sampleRate != 8000) {
+        ALOGW("getInputBufferSize bad sampling rate: %d", sampleRate);
+        return 0;
+    }
+    if (format != AudioSystem::PCM_16_BIT) {
+        ALOGW("getInputBufferSize bad format: %d", format);
+        return 0;
+    }
+    if (channelCount != 1) {
+        ALOGW("getInputBufferSize bad channel count: %d", channelCount);
+        return 0;
+    }
+
+    return 320;
+}
+
+// default implementation is unsupported
+status_t AudioHardwareBase::getMasterVolume(float *volume)
+{
+    return INVALID_OPERATION;
+}
+
+status_t AudioHardwareBase::dumpState(int fd, const Vector<String16>& args)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+    snprintf(buffer, SIZE, "AudioHardwareBase::dumpState\n");
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tmMode: %d\n", mMode);
+    result.append(buffer);
+    ::write(fd, result.string(), result.size());
+    dump(fd, args);  // Dump the state of the concrete child.
+    return NO_ERROR;
+}
+
+// default implementation calls its "without flags" counterpart
+AudioStreamOut* AudioHardwareInterface::openOutputStreamWithFlags(uint32_t devices,
+                                          audio_output_flags_t flags,
+                                          int *format,
+                                          uint32_t *channels,
+                                          uint32_t *sampleRate,
+                                          status_t *status)
+{
+    return openOutputStream(devices, format, channels, sampleRate, status);
+}
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libhardware_legacy/audio/AudioHardwareStub.cpp b/libhardware_legacy/audio/AudioHardwareStub.cpp
new file mode 100644
index 0000000..fd647d5
--- /dev/null
+++ b/libhardware_legacy/audio/AudioHardwareStub.cpp
@@ -0,0 +1,215 @@
+/* //device/servers/AudioFlinger/AudioHardwareStub.cpp
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <utils/String8.h>
+
+#include "AudioHardwareStub.h"
+#include <media/AudioRecord.h>
+
+namespace android_audio_legacy {
+
+// ----------------------------------------------------------------------------
+
+AudioHardwareStub::AudioHardwareStub() : mMicMute(false)
+{
+}
+
+AudioHardwareStub::~AudioHardwareStub()
+{
+}
+
+status_t AudioHardwareStub::initCheck()
+{
+    return NO_ERROR;
+}
+
+AudioStreamOut* AudioHardwareStub::openOutputStream(
+        uint32_t devices, int *format, uint32_t *channels, uint32_t *sampleRate, status_t *status)
+{
+    AudioStreamOutStub* out = new AudioStreamOutStub();
+    status_t lStatus = out->set(format, channels, sampleRate);
+    if (status) {
+        *status = lStatus;
+    }
+    if (lStatus == NO_ERROR)
+        return out;
+    delete out;
+    return 0;
+}
+
+void AudioHardwareStub::closeOutputStream(AudioStreamOut* out)
+{
+    delete out;
+}
+
+AudioStreamIn* AudioHardwareStub::openInputStream(
+        uint32_t devices, int *format, uint32_t *channels, uint32_t *sampleRate,
+        status_t *status, AudioSystem::audio_in_acoustics acoustics)
+{
+    // check for valid input source
+    if (!AudioSystem::isInputDevice((AudioSystem::audio_devices)devices)) {
+        return 0;
+    }
+
+    AudioStreamInStub* in = new AudioStreamInStub();
+    status_t lStatus = in->set(format, channels, sampleRate, acoustics);
+    if (status) {
+        *status = lStatus;
+    }
+    if (lStatus == NO_ERROR)
+        return in;
+    delete in;
+    return 0;
+}
+
+void AudioHardwareStub::closeInputStream(AudioStreamIn* in)
+{
+    delete in;
+}
+
+status_t AudioHardwareStub::setVoiceVolume(float volume)
+{
+    return NO_ERROR;
+}
+
+status_t AudioHardwareStub::setMasterVolume(float volume)
+{
+    return NO_ERROR;
+}
+
+status_t AudioHardwareStub::dumpInternals(int fd, const Vector<String16>& args)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+    result.append("AudioHardwareStub::dumpInternals\n");
+    snprintf(buffer, SIZE, "\tmMicMute: %s\n", mMicMute? "true": "false");
+    result.append(buffer);
+    ::write(fd, result.string(), result.size());
+    return NO_ERROR;
+}
+
+status_t AudioHardwareStub::dump(int fd, const Vector<String16>& args)
+{
+    dumpInternals(fd, args);
+    return NO_ERROR;
+}
+
+// ----------------------------------------------------------------------------
+
+status_t AudioStreamOutStub::set(int *pFormat, uint32_t *pChannels, uint32_t *pRate)
+{
+    if (pFormat) *pFormat = format();
+    if (pChannels) *pChannels = channels();
+    if (pRate) *pRate = sampleRate();
+
+    return NO_ERROR;
+}
+
+ssize_t AudioStreamOutStub::write(const void* buffer, size_t bytes)
+{
+    // fake timing for audio output
+    usleep(bytes * 1000000 / sizeof(int16_t) /
+               audio_channel_count_from_out_mask(channels()) / sampleRate());
+    return bytes;
+}
+
+status_t AudioStreamOutStub::standby()
+{
+    return NO_ERROR;
+}
+
+status_t AudioStreamOutStub::dump(int fd, const Vector<String16>& args)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+    snprintf(buffer, SIZE, "AudioStreamOutStub::dump\n");
+    snprintf(buffer, SIZE, "\tsample rate: %d\n", sampleRate());
+    snprintf(buffer, SIZE, "\tbuffer size: %d\n", bufferSize());
+    snprintf(buffer, SIZE, "\tchannels: %d\n", channels());
+    snprintf(buffer, SIZE, "\tformat: %d\n", format());
+    result.append(buffer);
+    ::write(fd, result.string(), result.size());
+    return NO_ERROR;
+}
+
+String8 AudioStreamOutStub::getParameters(const String8& keys)
+{
+    AudioParameter param = AudioParameter(keys);
+    return param.toString();
+}
+
+status_t AudioStreamOutStub::getRenderPosition(uint32_t *dspFrames)
+{
+    return INVALID_OPERATION;
+}
+
+// ----------------------------------------------------------------------------
+
+status_t AudioStreamInStub::set(int *pFormat, uint32_t *pChannels, uint32_t *pRate,
+                AudioSystem::audio_in_acoustics acoustics)
+{
+    return NO_ERROR;
+}
+
+ssize_t AudioStreamInStub::read(void* buffer, ssize_t bytes)
+{
+    // fake timing for audio input
+    usleep(bytes * 1000000 / sizeof(int16_t) /
+           audio_channel_count_from_in_mask(channels()) / sampleRate());
+    memset(buffer, 0, bytes);
+    return bytes;
+}
+
+status_t AudioStreamInStub::dump(int fd, const Vector<String16>& args)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+    snprintf(buffer, SIZE, "AudioStreamInStub::dump\n");
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tsample rate: %d\n", sampleRate());
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tbuffer size: %d\n", bufferSize());
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tchannels: %d\n", channels());
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tformat: %d\n", format());
+    result.append(buffer);
+    ::write(fd, result.string(), result.size());
+    return NO_ERROR;
+}
+
+String8 AudioStreamInStub::getParameters(const String8& keys)
+{
+    AudioParameter param = AudioParameter(keys);
+    return param.toString();
+}
+
+AudioHardwareInterface* createAudioHardware(void) {
+    return new AudioHardwareStub();
+}
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libhardware_legacy/audio/AudioHardwareStub.h b/libhardware_legacy/audio/AudioHardwareStub.h
new file mode 100644
index 0000000..c5f7a80
--- /dev/null
+++ b/libhardware_legacy/audio/AudioHardwareStub.h
@@ -0,0 +1,108 @@
+/* //device/servers/AudioFlinger/AudioHardwareStub.h
+**
+** Copyright 2007, 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_AUDIO_HARDWARE_STUB_H
+#define ANDROID_AUDIO_HARDWARE_STUB_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <hardware_legacy/AudioHardwareBase.h>
+
+namespace android_audio_legacy {
+
+// ----------------------------------------------------------------------------
+
+class AudioStreamOutStub : public AudioStreamOut {
+public:
+    virtual status_t    set(int *pFormat, uint32_t *pChannels, uint32_t *pRate);
+    virtual uint32_t    sampleRate() const { return 44100; }
+    virtual size_t      bufferSize() const { return 4096; }
+    virtual uint32_t    channels() const { return AudioSystem::CHANNEL_OUT_STEREO; }
+    virtual int         format() const { return AudioSystem::PCM_16_BIT; }
+    virtual uint32_t    latency() const { return 0; }
+    virtual status_t    setVolume(float left, float right) { return NO_ERROR; }
+    virtual ssize_t     write(const void* buffer, size_t bytes);
+    virtual status_t    standby();
+    virtual status_t    dump(int fd, const Vector<String16>& args);
+    virtual status_t    setParameters(const String8& keyValuePairs) { return NO_ERROR;}
+    virtual String8     getParameters(const String8& keys);
+    virtual status_t    getRenderPosition(uint32_t *dspFrames);
+};
+
+class AudioStreamInStub : public AudioStreamIn {
+public:
+    virtual status_t    set(int *pFormat, uint32_t *pChannels, uint32_t *pRate, AudioSystem::audio_in_acoustics acoustics);
+    virtual uint32_t    sampleRate() const { return 8000; }
+    virtual size_t      bufferSize() const { return 320; }
+    virtual uint32_t    channels() const { return AudioSystem::CHANNEL_IN_MONO; }
+    virtual int         format() const { return AudioSystem::PCM_16_BIT; }
+    virtual status_t    setGain(float gain) { return NO_ERROR; }
+    virtual ssize_t     read(void* buffer, ssize_t bytes);
+    virtual status_t    dump(int fd, const Vector<String16>& args);
+    virtual status_t    standby() { return NO_ERROR; }
+    virtual status_t    setParameters(const String8& keyValuePairs) { return NO_ERROR;}
+    virtual String8     getParameters(const String8& keys);
+    virtual unsigned int  getInputFramesLost() const { return 0; }
+    virtual status_t addAudioEffect(effect_handle_t effect) { return NO_ERROR; }
+    virtual status_t removeAudioEffect(effect_handle_t effect) { return NO_ERROR; }
+};
+
+class AudioHardwareStub : public  AudioHardwareBase
+{
+public:
+                        AudioHardwareStub();
+    virtual             ~AudioHardwareStub();
+    virtual status_t    initCheck();
+    virtual status_t    setVoiceVolume(float volume);
+    virtual status_t    setMasterVolume(float volume);
+
+    // mic mute
+    virtual status_t    setMicMute(bool state) { mMicMute = state;  return  NO_ERROR; }
+    virtual status_t    getMicMute(bool* state) { *state = mMicMute ; return NO_ERROR; }
+
+    // create I/O streams
+    virtual AudioStreamOut* openOutputStream(
+                                uint32_t devices,
+                                int *format=0,
+                                uint32_t *channels=0,
+                                uint32_t *sampleRate=0,
+                                status_t *status=0);
+    virtual    void        closeOutputStream(AudioStreamOut* out);
+
+    virtual AudioStreamIn* openInputStream(
+                                uint32_t devices,
+                                int *format,
+                                uint32_t *channels,
+                                uint32_t *sampleRate,
+                                status_t *status,
+                                AudioSystem::audio_in_acoustics acoustics);
+    virtual    void        closeInputStream(AudioStreamIn* in);
+
+protected:
+    virtual status_t    dump(int fd, const Vector<String16>& args);
+
+            bool        mMicMute;
+private:
+    status_t            dumpInternals(int fd, const Vector<String16>& args);
+};
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_AUDIO_HARDWARE_STUB_H
diff --git a/libhardware_legacy/audio/AudioPolicyCompatClient.cpp b/libhardware_legacy/audio/AudioPolicyCompatClient.cpp
new file mode 100644
index 0000000..9d02d98
--- /dev/null
+++ b/libhardware_legacy/audio/AudioPolicyCompatClient.cpp
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2011 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 "AudioPolicyCompatClient"
+//#define LOG_NDEBUG 0
+
+#include <stdint.h>
+
+#include <hardware/hardware.h>
+#include <system/audio.h>
+#include <system/audio_policy.h>
+#include <hardware/audio_policy.h>
+
+#include <hardware_legacy/AudioSystemLegacy.h>
+
+#include "AudioPolicyCompatClient.h"
+
+namespace android_audio_legacy {
+
+audio_module_handle_t AudioPolicyCompatClient::loadHwModule(const char *moduleName)
+{
+    return mServiceOps->load_hw_module(mService, moduleName);
+}
+
+audio_io_handle_t AudioPolicyCompatClient::openOutput(audio_module_handle_t module,
+                                                      audio_devices_t *pDevices,
+                                                      uint32_t *pSamplingRate,
+                                                      audio_format_t *pFormat,
+                                                      audio_channel_mask_t *pChannelMask,
+                                                      uint32_t *pLatencyMs,
+                                                      audio_output_flags_t flags,
+                                                      const audio_offload_info_t *offloadInfo)
+{
+    return mServiceOps->open_output_on_module(mService, module, pDevices, pSamplingRate,
+                                              pFormat, pChannelMask, pLatencyMs,
+                                              flags, offloadInfo);
+}
+
+audio_io_handle_t AudioPolicyCompatClient::openDuplicateOutput(audio_io_handle_t output1,
+                                                          audio_io_handle_t output2)
+{
+    return mServiceOps->open_duplicate_output(mService, output1, output2);
+}
+
+status_t AudioPolicyCompatClient::closeOutput(audio_io_handle_t output)
+{
+    return mServiceOps->close_output(mService, output);
+}
+
+status_t AudioPolicyCompatClient::suspendOutput(audio_io_handle_t output)
+{
+    return mServiceOps->suspend_output(mService, output);
+}
+
+status_t AudioPolicyCompatClient::restoreOutput(audio_io_handle_t output)
+{
+    return mServiceOps->restore_output(mService, output);
+}
+
+audio_io_handle_t AudioPolicyCompatClient::openInput(audio_module_handle_t module,
+                                                     audio_devices_t *pDevices,
+                                                     uint32_t *pSamplingRate,
+                                                     audio_format_t *pFormat,
+                                                     audio_channel_mask_t *pChannelMask)
+{
+    return mServiceOps->open_input_on_module(mService, module, pDevices,
+                                             pSamplingRate, pFormat, pChannelMask);
+}
+
+status_t AudioPolicyCompatClient::closeInput(audio_io_handle_t input)
+{
+    return mServiceOps->close_input(mService, input);
+}
+
+status_t AudioPolicyCompatClient::invalidateStream(AudioSystem::stream_type stream)
+{
+    return mServiceOps->invalidate_stream(mService, (audio_stream_type_t)stream);
+}
+
+status_t AudioPolicyCompatClient::moveEffects(int session, audio_io_handle_t srcOutput,
+                                               audio_io_handle_t dstOutput)
+{
+    return mServiceOps->move_effects(mService, session, srcOutput, dstOutput);
+}
+
+String8 AudioPolicyCompatClient::getParameters(audio_io_handle_t ioHandle, const String8& keys)
+{
+    char *str;
+    String8 out_str8;
+
+    str = mServiceOps->get_parameters(mService, ioHandle, keys.string());
+    out_str8 = String8(str);
+    free(str);
+
+    return out_str8;
+}
+
+void AudioPolicyCompatClient::setParameters(audio_io_handle_t ioHandle,
+                                            const String8& keyValuePairs,
+                                            int delayMs)
+{
+    mServiceOps->set_parameters(mService, ioHandle, keyValuePairs.string(),
+                           delayMs);
+}
+
+status_t AudioPolicyCompatClient::setStreamVolume(
+                                             AudioSystem::stream_type stream,
+                                             float volume,
+                                             audio_io_handle_t output,
+                                             int delayMs)
+{
+    return mServiceOps->set_stream_volume(mService, (audio_stream_type_t)stream,
+                                          volume, output, delayMs);
+}
+
+status_t AudioPolicyCompatClient::startTone(ToneGenerator::tone_type tone,
+                                       AudioSystem::stream_type stream)
+{
+    return mServiceOps->start_tone(mService,
+                                   AUDIO_POLICY_TONE_IN_CALL_NOTIFICATION,
+                                   (audio_stream_type_t)stream);
+}
+
+status_t AudioPolicyCompatClient::stopTone()
+{
+    return mServiceOps->stop_tone(mService);
+}
+
+status_t AudioPolicyCompatClient::setVoiceVolume(float volume, int delayMs)
+{
+    return mServiceOps->set_voice_volume(mService, volume, delayMs);
+}
+
+}; // namespace android_audio_legacy
diff --git a/libhardware_legacy/audio/AudioPolicyCompatClient.h b/libhardware_legacy/audio/AudioPolicyCompatClient.h
new file mode 100644
index 0000000..19f76e1
--- /dev/null
+++ b/libhardware_legacy/audio/AudioPolicyCompatClient.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2011 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_AUDIOPOLICYCLIENTLEGACY_H
+#define ANDROID_AUDIOPOLICYCLIENTLEGACY_H
+
+#include <system/audio.h>
+#include <system/audio_policy.h>
+#include <hardware/audio_policy.h>
+
+#include <hardware_legacy/AudioSystemLegacy.h>
+#include <hardware_legacy/AudioPolicyInterface.h>
+
+/************************************/
+/* FOR BACKWARDS COMPATIBILITY ONLY */
+/************************************/
+namespace android_audio_legacy {
+
+class AudioPolicyCompatClient : public AudioPolicyClientInterface {
+public:
+    AudioPolicyCompatClient(struct audio_policy_service_ops *serviceOps,
+                            void *service) :
+            mServiceOps(serviceOps) , mService(service) {}
+
+    virtual audio_module_handle_t loadHwModule(const char *moduleName);
+
+    virtual audio_io_handle_t openOutput(audio_module_handle_t module,
+                                         audio_devices_t *pDevices,
+                                         uint32_t *pSamplingRate,
+                                         audio_format_t *pFormat,
+                                         audio_channel_mask_t *pChannelMask,
+                                         uint32_t *pLatencyMs,
+                                         audio_output_flags_t flags,
+                                         const audio_offload_info_t *offloadInfo);
+    virtual audio_io_handle_t openDuplicateOutput(audio_io_handle_t output1,
+                                                  audio_io_handle_t output2);
+    virtual status_t closeOutput(audio_io_handle_t output);
+    virtual status_t suspendOutput(audio_io_handle_t output);
+    virtual status_t restoreOutput(audio_io_handle_t output);
+    virtual audio_io_handle_t openInput(audio_module_handle_t module,
+                                        audio_devices_t *pDevices,
+                                        uint32_t *pSamplingRate,
+                                        audio_format_t *pFormat,
+                                        audio_channel_mask_t *pChannelMask);
+    virtual status_t closeInput(audio_io_handle_t input);
+    virtual status_t invalidateStream(AudioSystem::stream_type stream);
+    virtual status_t moveEffects(int session,
+                                 audio_io_handle_t srcOutput,
+                                 audio_io_handle_t dstOutput);
+
+    virtual String8 getParameters(audio_io_handle_t ioHandle, const String8& keys);
+    virtual void setParameters(audio_io_handle_t ioHandle,
+                               const String8& keyValuePairs,
+                               int delayMs = 0);
+    virtual status_t setStreamVolume(AudioSystem::stream_type stream,
+                                     float volume,
+                                     audio_io_handle_t output,
+                                     int delayMs = 0);
+    virtual status_t startTone(ToneGenerator::tone_type tone, AudioSystem::stream_type stream);
+    virtual status_t stopTone();
+    virtual status_t setVoiceVolume(float volume, int delayMs = 0);
+
+private:
+    struct audio_policy_service_ops* mServiceOps;
+    void*                            mService;
+};
+
+}; // namespace android_audio_legacy
+
+#endif // ANDROID_AUDIOPOLICYCLIENTLEGACY_H
diff --git a/libhardware_legacy/audio/AudioPolicyManagerBase.cpp b/libhardware_legacy/audio/AudioPolicyManagerBase.cpp
new file mode 100644
index 0000000..60790b7
--- /dev/null
+++ b/libhardware_legacy/audio/AudioPolicyManagerBase.cpp
@@ -0,0 +1,4368 @@
+/*
+ * Copyright (C) 2009 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 "AudioPolicyManagerBase"
+//#define LOG_NDEBUG 0
+
+//#define VERY_VERBOSE_LOGGING
+#ifdef VERY_VERBOSE_LOGGING
+#define ALOGVV ALOGV
+#else
+#define ALOGVV(a...) do { } while(0)
+#endif
+
+// A device mask for all audio input devices that are considered "virtual" when evaluating
+// active inputs in getActiveInput()
+#define APM_AUDIO_IN_DEVICE_VIRTUAL_ALL  AUDIO_DEVICE_IN_REMOTE_SUBMIX
+// A device mask for all audio output devices that are considered "remote" when evaluating
+// active output devices in isStreamActiveRemotely()
+#define APM_AUDIO_OUT_DEVICE_REMOTE_ALL  AUDIO_DEVICE_OUT_REMOTE_SUBMIX
+
+#include <inttypes.h>
+#include <math.h>
+
+#include <cutils/properties.h>
+#include <utils/Log.h>
+#include <utils/Timers.h>
+
+#include <hardware/audio.h>
+#include <hardware/audio_effect.h>
+#include <hardware_legacy/audio_policy_conf.h>
+#include <hardware_legacy/AudioPolicyManagerBase.h>
+
+namespace android_audio_legacy {
+
+// ----------------------------------------------------------------------------
+// AudioPolicyInterface implementation
+// ----------------------------------------------------------------------------
+
+
+status_t AudioPolicyManagerBase::setDeviceConnectionState(audio_devices_t device,
+                                                  AudioSystem::device_connection_state state,
+                                                  const char *device_address)
+{
+    // device_address can be NULL and should be handled as an empty string in this case,
+    // and it is not checked by AudioPolicyInterfaceImpl.cpp
+    if (device_address == NULL) {
+        device_address = "";
+    }
+    ALOGV("setDeviceConnectionState() device: 0x%X, state %d, address %s", device, state, device_address);
+
+    // connect/disconnect only 1 device at a time
+    if (!audio_is_output_device(device) && !audio_is_input_device(device)) return BAD_VALUE;
+
+    if (strlen(device_address) >= MAX_DEVICE_ADDRESS_LEN) {
+        ALOGE("setDeviceConnectionState() invalid address: %s", device_address);
+        return BAD_VALUE;
+    }
+
+    // handle output devices
+    if (audio_is_output_device(device)) {
+        SortedVector <audio_io_handle_t> outputs;
+
+        if (!mHasA2dp && audio_is_a2dp_out_device(device)) {
+            ALOGE("setDeviceConnectionState() invalid A2DP device: %x", device);
+            return BAD_VALUE;
+        }
+        if (!mHasUsb && audio_is_usb_out_device(device)) {
+            ALOGE("setDeviceConnectionState() invalid USB audio device: %x", device);
+            return BAD_VALUE;
+        }
+        if (!mHasRemoteSubmix && audio_is_remote_submix_device((audio_devices_t)device)) {
+            ALOGE("setDeviceConnectionState() invalid remote submix audio device: %x", device);
+            return BAD_VALUE;
+        }
+
+        // save a copy of the opened output descriptors before any output is opened or closed
+        // by checkOutputsForDevice(). This will be needed by checkOutputForAllStrategies()
+        mPreviousOutputs = mOutputs;
+        String8 paramStr;
+        switch (state)
+        {
+        // handle output device connection
+        case AudioSystem::DEVICE_STATE_AVAILABLE:
+            if (mAvailableOutputDevices & device) {
+                ALOGW("setDeviceConnectionState() device already connected: %x", device);
+                return INVALID_OPERATION;
+            }
+            ALOGV("setDeviceConnectionState() connecting device %x", device);
+
+            if (mHasA2dp && audio_is_a2dp_out_device(device)) {
+                // handle A2DP device connection
+                AudioParameter param;
+                param.add(String8(AUDIO_PARAMETER_A2DP_SINK_ADDRESS), String8(device_address));
+                paramStr = param.toString();
+            } else if (mHasUsb && audio_is_usb_out_device(device)) {
+                // handle USB device connection
+                paramStr = String8(device_address, MAX_DEVICE_ADDRESS_LEN);
+            }
+
+            if (checkOutputsForDevice(device, state, outputs, paramStr) != NO_ERROR) {
+                return INVALID_OPERATION;
+            }
+            ALOGV("setDeviceConnectionState() checkOutputsForDevice() returned %zu outputs",
+                  outputs.size());
+            // register new device as available
+            mAvailableOutputDevices = (audio_devices_t)(mAvailableOutputDevices | device);
+
+            if (mHasA2dp && audio_is_a2dp_out_device(device)) {
+                // handle A2DP device connection
+                mA2dpDeviceAddress = String8(device_address, MAX_DEVICE_ADDRESS_LEN);
+                mA2dpSuspended = false;
+            } else if (audio_is_bluetooth_sco_device(device)) {
+                // handle SCO device connection
+                mScoDeviceAddress = String8(device_address, MAX_DEVICE_ADDRESS_LEN);
+            } else if (mHasUsb && audio_is_usb_out_device(device)) {
+                // handle USB device connection
+                mUsbOutCardAndDevice = String8(device_address, MAX_DEVICE_ADDRESS_LEN);
+            }
+
+            break;
+        // handle output device disconnection
+        case AudioSystem::DEVICE_STATE_UNAVAILABLE: {
+            if (!(mAvailableOutputDevices & device)) {
+                ALOGW("setDeviceConnectionState() device not connected: %x", device);
+                return INVALID_OPERATION;
+            }
+
+            ALOGV("setDeviceConnectionState() disconnecting device %x", device);
+            // remove device from available output devices
+            mAvailableOutputDevices = (audio_devices_t)(mAvailableOutputDevices & ~device);
+            checkOutputsForDevice(device, state, outputs, paramStr);
+
+            if (mHasA2dp && audio_is_a2dp_out_device(device)) {
+                // handle A2DP device disconnection
+                mA2dpDeviceAddress = "";
+                mA2dpSuspended = false;
+            } else if (audio_is_bluetooth_sco_device(device)) {
+                // handle SCO device disconnection
+                mScoDeviceAddress = "";
+            } else if (mHasUsb && audio_is_usb_out_device(device)) {
+                // handle USB device disconnection
+                mUsbOutCardAndDevice = "";
+            }
+            // not currently handling multiple simultaneous submixes: ignoring remote submix
+            //   case and address
+            } break;
+
+        default:
+            ALOGE("setDeviceConnectionState() invalid state: %x", state);
+            return BAD_VALUE;
+        }
+
+        checkA2dpSuspend();
+        checkOutputForAllStrategies();
+        // outputs must be closed after checkOutputForAllStrategies() is executed
+        if (!outputs.isEmpty()) {
+            for (size_t i = 0; i < outputs.size(); i++) {
+                AudioOutputDescriptor *desc = mOutputs.valueFor(outputs[i]);
+                // close unused outputs after device disconnection or direct outputs that have been
+                // opened by checkOutputsForDevice() to query dynamic parameters
+                if ((state == AudioSystem::DEVICE_STATE_UNAVAILABLE) ||
+                        (((desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) != 0) &&
+                         (desc->mDirectOpenCount == 0))) {
+                    closeOutput(outputs[i]);
+                }
+            }
+        }
+
+        updateDevicesAndOutputs();
+        for (size_t i = 0; i < mOutputs.size(); i++) {
+            // do not force device change on duplicated output because if device is 0, it will
+            // also force a device 0 for the two outputs it is duplicated to which may override
+            // a valid device selection on those outputs.
+            setOutputDevice(mOutputs.keyAt(i),
+                            getNewDevice(mOutputs.keyAt(i), true /*fromCache*/),
+                            !mOutputs.valueAt(i)->isDuplicated(),
+                            0);
+        }
+
+        return NO_ERROR;
+    }  // end if is output device
+
+    // handle input devices
+    if (audio_is_input_device(device)) {
+        SortedVector <audio_io_handle_t> inputs;
+
+        String8 paramStr;
+        switch (state)
+        {
+        // handle input device connection
+        case AudioSystem::DEVICE_STATE_AVAILABLE: {
+            if (mAvailableInputDevices & device) {
+                ALOGW("setDeviceConnectionState() device already connected: %d", device);
+                return INVALID_OPERATION;
+            }
+
+            if (mHasUsb && audio_is_usb_in_device(device)) {
+                // handle USB device connection
+                paramStr = String8(device_address, MAX_DEVICE_ADDRESS_LEN);
+            } else if (mHasA2dp && audio_is_a2dp_in_device(device)) {
+                // handle A2DP device connection
+                AudioParameter param;
+                param.add(String8(AUDIO_PARAMETER_A2DP_SOURCE_ADDRESS), String8(device_address));
+                paramStr = param.toString();
+            }
+
+            if (checkInputsForDevice(device, state, inputs, paramStr) != NO_ERROR) {
+                return INVALID_OPERATION;
+            }
+            mAvailableInputDevices = mAvailableInputDevices | (device & ~AUDIO_DEVICE_BIT_IN);
+            }
+            break;
+
+        // handle input device disconnection
+        case AudioSystem::DEVICE_STATE_UNAVAILABLE: {
+            if (!(mAvailableInputDevices & device)) {
+                ALOGW("setDeviceConnectionState() device not connected: %d", device);
+                return INVALID_OPERATION;
+            }
+            checkInputsForDevice(device, state, inputs, paramStr);
+            mAvailableInputDevices = (audio_devices_t) (mAvailableInputDevices & ~device);
+        } break;
+
+        default:
+            ALOGE("setDeviceConnectionState() invalid state: %x", state);
+            return BAD_VALUE;
+        }
+
+        closeAllInputs();
+
+        return NO_ERROR;
+    } // end if is input device
+
+    ALOGW("setDeviceConnectionState() invalid device: %x", device);
+    return BAD_VALUE;
+}
+
+AudioSystem::device_connection_state AudioPolicyManagerBase::getDeviceConnectionState(audio_devices_t device,
+                                                  const char *device_address)
+{
+    // similar to setDeviceConnectionState
+    if (device_address == NULL) {
+        device_address = "";
+    }
+    AudioSystem::device_connection_state state = AudioSystem::DEVICE_STATE_UNAVAILABLE;
+    String8 address = String8(device_address);
+    if (audio_is_output_device(device)) {
+        if (device & mAvailableOutputDevices) {
+            if (audio_is_a2dp_out_device(device) &&
+                (!mHasA2dp || (address != "" && mA2dpDeviceAddress != address))) {
+                return state;
+            }
+            if (audio_is_bluetooth_sco_device(device) &&
+                address != "" && mScoDeviceAddress != address) {
+                return state;
+            }
+            if (audio_is_usb_out_device(device) &&
+                (!mHasUsb || (address != "" && mUsbOutCardAndDevice != address))) {
+                ALOGE("getDeviceConnectionState() invalid device: %x", device);
+                return state;
+            }
+            if (audio_is_remote_submix_device((audio_devices_t)device) && !mHasRemoteSubmix) {
+                return state;
+            }
+            state = AudioSystem::DEVICE_STATE_AVAILABLE;
+        }
+    } else if (audio_is_input_device(device)) {
+        if (device & mAvailableInputDevices) {
+            state = AudioSystem::DEVICE_STATE_AVAILABLE;
+        }
+    }
+
+    return state;
+}
+
+void AudioPolicyManagerBase::setPhoneState(int state)
+{
+    ALOGV("setPhoneState() state %d", state);
+    audio_devices_t newDevice = AUDIO_DEVICE_NONE;
+    if (state < 0 || state >= AudioSystem::NUM_MODES) {
+        ALOGW("setPhoneState() invalid state %d", state);
+        return;
+    }
+
+    if (state == mPhoneState ) {
+        ALOGW("setPhoneState() setting same state %d", state);
+        return;
+    }
+
+    // if leaving call state, handle special case of active streams
+    // pertaining to sonification strategy see handleIncallSonification()
+    if (isInCall()) {
+        ALOGV("setPhoneState() in call state management: new state is %d", state);
+        for (int stream = 0; stream < AudioSystem::NUM_STREAM_TYPES; stream++) {
+            handleIncallSonification(stream, false, true);
+        }
+    }
+
+    // store previous phone state for management of sonification strategy below
+    int oldState = mPhoneState;
+    mPhoneState = state;
+    bool force = false;
+
+    // are we entering or starting a call
+    if (!isStateInCall(oldState) && isStateInCall(state)) {
+        ALOGV("  Entering call in setPhoneState()");
+        // force routing command to audio hardware when starting a call
+        // even if no device change is needed
+        force = true;
+        for (int j = 0; j < DEVICE_CATEGORY_CNT; j++) {
+            mStreams[AUDIO_STREAM_DTMF].mVolumeCurve[j] =
+                    sVolumeProfiles[AUDIO_STREAM_VOICE_CALL][j];
+        }
+    } else if (isStateInCall(oldState) && !isStateInCall(state)) {
+        ALOGV("  Exiting call in setPhoneState()");
+        // force routing command to audio hardware when exiting a call
+        // even if no device change is needed
+        force = true;
+        for (int j = 0; j < DEVICE_CATEGORY_CNT; j++) {
+            mStreams[AUDIO_STREAM_DTMF].mVolumeCurve[j] =
+                    sVolumeProfiles[AUDIO_STREAM_DTMF][j];
+        }
+    } else if (isStateInCall(state) && (state != oldState)) {
+        ALOGV("  Switching between telephony and VoIP in setPhoneState()");
+        // force routing command to audio hardware when switching between telephony and VoIP
+        // even if no device change is needed
+        force = true;
+    }
+
+    // check for device and output changes triggered by new phone state
+    newDevice = getNewDevice(mPrimaryOutput, false /*fromCache*/);
+    checkA2dpSuspend();
+    checkOutputForAllStrategies();
+    updateDevicesAndOutputs();
+
+    AudioOutputDescriptor *hwOutputDesc = mOutputs.valueFor(mPrimaryOutput);
+
+    // force routing command to audio hardware when ending call
+    // even if no device change is needed
+    if (isStateInCall(oldState) && newDevice == AUDIO_DEVICE_NONE) {
+        newDevice = hwOutputDesc->device();
+    }
+
+    int delayMs = 0;
+    if (isStateInCall(state)) {
+        nsecs_t sysTime = systemTime();
+        for (size_t i = 0; i < mOutputs.size(); i++) {
+            AudioOutputDescriptor *desc = mOutputs.valueAt(i);
+            // mute media and sonification strategies and delay device switch by the largest
+            // latency of any output where either strategy is active.
+            // This avoid sending the ring tone or music tail into the earpiece or headset.
+            if ((desc->isStrategyActive(STRATEGY_MEDIA,
+                                     SONIFICATION_HEADSET_MUSIC_DELAY,
+                                     sysTime) ||
+                    desc->isStrategyActive(STRATEGY_SONIFICATION,
+                                         SONIFICATION_HEADSET_MUSIC_DELAY,
+                                         sysTime)) &&
+                    (delayMs < (int)desc->mLatency*2)) {
+                delayMs = desc->mLatency*2;
+            }
+            setStrategyMute(STRATEGY_MEDIA, true, mOutputs.keyAt(i));
+            setStrategyMute(STRATEGY_MEDIA, false, mOutputs.keyAt(i), MUTE_TIME_MS,
+                getDeviceForStrategy(STRATEGY_MEDIA, true /*fromCache*/));
+            setStrategyMute(STRATEGY_SONIFICATION, true, mOutputs.keyAt(i));
+            setStrategyMute(STRATEGY_SONIFICATION, false, mOutputs.keyAt(i), MUTE_TIME_MS,
+                getDeviceForStrategy(STRATEGY_SONIFICATION, true /*fromCache*/));
+        }
+    }
+
+    // change routing is necessary
+    setOutputDevice(mPrimaryOutput, newDevice, force, delayMs);
+
+    // if entering in call state, handle special case of active streams
+    // pertaining to sonification strategy see handleIncallSonification()
+    if (isStateInCall(state)) {
+        ALOGV("setPhoneState() in call state management: new state is %d", state);
+        for (int stream = 0; stream < AudioSystem::NUM_STREAM_TYPES; stream++) {
+            handleIncallSonification(stream, true, true);
+        }
+    }
+
+    // Flag that ringtone volume must be limited to music volume until we exit MODE_RINGTONE
+    if (state == AudioSystem::MODE_RINGTONE &&
+        isStreamActive(AudioSystem::MUSIC, SONIFICATION_HEADSET_MUSIC_DELAY)) {
+        mLimitRingtoneVolume = true;
+    } else {
+        mLimitRingtoneVolume = false;
+    }
+}
+
+void AudioPolicyManagerBase::setForceUse(AudioSystem::force_use usage, AudioSystem::forced_config config)
+{
+    ALOGV("setForceUse() usage %d, config %d, mPhoneState %d", usage, config, mPhoneState);
+
+    bool forceVolumeReeval = false;
+    switch(usage) {
+    case AudioSystem::FOR_COMMUNICATION:
+        if (config != AudioSystem::FORCE_SPEAKER && config != AudioSystem::FORCE_BT_SCO &&
+            config != AudioSystem::FORCE_NONE) {
+            ALOGW("setForceUse() invalid config %d for FOR_COMMUNICATION", config);
+            return;
+        }
+        forceVolumeReeval = true;
+        mForceUse[usage] = config;
+        break;
+    case AudioSystem::FOR_MEDIA:
+        if (config != AudioSystem::FORCE_HEADPHONES && config != AudioSystem::FORCE_BT_A2DP &&
+            config != AudioSystem::FORCE_WIRED_ACCESSORY &&
+            config != AudioSystem::FORCE_ANALOG_DOCK &&
+            config != AudioSystem::FORCE_DIGITAL_DOCK && config != AudioSystem::FORCE_NONE &&
+            config != AudioSystem::FORCE_NO_BT_A2DP) {
+            ALOGW("setForceUse() invalid config %d for FOR_MEDIA", config);
+            return;
+        }
+        mForceUse[usage] = config;
+        break;
+    case AudioSystem::FOR_RECORD:
+        if (config != AudioSystem::FORCE_BT_SCO && config != AudioSystem::FORCE_WIRED_ACCESSORY &&
+            config != AudioSystem::FORCE_NONE) {
+            ALOGW("setForceUse() invalid config %d for FOR_RECORD", config);
+            return;
+        }
+        mForceUse[usage] = config;
+        break;
+    case AudioSystem::FOR_DOCK:
+        if (config != AudioSystem::FORCE_NONE && config != AudioSystem::FORCE_BT_CAR_DOCK &&
+            config != AudioSystem::FORCE_BT_DESK_DOCK &&
+            config != AudioSystem::FORCE_WIRED_ACCESSORY &&
+            config != AudioSystem::FORCE_ANALOG_DOCK &&
+            config != AudioSystem::FORCE_DIGITAL_DOCK) {
+            ALOGW("setForceUse() invalid config %d for FOR_DOCK", config);
+        }
+        forceVolumeReeval = true;
+        mForceUse[usage] = config;
+        break;
+    case AudioSystem::FOR_SYSTEM:
+        if (config != AudioSystem::FORCE_NONE &&
+            config != AudioSystem::FORCE_SYSTEM_ENFORCED) {
+            ALOGW("setForceUse() invalid config %d for FOR_SYSTEM", config);
+        }
+        forceVolumeReeval = true;
+        mForceUse[usage] = config;
+        break;
+    default:
+        ALOGW("setForceUse() invalid usage %d", usage);
+        break;
+    }
+
+    // check for device and output changes triggered by new force usage
+    checkA2dpSuspend();
+    checkOutputForAllStrategies();
+    updateDevicesAndOutputs();
+    for (size_t i = 0; i < mOutputs.size(); i++) {
+        audio_io_handle_t output = mOutputs.keyAt(i);
+        audio_devices_t newDevice = getNewDevice(output, true /*fromCache*/);
+        setOutputDevice(output, newDevice, (newDevice != AUDIO_DEVICE_NONE));
+        if (forceVolumeReeval && (newDevice != AUDIO_DEVICE_NONE)) {
+            applyStreamVolumes(output, newDevice, 0, true);
+        }
+    }
+
+    audio_io_handle_t activeInput = getActiveInput();
+    if (activeInput != 0) {
+        AudioInputDescriptor *inputDesc = mInputs.valueFor(activeInput);
+        audio_devices_t newDevice = getDeviceForInputSource(inputDesc->mInputSource);
+        if ((newDevice != AUDIO_DEVICE_NONE) && (newDevice != inputDesc->mDevice)) {
+            ALOGV("setForceUse() changing device from %x to %x for input %d",
+                    inputDesc->mDevice, newDevice, activeInput);
+            inputDesc->mDevice = newDevice;
+            AudioParameter param = AudioParameter();
+            param.addInt(String8(AudioParameter::keyRouting), (int)newDevice);
+            mpClientInterface->setParameters(activeInput, param.toString());
+        }
+    }
+
+}
+
+AudioSystem::forced_config AudioPolicyManagerBase::getForceUse(AudioSystem::force_use usage)
+{
+    return mForceUse[usage];
+}
+
+void AudioPolicyManagerBase::setSystemProperty(const char* property, const char* value)
+{
+    ALOGV("setSystemProperty() property %s, value %s", property, value);
+}
+
+// Find a direct output profile compatible with the parameters passed, even if the input flags do
+// not explicitly request a direct output
+AudioPolicyManagerBase::IOProfile *AudioPolicyManagerBase::getProfileForDirectOutput(
+                                                               audio_devices_t device,
+                                                               uint32_t samplingRate,
+                                                               audio_format_t format,
+                                                               audio_channel_mask_t channelMask,
+                                                               audio_output_flags_t flags)
+{
+    for (size_t i = 0; i < mHwModules.size(); i++) {
+        if (mHwModules[i]->mHandle == 0) {
+            continue;
+        }
+        for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++) {
+            IOProfile *profile = mHwModules[i]->mOutputProfiles[j];
+            if (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
+                if (profile->isCompatibleProfile(device, samplingRate, format,
+                                           channelMask,
+                                           AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)) {
+                    if (mAvailableOutputDevices & profile->mSupportedDevices) {
+                        return mHwModules[i]->mOutputProfiles[j];
+                    }
+                }
+            } else {
+                if (profile->isCompatibleProfile(device, samplingRate, format,
+                                           channelMask,
+                                           AUDIO_OUTPUT_FLAG_DIRECT)) {
+                    if (mAvailableOutputDevices & profile->mSupportedDevices) {
+                        return mHwModules[i]->mOutputProfiles[j];
+                    }
+                }
+            }
+        }
+    }
+    return 0;
+}
+
+audio_io_handle_t AudioPolicyManagerBase::getOutput(AudioSystem::stream_type stream,
+                                    uint32_t samplingRate,
+                                    audio_format_t format,
+                                    audio_channel_mask_t channelMask,
+                                    AudioSystem::output_flags flags,
+                                    const audio_offload_info_t *offloadInfo)
+{
+    audio_io_handle_t output = 0;
+    uint32_t latency = 0;
+    routing_strategy strategy = getStrategy((AudioSystem::stream_type)stream);
+    audio_devices_t device = getDeviceForStrategy(strategy, false /*fromCache*/);
+    ALOGV("getOutput() device %d, stream %d, samplingRate %d, format %x, channelMask %x, flags %x",
+          device, stream, samplingRate, format, channelMask, flags);
+
+#ifdef AUDIO_POLICY_TEST
+    if (mCurOutput != 0) {
+        ALOGV("getOutput() test output mCurOutput %d, samplingRate %d, format %d, channelMask %x, mDirectOutput %d",
+                mCurOutput, mTestSamplingRate, mTestFormat, mTestChannels, mDirectOutput);
+
+        if (mTestOutputs[mCurOutput] == 0) {
+            ALOGV("getOutput() opening test output");
+            AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor(NULL);
+            outputDesc->mDevice = mTestDevice;
+            outputDesc->mSamplingRate = mTestSamplingRate;
+            outputDesc->mFormat = mTestFormat;
+            outputDesc->mChannelMask = mTestChannels;
+            outputDesc->mLatency = mTestLatencyMs;
+            outputDesc->mFlags = (audio_output_flags_t)(mDirectOutput ? AudioSystem::OUTPUT_FLAG_DIRECT : 0);
+            outputDesc->mRefCount[stream] = 0;
+            mTestOutputs[mCurOutput] = mpClientInterface->openOutput(0, &outputDesc->mDevice,
+                                            &outputDesc->mSamplingRate,
+                                            &outputDesc->mFormat,
+                                            &outputDesc->mChannelMask,
+                                            &outputDesc->mLatency,
+                                            outputDesc->mFlags,
+                                            offloadInfo);
+            if (mTestOutputs[mCurOutput]) {
+                AudioParameter outputCmd = AudioParameter();
+                outputCmd.addInt(String8("set_id"),mCurOutput);
+                mpClientInterface->setParameters(mTestOutputs[mCurOutput],outputCmd.toString());
+                addOutput(mTestOutputs[mCurOutput], outputDesc);
+            }
+        }
+        return mTestOutputs[mCurOutput];
+    }
+#endif //AUDIO_POLICY_TEST
+
+    // open a direct output if required by specified parameters
+    //force direct flag if offload flag is set: offloading implies a direct output stream
+    // and all common behaviors are driven by checking only the direct flag
+    // this should normally be set appropriately in the policy configuration file
+    if ((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) {
+        flags = (AudioSystem::output_flags)(flags | AUDIO_OUTPUT_FLAG_DIRECT);
+    }
+
+    // Do not allow offloading if one non offloadable effect is enabled. This prevents from
+    // creating an offloaded track and tearing it down immediately after start when audioflinger
+    // detects there is an active non offloadable effect.
+    // FIXME: We should check the audio session here but we do not have it in this context.
+    // This may prevent offloading in rare situations where effects are left active by apps
+    // in the background.
+    IOProfile *profile = NULL;
+    if (((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) == 0) ||
+            !isNonOffloadableEffectEnabled()) {
+        profile = getProfileForDirectOutput(device,
+                                           samplingRate,
+                                           format,
+                                           channelMask,
+                                           (audio_output_flags_t)flags);
+    }
+
+    if (profile != NULL) {
+        AudioOutputDescriptor *outputDesc = NULL;
+
+        for (size_t i = 0; i < mOutputs.size(); i++) {
+            AudioOutputDescriptor *desc = mOutputs.valueAt(i);
+            if (!desc->isDuplicated() && (profile == desc->mProfile)) {
+                outputDesc = desc;
+                // reuse direct output if currently open and configured with same parameters
+                if ((samplingRate == outputDesc->mSamplingRate) &&
+                        (format == outputDesc->mFormat) &&
+                        (channelMask == outputDesc->mChannelMask)) {
+                    outputDesc->mDirectOpenCount++;
+                    ALOGV("getOutput() reusing direct output %d", mOutputs.keyAt(i));
+                    return mOutputs.keyAt(i);
+                }
+            }
+        }
+        // close direct output if currently open and configured with different parameters
+        if (outputDesc != NULL) {
+            closeOutput(outputDesc->mId);
+        }
+        outputDesc = new AudioOutputDescriptor(profile);
+        outputDesc->mDevice = device;
+        outputDesc->mSamplingRate = samplingRate;
+        outputDesc->mFormat = format;
+        outputDesc->mChannelMask = channelMask;
+        outputDesc->mLatency = 0;
+        outputDesc->mFlags =(audio_output_flags_t) (outputDesc->mFlags | flags);
+        outputDesc->mRefCount[stream] = 0;
+        outputDesc->mStopTime[stream] = 0;
+        outputDesc->mDirectOpenCount = 1;
+        output = mpClientInterface->openOutput(profile->mModule->mHandle,
+                                        &outputDesc->mDevice,
+                                        &outputDesc->mSamplingRate,
+                                        &outputDesc->mFormat,
+                                        &outputDesc->mChannelMask,
+                                        &outputDesc->mLatency,
+                                        outputDesc->mFlags,
+                                        offloadInfo);
+
+        // only accept an output with the requested parameters
+        if (output == 0 ||
+            (samplingRate != 0 && samplingRate != outputDesc->mSamplingRate) ||
+            (format != AUDIO_FORMAT_DEFAULT && format != outputDesc->mFormat) ||
+            (channelMask != 0 && channelMask != outputDesc->mChannelMask)) {
+            ALOGV("getOutput() failed opening direct output: output %d samplingRate %d %d,"
+                    "format %d %d, channelMask %04x %04x", output, samplingRate,
+                    outputDesc->mSamplingRate, format, outputDesc->mFormat, channelMask,
+                    outputDesc->mChannelMask);
+            if (output != 0) {
+                mpClientInterface->closeOutput(output);
+            }
+            delete outputDesc;
+            return 0;
+        }
+        audio_io_handle_t srcOutput = getOutputForEffect();
+        addOutput(output, outputDesc);
+        audio_io_handle_t dstOutput = getOutputForEffect();
+        if (dstOutput == output) {
+            mpClientInterface->moveEffects(AUDIO_SESSION_OUTPUT_MIX, srcOutput, dstOutput);
+        }
+        mPreviousOutputs = mOutputs;
+        ALOGV("getOutput() returns new direct output %d", output);
+        return output;
+    }
+
+    // ignoring channel mask due to downmix capability in mixer
+
+    // open a non direct output
+
+    // for non direct outputs, only PCM is supported
+    if (audio_is_linear_pcm(format)) {
+        // get which output is suitable for the specified stream. The actual
+        // routing change will happen when startOutput() will be called
+        SortedVector<audio_io_handle_t> outputs = getOutputsForDevice(device, mOutputs);
+
+        output = selectOutput(outputs, flags);
+    }
+    ALOGW_IF((output == 0), "getOutput() could not find output for stream %d, samplingRate %d,"
+            "format %d, channels %x, flags %x", stream, samplingRate, format, channelMask, flags);
+
+    ALOGV("getOutput() returns output %d", output);
+
+    return output;
+}
+
+audio_io_handle_t AudioPolicyManagerBase::selectOutput(const SortedVector<audio_io_handle_t>& outputs,
+                                                       AudioSystem::output_flags flags)
+{
+    // select one output among several that provide a path to a particular device or set of
+    // devices (the list was previously build by getOutputsForDevice()).
+    // The priority is as follows:
+    // 1: the output with the highest number of requested policy flags
+    // 2: the primary output
+    // 3: the first output in the list
+
+    if (outputs.size() == 0) {
+        return 0;
+    }
+    if (outputs.size() == 1) {
+        return outputs[0];
+    }
+
+    int maxCommonFlags = 0;
+    audio_io_handle_t outputFlags = 0;
+    audio_io_handle_t outputPrimary = 0;
+
+    for (size_t i = 0; i < outputs.size(); i++) {
+        AudioOutputDescriptor *outputDesc = mOutputs.valueFor(outputs[i]);
+        if (!outputDesc->isDuplicated()) {
+            int commonFlags = (int)AudioSystem::popCount(outputDesc->mProfile->mFlags & flags);
+            if (commonFlags > maxCommonFlags) {
+                outputFlags = outputs[i];
+                maxCommonFlags = commonFlags;
+                ALOGV("selectOutput() commonFlags for output %d, %04x", outputs[i], commonFlags);
+            }
+            if (outputDesc->mProfile->mFlags & AUDIO_OUTPUT_FLAG_PRIMARY) {
+                outputPrimary = outputs[i];
+            }
+        }
+    }
+
+    if (outputFlags != 0) {
+        return outputFlags;
+    }
+    if (outputPrimary != 0) {
+        return outputPrimary;
+    }
+
+    return outputs[0];
+}
+
+status_t AudioPolicyManagerBase::startOutput(audio_io_handle_t output,
+                                             AudioSystem::stream_type stream,
+                                             int session)
+{
+    ALOGV("startOutput() output %d, stream %d, session %d", output, stream, session);
+    ssize_t index = mOutputs.indexOfKey(output);
+    if (index < 0) {
+        ALOGW("startOutput() unknown output %d", output);
+        return BAD_VALUE;
+    }
+
+    AudioOutputDescriptor *outputDesc = mOutputs.valueAt(index);
+
+    // increment usage count for this stream on the requested output:
+    // NOTE that the usage count is the same for duplicated output and hardware output which is
+    // necessary for a correct control of hardware output routing by startOutput() and stopOutput()
+    outputDesc->changeRefCount(stream, 1);
+
+    if (outputDesc->mRefCount[stream] == 1) {
+        audio_devices_t newDevice = getNewDevice(output, false /*fromCache*/);
+        routing_strategy strategy = getStrategy(stream);
+        bool shouldWait = (strategy == STRATEGY_SONIFICATION) ||
+                            (strategy == STRATEGY_SONIFICATION_RESPECTFUL);
+        uint32_t waitMs = 0;
+        bool force = false;
+        for (size_t i = 0; i < mOutputs.size(); i++) {
+            AudioOutputDescriptor *desc = mOutputs.valueAt(i);
+            if (desc != outputDesc) {
+                // force a device change if any other output is managed by the same hw
+                // module and has a current device selection that differs from selected device.
+                // In this case, the audio HAL must receive the new device selection so that it can
+                // change the device currently selected by the other active output.
+                if (outputDesc->sharesHwModuleWith(desc) &&
+                    desc->device() != newDevice) {
+                    force = true;
+                }
+                // wait for audio on other active outputs to be presented when starting
+                // a notification so that audio focus effect can propagate.
+                uint32_t latency = desc->latency();
+                if (shouldWait && desc->isActive(latency * 2) && (waitMs < latency)) {
+                    waitMs = latency;
+                }
+            }
+        }
+        uint32_t muteWaitMs = setOutputDevice(output, newDevice, force);
+
+        // handle special case for sonification while in call
+        if (isInCall()) {
+            handleIncallSonification(stream, true, false);
+        }
+
+        // apply volume rules for current stream and device if necessary
+        checkAndSetVolume(stream,
+                          mStreams[stream].getVolumeIndex(newDevice),
+                          output,
+                          newDevice);
+
+        // update the outputs if starting an output with a stream that can affect notification
+        // routing
+        handleNotificationRoutingForStream(stream);
+        if (waitMs > muteWaitMs) {
+            usleep((waitMs - muteWaitMs) * 2 * 1000);
+        }
+    }
+    return NO_ERROR;
+}
+
+
+status_t AudioPolicyManagerBase::stopOutput(audio_io_handle_t output,
+                                            AudioSystem::stream_type stream,
+                                            int session)
+{
+    ALOGV("stopOutput() output %d, stream %d, session %d", output, stream, session);
+    ssize_t index = mOutputs.indexOfKey(output);
+    if (index < 0) {
+        ALOGW("stopOutput() unknown output %d", output);
+        return BAD_VALUE;
+    }
+
+    AudioOutputDescriptor *outputDesc = mOutputs.valueAt(index);
+
+    // handle special case for sonification while in call
+    if (isInCall()) {
+        handleIncallSonification(stream, false, false);
+    }
+
+    if (outputDesc->mRefCount[stream] > 0) {
+        // decrement usage count of this stream on the output
+        outputDesc->changeRefCount(stream, -1);
+        // store time at which the stream was stopped - see isStreamActive()
+        if (outputDesc->mRefCount[stream] == 0) {
+            outputDesc->mStopTime[stream] = systemTime();
+            audio_devices_t newDevice = getNewDevice(output, false /*fromCache*/);
+            // delay the device switch by twice the latency because stopOutput() is executed when
+            // the track stop() command is received and at that time the audio track buffer can
+            // still contain data that needs to be drained. The latency only covers the audio HAL
+            // and kernel buffers. Also the latency does not always include additional delay in the
+            // audio path (audio DSP, CODEC ...)
+            setOutputDevice(output, newDevice, false, outputDesc->mLatency*2);
+
+            // force restoring the device selection on other active outputs if it differs from the
+            // one being selected for this output
+            for (size_t i = 0; i < mOutputs.size(); i++) {
+                audio_io_handle_t curOutput = mOutputs.keyAt(i);
+                AudioOutputDescriptor *desc = mOutputs.valueAt(i);
+                if (curOutput != output &&
+                        desc->isActive() &&
+                        outputDesc->sharesHwModuleWith(desc) &&
+                        (newDevice != desc->device())) {
+                    setOutputDevice(curOutput,
+                                    getNewDevice(curOutput, false /*fromCache*/),
+                                    true,
+                                    outputDesc->mLatency*2);
+                }
+            }
+            // update the outputs if stopping one with a stream that can affect notification routing
+            handleNotificationRoutingForStream(stream);
+        }
+        return NO_ERROR;
+    } else {
+        ALOGW("stopOutput() refcount is already 0 for output %d", output);
+        return INVALID_OPERATION;
+    }
+}
+
+void AudioPolicyManagerBase::releaseOutput(audio_io_handle_t output)
+{
+    ALOGV("releaseOutput() %d", output);
+    ssize_t index = mOutputs.indexOfKey(output);
+    if (index < 0) {
+        ALOGW("releaseOutput() releasing unknown output %d", output);
+        return;
+    }
+
+#ifdef AUDIO_POLICY_TEST
+    int testIndex = testOutputIndex(output);
+    if (testIndex != 0) {
+        AudioOutputDescriptor *outputDesc = mOutputs.valueAt(index);
+        if (outputDesc->isActive()) {
+            mpClientInterface->closeOutput(output);
+            delete mOutputs.valueAt(index);
+            mOutputs.removeItem(output);
+            mTestOutputs[testIndex] = 0;
+        }
+        return;
+    }
+#endif //AUDIO_POLICY_TEST
+
+    AudioOutputDescriptor *desc = mOutputs.valueAt(index);
+    if (desc->mFlags & AudioSystem::OUTPUT_FLAG_DIRECT) {
+        if (desc->mDirectOpenCount <= 0) {
+            ALOGW("releaseOutput() invalid open count %d for output %d",
+                                                              desc->mDirectOpenCount, output);
+            return;
+        }
+        if (--desc->mDirectOpenCount == 0) {
+            closeOutput(output);
+            // If effects where present on the output, audioflinger moved them to the primary
+            // output by default: move them back to the appropriate output.
+            audio_io_handle_t dstOutput = getOutputForEffect();
+            if (dstOutput != mPrimaryOutput) {
+                mpClientInterface->moveEffects(AUDIO_SESSION_OUTPUT_MIX, mPrimaryOutput, dstOutput);
+            }
+        }
+    }
+}
+
+
+audio_io_handle_t AudioPolicyManagerBase::getInput(int inputSource,
+                                    uint32_t samplingRate,
+                                    audio_format_t format,
+                                    audio_channel_mask_t channelMask,
+                                    AudioSystem::audio_in_acoustics acoustics)
+{
+    audio_io_handle_t input = 0;
+    audio_devices_t device = getDeviceForInputSource(inputSource);
+
+    ALOGV("getInput() inputSource %d, samplingRate %d, format %d, channelMask %x, acoustics %x",
+          inputSource, samplingRate, format, channelMask, acoustics);
+
+    if (device == AUDIO_DEVICE_NONE) {
+        ALOGW("getInput() could not find device for inputSource %d", inputSource);
+        return 0;
+    }
+
+    // adapt channel selection to input source
+    switch(inputSource) {
+    case AUDIO_SOURCE_VOICE_UPLINK:
+        channelMask = AUDIO_CHANNEL_IN_VOICE_UPLINK;
+        break;
+    case AUDIO_SOURCE_VOICE_DOWNLINK:
+        channelMask = AUDIO_CHANNEL_IN_VOICE_DNLINK;
+        break;
+    case AUDIO_SOURCE_VOICE_CALL:
+        channelMask = AUDIO_CHANNEL_IN_VOICE_UPLINK | AUDIO_CHANNEL_IN_VOICE_DNLINK;
+        break;
+    default:
+        break;
+    }
+
+    IOProfile *profile = getInputProfile(device,
+                                         samplingRate,
+                                         format,
+                                         channelMask);
+    if (profile == NULL) {
+        ALOGW("getInput() could not find profile for device 0x%X, samplingRate %d, format %d, "
+                "channelMask 0x%X",
+                device, samplingRate, format, channelMask);
+        return 0;
+    }
+
+    if (profile->mModule->mHandle == 0) {
+        ALOGE("getInput(): HW module %s not opened", profile->mModule->mName);
+        return 0;
+    }
+
+    AudioInputDescriptor *inputDesc = new AudioInputDescriptor(profile);
+
+    inputDesc->mInputSource = inputSource;
+    inputDesc->mDevice = device;
+    inputDesc->mSamplingRate = samplingRate;
+    inputDesc->mFormat = format;
+    inputDesc->mChannelMask = channelMask;
+    inputDesc->mRefCount = 0;
+
+    input = mpClientInterface->openInput(profile->mModule->mHandle,
+                                    &inputDesc->mDevice,
+                                    &inputDesc->mSamplingRate,
+                                    &inputDesc->mFormat,
+                                    &inputDesc->mChannelMask);
+
+    // only accept input with the exact requested set of parameters
+    if (input == 0 ||
+        (samplingRate != inputDesc->mSamplingRate) ||
+        (format != inputDesc->mFormat) ||
+        (channelMask != inputDesc->mChannelMask)) {
+        ALOGI("getInput() failed opening input: samplingRate %d, format %d, channelMask 0x%X",
+                samplingRate, format, channelMask);
+        if (input != 0) {
+            mpClientInterface->closeInput(input);
+        }
+        delete inputDesc;
+        return 0;
+    }
+    addInput(input, inputDesc);
+
+    return input;
+}
+
+status_t AudioPolicyManagerBase::startInput(audio_io_handle_t input)
+{
+    ALOGV("startInput() input %d", input);
+    ssize_t index = mInputs.indexOfKey(input);
+    if (index < 0) {
+        ALOGW("startInput() unknown input %d", input);
+        return BAD_VALUE;
+    }
+    AudioInputDescriptor *inputDesc = mInputs.valueAt(index);
+
+#ifdef AUDIO_POLICY_TEST
+    if (mTestInput == 0)
+#endif //AUDIO_POLICY_TEST
+    {
+        // refuse 2 active AudioRecord clients at the same time except if the active input
+        // uses AUDIO_SOURCE_HOTWORD in which case it is closed.
+        audio_io_handle_t activeInput = getActiveInput();
+        if (!isVirtualInputDevice(inputDesc->mDevice) && activeInput != 0) {
+            AudioInputDescriptor *activeDesc = mInputs.valueFor(activeInput);
+            if (activeDesc->mInputSource == AUDIO_SOURCE_HOTWORD) {
+                ALOGW("startInput() preempting already started low-priority input %d", activeInput);
+                stopInput(activeInput);
+                releaseInput(activeInput);
+            } else {
+                ALOGW("startInput() input %d failed: other input already started", input);
+                return INVALID_OPERATION;
+            }
+        }
+    }
+
+    audio_devices_t newDevice = getDeviceForInputSource(inputDesc->mInputSource);
+    if ((newDevice != AUDIO_DEVICE_NONE) && (newDevice != inputDesc->mDevice)) {
+        inputDesc->mDevice = newDevice;
+    }
+
+    // automatically enable the remote submix output when input is started
+    if (audio_is_remote_submix_device(inputDesc->mDevice)) {
+        setDeviceConnectionState(AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
+                AudioSystem::DEVICE_STATE_AVAILABLE, AUDIO_REMOTE_SUBMIX_DEVICE_ADDRESS);
+    }
+
+    AudioParameter param = AudioParameter();
+    param.addInt(String8(AudioParameter::keyRouting), (int)inputDesc->mDevice);
+
+    int aliasSource = (inputDesc->mInputSource == AUDIO_SOURCE_HOTWORD) ?
+                                        AUDIO_SOURCE_VOICE_RECOGNITION : inputDesc->mInputSource;
+
+    param.addInt(String8(AudioParameter::keyInputSource), aliasSource);
+    ALOGV("AudioPolicyManager::startInput() input source = %d", inputDesc->mInputSource);
+
+    mpClientInterface->setParameters(input, param.toString());
+
+    inputDesc->mRefCount = 1;
+    return NO_ERROR;
+}
+
+status_t AudioPolicyManagerBase::stopInput(audio_io_handle_t input)
+{
+    ALOGV("stopInput() input %d", input);
+    ssize_t index = mInputs.indexOfKey(input);
+    if (index < 0) {
+        ALOGW("stopInput() unknown input %d", input);
+        return BAD_VALUE;
+    }
+    AudioInputDescriptor *inputDesc = mInputs.valueAt(index);
+
+    if (inputDesc->mRefCount == 0) {
+        ALOGW("stopInput() input %d already stopped", input);
+        return INVALID_OPERATION;
+    } else {
+        // automatically disable the remote submix output when input is stopped
+        if (audio_is_remote_submix_device(inputDesc->mDevice)) {
+            setDeviceConnectionState(AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
+                    AudioSystem::DEVICE_STATE_UNAVAILABLE, AUDIO_REMOTE_SUBMIX_DEVICE_ADDRESS);
+        }
+
+        AudioParameter param = AudioParameter();
+        param.addInt(String8(AudioParameter::keyRouting), 0);
+        mpClientInterface->setParameters(input, param.toString());
+        inputDesc->mRefCount = 0;
+        return NO_ERROR;
+    }
+}
+
+void AudioPolicyManagerBase::releaseInput(audio_io_handle_t input)
+{
+    ALOGV("releaseInput() %d", input);
+    ssize_t index = mInputs.indexOfKey(input);
+    if (index < 0) {
+        ALOGW("releaseInput() releasing unknown input %d", input);
+        return;
+    }
+    mpClientInterface->closeInput(input);
+    delete mInputs.valueAt(index);
+    mInputs.removeItem(input);
+
+    ALOGV("releaseInput() exit");
+}
+
+void AudioPolicyManagerBase::closeAllInputs() {
+    for(size_t input_index = 0; input_index < mInputs.size(); input_index++) {
+        mpClientInterface->closeInput(mInputs.keyAt(input_index));
+    }
+    mInputs.clear();
+}
+
+void AudioPolicyManagerBase::initStreamVolume(AudioSystem::stream_type stream,
+                                            int indexMin,
+                                            int indexMax)
+{
+    ALOGV("initStreamVolume() stream %d, min %d, max %d", stream , indexMin, indexMax);
+    if (indexMin < 0 || indexMin >= indexMax) {
+        ALOGW("initStreamVolume() invalid index limits for stream %d, min %d, max %d", stream , indexMin, indexMax);
+        return;
+    }
+    mStreams[stream].mIndexMin = indexMin;
+    mStreams[stream].mIndexMax = indexMax;
+}
+
+status_t AudioPolicyManagerBase::setStreamVolumeIndex(AudioSystem::stream_type stream,
+                                                      int index,
+                                                      audio_devices_t device)
+{
+
+    if ((index < mStreams[stream].mIndexMin) || (index > mStreams[stream].mIndexMax)) {
+        return BAD_VALUE;
+    }
+    if (!audio_is_output_device(device)) {
+        return BAD_VALUE;
+    }
+
+    // Force max volume if stream cannot be muted
+    if (!mStreams[stream].mCanBeMuted) index = mStreams[stream].mIndexMax;
+
+    ALOGV("setStreamVolumeIndex() stream %d, device %04x, index %d",
+          stream, device, index);
+
+    // if device is AUDIO_DEVICE_OUT_DEFAULT set default value and
+    // clear all device specific values
+    if (device == AUDIO_DEVICE_OUT_DEFAULT) {
+        mStreams[stream].mIndexCur.clear();
+    }
+    mStreams[stream].mIndexCur.add(device, index);
+
+    // compute and apply stream volume on all outputs according to connected device
+    status_t status = NO_ERROR;
+    for (size_t i = 0; i < mOutputs.size(); i++) {
+        audio_devices_t curDevice =
+                getDeviceForVolume(mOutputs.valueAt(i)->device());
+        if ((device == AUDIO_DEVICE_OUT_DEFAULT) || (device == curDevice)) {
+            status_t volStatus = checkAndSetVolume(stream, index, mOutputs.keyAt(i), curDevice);
+            if (volStatus != NO_ERROR) {
+                status = volStatus;
+            }
+        }
+    }
+    return status;
+}
+
+status_t AudioPolicyManagerBase::getStreamVolumeIndex(AudioSystem::stream_type stream,
+                                                      int *index,
+                                                      audio_devices_t device)
+{
+    if (index == NULL) {
+        return BAD_VALUE;
+    }
+    if (!audio_is_output_device(device)) {
+        return BAD_VALUE;
+    }
+    // if device is AUDIO_DEVICE_OUT_DEFAULT, return volume for device corresponding to
+    // the strategy the stream belongs to.
+    if (device == AUDIO_DEVICE_OUT_DEFAULT) {
+        device = getDeviceForStrategy(getStrategy(stream), true /*fromCache*/);
+    }
+    device = getDeviceForVolume(device);
+
+    *index =  mStreams[stream].getVolumeIndex(device);
+    ALOGV("getStreamVolumeIndex() stream %d device %08x index %d", stream, device, *index);
+    return NO_ERROR;
+}
+
+audio_io_handle_t AudioPolicyManagerBase::selectOutputForEffects(
+                                            const SortedVector<audio_io_handle_t>& outputs)
+{
+    // select one output among several suitable for global effects.
+    // The priority is as follows:
+    // 1: An offloaded output. If the effect ends up not being offloadable,
+    //    AudioFlinger will invalidate the track and the offloaded output
+    //    will be closed causing the effect to be moved to a PCM output.
+    // 2: A deep buffer output
+    // 3: the first output in the list
+
+    if (outputs.size() == 0) {
+        return 0;
+    }
+
+    audio_io_handle_t outputOffloaded = 0;
+    audio_io_handle_t outputDeepBuffer = 0;
+
+    for (size_t i = 0; i < outputs.size(); i++) {
+        AudioOutputDescriptor *desc = mOutputs.valueFor(outputs[i]);
+        ALOGV("selectOutputForEffects outputs[%zu] flags %x", i, desc->mFlags);
+        if ((desc->mFlags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) {
+            outputOffloaded = outputs[i];
+        }
+        if ((desc->mFlags & AUDIO_OUTPUT_FLAG_DEEP_BUFFER) != 0) {
+            outputDeepBuffer = outputs[i];
+        }
+    }
+
+    ALOGV("selectOutputForEffects outputOffloaded %d outputDeepBuffer %d",
+          outputOffloaded, outputDeepBuffer);
+    if (outputOffloaded != 0) {
+        return outputOffloaded;
+    }
+    if (outputDeepBuffer != 0) {
+        return outputDeepBuffer;
+    }
+
+    return outputs[0];
+}
+
+audio_io_handle_t AudioPolicyManagerBase::getOutputForEffect(const effect_descriptor_t *desc)
+{
+    // apply simple rule where global effects are attached to the same output as MUSIC streams
+
+    routing_strategy strategy = getStrategy(AudioSystem::MUSIC);
+    audio_devices_t device = getDeviceForStrategy(strategy, false /*fromCache*/);
+    SortedVector<audio_io_handle_t> dstOutputs = getOutputsForDevice(device, mOutputs);
+
+    audio_io_handle_t output = selectOutputForEffects(dstOutputs);
+    ALOGV("getOutputForEffect() got output %d for fx %s flags %x",
+          output, (desc == NULL) ? "unspecified" : desc->name,  (desc == NULL) ? 0 : desc->flags);
+
+    return output;
+}
+
+status_t AudioPolicyManagerBase::registerEffect(const effect_descriptor_t *desc,
+                                audio_io_handle_t io,
+                                uint32_t strategy,
+                                int session,
+                                int id)
+{
+    ssize_t index = mOutputs.indexOfKey(io);
+    if (index < 0) {
+        index = mInputs.indexOfKey(io);
+        if (index < 0) {
+            ALOGW("registerEffect() unknown io %d", io);
+            return INVALID_OPERATION;
+        }
+    }
+
+    if (mTotalEffectsMemory + desc->memoryUsage > getMaxEffectsMemory()) {
+        ALOGW("registerEffect() memory limit exceeded for Fx %s, Memory %d KB",
+                desc->name, desc->memoryUsage);
+        return INVALID_OPERATION;
+    }
+    mTotalEffectsMemory += desc->memoryUsage;
+    ALOGV("registerEffect() effect %s, io %d, strategy %d session %d id %d",
+            desc->name, io, strategy, session, id);
+    ALOGV("registerEffect() memory %d, total memory %d", desc->memoryUsage, mTotalEffectsMemory);
+
+    EffectDescriptor *pDesc = new EffectDescriptor();
+    memcpy (&pDesc->mDesc, desc, sizeof(effect_descriptor_t));
+    pDesc->mIo = io;
+    pDesc->mStrategy = (routing_strategy)strategy;
+    pDesc->mSession = session;
+    pDesc->mEnabled = false;
+
+    mEffects.add(id, pDesc);
+
+    return NO_ERROR;
+}
+
+status_t AudioPolicyManagerBase::unregisterEffect(int id)
+{
+    ssize_t index = mEffects.indexOfKey(id);
+    if (index < 0) {
+        ALOGW("unregisterEffect() unknown effect ID %d", id);
+        return INVALID_OPERATION;
+    }
+
+    EffectDescriptor *pDesc = mEffects.valueAt(index);
+
+    setEffectEnabled(pDesc, false);
+
+    if (mTotalEffectsMemory < pDesc->mDesc.memoryUsage) {
+        ALOGW("unregisterEffect() memory %d too big for total %d",
+                pDesc->mDesc.memoryUsage, mTotalEffectsMemory);
+        pDesc->mDesc.memoryUsage = mTotalEffectsMemory;
+    }
+    mTotalEffectsMemory -= pDesc->mDesc.memoryUsage;
+    ALOGV("unregisterEffect() effect %s, ID %d, memory %d total memory %d",
+            pDesc->mDesc.name, id, pDesc->mDesc.memoryUsage, mTotalEffectsMemory);
+
+    mEffects.removeItem(id);
+    delete pDesc;
+
+    return NO_ERROR;
+}
+
+status_t AudioPolicyManagerBase::setEffectEnabled(int id, bool enabled)
+{
+    ssize_t index = mEffects.indexOfKey(id);
+    if (index < 0) {
+        ALOGW("unregisterEffect() unknown effect ID %d", id);
+        return INVALID_OPERATION;
+    }
+
+    return setEffectEnabled(mEffects.valueAt(index), enabled);
+}
+
+status_t AudioPolicyManagerBase::setEffectEnabled(EffectDescriptor *pDesc, bool enabled)
+{
+    if (enabled == pDesc->mEnabled) {
+        ALOGV("setEffectEnabled(%s) effect already %s",
+             enabled?"true":"false", enabled?"enabled":"disabled");
+        return INVALID_OPERATION;
+    }
+
+    if (enabled) {
+        if (mTotalEffectsCpuLoad + pDesc->mDesc.cpuLoad > getMaxEffectsCpuLoad()) {
+            ALOGW("setEffectEnabled(true) CPU Load limit exceeded for Fx %s, CPU %f MIPS",
+                 pDesc->mDesc.name, (float)pDesc->mDesc.cpuLoad/10);
+            return INVALID_OPERATION;
+        }
+        mTotalEffectsCpuLoad += pDesc->mDesc.cpuLoad;
+        ALOGV("setEffectEnabled(true) total CPU %d", mTotalEffectsCpuLoad);
+    } else {
+        if (mTotalEffectsCpuLoad < pDesc->mDesc.cpuLoad) {
+            ALOGW("setEffectEnabled(false) CPU load %d too high for total %d",
+                    pDesc->mDesc.cpuLoad, mTotalEffectsCpuLoad);
+            pDesc->mDesc.cpuLoad = mTotalEffectsCpuLoad;
+        }
+        mTotalEffectsCpuLoad -= pDesc->mDesc.cpuLoad;
+        ALOGV("setEffectEnabled(false) total CPU %d", mTotalEffectsCpuLoad);
+    }
+    pDesc->mEnabled = enabled;
+    return NO_ERROR;
+}
+
+bool AudioPolicyManagerBase::isNonOffloadableEffectEnabled()
+{
+    for (size_t i = 0; i < mEffects.size(); i++) {
+        const EffectDescriptor * const pDesc = mEffects.valueAt(i);
+        if (pDesc->mEnabled && (pDesc->mStrategy == STRATEGY_MEDIA) &&
+                ((pDesc->mDesc.flags & EFFECT_FLAG_OFFLOAD_SUPPORTED) == 0)) {
+            ALOGV("isNonOffloadableEffectEnabled() non offloadable effect %s enabled on session %d",
+                  pDesc->mDesc.name, pDesc->mSession);
+            return true;
+        }
+    }
+    return false;
+}
+
+bool AudioPolicyManagerBase::isStreamActive(int stream, uint32_t inPastMs) const
+{
+    nsecs_t sysTime = systemTime();
+    for (size_t i = 0; i < mOutputs.size(); i++) {
+        const AudioOutputDescriptor *outputDesc = mOutputs.valueAt(i);
+        if (outputDesc->isStreamActive((AudioSystem::stream_type)stream, inPastMs, sysTime)) {
+            return true;
+        }
+    }
+    return false;
+}
+
+bool AudioPolicyManagerBase::isStreamActiveRemotely(int stream, uint32_t inPastMs) const
+{
+    nsecs_t sysTime = systemTime();
+    for (size_t i = 0; i < mOutputs.size(); i++) {
+        const AudioOutputDescriptor *outputDesc = mOutputs.valueAt(i);
+        if (((outputDesc->device() & APM_AUDIO_OUT_DEVICE_REMOTE_ALL) != 0) &&
+                outputDesc->isStreamActive((AudioSystem::stream_type)stream, inPastMs, sysTime)) {
+            return true;
+        }
+    }
+    return false;
+}
+
+bool AudioPolicyManagerBase::isSourceActive(audio_source_t source) const
+{
+    for (size_t i = 0; i < mInputs.size(); i++) {
+        const AudioInputDescriptor * inputDescriptor = mInputs.valueAt(i);
+        if ((inputDescriptor->mInputSource == (int)source ||
+                (source == (audio_source_t)AUDIO_SOURCE_VOICE_RECOGNITION &&
+                 inputDescriptor->mInputSource == AUDIO_SOURCE_HOTWORD))
+             && (inputDescriptor->mRefCount > 0)) {
+            return true;
+        }
+    }
+    return false;
+}
+
+
+status_t AudioPolicyManagerBase::dump(int fd)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+
+    snprintf(buffer, SIZE, "\nAudioPolicyManager Dump: %p\n", this);
+    result.append(buffer);
+
+    snprintf(buffer, SIZE, " Primary Output: %d\n", mPrimaryOutput);
+    result.append(buffer);
+    snprintf(buffer, SIZE, " A2DP device address: %s\n", mA2dpDeviceAddress.string());
+    result.append(buffer);
+    snprintf(buffer, SIZE, " SCO device address: %s\n", mScoDeviceAddress.string());
+    result.append(buffer);
+    snprintf(buffer, SIZE, " USB audio ALSA %s\n", mUsbOutCardAndDevice.string());
+    result.append(buffer);
+    snprintf(buffer, SIZE, " Output devices: %08x\n", mAvailableOutputDevices);
+    result.append(buffer);
+    snprintf(buffer, SIZE, " Input devices: %08x\n", mAvailableInputDevices);
+    result.append(buffer);
+    snprintf(buffer, SIZE, " Phone state: %d\n", mPhoneState);
+    result.append(buffer);
+    snprintf(buffer, SIZE, " Force use for communications %d\n", mForceUse[AudioSystem::FOR_COMMUNICATION]);
+    result.append(buffer);
+    snprintf(buffer, SIZE, " Force use for media %d\n", mForceUse[AudioSystem::FOR_MEDIA]);
+    result.append(buffer);
+    snprintf(buffer, SIZE, " Force use for record %d\n", mForceUse[AudioSystem::FOR_RECORD]);
+    result.append(buffer);
+    snprintf(buffer, SIZE, " Force use for dock %d\n", mForceUse[AudioSystem::FOR_DOCK]);
+    result.append(buffer);
+    snprintf(buffer, SIZE, " Force use for system %d\n", mForceUse[AudioSystem::FOR_SYSTEM]);
+    result.append(buffer);
+    write(fd, result.string(), result.size());
+
+
+    snprintf(buffer, SIZE, "\nHW Modules dump:\n");
+    write(fd, buffer, strlen(buffer));
+    for (size_t i = 0; i < mHwModules.size(); i++) {
+        snprintf(buffer, SIZE, "- HW Module %zu:\n", i + 1);
+        write(fd, buffer, strlen(buffer));
+        mHwModules[i]->dump(fd);
+    }
+
+    snprintf(buffer, SIZE, "\nOutputs dump:\n");
+    write(fd, buffer, strlen(buffer));
+    for (size_t i = 0; i < mOutputs.size(); i++) {
+        snprintf(buffer, SIZE, "- Output %d dump:\n", mOutputs.keyAt(i));
+        write(fd, buffer, strlen(buffer));
+        mOutputs.valueAt(i)->dump(fd);
+    }
+
+    snprintf(buffer, SIZE, "\nInputs dump:\n");
+    write(fd, buffer, strlen(buffer));
+    for (size_t i = 0; i < mInputs.size(); i++) {
+        snprintf(buffer, SIZE, "- Input %d dump:\n", mInputs.keyAt(i));
+        write(fd, buffer, strlen(buffer));
+        mInputs.valueAt(i)->dump(fd);
+    }
+
+    snprintf(buffer, SIZE, "\nStreams dump:\n");
+    write(fd, buffer, strlen(buffer));
+    snprintf(buffer, SIZE,
+             " Stream  Can be muted  Index Min  Index Max  Index Cur [device : index]...\n");
+    write(fd, buffer, strlen(buffer));
+    for (size_t i = 0; i < AudioSystem::NUM_STREAM_TYPES; i++) {
+        snprintf(buffer, SIZE, " %02zu      ", i);
+        write(fd, buffer, strlen(buffer));
+        mStreams[i].dump(fd);
+    }
+
+    snprintf(buffer, SIZE, "\nTotal Effects CPU: %f MIPS, Total Effects memory: %d KB\n",
+            (float)mTotalEffectsCpuLoad/10, mTotalEffectsMemory);
+    write(fd, buffer, strlen(buffer));
+
+    snprintf(buffer, SIZE, "Registered effects:\n");
+    write(fd, buffer, strlen(buffer));
+    for (size_t i = 0; i < mEffects.size(); i++) {
+        snprintf(buffer, SIZE, "- Effect %d dump:\n", mEffects.keyAt(i));
+        write(fd, buffer, strlen(buffer));
+        mEffects.valueAt(i)->dump(fd);
+    }
+
+
+    return NO_ERROR;
+}
+
+// This function checks for the parameters which can be offloaded.
+// This can be enhanced depending on the capability of the DSP and policy
+// of the system.
+bool AudioPolicyManagerBase::isOffloadSupported(const audio_offload_info_t& offloadInfo)
+{
+    ALOGV("isOffloadSupported: SR=%u, CM=0x%x, Format=0x%x, StreamType=%d,"
+     " BitRate=%u, duration=%" PRId64 " us, has_video=%d",
+     offloadInfo.sample_rate, offloadInfo.channel_mask,
+     offloadInfo.format,
+     offloadInfo.stream_type, offloadInfo.bit_rate, offloadInfo.duration_us,
+     offloadInfo.has_video);
+
+    // Check if offload has been disabled
+    char propValue[PROPERTY_VALUE_MAX];
+    if (property_get("audio.offload.disable", propValue, "0")) {
+        if (atoi(propValue) != 0) {
+            ALOGV("offload disabled by audio.offload.disable=%s", propValue );
+            return false;
+        }
+    }
+
+    // Check if stream type is music, then only allow offload as of now.
+    if (offloadInfo.stream_type != AUDIO_STREAM_MUSIC)
+    {
+        ALOGV("isOffloadSupported: stream_type != MUSIC, returning false");
+        return false;
+    }
+
+    //TODO: enable audio offloading with video when ready
+    if (offloadInfo.has_video)
+    {
+        ALOGV("isOffloadSupported: has_video == true, returning false");
+        return false;
+    }
+
+    //If duration is less than minimum value defined in property, return false
+    if (property_get("audio.offload.min.duration.secs", propValue, NULL)) {
+        if (offloadInfo.duration_us < (atoi(propValue) * 1000000 )) {
+            ALOGV("Offload denied by duration < audio.offload.min.duration.secs(=%s)", propValue);
+            return false;
+        }
+    } else if (offloadInfo.duration_us < OFFLOAD_DEFAULT_MIN_DURATION_SECS * 1000000) {
+        ALOGV("Offload denied by duration < default min(=%u)", OFFLOAD_DEFAULT_MIN_DURATION_SECS);
+        return false;
+    }
+
+    // Do not allow offloading if one non offloadable effect is enabled. This prevents from
+    // creating an offloaded track and tearing it down immediately after start when audioflinger
+    // detects there is an active non offloadable effect.
+    // FIXME: We should check the audio session here but we do not have it in this context.
+    // This may prevent offloading in rare situations where effects are left active by apps
+    // in the background.
+    if (isNonOffloadableEffectEnabled()) {
+        return false;
+    }
+
+    // See if there is a profile to support this.
+    // AUDIO_DEVICE_NONE
+    IOProfile *profile = getProfileForDirectOutput(AUDIO_DEVICE_NONE /*ignore device */,
+                                            offloadInfo.sample_rate,
+                                            offloadInfo.format,
+                                            offloadInfo.channel_mask,
+                                            AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD);
+    ALOGV("isOffloadSupported() profile %sfound", profile != NULL ? "" : "NOT ");
+    return (profile != NULL);
+}
+
+// ----------------------------------------------------------------------------
+// AudioPolicyManagerBase
+// ----------------------------------------------------------------------------
+
+AudioPolicyManagerBase::AudioPolicyManagerBase(AudioPolicyClientInterface *clientInterface)
+    :
+#ifdef AUDIO_POLICY_TEST
+    Thread(false),
+#endif //AUDIO_POLICY_TEST
+    mPrimaryOutput((audio_io_handle_t)0),
+    mAvailableOutputDevices(AUDIO_DEVICE_NONE),
+    mPhoneState(AudioSystem::MODE_NORMAL),
+    mLimitRingtoneVolume(false), mLastVoiceVolume(-1.0f),
+    mTotalEffectsCpuLoad(0), mTotalEffectsMemory(0),
+    mA2dpSuspended(false), mHasA2dp(false), mHasUsb(false), mHasRemoteSubmix(false),
+    mSpeakerDrcEnabled(false)
+{
+    mpClientInterface = clientInterface;
+
+    for (int i = 0; i < AudioSystem::NUM_FORCE_USE; i++) {
+        mForceUse[i] = AudioSystem::FORCE_NONE;
+    }
+
+    mA2dpDeviceAddress = String8("");
+    mScoDeviceAddress = String8("");
+    mUsbOutCardAndDevice = String8("");
+
+    if (loadAudioPolicyConfig(AUDIO_POLICY_VENDOR_CONFIG_FILE) != NO_ERROR) {
+        if (loadAudioPolicyConfig(AUDIO_POLICY_CONFIG_FILE) != NO_ERROR) {
+            ALOGE("could not load audio policy configuration file, setting defaults");
+            defaultAudioPolicyConfig();
+        }
+    }
+
+    // must be done after reading the policy
+    initializeVolumeCurves();
+
+    // open all output streams needed to access attached devices
+    for (size_t i = 0; i < mHwModules.size(); i++) {
+        mHwModules[i]->mHandle = mpClientInterface->loadHwModule(mHwModules[i]->mName);
+        if (mHwModules[i]->mHandle == 0) {
+            ALOGW("could not open HW module %s", mHwModules[i]->mName);
+            continue;
+        }
+        // open all output streams needed to access attached devices
+        // except for direct output streams that are only opened when they are actually
+        // required by an app.
+        for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++)
+        {
+            const IOProfile *outProfile = mHwModules[i]->mOutputProfiles[j];
+
+            if ((outProfile->mSupportedDevices & mAttachedOutputDevices) &&
+                    ((outProfile->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) == 0)) {
+                AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor(outProfile);
+                outputDesc->mDevice = (audio_devices_t)(mDefaultOutputDevice &
+                                                            outProfile->mSupportedDevices);
+                audio_io_handle_t output = mpClientInterface->openOutput(
+                                                outProfile->mModule->mHandle,
+                                                &outputDesc->mDevice,
+                                                &outputDesc->mSamplingRate,
+                                                &outputDesc->mFormat,
+                                                &outputDesc->mChannelMask,
+                                                &outputDesc->mLatency,
+                                                outputDesc->mFlags);
+                if (output == 0) {
+                    delete outputDesc;
+                } else {
+                    mAvailableOutputDevices = (audio_devices_t)(mAvailableOutputDevices |
+                                            (outProfile->mSupportedDevices & mAttachedOutputDevices));
+                    if (mPrimaryOutput == 0 &&
+                            outProfile->mFlags & AUDIO_OUTPUT_FLAG_PRIMARY) {
+                        mPrimaryOutput = output;
+                    }
+                    addOutput(output, outputDesc);
+                    setOutputDevice(output,
+                                    (audio_devices_t)(mDefaultOutputDevice &
+                                                        outProfile->mSupportedDevices),
+                                    true);
+                }
+            }
+        }
+    }
+
+    ALOGE_IF((mAttachedOutputDevices & ~mAvailableOutputDevices),
+             "Not output found for attached devices %08x",
+             (mAttachedOutputDevices & ~mAvailableOutputDevices));
+
+    ALOGE_IF((mPrimaryOutput == 0), "Failed to open primary output");
+
+    updateDevicesAndOutputs();
+
+#ifdef AUDIO_POLICY_TEST
+    if (mPrimaryOutput != 0) {
+        AudioParameter outputCmd = AudioParameter();
+        outputCmd.addInt(String8("set_id"), 0);
+        mpClientInterface->setParameters(mPrimaryOutput, outputCmd.toString());
+
+        mTestDevice = AUDIO_DEVICE_OUT_SPEAKER;
+        mTestSamplingRate = 44100;
+        mTestFormat = AudioSystem::PCM_16_BIT;
+        mTestChannels =  AudioSystem::CHANNEL_OUT_STEREO;
+        mTestLatencyMs = 0;
+        mCurOutput = 0;
+        mDirectOutput = false;
+        for (int i = 0; i < NUM_TEST_OUTPUTS; i++) {
+            mTestOutputs[i] = 0;
+        }
+
+        const size_t SIZE = 256;
+        char buffer[SIZE];
+        snprintf(buffer, SIZE, "AudioPolicyManagerTest");
+        run(buffer, ANDROID_PRIORITY_AUDIO);
+    }
+#endif //AUDIO_POLICY_TEST
+}
+
+AudioPolicyManagerBase::~AudioPolicyManagerBase()
+{
+#ifdef AUDIO_POLICY_TEST
+    exit();
+#endif //AUDIO_POLICY_TEST
+   for (size_t i = 0; i < mOutputs.size(); i++) {
+        mpClientInterface->closeOutput(mOutputs.keyAt(i));
+        delete mOutputs.valueAt(i);
+   }
+   for (size_t i = 0; i < mInputs.size(); i++) {
+        mpClientInterface->closeInput(mInputs.keyAt(i));
+        delete mInputs.valueAt(i);
+   }
+   for (size_t i = 0; i < mHwModules.size(); i++) {
+        delete mHwModules[i];
+   }
+}
+
+status_t AudioPolicyManagerBase::initCheck()
+{
+    return (mPrimaryOutput == 0) ? NO_INIT : NO_ERROR;
+}
+
+#ifdef AUDIO_POLICY_TEST
+bool AudioPolicyManagerBase::threadLoop()
+{
+    ALOGV("entering threadLoop()");
+    while (!exitPending())
+    {
+        String8 command;
+        int valueInt;
+        String8 value;
+
+        Mutex::Autolock _l(mLock);
+        mWaitWorkCV.waitRelative(mLock, milliseconds(50));
+
+        command = mpClientInterface->getParameters(0, String8("test_cmd_policy"));
+        AudioParameter param = AudioParameter(command);
+
+        if (param.getInt(String8("test_cmd_policy"), valueInt) == NO_ERROR &&
+            valueInt != 0) {
+            ALOGV("Test command %s received", command.string());
+            String8 target;
+            if (param.get(String8("target"), target) != NO_ERROR) {
+                target = "Manager";
+            }
+            if (param.getInt(String8("test_cmd_policy_output"), valueInt) == NO_ERROR) {
+                param.remove(String8("test_cmd_policy_output"));
+                mCurOutput = valueInt;
+            }
+            if (param.get(String8("test_cmd_policy_direct"), value) == NO_ERROR) {
+                param.remove(String8("test_cmd_policy_direct"));
+                if (value == "false") {
+                    mDirectOutput = false;
+                } else if (value == "true") {
+                    mDirectOutput = true;
+                }
+            }
+            if (param.getInt(String8("test_cmd_policy_input"), valueInt) == NO_ERROR) {
+                param.remove(String8("test_cmd_policy_input"));
+                mTestInput = valueInt;
+            }
+
+            if (param.get(String8("test_cmd_policy_format"), value) == NO_ERROR) {
+                param.remove(String8("test_cmd_policy_format"));
+                int format = AudioSystem::INVALID_FORMAT;
+                if (value == "PCM 16 bits") {
+                    format = AudioSystem::PCM_16_BIT;
+                } else if (value == "PCM 8 bits") {
+                    format = AudioSystem::PCM_8_BIT;
+                } else if (value == "Compressed MP3") {
+                    format = AudioSystem::MP3;
+                }
+                if (format != AudioSystem::INVALID_FORMAT) {
+                    if (target == "Manager") {
+                        mTestFormat = format;
+                    } else if (mTestOutputs[mCurOutput] != 0) {
+                        AudioParameter outputParam = AudioParameter();
+                        outputParam.addInt(String8("format"), format);
+                        mpClientInterface->setParameters(mTestOutputs[mCurOutput], outputParam.toString());
+                    }
+                }
+            }
+            if (param.get(String8("test_cmd_policy_channels"), value) == NO_ERROR) {
+                param.remove(String8("test_cmd_policy_channels"));
+                int channels = 0;
+
+                if (value == "Channels Stereo") {
+                    channels =  AudioSystem::CHANNEL_OUT_STEREO;
+                } else if (value == "Channels Mono") {
+                    channels =  AudioSystem::CHANNEL_OUT_MONO;
+                }
+                if (channels != 0) {
+                    if (target == "Manager") {
+                        mTestChannels = channels;
+                    } else if (mTestOutputs[mCurOutput] != 0) {
+                        AudioParameter outputParam = AudioParameter();
+                        outputParam.addInt(String8("channels"), channels);
+                        mpClientInterface->setParameters(mTestOutputs[mCurOutput], outputParam.toString());
+                    }
+                }
+            }
+            if (param.getInt(String8("test_cmd_policy_sampleRate"), valueInt) == NO_ERROR) {
+                param.remove(String8("test_cmd_policy_sampleRate"));
+                if (valueInt >= 0 && valueInt <= 96000) {
+                    int samplingRate = valueInt;
+                    if (target == "Manager") {
+                        mTestSamplingRate = samplingRate;
+                    } else if (mTestOutputs[mCurOutput] != 0) {
+                        AudioParameter outputParam = AudioParameter();
+                        outputParam.addInt(String8("sampling_rate"), samplingRate);
+                        mpClientInterface->setParameters(mTestOutputs[mCurOutput], outputParam.toString());
+                    }
+                }
+            }
+
+            if (param.get(String8("test_cmd_policy_reopen"), value) == NO_ERROR) {
+                param.remove(String8("test_cmd_policy_reopen"));
+
+                AudioOutputDescriptor *outputDesc = mOutputs.valueFor(mPrimaryOutput);
+                mpClientInterface->closeOutput(mPrimaryOutput);
+
+                audio_module_handle_t moduleHandle = outputDesc->mModule->mHandle;
+
+                delete mOutputs.valueFor(mPrimaryOutput);
+                mOutputs.removeItem(mPrimaryOutput);
+
+                AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor(NULL);
+                outputDesc->mDevice = AUDIO_DEVICE_OUT_SPEAKER;
+                mPrimaryOutput = mpClientInterface->openOutput(moduleHandle,
+                                                &outputDesc->mDevice,
+                                                &outputDesc->mSamplingRate,
+                                                &outputDesc->mFormat,
+                                                &outputDesc->mChannelMask,
+                                                &outputDesc->mLatency,
+                                                outputDesc->mFlags);
+                if (mPrimaryOutput == 0) {
+                    ALOGE("Failed to reopen hardware output stream, samplingRate: %d, format %d, channels %d",
+                            outputDesc->mSamplingRate, outputDesc->mFormat, outputDesc->mChannelMask);
+                } else {
+                    AudioParameter outputCmd = AudioParameter();
+                    outputCmd.addInt(String8("set_id"), 0);
+                    mpClientInterface->setParameters(mPrimaryOutput, outputCmd.toString());
+                    addOutput(mPrimaryOutput, outputDesc);
+                }
+            }
+
+
+            mpClientInterface->setParameters(0, String8("test_cmd_policy="));
+        }
+    }
+    return false;
+}
+
+void AudioPolicyManagerBase::exit()
+{
+    {
+        AutoMutex _l(mLock);
+        requestExit();
+        mWaitWorkCV.signal();
+    }
+    requestExitAndWait();
+}
+
+int AudioPolicyManagerBase::testOutputIndex(audio_io_handle_t output)
+{
+    for (int i = 0; i < NUM_TEST_OUTPUTS; i++) {
+        if (output == mTestOutputs[i]) return i;
+    }
+    return 0;
+}
+#endif //AUDIO_POLICY_TEST
+
+// ---
+
+void AudioPolicyManagerBase::addOutput(audio_io_handle_t id, AudioOutputDescriptor *outputDesc)
+{
+    outputDesc->mId = id;
+    mOutputs.add(id, outputDesc);
+}
+
+void AudioPolicyManagerBase::addInput(audio_io_handle_t id, AudioInputDescriptor *inputDesc)
+{
+    inputDesc->mId = id;
+    mInputs.add(id, inputDesc);
+}
+
+status_t AudioPolicyManagerBase::checkOutputsForDevice(audio_devices_t device,
+                                                       AudioSystem::device_connection_state state,
+                                                       SortedVector<audio_io_handle_t>& outputs,
+                                                       const String8 paramStr)
+{
+    AudioOutputDescriptor *desc;
+
+    if (state == AudioSystem::DEVICE_STATE_AVAILABLE) {
+        // first list already open outputs that can be routed to this device
+        for (size_t i = 0; i < mOutputs.size(); i++) {
+            desc = mOutputs.valueAt(i);
+            if (!desc->isDuplicated() && (desc->mProfile->mSupportedDevices & device)) {
+                ALOGV("checkOutputsForDevice(): adding opened output %d", mOutputs.keyAt(i));
+                outputs.add(mOutputs.keyAt(i));
+            }
+        }
+        // then look for output profiles that can be routed to this device
+        SortedVector<IOProfile *> profiles;
+        for (size_t i = 0; i < mHwModules.size(); i++)
+        {
+            if (mHwModules[i]->mHandle == 0) {
+                continue;
+            }
+            for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++)
+            {
+                if (mHwModules[i]->mOutputProfiles[j]->mSupportedDevices & device) {
+                    ALOGV("checkOutputsForDevice(): adding profile %zu from module %zu", j, i);
+                    profiles.add(mHwModules[i]->mOutputProfiles[j]);
+                }
+            }
+        }
+
+        if (profiles.isEmpty() && outputs.isEmpty()) {
+            ALOGW("checkOutputsForDevice(): No output available for device %04x", device);
+            return BAD_VALUE;
+        }
+
+        // open outputs for matching profiles if needed. Direct outputs are also opened to
+        // query for dynamic parameters and will be closed later by setDeviceConnectionState()
+        for (ssize_t profile_index = 0; profile_index < (ssize_t)profiles.size(); profile_index++) {
+            IOProfile *profile = profiles[profile_index];
+
+            // nothing to do if one output is already opened for this profile
+            size_t j;
+            for (j = 0; j < mOutputs.size(); j++) {
+                desc = mOutputs.valueAt(j);
+                if (!desc->isDuplicated() && desc->mProfile == profile) {
+                    break;
+                }
+            }
+            if (j != mOutputs.size()) {
+                continue;
+            }
+
+            ALOGV("opening output for device %08x with params %s", device, paramStr.string());
+            desc = new AudioOutputDescriptor(profile);
+            desc->mDevice = device;
+            audio_offload_info_t offloadInfo = AUDIO_INFO_INITIALIZER;
+            offloadInfo.sample_rate = desc->mSamplingRate;
+            offloadInfo.format = desc->mFormat;
+            offloadInfo.channel_mask = desc->mChannelMask;
+
+            audio_io_handle_t output = mpClientInterface->openOutput(profile->mModule->mHandle,
+                                                                       &desc->mDevice,
+                                                                       &desc->mSamplingRate,
+                                                                       &desc->mFormat,
+                                                                       &desc->mChannelMask,
+                                                                       &desc->mLatency,
+                                                                       desc->mFlags,
+                                                                       &offloadInfo);
+            if (output != 0) {
+                if (!paramStr.isEmpty()) {
+                    // Here is where the out_set_parameters() for card & device gets called
+                    mpClientInterface->setParameters(output, paramStr);
+                }
+
+                // Here is where we step through and resolve any "dynamic" fields
+                String8 reply;
+                char *value;
+                if (profile->mSamplingRates[0] == 0) {
+                    reply = mpClientInterface->getParameters(output,
+                                            String8(AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES));
+                    ALOGV("checkOutputsForDevice() direct output sup sampling rates %s",
+                              reply.string());
+                    value = strpbrk((char *)reply.string(), "=");
+                    if (value != NULL) {
+                        loadSamplingRates(value + 1, profile);
+                    }
+                }
+                if (profile->mFormats[0] == AUDIO_FORMAT_DEFAULT) {
+                    reply = mpClientInterface->getParameters(output,
+                                                   String8(AUDIO_PARAMETER_STREAM_SUP_FORMATS));
+                    ALOGV("checkOutputsForDevice() direct output sup formats %s",
+                              reply.string());
+                    value = strpbrk((char *)reply.string(), "=");
+                    if (value != NULL) {
+                        loadFormats(value + 1, profile);
+                    }
+                }
+                if (profile->mChannelMasks[0] == 0) {
+                    reply = mpClientInterface->getParameters(output,
+                                                  String8(AUDIO_PARAMETER_STREAM_SUP_CHANNELS));
+                    ALOGV("checkOutputsForDevice() direct output sup channel masks %s",
+                              reply.string());
+                    value = strpbrk((char *)reply.string(), "=");
+                    if (value != NULL) {
+                        loadOutChannels(value + 1, profile);
+                    }
+                }
+                if (((profile->mSamplingRates[0] == 0) &&
+                         (profile->mSamplingRates.size() < 2)) ||
+                     ((profile->mFormats[0] == 0) &&
+                         (profile->mFormats.size() < 2)) ||
+                     ((profile->mChannelMasks[0] == 0) &&
+                         (profile->mChannelMasks.size() < 2))) {
+                    ALOGW("checkOutputsForDevice() direct output missing param");
+                    mpClientInterface->closeOutput(output);
+                    output = 0;
+                } else if (profile->mSamplingRates[0] == 0) {
+                    mpClientInterface->closeOutput(output);
+                    desc->mSamplingRate = profile->mSamplingRates[1];
+                    offloadInfo.sample_rate = desc->mSamplingRate;
+                    output = mpClientInterface->openOutput(
+                                                    profile->mModule->mHandle,
+                                                    &desc->mDevice,
+                                                    &desc->mSamplingRate,
+                                                    &desc->mFormat,
+                                                    &desc->mChannelMask,
+                                                    &desc->mLatency,
+                                                    desc->mFlags,
+                                                    &offloadInfo);
+                }
+
+                if (output != 0) {
+                    addOutput(output, desc);
+                    if ((desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) == 0) {
+                        audio_io_handle_t duplicatedOutput = 0;
+
+                        // set initial stream volume for device
+                        applyStreamVolumes(output, device, 0, true);
+
+                        //TODO: configure audio effect output stage here
+
+                        // open a duplicating output thread for the new output and the primary output
+                        duplicatedOutput = mpClientInterface->openDuplicateOutput(output,
+                                                                                  mPrimaryOutput);
+                        if (duplicatedOutput != 0) {
+                            // add duplicated output descriptor
+                            AudioOutputDescriptor *dupOutputDesc = new AudioOutputDescriptor(NULL);
+                            dupOutputDesc->mOutput1 = mOutputs.valueFor(mPrimaryOutput);
+                            dupOutputDesc->mOutput2 = mOutputs.valueFor(output);
+                            dupOutputDesc->mSamplingRate = desc->mSamplingRate;
+                            dupOutputDesc->mFormat = desc->mFormat;
+                            dupOutputDesc->mChannelMask = desc->mChannelMask;
+                            dupOutputDesc->mLatency = desc->mLatency;
+                            addOutput(duplicatedOutput, dupOutputDesc);
+                            applyStreamVolumes(duplicatedOutput, device, 0, true);
+                        } else {
+                            ALOGW("checkOutputsForDevice() could not open dup output for %d and %d",
+                                    mPrimaryOutput, output);
+                            mpClientInterface->closeOutput(output);
+                            mOutputs.removeItem(output);
+                            output = 0;
+                        }
+                    }
+                }
+            }
+            if (output == 0) {
+                ALOGW("checkOutputsForDevice() could not open output for device %x", device);
+                delete desc;
+                profiles.removeAt(profile_index);
+                profile_index--;
+            } else {
+                outputs.add(output);
+                ALOGV("checkOutputsForDevice(): adding output %d", output);
+            }
+        }
+
+        if (profiles.isEmpty()) {
+            ALOGW("checkOutputsForDevice(): No output available for device %04x", device);
+            return BAD_VALUE;
+        }
+    } else { // Disconnect
+        // check if one opened output is not needed any more after disconnecting one device
+        for (size_t i = 0; i < mOutputs.size(); i++) {
+            desc = mOutputs.valueAt(i);
+            if (!desc->isDuplicated() &&
+                    !(desc->mProfile->mSupportedDevices & mAvailableOutputDevices)) {
+                ALOGV("checkOutputsForDevice(): disconnecting adding output %d", mOutputs.keyAt(i));
+                outputs.add(mOutputs.keyAt(i));
+            }
+        }
+        // Clear any profiles associated with the disconnected device.
+        for (size_t i = 0; i < mHwModules.size(); i++)
+        {
+            if (mHwModules[i]->mHandle == 0) {
+                continue;
+            }
+            for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++)
+            {
+                IOProfile *profile = mHwModules[i]->mOutputProfiles[j];
+                if (profile->mSupportedDevices & device) {
+                    ALOGV("checkOutputsForDevice(): clearing direct output profile %zu on module %zu",
+                          j, i);
+                    if (profile->mSamplingRates[0] == 0) {
+                        profile->mSamplingRates.clear();
+                        profile->mSamplingRates.add(0);
+                    }
+                    if (profile->mFormats[0] == AUDIO_FORMAT_DEFAULT) {
+                        profile->mFormats.clear();
+                        profile->mFormats.add(AUDIO_FORMAT_DEFAULT);
+                    }
+                    if (profile->mChannelMasks[0] == 0) {
+                        profile->mChannelMasks.clear();
+                        profile->mChannelMasks.add(0);
+                    }
+                }
+            }
+        }
+    }
+    return NO_ERROR;
+}
+
+status_t AudioPolicyManagerBase::checkInputsForDevice(audio_devices_t device,
+                                                      AudioSystem::device_connection_state state,
+                                                      SortedVector<audio_io_handle_t>& inputs,
+                                                      const String8 paramStr)
+{
+    AudioInputDescriptor *desc;
+    if (state == AudioSystem::DEVICE_STATE_AVAILABLE) {
+        // first list already open inputs that can be routed to this device
+        for (size_t input_index = 0; input_index < mInputs.size(); input_index++) {
+            desc = mInputs.valueAt(input_index);
+            if (desc->mProfile->mSupportedDevices & (device & ~AUDIO_DEVICE_BIT_IN)) {
+                ALOGV("checkInputsForDevice(): adding opened input %d", mInputs.keyAt(input_index));
+               inputs.add(mInputs.keyAt(input_index));
+            }
+        }
+
+        // then look for input profiles that can be routed to this device
+        SortedVector<IOProfile *> profiles;
+        for (size_t module_index = 0; module_index < mHwModules.size(); module_index++)
+        {
+            if (mHwModules[module_index]->mHandle == 0) {
+                continue;
+            }
+            for (size_t profile_index = 0;
+                 profile_index < mHwModules[module_index]->mInputProfiles.size();
+                 profile_index++)
+            {
+                if (mHwModules[module_index]->mInputProfiles[profile_index]->mSupportedDevices
+                        & (device & ~AUDIO_DEVICE_BIT_IN)) {
+                    ALOGV("checkInputsForDevice(): adding profile %zu from module %zu",
+                          profile_index, module_index);
+                    profiles.add(mHwModules[module_index]->mInputProfiles[profile_index]);
+                }
+            }
+        }
+
+        if (profiles.isEmpty() && inputs.isEmpty()) {
+            ALOGW("checkInputsForDevice(): No input available for device 0x%X", device);
+            return BAD_VALUE;
+        }
+
+        // open inputs for matching profiles if needed. Direct inputs are also opened to
+        // query for dynamic parameters and will be closed later by setDeviceConnectionState()
+        for (ssize_t profile_index = 0; profile_index < (ssize_t)profiles.size(); profile_index++) {
+
+            IOProfile *profile = profiles[profile_index];
+            // nothing to do if one input is already opened for this profile
+            size_t input_index;
+            for (input_index = 0; input_index < mInputs.size(); input_index++) {
+                desc = mInputs.valueAt(input_index);
+                if (desc->mProfile == profile) {
+                    break;
+                }
+            }
+            if (input_index != mInputs.size()) {
+                continue;
+            }
+
+            ALOGV("opening input for device 0x%X with params %s", device, paramStr.string());
+            desc = new AudioInputDescriptor(profile);
+            desc->mDevice = device;
+
+            audio_io_handle_t input = mpClientInterface->openInput(profile->mModule->mHandle,
+                                            &desc->mDevice,
+                                            &desc->mSamplingRate,
+                                            &desc->mFormat,
+                                            &desc->mChannelMask);
+
+            if (input != 0) {
+                if (!paramStr.isEmpty()) {
+                    mpClientInterface->setParameters(input, paramStr);
+                }
+
+                // Here is where we step through and resolve any "dynamic" fields
+                String8 reply;
+                char *value;
+                if (profile->mSamplingRates[0] == 0) {
+                    reply = mpClientInterface->getParameters(input,
+                                            String8(AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES));
+                    ALOGV("checkInputsForDevice() direct input sup sampling rates %s",
+                              reply.string());
+                    value = strpbrk((char *)reply.string(), "=");
+                    if (value != NULL) {
+                        loadSamplingRates(value + 1, profile);
+                    }
+                }
+                if (profile->mFormats[0] == AUDIO_FORMAT_DEFAULT) {
+                    reply = mpClientInterface->getParameters(input,
+                                                   String8(AUDIO_PARAMETER_STREAM_SUP_FORMATS));
+                    ALOGV("checkInputsForDevice() direct input sup formats %s", reply.string());
+                    value = strpbrk((char *)reply.string(), "=");
+                    if (value != NULL) {
+                        loadFormats(value + 1, profile);
+                    }
+                }
+                if (profile->mChannelMasks[0] == 0) {
+                    reply = mpClientInterface->getParameters(input,
+                                                  String8(AUDIO_PARAMETER_STREAM_SUP_CHANNELS));
+                    ALOGV("checkInputsForDevice() direct input sup channel masks %s",
+                              reply.string());
+                    value = strpbrk((char *)reply.string(), "=");
+                    if (value != NULL) {
+                        loadInChannels(value + 1, profile);
+                    }
+                }
+                if (((profile->mSamplingRates[0] == 0) && (profile->mSamplingRates.size() < 2)) ||
+                     ((profile->mFormats[0] == 0) && (profile->mFormats.size() < 2)) ||
+                     ((profile->mChannelMasks[0] == 0) && (profile->mChannelMasks.size() < 2))) {
+                    ALOGW("checkInputsForDevice() direct input missing param");
+                    mpClientInterface->closeInput(input);
+                    input = 0;
+                }
+
+                if (input != 0) {
+                    addInput(input, desc);
+                }
+            } // endif input != 0
+
+            if (input == 0) {
+                ALOGW("checkInputsForDevice() could not open input for device 0x%X", device);
+                delete desc;
+                profiles.removeAt(profile_index);
+                profile_index--;
+            } else {
+                inputs.add(input);
+                ALOGV("checkInputsForDevice(): adding input %d", input);
+            }
+        } // end scan profiles
+
+        if (profiles.isEmpty()) {
+            ALOGW("checkInputsForDevice(): No input available for device 0x%X", device);
+            return BAD_VALUE;
+        }
+    } else {
+        // Disconnect
+        // check if one opened input is not needed any more after disconnecting one device
+        for (size_t input_index = 0; input_index < mInputs.size(); input_index++) {
+            desc = mInputs.valueAt(input_index);
+            if (!(desc->mProfile->mSupportedDevices & mAvailableInputDevices)) {
+                ALOGV("checkInputsForDevice(): disconnecting adding input %d",
+                      mInputs.keyAt(input_index));
+                inputs.add(mInputs.keyAt(input_index));
+            }
+        }
+        // Clear any profiles associated with the disconnected device.
+        for (size_t module_index = 0; module_index < mHwModules.size(); module_index++)
+        {
+            if (mHwModules[module_index]->mHandle == 0) {
+                continue;
+            }
+            for (size_t profile_index = 0;
+                 profile_index < mHwModules[module_index]->mInputProfiles.size();
+                 profile_index++)
+            {
+                IOProfile *profile = mHwModules[module_index]->mInputProfiles[profile_index];
+                if (profile->mSupportedDevices & device) {
+                    ALOGV("checkInputsForDevice(): clearing direct input profile %zu on module %zu",
+                          profile_index, module_index);
+                    if (profile->mSamplingRates[0] == 0) {
+                        profile->mSamplingRates.clear();
+                        profile->mSamplingRates.add(0);
+                    }
+                    if (profile->mFormats[0] == AUDIO_FORMAT_DEFAULT) {
+                        profile->mFormats.clear();
+                        profile->mFormats.add(AUDIO_FORMAT_DEFAULT);
+                    }
+                    if (profile->mChannelMasks[0] == 0) {
+                        profile->mChannelMasks.clear();
+                        profile->mChannelMasks.add(0);
+                    }
+                }
+            }
+        }
+    } // end disconnect
+
+    return NO_ERROR;
+}
+
+void AudioPolicyManagerBase::closeOutput(audio_io_handle_t output)
+{
+    ALOGV("closeOutput(%d)", output);
+
+    AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output);
+    if (outputDesc == NULL) {
+        ALOGW("closeOutput() unknown output %d", output);
+        return;
+    }
+
+    // look for duplicated outputs connected to the output being removed.
+    for (size_t i = 0; i < mOutputs.size(); i++) {
+        AudioOutputDescriptor *dupOutputDesc = mOutputs.valueAt(i);
+        if (dupOutputDesc->isDuplicated() &&
+                (dupOutputDesc->mOutput1 == outputDesc ||
+                dupOutputDesc->mOutput2 == outputDesc)) {
+            AudioOutputDescriptor *outputDesc2;
+            if (dupOutputDesc->mOutput1 == outputDesc) {
+                outputDesc2 = dupOutputDesc->mOutput2;
+            } else {
+                outputDesc2 = dupOutputDesc->mOutput1;
+            }
+            // As all active tracks on duplicated output will be deleted,
+            // and as they were also referenced on the other output, the reference
+            // count for their stream type must be adjusted accordingly on
+            // the other output.
+            for (int j = 0; j < (int)AudioSystem::NUM_STREAM_TYPES; j++) {
+                int refCount = dupOutputDesc->mRefCount[j];
+                outputDesc2->changeRefCount((AudioSystem::stream_type)j,-refCount);
+            }
+            audio_io_handle_t duplicatedOutput = mOutputs.keyAt(i);
+            ALOGV("closeOutput() closing also duplicated output %d", duplicatedOutput);
+
+            mpClientInterface->closeOutput(duplicatedOutput);
+            delete mOutputs.valueFor(duplicatedOutput);
+            mOutputs.removeItem(duplicatedOutput);
+        }
+    }
+
+    AudioParameter param;
+    param.add(String8("closing"), String8("true"));
+    mpClientInterface->setParameters(output, param.toString());
+
+    mpClientInterface->closeOutput(output);
+    delete outputDesc;
+    mOutputs.removeItem(output);
+    mPreviousOutputs = mOutputs;
+}
+
+SortedVector<audio_io_handle_t> AudioPolicyManagerBase::getOutputsForDevice(audio_devices_t device,
+                        DefaultKeyedVector<audio_io_handle_t, AudioOutputDescriptor *> openOutputs)
+{
+    SortedVector<audio_io_handle_t> outputs;
+
+    ALOGVV("getOutputsForDevice() device %04x", device);
+    for (size_t i = 0; i < openOutputs.size(); i++) {
+        ALOGVV("output %d isDuplicated=%d device=%04x",
+                i, openOutputs.valueAt(i)->isDuplicated(), openOutputs.valueAt(i)->supportedDevices());
+        if ((device & openOutputs.valueAt(i)->supportedDevices()) == device) {
+            ALOGVV("getOutputsForDevice() found output %d", openOutputs.keyAt(i));
+            outputs.add(openOutputs.keyAt(i));
+        }
+    }
+    return outputs;
+}
+
+bool AudioPolicyManagerBase::vectorsEqual(SortedVector<audio_io_handle_t>& outputs1,
+                                   SortedVector<audio_io_handle_t>& outputs2)
+{
+    if (outputs1.size() != outputs2.size()) {
+        return false;
+    }
+    for (size_t i = 0; i < outputs1.size(); i++) {
+        if (outputs1[i] != outputs2[i]) {
+            return false;
+        }
+    }
+    return true;
+}
+
+void AudioPolicyManagerBase::checkOutputForStrategy(routing_strategy strategy)
+{
+    audio_devices_t oldDevice = getDeviceForStrategy(strategy, true /*fromCache*/);
+    audio_devices_t newDevice = getDeviceForStrategy(strategy, false /*fromCache*/);
+    SortedVector<audio_io_handle_t> srcOutputs = getOutputsForDevice(oldDevice, mPreviousOutputs);
+    SortedVector<audio_io_handle_t> dstOutputs = getOutputsForDevice(newDevice, mOutputs);
+
+    if (!vectorsEqual(srcOutputs,dstOutputs)) {
+        ALOGV("checkOutputForStrategy() strategy %d, moving from output %d to output %d",
+              strategy, srcOutputs[0], dstOutputs[0]);
+        // mute strategy while moving tracks from one output to another
+        for (size_t i = 0; i < srcOutputs.size(); i++) {
+            AudioOutputDescriptor *desc = mOutputs.valueFor(srcOutputs[i]);
+            if (desc->isStrategyActive(strategy)) {
+                setStrategyMute(strategy, true, srcOutputs[i]);
+                setStrategyMute(strategy, false, srcOutputs[i], MUTE_TIME_MS, newDevice);
+            }
+        }
+
+        // Move effects associated to this strategy from previous output to new output
+        if (strategy == STRATEGY_MEDIA) {
+            audio_io_handle_t fxOutput = selectOutputForEffects(dstOutputs);
+            SortedVector<audio_io_handle_t> moved;
+            for (size_t i = 0; i < mEffects.size(); i++) {
+                EffectDescriptor *desc = mEffects.valueAt(i);
+                if (desc->mSession == AUDIO_SESSION_OUTPUT_MIX &&
+                        desc->mIo != fxOutput) {
+                    if (moved.indexOf(desc->mIo) < 0) {
+                        ALOGV("checkOutputForStrategy() moving effect %d to output %d",
+                              mEffects.keyAt(i), fxOutput);
+                        mpClientInterface->moveEffects(AUDIO_SESSION_OUTPUT_MIX, desc->mIo,
+                                                       fxOutput);
+                        moved.add(desc->mIo);
+                    }
+                    desc->mIo = fxOutput;
+                }
+            }
+        }
+        // Move tracks associated to this strategy from previous output to new output
+        for (int i = 0; i < (int)AudioSystem::NUM_STREAM_TYPES; i++) {
+            if (getStrategy((AudioSystem::stream_type)i) == strategy) {
+                mpClientInterface->invalidateStream((AudioSystem::stream_type)i);
+            }
+        }
+    }
+}
+
+void AudioPolicyManagerBase::checkOutputForAllStrategies()
+{
+    checkOutputForStrategy(STRATEGY_ENFORCED_AUDIBLE);
+    checkOutputForStrategy(STRATEGY_PHONE);
+    checkOutputForStrategy(STRATEGY_SONIFICATION);
+    checkOutputForStrategy(STRATEGY_SONIFICATION_RESPECTFUL);
+    checkOutputForStrategy(STRATEGY_MEDIA);
+    checkOutputForStrategy(STRATEGY_DTMF);
+}
+
+audio_io_handle_t AudioPolicyManagerBase::getA2dpOutput()
+{
+    if (!mHasA2dp) {
+        return 0;
+    }
+
+    for (size_t i = 0; i < mOutputs.size(); i++) {
+        AudioOutputDescriptor *outputDesc = mOutputs.valueAt(i);
+        if (!outputDesc->isDuplicated() && outputDesc->device() & AUDIO_DEVICE_OUT_ALL_A2DP) {
+            return mOutputs.keyAt(i);
+        }
+    }
+
+    return 0;
+}
+
+void AudioPolicyManagerBase::checkA2dpSuspend()
+{
+    if (!mHasA2dp) {
+        return;
+    }
+    audio_io_handle_t a2dpOutput = getA2dpOutput();
+    if (a2dpOutput == 0) {
+        return;
+    }
+
+    // suspend A2DP output if:
+    //      (NOT already suspended) &&
+    //      ((SCO device is connected &&
+    //       (forced usage for communication || for record is SCO))) ||
+    //      (phone state is ringing || in call)
+    //
+    // restore A2DP output if:
+    //      (Already suspended) &&
+    //      ((SCO device is NOT connected ||
+    //       (forced usage NOT for communication && NOT for record is SCO))) &&
+    //      (phone state is NOT ringing && NOT in call)
+    //
+    if (mA2dpSuspended) {
+        if (((mScoDeviceAddress == "") ||
+             ((mForceUse[AudioSystem::FOR_COMMUNICATION] != AudioSystem::FORCE_BT_SCO) &&
+              (mForceUse[AudioSystem::FOR_RECORD] != AudioSystem::FORCE_BT_SCO))) &&
+             ((mPhoneState != AudioSystem::MODE_IN_CALL) &&
+              (mPhoneState != AudioSystem::MODE_RINGTONE))) {
+
+            mpClientInterface->restoreOutput(a2dpOutput);
+            mA2dpSuspended = false;
+        }
+    } else {
+        if (((mScoDeviceAddress != "") &&
+             ((mForceUse[AudioSystem::FOR_COMMUNICATION] == AudioSystem::FORCE_BT_SCO) ||
+              (mForceUse[AudioSystem::FOR_RECORD] == AudioSystem::FORCE_BT_SCO))) ||
+             ((mPhoneState == AudioSystem::MODE_IN_CALL) ||
+              (mPhoneState == AudioSystem::MODE_RINGTONE))) {
+
+            mpClientInterface->suspendOutput(a2dpOutput);
+            mA2dpSuspended = true;
+        }
+    }
+}
+
+audio_devices_t AudioPolicyManagerBase::getNewDevice(audio_io_handle_t output, bool fromCache)
+{
+    audio_devices_t device = AUDIO_DEVICE_NONE;
+
+    AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output);
+    // check the following by order of priority to request a routing change if necessary:
+    // 1: the strategy enforced audible is active on the output:
+    //      use device for strategy enforced audible
+    // 2: we are in call or the strategy phone is active on the output:
+    //      use device for strategy phone
+    // 3: the strategy sonification is active on the output:
+    //      use device for strategy sonification
+    // 4: the strategy "respectful" sonification is active on the output:
+    //      use device for strategy "respectful" sonification
+    // 5: the strategy media is active on the output:
+    //      use device for strategy media
+    // 6: the strategy DTMF is active on the output:
+    //      use device for strategy DTMF
+    if (outputDesc->isStrategyActive(STRATEGY_ENFORCED_AUDIBLE)) {
+        device = getDeviceForStrategy(STRATEGY_ENFORCED_AUDIBLE, fromCache);
+    } else if (isInCall() ||
+                    outputDesc->isStrategyActive(STRATEGY_PHONE)) {
+        device = getDeviceForStrategy(STRATEGY_PHONE, fromCache);
+    } else if (outputDesc->isStrategyActive(STRATEGY_SONIFICATION)) {
+        device = getDeviceForStrategy(STRATEGY_SONIFICATION, fromCache);
+    } else if (outputDesc->isStrategyActive(STRATEGY_SONIFICATION_RESPECTFUL)) {
+        device = getDeviceForStrategy(STRATEGY_SONIFICATION_RESPECTFUL, fromCache);
+    } else if (outputDesc->isStrategyActive(STRATEGY_MEDIA)) {
+        device = getDeviceForStrategy(STRATEGY_MEDIA, fromCache);
+    } else if (outputDesc->isStrategyActive(STRATEGY_DTMF)) {
+        device = getDeviceForStrategy(STRATEGY_DTMF, fromCache);
+    }
+
+    ALOGV("getNewDevice() selected device %x", device);
+    return device;
+}
+
+uint32_t AudioPolicyManagerBase::getStrategyForStream(AudioSystem::stream_type stream) {
+    return (uint32_t)getStrategy(stream);
+}
+
+audio_devices_t AudioPolicyManagerBase::getDevicesForStream(AudioSystem::stream_type stream) {
+    audio_devices_t devices;
+    // By checking the range of stream before calling getStrategy, we avoid
+    // getStrategy's behavior for invalid streams.  getStrategy would do a ALOGE
+    // and then return STRATEGY_MEDIA, but we want to return the empty set.
+    if (stream < (AudioSystem::stream_type) 0 || stream >= AudioSystem::NUM_STREAM_TYPES) {
+        devices = AUDIO_DEVICE_NONE;
+    } else {
+        AudioPolicyManagerBase::routing_strategy strategy = getStrategy(stream);
+        devices = getDeviceForStrategy(strategy, true /*fromCache*/);
+    }
+    return devices;
+}
+
+AudioPolicyManagerBase::routing_strategy AudioPolicyManagerBase::getStrategy(
+        AudioSystem::stream_type stream) {
+    // stream to strategy mapping
+    switch (stream) {
+    case AudioSystem::VOICE_CALL:
+    case AudioSystem::BLUETOOTH_SCO:
+        return STRATEGY_PHONE;
+    case AudioSystem::RING:
+    case AudioSystem::ALARM:
+        return STRATEGY_SONIFICATION;
+    case AudioSystem::NOTIFICATION:
+        return STRATEGY_SONIFICATION_RESPECTFUL;
+    case AudioSystem::DTMF:
+        return STRATEGY_DTMF;
+    default:
+        ALOGE("unknown stream type");
+    case AudioSystem::SYSTEM:
+        // NOTE: SYSTEM stream uses MEDIA strategy because muting music and switching outputs
+        // while key clicks are played produces a poor result
+    case AudioSystem::TTS:
+    case AudioSystem::MUSIC:
+        return STRATEGY_MEDIA;
+    case AudioSystem::ENFORCED_AUDIBLE:
+        return STRATEGY_ENFORCED_AUDIBLE;
+    }
+}
+
+void AudioPolicyManagerBase::handleNotificationRoutingForStream(AudioSystem::stream_type stream) {
+    switch(stream) {
+    case AudioSystem::MUSIC:
+        checkOutputForStrategy(STRATEGY_SONIFICATION_RESPECTFUL);
+        updateDevicesAndOutputs();
+        break;
+    default:
+        break;
+    }
+}
+
+audio_devices_t AudioPolicyManagerBase::getDeviceForStrategy(routing_strategy strategy,
+                                                             bool fromCache)
+{
+    uint32_t device = AUDIO_DEVICE_NONE;
+
+    if (fromCache) {
+        ALOGVV("getDeviceForStrategy() from cache strategy %d, device %x",
+              strategy, mDeviceForStrategy[strategy]);
+        return mDeviceForStrategy[strategy];
+    }
+
+    switch (strategy) {
+
+    case STRATEGY_SONIFICATION_RESPECTFUL:
+        if (isInCall()) {
+            device = getDeviceForStrategy(STRATEGY_SONIFICATION, false /*fromCache*/);
+        } else if (isStreamActiveRemotely(AudioSystem::MUSIC,
+                SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY)) {
+            // while media is playing on a remote device, use the the sonification behavior.
+            // Note that we test this usecase before testing if media is playing because
+            //   the isStreamActive() method only informs about the activity of a stream, not
+            //   if it's for local playback. Note also that we use the same delay between both tests
+            device = getDeviceForStrategy(STRATEGY_SONIFICATION, false /*fromCache*/);
+        } else if (isStreamActive(AudioSystem::MUSIC, SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY)) {
+            // while media is playing (or has recently played), use the same device
+            device = getDeviceForStrategy(STRATEGY_MEDIA, false /*fromCache*/);
+        } else {
+            // when media is not playing anymore, fall back on the sonification behavior
+            device = getDeviceForStrategy(STRATEGY_SONIFICATION, false /*fromCache*/);
+        }
+
+        break;
+
+    case STRATEGY_DTMF:
+        if (!isInCall()) {
+            // when off call, DTMF strategy follows the same rules as MEDIA strategy
+            device = getDeviceForStrategy(STRATEGY_MEDIA, false /*fromCache*/);
+            break;
+        }
+        // when in call, DTMF and PHONE strategies follow the same rules
+        // FALL THROUGH
+
+    case STRATEGY_PHONE:
+        // for phone strategy, we first consider the forced use and then the available devices by order
+        // of priority
+        switch (mForceUse[AudioSystem::FOR_COMMUNICATION]) {
+        case AudioSystem::FORCE_BT_SCO:
+            if (!isInCall() || strategy != STRATEGY_DTMF) {
+                device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
+                if (device) break;
+            }
+            device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
+            if (device) break;
+            device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_SCO;
+            if (device) break;
+            // if SCO device is requested but no SCO device is available, fall back to default case
+            // FALL THROUGH
+
+        default:    // FORCE_NONE
+            // when not in a phone call, phone strategy should route STREAM_VOICE_CALL to A2DP
+            if (mHasA2dp && !isInCall() &&
+                    (mForceUse[AudioSystem::FOR_MEDIA] != AudioSystem::FORCE_NO_BT_A2DP) &&
+                    (getA2dpOutput() != 0) && !mA2dpSuspended) {
+                device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP;
+                if (device) break;
+                device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES;
+                if (device) break;
+            }
+            device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE;
+            if (device) break;
+            device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_WIRED_HEADSET;
+            if (device) break;
+            if (mPhoneState != AudioSystem::MODE_IN_CALL) {
+                device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_ACCESSORY;
+                if (device) break;
+                device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_DEVICE;
+                if (device) break;
+                device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET;
+                if (device) break;
+                device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_AUX_DIGITAL;
+                if (device) break;
+                device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET;
+                if (device) break;
+            }
+            device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_EARPIECE;
+            if (device) break;
+            device = mDefaultOutputDevice;
+            if (device == AUDIO_DEVICE_NONE) {
+                ALOGE("getDeviceForStrategy() no device found for STRATEGY_PHONE");
+            }
+            break;
+
+        case AudioSystem::FORCE_SPEAKER:
+            // when not in a phone call, phone strategy should route STREAM_VOICE_CALL to
+            // A2DP speaker when forcing to speaker output
+            if (mHasA2dp && !isInCall() &&
+                    (mForceUse[AudioSystem::FOR_MEDIA] != AudioSystem::FORCE_NO_BT_A2DP) &&
+                    (getA2dpOutput() != 0) && !mA2dpSuspended) {
+                device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER;
+                if (device) break;
+            }
+            if (mPhoneState != AudioSystem::MODE_IN_CALL) {
+                device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_ACCESSORY;
+                if (device) break;
+                device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_DEVICE;
+                if (device) break;
+                device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET;
+                if (device) break;
+                device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_AUX_DIGITAL;
+                if (device) break;
+                device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET;
+                if (device) break;
+            }
+            device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_SPEAKER;
+            if (device) break;
+            device = mDefaultOutputDevice;
+            if (device == AUDIO_DEVICE_NONE) {
+                ALOGE("getDeviceForStrategy() no device found for STRATEGY_PHONE, FORCE_SPEAKER");
+            }
+            break;
+        }
+    break;
+
+    case STRATEGY_SONIFICATION:
+
+        // If incall, just select the STRATEGY_PHONE device: The rest of the behavior is handled by
+        // handleIncallSonification().
+        if (isInCall()) {
+            device = getDeviceForStrategy(STRATEGY_PHONE, false /*fromCache*/);
+            break;
+        }
+        // FALL THROUGH
+
+    case STRATEGY_ENFORCED_AUDIBLE:
+        // strategy STRATEGY_ENFORCED_AUDIBLE uses same routing policy as STRATEGY_SONIFICATION
+        // except:
+        //   - when in call where it doesn't default to STRATEGY_PHONE behavior
+        //   - in countries where not enforced in which case it follows STRATEGY_MEDIA
+
+        if ((strategy == STRATEGY_SONIFICATION) ||
+                (mForceUse[AudioSystem::FOR_SYSTEM] == AudioSystem::FORCE_SYSTEM_ENFORCED)) {
+            device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_SPEAKER;
+            if (device == AUDIO_DEVICE_NONE) {
+                ALOGE("getDeviceForStrategy() speaker device not found for STRATEGY_SONIFICATION");
+            }
+        }
+        // The second device used for sonification is the same as the device used by media strategy
+        // FALL THROUGH
+
+    case STRATEGY_MEDIA: {
+        uint32_t device2 = AUDIO_DEVICE_NONE;
+        if (strategy != STRATEGY_SONIFICATION) {
+            // no sonification on remote submix (e.g. WFD)
+            device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_REMOTE_SUBMIX;
+        }
+        if ((device2 == AUDIO_DEVICE_NONE) &&
+                mHasA2dp && (mForceUse[AudioSystem::FOR_MEDIA] != AudioSystem::FORCE_NO_BT_A2DP) &&
+                (getA2dpOutput() != 0) && !mA2dpSuspended) {
+            device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP;
+            if (device2 == AUDIO_DEVICE_NONE) {
+                device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES;
+            }
+            if (device2 == AUDIO_DEVICE_NONE) {
+                device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER;
+            }
+        }
+        if (device2 == AUDIO_DEVICE_NONE) {
+            device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE;
+        }
+        if (device2 == AUDIO_DEVICE_NONE) {
+            device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_WIRED_HEADSET;
+        }
+        if (device2 == AUDIO_DEVICE_NONE) {
+            device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_ACCESSORY;
+        }
+        if (device2 == AUDIO_DEVICE_NONE) {
+            device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_DEVICE;
+        }
+        if (device2 == AUDIO_DEVICE_NONE) {
+            device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET;
+        }
+        if ((device2 == AUDIO_DEVICE_NONE) && (strategy != STRATEGY_SONIFICATION)) {
+            // no sonification on aux digital (e.g. HDMI)
+            device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_AUX_DIGITAL;
+        }
+        if ((device2 == AUDIO_DEVICE_NONE) &&
+                (mForceUse[AudioSystem::FOR_DOCK] == AudioSystem::FORCE_ANALOG_DOCK)) {
+            device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET;
+        }
+        if (device2 == AUDIO_DEVICE_NONE) {
+            device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_SPEAKER;
+        }
+
+        // device is DEVICE_OUT_SPEAKER if we come from case STRATEGY_SONIFICATION or
+        // STRATEGY_ENFORCED_AUDIBLE, AUDIO_DEVICE_NONE otherwise
+        device |= device2;
+        if (device) break;
+        device = mDefaultOutputDevice;
+        if (device == AUDIO_DEVICE_NONE) {
+            ALOGE("getDeviceForStrategy() no device found for STRATEGY_MEDIA");
+        }
+        } break;
+
+    default:
+        ALOGW("getDeviceForStrategy() unknown strategy: %d", strategy);
+        break;
+    }
+
+    ALOGVV("getDeviceForStrategy() strategy %d, device %x", strategy, device);
+    return device;
+}
+
+void AudioPolicyManagerBase::updateDevicesAndOutputs()
+{
+    for (int i = 0; i < NUM_STRATEGIES; i++) {
+        mDeviceForStrategy[i] = getDeviceForStrategy((routing_strategy)i, false /*fromCache*/);
+    }
+    mPreviousOutputs = mOutputs;
+}
+
+uint32_t AudioPolicyManagerBase::checkDeviceMuteStrategies(AudioOutputDescriptor *outputDesc,
+                                                       audio_devices_t prevDevice,
+                                                       uint32_t delayMs)
+{
+    // mute/unmute strategies using an incompatible device combination
+    // if muting, wait for the audio in pcm buffer to be drained before proceeding
+    // if unmuting, unmute only after the specified delay
+    if (outputDesc->isDuplicated()) {
+        return 0;
+    }
+
+    uint32_t muteWaitMs = 0;
+    audio_devices_t device = outputDesc->device();
+    bool shouldMute = outputDesc->isActive() && (AudioSystem::popCount(device) >= 2);
+    // temporary mute output if device selection changes to avoid volume bursts due to
+    // different per device volumes
+    bool tempMute = outputDesc->isActive() && (device != prevDevice);
+
+    for (size_t i = 0; i < NUM_STRATEGIES; i++) {
+        audio_devices_t curDevice = getDeviceForStrategy((routing_strategy)i, false /*fromCache*/);
+        bool mute = shouldMute && (curDevice & device) && (curDevice != device);
+        bool doMute = false;
+
+        if (mute && !outputDesc->mStrategyMutedByDevice[i]) {
+            doMute = true;
+            outputDesc->mStrategyMutedByDevice[i] = true;
+        } else if (!mute && outputDesc->mStrategyMutedByDevice[i]){
+            doMute = true;
+            outputDesc->mStrategyMutedByDevice[i] = false;
+        }
+        if (doMute || tempMute) {
+            for (size_t j = 0; j < mOutputs.size(); j++) {
+                AudioOutputDescriptor *desc = mOutputs.valueAt(j);
+                // skip output if it does not share any device with current output
+                if ((desc->supportedDevices() & outputDesc->supportedDevices())
+                        == AUDIO_DEVICE_NONE) {
+                    continue;
+                }
+                audio_io_handle_t curOutput = mOutputs.keyAt(j);
+                ALOGVV("checkDeviceMuteStrategies() %s strategy %d (curDevice %04x) on output %d",
+                      mute ? "muting" : "unmuting", i, curDevice, curOutput);
+                setStrategyMute((routing_strategy)i, mute, curOutput, mute ? 0 : delayMs);
+                if (desc->isStrategyActive((routing_strategy)i)) {
+                    // do tempMute only for current output
+                    if (tempMute && (desc == outputDesc)) {
+                        setStrategyMute((routing_strategy)i, true, curOutput);
+                        setStrategyMute((routing_strategy)i, false, curOutput,
+                                            desc->latency() * 2, device);
+                    }
+                    if ((tempMute && (desc == outputDesc)) || mute) {
+                        if (muteWaitMs < desc->latency()) {
+                            muteWaitMs = desc->latency();
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    // FIXME: should not need to double latency if volume could be applied immediately by the
+    // audioflinger mixer. We must account for the delay between now and the next time
+    // the audioflinger thread for this output will process a buffer (which corresponds to
+    // one buffer size, usually 1/2 or 1/4 of the latency).
+    muteWaitMs *= 2;
+    // wait for the PCM output buffers to empty before proceeding with the rest of the command
+    if (muteWaitMs > delayMs) {
+        muteWaitMs -= delayMs;
+        usleep(muteWaitMs * 1000);
+        return muteWaitMs;
+    }
+    return 0;
+}
+
+uint32_t AudioPolicyManagerBase::setOutputDevice(audio_io_handle_t output,
+                                             audio_devices_t device,
+                                             bool force,
+                                             int delayMs)
+{
+    ALOGV("setOutputDevice() output %d device %04x delayMs %d", output, device, delayMs);
+    AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output);
+    AudioParameter param;
+    uint32_t muteWaitMs;
+
+    if (outputDesc->isDuplicated()) {
+        muteWaitMs = setOutputDevice(outputDesc->mOutput1->mId, device, force, delayMs);
+        muteWaitMs += setOutputDevice(outputDesc->mOutput2->mId, device, force, delayMs);
+        return muteWaitMs;
+    }
+    // no need to proceed if new device is not AUDIO_DEVICE_NONE and not supported by current
+    // output profile
+    if ((device != AUDIO_DEVICE_NONE) &&
+            ((device & outputDesc->mProfile->mSupportedDevices) == 0)) {
+        return 0;
+    }
+
+    // filter devices according to output selected
+    device = (audio_devices_t)(device & outputDesc->mProfile->mSupportedDevices);
+
+    audio_devices_t prevDevice = outputDesc->mDevice;
+
+    ALOGV("setOutputDevice() prevDevice %04x", prevDevice);
+
+    if (device != AUDIO_DEVICE_NONE) {
+        outputDesc->mDevice = device;
+
+        // Force routing if previously asked for this output
+        if (outputDesc->mForceRouting) {
+            ALOGV("Force routing to current device as previous device was null for this output");
+            force = true;
+
+            // Request consumed. Reset mForceRouting to false
+            outputDesc->mForceRouting = false;
+        }
+    }
+    else {
+        // Device is null and does not reflect the routing. Save the necessity to force
+        // re-routing upon next attempt to select a non-null device for this output
+        outputDesc->mForceRouting = true;
+    }
+
+    muteWaitMs = checkDeviceMuteStrategies(outputDesc, prevDevice, delayMs);
+
+    // Do not change the routing if:
+    //  - the requested device is AUDIO_DEVICE_NONE
+    //  - the requested device is the same as current device and force is not specified.
+    // Doing this check here allows the caller to call setOutputDevice() without conditions
+    if ((device == AUDIO_DEVICE_NONE || device == prevDevice) && !force) {
+        ALOGV("setOutputDevice() setting same device %04x or null device for output %d", device, output);
+        return muteWaitMs;
+    }
+
+    ALOGV("setOutputDevice() changing device");
+    // do the routing
+    param.addInt(String8(AudioParameter::keyRouting), (int)device);
+    mpClientInterface->setParameters(output, param.toString(), delayMs);
+
+    // update stream volumes according to new device
+    applyStreamVolumes(output, device, delayMs);
+
+    return muteWaitMs;
+}
+
+AudioPolicyManagerBase::IOProfile *AudioPolicyManagerBase::getInputProfile(audio_devices_t device,
+                                                   uint32_t samplingRate,
+                                                   audio_format_t format,
+                                                   audio_channel_mask_t channelMask)
+{
+    // Choose an input profile based on the requested capture parameters: select the first available
+    // profile supporting all requested parameters.
+    for (size_t i = 0; i < mHwModules.size(); i++)
+    {
+        if (mHwModules[i]->mHandle == 0) {
+            continue;
+        }
+        for (size_t j = 0; j < mHwModules[i]->mInputProfiles.size(); j++)
+        {
+            IOProfile *profile = mHwModules[i]->mInputProfiles[j];
+            // profile->log();
+            if (profile->isCompatibleProfile(device, samplingRate, format,
+                                             channelMask, AUDIO_OUTPUT_FLAG_NONE)) {
+                return profile;
+            }
+        }
+    }
+    return NULL;
+}
+
+audio_devices_t AudioPolicyManagerBase::getDeviceForInputSource(int inputSource)
+{
+    uint32_t device = AUDIO_DEVICE_NONE;
+
+    switch (inputSource) {
+    case AUDIO_SOURCE_VOICE_UPLINK:
+      if (mAvailableInputDevices & AUDIO_DEVICE_IN_VOICE_CALL) {
+          device = AUDIO_DEVICE_IN_VOICE_CALL;
+          break;
+      }
+      // FALL THROUGH
+
+    case AUDIO_SOURCE_DEFAULT:
+    case AUDIO_SOURCE_MIC:
+    if (mAvailableInputDevices & AUDIO_DEVICE_IN_BLUETOOTH_A2DP) {
+        device = AUDIO_DEVICE_IN_BLUETOOTH_A2DP;
+        break;
+    }
+    // FALL THROUGH
+
+    case AUDIO_SOURCE_VOICE_RECOGNITION:
+    case AUDIO_SOURCE_HOTWORD:
+    case AUDIO_SOURCE_VOICE_COMMUNICATION:
+        if (mForceUse[AudioSystem::FOR_RECORD] == AudioSystem::FORCE_BT_SCO &&
+            mAvailableInputDevices & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) {
+            device = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET;
+        } else if (mAvailableInputDevices & AUDIO_DEVICE_IN_WIRED_HEADSET) {
+            device = AUDIO_DEVICE_IN_WIRED_HEADSET;
+        } else if (mAvailableInputDevices & AUDIO_DEVICE_IN_USB_DEVICE) {
+            device = AUDIO_DEVICE_IN_USB_DEVICE;
+        } else if (mAvailableInputDevices & AUDIO_DEVICE_IN_BUILTIN_MIC) {
+            device = AUDIO_DEVICE_IN_BUILTIN_MIC;
+        }
+        break;
+    case AUDIO_SOURCE_CAMCORDER:
+        if (mAvailableInputDevices & AUDIO_DEVICE_IN_BACK_MIC) {
+            device = AUDIO_DEVICE_IN_BACK_MIC;
+        } else if (mAvailableInputDevices & AUDIO_DEVICE_IN_BUILTIN_MIC) {
+            device = AUDIO_DEVICE_IN_BUILTIN_MIC;
+        }
+        break;
+    case AUDIO_SOURCE_VOICE_DOWNLINK:
+    case AUDIO_SOURCE_VOICE_CALL:
+        if (mAvailableInputDevices & AUDIO_DEVICE_IN_VOICE_CALL) {
+            device = AUDIO_DEVICE_IN_VOICE_CALL;
+        }
+        break;
+    case AUDIO_SOURCE_REMOTE_SUBMIX:
+        if (mAvailableInputDevices & AUDIO_DEVICE_IN_REMOTE_SUBMIX) {
+            device = AUDIO_DEVICE_IN_REMOTE_SUBMIX;
+        }
+        break;
+    default:
+        ALOGW("getDeviceForInputSource() invalid input source %d", inputSource);
+        break;
+    }
+    ALOGV("getDeviceForInputSource()input source %d, device %08x", inputSource, device);
+    return device;
+}
+
+bool AudioPolicyManagerBase::isVirtualInputDevice(audio_devices_t device)
+{
+    if ((device & AUDIO_DEVICE_BIT_IN) != 0) {
+        device &= ~AUDIO_DEVICE_BIT_IN;
+        if ((popcount(device) == 1) && ((device & ~APM_AUDIO_IN_DEVICE_VIRTUAL_ALL) == 0))
+            return true;
+    }
+    return false;
+}
+
+audio_io_handle_t AudioPolicyManagerBase::getActiveInput(bool ignoreVirtualInputs)
+{
+    for (size_t i = 0; i < mInputs.size(); i++) {
+        const AudioInputDescriptor * input_descriptor = mInputs.valueAt(i);
+        if ((input_descriptor->mRefCount > 0)
+                && (!ignoreVirtualInputs || !isVirtualInputDevice(input_descriptor->mDevice))) {
+            return mInputs.keyAt(i);
+        }
+    }
+    return 0;
+}
+
+
+audio_devices_t AudioPolicyManagerBase::getDeviceForVolume(audio_devices_t device)
+{
+    if (device == AUDIO_DEVICE_NONE) {
+        // this happens when forcing a route update and no track is active on an output.
+        // In this case the returned category is not important.
+        device =  AUDIO_DEVICE_OUT_SPEAKER;
+    } else if (AudioSystem::popCount(device) > 1) {
+        // Multiple device selection is either:
+        //  - speaker + one other device: give priority to speaker in this case.
+        //  - one A2DP device + another device: happens with duplicated output. In this case
+        // retain the device on the A2DP output as the other must not correspond to an active
+        // selection if not the speaker.
+        if (device & AUDIO_DEVICE_OUT_SPEAKER) {
+            device = AUDIO_DEVICE_OUT_SPEAKER;
+        } else {
+            device = (audio_devices_t)(device & AUDIO_DEVICE_OUT_ALL_A2DP);
+        }
+    }
+
+    ALOGW_IF(AudioSystem::popCount(device) != 1,
+            "getDeviceForVolume() invalid device combination: %08x",
+            device);
+
+    return device;
+}
+
+AudioPolicyManagerBase::device_category AudioPolicyManagerBase::getDeviceCategory(audio_devices_t device)
+{
+    switch(getDeviceForVolume(device)) {
+        case AUDIO_DEVICE_OUT_EARPIECE:
+            return DEVICE_CATEGORY_EARPIECE;
+        case AUDIO_DEVICE_OUT_WIRED_HEADSET:
+        case AUDIO_DEVICE_OUT_WIRED_HEADPHONE:
+        case AUDIO_DEVICE_OUT_BLUETOOTH_SCO:
+        case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET:
+        case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP:
+        case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES:
+            return DEVICE_CATEGORY_HEADSET;
+        case AUDIO_DEVICE_OUT_SPEAKER:
+        case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT:
+        case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER:
+        case AUDIO_DEVICE_OUT_AUX_DIGITAL:
+        case AUDIO_DEVICE_OUT_USB_ACCESSORY:
+        case AUDIO_DEVICE_OUT_USB_DEVICE:
+        case AUDIO_DEVICE_OUT_REMOTE_SUBMIX:
+        default:
+            return DEVICE_CATEGORY_SPEAKER;
+    }
+}
+
+float AudioPolicyManagerBase::volIndexToAmpl(audio_devices_t device, const StreamDescriptor& streamDesc,
+        int indexInUi)
+{
+    device_category deviceCategory = getDeviceCategory(device);
+    const VolumeCurvePoint *curve = streamDesc.mVolumeCurve[deviceCategory];
+
+    // the volume index in the UI is relative to the min and max volume indices for this stream type
+    int nbSteps = 1 + curve[VOLMAX].mIndex -
+            curve[VOLMIN].mIndex;
+    int volIdx = (nbSteps * (indexInUi - streamDesc.mIndexMin)) /
+            (streamDesc.mIndexMax - streamDesc.mIndexMin);
+
+    // find what part of the curve this index volume belongs to, or if it's out of bounds
+    int segment = 0;
+    if (volIdx < curve[VOLMIN].mIndex) {         // out of bounds
+        return 0.0f;
+    } else if (volIdx < curve[VOLKNEE1].mIndex) {
+        segment = 0;
+    } else if (volIdx < curve[VOLKNEE2].mIndex) {
+        segment = 1;
+    } else if (volIdx <= curve[VOLMAX].mIndex) {
+        segment = 2;
+    } else {                                                               // out of bounds
+        return 1.0f;
+    }
+
+    // linear interpolation in the attenuation table in dB
+    float decibels = curve[segment].mDBAttenuation +
+            ((float)(volIdx - curve[segment].mIndex)) *
+                ( (curve[segment+1].mDBAttenuation -
+                        curve[segment].mDBAttenuation) /
+                    ((float)(curve[segment+1].mIndex -
+                            curve[segment].mIndex)) );
+
+    float amplification = exp( decibels * 0.115129f); // exp( dB * ln(10) / 20 )
+
+    ALOGVV("VOLUME vol index=[%d %d %d], dB=[%.1f %.1f %.1f] ampl=%.5f",
+            curve[segment].mIndex, volIdx,
+            curve[segment+1].mIndex,
+            curve[segment].mDBAttenuation,
+            decibels,
+            curve[segment+1].mDBAttenuation,
+            amplification);
+
+    return amplification;
+}
+
+const AudioPolicyManagerBase::VolumeCurvePoint
+    AudioPolicyManagerBase::sDefaultVolumeCurve[AudioPolicyManagerBase::VOLCNT] = {
+    {1, -49.5f}, {33, -33.5f}, {66, -17.0f}, {100, 0.0f}
+};
+
+const AudioPolicyManagerBase::VolumeCurvePoint
+    AudioPolicyManagerBase::sDefaultMediaVolumeCurve[AudioPolicyManagerBase::VOLCNT] = {
+    {1, -58.0f}, {20, -40.0f}, {60, -17.0f}, {100, 0.0f}
+};
+
+const AudioPolicyManagerBase::VolumeCurvePoint
+    AudioPolicyManagerBase::sSpeakerMediaVolumeCurve[AudioPolicyManagerBase::VOLCNT] = {
+    {1, -56.0f}, {20, -34.0f}, {60, -11.0f}, {100, 0.0f}
+};
+
+const AudioPolicyManagerBase::VolumeCurvePoint
+    AudioPolicyManagerBase::sSpeakerSonificationVolumeCurve[AudioPolicyManagerBase::VOLCNT] = {
+    {1, -29.7f}, {33, -20.1f}, {66, -10.2f}, {100, 0.0f}
+};
+
+const AudioPolicyManagerBase::VolumeCurvePoint
+    AudioPolicyManagerBase::sSpeakerSonificationVolumeCurveDrc[AudioPolicyManagerBase::VOLCNT] = {
+    {1, -35.7f}, {33, -26.1f}, {66, -13.2f}, {100, 0.0f}
+};
+
+// AUDIO_STREAM_SYSTEM, AUDIO_STREAM_ENFORCED_AUDIBLE and AUDIO_STREAM_DTMF volume tracks
+// AUDIO_STREAM_RING on phones and AUDIO_STREAM_MUSIC on tablets.
+// AUDIO_STREAM_DTMF tracks AUDIO_STREAM_VOICE_CALL while in call (See AudioService.java).
+// The range is constrained between -24dB and -6dB over speaker and -30dB and -18dB over headset.
+
+const AudioPolicyManagerBase::VolumeCurvePoint
+    AudioPolicyManagerBase::sDefaultSystemVolumeCurve[AudioPolicyManagerBase::VOLCNT] = {
+    {1, -24.0f}, {33, -18.0f}, {66, -12.0f}, {100, -6.0f}
+};
+
+const AudioPolicyManagerBase::VolumeCurvePoint
+    AudioPolicyManagerBase::sDefaultSystemVolumeCurveDrc[AudioPolicyManagerBase::VOLCNT] = {
+    {1, -34.0f}, {33, -24.0f}, {66, -15.0f}, {100, -6.0f}
+};
+
+const AudioPolicyManagerBase::VolumeCurvePoint
+    AudioPolicyManagerBase::sHeadsetSystemVolumeCurve[AudioPolicyManagerBase::VOLCNT] = {
+    {1, -30.0f}, {33, -26.0f}, {66, -22.0f}, {100, -18.0f}
+};
+
+const AudioPolicyManagerBase::VolumeCurvePoint
+    AudioPolicyManagerBase::sDefaultVoiceVolumeCurve[AudioPolicyManagerBase::VOLCNT] = {
+    {0, -42.0f}, {33, -28.0f}, {66, -14.0f}, {100, 0.0f}
+};
+
+const AudioPolicyManagerBase::VolumeCurvePoint
+    AudioPolicyManagerBase::sSpeakerVoiceVolumeCurve[AudioPolicyManagerBase::VOLCNT] = {
+    {0, -24.0f}, {33, -16.0f}, {66, -8.0f}, {100, 0.0f}
+};
+
+const AudioPolicyManagerBase::VolumeCurvePoint
+            *AudioPolicyManagerBase::sVolumeProfiles[AudioSystem::NUM_STREAM_TYPES]
+                                                   [AudioPolicyManagerBase::DEVICE_CATEGORY_CNT] = {
+    { // AUDIO_STREAM_VOICE_CALL
+        sDefaultVoiceVolumeCurve, // DEVICE_CATEGORY_HEADSET
+        sSpeakerVoiceVolumeCurve, // DEVICE_CATEGORY_SPEAKER
+        sDefaultVoiceVolumeCurve  // DEVICE_CATEGORY_EARPIECE
+    },
+    { // AUDIO_STREAM_SYSTEM
+        sHeadsetSystemVolumeCurve, // DEVICE_CATEGORY_HEADSET
+        sDefaultSystemVolumeCurve, // DEVICE_CATEGORY_SPEAKER
+        sDefaultSystemVolumeCurve  // DEVICE_CATEGORY_EARPIECE
+    },
+    { // AUDIO_STREAM_RING
+        sDefaultVolumeCurve, // DEVICE_CATEGORY_HEADSET
+        sSpeakerSonificationVolumeCurve, // DEVICE_CATEGORY_SPEAKER
+        sDefaultVolumeCurve  // DEVICE_CATEGORY_EARPIECE
+    },
+    { // AUDIO_STREAM_MUSIC
+        sDefaultMediaVolumeCurve, // DEVICE_CATEGORY_HEADSET
+        sSpeakerMediaVolumeCurve, // DEVICE_CATEGORY_SPEAKER
+        sDefaultMediaVolumeCurve  // DEVICE_CATEGORY_EARPIECE
+    },
+    { // AUDIO_STREAM_ALARM
+        sDefaultVolumeCurve, // DEVICE_CATEGORY_HEADSET
+        sSpeakerSonificationVolumeCurve, // DEVICE_CATEGORY_SPEAKER
+        sDefaultVolumeCurve  // DEVICE_CATEGORY_EARPIECE
+    },
+    { // AUDIO_STREAM_NOTIFICATION
+        sDefaultVolumeCurve, // DEVICE_CATEGORY_HEADSET
+        sSpeakerSonificationVolumeCurve, // DEVICE_CATEGORY_SPEAKER
+        sDefaultVolumeCurve  // DEVICE_CATEGORY_EARPIECE
+    },
+    { // AUDIO_STREAM_BLUETOOTH_SCO
+        sDefaultVoiceVolumeCurve, // DEVICE_CATEGORY_HEADSET
+        sSpeakerVoiceVolumeCurve, // DEVICE_CATEGORY_SPEAKER
+        sDefaultVoiceVolumeCurve  // DEVICE_CATEGORY_EARPIECE
+    },
+    { // AUDIO_STREAM_ENFORCED_AUDIBLE
+        sHeadsetSystemVolumeCurve, // DEVICE_CATEGORY_HEADSET
+        sDefaultSystemVolumeCurve, // DEVICE_CATEGORY_SPEAKER
+        sDefaultSystemVolumeCurve  // DEVICE_CATEGORY_EARPIECE
+    },
+    {  // AUDIO_STREAM_DTMF
+        sHeadsetSystemVolumeCurve, // DEVICE_CATEGORY_HEADSET
+        sDefaultSystemVolumeCurve, // DEVICE_CATEGORY_SPEAKER
+        sDefaultSystemVolumeCurve  // DEVICE_CATEGORY_EARPIECE
+    },
+    { // AUDIO_STREAM_TTS
+        sDefaultMediaVolumeCurve, // DEVICE_CATEGORY_HEADSET
+        sSpeakerMediaVolumeCurve, // DEVICE_CATEGORY_SPEAKER
+        sDefaultMediaVolumeCurve  // DEVICE_CATEGORY_EARPIECE
+    },
+};
+
+void AudioPolicyManagerBase::initializeVolumeCurves()
+{
+    for (int i = 0; i < AudioSystem::NUM_STREAM_TYPES; i++) {
+        for (int j = 0; j < DEVICE_CATEGORY_CNT; j++) {
+            mStreams[i].mVolumeCurve[j] =
+                    sVolumeProfiles[i][j];
+        }
+    }
+
+    // Check availability of DRC on speaker path: if available, override some of the speaker curves
+    if (mSpeakerDrcEnabled) {
+        mStreams[AUDIO_STREAM_SYSTEM].mVolumeCurve[DEVICE_CATEGORY_SPEAKER] =
+                sDefaultSystemVolumeCurveDrc;
+        mStreams[AUDIO_STREAM_RING].mVolumeCurve[DEVICE_CATEGORY_SPEAKER] =
+                sSpeakerSonificationVolumeCurveDrc;
+        mStreams[AUDIO_STREAM_ALARM].mVolumeCurve[DEVICE_CATEGORY_SPEAKER] =
+                sSpeakerSonificationVolumeCurveDrc;
+        mStreams[AUDIO_STREAM_NOTIFICATION].mVolumeCurve[DEVICE_CATEGORY_SPEAKER] =
+                sSpeakerSonificationVolumeCurveDrc;
+    }
+}
+
+float AudioPolicyManagerBase::computeVolume(int stream,
+                                            int index,
+                                            audio_io_handle_t output,
+                                            audio_devices_t device)
+{
+    float volume = 1.0;
+    AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output);
+    StreamDescriptor &streamDesc = mStreams[stream];
+
+    if (device == AUDIO_DEVICE_NONE) {
+        device = outputDesc->device();
+    }
+
+    // if volume is not 0 (not muted), force media volume to max on digital output
+    if (stream == AudioSystem::MUSIC &&
+        index != mStreams[stream].mIndexMin &&
+        (device == AUDIO_DEVICE_OUT_AUX_DIGITAL ||
+         device == AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET)) {
+        return 1.0;
+    }
+
+    volume = volIndexToAmpl(device, streamDesc, index);
+
+    // if a headset is connected, apply the following rules to ring tones and notifications
+    // to avoid sound level bursts in user's ears:
+    // - always attenuate ring tones and notifications volume by 6dB
+    // - if music is playing, always limit the volume to current music volume,
+    // with a minimum threshold at -36dB so that notification is always perceived.
+    const routing_strategy stream_strategy = getStrategy((AudioSystem::stream_type)stream);
+    if ((device & (AUDIO_DEVICE_OUT_BLUETOOTH_A2DP |
+            AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
+            AUDIO_DEVICE_OUT_WIRED_HEADSET |
+            AUDIO_DEVICE_OUT_WIRED_HEADPHONE)) &&
+        ((stream_strategy == STRATEGY_SONIFICATION)
+                || (stream_strategy == STRATEGY_SONIFICATION_RESPECTFUL)
+                || (stream == AudioSystem::SYSTEM)
+                || ((stream_strategy == STRATEGY_ENFORCED_AUDIBLE) &&
+                    (mForceUse[AudioSystem::FOR_SYSTEM] == AudioSystem::FORCE_NONE))) &&
+        streamDesc.mCanBeMuted) {
+        volume *= SONIFICATION_HEADSET_VOLUME_FACTOR;
+        // when the phone is ringing we must consider that music could have been paused just before
+        // by the music application and behave as if music was active if the last music track was
+        // just stopped
+        if (isStreamActive(AudioSystem::MUSIC, SONIFICATION_HEADSET_MUSIC_DELAY) ||
+                mLimitRingtoneVolume) {
+            audio_devices_t musicDevice = getDeviceForStrategy(STRATEGY_MEDIA, true /*fromCache*/);
+            float musicVol = computeVolume(AudioSystem::MUSIC,
+                               mStreams[AudioSystem::MUSIC].getVolumeIndex(musicDevice),
+                               output,
+                               musicDevice);
+            float minVol = (musicVol > SONIFICATION_HEADSET_VOLUME_MIN) ?
+                                musicVol : SONIFICATION_HEADSET_VOLUME_MIN;
+            if (volume > minVol) {
+                volume = minVol;
+                ALOGV("computeVolume limiting volume to %f musicVol %f", minVol, musicVol);
+            }
+        }
+    }
+
+    return volume;
+}
+
+status_t AudioPolicyManagerBase::checkAndSetVolume(int stream,
+                                                   int index,
+                                                   audio_io_handle_t output,
+                                                   audio_devices_t device,
+                                                   int delayMs,
+                                                   bool force)
+{
+
+    // do not change actual stream volume if the stream is muted
+    if (mOutputs.valueFor(output)->mMuteCount[stream] != 0) {
+        ALOGVV("checkAndSetVolume() stream %d muted count %d",
+              stream, mOutputs.valueFor(output)->mMuteCount[stream]);
+        return NO_ERROR;
+    }
+
+    // do not change in call volume if bluetooth is connected and vice versa
+    if ((stream == AudioSystem::VOICE_CALL && mForceUse[AudioSystem::FOR_COMMUNICATION] == AudioSystem::FORCE_BT_SCO) ||
+        (stream == AudioSystem::BLUETOOTH_SCO && mForceUse[AudioSystem::FOR_COMMUNICATION] != AudioSystem::FORCE_BT_SCO)) {
+        ALOGV("checkAndSetVolume() cannot set stream %d volume with force use = %d for comm",
+             stream, mForceUse[AudioSystem::FOR_COMMUNICATION]);
+        return INVALID_OPERATION;
+    }
+
+    float volume = computeVolume(stream, index, output, device);
+    // We actually change the volume if:
+    // - the float value returned by computeVolume() changed
+    // - the force flag is set
+    if (volume != mOutputs.valueFor(output)->mCurVolume[stream] ||
+            force) {
+        mOutputs.valueFor(output)->mCurVolume[stream] = volume;
+        ALOGVV("checkAndSetVolume() for output %d stream %d, volume %f, delay %d", output, stream, volume, delayMs);
+        // Force VOICE_CALL to track BLUETOOTH_SCO stream volume when bluetooth audio is
+        // enabled
+        if (stream == AudioSystem::BLUETOOTH_SCO) {
+            mpClientInterface->setStreamVolume(AudioSystem::VOICE_CALL, volume, output, delayMs);
+        }
+        mpClientInterface->setStreamVolume((AudioSystem::stream_type)stream, volume, output, delayMs);
+    }
+
+    if (stream == AudioSystem::VOICE_CALL ||
+        stream == AudioSystem::BLUETOOTH_SCO) {
+        float voiceVolume;
+        // Force voice volume to max for bluetooth SCO as volume is managed by the headset
+        if (stream == AudioSystem::VOICE_CALL) {
+            voiceVolume = (float)index/(float)mStreams[stream].mIndexMax;
+        } else {
+            voiceVolume = 1.0;
+        }
+
+        if (voiceVolume != mLastVoiceVolume && output == mPrimaryOutput) {
+            mpClientInterface->setVoiceVolume(voiceVolume, delayMs);
+            mLastVoiceVolume = voiceVolume;
+        }
+    }
+
+    return NO_ERROR;
+}
+
+void AudioPolicyManagerBase::applyStreamVolumes(audio_io_handle_t output,
+                                                audio_devices_t device,
+                                                int delayMs,
+                                                bool force)
+{
+    ALOGVV("applyStreamVolumes() for output %d and device %x", output, device);
+
+    for (int stream = 0; stream < AudioSystem::NUM_STREAM_TYPES; stream++) {
+        checkAndSetVolume(stream,
+                          mStreams[stream].getVolumeIndex(device),
+                          output,
+                          device,
+                          delayMs,
+                          force);
+    }
+}
+
+void AudioPolicyManagerBase::setStrategyMute(routing_strategy strategy,
+                                             bool on,
+                                             audio_io_handle_t output,
+                                             int delayMs,
+                                             audio_devices_t device)
+{
+    ALOGVV("setStrategyMute() strategy %d, mute %d, output %d", strategy, on, output);
+    for (int stream = 0; stream < AudioSystem::NUM_STREAM_TYPES; stream++) {
+        if (getStrategy((AudioSystem::stream_type)stream) == strategy) {
+            setStreamMute(stream, on, output, delayMs, device);
+        }
+    }
+}
+
+void AudioPolicyManagerBase::setStreamMute(int stream,
+                                           bool on,
+                                           audio_io_handle_t output,
+                                           int delayMs,
+                                           audio_devices_t device)
+{
+    StreamDescriptor &streamDesc = mStreams[stream];
+    AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output);
+    if (device == AUDIO_DEVICE_NONE) {
+        device = outputDesc->device();
+    }
+
+    ALOGVV("setStreamMute() stream %d, mute %d, output %d, mMuteCount %d device %04x",
+          stream, on, output, outputDesc->mMuteCount[stream], device);
+
+    if (on) {
+        if (outputDesc->mMuteCount[stream] == 0) {
+            if (streamDesc.mCanBeMuted &&
+                    ((stream != AudioSystem::ENFORCED_AUDIBLE) ||
+                     (mForceUse[AudioSystem::FOR_SYSTEM] == AudioSystem::FORCE_NONE))) {
+                checkAndSetVolume(stream, 0, output, device, delayMs);
+            }
+        }
+        // increment mMuteCount after calling checkAndSetVolume() so that volume change is not ignored
+        outputDesc->mMuteCount[stream]++;
+    } else {
+        if (outputDesc->mMuteCount[stream] == 0) {
+            ALOGV("setStreamMute() unmuting non muted stream!");
+            return;
+        }
+        if (--outputDesc->mMuteCount[stream] == 0) {
+            checkAndSetVolume(stream,
+                              streamDesc.getVolumeIndex(device),
+                              output,
+                              device,
+                              delayMs);
+        }
+    }
+}
+
+void AudioPolicyManagerBase::handleIncallSonification(int stream, bool starting, bool stateChange)
+{
+    // if the stream pertains to sonification strategy and we are in call we must
+    // mute the stream if it is low visibility. If it is high visibility, we must play a tone
+    // in the device used for phone strategy and play the tone if the selected device does not
+    // interfere with the device used for phone strategy
+    // if stateChange is true, we are called from setPhoneState() and we must mute or unmute as
+    // many times as there are active tracks on the output
+    const routing_strategy stream_strategy = getStrategy((AudioSystem::stream_type)stream);
+    if ((stream_strategy == STRATEGY_SONIFICATION) ||
+            ((stream_strategy == STRATEGY_SONIFICATION_RESPECTFUL))) {
+        AudioOutputDescriptor *outputDesc = mOutputs.valueFor(mPrimaryOutput);
+        ALOGV("handleIncallSonification() stream %d starting %d device %x stateChange %d",
+                stream, starting, outputDesc->mDevice, stateChange);
+        if (outputDesc->mRefCount[stream]) {
+            int muteCount = 1;
+            if (stateChange) {
+                muteCount = outputDesc->mRefCount[stream];
+            }
+            if (AudioSystem::isLowVisibility((AudioSystem::stream_type)stream)) {
+                ALOGV("handleIncallSonification() low visibility, muteCount %d", muteCount);
+                for (int i = 0; i < muteCount; i++) {
+                    setStreamMute(stream, starting, mPrimaryOutput);
+                }
+            } else {
+                ALOGV("handleIncallSonification() high visibility");
+                if (outputDesc->device() &
+                        getDeviceForStrategy(STRATEGY_PHONE, true /*fromCache*/)) {
+                    ALOGV("handleIncallSonification() high visibility muted, muteCount %d", muteCount);
+                    for (int i = 0; i < muteCount; i++) {
+                        setStreamMute(stream, starting, mPrimaryOutput);
+                    }
+                }
+                if (starting) {
+                    mpClientInterface->startTone(ToneGenerator::TONE_SUP_CALL_WAITING, AudioSystem::VOICE_CALL);
+                } else {
+                    mpClientInterface->stopTone();
+                }
+            }
+        }
+    }
+}
+
+bool AudioPolicyManagerBase::isInCall()
+{
+    return isStateInCall(mPhoneState);
+}
+
+bool AudioPolicyManagerBase::isStateInCall(int state) {
+    return ((state == AudioSystem::MODE_IN_CALL) ||
+            (state == AudioSystem::MODE_IN_COMMUNICATION));
+}
+
+uint32_t AudioPolicyManagerBase::getMaxEffectsCpuLoad()
+{
+    return MAX_EFFECTS_CPU_LOAD;
+}
+
+uint32_t AudioPolicyManagerBase::getMaxEffectsMemory()
+{
+    return MAX_EFFECTS_MEMORY;
+}
+
+// --- AudioOutputDescriptor class implementation
+
+AudioPolicyManagerBase::AudioOutputDescriptor::AudioOutputDescriptor(
+        const IOProfile *profile)
+    : mId(0), mSamplingRate(0), mFormat(AUDIO_FORMAT_DEFAULT),
+      mChannelMask(0), mLatency(0),
+    mFlags((audio_output_flags_t)0), mDevice(AUDIO_DEVICE_NONE),
+    mOutput1(0), mOutput2(0), mProfile(profile), mDirectOpenCount(0),
+    mForceRouting(false)
+{
+    // clear usage count for all stream types
+    for (int i = 0; i < AudioSystem::NUM_STREAM_TYPES; i++) {
+        mRefCount[i] = 0;
+        mCurVolume[i] = -1.0;
+        mMuteCount[i] = 0;
+        mStopTime[i] = 0;
+    }
+    for (int i = 0; i < NUM_STRATEGIES; i++) {
+        mStrategyMutedByDevice[i] = false;
+    }
+    if (profile != NULL) {
+        mSamplingRate = profile->mSamplingRates[0];
+        mFormat = profile->mFormats[0];
+        mChannelMask = profile->mChannelMasks[0];
+        mFlags = profile->mFlags;
+    }
+}
+
+audio_devices_t AudioPolicyManagerBase::AudioOutputDescriptor::device() const
+{
+    if (isDuplicated()) {
+        return (audio_devices_t)(mOutput1->mDevice | mOutput2->mDevice);
+    } else {
+        return mDevice;
+    }
+}
+
+uint32_t AudioPolicyManagerBase::AudioOutputDescriptor::latency()
+{
+    if (isDuplicated()) {
+        return (mOutput1->mLatency > mOutput2->mLatency) ? mOutput1->mLatency : mOutput2->mLatency;
+    } else {
+        return mLatency;
+    }
+}
+
+bool AudioPolicyManagerBase::AudioOutputDescriptor::sharesHwModuleWith(
+        const AudioOutputDescriptor *outputDesc)
+{
+    if (isDuplicated()) {
+        return mOutput1->sharesHwModuleWith(outputDesc) || mOutput2->sharesHwModuleWith(outputDesc);
+    } else if (outputDesc->isDuplicated()){
+        return sharesHwModuleWith(outputDesc->mOutput1) || sharesHwModuleWith(outputDesc->mOutput2);
+    } else {
+        return (mProfile->mModule == outputDesc->mProfile->mModule);
+    }
+}
+
+void AudioPolicyManagerBase::AudioOutputDescriptor::changeRefCount(AudioSystem::stream_type stream, int delta)
+{
+    // forward usage count change to attached outputs
+    if (isDuplicated()) {
+        mOutput1->changeRefCount(stream, delta);
+        mOutput2->changeRefCount(stream, delta);
+    }
+    if ((delta + (int)mRefCount[stream]) < 0) {
+        ALOGW("changeRefCount() invalid delta %d for stream %d, refCount %d", delta, stream, mRefCount[stream]);
+        mRefCount[stream] = 0;
+        return;
+    }
+    mRefCount[stream] += delta;
+    ALOGV("changeRefCount() stream %d, count %d", stream, mRefCount[stream]);
+}
+
+audio_devices_t AudioPolicyManagerBase::AudioOutputDescriptor::supportedDevices()
+{
+    if (isDuplicated()) {
+        return (audio_devices_t)(mOutput1->supportedDevices() | mOutput2->supportedDevices());
+    } else {
+        return mProfile->mSupportedDevices ;
+    }
+}
+
+bool AudioPolicyManagerBase::AudioOutputDescriptor::isActive(uint32_t inPastMs) const
+{
+    return isStrategyActive(NUM_STRATEGIES, inPastMs);
+}
+
+bool AudioPolicyManagerBase::AudioOutputDescriptor::isStrategyActive(routing_strategy strategy,
+                                                                       uint32_t inPastMs,
+                                                                       nsecs_t sysTime) const
+{
+    if ((sysTime == 0) && (inPastMs != 0)) {
+        sysTime = systemTime();
+    }
+    for (int i = 0; i < AudioSystem::NUM_STREAM_TYPES; i++) {
+        if (((getStrategy((AudioSystem::stream_type)i) == strategy) ||
+                (NUM_STRATEGIES == strategy)) &&
+                isStreamActive((AudioSystem::stream_type)i, inPastMs, sysTime)) {
+            return true;
+        }
+    }
+    return false;
+}
+
+bool AudioPolicyManagerBase::AudioOutputDescriptor::isStreamActive(AudioSystem::stream_type stream,
+                                                                       uint32_t inPastMs,
+                                                                       nsecs_t sysTime) const
+{
+    if (mRefCount[stream] != 0) {
+        return true;
+    }
+    if (inPastMs == 0) {
+        return false;
+    }
+    if (sysTime == 0) {
+        sysTime = systemTime();
+    }
+    if (ns2ms(sysTime - mStopTime[stream]) < inPastMs) {
+        return true;
+    }
+    return false;
+}
+
+
+status_t AudioPolicyManagerBase::AudioOutputDescriptor::dump(int fd)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+
+    snprintf(buffer, SIZE, " Sampling rate: %d\n", mSamplingRate);
+    result.append(buffer);
+    snprintf(buffer, SIZE, " Format: %08x\n", mFormat);
+    result.append(buffer);
+    snprintf(buffer, SIZE, " Channels: %08x\n", mChannelMask);
+    result.append(buffer);
+    snprintf(buffer, SIZE, " Latency: %d\n", mLatency);
+    result.append(buffer);
+    snprintf(buffer, SIZE, " Flags %08x\n", mFlags);
+    result.append(buffer);
+    snprintf(buffer, SIZE, " Devices %08x\n", device());
+    result.append(buffer);
+    snprintf(buffer, SIZE, " Stream volume refCount muteCount\n");
+    result.append(buffer);
+    for (int i = 0; i < AudioSystem::NUM_STREAM_TYPES; i++) {
+        snprintf(buffer, SIZE, " %02d     %.03f     %02d       %02d\n", i, mCurVolume[i], mRefCount[i], mMuteCount[i]);
+        result.append(buffer);
+    }
+    write(fd, result.string(), result.size());
+
+    return NO_ERROR;
+}
+
+// --- AudioInputDescriptor class implementation
+
+AudioPolicyManagerBase::AudioInputDescriptor::AudioInputDescriptor(const IOProfile *profile)
+    :  mId(0), mSamplingRate(0), mFormat(AUDIO_FORMAT_DEFAULT), mChannelMask(0),
+      mDevice(AUDIO_DEVICE_NONE), mRefCount(0),
+      mInputSource(0), mProfile(profile)
+{
+    if (profile != NULL) {
+         mSamplingRate = profile->mSamplingRates[0];
+         mFormat = profile->mFormats[0];
+         mChannelMask = profile->mChannelMasks[0];
+     }
+}
+
+status_t AudioPolicyManagerBase::AudioInputDescriptor::dump(int fd)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+
+    snprintf(buffer, SIZE, " Sampling rate: %d\n", mSamplingRate);
+    result.append(buffer);
+    snprintf(buffer, SIZE, " Format: %d\n", mFormat);
+    result.append(buffer);
+    snprintf(buffer, SIZE, " Channels: %08x\n", mChannelMask);
+    result.append(buffer);
+    snprintf(buffer, SIZE, " Devices %08x\n", mDevice);
+    result.append(buffer);
+    snprintf(buffer, SIZE, " Ref Count %d\n", mRefCount);
+    result.append(buffer);
+    write(fd, result.string(), result.size());
+
+    return NO_ERROR;
+}
+
+// --- StreamDescriptor class implementation
+
+AudioPolicyManagerBase::StreamDescriptor::StreamDescriptor()
+    :   mIndexMin(0), mIndexMax(1), mCanBeMuted(true)
+{
+    mIndexCur.add(AUDIO_DEVICE_OUT_DEFAULT, 0);
+}
+
+int AudioPolicyManagerBase::StreamDescriptor::getVolumeIndex(audio_devices_t device)
+{
+    device = AudioPolicyManagerBase::getDeviceForVolume(device);
+    // there is always a valid entry for AUDIO_DEVICE_OUT_DEFAULT
+    if (mIndexCur.indexOfKey(device) < 0) {
+        device = AUDIO_DEVICE_OUT_DEFAULT;
+    }
+    return mIndexCur.valueFor(device);
+}
+
+void AudioPolicyManagerBase::StreamDescriptor::dump(int fd)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+
+    snprintf(buffer, SIZE, "%s         %02d         %02d         ",
+             mCanBeMuted ? "true " : "false", mIndexMin, mIndexMax);
+    result.append(buffer);
+    for (size_t i = 0; i < mIndexCur.size(); i++) {
+        snprintf(buffer, SIZE, "%04x : %02d, ",
+                 mIndexCur.keyAt(i),
+                 mIndexCur.valueAt(i));
+        result.append(buffer);
+    }
+    result.append("\n");
+
+    write(fd, result.string(), result.size());
+}
+
+// --- EffectDescriptor class implementation
+
+status_t AudioPolicyManagerBase::EffectDescriptor::dump(int fd)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+
+    snprintf(buffer, SIZE, " I/O: %d\n", mIo);
+    result.append(buffer);
+    snprintf(buffer, SIZE, " Strategy: %d\n", mStrategy);
+    result.append(buffer);
+    snprintf(buffer, SIZE, " Session: %d\n", mSession);
+    result.append(buffer);
+    snprintf(buffer, SIZE, " Name: %s\n",  mDesc.name);
+    result.append(buffer);
+    snprintf(buffer, SIZE, " %s\n",  mEnabled ? "Enabled" : "Disabled");
+    result.append(buffer);
+    write(fd, result.string(), result.size());
+
+    return NO_ERROR;
+}
+
+// --- IOProfile class implementation
+
+AudioPolicyManagerBase::HwModule::HwModule(const char *name)
+    : mName(strndup(name, AUDIO_HARDWARE_MODULE_ID_MAX_LEN)), mHandle(0)
+{
+}
+
+AudioPolicyManagerBase::HwModule::~HwModule()
+{
+    for (size_t i = 0; i < mOutputProfiles.size(); i++) {
+         delete mOutputProfiles[i];
+    }
+    for (size_t i = 0; i < mInputProfiles.size(); i++) {
+         delete mInputProfiles[i];
+    }
+    free((void *)mName);
+}
+
+void AudioPolicyManagerBase::HwModule::dump(int fd)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+
+    snprintf(buffer, SIZE, "  - name: %s\n", mName);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "  - handle: %d\n", mHandle);
+    result.append(buffer);
+    write(fd, result.string(), result.size());
+    if (mOutputProfiles.size()) {
+        write(fd, "  - outputs:\n", strlen("  - outputs:\n"));
+        for (size_t i = 0; i < mOutputProfiles.size(); i++) {
+            snprintf(buffer, SIZE, "    output %zu:\n", i);
+            write(fd, buffer, strlen(buffer));
+            mOutputProfiles[i]->dump(fd);
+        }
+    }
+    if (mInputProfiles.size()) {
+        write(fd, "  - inputs:\n", strlen("  - inputs:\n"));
+        for (size_t i = 0; i < mInputProfiles.size(); i++) {
+            snprintf(buffer, SIZE, "    input %zu:\n", i);
+            write(fd, buffer, strlen(buffer));
+            mInputProfiles[i]->dump(fd);
+        }
+    }
+}
+
+AudioPolicyManagerBase::IOProfile::IOProfile(HwModule *module)
+    : mFlags((audio_output_flags_t)0), mModule(module)
+{
+}
+
+AudioPolicyManagerBase::IOProfile::~IOProfile()
+{
+}
+
+// checks if the IO profile is compatible with specified parameters.
+// Sampling rate, format and channel mask must be specified in order to
+// get a valid a match
+bool AudioPolicyManagerBase::IOProfile::isCompatibleProfile(audio_devices_t device,
+                                                            uint32_t samplingRate,
+                                                            audio_format_t format,
+                                                            audio_channel_mask_t channelMask,
+                                                            audio_output_flags_t flags) const
+{
+    if (samplingRate == 0 || !audio_is_valid_format(format) || channelMask == 0) {
+         return false;
+     }
+
+     if ((mSupportedDevices & device) != device) {
+         return false;
+     }
+     if ((mFlags & flags) != flags) {
+         return false;
+     }
+     size_t i;
+     for (i = 0; i < mSamplingRates.size(); i++)
+     {
+         if (mSamplingRates[i] == samplingRate) {
+             break;
+         }
+     }
+     if (i == mSamplingRates.size()) {
+         return false;
+     }
+     for (i = 0; i < mFormats.size(); i++)
+     {
+         if (mFormats[i] == format) {
+             break;
+         }
+     }
+     if (i == mFormats.size()) {
+         return false;
+     }
+     for (i = 0; i < mChannelMasks.size(); i++)
+     {
+         if (mChannelMasks[i] == channelMask) {
+             break;
+         }
+     }
+     if (i == mChannelMasks.size()) {
+         return false;
+     }
+     return true;
+}
+
+void AudioPolicyManagerBase::IOProfile::dump(int fd)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+
+    snprintf(buffer, SIZE, "    - sampling rates: ");
+    result.append(buffer);
+    for (size_t i = 0; i < mSamplingRates.size(); i++) {
+        snprintf(buffer, SIZE, "%d", mSamplingRates[i]);
+        result.append(buffer);
+        result.append(i == (mSamplingRates.size() - 1) ? "\n" : ", ");
+    }
+
+    snprintf(buffer, SIZE, "    - channel masks: ");
+    result.append(buffer);
+    for (size_t i = 0; i < mChannelMasks.size(); i++) {
+        snprintf(buffer, SIZE, "0x%04x", mChannelMasks[i]);
+        result.append(buffer);
+        result.append(i == (mChannelMasks.size() - 1) ? "\n" : ", ");
+    }
+
+    snprintf(buffer, SIZE, "    - formats: ");
+    result.append(buffer);
+    for (size_t i = 0; i < mFormats.size(); i++) {
+        snprintf(buffer, SIZE, "0x%08x", mFormats[i]);
+        result.append(buffer);
+        result.append(i == (mFormats.size() - 1) ? "\n" : ", ");
+    }
+
+    snprintf(buffer, SIZE, "    - devices: 0x%04x\n", mSupportedDevices);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "    - flags: 0x%04x\n", mFlags);
+    result.append(buffer);
+
+    write(fd, result.string(), result.size());
+}
+
+void AudioPolicyManagerBase::IOProfile::log()
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+
+    ALOGV("    - sampling rates: ");
+    for (size_t i = 0; i < mSamplingRates.size(); i++) {
+        ALOGV("  %d", mSamplingRates[i]);
+    }
+
+    ALOGV("    - channel masks: ");
+    for (size_t i = 0; i < mChannelMasks.size(); i++) {
+        ALOGV("  0x%04x", mChannelMasks[i]);
+    }
+
+    ALOGV("    - formats: ");
+    for (size_t i = 0; i < mFormats.size(); i++) {
+        ALOGV("  0x%08x", mFormats[i]);
+    }
+
+    ALOGV("    - devices: 0x%04x\n", mSupportedDevices);
+    ALOGV("    - flags: 0x%04x\n", mFlags);
+}
+
+// --- audio_policy.conf file parsing
+
+struct StringToEnum {
+    const char *name;
+    uint32_t value;
+};
+
+#define STRING_TO_ENUM(string) { #string, string }
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+
+const struct StringToEnum sDeviceNameToEnumTable[] = {
+    STRING_TO_ENUM(AUDIO_DEVICE_OUT_EARPIECE),
+    STRING_TO_ENUM(AUDIO_DEVICE_OUT_SPEAKER),
+    STRING_TO_ENUM(AUDIO_DEVICE_OUT_WIRED_HEADSET),
+    STRING_TO_ENUM(AUDIO_DEVICE_OUT_WIRED_HEADPHONE),
+    STRING_TO_ENUM(AUDIO_DEVICE_OUT_ALL_SCO),
+    STRING_TO_ENUM(AUDIO_DEVICE_OUT_ALL_A2DP),
+    STRING_TO_ENUM(AUDIO_DEVICE_OUT_AUX_DIGITAL),
+    STRING_TO_ENUM(AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET),
+    STRING_TO_ENUM(AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET),
+    STRING_TO_ENUM(AUDIO_DEVICE_OUT_USB_DEVICE),
+    STRING_TO_ENUM(AUDIO_DEVICE_OUT_USB_ACCESSORY),
+    STRING_TO_ENUM(AUDIO_DEVICE_OUT_ALL_USB),
+    STRING_TO_ENUM(AUDIO_DEVICE_OUT_REMOTE_SUBMIX),
+    STRING_TO_ENUM(AUDIO_DEVICE_IN_BUILTIN_MIC),
+    STRING_TO_ENUM(AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET),
+    STRING_TO_ENUM(AUDIO_DEVICE_IN_WIRED_HEADSET),
+    STRING_TO_ENUM(AUDIO_DEVICE_IN_AUX_DIGITAL),
+    STRING_TO_ENUM(AUDIO_DEVICE_IN_VOICE_CALL),
+    STRING_TO_ENUM(AUDIO_DEVICE_IN_BACK_MIC),
+    STRING_TO_ENUM(AUDIO_DEVICE_IN_REMOTE_SUBMIX),
+    STRING_TO_ENUM(AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET),
+    STRING_TO_ENUM(AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET),
+    STRING_TO_ENUM(AUDIO_DEVICE_IN_USB_ACCESSORY),
+    STRING_TO_ENUM(AUDIO_DEVICE_IN_USB_DEVICE),
+    STRING_TO_ENUM(AUDIO_DEVICE_IN_BLUETOOTH_A2DP),
+};
+
+const struct StringToEnum sFlagNameToEnumTable[] = {
+    STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_DIRECT),
+    STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_PRIMARY),
+    STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_FAST),
+    STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_DEEP_BUFFER),
+    STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD),
+    STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_NON_BLOCKING),
+};
+
+const struct StringToEnum sFormatNameToEnumTable[] = {
+    STRING_TO_ENUM(AUDIO_FORMAT_PCM_16_BIT),
+    STRING_TO_ENUM(AUDIO_FORMAT_PCM_8_BIT),
+    STRING_TO_ENUM(AUDIO_FORMAT_PCM_32_BIT),
+    STRING_TO_ENUM(AUDIO_FORMAT_PCM_8_24_BIT),
+    STRING_TO_ENUM(AUDIO_FORMAT_PCM_FLOAT),
+    STRING_TO_ENUM(AUDIO_FORMAT_PCM_24_BIT_PACKED),
+    STRING_TO_ENUM(AUDIO_FORMAT_MP3),
+    STRING_TO_ENUM(AUDIO_FORMAT_AAC),
+    STRING_TO_ENUM(AUDIO_FORMAT_VORBIS),
+    STRING_TO_ENUM(AUDIO_FORMAT_HE_AAC_V1),
+    STRING_TO_ENUM(AUDIO_FORMAT_HE_AAC_V2),
+    STRING_TO_ENUM(AUDIO_FORMAT_OPUS),
+    STRING_TO_ENUM(AUDIO_FORMAT_AC3),
+    STRING_TO_ENUM(AUDIO_FORMAT_E_AC3),
+};
+
+const struct StringToEnum sOutChannelsNameToEnumTable[] = {
+    STRING_TO_ENUM(AUDIO_CHANNEL_OUT_MONO),
+    STRING_TO_ENUM(AUDIO_CHANNEL_OUT_STEREO),
+    STRING_TO_ENUM(AUDIO_CHANNEL_OUT_5POINT1),
+    STRING_TO_ENUM(AUDIO_CHANNEL_OUT_7POINT1),
+};
+
+const struct StringToEnum sInChannelsNameToEnumTable[] = {
+    STRING_TO_ENUM(AUDIO_CHANNEL_IN_MONO),
+    STRING_TO_ENUM(AUDIO_CHANNEL_IN_STEREO),
+    STRING_TO_ENUM(AUDIO_CHANNEL_IN_FRONT_BACK),
+};
+
+
+uint32_t AudioPolicyManagerBase::stringToEnum(const struct StringToEnum *table,
+                                              size_t size,
+                                              const char *name)
+{
+    for (size_t i = 0; i < size; i++) {
+        if (strcmp(table[i].name, name) == 0) {
+            ALOGV("stringToEnum() found %s", table[i].name);
+            return table[i].value;
+        }
+    }
+    return 0;
+}
+
+bool AudioPolicyManagerBase::stringToBool(const char *value)
+{
+    return ((strcasecmp("true", value) == 0) || (strcmp("1", value) == 0));
+}
+
+audio_output_flags_t AudioPolicyManagerBase::parseFlagNames(char *name)
+{
+    uint32_t flag = 0;
+
+    // it is OK to cast name to non const here as we are not going to use it after
+    // strtok() modifies it
+    char *flagName = strtok(name, "|");
+    while (flagName != NULL) {
+        if (strlen(flagName) != 0) {
+            flag |= stringToEnum(sFlagNameToEnumTable,
+                               ARRAY_SIZE(sFlagNameToEnumTable),
+                               flagName);
+        }
+        flagName = strtok(NULL, "|");
+    }
+    //force direct flag if offload flag is set: offloading implies a direct output stream
+    // and all common behaviors are driven by checking only the direct flag
+    // this should normally be set appropriately in the policy configuration file
+    if ((flag & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) {
+        flag |= AUDIO_OUTPUT_FLAG_DIRECT;
+    }
+
+    return (audio_output_flags_t)flag;
+}
+
+audio_devices_t AudioPolicyManagerBase::parseDeviceNames(char *name)
+{
+    uint32_t device = 0;
+
+    char *devName = strtok(name, "|");
+    while (devName != NULL) {
+        if (strlen(devName) != 0) {
+            device |= stringToEnum(sDeviceNameToEnumTable,
+                                 ARRAY_SIZE(sDeviceNameToEnumTable),
+                                 devName);
+        }
+        devName = strtok(NULL, "|");
+    }
+    return device;
+}
+
+void AudioPolicyManagerBase::loadSamplingRates(char *name, IOProfile *profile)
+{
+    char *str = strtok(name, "|");
+
+    // by convention, "0' in the first entry in mSamplingRates indicates the supported sampling
+    // rates should be read from the output stream after it is opened for the first time
+    if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG) == 0) {
+        profile->mSamplingRates.add(0);
+        return;
+    }
+
+    while (str != NULL) {
+        uint32_t rate = atoi(str);
+        if (rate != 0) {
+            ALOGV("loadSamplingRates() adding rate %d", rate);
+            profile->mSamplingRates.add(rate);
+        }
+        str = strtok(NULL, "|");
+    }
+    return;
+}
+
+void AudioPolicyManagerBase::loadFormats(char *name, IOProfile *profile)
+{
+    char *str = strtok(name, "|");
+
+    // by convention, "0' in the first entry in mFormats indicates the supported formats
+    // should be read from the output stream after it is opened for the first time
+    if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG) == 0) {
+        profile->mFormats.add(AUDIO_FORMAT_DEFAULT);
+        return;
+    }
+
+    while (str != NULL) {
+        audio_format_t format = (audio_format_t)stringToEnum(sFormatNameToEnumTable,
+                                                             ARRAY_SIZE(sFormatNameToEnumTable),
+                                                             str);
+        if (format != AUDIO_FORMAT_DEFAULT) {
+            profile->mFormats.add(format);
+        }
+        str = strtok(NULL, "|");
+    }
+    return;
+}
+
+void AudioPolicyManagerBase::loadInChannels(char *name, IOProfile *profile)
+{
+    const char *str = strtok(name, "|");
+
+    ALOGV("loadInChannels() %s", name);
+
+    if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG) == 0) {
+        profile->mChannelMasks.add(0);
+        return;
+    }
+
+    while (str != NULL) {
+        audio_channel_mask_t channelMask =
+                (audio_channel_mask_t)stringToEnum(sInChannelsNameToEnumTable,
+                                                   ARRAY_SIZE(sInChannelsNameToEnumTable),
+                                                   str);
+        if (channelMask != 0) {
+            ALOGV("loadInChannels() adding channelMask %04x", channelMask);
+            profile->mChannelMasks.add(channelMask);
+        }
+        str = strtok(NULL, "|");
+    }
+    return;
+}
+
+void AudioPolicyManagerBase::loadOutChannels(char *name, IOProfile *profile)
+{
+    const char *str = strtok(name, "|");
+
+    ALOGV("loadOutChannels() %s", name);
+
+    // by convention, "0' in the first entry in mChannelMasks indicates the supported channel
+    // masks should be read from the output stream after it is opened for the first time
+    if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG) == 0) {
+        profile->mChannelMasks.add(0);
+        return;
+    }
+
+    while (str != NULL) {
+        audio_channel_mask_t channelMask =
+                (audio_channel_mask_t)stringToEnum(sOutChannelsNameToEnumTable,
+                                                   ARRAY_SIZE(sOutChannelsNameToEnumTable),
+                                                   str);
+        if (channelMask != 0) {
+            profile->mChannelMasks.add(channelMask);
+        }
+        str = strtok(NULL, "|");
+    }
+    return;
+}
+
+status_t AudioPolicyManagerBase::loadInput(cnode *root, HwModule *module)
+{
+    cnode *node = root->first_child;
+
+    IOProfile *profile = new IOProfile(module);
+
+    while (node) {
+        if (strcmp(node->name, SAMPLING_RATES_TAG) == 0) {
+            loadSamplingRates((char *)node->value, profile);
+        } else if (strcmp(node->name, FORMATS_TAG) == 0) {
+            loadFormats((char *)node->value, profile);
+        } else if (strcmp(node->name, CHANNELS_TAG) == 0) {
+            loadInChannels((char *)node->value, profile);
+        } else if (strcmp(node->name, DEVICES_TAG) == 0) {
+            profile->mSupportedDevices = parseDeviceNames((char *)node->value);
+        }
+        node = node->next;
+    }
+    ALOGW_IF(profile->mSupportedDevices == AUDIO_DEVICE_NONE,
+            "loadInput() invalid supported devices");
+    ALOGW_IF(profile->mChannelMasks.size() == 0,
+            "loadInput() invalid supported channel masks");
+    ALOGW_IF(profile->mSamplingRates.size() == 0,
+            "loadInput() invalid supported sampling rates");
+    ALOGW_IF(profile->mFormats.size() == 0,
+            "loadInput() invalid supported formats");
+    if ((profile->mSupportedDevices != AUDIO_DEVICE_NONE) &&
+            (profile->mChannelMasks.size() != 0) &&
+            (profile->mSamplingRates.size() != 0) &&
+            (profile->mFormats.size() != 0)) {
+
+        ALOGV("loadInput() adding input mSupportedDevices 0x%X", profile->mSupportedDevices);
+
+        module->mInputProfiles.add(profile);
+        return NO_ERROR;
+    } else {
+        delete profile;
+        return BAD_VALUE;
+    }
+}
+
+status_t AudioPolicyManagerBase::loadOutput(cnode *root, HwModule *module)
+{
+    cnode *node = root->first_child;
+
+    IOProfile *profile = new IOProfile(module);
+
+    while (node) {
+        if (strcmp(node->name, SAMPLING_RATES_TAG) == 0) {
+            loadSamplingRates((char *)node->value, profile);
+        } else if (strcmp(node->name, FORMATS_TAG) == 0) {
+            loadFormats((char *)node->value, profile);
+        } else if (strcmp(node->name, CHANNELS_TAG) == 0) {
+            loadOutChannels((char *)node->value, profile);
+        } else if (strcmp(node->name, DEVICES_TAG) == 0) {
+            profile->mSupportedDevices = parseDeviceNames((char *)node->value);
+        } else if (strcmp(node->name, FLAGS_TAG) == 0) {
+            profile->mFlags = parseFlagNames((char *)node->value);
+        }
+        node = node->next;
+    }
+    ALOGW_IF(profile->mSupportedDevices == AUDIO_DEVICE_NONE,
+            "loadOutput() invalid supported devices");
+    ALOGW_IF(profile->mChannelMasks.size() == 0,
+            "loadOutput() invalid supported channel masks");
+    ALOGW_IF(profile->mSamplingRates.size() == 0,
+            "loadOutput() invalid supported sampling rates");
+    ALOGW_IF(profile->mFormats.size() == 0,
+            "loadOutput() invalid supported formats");
+    if ((profile->mSupportedDevices != AUDIO_DEVICE_NONE) &&
+            (profile->mChannelMasks.size() != 0) &&
+            (profile->mSamplingRates.size() != 0) &&
+            (profile->mFormats.size() != 0)) {
+
+        ALOGV("loadOutput() adding output mSupportedDevices %04x, mFlags %04x",
+              profile->mSupportedDevices, profile->mFlags);
+
+        module->mOutputProfiles.add(profile);
+        return NO_ERROR;
+    } else {
+        delete profile;
+        return BAD_VALUE;
+    }
+}
+
+void AudioPolicyManagerBase::loadHwModule(cnode *root)
+{
+    cnode *node = config_find(root, OUTPUTS_TAG);
+    status_t status = NAME_NOT_FOUND;
+
+    HwModule *module = new HwModule(root->name);
+
+    if (node != NULL) {
+        if (strcmp(root->name, AUDIO_HARDWARE_MODULE_ID_A2DP) == 0) {
+            mHasA2dp = true;
+        } else if (strcmp(root->name, AUDIO_HARDWARE_MODULE_ID_USB) == 0) {
+            mHasUsb = true;
+        } else if (strcmp(root->name, AUDIO_HARDWARE_MODULE_ID_REMOTE_SUBMIX) == 0) {
+            mHasRemoteSubmix = true;
+        }
+
+        node = node->first_child;
+        while (node) {
+            ALOGV("loadHwModule() loading output %s", node->name);
+            status_t tmpStatus = loadOutput(node, module);
+            if (status == NAME_NOT_FOUND || status == NO_ERROR) {
+                status = tmpStatus;
+            }
+            node = node->next;
+        }
+    }
+    node = config_find(root, INPUTS_TAG);
+    if (node != NULL) {
+        node = node->first_child;
+        while (node) {
+            ALOGV("loadHwModule() loading input %s", node->name);
+            status_t tmpStatus = loadInput(node, module);
+            if (status == NAME_NOT_FOUND || status == NO_ERROR) {
+                status = tmpStatus;
+            }
+            node = node->next;
+        }
+    }
+    if (status == NO_ERROR) {
+        mHwModules.add(module);
+    } else {
+        delete module;
+    }
+}
+
+void AudioPolicyManagerBase::loadHwModules(cnode *root)
+{
+    cnode *node = config_find(root, AUDIO_HW_MODULE_TAG);
+    if (node == NULL) {
+        return;
+    }
+
+    node = node->first_child;
+    while (node) {
+        ALOGV("loadHwModules() loading module %s", node->name);
+        loadHwModule(node);
+        node = node->next;
+    }
+}
+
+void AudioPolicyManagerBase::loadGlobalConfig(cnode *root)
+{
+    cnode *node = config_find(root, GLOBAL_CONFIG_TAG);
+    if (node == NULL) {
+        return;
+    }
+    node = node->first_child;
+    while (node) {
+        if (strcmp(ATTACHED_OUTPUT_DEVICES_TAG, node->name) == 0) {
+            mAttachedOutputDevices = parseDeviceNames((char *)node->value);
+            ALOGW_IF(mAttachedOutputDevices == AUDIO_DEVICE_NONE,
+                    "loadGlobalConfig() no attached output devices");
+            ALOGV("loadGlobalConfig() mAttachedOutputDevices %04x", mAttachedOutputDevices);
+        } else if (strcmp(DEFAULT_OUTPUT_DEVICE_TAG, node->name) == 0) {
+            mDefaultOutputDevice = (audio_devices_t)stringToEnum(sDeviceNameToEnumTable,
+                                              ARRAY_SIZE(sDeviceNameToEnumTable),
+                                              (char *)node->value);
+            ALOGW_IF(mDefaultOutputDevice == AUDIO_DEVICE_NONE,
+                    "loadGlobalConfig() default device not specified");
+            ALOGV("loadGlobalConfig() mDefaultOutputDevice %04x", mDefaultOutputDevice);
+        } else if (strcmp(ATTACHED_INPUT_DEVICES_TAG, node->name) == 0) {
+            mAvailableInputDevices = parseDeviceNames((char *)node->value) & ~AUDIO_DEVICE_BIT_IN;
+            ALOGV("loadGlobalConfig() mAvailableInputDevices %04x", mAvailableInputDevices);
+        } else if (strcmp(SPEAKER_DRC_ENABLED_TAG, node->name) == 0) {
+            mSpeakerDrcEnabled = stringToBool((char *)node->value);
+            ALOGV("loadGlobalConfig() mSpeakerDrcEnabled = %d", mSpeakerDrcEnabled);
+        }
+        node = node->next;
+    }
+}
+
+status_t AudioPolicyManagerBase::loadAudioPolicyConfig(const char *path)
+{
+    cnode *root;
+    char *data;
+
+    data = (char *)load_file(path, NULL);
+    if (data == NULL) {
+        return -ENODEV;
+    }
+    root = config_node("", "");
+    config_load(root, data);
+
+    loadGlobalConfig(root);
+    loadHwModules(root);
+
+    config_free(root);
+    free(root);
+    free(data);
+
+    ALOGI("loadAudioPolicyConfig() loaded %s\n", path);
+
+    return NO_ERROR;
+}
+
+void AudioPolicyManagerBase::defaultAudioPolicyConfig(void)
+{
+    HwModule *module;
+    IOProfile *profile;
+
+    mDefaultOutputDevice = AUDIO_DEVICE_OUT_SPEAKER;
+    mAttachedOutputDevices = AUDIO_DEVICE_OUT_SPEAKER;
+    mAvailableInputDevices = AUDIO_DEVICE_IN_BUILTIN_MIC & ~AUDIO_DEVICE_BIT_IN;
+
+    module = new HwModule("primary");
+
+    profile = new IOProfile(module);
+    profile->mSamplingRates.add(44100);
+    profile->mFormats.add(AUDIO_FORMAT_PCM_16_BIT);
+    profile->mChannelMasks.add(AUDIO_CHANNEL_OUT_STEREO);
+    profile->mSupportedDevices = AUDIO_DEVICE_OUT_SPEAKER;
+    profile->mFlags = AUDIO_OUTPUT_FLAG_PRIMARY;
+    module->mOutputProfiles.add(profile);
+
+    profile = new IOProfile(module);
+    profile->mSamplingRates.add(8000);
+    profile->mFormats.add(AUDIO_FORMAT_PCM_16_BIT);
+    profile->mChannelMasks.add(AUDIO_CHANNEL_IN_MONO);
+    profile->mSupportedDevices = AUDIO_DEVICE_IN_BUILTIN_MIC;
+    module->mInputProfiles.add(profile);
+
+    mHwModules.add(module);
+}
+
+}; // namespace android
diff --git a/libhardware_legacy/audio/AudioPolicyManagerDefault.cpp b/libhardware_legacy/audio/AudioPolicyManagerDefault.cpp
new file mode 100644
index 0000000..9083638
--- /dev/null
+++ b/libhardware_legacy/audio/AudioPolicyManagerDefault.cpp
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2009 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 "AudioPolicyManagerDefault"
+//#define LOG_NDEBUG 0
+
+#include "AudioPolicyManagerDefault.h"
+
+namespace android_audio_legacy {
+
+extern "C" AudioPolicyInterface* createAudioPolicyManager(AudioPolicyClientInterface *clientInterface)
+{
+    return new AudioPolicyManagerDefault(clientInterface);
+}
+
+extern "C" void destroyAudioPolicyManager(AudioPolicyInterface *interface)
+{
+    delete interface;
+}
+
+}; // namespace android
diff --git a/libhardware_legacy/audio/AudioPolicyManagerDefault.h b/libhardware_legacy/audio/AudioPolicyManagerDefault.h
new file mode 100644
index 0000000..987fdf0
--- /dev/null
+++ b/libhardware_legacy/audio/AudioPolicyManagerDefault.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <hardware_legacy/AudioPolicyManagerBase.h>
+
+namespace android_audio_legacy {
+
+class AudioPolicyManagerDefault: public AudioPolicyManagerBase
+{
+
+public:
+                explicit AudioPolicyManagerDefault(AudioPolicyClientInterface *clientInterface)
+                : AudioPolicyManagerBase(clientInterface) {}
+
+        virtual ~AudioPolicyManagerDefault() {}
+
+};
+};
diff --git a/libhardware_legacy/audio/audio_hw_hal.cpp b/libhardware_legacy/audio/audio_hw_hal.cpp
new file mode 100644
index 0000000..d15044a
--- /dev/null
+++ b/libhardware_legacy/audio/audio_hw_hal.cpp
@@ -0,0 +1,713 @@
+/*
+ * Copyright (C) 2011 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 "legacy_audio_hw_hal"
+//#define LOG_NDEBUG 0
+
+#include <stdint.h>
+
+#include <hardware/hardware.h>
+#include <system/audio.h>
+#include <hardware/audio.h>
+
+#include <hardware_legacy/AudioHardwareInterface.h>
+#include <hardware_legacy/AudioSystemLegacy.h>
+
+namespace android_audio_legacy {
+
+class AudioHardwareInterface;
+
+extern "C" {
+
+struct legacy_audio_module {
+    struct audio_module module;
+};
+
+struct legacy_audio_device {
+    struct audio_hw_device device;
+
+    AudioHardwareInterface *hwif;
+};
+
+struct legacy_stream_out {
+    struct audio_stream_out stream;
+
+    AudioStreamOut *legacy_out;
+};
+
+struct legacy_stream_in {
+    struct audio_stream_in stream;
+
+    AudioStreamIn *legacy_in;
+};
+
+
+enum {
+    HAL_API_REV_1_0,
+    HAL_API_REV_2_0,
+    HAL_API_REV_NUM
+} hal_api_rev;
+
+static uint32_t audio_device_conv_table[][HAL_API_REV_NUM] =
+{
+    /* output devices */
+    { AudioSystem::DEVICE_OUT_EARPIECE, AUDIO_DEVICE_OUT_EARPIECE },
+    { AudioSystem::DEVICE_OUT_SPEAKER, AUDIO_DEVICE_OUT_SPEAKER },
+    { AudioSystem::DEVICE_OUT_WIRED_HEADSET, AUDIO_DEVICE_OUT_WIRED_HEADSET },
+    { AudioSystem::DEVICE_OUT_WIRED_HEADPHONE, AUDIO_DEVICE_OUT_WIRED_HEADPHONE },
+    { AudioSystem::DEVICE_OUT_BLUETOOTH_SCO, AUDIO_DEVICE_OUT_BLUETOOTH_SCO },
+    { AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_HEADSET, AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET },
+    { AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_CARKIT, AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT },
+    { AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP, AUDIO_DEVICE_OUT_BLUETOOTH_A2DP },
+    { AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES, AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES },
+    { AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER, AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER },
+    { AudioSystem::DEVICE_OUT_AUX_DIGITAL, AUDIO_DEVICE_OUT_AUX_DIGITAL },
+    { AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET, AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET },
+    { AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET, AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET },
+    { AudioSystem::DEVICE_OUT_DEFAULT, AUDIO_DEVICE_OUT_DEFAULT },
+    /* input devices */
+    { AudioSystem::DEVICE_IN_COMMUNICATION, AUDIO_DEVICE_IN_COMMUNICATION },
+    { AudioSystem::DEVICE_IN_AMBIENT, AUDIO_DEVICE_IN_AMBIENT },
+    { AudioSystem::DEVICE_IN_BUILTIN_MIC, AUDIO_DEVICE_IN_BUILTIN_MIC },
+    { AudioSystem::DEVICE_IN_BLUETOOTH_SCO_HEADSET, AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET },
+    { AudioSystem::DEVICE_IN_WIRED_HEADSET, AUDIO_DEVICE_IN_WIRED_HEADSET },
+    { AudioSystem::DEVICE_IN_AUX_DIGITAL, AUDIO_DEVICE_IN_AUX_DIGITAL },
+    { AudioSystem::DEVICE_IN_VOICE_CALL, AUDIO_DEVICE_IN_VOICE_CALL },
+    { AudioSystem::DEVICE_IN_BACK_MIC, AUDIO_DEVICE_IN_BACK_MIC },
+    { AudioSystem::DEVICE_IN_DEFAULT, AUDIO_DEVICE_IN_DEFAULT },
+};
+
+static uint32_t convert_audio_device(uint32_t from_device, int from_rev, int to_rev)
+{
+    const uint32_t k_num_devices = sizeof(audio_device_conv_table)/sizeof(uint32_t)/HAL_API_REV_NUM;
+    uint32_t to_device = AUDIO_DEVICE_NONE;
+    uint32_t in_bit = 0;
+
+    if (from_rev != HAL_API_REV_1_0) {
+        in_bit = from_device & AUDIO_DEVICE_BIT_IN;
+        from_device &= ~AUDIO_DEVICE_BIT_IN;
+    }
+
+    while (from_device) {
+        uint32_t i = 31 - __builtin_clz(from_device);
+        uint32_t cur_device = (1 << i) | in_bit;
+
+        for (i = 0; i < k_num_devices; i++) {
+            if (audio_device_conv_table[i][from_rev] == cur_device) {
+                to_device |= audio_device_conv_table[i][to_rev];
+                break;
+            }
+        }
+        from_device &= ~cur_device;
+    }
+    return to_device;
+}
+
+
+/** audio_stream_out implementation **/
+static uint32_t out_get_sample_rate(const struct audio_stream *stream)
+{
+    const struct legacy_stream_out *out =
+        reinterpret_cast<const struct legacy_stream_out *>(stream);
+    return out->legacy_out->sampleRate();
+}
+
+static int out_set_sample_rate(struct audio_stream *stream, uint32_t rate)
+{
+    struct legacy_stream_out *out =
+        reinterpret_cast<struct legacy_stream_out *>(stream);
+
+    ALOGE("(%s:%d) %s: Implement me!", __FILE__, __LINE__, __func__);
+    /* TODO: implement this */
+    return 0;
+}
+
+static size_t out_get_buffer_size(const struct audio_stream *stream)
+{
+    const struct legacy_stream_out *out =
+        reinterpret_cast<const struct legacy_stream_out *>(stream);
+    return out->legacy_out->bufferSize();
+}
+
+static audio_channel_mask_t out_get_channels(const struct audio_stream *stream)
+{
+    const struct legacy_stream_out *out =
+        reinterpret_cast<const struct legacy_stream_out *>(stream);
+    return (audio_channel_mask_t) out->legacy_out->channels();
+}
+
+static audio_format_t out_get_format(const struct audio_stream *stream)
+{
+    const struct legacy_stream_out *out =
+        reinterpret_cast<const struct legacy_stream_out *>(stream);
+    // legacy API, don't change return type
+    return (audio_format_t) out->legacy_out->format();
+}
+
+static int out_set_format(struct audio_stream *stream, audio_format_t format)
+{
+    struct legacy_stream_out *out =
+        reinterpret_cast<struct legacy_stream_out *>(stream);
+    ALOGE("(%s:%d) %s: Implement me!", __FILE__, __LINE__, __func__);
+    /* TODO: implement me */
+    return 0;
+}
+
+static int out_standby(struct audio_stream *stream)
+{
+    struct legacy_stream_out *out =
+        reinterpret_cast<struct legacy_stream_out *>(stream);
+    return out->legacy_out->standby();
+}
+
+static int out_dump(const struct audio_stream *stream, int fd)
+{
+    const struct legacy_stream_out *out =
+        reinterpret_cast<const struct legacy_stream_out *>(stream);
+    Vector<String16> args;
+    return out->legacy_out->dump(fd, args);
+}
+
+static int out_set_parameters(struct audio_stream *stream, const char *kvpairs)
+{
+    struct legacy_stream_out *out =
+        reinterpret_cast<struct legacy_stream_out *>(stream);
+    int val;
+    String8 s8 = String8(kvpairs);
+    AudioParameter parms = AudioParameter(String8(kvpairs));
+
+    if (parms.getInt(String8(AUDIO_PARAMETER_STREAM_ROUTING), val) == NO_ERROR) {
+        val = convert_audio_device(val, HAL_API_REV_2_0, HAL_API_REV_1_0);
+        parms.remove(String8(AUDIO_PARAMETER_STREAM_ROUTING));
+        parms.addInt(String8(AUDIO_PARAMETER_STREAM_ROUTING), val);
+        s8 = parms.toString();
+    }
+
+    return out->legacy_out->setParameters(s8);
+}
+
+static char * out_get_parameters(const struct audio_stream *stream, const char *keys)
+{
+    const struct legacy_stream_out *out =
+        reinterpret_cast<const struct legacy_stream_out *>(stream);
+    String8 s8;
+    int val;
+
+    s8 = out->legacy_out->getParameters(String8(keys));
+
+    AudioParameter parms = AudioParameter(s8);
+    if (parms.getInt(String8(AUDIO_PARAMETER_STREAM_ROUTING), val) == NO_ERROR) {
+        val = convert_audio_device(val, HAL_API_REV_1_0, HAL_API_REV_2_0);
+        parms.remove(String8(AUDIO_PARAMETER_STREAM_ROUTING));
+        parms.addInt(String8(AUDIO_PARAMETER_STREAM_ROUTING), val);
+        s8 = parms.toString();
+    }
+
+    return strdup(s8.string());
+}
+
+static uint32_t out_get_latency(const struct audio_stream_out *stream)
+{
+    const struct legacy_stream_out *out =
+        reinterpret_cast<const struct legacy_stream_out *>(stream);
+    return out->legacy_out->latency();
+}
+
+static int out_set_volume(struct audio_stream_out *stream, float left,
+                          float right)
+{
+    struct legacy_stream_out *out =
+        reinterpret_cast<struct legacy_stream_out *>(stream);
+    return out->legacy_out->setVolume(left, right);
+}
+
+static ssize_t out_write(struct audio_stream_out *stream, const void* buffer,
+                         size_t bytes)
+{
+    struct legacy_stream_out *out =
+        reinterpret_cast<struct legacy_stream_out *>(stream);
+    return out->legacy_out->write(buffer, bytes);
+}
+
+static int out_get_render_position(const struct audio_stream_out *stream,
+                                   uint32_t *dsp_frames)
+{
+    const struct legacy_stream_out *out =
+        reinterpret_cast<const struct legacy_stream_out *>(stream);
+    return out->legacy_out->getRenderPosition(dsp_frames);
+}
+
+static int out_get_next_write_timestamp(const struct audio_stream_out *stream,
+                                        int64_t *timestamp)
+{
+    const struct legacy_stream_out *out =
+        reinterpret_cast<const struct legacy_stream_out *>(stream);
+    return out->legacy_out->getNextWriteTimestamp(timestamp);
+}
+
+static int out_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
+{
+    return 0;
+}
+
+static int out_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
+{
+    return 0;
+}
+
+/** audio_stream_in implementation **/
+static uint32_t in_get_sample_rate(const struct audio_stream *stream)
+{
+    const struct legacy_stream_in *in =
+        reinterpret_cast<const struct legacy_stream_in *>(stream);
+    return in->legacy_in->sampleRate();
+}
+
+static int in_set_sample_rate(struct audio_stream *stream, uint32_t rate)
+{
+    struct legacy_stream_in *in =
+        reinterpret_cast<struct legacy_stream_in *>(stream);
+
+    ALOGE("(%s:%d) %s: Implement me!", __FILE__, __LINE__, __func__);
+    /* TODO: implement this */
+    return 0;
+}
+
+static size_t in_get_buffer_size(const struct audio_stream *stream)
+{
+    const struct legacy_stream_in *in =
+        reinterpret_cast<const struct legacy_stream_in *>(stream);
+    return in->legacy_in->bufferSize();
+}
+
+static audio_channel_mask_t in_get_channels(const struct audio_stream *stream)
+{
+    const struct legacy_stream_in *in =
+        reinterpret_cast<const struct legacy_stream_in *>(stream);
+    return (audio_channel_mask_t) in->legacy_in->channels();
+}
+
+static audio_format_t in_get_format(const struct audio_stream *stream)
+{
+    const struct legacy_stream_in *in =
+        reinterpret_cast<const struct legacy_stream_in *>(stream);
+    // legacy API, don't change return type
+    return (audio_format_t) in->legacy_in->format();
+}
+
+static int in_set_format(struct audio_stream *stream, audio_format_t format)
+{
+    struct legacy_stream_in *in =
+        reinterpret_cast<struct legacy_stream_in *>(stream);
+    ALOGE("(%s:%d) %s: Implement me!", __FILE__, __LINE__, __func__);
+    /* TODO: implement me */
+    return 0;
+}
+
+static int in_standby(struct audio_stream *stream)
+{
+    struct legacy_stream_in *in = reinterpret_cast<struct legacy_stream_in *>(stream);
+    return in->legacy_in->standby();
+}
+
+static int in_dump(const struct audio_stream *stream, int fd)
+{
+    const struct legacy_stream_in *in =
+        reinterpret_cast<const struct legacy_stream_in *>(stream);
+    Vector<String16> args;
+    return in->legacy_in->dump(fd, args);
+}
+
+static int in_set_parameters(struct audio_stream *stream, const char *kvpairs)
+{
+    struct legacy_stream_in *in =
+        reinterpret_cast<struct legacy_stream_in *>(stream);
+    int val;
+    AudioParameter parms = AudioParameter(String8(kvpairs));
+    String8 s8 = String8(kvpairs);
+
+    if (parms.getInt(String8(AUDIO_PARAMETER_STREAM_ROUTING), val) == NO_ERROR) {
+        val = convert_audio_device(val, HAL_API_REV_2_0, HAL_API_REV_1_0);
+        parms.remove(String8(AUDIO_PARAMETER_STREAM_ROUTING));
+        parms.addInt(String8(AUDIO_PARAMETER_STREAM_ROUTING), val);
+        s8 = parms.toString();
+    }
+
+    return in->legacy_in->setParameters(s8);
+}
+
+static char * in_get_parameters(const struct audio_stream *stream,
+                                const char *keys)
+{
+    const struct legacy_stream_in *in =
+        reinterpret_cast<const struct legacy_stream_in *>(stream);
+    String8 s8;
+    int val;
+
+    s8 = in->legacy_in->getParameters(String8(keys));
+
+    AudioParameter parms = AudioParameter(s8);
+    if (parms.getInt(String8(AUDIO_PARAMETER_STREAM_ROUTING), val) == NO_ERROR) {
+        val = convert_audio_device(val, HAL_API_REV_1_0, HAL_API_REV_2_0);
+        parms.remove(String8(AUDIO_PARAMETER_STREAM_ROUTING));
+        parms.addInt(String8(AUDIO_PARAMETER_STREAM_ROUTING), val);
+        s8 = parms.toString();
+    }
+
+    return strdup(s8.string());
+}
+
+static int in_set_gain(struct audio_stream_in *stream, float gain)
+{
+    struct legacy_stream_in *in =
+        reinterpret_cast<struct legacy_stream_in *>(stream);
+    return in->legacy_in->setGain(gain);
+}
+
+static ssize_t in_read(struct audio_stream_in *stream, void* buffer,
+                       size_t bytes)
+{
+    struct legacy_stream_in *in =
+        reinterpret_cast<struct legacy_stream_in *>(stream);
+    return in->legacy_in->read(buffer, bytes);
+}
+
+static uint32_t in_get_input_frames_lost(struct audio_stream_in *stream)
+{
+    struct legacy_stream_in *in =
+        reinterpret_cast<struct legacy_stream_in *>(stream);
+    return in->legacy_in->getInputFramesLost();
+}
+
+static int in_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
+{
+    const struct legacy_stream_in *in =
+        reinterpret_cast<const struct legacy_stream_in *>(stream);
+    return in->legacy_in->addAudioEffect(effect);
+}
+
+static int in_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
+{
+    const struct legacy_stream_in *in =
+        reinterpret_cast<const struct legacy_stream_in *>(stream);
+    return in->legacy_in->removeAudioEffect(effect);
+}
+
+/** audio_hw_device implementation **/
+static inline struct legacy_audio_device * to_ladev(struct audio_hw_device *dev)
+{
+    return reinterpret_cast<struct legacy_audio_device *>(dev);
+}
+
+static inline const struct legacy_audio_device * to_cladev(const struct audio_hw_device *dev)
+{
+    return reinterpret_cast<const struct legacy_audio_device *>(dev);
+}
+
+static int adev_init_check(const struct audio_hw_device *dev)
+{
+    const struct legacy_audio_device *ladev = to_cladev(dev);
+
+    return ladev->hwif->initCheck();
+}
+
+static int adev_set_voice_volume(struct audio_hw_device *dev, float volume)
+{
+    struct legacy_audio_device *ladev = to_ladev(dev);
+    return ladev->hwif->setVoiceVolume(volume);
+}
+
+static int adev_set_master_volume(struct audio_hw_device *dev, float volume)
+{
+    struct legacy_audio_device *ladev = to_ladev(dev);
+    return ladev->hwif->setMasterVolume(volume);
+}
+
+static int adev_get_master_volume(struct audio_hw_device *dev, float* volume)
+{
+    struct legacy_audio_device *ladev = to_ladev(dev);
+    return ladev->hwif->getMasterVolume(volume);
+}
+
+static int adev_set_mode(struct audio_hw_device *dev, audio_mode_t mode)
+{
+    struct legacy_audio_device *ladev = to_ladev(dev);
+    // as this is the legacy API, don't change it to use audio_mode_t instead of int
+    return ladev->hwif->setMode((int) mode);
+}
+
+static int adev_set_mic_mute(struct audio_hw_device *dev, bool state)
+{
+    struct legacy_audio_device *ladev = to_ladev(dev);
+    return ladev->hwif->setMicMute(state);
+}
+
+static int adev_get_mic_mute(const struct audio_hw_device *dev, bool *state)
+{
+    const struct legacy_audio_device *ladev = to_cladev(dev);
+    return ladev->hwif->getMicMute(state);
+}
+
+static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs)
+{
+    struct legacy_audio_device *ladev = to_ladev(dev);
+    return ladev->hwif->setParameters(String8(kvpairs));
+}
+
+static char * adev_get_parameters(const struct audio_hw_device *dev,
+                                  const char *keys)
+{
+    const struct legacy_audio_device *ladev = to_cladev(dev);
+    String8 s8;
+
+    s8 = ladev->hwif->getParameters(String8(keys));
+    return strdup(s8.string());
+}
+
+static size_t adev_get_input_buffer_size(const struct audio_hw_device *dev,
+                                         const struct audio_config *config)
+{
+    const struct legacy_audio_device *ladev = to_cladev(dev);
+    return ladev->hwif->getInputBufferSize(config->sample_rate, (int) config->format,
+                                           audio_channel_count_from_in_mask(config->channel_mask));
+}
+
+static int adev_open_output_stream(struct audio_hw_device *dev,
+                                   audio_io_handle_t handle,
+                                   audio_devices_t devices,
+                                   audio_output_flags_t flags,
+                                   struct audio_config *config,
+                                   struct audio_stream_out **stream_out,
+                                   const char *address __unused)
+{
+    struct legacy_audio_device *ladev = to_ladev(dev);
+    status_t status;
+    struct legacy_stream_out *out;
+    int ret;
+
+    out = (struct legacy_stream_out *)calloc(1, sizeof(*out));
+    if (!out)
+        return -ENOMEM;
+
+    devices = convert_audio_device(devices, HAL_API_REV_2_0, HAL_API_REV_1_0);
+
+    out->legacy_out = ladev->hwif->openOutputStreamWithFlags(devices, flags,
+                                                    (int *) &config->format,
+                                                    &config->channel_mask,
+                                                    &config->sample_rate, &status);
+    if (!out->legacy_out) {
+        ret = status;
+        goto err_open;
+    }
+
+    out->stream.common.get_sample_rate = out_get_sample_rate;
+    out->stream.common.set_sample_rate = out_set_sample_rate;
+    out->stream.common.get_buffer_size = out_get_buffer_size;
+    out->stream.common.get_channels = out_get_channels;
+    out->stream.common.get_format = out_get_format;
+    out->stream.common.set_format = out_set_format;
+    out->stream.common.standby = out_standby;
+    out->stream.common.dump = out_dump;
+    out->stream.common.set_parameters = out_set_parameters;
+    out->stream.common.get_parameters = out_get_parameters;
+    out->stream.common.add_audio_effect = out_add_audio_effect;
+    out->stream.common.remove_audio_effect = out_remove_audio_effect;
+    out->stream.get_latency = out_get_latency;
+    out->stream.set_volume = out_set_volume;
+    out->stream.write = out_write;
+    out->stream.get_render_position = out_get_render_position;
+    out->stream.get_next_write_timestamp = out_get_next_write_timestamp;
+
+    *stream_out = &out->stream;
+    return 0;
+
+err_open:
+    free(out);
+    *stream_out = NULL;
+    return ret;
+}
+
+static void adev_close_output_stream(struct audio_hw_device *dev,
+                                     struct audio_stream_out* stream)
+{
+    struct legacy_audio_device *ladev = to_ladev(dev);
+    struct legacy_stream_out *out = reinterpret_cast<struct legacy_stream_out *>(stream);
+
+    ladev->hwif->closeOutputStream(out->legacy_out);
+    free(out);
+}
+
+/** This method creates and opens the audio hardware input stream */
+static int adev_open_input_stream(struct audio_hw_device *dev,
+                                  audio_io_handle_t handle,
+                                  audio_devices_t devices,
+                                  struct audio_config *config,
+                                  struct audio_stream_in **stream_in,
+                                  audio_input_flags_t flags __unused,
+                                  const char *address __unused,
+                                  audio_source_t source __unused)
+{
+    struct legacy_audio_device *ladev = to_ladev(dev);
+    status_t status;
+    struct legacy_stream_in *in;
+    int ret;
+
+    in = (struct legacy_stream_in *)calloc(1, sizeof(*in));
+    if (!in)
+        return -ENOMEM;
+
+    devices = convert_audio_device(devices, HAL_API_REV_2_0, HAL_API_REV_1_0);
+
+    in->legacy_in = ladev->hwif->openInputStream(devices, (int *) &config->format,
+                                                 &config->channel_mask, &config->sample_rate,
+                                                 &status, (AudioSystem::audio_in_acoustics)0);
+    if (!in->legacy_in) {
+        ret = status;
+        goto err_open;
+    }
+
+    in->stream.common.get_sample_rate = in_get_sample_rate;
+    in->stream.common.set_sample_rate = in_set_sample_rate;
+    in->stream.common.get_buffer_size = in_get_buffer_size;
+    in->stream.common.get_channels = in_get_channels;
+    in->stream.common.get_format = in_get_format;
+    in->stream.common.set_format = in_set_format;
+    in->stream.common.standby = in_standby;
+    in->stream.common.dump = in_dump;
+    in->stream.common.set_parameters = in_set_parameters;
+    in->stream.common.get_parameters = in_get_parameters;
+    in->stream.common.add_audio_effect = in_add_audio_effect;
+    in->stream.common.remove_audio_effect = in_remove_audio_effect;
+    in->stream.set_gain = in_set_gain;
+    in->stream.read = in_read;
+    in->stream.get_input_frames_lost = in_get_input_frames_lost;
+
+    *stream_in = &in->stream;
+    return 0;
+
+err_open:
+    free(in);
+    *stream_in = NULL;
+    return ret;
+}
+
+static void adev_close_input_stream(struct audio_hw_device *dev,
+                               struct audio_stream_in *stream)
+{
+    struct legacy_audio_device *ladev = to_ladev(dev);
+    struct legacy_stream_in *in =
+        reinterpret_cast<struct legacy_stream_in *>(stream);
+
+    ladev->hwif->closeInputStream(in->legacy_in);
+    free(in);
+}
+
+static int adev_dump(const struct audio_hw_device *dev, int fd)
+{
+    const struct legacy_audio_device *ladev = to_cladev(dev);
+    Vector<String16> args;
+
+    return ladev->hwif->dumpState(fd, args);
+}
+
+static int legacy_adev_close(hw_device_t* device)
+{
+    struct audio_hw_device *hwdev =
+                        reinterpret_cast<struct audio_hw_device *>(device);
+    struct legacy_audio_device *ladev = to_ladev(hwdev);
+
+    if (!ladev)
+        return 0;
+
+    if (ladev->hwif)
+        delete ladev->hwif;
+
+    free(ladev);
+    return 0;
+}
+
+static int legacy_adev_open(const hw_module_t* module, const char* name,
+                            hw_device_t** device)
+{
+    struct legacy_audio_device *ladev;
+    int ret;
+
+    if (strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0)
+        return -EINVAL;
+
+    ladev = (struct legacy_audio_device *)calloc(1, sizeof(*ladev));
+    if (!ladev)
+        return -ENOMEM;
+
+    ladev->device.common.tag = HARDWARE_DEVICE_TAG;
+    ladev->device.common.version = AUDIO_DEVICE_API_VERSION_2_0;
+    ladev->device.common.module = const_cast<hw_module_t*>(module);
+    ladev->device.common.close = legacy_adev_close;
+
+    ladev->device.init_check = adev_init_check;
+    ladev->device.set_voice_volume = adev_set_voice_volume;
+    ladev->device.set_master_volume = adev_set_master_volume;
+    ladev->device.get_master_volume = adev_get_master_volume;
+    ladev->device.set_mode = adev_set_mode;
+    ladev->device.set_mic_mute = adev_set_mic_mute;
+    ladev->device.get_mic_mute = adev_get_mic_mute;
+    ladev->device.set_parameters = adev_set_parameters;
+    ladev->device.get_parameters = adev_get_parameters;
+    ladev->device.get_input_buffer_size = adev_get_input_buffer_size;
+    ladev->device.open_output_stream = adev_open_output_stream;
+    ladev->device.close_output_stream = adev_close_output_stream;
+    ladev->device.open_input_stream = adev_open_input_stream;
+    ladev->device.close_input_stream = adev_close_input_stream;
+    ladev->device.dump = adev_dump;
+
+    ladev->hwif = createAudioHardware();
+    if (!ladev->hwif) {
+        ret = -EIO;
+        goto err_create_audio_hw;
+    }
+
+    *device = &ladev->device.common;
+
+    return 0;
+
+err_create_audio_hw:
+    free(ladev);
+    return ret;
+}
+
+static struct hw_module_methods_t legacy_audio_module_methods = {
+        open: legacy_adev_open
+};
+
+struct legacy_audio_module HAL_MODULE_INFO_SYM = {
+    module: {
+        common: {
+            tag: HARDWARE_MODULE_TAG,
+            module_api_version: AUDIO_MODULE_API_VERSION_0_1,
+            hal_api_version: HARDWARE_HAL_API_VERSION,
+            id: AUDIO_HARDWARE_MODULE_ID,
+            name: "LEGACY Audio HW HAL",
+            author: "The Android Open Source Project",
+            methods: &legacy_audio_module_methods,
+            dso : NULL,
+            reserved : {0},
+        },
+    },
+};
+
+}; // extern "C"
+
+}; // namespace android_audio_legacy
diff --git a/libhardware_legacy/audio/audio_policy.conf b/libhardware_legacy/audio/audio_policy.conf
new file mode 100644
index 0000000..3e29976
--- /dev/null
+++ b/libhardware_legacy/audio/audio_policy.conf
@@ -0,0 +1,64 @@
+#
+# Audio policy configuration for generic device builds (goldfish audio HAL - emulator)
+#
+
+# Global configuration section: lists input and output devices always present on the device
+# as well as the output device selected by default.
+# Devices are designated by a string that corresponds to the enum in audio.h
+
+global_configuration {
+  attached_output_devices AUDIO_DEVICE_OUT_SPEAKER
+  default_output_device AUDIO_DEVICE_OUT_SPEAKER
+  attached_input_devices AUDIO_DEVICE_IN_BUILTIN_MIC|AUDIO_DEVICE_IN_REMOTE_SUBMIX
+}
+
+# audio hardware module section: contains descriptors for all audio hw modules present on the
+# device. Each hw module node is named after the corresponding hw module library base name.
+# For instance, "primary" corresponds to audio.primary.<device>.so.
+# The "primary" module is mandatory and must include at least one output with
+# AUDIO_OUTPUT_FLAG_PRIMARY flag.
+# Each module descriptor contains one or more output profile descriptors and zero or more
+# input profile descriptors. Each profile lists all the parameters supported by a given output
+# or input stream category.
+# The "channel_masks", "formats", "devices" and "flags" are specified using strings corresponding
+# to enums in audio.h and audio_policy.h. They are concatenated by use of "|" without space or "\n".
+
+audio_hw_modules {
+  primary {
+    outputs {
+      primary {
+        sampling_rates 44100
+        channel_masks AUDIO_CHANNEL_OUT_STEREO
+        formats AUDIO_FORMAT_PCM_16_BIT
+        devices AUDIO_DEVICE_OUT_SPEAKER
+        flags AUDIO_OUTPUT_FLAG_PRIMARY
+      }
+    }
+    inputs {
+      primary {
+        sampling_rates 8000|16000
+        channel_masks AUDIO_CHANNEL_IN_MONO
+        formats AUDIO_FORMAT_PCM_16_BIT
+        devices AUDIO_DEVICE_IN_BUILTIN_MIC
+      }
+    }
+  }
+  r_submix {
+    outputs {
+      submix {
+        sampling_rates 48000
+        channel_masks AUDIO_CHANNEL_OUT_STEREO
+        formats AUDIO_FORMAT_PCM_16_BIT
+        devices AUDIO_DEVICE_OUT_REMOTE_SUBMIX
+      }
+    }
+    inputs {
+      submix {
+        sampling_rates 48000
+        channel_masks AUDIO_CHANNEL_IN_STEREO
+        formats AUDIO_FORMAT_PCM_16_BIT
+        devices AUDIO_DEVICE_IN_REMOTE_SUBMIX
+      }
+    }
+  }
+}
diff --git a/libhardware_legacy/audio/audio_policy_hal.cpp b/libhardware_legacy/audio/audio_policy_hal.cpp
new file mode 100644
index 0000000..87c4131
--- /dev/null
+++ b/libhardware_legacy/audio/audio_policy_hal.cpp
@@ -0,0 +1,477 @@
+/*
+ * Copyright (C) 2011 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 "legacy_audio_policy_hal"
+//#define LOG_NDEBUG 0
+
+#include <stdint.h>
+
+#include <hardware/hardware.h>
+#include <system/audio.h>
+#include <system/audio_policy.h>
+#include <hardware/audio_policy.h>
+
+#include <hardware_legacy/AudioPolicyInterface.h>
+#include <hardware_legacy/AudioSystemLegacy.h>
+
+#include "AudioPolicyCompatClient.h"
+
+namespace android_audio_legacy {
+
+extern "C" {
+
+struct legacy_ap_module {
+    struct audio_policy_module module;
+};
+
+struct legacy_ap_device {
+    struct audio_policy_device device;
+};
+
+struct legacy_audio_policy {
+    struct audio_policy policy;
+
+    void *service;
+    struct audio_policy_service_ops *aps_ops;
+    AudioPolicyCompatClient *service_client;
+    AudioPolicyInterface *apm;
+};
+
+static inline struct legacy_audio_policy * to_lap(struct audio_policy *pol)
+{
+    return reinterpret_cast<struct legacy_audio_policy *>(pol);
+}
+
+static inline const struct legacy_audio_policy * to_clap(const struct audio_policy *pol)
+{
+    return reinterpret_cast<const struct legacy_audio_policy *>(pol);
+}
+
+
+static int ap_set_device_connection_state(struct audio_policy *pol,
+                                          audio_devices_t device,
+                                          audio_policy_dev_state_t state,
+                                          const char *device_address)
+{
+    struct legacy_audio_policy *lap = to_lap(pol);
+    return lap->apm->setDeviceConnectionState(
+                    (AudioSystem::audio_devices)device,
+                    (AudioSystem::device_connection_state)state,
+                    device_address);
+}
+
+static audio_policy_dev_state_t ap_get_device_connection_state(
+                                            const struct audio_policy *pol,
+                                            audio_devices_t device,
+                                            const char *device_address)
+{
+    const struct legacy_audio_policy *lap = to_clap(pol);
+    return (audio_policy_dev_state_t)lap->apm->getDeviceConnectionState(
+                    (AudioSystem::audio_devices)device,
+                    device_address);
+}
+
+static void ap_set_phone_state(struct audio_policy *pol, audio_mode_t state)
+{
+    struct legacy_audio_policy *lap = to_lap(pol);
+    // as this is the legacy API, don't change it to use audio_mode_t instead of int
+    lap->apm->setPhoneState((int) state);
+}
+
+    /* indicate a change in ringer mode */
+static void ap_set_ringer_mode(struct audio_policy *pol, uint32_t mode,
+                               uint32_t mask)
+{
+    // deprecated, never called
+}
+
+    /* force using a specific device category for the specified usage */
+static void ap_set_force_use(struct audio_policy *pol,
+                          audio_policy_force_use_t usage,
+                          audio_policy_forced_cfg_t config)
+{
+    struct legacy_audio_policy *lap = to_lap(pol);
+    lap->apm->setForceUse((AudioSystem::force_use)usage,
+                          (AudioSystem::forced_config)config);
+}
+
+    /* retreive current device category forced for a given usage */
+static audio_policy_forced_cfg_t ap_get_force_use(
+                                               const struct audio_policy *pol,
+                                               audio_policy_force_use_t usage)
+{
+    const struct legacy_audio_policy *lap = to_clap(pol);
+    return (audio_policy_forced_cfg_t)lap->apm->getForceUse(
+                          (AudioSystem::force_use)usage);
+}
+
+/* if can_mute is true, then audio streams that are marked ENFORCED_AUDIBLE
+ * can still be muted. */
+static void ap_set_can_mute_enforced_audible(struct audio_policy *pol,
+                                             bool can_mute)
+{
+    struct legacy_audio_policy *lap = to_lap(pol);
+    lap->apm->setSystemProperty("ro.camera.sound.forced", can_mute ? "0" : "1");
+}
+
+static int ap_init_check(const struct audio_policy *pol)
+{
+    const struct legacy_audio_policy *lap = to_clap(pol);
+    return lap->apm->initCheck();
+}
+
+static audio_io_handle_t ap_get_output(struct audio_policy *pol,
+                                       audio_stream_type_t stream,
+                                       uint32_t sampling_rate,
+                                       audio_format_t format,
+                                       audio_channel_mask_t channelMask,
+                                       audio_output_flags_t flags,
+                                       const audio_offload_info_t *offloadInfo)
+{
+    struct legacy_audio_policy *lap = to_lap(pol);
+
+    ALOGV("%s: tid %d", __func__, gettid());
+    return lap->apm->getOutput((AudioSystem::stream_type)stream,
+                               sampling_rate, format, channelMask,
+                               (AudioSystem::output_flags)flags,
+                               offloadInfo);
+}
+
+static int ap_start_output(struct audio_policy *pol, audio_io_handle_t output,
+                           audio_stream_type_t stream, int session)
+{
+    struct legacy_audio_policy *lap = to_lap(pol);
+    return lap->apm->startOutput(output, (AudioSystem::stream_type)stream,
+                                 session);
+}
+
+static int ap_stop_output(struct audio_policy *pol, audio_io_handle_t output,
+                          audio_stream_type_t stream, int session)
+{
+    struct legacy_audio_policy *lap = to_lap(pol);
+    return lap->apm->stopOutput(output, (AudioSystem::stream_type)stream,
+                                session);
+}
+
+static void ap_release_output(struct audio_policy *pol,
+                              audio_io_handle_t output)
+{
+    struct legacy_audio_policy *lap = to_lap(pol);
+    lap->apm->releaseOutput(output);
+}
+
+static audio_io_handle_t ap_get_input(struct audio_policy *pol, audio_source_t inputSource,
+                                      uint32_t sampling_rate,
+                                      audio_format_t format,
+                                      audio_channel_mask_t channelMask,
+                                      audio_in_acoustics_t acoustics)
+{
+    struct legacy_audio_policy *lap = to_lap(pol);
+    return lap->apm->getInput((int) inputSource, sampling_rate, format, channelMask,
+                              (AudioSystem::audio_in_acoustics)acoustics);
+}
+
+static int ap_start_input(struct audio_policy *pol, audio_io_handle_t input)
+{
+    struct legacy_audio_policy *lap = to_lap(pol);
+    return lap->apm->startInput(input);
+}
+
+static int ap_stop_input(struct audio_policy *pol, audio_io_handle_t input)
+{
+    struct legacy_audio_policy *lap = to_lap(pol);
+    return lap->apm->stopInput(input);
+}
+
+static void ap_release_input(struct audio_policy *pol, audio_io_handle_t input)
+{
+    struct legacy_audio_policy *lap = to_lap(pol);
+    lap->apm->releaseInput(input);
+}
+
+static void ap_init_stream_volume(struct audio_policy *pol,
+                                  audio_stream_type_t stream, int index_min,
+                                  int index_max)
+{
+    struct legacy_audio_policy *lap = to_lap(pol);
+    lap->apm->initStreamVolume((AudioSystem::stream_type)stream, index_min,
+                               index_max);
+}
+
+static int ap_set_stream_volume_index(struct audio_policy *pol,
+                                      audio_stream_type_t stream,
+                                      int index)
+{
+    struct legacy_audio_policy *lap = to_lap(pol);
+    return lap->apm->setStreamVolumeIndex((AudioSystem::stream_type)stream,
+                                          index,
+                                          AUDIO_DEVICE_OUT_DEFAULT);
+}
+
+static int ap_get_stream_volume_index(const struct audio_policy *pol,
+                                      audio_stream_type_t stream,
+                                      int *index)
+{
+    const struct legacy_audio_policy *lap = to_clap(pol);
+    return lap->apm->getStreamVolumeIndex((AudioSystem::stream_type)stream,
+                                          index,
+                                          AUDIO_DEVICE_OUT_DEFAULT);
+}
+
+static int ap_set_stream_volume_index_for_device(struct audio_policy *pol,
+                                      audio_stream_type_t stream,
+                                      int index,
+                                      audio_devices_t device)
+{
+    struct legacy_audio_policy *lap = to_lap(pol);
+    return lap->apm->setStreamVolumeIndex((AudioSystem::stream_type)stream,
+                                          index,
+                                          device);
+}
+
+static int ap_get_stream_volume_index_for_device(const struct audio_policy *pol,
+                                      audio_stream_type_t stream,
+                                      int *index,
+                                      audio_devices_t device)
+{
+    const struct legacy_audio_policy *lap = to_clap(pol);
+    return lap->apm->getStreamVolumeIndex((AudioSystem::stream_type)stream,
+                                          index,
+                                          device);
+}
+
+static uint32_t ap_get_strategy_for_stream(const struct audio_policy *pol,
+                                           audio_stream_type_t stream)
+{
+    const struct legacy_audio_policy *lap = to_clap(pol);
+    return lap->apm->getStrategyForStream((AudioSystem::stream_type)stream);
+}
+
+static audio_devices_t ap_get_devices_for_stream(const struct audio_policy *pol,
+                                       audio_stream_type_t stream)
+{
+    const struct legacy_audio_policy *lap = to_clap(pol);
+    return lap->apm->getDevicesForStream((AudioSystem::stream_type)stream);
+}
+
+static audio_io_handle_t ap_get_output_for_effect(struct audio_policy *pol,
+                                            const struct effect_descriptor_s *desc)
+{
+    struct legacy_audio_policy *lap = to_lap(pol);
+    return lap->apm->getOutputForEffect(desc);
+}
+
+static int ap_register_effect(struct audio_policy *pol,
+                              const struct effect_descriptor_s *desc,
+                              audio_io_handle_t io,
+                              uint32_t strategy,
+                              int session,
+                              int id)
+{
+    struct legacy_audio_policy *lap = to_lap(pol);
+    return lap->apm->registerEffect(desc, io, strategy, session, id);
+}
+
+static int ap_unregister_effect(struct audio_policy *pol, int id)
+{
+    struct legacy_audio_policy *lap = to_lap(pol);
+    return lap->apm->unregisterEffect(id);
+}
+
+static int ap_set_effect_enabled(struct audio_policy *pol, int id, bool enabled)
+{
+    struct legacy_audio_policy *lap = to_lap(pol);
+    return lap->apm->setEffectEnabled(id, enabled);
+}
+
+static bool ap_is_stream_active(const struct audio_policy *pol, audio_stream_type_t stream,
+                                uint32_t in_past_ms)
+{
+    const struct legacy_audio_policy *lap = to_clap(pol);
+    return lap->apm->isStreamActive((int) stream, in_past_ms);
+}
+
+static bool ap_is_stream_active_remotely(const struct audio_policy *pol, audio_stream_type_t stream,
+                                uint32_t in_past_ms)
+{
+    const struct legacy_audio_policy *lap = to_clap(pol);
+    return lap->apm->isStreamActiveRemotely((int) stream, in_past_ms);
+}
+
+static bool ap_is_source_active(const struct audio_policy *pol, audio_source_t source)
+{
+    const struct legacy_audio_policy *lap = to_clap(pol);
+    return lap->apm->isSourceActive(source);
+}
+
+static int ap_dump(const struct audio_policy *pol, int fd)
+{
+    const struct legacy_audio_policy *lap = to_clap(pol);
+    return lap->apm->dump(fd);
+}
+
+static bool ap_is_offload_supported(const struct audio_policy *pol,
+                                    const audio_offload_info_t *info)
+{
+    const struct legacy_audio_policy *lap = to_clap(pol);
+    return lap->apm->isOffloadSupported(*info);
+}
+
+static int create_legacy_ap(const struct audio_policy_device *device,
+                            struct audio_policy_service_ops *aps_ops,
+                            void *service,
+                            struct audio_policy **ap)
+{
+    struct legacy_audio_policy *lap;
+    int ret;
+
+    if (!service || !aps_ops)
+        return -EINVAL;
+
+    lap = (struct legacy_audio_policy *)calloc(1, sizeof(*lap));
+    if (!lap)
+        return -ENOMEM;
+
+    lap->policy.set_device_connection_state = ap_set_device_connection_state;
+    lap->policy.get_device_connection_state = ap_get_device_connection_state;
+    lap->policy.set_phone_state = ap_set_phone_state;
+    lap->policy.set_ringer_mode = ap_set_ringer_mode;
+    lap->policy.set_force_use = ap_set_force_use;
+    lap->policy.get_force_use = ap_get_force_use;
+    lap->policy.set_can_mute_enforced_audible =
+        ap_set_can_mute_enforced_audible;
+    lap->policy.init_check = ap_init_check;
+    lap->policy.get_output = ap_get_output;
+    lap->policy.start_output = ap_start_output;
+    lap->policy.stop_output = ap_stop_output;
+    lap->policy.release_output = ap_release_output;
+    lap->policy.get_input = ap_get_input;
+    lap->policy.start_input = ap_start_input;
+    lap->policy.stop_input = ap_stop_input;
+    lap->policy.release_input = ap_release_input;
+    lap->policy.init_stream_volume = ap_init_stream_volume;
+    lap->policy.set_stream_volume_index = ap_set_stream_volume_index;
+    lap->policy.get_stream_volume_index = ap_get_stream_volume_index;
+    lap->policy.set_stream_volume_index_for_device = ap_set_stream_volume_index_for_device;
+    lap->policy.get_stream_volume_index_for_device = ap_get_stream_volume_index_for_device;
+    lap->policy.get_strategy_for_stream = ap_get_strategy_for_stream;
+    lap->policy.get_devices_for_stream = ap_get_devices_for_stream;
+    lap->policy.get_output_for_effect = ap_get_output_for_effect;
+    lap->policy.register_effect = ap_register_effect;
+    lap->policy.unregister_effect = ap_unregister_effect;
+    lap->policy.set_effect_enabled = ap_set_effect_enabled;
+    lap->policy.is_stream_active = ap_is_stream_active;
+    lap->policy.is_stream_active_remotely = ap_is_stream_active_remotely;
+    lap->policy.is_source_active = ap_is_source_active;
+    lap->policy.dump = ap_dump;
+    lap->policy.is_offload_supported = ap_is_offload_supported;
+
+    lap->service = service;
+    lap->aps_ops = aps_ops;
+    lap->service_client =
+        new AudioPolicyCompatClient(aps_ops, service);
+    if (!lap->service_client) {
+        ret = -ENOMEM;
+        goto err_new_compat_client;
+    }
+
+    lap->apm = createAudioPolicyManager(lap->service_client);
+    if (!lap->apm) {
+        ret = -ENOMEM;
+        goto err_create_apm;
+    }
+
+    *ap = &lap->policy;
+    return 0;
+
+err_create_apm:
+    delete lap->service_client;
+err_new_compat_client:
+    free(lap);
+    *ap = NULL;
+    return ret;
+}
+
+static int destroy_legacy_ap(const struct audio_policy_device *ap_dev,
+                             struct audio_policy *ap)
+{
+    struct legacy_audio_policy *lap = to_lap(ap);
+
+    if (!lap)
+        return 0;
+
+    if (lap->apm)
+        destroyAudioPolicyManager(lap->apm);
+    if (lap->service_client)
+        delete lap->service_client;
+    free(lap);
+    return 0;
+}
+
+static int legacy_ap_dev_close(hw_device_t* device)
+{
+    if (device)
+        free(device);
+    return 0;
+}
+
+static int legacy_ap_dev_open(const hw_module_t* module, const char* name,
+                                    hw_device_t** device)
+{
+    struct legacy_ap_device *dev;
+
+    if (strcmp(name, AUDIO_POLICY_INTERFACE) != 0)
+        return -EINVAL;
+
+    dev = (struct legacy_ap_device *)calloc(1, sizeof(*dev));
+    if (!dev)
+        return -ENOMEM;
+
+    dev->device.common.tag = HARDWARE_DEVICE_TAG;
+    dev->device.common.version = 0;
+    dev->device.common.module = const_cast<hw_module_t*>(module);
+    dev->device.common.close = legacy_ap_dev_close;
+    dev->device.create_audio_policy = create_legacy_ap;
+    dev->device.destroy_audio_policy = destroy_legacy_ap;
+
+    *device = &dev->device.common;
+
+    return 0;
+}
+
+static struct hw_module_methods_t legacy_ap_module_methods = {
+        .open = legacy_ap_dev_open
+};
+
+struct legacy_ap_module HAL_MODULE_INFO_SYM = {
+    .module = {
+        .common = {
+            .tag = HARDWARE_MODULE_TAG,
+            .version_major = 1,
+            .version_minor = 0,
+            .id = AUDIO_POLICY_HARDWARE_MODULE_ID,
+            .name = "LEGACY Audio Policy HAL",
+            .author = "The Android Open Source Project",
+            .methods = &legacy_ap_module_methods,
+            .dso = NULL,
+            .reserved = {0},
+        },
+    },
+};
+
+}; // extern "C"
+
+}; // namespace android_audio_legacy
diff --git a/libhardware_legacy/include/hardware_legacy/AudioHardwareBase.h b/libhardware_legacy/include/hardware_legacy/AudioHardwareBase.h
new file mode 100644
index 0000000..eac40dc
--- /dev/null
+++ b/libhardware_legacy/include/hardware_legacy/AudioHardwareBase.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2007 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_AUDIO_HARDWARE_BASE_H
+#define ANDROID_AUDIO_HARDWARE_BASE_H
+
+#include <hardware_legacy/AudioHardwareInterface.h>
+
+#include <system/audio.h>
+
+namespace android_audio_legacy {
+
+// ----------------------------------------------------------------------------
+
+/**
+ * AudioHardwareBase is a convenient base class used for implementing the
+ * AudioHardwareInterface interface.
+ */
+class AudioHardwareBase : public AudioHardwareInterface
+{
+public:
+                        AudioHardwareBase();
+    virtual             ~AudioHardwareBase() { }
+
+    /**
+     * setMode is called when the audio mode changes. NORMAL mode is for
+     * standard audio playback, RINGTONE when a ringtone is playing, IN_CALL
+     * when a telephony call is in progress, IN_COMMUNICATION when a VoIP call is in progress.
+     */
+    virtual status_t    setMode(int mode);
+
+    virtual status_t    setParameters(const String8& keyValuePairs);
+    virtual String8     getParameters(const String8& keys);
+
+    virtual  size_t     getInputBufferSize(uint32_t sampleRate, int format, int channelCount);
+    virtual status_t    getMasterVolume(float *volume);
+
+    /**This method dumps the state of the audio hardware */
+    virtual status_t dumpState(int fd, const Vector<String16>& args);
+
+protected:
+    /** returns true if the given mode maps to a telephony or VoIP call is in progress */
+    virtual bool     isModeInCall(int mode)
+                        { return ((mode == AudioSystem::MODE_IN_CALL)
+                                || (mode == AudioSystem::MODE_IN_COMMUNICATION)); };
+    /** returns true if a telephony or VoIP call is in progress */
+    virtual bool     isInCall() { return isModeInCall(mMode); };
+    int              mMode;
+};
+
+}; // namespace android
+
+#endif // ANDROID_AUDIO_HARDWARE_BASE_H
diff --git a/libhardware_legacy/include/hardware_legacy/AudioHardwareInterface.h b/libhardware_legacy/include/hardware_legacy/AudioHardwareInterface.h
new file mode 100644
index 0000000..6328063
--- /dev/null
+++ b/libhardware_legacy/include/hardware_legacy/AudioHardwareInterface.h
@@ -0,0 +1,309 @@
+/*
+ * Copyright (C) 2007 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_AUDIO_HARDWARE_INTERFACE_H
+#define ANDROID_AUDIO_HARDWARE_INTERFACE_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <utils/Vector.h>
+#include <utils/String16.h>
+#include <utils/String8.h>
+
+#include <media/IAudioFlinger.h>
+#include <hardware_legacy/AudioSystemLegacy.h>
+
+#include <system/audio.h>
+#include <hardware/audio.h>
+
+#include <cutils/bitops.h>
+
+namespace android_audio_legacy {
+    using android::Vector;
+    using android::String16;
+    using android::String8;
+
+// ----------------------------------------------------------------------------
+
+/**
+ * AudioStreamOut is the abstraction interface for the audio output hardware.
+ *
+ * It provides information about various properties of the audio output hardware driver.
+ */
+class AudioStreamOut {
+public:
+    virtual             ~AudioStreamOut() = 0;
+
+    /** return audio sampling rate in hz - eg. 44100 */
+    virtual uint32_t    sampleRate() const = 0;
+
+    /** returns size of output buffer - eg. 4800 */
+    virtual size_t      bufferSize() const = 0;
+
+    /**
+     * returns the output channel mask
+     */
+    virtual uint32_t    channels() const = 0;
+
+    /**
+     * return audio format in 8bit or 16bit PCM format -
+     * eg. AudioSystem:PCM_16_BIT
+     */
+    virtual int         format() const = 0;
+
+    /**
+     * return the frame size (number of bytes per sample).
+     */
+    uint32_t    frameSize() const { return audio_channel_count_from_out_mask(channels())*
+                            ((format()==AUDIO_FORMAT_PCM_16_BIT)?sizeof(int16_t):sizeof(int8_t)); }
+
+    /**
+     * return the audio hardware driver latency in milli seconds.
+     */
+    virtual uint32_t    latency() const = 0;
+
+    /**
+     * Use this method in situations where audio mixing is done in the
+     * hardware. This method serves as a direct interface with hardware,
+     * allowing you to directly set the volume as apposed to via the framework.
+     * This method might produce multiple PCM outputs or hardware accelerated
+     * codecs, such as MP3 or AAC.
+     */
+    virtual status_t    setVolume(float left, float right) = 0;
+
+    /** write audio buffer to driver. Returns number of bytes written */
+    virtual ssize_t     write(const void* buffer, size_t bytes) = 0;
+
+    /**
+     * Put the audio hardware output into standby mode. Returns
+     * status based on include/utils/Errors.h
+     */
+    virtual status_t    standby() = 0;
+
+    /** dump the state of the audio output device */
+    virtual status_t dump(int fd, const Vector<String16>& args) = 0;
+
+    // set/get audio output parameters. The function accepts a list of parameters
+    // key value pairs in the form: key1=value1;key2=value2;...
+    // Some keys are reserved for standard parameters (See AudioParameter class).
+    // If the implementation does not accept a parameter change while the output is
+    // active but the parameter is acceptable otherwise, it must return INVALID_OPERATION.
+    // The audio flinger will put the output in standby and then change the parameter value.
+    virtual status_t    setParameters(const String8& keyValuePairs) = 0;
+    virtual String8     getParameters(const String8& keys) = 0;
+
+    // return the number of audio frames written by the audio dsp to DAC since
+    // the output has exited standby
+    virtual status_t    getRenderPosition(uint32_t *dspFrames) = 0;
+
+    /**
+     * get the local time at which the next write to the audio driver will be
+     * presented
+     */
+    virtual status_t    getNextWriteTimestamp(int64_t *timestamp);
+
+    /**
+     * Return a recent count of the number of audio frames presented to an external observer.
+     */
+    virtual status_t    getPresentationPosition(uint64_t *frames, struct timespec *timestamp);
+
+};
+
+/**
+ * AudioStreamIn is the abstraction interface for the audio input hardware.
+ *
+ * It defines the various properties of the audio hardware input driver.
+ */
+class AudioStreamIn {
+public:
+    virtual             ~AudioStreamIn() = 0;
+
+    /** return audio sampling rate in hz - eg. 44100 */
+    virtual uint32_t    sampleRate() const = 0;
+
+    /** return the input buffer size allowed by audio driver */
+    virtual size_t      bufferSize() const = 0;
+
+    /** return input channel mask */
+    virtual uint32_t    channels() const = 0;
+
+    /**
+     * return audio format in 8bit or 16bit PCM format -
+     * eg. AudioSystem:PCM_16_BIT
+     */
+    virtual int         format() const = 0;
+
+    /**
+     * return the frame size (number of bytes per sample).
+     */
+    uint32_t    frameSize() const { return audio_channel_count_from_in_mask(channels())*
+                            ((format()==AudioSystem::PCM_16_BIT)?sizeof(int16_t):sizeof(int8_t)); }
+
+    /** set the input gain for the audio driver. This method is for
+     *  for future use */
+    virtual status_t    setGain(float gain) = 0;
+
+    /** read audio buffer in from audio driver */
+    virtual ssize_t     read(void* buffer, ssize_t bytes) = 0;
+
+    /** dump the state of the audio input device */
+    virtual status_t dump(int fd, const Vector<String16>& args) = 0;
+
+    /**
+     * Put the audio hardware input into standby mode. Returns
+     * status based on include/utils/Errors.h
+     */
+    virtual status_t    standby() = 0;
+
+    // set/get audio input parameters. The function accepts a list of parameters
+    // key value pairs in the form: key1=value1;key2=value2;...
+    // Some keys are reserved for standard parameters (See AudioParameter class).
+    // If the implementation does not accept a parameter change while the output is
+    // active but the parameter is acceptable otherwise, it must return INVALID_OPERATION.
+    // The audio flinger will put the input in standby and then change the parameter value.
+    virtual status_t    setParameters(const String8& keyValuePairs) = 0;
+    virtual String8     getParameters(const String8& keys) = 0;
+
+
+    // Return the number of input frames lost in the audio driver since the last call of this function.
+    // Audio driver is expected to reset the value to 0 and restart counting upon returning the current value by this function call.
+    // Such loss typically occurs when the user space process is blocked longer than the capacity of audio driver buffers.
+    // Unit: the number of input audio frames
+    virtual unsigned int  getInputFramesLost() const = 0;
+
+    virtual status_t addAudioEffect(effect_handle_t effect) = 0;
+    virtual status_t removeAudioEffect(effect_handle_t effect) = 0;
+};
+
+/**
+ * AudioHardwareInterface.h defines the interface to the audio hardware abstraction layer.
+ *
+ * The interface supports setting and getting parameters, selecting audio routing
+ * paths, and defining input and output streams.
+ *
+ * AudioFlinger initializes the audio hardware and immediately opens an output stream.
+ * You can set Audio routing to output to handset, speaker, Bluetooth, or a headset.
+ *
+ * The audio input stream is initialized when AudioFlinger is called to carry out
+ * a record operation.
+ */
+class AudioHardwareInterface
+{
+public:
+    virtual ~AudioHardwareInterface() {}
+
+    /**
+     * check to see if the audio hardware interface has been initialized.
+     * return status based on values defined in include/utils/Errors.h
+     */
+    virtual status_t    initCheck() = 0;
+
+    /** set the audio volume of a voice call. Range is between 0.0 and 1.0 */
+    virtual status_t    setVoiceVolume(float volume) = 0;
+
+    /**
+     * set the audio volume for all audio activities other than voice call.
+     * Range between 0.0 and 1.0. If any value other than NO_ERROR is returned,
+     * the software mixer will emulate this capability.
+     */
+    virtual status_t    setMasterVolume(float volume) = 0;
+
+    /**
+     * Get the current master volume value for the HAL, if the HAL supports
+     * master volume control.  AudioFlinger will query this value from the
+     * primary audio HAL when the service starts and use the value for setting
+     * the initial master volume across all HALs.
+     */
+    virtual status_t    getMasterVolume(float *volume) = 0;
+
+    /**
+     * setMode is called when the audio mode changes. NORMAL mode is for
+     * standard audio playback, RINGTONE when a ringtone is playing, and IN_CALL
+     * when a call is in progress.
+     */
+    virtual status_t    setMode(int mode) = 0;
+
+    // mic mute
+    virtual status_t    setMicMute(bool state) = 0;
+    virtual status_t    getMicMute(bool* state) = 0;
+
+    // set/get global audio parameters
+    virtual status_t    setParameters(const String8& keyValuePairs) = 0;
+    virtual String8     getParameters(const String8& keys) = 0;
+
+    // Returns audio input buffer size according to parameters passed or 0 if one of the
+    // parameters is not supported
+    virtual size_t    getInputBufferSize(uint32_t sampleRate, int format, int channelCount) = 0;
+
+    /** This method creates and opens the audio hardware output stream */
+    virtual AudioStreamOut* openOutputStream(
+                                uint32_t devices,
+                                int *format=0,
+                                uint32_t *channels=0,
+                                uint32_t *sampleRate=0,
+                                status_t *status=0) = 0;
+    virtual AudioStreamOut* openOutputStreamWithFlags(
+                                uint32_t devices,
+                                audio_output_flags_t flags=(audio_output_flags_t)0,
+                                int *format=0,
+                                uint32_t *channels=0,
+                                uint32_t *sampleRate=0,
+                                status_t *status=0) = 0;
+    virtual    void        closeOutputStream(AudioStreamOut* out) = 0;
+
+    /** This method creates and opens the audio hardware input stream */
+    virtual AudioStreamIn* openInputStream(
+                                uint32_t devices,
+                                int *format,
+                                uint32_t *channels,
+                                uint32_t *sampleRate,
+                                status_t *status,
+                                AudioSystem::audio_in_acoustics acoustics) = 0;
+    virtual    void        closeInputStream(AudioStreamIn* in) = 0;
+
+    /**This method dumps the state of the audio hardware */
+    virtual status_t dumpState(int fd, const Vector<String16>& args) = 0;
+
+    virtual status_t setMasterMute(bool muted) = 0;
+
+    static AudioHardwareInterface* create();
+
+    virtual int createAudioPatch(unsigned int num_sources,
+                               const struct audio_port_config *sources,
+                               unsigned int num_sinks,
+                               const struct audio_port_config *sinks,
+                               audio_patch_handle_t *handle) = 0;
+
+    virtual int releaseAudioPatch(audio_patch_handle_t handle) = 0;
+
+    virtual int getAudioPort(struct audio_port *port) = 0;
+
+    virtual int setAudioPortConfig(const struct audio_port_config *config) = 0;
+
+protected:
+
+    virtual status_t dump(int fd, const Vector<String16>& args) = 0;
+};
+
+// ----------------------------------------------------------------------------
+
+extern "C" AudioHardwareInterface* createAudioHardware(void);
+
+}; // namespace android
+
+#endif // ANDROID_AUDIO_HARDWARE_INTERFACE_H
diff --git a/libhardware_legacy/include/hardware_legacy/AudioPolicyInterface.h b/libhardware_legacy/include/hardware_legacy/AudioPolicyInterface.h
new file mode 100644
index 0000000..da03ee3
--- /dev/null
+++ b/libhardware_legacy/include/hardware_legacy/AudioPolicyInterface.h
@@ -0,0 +1,261 @@
+/*
+ * Copyright (C) 2009 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_AUDIOPOLICYINTERFACE_H
+#define ANDROID_AUDIOPOLICYINTERFACE_H
+
+#include <media/AudioSystem.h>
+#include <media/ToneGenerator.h>
+#include <utils/String8.h>
+
+#include <hardware_legacy/AudioSystemLegacy.h>
+#include <hardware/audio_policy.h>
+
+namespace android_audio_legacy {
+    using android::Vector;
+    using android::String8;
+    using android::ToneGenerator;
+
+// ----------------------------------------------------------------------------
+
+// The AudioPolicyInterface and AudioPolicyClientInterface classes define the communication interfaces
+// between the platform specific audio policy manager and Android generic audio policy manager.
+// The platform specific audio policy manager must implement methods of the AudioPolicyInterface class.
+// This implementation makes use of the AudioPolicyClientInterface to control the activity and
+// configuration of audio input and output streams.
+//
+// The platform specific audio policy manager is in charge of the audio routing and volume control
+// policies for a given platform.
+// The main roles of this module are:
+//   - keep track of current system state (removable device connections, phone state, user requests...).
+//   System state changes and user actions are notified to audio policy manager with methods of the AudioPolicyInterface.
+//   - process getOutput() queries received when AudioTrack objects are created: Those queries
+//   return a handler on an output that has been selected, configured and opened by the audio policy manager and that
+//   must be used by the AudioTrack when registering to the AudioFlinger with the createTrack() method.
+//   When the AudioTrack object is released, a putOutput() query is received and the audio policy manager can decide
+//   to close or reconfigure the output depending on other streams using this output and current system state.
+//   - similarly process getInput() and putInput() queries received from AudioRecord objects and configure audio inputs.
+//   - process volume control requests: the stream volume is converted from an index value (received from UI) to a float value
+//   applicable to each output as a function of platform specific settings and current output route (destination device). It
+//   also make sure that streams are not muted if not allowed (e.g. camera shutter sound in some countries).
+//
+// The platform specific audio policy manager is provided as a shared library by platform vendors (as for libaudio.so)
+// and is linked with libaudioflinger.so
+
+
+//    Audio Policy Manager Interface
+class AudioPolicyInterface
+{
+
+public:
+    virtual ~AudioPolicyInterface() {}
+    //
+    // configuration functions
+    //
+
+    // indicate a change in device connection status
+    virtual status_t setDeviceConnectionState(audio_devices_t device,
+                                          AudioSystem::device_connection_state state,
+                                          const char *device_address) = 0;
+    // retrieve a device connection status
+    virtual AudioSystem::device_connection_state getDeviceConnectionState(audio_devices_t device,
+                                                                          const char *device_address) = 0;
+    // indicate a change in phone state. Valid phones states are defined by AudioSystem::audio_mode
+    virtual void setPhoneState(int state) = 0;
+    // force using a specific device category for the specified usage
+    virtual void setForceUse(AudioSystem::force_use usage, AudioSystem::forced_config config) = 0;
+    // retrieve current device category forced for a given usage
+    virtual AudioSystem::forced_config getForceUse(AudioSystem::force_use usage) = 0;
+    // set a system property (e.g. camera sound always audible)
+    virtual void setSystemProperty(const char* property, const char* value) = 0;
+    // check proper initialization
+    virtual status_t initCheck() = 0;
+
+    //
+    // Audio routing query functions
+    //
+
+    // request an output appropriate for playback of the supplied stream type and parameters
+    virtual audio_io_handle_t getOutput(AudioSystem::stream_type stream,
+                                        uint32_t samplingRate,
+                                        audio_format_t format,
+                                        audio_channel_mask_t channelMask,
+                                        AudioSystem::output_flags flags,
+                                        const audio_offload_info_t *offloadInfo) = 0;
+    // indicates to the audio policy manager that the output starts being used by corresponding stream.
+    virtual status_t startOutput(audio_io_handle_t output,
+                                 AudioSystem::stream_type stream,
+                                 int session = 0) = 0;
+    // indicates to the audio policy manager that the output stops being used by corresponding stream.
+    virtual status_t stopOutput(audio_io_handle_t output,
+                                AudioSystem::stream_type stream,
+                                int session = 0) = 0;
+    // releases the output.
+    virtual void releaseOutput(audio_io_handle_t output) = 0;
+
+    // request an input appropriate for record from the supplied device with supplied parameters.
+    virtual audio_io_handle_t getInput(int inputSource,
+                                    uint32_t samplingRate,
+                                    audio_format_t format,
+                                    audio_channel_mask_t channelMask,
+                                    AudioSystem::audio_in_acoustics acoustics) = 0;
+    // indicates to the audio policy manager that the input starts being used.
+    virtual status_t startInput(audio_io_handle_t input) = 0;
+    // indicates to the audio policy manager that the input stops being used.
+    virtual status_t stopInput(audio_io_handle_t input) = 0;
+    // releases the input.
+    virtual void releaseInput(audio_io_handle_t input) = 0;
+
+    //
+    // volume control functions
+    //
+
+    // initialises stream volume conversion parameters by specifying volume index range.
+    virtual void initStreamVolume(AudioSystem::stream_type stream,
+                                      int indexMin,
+                                      int indexMax) = 0;
+
+    // sets the new stream volume at a level corresponding to the supplied index for the
+    // supplied device. By convention, specifying AUDIO_DEVICE_OUT_DEFAULT means
+    // setting volume for all devices
+    virtual status_t setStreamVolumeIndex(AudioSystem::stream_type stream,
+                                          int index,
+                                          audio_devices_t device) = 0;
+
+    // retrieve current volume index for the specified stream and the
+    // specified device. By convention, specifying AUDIO_DEVICE_OUT_DEFAULT means
+    // querying the volume of the active device.
+    virtual status_t getStreamVolumeIndex(AudioSystem::stream_type stream,
+                                          int *index,
+                                          audio_devices_t device) = 0;
+
+    // return the strategy corresponding to a given stream type
+    virtual uint32_t getStrategyForStream(AudioSystem::stream_type stream) = 0;
+
+    // return the enabled output devices for the given stream type
+    virtual audio_devices_t getDevicesForStream(AudioSystem::stream_type stream) = 0;
+
+    // Audio effect management
+    virtual audio_io_handle_t getOutputForEffect(const effect_descriptor_t *desc) = 0;
+    virtual status_t registerEffect(const effect_descriptor_t *desc,
+                                    audio_io_handle_t io,
+                                    uint32_t strategy,
+                                    int session,
+                                    int id) = 0;
+    virtual status_t unregisterEffect(int id) = 0;
+    virtual status_t setEffectEnabled(int id, bool enabled) = 0;
+
+    virtual bool isStreamActive(int stream, uint32_t inPastMs = 0) const = 0;
+    virtual bool isStreamActiveRemotely(int stream, uint32_t inPastMs = 0) const = 0;
+    virtual bool isSourceActive(audio_source_t source) const = 0;
+
+    //dump state
+    virtual status_t    dump(int fd) = 0;
+
+    virtual bool isOffloadSupported(const audio_offload_info_t& offloadInfo) = 0;
+};
+
+
+// Audio Policy client Interface
+class AudioPolicyClientInterface
+{
+public:
+    virtual ~AudioPolicyClientInterface() {}
+
+    //
+    // Audio HW module functions
+    //
+
+    // loads a HW module.
+    virtual audio_module_handle_t loadHwModule(const char *name) = 0;
+
+    //
+    // Audio output Control functions
+    //
+
+    // opens an audio output with the requested parameters. The parameter values can indicate to use the default values
+    // in case the audio policy manager has no specific requirements for the output being opened.
+    // When the function returns, the parameter values reflect the actual values used by the audio hardware output stream.
+    // The audio policy manager can check if the proposed parameters are suitable or not and act accordingly.
+    virtual audio_io_handle_t openOutput(audio_module_handle_t module,
+                                         audio_devices_t *pDevices,
+                                         uint32_t *pSamplingRate,
+                                         audio_format_t *pFormat,
+                                         audio_channel_mask_t *pChannelMask,
+                                         uint32_t *pLatencyMs,
+                                         audio_output_flags_t flags,
+                                         const audio_offload_info_t *offloadInfo = NULL) = 0;
+    // creates a special output that is duplicated to the two outputs passed as arguments. The duplication is performed by
+    // a special mixer thread in the AudioFlinger.
+    virtual audio_io_handle_t openDuplicateOutput(audio_io_handle_t output1, audio_io_handle_t output2) = 0;
+    // closes the output stream
+    virtual status_t closeOutput(audio_io_handle_t output) = 0;
+    // suspends the output. When an output is suspended, the corresponding audio hardware output stream is placed in
+    // standby and the AudioTracks attached to the mixer thread are still processed but the output mix is discarded.
+    virtual status_t suspendOutput(audio_io_handle_t output) = 0;
+    // restores a suspended output.
+    virtual status_t restoreOutput(audio_io_handle_t output) = 0;
+
+    //
+    // Audio input Control functions
+    //
+
+    // opens an audio input
+    virtual audio_io_handle_t openInput(audio_module_handle_t module,
+                                        audio_devices_t *pDevices,
+                                        uint32_t *pSamplingRate,
+                                        audio_format_t *pFormat,
+                                        audio_channel_mask_t *pChannelMask) = 0;
+    // closes an audio input
+    virtual status_t closeInput(audio_io_handle_t input) = 0;
+    //
+    // misc control functions
+    //
+
+    // set a stream volume for a particular output. For the same user setting, a given stream type can have different volumes
+    // for each output (destination device) it is attached to.
+    virtual status_t setStreamVolume(AudioSystem::stream_type stream, float volume, audio_io_handle_t output, int delayMs = 0) = 0;
+
+    // invalidate a stream type, causing a reroute to an unspecified new output
+    virtual status_t invalidateStream(AudioSystem::stream_type stream) = 0;
+
+    // function enabling to send proprietary informations directly from audio policy manager to audio hardware interface.
+    virtual void setParameters(audio_io_handle_t ioHandle, const String8& keyValuePairs, int delayMs = 0) = 0;
+    // function enabling to receive proprietary informations directly from audio hardware interface to audio policy manager.
+    virtual String8 getParameters(audio_io_handle_t ioHandle, const String8& keys) = 0;
+
+    // request the playback of a tone on the specified stream: used for instance to replace notification sounds when playing
+    // over a telephony device during a phone call.
+    virtual status_t startTone(ToneGenerator::tone_type tone, AudioSystem::stream_type stream) = 0;
+    virtual status_t stopTone() = 0;
+
+    // set down link audio volume.
+    virtual status_t setVoiceVolume(float volume, int delayMs = 0) = 0;
+
+    // move effect to the specified output
+    virtual status_t moveEffects(int session,
+                                     audio_io_handle_t srcOutput,
+                                     audio_io_handle_t dstOutput) = 0;
+
+};
+
+extern "C" AudioPolicyInterface* createAudioPolicyManager(AudioPolicyClientInterface *clientInterface);
+extern "C" void destroyAudioPolicyManager(AudioPolicyInterface *interface);
+
+
+}; // namespace android
+
+#endif // ANDROID_AUDIOPOLICYINTERFACE_H
diff --git a/libhardware_legacy/include/hardware_legacy/AudioPolicyManagerBase.h b/libhardware_legacy/include/hardware_legacy/AudioPolicyManagerBase.h
new file mode 100644
index 0000000..cf03f78
--- /dev/null
+++ b/libhardware_legacy/include/hardware_legacy/AudioPolicyManagerBase.h
@@ -0,0 +1,600 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <cutils/config_utils.h>
+#include <cutils/misc.h>
+#include <utils/Timers.h>
+#include <utils/Errors.h>
+#include <utils/KeyedVector.h>
+#include <utils/SortedVector.h>
+#include <hardware_legacy/AudioPolicyInterface.h>
+
+
+namespace android_audio_legacy {
+    using android::KeyedVector;
+    using android::DefaultKeyedVector;
+    using android::SortedVector;
+
+// ----------------------------------------------------------------------------
+
+#define MAX_DEVICE_ADDRESS_LEN 20
+// Attenuation applied to STRATEGY_SONIFICATION streams when a headset is connected: 6dB
+#define SONIFICATION_HEADSET_VOLUME_FACTOR 0.5
+// Min volume for STRATEGY_SONIFICATION streams when limited by music volume: -36dB
+#define SONIFICATION_HEADSET_VOLUME_MIN  0.016
+// Time in milliseconds during which we consider that music is still active after a music
+// track was stopped - see computeVolume()
+#define SONIFICATION_HEADSET_MUSIC_DELAY  5000
+// Time in milliseconds after media stopped playing during which we consider that the
+// sonification should be as unobtrusive as during the time media was playing.
+#define SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY 5000
+// Time in milliseconds during witch some streams are muted while the audio path
+// is switched
+#define MUTE_TIME_MS 2000
+
+#define NUM_TEST_OUTPUTS 5
+
+#define NUM_VOL_CURVE_KNEES 2
+
+// Default minimum length allowed for offloading a compressed track
+// Can be overridden by the audio.offload.min.duration.secs property
+#define OFFLOAD_DEFAULT_MIN_DURATION_SECS 60
+
+// ----------------------------------------------------------------------------
+// AudioPolicyManagerBase implements audio policy manager behavior common to all platforms.
+// Each platform must implement an AudioPolicyManager class derived from AudioPolicyManagerBase
+// and override methods for which the platform specific behavior differs from the implementation
+// in AudioPolicyManagerBase. Even if no specific behavior is required, the AudioPolicyManager
+// class must be implemented as well as the class factory function createAudioPolicyManager()
+// and provided in a shared library libaudiopolicy.so.
+// ----------------------------------------------------------------------------
+
+class AudioPolicyManagerBase: public AudioPolicyInterface
+#ifdef AUDIO_POLICY_TEST
+    , public Thread
+#endif //AUDIO_POLICY_TEST
+{
+
+public:
+                AudioPolicyManagerBase(AudioPolicyClientInterface *clientInterface);
+        virtual ~AudioPolicyManagerBase();
+
+        // AudioPolicyInterface
+        virtual status_t setDeviceConnectionState(audio_devices_t device,
+                                                          AudioSystem::device_connection_state state,
+                                                          const char *device_address);
+        virtual AudioSystem::device_connection_state getDeviceConnectionState(audio_devices_t device,
+                                                                              const char *device_address);
+        virtual void setPhoneState(int state);
+        virtual void setForceUse(AudioSystem::force_use usage, AudioSystem::forced_config config);
+        virtual AudioSystem::forced_config getForceUse(AudioSystem::force_use usage);
+        virtual void setSystemProperty(const char* property, const char* value);
+        virtual status_t initCheck();
+        virtual audio_io_handle_t getOutput(AudioSystem::stream_type stream,
+                                            uint32_t samplingRate,
+                                            audio_format_t format,
+                                            audio_channel_mask_t channelMask,
+                                            AudioSystem::output_flags flags,
+                                            const audio_offload_info_t *offloadInfo);
+        virtual status_t startOutput(audio_io_handle_t output,
+                                     AudioSystem::stream_type stream,
+                                     int session = 0);
+        virtual status_t stopOutput(audio_io_handle_t output,
+                                    AudioSystem::stream_type stream,
+                                    int session = 0);
+        virtual void releaseOutput(audio_io_handle_t output);
+        virtual audio_io_handle_t getInput(int inputSource,
+                                            uint32_t samplingRate,
+                                            audio_format_t format,
+                                            audio_channel_mask_t channelMask,
+                                            AudioSystem::audio_in_acoustics acoustics);
+
+        // indicates to the audio policy manager that the input starts being used.
+        virtual status_t startInput(audio_io_handle_t input);
+
+        // indicates to the audio policy manager that the input stops being used.
+        virtual status_t stopInput(audio_io_handle_t input);
+        virtual void releaseInput(audio_io_handle_t input);
+        virtual void closeAllInputs();
+        virtual void initStreamVolume(AudioSystem::stream_type stream,
+                                                    int indexMin,
+                                                    int indexMax);
+        virtual status_t setStreamVolumeIndex(AudioSystem::stream_type stream,
+                                              int index,
+                                              audio_devices_t device);
+        virtual status_t getStreamVolumeIndex(AudioSystem::stream_type stream,
+                                              int *index,
+                                              audio_devices_t device);
+
+        // return the strategy corresponding to a given stream type
+        virtual uint32_t getStrategyForStream(AudioSystem::stream_type stream);
+
+        // return the enabled output devices for the given stream type
+        virtual audio_devices_t getDevicesForStream(AudioSystem::stream_type stream);
+
+        virtual audio_io_handle_t getOutputForEffect(const effect_descriptor_t *desc = NULL);
+        virtual status_t registerEffect(const effect_descriptor_t *desc,
+                                        audio_io_handle_t io,
+                                        uint32_t strategy,
+                                        int session,
+                                        int id);
+        virtual status_t unregisterEffect(int id);
+        virtual status_t setEffectEnabled(int id, bool enabled);
+
+        virtual bool isStreamActive(int stream, uint32_t inPastMs = 0) const;
+        // return whether a stream is playing remotely, override to change the definition of
+        //   local/remote playback, used for instance by notification manager to not make
+        //   media players lose audio focus when not playing locally
+        virtual bool isStreamActiveRemotely(int stream, uint32_t inPastMs = 0) const;
+        virtual bool isSourceActive(audio_source_t source) const;
+
+        virtual status_t dump(int fd);
+
+        virtual bool isOffloadSupported(const audio_offload_info_t& offloadInfo);
+
+protected:
+
+        enum routing_strategy {
+            STRATEGY_MEDIA,
+            STRATEGY_PHONE,
+            STRATEGY_SONIFICATION,
+            STRATEGY_SONIFICATION_RESPECTFUL,
+            STRATEGY_DTMF,
+            STRATEGY_ENFORCED_AUDIBLE,
+            NUM_STRATEGIES
+        };
+
+        // 4 points to define the volume attenuation curve, each characterized by the volume
+        // index (from 0 to 100) at which they apply, and the attenuation in dB at that index.
+        // we use 100 steps to avoid rounding errors when computing the volume in volIndexToAmpl()
+
+        enum { VOLMIN = 0, VOLKNEE1 = 1, VOLKNEE2 = 2, VOLMAX = 3, VOLCNT = 4};
+
+        class VolumeCurvePoint
+        {
+        public:
+            int mIndex;
+            float mDBAttenuation;
+        };
+
+        // device categories used for volume curve management.
+        enum device_category {
+            DEVICE_CATEGORY_HEADSET,
+            DEVICE_CATEGORY_SPEAKER,
+            DEVICE_CATEGORY_EARPIECE,
+            DEVICE_CATEGORY_CNT
+        };
+
+        class IOProfile;
+
+        class HwModule {
+        public:
+                    HwModule(const char *name);
+                    ~HwModule();
+
+            void dump(int fd);
+
+            const char *const mName; // base name of the audio HW module (primary, a2dp ...)
+            audio_module_handle_t mHandle;
+            Vector <IOProfile *> mOutputProfiles; // output profiles exposed by this module
+            Vector <IOProfile *> mInputProfiles;  // input profiles exposed by this module
+        };
+
+        // the IOProfile class describes the capabilities of an output or input stream.
+        // It is currently assumed that all combination of listed parameters are supported.
+        // It is used by the policy manager to determine if an output or input is suitable for
+        // a given use case,  open/close it accordingly and connect/disconnect audio tracks
+        // to/from it.
+        class IOProfile
+        {
+        public:
+            IOProfile(HwModule *module);
+            ~IOProfile();
+
+            bool isCompatibleProfile(audio_devices_t device,
+                                     uint32_t samplingRate,
+                                     audio_format_t format,
+                                     audio_channel_mask_t channelMask,
+                                     audio_output_flags_t flags) const;
+
+            void dump(int fd);
+            void log();
+
+            // by convention, "0' in the first entry in mSamplingRates, mChannelMasks or mFormats
+            // indicates the supported parameters should be read from the output stream
+            // after it is opened for the first time
+            Vector <uint32_t> mSamplingRates; // supported sampling rates
+            Vector <audio_channel_mask_t> mChannelMasks; // supported channel masks
+            Vector <audio_format_t> mFormats; // supported audio formats
+            audio_devices_t mSupportedDevices; // supported devices (devices this output can be
+                                               // routed to)
+            audio_output_flags_t mFlags; // attribute flags (e.g primary output,
+                                                // direct output...). For outputs only.
+            HwModule *mModule;                     // audio HW module exposing this I/O stream
+        };
+
+        // default volume curve
+        static const VolumeCurvePoint sDefaultVolumeCurve[AudioPolicyManagerBase::VOLCNT];
+        // default volume curve for media strategy
+        static const VolumeCurvePoint sDefaultMediaVolumeCurve[AudioPolicyManagerBase::VOLCNT];
+        // volume curve for media strategy on speakers
+        static const VolumeCurvePoint sSpeakerMediaVolumeCurve[AudioPolicyManagerBase::VOLCNT];
+        // volume curve for sonification strategy on speakers
+        static const VolumeCurvePoint sSpeakerSonificationVolumeCurve[AudioPolicyManagerBase::VOLCNT];
+        static const VolumeCurvePoint sSpeakerSonificationVolumeCurveDrc[AudioPolicyManagerBase::VOLCNT];
+        static const VolumeCurvePoint sDefaultSystemVolumeCurve[AudioPolicyManagerBase::VOLCNT];
+        static const VolumeCurvePoint sDefaultSystemVolumeCurveDrc[AudioPolicyManagerBase::VOLCNT];
+        static const VolumeCurvePoint sHeadsetSystemVolumeCurve[AudioPolicyManagerBase::VOLCNT];
+        static const VolumeCurvePoint sDefaultVoiceVolumeCurve[AudioPolicyManagerBase::VOLCNT];
+        static const VolumeCurvePoint sSpeakerVoiceVolumeCurve[AudioPolicyManagerBase::VOLCNT];
+        // default volume curves per stream and device category. See initializeVolumeCurves()
+        static const VolumeCurvePoint *sVolumeProfiles[AudioSystem::NUM_STREAM_TYPES][DEVICE_CATEGORY_CNT];
+
+        // descriptor for audio outputs. Used to maintain current configuration of each opened audio output
+        // and keep track of the usage of this output by each audio stream type.
+        class AudioOutputDescriptor
+        {
+        public:
+            AudioOutputDescriptor(const IOProfile *profile);
+
+            status_t    dump(int fd);
+
+            audio_devices_t device() const;
+            void changeRefCount(AudioSystem::stream_type stream, int delta);
+
+            bool isDuplicated() const { return (mOutput1 != NULL && mOutput2 != NULL); }
+            audio_devices_t supportedDevices();
+            uint32_t latency();
+            bool sharesHwModuleWith(const AudioOutputDescriptor *outputDesc);
+            bool isActive(uint32_t inPastMs = 0) const;
+            bool isStreamActive(AudioSystem::stream_type stream,
+                                uint32_t inPastMs = 0,
+                                nsecs_t sysTime = 0) const;
+            bool isStrategyActive(routing_strategy strategy,
+                             uint32_t inPastMs = 0,
+                             nsecs_t sysTime = 0) const;
+
+            audio_io_handle_t mId;              // output handle
+            uint32_t mSamplingRate;             //
+            audio_format_t mFormat;             //
+            audio_channel_mask_t mChannelMask;     // output configuration
+            uint32_t mLatency;                  //
+            audio_output_flags_t mFlags;   //
+            audio_devices_t mDevice;                   // current device this output is routed to
+            uint32_t mRefCount[AudioSystem::NUM_STREAM_TYPES]; // number of streams of each type using this output
+            nsecs_t mStopTime[AudioSystem::NUM_STREAM_TYPES];
+            AudioOutputDescriptor *mOutput1;    // used by duplicated outputs: first output
+            AudioOutputDescriptor *mOutput2;    // used by duplicated outputs: second output
+            float mCurVolume[AudioSystem::NUM_STREAM_TYPES];   // current stream volume
+            int mMuteCount[AudioSystem::NUM_STREAM_TYPES];     // mute request counter
+            const IOProfile *mProfile;          // I/O profile this output derives from
+            bool mStrategyMutedByDevice[NUM_STRATEGIES]; // strategies muted because of incompatible
+                                                // device selection. See checkDeviceMuteStrategies()
+            uint32_t mDirectOpenCount; // number of clients using this output (direct outputs only)
+            bool mForceRouting; // Next routing for this output will be forced as current device routed is null
+        };
+
+        // descriptor for audio inputs. Used to maintain current configuration of each opened audio input
+        // and keep track of the usage of this input.
+        class AudioInputDescriptor
+        {
+        public:
+            AudioInputDescriptor(const IOProfile *profile);
+
+            status_t    dump(int fd);
+
+            audio_io_handle_t mId;                      // input handle
+            uint32_t mSamplingRate;                     //
+            audio_format_t mFormat;                     // input configuration
+            audio_channel_mask_t mChannelMask;             //
+            audio_devices_t mDevice;                    // current device this input is routed to
+            uint32_t mRefCount;                         // number of AudioRecord clients using this output
+            int      mInputSource;                      // input source selected by application (mediarecorder.h)
+            const IOProfile *mProfile;                  // I/O profile this output derives from
+        };
+
+        // stream descriptor used for volume control
+        class StreamDescriptor
+        {
+        public:
+            StreamDescriptor();
+
+            int getVolumeIndex(audio_devices_t device);
+            void dump(int fd);
+
+            int mIndexMin;      // min volume index
+            int mIndexMax;      // max volume index
+            KeyedVector<audio_devices_t, int> mIndexCur;   // current volume index per device
+            bool mCanBeMuted;   // true is the stream can be muted
+
+            const VolumeCurvePoint *mVolumeCurve[DEVICE_CATEGORY_CNT];
+        };
+
+        // stream descriptor used for volume control
+        class EffectDescriptor
+        {
+        public:
+
+            status_t dump(int fd);
+
+            int mIo;                // io the effect is attached to
+            routing_strategy mStrategy; // routing strategy the effect is associated to
+            int mSession;               // audio session the effect is on
+            effect_descriptor_t mDesc;  // effect descriptor
+            bool mEnabled;              // enabled state: CPU load being used or not
+        };
+
+        void addOutput(audio_io_handle_t id, AudioOutputDescriptor *outputDesc);
+        void addInput(audio_io_handle_t id, AudioInputDescriptor *inputDesc);
+
+        // return the strategy corresponding to a given stream type
+        static routing_strategy getStrategy(AudioSystem::stream_type stream);
+
+        // return appropriate device for streams handled by the specified strategy according to current
+        // phone state, connected devices...
+        // if fromCache is true, the device is returned from mDeviceForStrategy[],
+        // otherwise it is determine by current state
+        // (device connected,phone state, force use, a2dp output...)
+        // This allows to:
+        //  1 speed up process when the state is stable (when starting or stopping an output)
+        //  2 access to either current device selection (fromCache == true) or
+        // "future" device selection (fromCache == false) when called from a context
+        //  where conditions are changing (setDeviceConnectionState(), setPhoneState()...) AND
+        //  before updateDevicesAndOutputs() is called.
+        virtual audio_devices_t getDeviceForStrategy(routing_strategy strategy,
+                                                     bool fromCache);
+
+        // change the route of the specified output. Returns the number of ms we have slept to
+        // allow new routing to take effect in certain cases.
+        uint32_t setOutputDevice(audio_io_handle_t output,
+                             audio_devices_t device,
+                             bool force = false,
+                             int delayMs = 0);
+
+        // select input device corresponding to requested audio source
+        virtual audio_devices_t getDeviceForInputSource(int inputSource);
+
+        // return io handle of active input or 0 if no input is active
+        //    Only considers inputs from physical devices (e.g. main mic, headset mic) when
+        //    ignoreVirtualInputs is true.
+        audio_io_handle_t getActiveInput(bool ignoreVirtualInputs = true);
+
+        // initialize volume curves for each strategy and device category
+        void initializeVolumeCurves();
+
+        // compute the actual volume for a given stream according to the requested index and a particular
+        // device
+        virtual float computeVolume(int stream, int index, audio_io_handle_t output, audio_devices_t device);
+
+        // check that volume change is permitted, compute and send new volume to audio hardware
+        status_t checkAndSetVolume(int stream, int index, audio_io_handle_t output, audio_devices_t device, int delayMs = 0, bool force = false);
+
+        // apply all stream volumes to the specified output and device
+        void applyStreamVolumes(audio_io_handle_t output, audio_devices_t device, int delayMs = 0, bool force = false);
+
+        // Mute or unmute all streams handled by the specified strategy on the specified output
+        void setStrategyMute(routing_strategy strategy,
+                             bool on,
+                             audio_io_handle_t output,
+                             int delayMs = 0,
+                             audio_devices_t device = (audio_devices_t)0);
+
+        // Mute or unmute the stream on the specified output
+        void setStreamMute(int stream,
+                           bool on,
+                           audio_io_handle_t output,
+                           int delayMs = 0,
+                           audio_devices_t device = (audio_devices_t)0);
+
+        // handle special cases for sonification strategy while in call: mute streams or replace by
+        // a special tone in the device used for communication
+        void handleIncallSonification(int stream, bool starting, bool stateChange);
+
+        // true if device is in a telephony or VoIP call
+        virtual bool isInCall();
+
+        // true if given state represents a device in a telephony or VoIP call
+        virtual bool isStateInCall(int state);
+
+        // when a device is connected, checks if an open output can be routed
+        // to this device. If none is open, tries to open one of the available outputs.
+        // Returns an output suitable to this device or 0.
+        // when a device is disconnected, checks if an output is not used any more and
+        // returns its handle if any.
+        // transfers the audio tracks and effects from one output thread to another accordingly.
+        status_t checkOutputsForDevice(audio_devices_t device,
+                                       AudioSystem::device_connection_state state,
+                                       SortedVector<audio_io_handle_t>& outputs,
+                                       const String8 paramStr);
+
+        status_t checkInputsForDevice(audio_devices_t device,
+                                      AudioSystem::device_connection_state state,
+                                      SortedVector<audio_io_handle_t>& inputs,
+                                      const String8 paramStr);
+
+        // close an output and its companion duplicating output.
+        void closeOutput(audio_io_handle_t output);
+
+        // checks and if necessary changes outputs used for all strategies.
+        // must be called every time a condition that affects the output choice for a given strategy
+        // changes: connected device, phone state, force use...
+        // Must be called before updateDevicesAndOutputs()
+        void checkOutputForStrategy(routing_strategy strategy);
+
+        // Same as checkOutputForStrategy() but for a all strategies in order of priority
+        void checkOutputForAllStrategies();
+
+        // manages A2DP output suspend/restore according to phone state and BT SCO usage
+        void checkA2dpSuspend();
+
+        // returns the A2DP output handle if it is open or 0 otherwise
+        audio_io_handle_t getA2dpOutput();
+
+        // selects the most appropriate device on output for current state
+        // must be called every time a condition that affects the device choice for a given output is
+        // changed: connected device, phone state, force use, output start, output stop..
+        // see getDeviceForStrategy() for the use of fromCache parameter
+
+        audio_devices_t getNewDevice(audio_io_handle_t output, bool fromCache);
+        // updates cache of device used by all strategies (mDeviceForStrategy[])
+        // must be called every time a condition that affects the device choice for a given strategy is
+        // changed: connected device, phone state, force use...
+        // cached values are used by getDeviceForStrategy() if parameter fromCache is true.
+         // Must be called after checkOutputForAllStrategies()
+
+        void updateDevicesAndOutputs();
+
+        virtual uint32_t getMaxEffectsCpuLoad();
+        virtual uint32_t getMaxEffectsMemory();
+#ifdef AUDIO_POLICY_TEST
+        virtual     bool        threadLoop();
+                    void        exit();
+        int testOutputIndex(audio_io_handle_t output);
+#endif //AUDIO_POLICY_TEST
+
+        status_t setEffectEnabled(EffectDescriptor *pDesc, bool enabled);
+
+        // returns the category the device belongs to with regard to volume curve management
+        static device_category getDeviceCategory(audio_devices_t device);
+
+        // extract one device relevant for volume control from multiple device selection
+        static audio_devices_t getDeviceForVolume(audio_devices_t device);
+
+        SortedVector<audio_io_handle_t> getOutputsForDevice(audio_devices_t device,
+                        DefaultKeyedVector<audio_io_handle_t, AudioOutputDescriptor *> openOutputs);
+        bool vectorsEqual(SortedVector<audio_io_handle_t>& outputs1,
+                                           SortedVector<audio_io_handle_t>& outputs2);
+
+        // mute/unmute strategies using an incompatible device combination
+        // if muting, wait for the audio in pcm buffer to be drained before proceeding
+        // if unmuting, unmute only after the specified delay
+        // Returns the number of ms waited
+        uint32_t  checkDeviceMuteStrategies(AudioOutputDescriptor *outputDesc,
+                                            audio_devices_t prevDevice,
+                                            uint32_t delayMs);
+
+        audio_io_handle_t selectOutput(const SortedVector<audio_io_handle_t>& outputs,
+                                       AudioSystem::output_flags flags);
+        IOProfile *getInputProfile(audio_devices_t device,
+                                   uint32_t samplingRate,
+                                   audio_format_t format,
+                                   audio_channel_mask_t channelMask);
+        IOProfile *getProfileForDirectOutput(audio_devices_t device,
+                                                       uint32_t samplingRate,
+                                                       audio_format_t format,
+                                                       audio_channel_mask_t channelMask,
+                                                       audio_output_flags_t flags);
+
+        audio_io_handle_t selectOutputForEffects(const SortedVector<audio_io_handle_t>& outputs);
+
+        bool isNonOffloadableEffectEnabled();
+
+        //
+        // Audio policy configuration file parsing (audio_policy.conf)
+        //
+        static uint32_t stringToEnum(const struct StringToEnum *table,
+                                     size_t size,
+                                     const char *name);
+        static bool stringToBool(const char *value);
+        static audio_output_flags_t parseFlagNames(char *name);
+        static audio_devices_t parseDeviceNames(char *name);
+        void loadSamplingRates(char *name, IOProfile *profile);
+        void loadFormats(char *name, IOProfile *profile);
+        void loadOutChannels(char *name, IOProfile *profile);
+        void loadInChannels(char *name, IOProfile *profile);
+        status_t loadOutput(cnode *root,  HwModule *module);
+        status_t loadInput(cnode *root,  HwModule *module);
+        void loadHwModule(cnode *root);
+        void loadHwModules(cnode *root);
+        void loadGlobalConfig(cnode *root);
+        status_t loadAudioPolicyConfig(const char *path);
+        void defaultAudioPolicyConfig(void);
+
+
+        AudioPolicyClientInterface *mpClientInterface;  // audio policy client interface
+        audio_io_handle_t mPrimaryOutput;              // primary output handle
+        // list of descriptors for outputs currently opened
+        DefaultKeyedVector<audio_io_handle_t, AudioOutputDescriptor *> mOutputs;
+        // copy of mOutputs before setDeviceConnectionState() opens new outputs
+        // reset to mOutputs when updateDevicesAndOutputs() is called.
+        DefaultKeyedVector<audio_io_handle_t, AudioOutputDescriptor *> mPreviousOutputs;
+
+        // list of input descriptors currently opened
+        DefaultKeyedVector<audio_io_handle_t, AudioInputDescriptor *> mInputs;
+
+        audio_devices_t mAvailableOutputDevices; // bit field of all available output devices
+        audio_devices_t mAvailableInputDevices; // bit field of all available input devices
+                                                // without AUDIO_DEVICE_BIT_IN to allow direct bit
+                                                // field comparisons
+        int mPhoneState;                                                    // current phone state
+        AudioSystem::forced_config mForceUse[AudioSystem::NUM_FORCE_USE];   // current forced use configuration
+
+        StreamDescriptor mStreams[AudioSystem::NUM_STREAM_TYPES];           // stream descriptors for volume control
+        String8 mA2dpDeviceAddress;                                         // A2DP device MAC address
+        String8 mScoDeviceAddress;                                          // SCO device MAC address
+        String8 mUsbOutCardAndDevice;                                       // USB audio ALSA card and device numbers:
+                                                                            // card=<card_number>;device=<><device_number>
+        bool    mLimitRingtoneVolume;                                       // limit ringtone volume to music volume if headset connected
+        audio_devices_t mDeviceForStrategy[NUM_STRATEGIES];
+        float   mLastVoiceVolume;                                           // last voice volume value sent to audio HAL
+
+        // Maximum CPU load allocated to audio effects in 0.1 MIPS (ARMv5TE, 0 WS memory) units
+        static const uint32_t MAX_EFFECTS_CPU_LOAD = 1000;
+        // Maximum memory allocated to audio effects in KB
+        static const uint32_t MAX_EFFECTS_MEMORY = 512;
+        uint32_t mTotalEffectsCpuLoad; // current CPU load used by effects
+        uint32_t mTotalEffectsMemory;  // current memory used by effects
+        KeyedVector<int, EffectDescriptor *> mEffects;  // list of registered audio effects
+        bool    mA2dpSuspended;  // true if A2DP output is suspended
+        bool mHasA2dp; // true on platforms with support for bluetooth A2DP
+        bool mHasUsb; // true on platforms with support for USB audio
+        bool mHasRemoteSubmix; // true on platforms with support for remote presentation of a submix
+        audio_devices_t mAttachedOutputDevices; // output devices always available on the platform
+        audio_devices_t mDefaultOutputDevice; // output device selected by default at boot time
+                                              // (must be in mAttachedOutputDevices)
+        bool mSpeakerDrcEnabled;// true on devices that use DRC on the DEVICE_CATEGORY_SPEAKER path
+                                // to boost soft sounds, used to adjust volume curves accordingly
+
+        Vector <HwModule *> mHwModules;
+
+#ifdef AUDIO_POLICY_TEST
+        Mutex   mLock;
+        Condition mWaitWorkCV;
+
+        int             mCurOutput;
+        bool            mDirectOutput;
+        audio_io_handle_t mTestOutputs[NUM_TEST_OUTPUTS];
+        int             mTestInput;
+        uint32_t        mTestDevice;
+        uint32_t        mTestSamplingRate;
+        uint32_t        mTestFormat;
+        uint32_t        mTestChannels;
+        uint32_t        mTestLatencyMs;
+#endif //AUDIO_POLICY_TEST
+
+private:
+        static float volIndexToAmpl(audio_devices_t device, const StreamDescriptor& streamDesc,
+                int indexInUi);
+        // updates device caching and output for streams that can influence the
+        //    routing of notifications
+        void handleNotificationRoutingForStream(AudioSystem::stream_type stream);
+        static bool isVirtualInputDevice(audio_devices_t device);
+};
+
+};
diff --git a/libhardware_legacy/include/hardware_legacy/AudioSystemLegacy.h b/libhardware_legacy/include/hardware_legacy/AudioSystemLegacy.h
new file mode 100644
index 0000000..524e798
--- /dev/null
+++ b/libhardware_legacy/include/hardware_legacy/AudioSystemLegacy.h
@@ -0,0 +1,362 @@
+/*
+ * Copyright (C) 2008 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_AUDIOSYSTEM_LEGACY_H_
+#define ANDROID_AUDIOSYSTEM_LEGACY_H_
+
+#include <utils/Errors.h>
+#include <media/AudioParameter.h>
+
+#include <system/audio.h>
+#include <system/audio_policy.h>
+
+namespace android_audio_legacy {
+
+using android::status_t;
+using android::AudioParameter;
+
+enum {
+    OK                  = android::OK,
+    NO_ERROR            = android::NO_ERROR,
+
+    UNKNOWN_ERROR       = android::UNKNOWN_ERROR,
+
+    NO_MEMORY           = android::NO_MEMORY,
+    INVALID_OPERATION   = android::INVALID_OPERATION,
+    BAD_VALUE           = android::BAD_VALUE,
+    BAD_TYPE            = android::BAD_TYPE,
+    NAME_NOT_FOUND      = android::NAME_NOT_FOUND,
+    PERMISSION_DENIED   = android::PERMISSION_DENIED,
+    NO_INIT             = android::NO_INIT,
+    ALREADY_EXISTS      = android::ALREADY_EXISTS,
+    DEAD_OBJECT         = android::DEAD_OBJECT,
+    FAILED_TRANSACTION  = android::FAILED_TRANSACTION,
+    BAD_INDEX           = android::BAD_INDEX,
+    NOT_ENOUGH_DATA     = android::NOT_ENOUGH_DATA,
+    WOULD_BLOCK         = android::WOULD_BLOCK,
+    TIMED_OUT           = android::TIMED_OUT,
+    UNKNOWN_TRANSACTION = android::UNKNOWN_TRANSACTION,
+};
+
+enum audio_source {
+    AUDIO_SOURCE_DEFAULT = 0,
+    AUDIO_SOURCE_MIC = 1,
+    AUDIO_SOURCE_VOICE_UPLINK = 2,
+    AUDIO_SOURCE_VOICE_DOWNLINK = 3,
+    AUDIO_SOURCE_VOICE_CALL = 4,
+    AUDIO_SOURCE_CAMCORDER = 5,
+    AUDIO_SOURCE_VOICE_RECOGNITION = 6,
+    AUDIO_SOURCE_VOICE_COMMUNICATION = 7,
+    AUDIO_SOURCE_MAX = AUDIO_SOURCE_VOICE_COMMUNICATION,
+
+    AUDIO_SOURCE_LIST_END  // must be last - used to validate audio source type
+};
+
+class AudioSystem {
+public:
+#if 1
+    enum stream_type {
+        DEFAULT          =-1,
+        VOICE_CALL       = 0,
+        SYSTEM           = 1,
+        RING             = 2,
+        MUSIC            = 3,
+        ALARM            = 4,
+        NOTIFICATION     = 5,
+        BLUETOOTH_SCO    = 6,
+        ENFORCED_AUDIBLE = 7, // Sounds that cannot be muted by user and must be routed to speaker
+        DTMF             = 8,
+        TTS              = 9,
+        NUM_STREAM_TYPES
+    };
+
+    // Audio sub formats (see AudioSystem::audio_format).
+    enum pcm_sub_format {
+        PCM_SUB_16_BIT          = 0x1, // must be 1 for backward compatibility
+        PCM_SUB_8_BIT           = 0x2, // must be 2 for backward compatibility
+    };
+
+    enum audio_sessions {
+        SESSION_OUTPUT_STAGE = AUDIO_SESSION_OUTPUT_STAGE,
+        SESSION_OUTPUT_MIX = AUDIO_SESSION_OUTPUT_MIX,
+    };
+
+    // MP3 sub format field definition : can use 11 LSBs in the same way as MP3 frame header to specify
+    // bit rate, stereo mode, version...
+    enum mp3_sub_format {
+        //TODO
+    };
+
+    // AMR NB/WB sub format field definition: specify frame block interleaving, bandwidth efficient or octet aligned,
+    // encoding mode for recording...
+    enum amr_sub_format {
+        //TODO
+    };
+
+    // AAC sub format field definition: specify profile or bitrate for recording...
+    enum aac_sub_format {
+        //TODO
+    };
+
+    // VORBIS sub format field definition: specify quality for recording...
+    enum vorbis_sub_format {
+        //TODO
+    };
+
+    // Audio format consists in a main format field (upper 8 bits) and a sub format field (lower 24 bits).
+    // The main format indicates the main codec type. The sub format field indicates options and parameters
+    // for each format. The sub format is mainly used for record to indicate for instance the requested bitrate
+    // or profile. It can also be used for certain formats to give informations not present in the encoded
+    // audio stream (e.g. octet alignement for AMR).
+    enum audio_format {
+        INVALID_FORMAT      = -1,
+        FORMAT_DEFAULT      = 0,
+        PCM                 = 0x00000000, // must be 0 for backward compatibility
+        MP3                 = 0x01000000,
+        AMR_NB              = 0x02000000,
+        AMR_WB              = 0x03000000,
+        AAC                 = 0x04000000,
+        HE_AAC_V1           = 0x05000000,
+        HE_AAC_V2           = 0x06000000,
+        VORBIS              = 0x07000000,
+        MAIN_FORMAT_MASK    = 0xFF000000,
+        SUB_FORMAT_MASK     = 0x00FFFFFF,
+        // Aliases
+        PCM_16_BIT          = (PCM|PCM_SUB_16_BIT),
+        PCM_8_BIT          = (PCM|PCM_SUB_8_BIT)
+    };
+
+    enum audio_channels {
+        // output channels
+        CHANNEL_OUT_FRONT_LEFT            = 0x1,
+        CHANNEL_OUT_FRONT_RIGHT           = 0x2,
+        CHANNEL_OUT_FRONT_CENTER          = 0x4,
+        CHANNEL_OUT_LOW_FREQUENCY         = 0x8,
+        CHANNEL_OUT_BACK_LEFT             = 0x10,
+        CHANNEL_OUT_BACK_RIGHT            = 0x20,
+        CHANNEL_OUT_FRONT_LEFT_OF_CENTER  = 0x40,
+        CHANNEL_OUT_FRONT_RIGHT_OF_CENTER = 0x80,
+        CHANNEL_OUT_BACK_CENTER           = 0x100,
+        CHANNEL_OUT_SIDE_LEFT             = 0x200,
+        CHANNEL_OUT_SIDE_RIGHT            = 0x400,
+        CHANNEL_OUT_TOP_CENTER            = 0x800,
+        CHANNEL_OUT_TOP_FRONT_LEFT        = 0x1000,
+        CHANNEL_OUT_TOP_FRONT_CENTER      = 0x2000,
+        CHANNEL_OUT_TOP_FRONT_RIGHT       = 0x4000,
+        CHANNEL_OUT_TOP_BACK_LEFT         = 0x8000,
+        CHANNEL_OUT_TOP_BACK_CENTER       = 0x10000,
+        CHANNEL_OUT_TOP_BACK_RIGHT        = 0x20000,
+
+        CHANNEL_OUT_MONO = CHANNEL_OUT_FRONT_LEFT,
+        CHANNEL_OUT_STEREO = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT),
+        CHANNEL_OUT_QUAD = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT |
+                CHANNEL_OUT_BACK_LEFT | CHANNEL_OUT_BACK_RIGHT),
+        CHANNEL_OUT_SURROUND = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT |
+                CHANNEL_OUT_FRONT_CENTER | CHANNEL_OUT_BACK_CENTER),
+        CHANNEL_OUT_5POINT1 = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT |
+                CHANNEL_OUT_FRONT_CENTER | CHANNEL_OUT_LOW_FREQUENCY |
+                CHANNEL_OUT_BACK_LEFT | CHANNEL_OUT_BACK_RIGHT),
+        // matches the correct AudioFormat.CHANNEL_OUT_7POINT1_SURROUND definition for 7.1
+        CHANNEL_OUT_7POINT1 = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT |
+                CHANNEL_OUT_FRONT_CENTER | CHANNEL_OUT_LOW_FREQUENCY |
+                CHANNEL_OUT_BACK_LEFT | CHANNEL_OUT_BACK_RIGHT |
+                CHANNEL_OUT_SIDE_LEFT | CHANNEL_OUT_SIDE_RIGHT),
+        CHANNEL_OUT_ALL = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT |
+                CHANNEL_OUT_FRONT_CENTER | CHANNEL_OUT_LOW_FREQUENCY | CHANNEL_OUT_BACK_LEFT |
+                CHANNEL_OUT_BACK_RIGHT | CHANNEL_OUT_FRONT_LEFT_OF_CENTER |
+                CHANNEL_OUT_FRONT_RIGHT_OF_CENTER | CHANNEL_OUT_BACK_CENTER |
+                CHANNEL_OUT_SIDE_LEFT | CHANNEL_OUT_SIDE_RIGHT | CHANNEL_OUT_TOP_CENTER |
+                CHANNEL_OUT_TOP_FRONT_LEFT | CHANNEL_OUT_TOP_FRONT_CENTER |
+                CHANNEL_OUT_TOP_FRONT_RIGHT | CHANNEL_OUT_TOP_BACK_LEFT |
+                CHANNEL_OUT_TOP_BACK_CENTER | CHANNEL_OUT_TOP_BACK_RIGHT),
+
+        // input channels
+        CHANNEL_IN_LEFT = 0x4,
+        CHANNEL_IN_RIGHT = 0x8,
+        CHANNEL_IN_FRONT = 0x10,
+        CHANNEL_IN_BACK = 0x20,
+        CHANNEL_IN_LEFT_PROCESSED = 0x40,
+        CHANNEL_IN_RIGHT_PROCESSED = 0x80,
+        CHANNEL_IN_FRONT_PROCESSED = 0x100,
+        CHANNEL_IN_BACK_PROCESSED = 0x200,
+        CHANNEL_IN_PRESSURE = 0x400,
+        CHANNEL_IN_X_AXIS = 0x800,
+        CHANNEL_IN_Y_AXIS = 0x1000,
+        CHANNEL_IN_Z_AXIS = 0x2000,
+        CHANNEL_IN_VOICE_UPLINK = 0x4000,
+        CHANNEL_IN_VOICE_DNLINK = 0x8000,
+        CHANNEL_IN_MONO = CHANNEL_IN_FRONT,
+        CHANNEL_IN_STEREO = (CHANNEL_IN_LEFT | CHANNEL_IN_RIGHT),
+        CHANNEL_IN_ALL = (CHANNEL_IN_LEFT | CHANNEL_IN_RIGHT | CHANNEL_IN_FRONT | CHANNEL_IN_BACK|
+                CHANNEL_IN_LEFT_PROCESSED | CHANNEL_IN_RIGHT_PROCESSED | CHANNEL_IN_FRONT_PROCESSED | CHANNEL_IN_BACK_PROCESSED|
+                CHANNEL_IN_PRESSURE | CHANNEL_IN_X_AXIS | CHANNEL_IN_Y_AXIS | CHANNEL_IN_Z_AXIS |
+                CHANNEL_IN_VOICE_UPLINK | CHANNEL_IN_VOICE_DNLINK)
+    };
+
+    enum audio_mode {
+        MODE_INVALID = -2,
+        MODE_CURRENT = -1,
+        MODE_NORMAL = 0,
+        MODE_RINGTONE,
+        MODE_IN_CALL,
+        MODE_IN_COMMUNICATION,
+        NUM_MODES  // not a valid entry, denotes end-of-list
+    };
+
+    enum audio_in_acoustics {
+        AGC_ENABLE    = 0x0001,
+        AGC_DISABLE   = 0,
+        NS_ENABLE     = 0x0002,
+        NS_DISABLE    = 0,
+        TX_IIR_ENABLE = 0x0004,
+        TX_DISABLE    = 0
+    };
+
+    // DO NOT USE: the "audio_devices" enumeration below is obsolete, use type "audio_devices_t" and
+    //   audio device enumeration from system/audio.h instead.
+    enum audio_devices {
+        // output devices
+        DEVICE_OUT_EARPIECE = 0x1,
+        DEVICE_OUT_SPEAKER = 0x2,
+        DEVICE_OUT_WIRED_HEADSET = 0x4,
+        DEVICE_OUT_WIRED_HEADPHONE = 0x8,
+        DEVICE_OUT_BLUETOOTH_SCO = 0x10,
+        DEVICE_OUT_BLUETOOTH_SCO_HEADSET = 0x20,
+        DEVICE_OUT_BLUETOOTH_SCO_CARKIT = 0x40,
+        DEVICE_OUT_BLUETOOTH_A2DP = 0x80,
+        DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES = 0x100,
+        DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER = 0x200,
+        DEVICE_OUT_AUX_DIGITAL = 0x400,
+        DEVICE_OUT_ANLG_DOCK_HEADSET = 0x800,
+        DEVICE_OUT_DGTL_DOCK_HEADSET = 0x1000,
+        DEVICE_OUT_DEFAULT = 0x8000,
+        DEVICE_OUT_ALL = (DEVICE_OUT_EARPIECE | DEVICE_OUT_SPEAKER | DEVICE_OUT_WIRED_HEADSET |
+                DEVICE_OUT_WIRED_HEADPHONE | DEVICE_OUT_BLUETOOTH_SCO | DEVICE_OUT_BLUETOOTH_SCO_HEADSET |
+                DEVICE_OUT_BLUETOOTH_SCO_CARKIT | DEVICE_OUT_BLUETOOTH_A2DP | DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
+                DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER | DEVICE_OUT_AUX_DIGITAL |
+                DEVICE_OUT_ANLG_DOCK_HEADSET | DEVICE_OUT_DGTL_DOCK_HEADSET |
+                DEVICE_OUT_DEFAULT),
+        DEVICE_OUT_ALL_A2DP = (DEVICE_OUT_BLUETOOTH_A2DP | DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
+                DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER),
+
+        // input devices
+        DEVICE_IN_COMMUNICATION = 0x10000,
+        DEVICE_IN_AMBIENT = 0x20000,
+        DEVICE_IN_BUILTIN_MIC = 0x40000,
+        DEVICE_IN_BLUETOOTH_SCO_HEADSET = 0x80000,
+        DEVICE_IN_WIRED_HEADSET = 0x100000,
+        DEVICE_IN_AUX_DIGITAL = 0x200000,
+        DEVICE_IN_VOICE_CALL = 0x400000,
+        DEVICE_IN_BACK_MIC = 0x800000,
+        DEVICE_IN_DEFAULT = 0x80000000,
+
+        DEVICE_IN_ALL = (DEVICE_IN_COMMUNICATION | DEVICE_IN_AMBIENT | DEVICE_IN_BUILTIN_MIC |
+                DEVICE_IN_BLUETOOTH_SCO_HEADSET | DEVICE_IN_WIRED_HEADSET | DEVICE_IN_AUX_DIGITAL |
+                DEVICE_IN_VOICE_CALL | DEVICE_IN_BACK_MIC | DEVICE_IN_DEFAULT)
+    };
+
+    // request to open a direct output with getOutput() (by opposition to sharing an output with other AudioTracks)
+    enum output_flags {
+        OUTPUT_FLAG_INDIRECT = 0x0,
+        OUTPUT_FLAG_DIRECT = 0x1
+    };
+
+    // device categories used for setForceUse()
+    enum forced_config {
+        FORCE_NONE,
+        FORCE_SPEAKER,
+        FORCE_HEADPHONES,
+        FORCE_BT_SCO,
+        FORCE_BT_A2DP,
+        FORCE_WIRED_ACCESSORY,
+        FORCE_BT_CAR_DOCK,
+        FORCE_BT_DESK_DOCK,
+        FORCE_ANALOG_DOCK,
+        FORCE_DIGITAL_DOCK,
+        FORCE_NO_BT_A2DP,
+        FORCE_SYSTEM_ENFORCED,
+        NUM_FORCE_CONFIG,
+        FORCE_DEFAULT = FORCE_NONE
+    };
+
+    // usages used for setForceUse()
+    enum force_use {
+        FOR_COMMUNICATION,
+        FOR_MEDIA,
+        FOR_RECORD,
+        FOR_DOCK,
+        FOR_SYSTEM,
+        NUM_FORCE_USE
+    };
+
+    //
+    // AudioPolicyService interface
+    //
+
+    // device connection states used for setDeviceConnectionState()
+    enum device_connection_state {
+        DEVICE_STATE_UNAVAILABLE,
+        DEVICE_STATE_AVAILABLE,
+        NUM_DEVICE_STATES
+    };
+
+#endif
+
+    static uint32_t popCount(uint32_t u) {
+        return popcount(u);
+    }
+
+#if 1
+    static bool isOutputDevice(audio_devices device) {
+        if ((popcount(device) == 1) && ((device & ~DEVICE_OUT_ALL) == 0))
+             return true;
+         else
+             return false;
+    }
+    static bool isInputDevice(audio_devices device) {
+        if ((popcount(device) == 1) && ((device & ~DEVICE_IN_ALL) == 0))
+             return true;
+         else
+             return false;
+    }
+    static bool isA2dpDevice(audio_devices device) {
+        return audio_is_a2dp_device((audio_devices_t)device);
+    }
+    static bool isBluetoothScoDevice(audio_devices device) {
+        return audio_is_bluetooth_sco_device((audio_devices_t)device);
+    }
+    static bool isLowVisibility(stream_type stream) {
+        return audio_is_low_visibility((audio_stream_type_t)stream);
+    }
+    static bool isValidFormat(uint32_t format) {
+        return audio_is_valid_format((audio_format_t) format);
+    }
+    static bool isLinearPCM(uint32_t format) {
+        return audio_is_linear_pcm((audio_format_t) format);
+    }
+    static bool isOutputChannel(uint32_t channel) {
+        return audio_is_output_channel(channel);
+    }
+    static bool isInputChannel(uint32_t channel) {
+        return audio_is_input_channel(channel);
+    }
+
+#endif
+};
+
+};  // namespace android
+
+#endif // ANDROID_AUDIOSYSTEM_LEGACY_H_
diff --git a/libhardware_legacy/include/hardware_legacy/IMountService.h b/libhardware_legacy/include/hardware_legacy/IMountService.h
new file mode 100644
index 0000000..257319c
--- /dev/null
+++ b/libhardware_legacy/include/hardware_legacy/IMountService.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2007 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_HARDWARE_IMOUNTSERVICE_H
+#define ANDROID_HARDWARE_IMOUNTSERVICE_H
+
+#include <binder/IInterface.h>
+#include <utils/String16.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------
+
+class IMountService : public IInterface
+{
+public:
+    static const int OperationSucceeded               = 0;
+    static const int OperationFailedInternalError     = -1;
+    static const int OperationFailedNoMedia           = -2;
+    static const int OperationFailedMediaBlank        = -3;
+    static const int OperationFailedMediaCorrupt      = -4;
+    static const int OperationFailedVolumeNotMounted  = -5;
+
+
+public:
+    DECLARE_META_INTERFACE(MountService);
+
+    virtual void getShareMethodList() = 0;
+    virtual bool getShareMethodAvailable(String16 method) = 0;
+    virtual int shareVolume(String16 path, String16 method) = 0;
+    virtual int unshareVolume(String16 path, String16 method) = 0;
+    virtual bool getVolumeShared(String16 path, String16 method) = 0;
+    virtual int mountVolume(String16 path) = 0;
+    virtual int unmountVolume(String16 path) = 0;
+    virtual int formatVolume(String16 path) = 0;
+    virtual String16 getVolumeState(String16 mountPoint) = 0;
+    virtual int createSecureContainer(String16 id, int sizeMb, String16 fstype, String16 key, int ownerUid) = 0;
+    virtual int finalizeSecureContainer(String16 id) = 0;
+    virtual int destroySecureContainer(String16 id) = 0;
+    virtual int mountSecureContainer(String16 id, String16 key, int ownerUid) = 0;
+    virtual int unmountSecureContainer(String16 id) = 0;
+    virtual int renameSecureContainer(String16 oldId, String16 newId) = 0;
+    virtual String16 getSecureContainerPath(String16 id) = 0;
+    virtual void getSecureContainerList() = 0;
+    virtual void shutdown() = 0;
+};
+
+// ----------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_HARDWARE_IMOUNTSERVICE_H
diff --git a/libhardware_legacy/include/hardware_legacy/audio_policy_conf.h b/libhardware_legacy/include/hardware_legacy/audio_policy_conf.h
new file mode 100644
index 0000000..3ec2c94
--- /dev/null
+++ b/libhardware_legacy/include/hardware_legacy/audio_policy_conf.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2012 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_AUDIO_POLICY_CONF_H
+#define ANDROID_AUDIO_POLICY_CONF_H
+
+
+/////////////////////////////////////////////////
+//      Definitions for audio policy configuration file (audio_policy.conf)
+/////////////////////////////////////////////////
+
+#define AUDIO_HARDWARE_MODULE_ID_MAX_LEN 32
+
+#define AUDIO_POLICY_CONFIG_FILE "/system/etc/audio_policy.conf"
+#define AUDIO_POLICY_VENDOR_CONFIG_FILE "/vendor/etc/audio_policy.conf"
+
+// global configuration
+#define GLOBAL_CONFIG_TAG "global_configuration"
+
+#define ATTACHED_OUTPUT_DEVICES_TAG "attached_output_devices"
+#define DEFAULT_OUTPUT_DEVICE_TAG "default_output_device"
+#define ATTACHED_INPUT_DEVICES_TAG "attached_input_devices"
+#define SPEAKER_DRC_ENABLED_TAG "speaker_drc_enabled"
+
+// hw modules descriptions
+#define AUDIO_HW_MODULE_TAG "audio_hw_modules"
+
+#define OUTPUTS_TAG "outputs"
+#define INPUTS_TAG "inputs"
+
+#define SAMPLING_RATES_TAG "sampling_rates"
+#define FORMATS_TAG "formats"
+#define CHANNELS_TAG "channel_masks"
+#define DEVICES_TAG "devices"
+#define FLAGS_TAG "flags"
+
+#define DYNAMIC_VALUE_TAG "dynamic" // special value for "channel_masks", "sampling_rates" and
+                                    // "formats" in outputs descriptors indicating that supported
+                                    // values should be queried after opening the output.
+
+#endif  // ANDROID_AUDIO_POLICY_CONF_H
diff --git a/libhardware_legacy/include/hardware_legacy/gscan.h b/libhardware_legacy/include/hardware_legacy/gscan.h
new file mode 100644
index 0000000..69e4159
--- /dev/null
+++ b/libhardware_legacy/include/hardware_legacy/gscan.h
@@ -0,0 +1,461 @@
+
+#include "wifi_hal.h"
+
+#ifndef __WIFI_HAL_GSCAN_H__
+#define __WIFI_HAL_GSCAN_H__
+
+/* AP Scans */
+
+typedef enum {
+    WIFI_BAND_UNSPECIFIED,
+    WIFI_BAND_BG = 1,                       // 2.4 GHz
+    WIFI_BAND_A = 2,                        // 5 GHz without DFS
+    WIFI_BAND_A_DFS = 4,                    // 5 GHz DFS only
+    WIFI_BAND_A_WITH_DFS = 6,               // 5 GHz with DFS
+    WIFI_BAND_ABG = 3,                      // 2.4 GHz + 5 GHz; no DFS
+    WIFI_BAND_ABG_WITH_DFS = 7,             // 2.4 GHz + 5 GHz with DFS
+} wifi_band;
+
+const unsigned MAX_CHANNELS                = 16;
+const unsigned MAX_BUCKETS                 = 16;
+const unsigned MAX_HOTLIST_APS             = 128;
+const unsigned MAX_SIGNIFICANT_CHANGE_APS  = 64;
+const unsigned MAX_PNO_SSID                = 64;
+const unsigned MAX_HOTLIST_SSID            = 8;
+const unsigned MAX_BLACKLIST_BSSID         = 16;
+const unsigned MAX_AP_CACHE_PER_SCAN       = 32;
+
+wifi_error wifi_get_valid_channels(wifi_interface_handle handle,
+        int band, int max_channels, wifi_channel *channels, int *num_channels);
+
+typedef struct {
+    int max_scan_cache_size;                 // total space allocated for scan (in bytes)
+    int max_scan_buckets;                    // maximum number of channel buckets
+    int max_ap_cache_per_scan;               // maximum number of APs that can be stored per scan
+    int max_rssi_sample_size;                // number of RSSI samples used for averaging RSSI
+    int max_scan_reporting_threshold;        // max possible report_threshold as described
+                                             // in wifi_scan_cmd_params
+    int max_hotlist_bssids;                  // maximum number of entries for hotlist BSSIDs
+    int max_hotlist_ssids;                   // maximum number of entries for hotlist SSIDs
+    int max_significant_wifi_change_aps;     // maximum number of entries for
+                                             // significant wifi change APs
+    int max_bssid_history_entries;           // number of BSSID/RSSI entries that device can hold
+    int max_number_epno_networks;            // max number of epno entries
+    int max_number_epno_networks_by_ssid;    // max number of epno entries if ssid is specified,
+                                             // that is, epno entries for which an exact match is
+                                             // required, or entries corresponding to hidden ssids
+    int max_number_of_white_listed_ssid;     // max number of white listed SSIDs, M target is 2 to 4
+} wifi_gscan_capabilities;
+
+wifi_error wifi_get_gscan_capabilities(wifi_interface_handle handle,
+        wifi_gscan_capabilities *capabilities);
+
+typedef enum {
+   WIFI_SCAN_BUFFER_FULL,
+   WIFI_SCAN_COMPLETE,
+} wifi_scan_event;
+
+
+/* Format of information elements found in the beacon */
+typedef struct {
+    byte id;                            // element identifier
+    byte len;                           // number of bytes to follow
+    byte data[];
+} wifi_information_element;
+
+typedef struct {
+    wifi_timestamp ts;                  // time since boot (in microsecond) when the result was
+                                        // retrieved
+    char ssid[32+1];                    // null terminated
+    mac_addr bssid;
+    wifi_channel channel;               // channel frequency in MHz
+    wifi_rssi rssi;                     // in db
+    wifi_timespan rtt;                  // in nanoseconds
+    wifi_timespan rtt_sd;               // standard deviation in rtt
+    unsigned short beacon_period;       // period advertised in the beacon
+    unsigned short capability;          // capabilities advertised in the beacon
+    unsigned int ie_length;             // size of the ie_data blob
+    char         ie_data[1];            // blob of all the information elements found in the
+                                        // beacon; this data should be a packed list of
+                                        // wifi_information_element objects, one after the other.
+    // other fields
+} wifi_scan_result;
+
+typedef struct {
+    /* reported when report_threshold is reached in scan cache */
+    void (*on_scan_results_available) (wifi_request_id id, unsigned num_results_available);
+
+    /* reported when each probe response is received, if report_events
+     * enabled in wifi_scan_cmd_params */
+    void (*on_full_scan_result) (wifi_request_id id, wifi_scan_result *result);
+
+    /* optional event - indicates progress of scanning statemachine */
+    void (*on_scan_event) (wifi_scan_event event, unsigned status);
+
+} wifi_scan_result_handler;
+
+typedef struct {
+    wifi_channel channel;               // frequency
+    int dwellTimeMs;                    // dwell time hint
+    int passive;                        // 0 => active, 1 => passive scan; ignored for DFS
+    /* Add channel class */
+} wifi_scan_channel_spec;
+
+#define REPORT_EVENTS_BUFFER_FULL      0
+#define REPORT_EVENTS_EACH_SCAN        1
+#define REPORT_EVENTS_FULL_RESULTS     2
+#define REPORT_EVENTS_NO_BATCH         4
+
+typedef struct {
+    int bucket;                         // bucket index, 0 based
+    wifi_band band;                     // when UNSPECIFIED, use channel list
+    int period;                         // desired period, in millisecond; if this is too
+                                        // low, the firmware should choose to generate results as
+                                        // fast as it can instead of failing the command.
+                                        // for exponential backoff bucket this is the min_period
+    /* report_events semantics -
+     *  This is a bit field; which defines following bits -
+     *  REPORT_EVENTS_BUFFER_FULL  => report only when scan history is % full
+     *  REPORT_EVENTS_EACH_SCAN    => report a scan completion event after scan
+     *  REPORT_EVENTS_FULL_RESULTS => forward scan results (beacons/probe responses + IEs)
+     *                                 in real time to HAL, in addition to completion events
+     *                                 Note: To keep backward compatibility, fire completion
+     *                                 events regardless of REPORT_EVENTS_EACH_SCAN.
+     *  REPORT_EVENTS_NO_BATCH     => controls batching, 0 => batching, 1 => no batching
+     */
+    byte report_events;
+    int max_period; // if max_period is non zero or different than period, then this bucket is
+                    // an exponential backoff bucket and the scan period will grow exponentially
+                    // as per formula: actual_period(N) = period ^ (N/(step_count+1))
+                    // to a maximum period of max_period
+    int exponent;   // for exponential back off bucket: multiplier: new_period=old_period*exponent
+    int step_count; // for exponential back off bucket, number of scans performed at a given
+                    // period and until the exponent is applied
+
+    int num_channels;
+    // channels to scan; these may include DFS channels
+    // Note that a given channel may appear in multiple buckets
+    wifi_scan_channel_spec channels[MAX_CHANNELS];
+} wifi_scan_bucket_spec;
+
+typedef struct {
+    int base_period;                    // base timer period in ms
+    int max_ap_per_scan;                // number of APs to store in each scan ientryn the
+                                        // BSSID/RSSI history buffer (keep the highest RSSI APs)
+    int report_threshold_percent;       // in %, when scan buffer is this much full, wake up AP
+    int report_threshold_num_scans;     // in number of scans, wake up AP after these many scans
+    int num_buckets;
+    wifi_scan_bucket_spec buckets[MAX_BUCKETS];
+} wifi_scan_cmd_params;
+
+/* Start periodic GSCAN */
+wifi_error wifi_start_gscan(wifi_request_id id, wifi_interface_handle iface,
+        wifi_scan_cmd_params params, wifi_scan_result_handler handler);
+
+/* Stop periodic GSCAN */
+wifi_error wifi_stop_gscan(wifi_request_id id, wifi_interface_handle iface);
+
+typedef enum {
+    WIFI_SCAN_FLAG_INTERRUPTED = 1      // Indicates that scan results are not complete because
+                                        // probes were not sent on some channels
+} wifi_scan_flags;
+
+/* Get the GSCAN cached scan results */
+typedef struct {
+    int scan_id;                                     // a unique identifier for the scan unit
+    int flags;                                       // a bitmask with additional 
+                                                     // information about scan
+    int num_results;                                 // number of bssids retrieved by the scan
+    wifi_scan_result results[MAX_AP_CACHE_PER_SCAN]; // scan results - one for each bssid
+} wifi_cached_scan_results;
+
+wifi_error wifi_get_cached_gscan_results(wifi_interface_handle iface, byte flush,
+        int max, wifi_cached_scan_results *results, int *num);
+
+/* BSSID Hotlist */
+typedef struct {
+    void (*on_hotlist_ap_found)(wifi_request_id id,
+            unsigned num_results, wifi_scan_result *results);
+    void (*on_hotlist_ap_lost)(wifi_request_id id,
+            unsigned num_results, wifi_scan_result *results);
+} wifi_hotlist_ap_found_handler;
+
+typedef struct {
+    mac_addr  bssid;                    // AP BSSID
+    wifi_rssi low;                      // low threshold
+    wifi_rssi high;                     // high threshold
+} ap_threshold_param;
+
+typedef struct {
+    int lost_ap_sample_size;
+    int num_bssid;                                 // number of hotlist APs
+    ap_threshold_param ap[MAX_HOTLIST_APS];     // hotlist APs
+} wifi_bssid_hotlist_params;
+
+/* Set the BSSID Hotlist */
+wifi_error wifi_set_bssid_hotlist(wifi_request_id id, wifi_interface_handle iface,
+        wifi_bssid_hotlist_params params, wifi_hotlist_ap_found_handler handler);
+
+/* Clear the BSSID Hotlist */
+wifi_error wifi_reset_bssid_hotlist(wifi_request_id id, wifi_interface_handle iface);
+
+/* SSID Hotlist */
+typedef struct {
+    void (*on_hotlist_ssid_found)(wifi_request_id id,
+            unsigned num_results, wifi_scan_result *results);
+    void (*on_hotlist_ssid_lost)(wifi_request_id id,
+            unsigned num_results, wifi_scan_result *results);
+} wifi_hotlist_ssid_handler;
+
+typedef struct {
+    char  ssid[32+1];                   // SSID
+    wifi_band band;                     // band for this set of threshold params
+    wifi_rssi low;                      // low threshold
+    wifi_rssi high;                     // high threshold
+} ssid_threshold_param;
+
+typedef struct {
+    int lost_ssid_sample_size;
+    int num_ssid;                                   // number of hotlist SSIDs
+    ssid_threshold_param ssid[MAX_HOTLIST_SSID];    // hotlist SSIDs
+} wifi_ssid_hotlist_params;
+
+
+/* Set the SSID Hotlist */
+wifi_error wifi_set_ssid_hotlist(wifi_request_id id, wifi_interface_handle iface,
+        wifi_ssid_hotlist_params params, wifi_hotlist_ssid_handler handler);
+
+/* Clear the SSID Hotlist */
+wifi_error wifi_reset_ssid_hotlist(wifi_request_id id, wifi_interface_handle iface);
+
+
+/* BSSID blacklist */
+typedef struct {
+    int num_bssid;                           // number of blacklisted BSSIDs
+    mac_addr bssids[MAX_BLACKLIST_BSSID];    // blacklisted BSSIDs
+} wifi_bssid_params;
+
+/* Set the BSSID blacklist */
+wifi_error wifi_set_bssid_blacklist(wifi_request_id id, wifi_interface_handle iface,
+        wifi_bssid_params params);
+
+
+/* Significant wifi change */
+typedef struct {
+    mac_addr bssid;                     // BSSID
+    wifi_channel channel;               // channel frequency in MHz
+    int num_rssi;                       // number of rssi samples
+    wifi_rssi rssi[];                   // RSSI history in db
+} wifi_significant_change_result;
+
+typedef struct {
+    void (*on_significant_change)(wifi_request_id id,
+            unsigned num_results, wifi_significant_change_result **results);
+} wifi_significant_change_handler;
+
+// The sample size parameters in the wifi_significant_change_params structure
+// represent the number of occurence of a g-scan where the BSSID was seen and RSSI was
+// collected for that BSSID, or, the BSSID was expected to be seen and didn't.
+// for instance: lost_ap_sample_size : number of time a g-scan was performed on the
+// channel the BSSID was seen last, and the BSSID was not seen during those g-scans
+typedef struct {
+    int rssi_sample_size;               // number of samples for averaging RSSI
+    int lost_ap_sample_size;            // number of samples to confirm AP loss
+    int min_breaching;                  // number of APs breaching threshold
+    int num_bssid;                         // max 64
+    ap_threshold_param ap[MAX_SIGNIFICANT_CHANGE_APS];
+} wifi_significant_change_params;
+
+/* Set the Signifcant AP change list */
+wifi_error wifi_set_significant_change_handler(wifi_request_id id, wifi_interface_handle iface,
+        wifi_significant_change_params params, wifi_significant_change_handler handler);
+
+/* Clear the Signifcant AP change list */
+wifi_error wifi_reset_significant_change_handler(wifi_request_id id, wifi_interface_handle iface);
+
+/* Random MAC OUI for PNO */
+wifi_error wifi_set_scanning_mac_oui(wifi_interface_handle handle, oui scan_oui);
+
+// Whether directed scan needs to be performed (for hidden SSIDs)
+#define WIFI_PNO_FLAG_DIRECTED_SCAN = 1
+// Whether PNO event shall be triggered if the network is found on A band
+#define WIFI_PNO_FLAG_A_BAND = 2
+// Whether PNO event shall be triggered if the network is found on G band
+#define WIFI_PNO_FLAG_G_BAND = 4
+// Whether strict matching is required (i.e. firmware shall not match on the entire SSID)
+#define WIFI_PNO_FLAG_STRICT_MATCH = 8
+
+// Code for matching the beacon AUTH IE - additional codes TBD
+#define WIFI_PNO_AUTH_CODE_OPEN  1 // open
+#define WIFI_PNO_AUTH_CODE_PSK   2 // WPA_PSK or WPA2PSK
+#define WIFI_PNO_AUTH_CODE_EAPOL 4 // any EAPOL
+
+// Enhanced PNO:
+// Enhanced PNO feature is expected to be enabled all of the time (e.g. screen lit) and may thus
+// requires firmware to store a large number of networks, covering the whole list of known network.
+// Therefore, it is acceptable for firmware to store a crc24, crc32 or other short hash of the SSID,
+// such that a low but non-zero probability of collision exist. With that scheme it should be
+// possible for firmware to keep an entry as small as 4 bytes for each pno network.
+// For instance, a firmware pn0 entry can be implemented in the form of:
+//          PNO ENTRY = crc24(3 bytes) | RSSI_THRESHOLD>>3 (5 bits) | auth flags(3 bits)
+//
+// A PNO network shall be reported once, that is, once a network is reported by firmware
+// its entry shall be marked as "done" until framework calls wifi_set_epno_list again.
+// Calling wifi_set_epno_list shall reset the "done" status of pno networks in firmware.
+typedef struct {
+    char ssid[32+1];
+    byte rssi_threshold; // threshold for considering this SSID as found, required granularity for
+                         // this threshold is 4dBm to 8dBm
+    byte flags;          //  WIFI_PNO_FLAG_XXX
+    byte auth_bit_field; // auth bit field for matching WPA IE
+} wifi_epno_network;
+
+/* PNO list */
+typedef struct {
+    int num_networks;                 // number of SSIDs
+    wifi_epno_network networks[];     // PNO networks
+} wifi_epno_params;
+
+typedef struct {
+    // on results
+    void (*on_network_found)(wifi_request_id id,
+            unsigned num_results, wifi_scan_result *results);
+} wifi_epno_handler;
+
+
+/* Set the PNO list */
+wifi_error wifi_set_epno_list(wifi_request_id id, wifi_interface_handle iface,
+        int num_networks, wifi_epno_network *networks, wifi_epno_handler handler);
+
+
+/* SSID white list */
+/* Note that this feature requires firmware to be able to indicate to kernel sme and wpa_supplicant
+ * that the SSID of the network has changed
+ * and thus requires further changed in cfg80211 stack, for instance,
+ * the below function would change:
+
+ void __cfg80211_roamed(struct wireless_dev *wdev,
+ 		       struct cfg80211_bss *bss,
+ 		       const u8 *req_ie, size_t req_ie_len,
+ 		       const u8 *resp_ie, size_t resp_ie_len)
+ * when firmware roam to a new SSID the corresponding link layer stats info need to be updated:
+     struct wifi_interface_link_layer_info;
+ */
+typedef struct {
+    char ssid[32+1]; // null terminated
+} wifi_ssid;
+
+wifi_error wifi_set_ssid_white_list(wifi_request_id id, wifi_interface_handle iface,
+        int num_networks, wifi_ssid *ssids);
+
+/* Set G-SCAN roam parameters */
+/**
+ * Firmware roaming is implemented with two modes:
+ *   1- "Alert" mode roaming, (Note: alert roaming is the pre-L roaming, whereas firmware is
+ *      "urgently" hunting for another BSSID because the RSSI is low, or because many successive
+ *      beacons have been lost or other bad link conditions).
+ *   2- "Lazy" mode, where firmware is hunting for a better BSSID or white listed SSID even though
+ *      the RSSI of the link is good.
+ *      Lazy mode is configured thru G-scan, that is, the results of G-scans are compared to the
+ *      current RSSI and fed thru the roaming engine.
+ *      Lazy scan will be enabled (and or throttled down by reducing the number of G-scans) by
+ *      framework only in certain conditions, such as:
+ *          - no real time (VO/VI) traffic at the interface
+ *          - low packet rate for BE/BK packets a the interface
+ *          - system conditions (screen lit/dark) etc...
+ *
+ * For consistency, the roam parameters will always be configured by framework such that:
+ *
+ * condition 1- A_band_boost_threshold >= (alert_roam_rssi_trigger + 10)
+ * This condition ensures that Lazy roam doesn't cause the device to roam to a 5GHz BSSID whose RSSI
+ * is lower than the alert threshold, which would consequently trigger a roam to a low RSSI BSSID,
+ * hence triggering alert mode roaming.
+ * In other words, in alert mode, the A_band parameters may safely be ignored by WiFi chipset.
+ *
+ * condition 2- A_band_boost_threshold > A_band_penalty_factor
+ *
+ */
+
+/**
+ * Example:
+ * A_band_boost_threshold = -65
+ * A_band_penalty_threshold = -75
+ * A_band_boost_factor = 4
+ * A_band_penalty_factor = 2
+ * A_band_max_boost = 50
+ *
+ * a 5GHz RSSI value is transformed as below:
+ * -20 -> -20+ 50 = 30
+ * -60 -> -60 + 4 * (-60 - A_band_boost_threshold) = -60 + 16 = -44
+ * -70 -> -70
+ * -80 -> -80 - 2 * (A_band_penalty_threshold - (-80)) = -80 - 10 = -90
+ */
+
+typedef struct {
+    // Lazy roam parameters
+    // A_band_XX parameters are applied to 5GHz BSSIDs when comparing with a 2.4GHz BSSID
+    // they may not be applied when comparing two 5GHz BSSIDs
+    int A_band_boost_threshold;     // RSSI threshold above which 5GHz RSSI is favored
+    int A_band_penalty_threshold;   // RSSI threshold below which 5GHz RSSI is penalized
+    int A_band_boost_factor;        // factor by which 5GHz RSSI is boosted
+                               // boost=RSSI_measured-5GHz_boost_threshold)*5GHz_boost_factor
+    int A_band_penalty_factor;      // factor by which 5GHz RSSI is penalized
+                               // penalty=(5GHz_penalty_factor-RSSI_measured)*5GHz_penalty_factor
+    int A_band_max_boost;           // maximum boost that can be applied to a 5GHz RSSI
+
+    // Hysteresis: ensuring the currently associated BSSID is favored
+    // so as to prevent ping-pong situations
+    int lazy_roam_hysteresis;       // boost applied to current BSSID
+
+    // Alert mode enable, i.e. configuring when firmware enters alert mode
+    int alert_roam_rssi_trigger;    // RSSI below which "Alert" roam is enabled
+} wifi_roam_params;
+
+wifi_error wifi_set_gscan_roam_params(wifi_request_id id, wifi_interface_handle iface,
+                                        wifi_roam_params * params);
+
+/**
+ * Enable/Disable "Lazy" roam
+ */
+wifi_error wifi_enable_lazy_roam(wifi_request_id id, wifi_interface_handle iface, int enable);
+
+/**
+ * Per BSSID preference
+ */
+typedef struct {
+    mac_addr bssid;
+    int rssi_modifier;  // modifier applied to the RSSI of the BSSID for the purpose of comparing
+                        // it with other roam candidate
+} wifi_bssid_preference;
+
+wifi_error wifi_set_bssid_preference(wifi_request_id id, wifi_interface_handle iface,
+                                    int num_bssid, wifi_bssid_preference *prefs);
+
+typedef struct {
+    int  id;                            // identifier of this network block, report this in event
+    char realm[256];                    // null terminated UTF8 encoded realm, 0 if unspecified
+    int64_t roamingConsortiumIds[16];   // roaming consortium ids to match, 0s if unspecified
+    byte plmn[3];                       // mcc/mnc combination as per rules, 0s if unspecified
+} wifi_passpoint_network;
+
+typedef struct {
+    void (*on_passpoint_network_found)(
+            wifi_request_id id,
+            int net_id,                        // network block identifier for the matched network
+            wifi_scan_result *result,          // scan result, with channel and beacon information
+            int anqp_len,                      // length of ANQP blob
+            byte *anqp                         // ANQP data, in the information_element format
+            );
+} wifi_passpoint_event_handler;
+
+/* Sets a list for passpoint networks for PNO purposes; it should be matched
+ * against any passpoint networks (designated by Interworking element) found
+ * during regular PNO scan. */
+wifi_error wifi_set_passpoint_list(wifi_request_id id, wifi_interface_handle iface, int num,
+        wifi_passpoint_network *networks, wifi_passpoint_event_handler handler);
+
+/* Reset passpoint network list - no Passpoint networks should be matched after this */
+wifi_error wifi_reset_passpoint_list(wifi_request_id id, wifi_interface_handle iface);
+
+#endif
+
diff --git a/libhardware_legacy/include/hardware_legacy/link_layer_stats.h b/libhardware_legacy/include/hardware_legacy/link_layer_stats.h
new file mode 100644
index 0000000..c6202ad
--- /dev/null
+++ b/libhardware_legacy/include/hardware_legacy/link_layer_stats.h
@@ -0,0 +1,253 @@
+#include "wifi_hal.h"

+

+#ifndef __WIFI_HAL_STATS_H

+#define __WIFI_HAL_STATS_H

+

+#ifdef __cplusplus

+extern "C"

+{

+#endif /* __cplusplus */

+

+#define STATS_MAJOR_VERSION      1

+#define STATS_MINOR_VERSION      0

+#define STATS_MICRO_VERSION      0

+

+typedef enum {

+    WIFI_DISCONNECTED = 0,

+    WIFI_AUTHENTICATING = 1,

+    WIFI_ASSOCIATING = 2,

+    WIFI_ASSOCIATED = 3,

+    WIFI_EAPOL_STARTED = 4,   // if done by firmware/driver

+    WIFI_EAPOL_COMPLETED = 5, // if done by firmware/driver

+} wifi_connection_state;

+

+typedef enum {

+    WIFI_ROAMING_IDLE = 0,

+    WIFI_ROAMING_ACTIVE = 1,

+} wifi_roam_state;

+

+typedef enum {

+    WIFI_INTERFACE_STA = 0,

+    WIFI_INTERFACE_SOFTAP = 1,

+    WIFI_INTERFACE_IBSS = 2,

+    WIFI_INTERFACE_P2P_CLIENT = 3,

+    WIFI_INTERFACE_P2P_GO = 4,

+    WIFI_INTERFACE_NAN = 5,

+    WIFI_INTERFACE_MESH = 6,

+    WIFI_INTERFACE_UNKNOWN = -1

+ } wifi_interface_mode;

+

+#define WIFI_CAPABILITY_QOS          0x00000001     // set for QOS association

+#define WIFI_CAPABILITY_PROTECTED    0x00000002     // set for protected association (802.11 beacon frame control protected bit set)

+#define WIFI_CAPABILITY_INTERWORKING 0x00000004     // set if 802.11 Extended Capabilities element interworking bit is set

+#define WIFI_CAPABILITY_HS20         0x00000008     // set for HS20 association

+#define WIFI_CAPABILITY_SSID_UTF8    0x00000010     // set is 802.11 Extended Capabilities element UTF-8 SSID bit is set

+#define WIFI_CAPABILITY_COUNTRY      0x00000020     // set is 802.11 Country Element is present

+

+typedef struct {

+   wifi_interface_mode mode;     // interface mode

+   u8 mac_addr[6];               // interface mac address (self)

+   wifi_connection_state state;  // connection state (valid for STA, CLI only)

+   wifi_roam_state roaming;      // roaming state

+   u32 capabilities;             // WIFI_CAPABILITY_XXX (self)

+   u8 ssid[33];                  // null terminated SSID

+   u8 bssid[6];                  // bssid

+   u8 ap_country_str[3];         // country string advertised by AP

+   u8 country_str[3];            // country string for this association

+} wifi_interface_link_layer_info;

+

+/* channel information */

+typedef struct {

+   wifi_channel_width width;   // channel width (20, 40, 80, 80+80, 160)

+   wifi_channel center_freq;   // primary 20 MHz channel

+   wifi_channel center_freq0;  // center frequency (MHz) first segment

+   wifi_channel center_freq1;  // center frequency (MHz) second segment

+} wifi_channel_info;

+

+/* wifi rate */

+typedef struct {

+   u32 preamble   :3;   // 0: OFDM, 1:CCK, 2:HT 3:VHT 4..7 reserved

+   u32 nss        :2;   // 0:1x1, 1:2x2, 3:3x3, 4:4x4

+   u32 bw         :3;   // 0:20MHz, 1:40Mhz, 2:80Mhz, 3:160Mhz

+   u32 rateMcsIdx :8;   // OFDM/CCK rate code would be as per ieee std in the units of 0.5mbps

+                        // HT/VHT it would be mcs index

+   u32 reserved  :16;   // reserved

+   u32 bitrate;         // units of 100 Kbps

+} wifi_rate;

+

+/* channel statistics */

+typedef struct {

+   wifi_channel_info channel;  // channel

+   u32 on_time;                // msecs the radio is awake (32 bits number accruing over time)

+   u32 cca_busy_time;          // msecs the CCA register is busy (32 bits number accruing over time)

+} wifi_channel_stat;

+

+/* radio statistics */

+typedef struct {

+   wifi_radio radio;               // wifi radio (if multiple radio supported)

+   u32 on_time;                    // msecs the radio is awake (32 bits number accruing over time)

+   u32 tx_time;                    // msecs the radio is transmitting (32 bits number accruing over time)

+   u32 rx_time;                    // msecs the radio is in active receive (32 bits number accruing over time)

+   u32 on_time_scan;               // msecs the radio is awake due to all scan (32 bits number accruing over time)

+   u32 on_time_nbd;                // msecs the radio is awake due to NAN (32 bits number accruing over time)

+   u32 on_time_gscan;              // msecs the radio is awake due to G?scan (32 bits number accruing over time)

+   u32 on_time_roam_scan;          // msecs the radio is awake due to roam?scan (32 bits number accruing over time)

+   u32 on_time_pno_scan;           // msecs the radio is awake due to PNO scan (32 bits number accruing over time)

+   u32 on_time_hs20;               // msecs the radio is awake due to HS2.0 scans and GAS exchange (32 bits number accruing over time)

+   u32 num_channels;               // number of channels

+   wifi_channel_stat channels[];   // channel statistics

+} wifi_radio_stat;

+

+/**

+ * Packet statistics reporting by firmware is performed on MPDU basi (i.e. counters increase by 1 for each MPDU)

+ * As well, "data packet" in associated comments, shall be interpreted as 802.11 data packet,

+ * that is, 802.11 frame control subtype == 2 and excluding management and control frames.

+ *

+ * As an example, in the case of transmission of an MSDU fragmented in 16 MPDUs which are transmitted

+ * OTA in a 16 units long a-mpdu, for which a block ack is received with 5 bits set:

+ *          tx_mpdu : shall increase by 5

+ *          retries : shall increase by 16

+ *          tx_ampdu : shall increase by 1

+ * data packet counters shall not increase regardless of the number of BAR potentially sent by device for this a-mpdu

+ * data packet counters shall not increase regardless of the number of BA received by device for this a-mpdu

+ *

+ * For each subsequent retransmission of the 11 remaining non ACK'ed mpdus

+ * (regardless of the fact that they are transmitted in a-mpdu or not)

+ *          retries : shall increase by 1

+ *

+ * If no subsequent BA or ACK are received from AP, until packet lifetime expires for those 11 packet that were not ACK'ed

+ *          mpdu_lost : shall increase by 11

+ */

+

+/* per rate statistics */

+typedef struct {

+   wifi_rate rate;     // rate information

+   u32 tx_mpdu;        // number of successfully transmitted data pkts (ACK rcvd)

+   u32 rx_mpdu;        // number of received data pkts

+   u32 mpdu_lost;      // number of data packet losses (no ACK)

+   u32 retries;        // total number of data pkt retries

+   u32 retries_short;  // number of short data pkt retries

+   u32 retries_long;   // number of long data pkt retries

+} wifi_rate_stat;

+

+/* access categories */

+typedef enum {

+   WIFI_AC_VO  = 0,

+   WIFI_AC_VI  = 1,

+   WIFI_AC_BE  = 2,

+   WIFI_AC_BK  = 3,

+   WIFI_AC_MAX = 4,

+} wifi_traffic_ac;

+

+/* wifi peer type */

+typedef enum

+{

+   WIFI_PEER_STA,

+   WIFI_PEER_AP,

+   WIFI_PEER_P2P_GO,

+   WIFI_PEER_P2P_CLIENT,

+   WIFI_PEER_NAN,

+   WIFI_PEER_TDLS,

+   WIFI_PEER_INVALID,

+} wifi_peer_type;

+

+/* per peer statistics */

+typedef struct {

+   wifi_peer_type type;           // peer type (AP, TDLS, GO etc.)

+   u8 peer_mac_address[6];        // mac address

+   u32 capabilities;              // peer WIFI_CAPABILITY_XXX

+   u32 num_rate;                  // number of rates

+   wifi_rate_stat rate_stats[];   // per rate statistics, number of entries  = num_rate

+} wifi_peer_info;

+

+/* Per access category statistics */

+typedef struct {

+   wifi_traffic_ac ac;             // access category (VI, VO, BE, BK)

+   u32 tx_mpdu;                    // number of successfully transmitted unicast data pkts (ACK rcvd)

+   u32 rx_mpdu;                    // number of received unicast data packets

+   u32 tx_mcast;                   // number of succesfully transmitted multicast data packets

+                                   // STA case: implies ACK received from AP for the unicast packet in which mcast pkt was sent

+   u32 rx_mcast;                   // number of received multicast data packets

+   u32 rx_ampdu;                   // number of received unicast a-mpdus; support of this counter is optional

+   u32 tx_ampdu;                   // number of transmitted unicast a-mpdus; support of this counter is optional

+   u32 mpdu_lost;                  // number of data pkt losses (no ACK)

+   u32 retries;                    // total number of data pkt retries

+   u32 retries_short;              // number of short data pkt retries

+   u32 retries_long;               // number of long data pkt retries

+   u32 contention_time_min;        // data pkt min contention time (usecs)

+   u32 contention_time_max;        // data pkt max contention time (usecs)

+   u32 contention_time_avg;        // data pkt avg contention time (usecs)

+   u32 contention_num_samples;     // num of data pkts used for contention statistics

+} wifi_wmm_ac_stat;

+

+/* interface statistics */

+typedef struct {

+   wifi_interface_handle iface;          // wifi interface

+   wifi_interface_link_layer_info info;  // current state of the interface

+   u32 beacon_rx;                        // access point beacon received count from connected AP

+   u64 average_tsf_offset;               // average beacon offset encountered (beacon_TSF - TBTT)

+                                         // The average_tsf_offset field is used so as to calculate the

+                                         // typical beacon contention time on the channel as well may be

+                                         // used to debug beacon synchronization and related power consumption issue

+   u32 leaky_ap_detected;                // indicate that this AP typically leaks packets beyond the driver guard time.

+   u32 leaky_ap_avg_num_frames_leaked;  // average number of frame leaked by AP after frame with PM bit set was ACK'ed by AP

+   u32 leaky_ap_guard_time;              // guard time currently in force (when implementing IEEE power management based on

+                                         // frame control PM bit), How long driver waits before shutting down the radio and

+                                         // after receiving an ACK for a data frame with PM bit set)

+   u32 mgmt_rx;                          // access point mgmt frames received count from connected AP (including Beacon)

+   u32 mgmt_action_rx;                   // action frames received count

+   u32 mgmt_action_tx;                   // action frames transmit count

+   wifi_rssi rssi_mgmt;                  // access Point Beacon and Management frames RSSI (averaged)

+   wifi_rssi rssi_data;                  // access Point Data Frames RSSI (averaged) from connected AP

+   wifi_rssi rssi_ack;                   // access Point ACK RSSI (averaged) from connected AP

+   wifi_wmm_ac_stat ac[WIFI_AC_MAX];     // per ac data packet statistics

+   u32 num_peers;                        // number of peers

+   wifi_peer_info peer_info[];           // per peer statistics

+} wifi_iface_stat;

+

+/* configuration params */

+typedef struct {

+   u32 mpdu_size_threshold;             // threshold to classify the pkts as short or long

+                                        // packet size < mpdu_size_threshold => short

+   u32 aggressive_statistics_gathering; // set for field debug mode. Driver should collect all statistics regardless of performance impact.

+} wifi_link_layer_params;

+

+/* API to trigger the link layer statistics collection.

+   Unless his API is invoked - link layer statistics will not be collected.

+   Radio statistics (once started) do not stop or get reset unless wifi_clear_link_stats is invoked

+   Interface statistics (once started) reset and start afresh after each connection */

+wifi_error wifi_set_link_stats(wifi_interface_handle iface, wifi_link_layer_params params);

+

+/* callback for reporting link layer stats */

+typedef struct {

+  void (*on_link_stats_results) (wifi_request_id id, wifi_iface_stat *iface_stat,

+         int num_radios, wifi_radio_stat *radio_stat);

+} wifi_stats_result_handler;

+

+/* api to collect the link layer statistics for a given iface and all the radio stats */

+wifi_error wifi_get_link_stats(wifi_request_id id,

+        wifi_interface_handle iface, wifi_stats_result_handler handler);

+

+/* wifi statistics bitmap  */

+#define WIFI_STATS_RADIO              0x00000001      // all radio statistics

+#define WIFI_STATS_RADIO_CCA          0x00000002      // cca_busy_time (within radio statistics)

+#define WIFI_STATS_RADIO_CHANNELS     0x00000004      // all channel statistics (within radio statistics)

+#define WIFI_STATS_RADIO_SCAN         0x00000008      // all scan statistics (within radio statistics)

+#define WIFI_STATS_IFACE              0x00000010      // all interface statistics

+#define WIFI_STATS_IFACE_TXRATE       0x00000020      // all tx rate statistics (within interface statistics)

+#define WIFI_STATS_IFACE_AC           0x00000040      // all ac statistics (within interface statistics)

+#define WIFI_STATS_IFACE_CONTENTION   0x00000080      // all contention (min, max, avg) statistics (within ac statisctics)

+

+/* clear api to reset statistics, stats_clear_rsp_mask identifies what stats have been cleared

+   stop_req = 1 will imply whether to stop the statistics collection.

+   stop_rsp = 1 will imply that stop_req was honored and statistics collection was stopped.

+ */

+wifi_error wifi_clear_link_stats(wifi_interface_handle iface,

+      u32 stats_clear_req_mask, u32 *stats_clear_rsp_mask, u8 stop_req, u8 *stop_rsp);

+

+#ifdef __cplusplus

+}

+#endif /* __cplusplus */

+

+#endif /*__WIFI_HAL_STATS_ */

+

diff --git a/libhardware_legacy/include/hardware_legacy/power.h b/libhardware_legacy/include/hardware_legacy/power.h
new file mode 100644
index 0000000..604e0ed
--- /dev/null
+++ b/libhardware_legacy/include/hardware_legacy/power.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2008 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 _HARDWARE_POWER_H
+#define _HARDWARE_POWER_H
+
+#include <stdint.h>
+
+#if __cplusplus
+extern "C" {
+#endif
+
+enum {
+    PARTIAL_WAKE_LOCK = 1,  // the cpu stays on, but the screen is off
+    FULL_WAKE_LOCK = 2      // the screen is also on
+};
+
+// while you have a lock held, the device will stay on at least at the
+// level you request.
+int acquire_wake_lock(int lock, const char* id);
+int release_wake_lock(const char* id);
+
+
+#if __cplusplus
+} // extern "C"
+#endif
+
+#endif // _HARDWARE_POWER_H
diff --git a/libhardware_legacy/include/hardware_legacy/rtt.h b/libhardware_legacy/include/hardware_legacy/rtt.h
new file mode 100644
index 0000000..2808723
--- /dev/null
+++ b/libhardware_legacy/include/hardware_legacy/rtt.h
@@ -0,0 +1,274 @@
+
+#include "wifi_hal.h"
+#include "gscan.h"
+
+#ifndef __WIFI_HAL_RTT_H__
+#define __WIFI_HAL_RTT_H__
+
+/* Ranging status */
+typedef enum {
+    RTT_STATUS_SUCCESS       = 0,
+    RTT_STATUS_FAILURE       = 1,           // general failure status
+    RTT_STATUS_FAIL_NO_RSP   = 2,           // target STA does not respond to request
+    RTT_STATUS_FAIL_REJECTED = 3,           // request rejected. Applies to 2-sided RTT only
+    RTT_STATUS_FAIL_NOT_SCHEDULED_YET  = 4,
+    RTT_STATUS_FAIL_TM_TIMEOUT         = 5, // timing measurement times out
+    RTT_STATUS_FAIL_AP_ON_DIFF_CHANNEL = 6, // Target on different channel, cannot range
+    RTT_STATUS_FAIL_NO_CAPABILITY  = 7,     // ranging not supported
+    RTT_STATUS_ABORTED             = 8,     // request aborted for unknown reason
+    RTT_STATUS_FAIL_INVALID_TS     = 9,     // Invalid T1-T4 timestamp
+    RTT_STATUS_FAIL_PROTOCOL       = 10,    // 11mc protocol failed
+    RTT_STATUS_FAIL_SCHEDULE       = 11,    // request could not be scheduled
+    RTT_STATUS_FAIL_BUSY_TRY_LATER = 12,    // responder cannot collaborate at time of request
+    RTT_STATUS_INVALID_REQ         = 13,    // bad request args
+    RTT_STATUS_NO_WIFI             = 14,    // WiFi not enabled
+    RTT_STATUS_FAIL_FTM_PARAM_OVERRIDE = 15 // Responder overrides param info, cannot range with new params
+} wifi_rtt_status;
+
+/* RTT peer type */
+typedef enum {
+    RTT_PEER_AP         = 0x1,
+    RTT_PEER_STA        = 0x2,
+    RTT_PEER_P2P_GO     = 0x3,
+    RTT_PEER_P2P_CLIENT = 0x4,
+    RTT_PEER_NAN        = 0x5
+} rtt_peer_type;
+
+/* RTT Measurement Bandwidth */
+typedef enum {
+    WIFI_RTT_BW_5   = 0x01,
+    WIFI_RTT_BW_10  = 0x02,
+    WIFI_RTT_BW_20  = 0x04,
+    WIFI_RTT_BW_40  = 0x08,
+    WIFI_RTT_BW_80  = 0x10,
+    WIFI_RTT_BW_160 = 0x20
+} wifi_rtt_bw;
+
+/* RTT Measurement Preamble */
+typedef enum {
+    WIFI_RTT_PREAMBLE_LEGACY = 0x1,
+    WIFI_RTT_PREAMBLE_HT     = 0x2,
+    WIFI_RTT_PREAMBLE_VHT    = 0x4
+} wifi_rtt_preamble;
+
+/* RTT Type */
+typedef enum {
+    RTT_TYPE_1_SIDED = 0x1,
+    RTT_TYPE_2_SIDED = 0x2,
+} wifi_rtt_type;
+
+/* RTT configuration */
+typedef struct {
+    mac_addr addr;                 // peer device mac address
+    wifi_rtt_type type;            // 1-sided or 2-sided RTT
+    rtt_peer_type peer;            // optional - peer device hint (STA, P2P, AP)
+    wifi_channel_info channel;     // Required for STA-AP mode, optional for P2P, NBD etc.
+    unsigned burst_period;         // Time interval between bursts (units: 100 ms).
+                                   // Applies to 1-sided and 2-sided RTT multi-burst requests.
+                                   // Range: 0-31, 0: no preference by initiator (2-sided RTT)
+    unsigned num_burst;            // Total number of RTT bursts to be executed. It will be
+                                   // specified in the same way as the parameter "Number of
+                                   // Burst Exponent" found in the FTM frame format. It
+                                   // applies to both: 1-sided RTT and 2-sided RTT. Valid
+                                   // values are 0 to 15 as defined in 802.11mc std.
+                                   // 0 means single shot
+                                   // The implication of this parameter on the maximum
+                                   // number of RTT results is the following:
+                                   // for 1-sided RTT: max num of RTT results = (2^num_burst)*(num_frames_per_burst)
+                                   // for 2-sided RTT: max num of RTT results = (2^num_burst)*(num_frames_per_burst - 1)
+    unsigned num_frames_per_burst; // num of frames per burst.
+                                   // Minimum value = 1, Maximum value = 31
+                                   // For 2-sided this equals the number of FTM frames
+                                   // to be attempted in a single burst. This also
+                                   // equals the number of FTM frames that the
+                                   // initiator will request that the responder send
+                                   // in a single frame.
+    unsigned num_retries_per_rtt_frame; // number of retries for a failed RTT frame. Applies
+                                        // to 1-sided RTT only. Minimum value = 0, Maximum value = 3
+
+    //following fields are only valid for 2-side RTT
+    unsigned num_retries_per_ftmr; // Maximum number of retries that the initiator can
+                                   // retry an FTMR frame.
+                                   // Minimum value = 0, Maximum value = 3
+    byte LCI_request;              // 1: request LCI, 0: do not request LCI
+    byte LCR_request;              // 1: request LCR, 0: do not request LCR
+    unsigned burst_duration;       // Applies to 1-sided and 2-sided RTT. Valid values will
+                                   // be 2-11 and 15 as specified by the 802.11mc std for
+                                   // the FTM parameter burst duration. In a multi-burst
+                                   // request, if responder overrides with larger value,
+                                   // the initiator will return failure. In a single-burst
+                                   // request if responder overrides with larger value,
+                                   // the initiator will sent TMR_STOP to terminate RTT
+                                   // at the end of the burst_duration it requested.
+    wifi_rtt_preamble preamble;    // RTT preamble to be used in the RTT frames
+    wifi_rtt_bw bw;                // RTT BW to be used in the RTT frames
+} wifi_rtt_config;
+
+/* RTT results */
+typedef struct {
+    mac_addr addr;                // device mac address
+    unsigned burst_num;           // burst number in a multi-burst request
+    unsigned measurement_number;  // Total RTT measurement frames attempted
+    unsigned success_number;      // Total successful RTT measurement frames
+    byte  number_per_burst_peer;  // Maximum number of "FTM frames per burst" supported by
+                                  // the responder STA. Applies to 2-sided RTT only.
+                                  // If reponder overrides with larger value:
+                                  // - for single-burst request initiator will truncate the
+                                  // larger value and send a TMR_STOP after receiving as
+                                  // many frames as originally requested.
+                                  // - for multi-burst request, initiator will return
+                                  // failure right away.
+    wifi_rtt_status status;       // ranging status
+    byte retry_after_duration;    // When status == RTT_STATUS_FAIL_BUSY_TRY_LATER,
+                                  // this will be the time provided by the responder as to
+                                  // when the request can be tried again. Applies to 2-sided
+                                  // RTT only. In sec, 1-31sec.
+    wifi_rtt_type type;           // RTT type
+    wifi_rssi rssi;               // average rssi in 0.5 dB steps e.g. 143 implies -71.5 dB
+    wifi_rssi rssi_spread;        // rssi spread in 0.5 dB steps e.g. 5 implies 2.5 dB spread (optional)
+    wifi_rate tx_rate;            // 1-sided RTT: TX rate of RTT frame.
+                                  // 2-sided RTT: TX rate of initiator's Ack in response to FTM frame.
+    wifi_rate rx_rate;            // 1-sided RTT: TX rate of Ack from other side.
+                                  // 2-sided RTT: TX rate of FTM frame coming from responder.
+    wifi_timespan rtt;            // round trip time in 0.1 nanoseconds
+    wifi_timespan rtt_sd;         // rtt standard deviation in 0.1 nanoseconds
+    wifi_timespan rtt_spread;     // difference between max and min rtt times recorded
+    int distance;                 // distance in cm (optional)
+    int distance_sd;              // standard deviation in cm (optional)
+    int distance_spread;          // difference between max and min distance recorded (optional)
+    wifi_timestamp ts;            // time of the measurement (in microseconds since boot)
+    int burst_duration;           // in ms, actual time taken by the FW to finish one burst
+                                  // measurement. Applies to 1-sided and 2-sided RTT.
+    int negotiated_burst_num;  // Number of bursts allowed by the responder. Applies
+                                   // to 2-sided RTT only.
+    wifi_information_element *LCI; // for 11mc only
+    wifi_information_element *LCR; // for 11mc only
+} wifi_rtt_result;
+
+/* RTT result callback */
+typedef struct {
+    void (*on_rtt_results) (wifi_request_id id, unsigned num_results, wifi_rtt_result *rtt_result[]);
+} wifi_rtt_event_handler;
+
+/* API to request RTT measurement */
+wifi_error wifi_rtt_range_request(wifi_request_id id, wifi_interface_handle iface,
+        unsigned num_rtt_config, wifi_rtt_config rtt_config[], wifi_rtt_event_handler handler);
+
+/* API to cancel RTT measurements */
+wifi_error wifi_rtt_range_cancel(wifi_request_id id,  wifi_interface_handle iface,
+        unsigned num_devices, mac_addr addr[]);
+
+/* NBD ranging channel map */
+typedef struct {
+    wifi_channel availablity[32]; // specifies the channel map for each of the 16 TU windows
+    // frequency of 0 => unspecified; which means firmware is
+    // free to do whatever it wants in this window.
+} wifi_channel_map;
+
+/* API to start publishing the channel map on responder device in a NBD cluster.
+   Responder device will take this request and schedule broadcasting the channel map
+   in a NBD ranging attribute in a SDF. DE will automatically remove the ranging
+   attribute from the OTA queue after number of DW specified by num_dw
+   where Each DW is 512 TUs apart */
+wifi_error wifi_rtt_channel_map_set(wifi_request_id id,
+        wifi_interface_handle iface, wifi_channel_map *params, unsigned num_dw);
+
+/* API to clear the channel map on the responder device in a NBD cluster.
+   Responder device will cancel future ranging channel request, starting from “next”
+   DW interval and will also stop broadcasting NBD ranging attribute in SDF */
+wifi_error wifi_rtt_channel_map_clear(wifi_request_id id,  wifi_interface_handle iface);
+
+// Preamble definition for bit mask used in wifi_rtt_capabilities
+#define PREAMBLE_LEGACY 0x1
+#define PREAMBLE_HT     0x2
+#define PREAMBLE_VHT    0x4
+
+// BW definition for bit mask used in wifi_rtt_capabilities
+#define BW_5_SUPPORT   0x1
+#define BW_10_SUPPORT  0x2
+#define BW_20_SUPPORT  0x4
+#define BW_40_SUPPORT  0x8
+#define BW_80_SUPPORT  0x10
+#define BW_160_SUPPORT 0x20
+
+/* RTT Capabilities */
+typedef struct {
+    byte rtt_one_sided_supported;  // if 1-sided rtt data collection is supported
+    byte rtt_ftm_supported;        // if ftm rtt data collection is supported
+    byte lci_support;              // if initiator supports LCI request. Applies to 2-sided RTT
+    byte lcr_support;              // if initiator supports LCR request. Applies to 2-sided RTT
+    byte preamble_support;         // bit mask indicates what preamble is supported by initiator
+    byte bw_support;               // bit mask indicates what BW is supported by initiator
+} wifi_rtt_capabilities;
+
+/*  RTT capabilities of the device */
+wifi_error wifi_get_rtt_capabilities(wifi_interface_handle iface, wifi_rtt_capabilities *capabilities);
+
+/* debugging definitions */
+enum {
+    RTT_DEBUG_DISABLE,
+    RTT_DEBUG_LOG,
+    RTT_DEBUG_PROTO,
+    RTT_DEBUG_BURST,
+    RTT_DEBUG_ACCURACY,
+    RTT_DEBUG_LOGDETAIL
+};  //rtt debug type
+
+enum {
+    RTT_DEBUG_FORMAT_TXT,
+    RTT_DEBUG_FORMAT_BINARY
+}; //rtt debug format
+
+typedef struct rtt_debug {
+    unsigned version;
+    unsigned len; // total length of after len field
+    unsigned type;  // rtt debug type
+    unsigned format; //rtt debug format
+    char dbuf[0]; // debug content
+} rtt_debug_t;
+
+/* set configuration for debug */
+wifi_error wifi_rtt_debug_cfg(wifi_interface_handle h, unsigned rtt_dbg_type, char *cfgbuf, unsigned cfg_buf_size);
+/* get the debug information */
+wifi_error wifi_rtt_debug_get(wifi_interface_handle h, rtt_debug_t **debugbuf);
+/* free the debug buffer */
+wifi_error wifi_rtt_debug_free(wifi_interface_handle h, rtt_debug_t *debugbuf);
+
+/* API for setting LCI/LCR information to be provided to a requestor */
+typedef enum {
+    WIFI_MOTION_NOT_EXPECTED = 0, // Not expected to change location
+    WIFI_MOTION_EXPECTED = 1,     // Expected to change location
+    WIFI_MOTION_UNKNOWN  = 2,     // Movement pattern unknown
+} wifi_motion_pattern;
+
+typedef struct {
+    long latitude;              // latitude in degrees * 2^25 , 2's complement
+    long longitude;             // latitude in degrees * 2^25 , 2's complement
+    int  altitude;              // Altitude in units of 1/256 m
+    byte latitude_unc;          // As defined in Section 2.3.2 of IETF RFC 6225
+    byte longitude_unc;         // As defined in Section 2.3.2 of IETF RFC 6225
+    byte altitude_unc;          // As defined in Section 2.4.5 from IETF RFC 6225:
+
+    //Following element for configuring the Z subelement
+    wifi_motion_pattern motion_pattern;
+    int  floor;                 // floor in units of 1/16th of floor. 0x80000000 if unknown.
+    int  height_above_floor;    // in units of 1/64 m
+    int  height_unc;            // in units of 1/64 m. 0 if unknown
+} wifi_lci_information;
+
+typedef struct {
+    char country_code[2];       // country code
+    int  length;                // length of the info field
+    char civic_info[256];       // Civic info to be copied in FTM frame
+} wifi_lcr_information;
+
+// API to configure the LCI. Used in RTT Responder mode only
+wifi_error wifi_set_lci(wifi_request_id id, wifi_interface_handle iface,
+                        wifi_lci_information *lci);
+
+// API to configure the LCR. Used in RTT Responder mode only.
+wifi_error wifi_set_lcr(wifi_request_id id, wifi_interface_handle iface,
+                        wifi_lcr_information *lcr);
+
+#endif
+
diff --git a/libhardware_legacy/include/hardware_legacy/tdls.h b/libhardware_legacy/include/hardware_legacy/tdls.h
new file mode 100644
index 0000000..9ac225a
--- /dev/null
+++ b/libhardware_legacy/include/hardware_legacy/tdls.h
@@ -0,0 +1,85 @@
+
+#include "wifi_hal.h"
+
+#ifndef _TDLS_H_
+#define _TDLS_H_
+
+typedef enum {
+    WIFI_TDLS_DISABLED = 1,                 /* TDLS is not enabled, default status for all STAs */
+    WIFI_TDLS_ENABLED,                      /* TDLS is enabled, but not yet tried */
+    WIFI_TDLS_ESTABLISHED,                  /* Direct link is established */
+    WIFI_TDLS_ESTABLISHED_OFF_CHANNEL,      /* Direct link is established using MCC */
+    WIFI_TDLS_DROPPED,                      /* Direct link was established,
+                                             * but is temporarily dropped now */
+    WIFI_TDLS_FAILED                        /* TDLS permanent failed. Inform error to upper layer
+                                             * and go back to WIFI_TDLS_DISABLED */
+} wifi_tdls_state;
+
+typedef enum {
+    WIFI_TDLS_SUCCESS,                              /* Success */
+    WIFI_TDLS_UNSPECIFIED           = -1,           /* Unspecified reason */
+    WIFI_TDLS_NOT_SUPPORTED         = -2,           /* Remote side doesn't support TDLS */
+    WIFI_TDLS_UNSUPPORTED_BAND      = -3,           /* Remote side doesn't support this band */
+    WIFI_TDLS_NOT_BENEFICIAL        = -4,           /* Going to AP is better than going direct */
+    WIFI_TDLS_DROPPED_BY_REMOTE     = -5            /* Remote side doesn't want it anymore */
+} wifi_tdls_reason;
+
+typedef struct {
+    int channel;                        /* channel hint, in channel number (NOT frequency ) */
+    int global_operating_class;         /* operating class to use */
+    int max_latency_ms;                 /* max latency that can be tolerated by apps */
+    int min_bandwidth_kbps;             /* bandwidth required by apps, in kilo bits per second */
+} wifi_tdls_params;
+
+typedef struct {
+    int channel;
+    int global_operating_class;
+    wifi_tdls_state state;
+    wifi_tdls_reason reason;
+} wifi_tdls_status;
+
+typedef struct {
+    int max_concurrent_tdls_session_num;      /* Maximum TDLS session number can be supported by the
+                                              * Firmware and hardware*/
+    int is_global_tdls_supported;            /* 1 -- support,  0 -- not support */
+    int is_per_mac_tdls_supported;           /* 1 -- support,  0 -- not support */
+    int is_off_channel_tdls_supported;       /* 1 -- support,  0 -- not support */
+} wifi_tdls_capabilities;
+
+typedef struct {
+    /* on_tdls_state_changed - reports state of TDLS link to framework
+     * Report this event when the state of TDLS link changes */
+    void (*on_tdls_state_changed)(mac_addr addr, wifi_tdls_status status);
+} wifi_tdls_handler;
+
+
+/* wifi_enable_tdls - enables TDLS-auto mode for a specific route
+ *
+ * params specifies hints, which provide more information about
+ * why TDLS is being sought. The firmware should do its best to
+ * honor the hints before downgrading regular AP link
+ * If upper layer has no specific values, this should be NULL
+ *
+ * handler is used to inform the upper layer about the status change and the corresponding reason
+ */
+wifi_error wifi_enable_tdls(wifi_interface_handle iface, mac_addr addr,
+        wifi_tdls_params *params, wifi_tdls_handler handler);
+
+/* wifi_disable_tdls - disables TDLS-auto mode for a specific route
+ *
+ * This terminates any existing TDLS with addr device, and frees the
+ * device resources to make TDLS connections on new routes.
+ *
+ * DON'T fire any more events on 'handler' specified in earlier call to
+ * wifi_enable_tdls after this action.
+ */
+wifi_error wifi_disable_tdls(wifi_interface_handle iface, mac_addr addr);
+
+/* wifi_get_tdls_status - allows getting the status of TDLS for a specific route */
+wifi_error wifi_get_tdls_status(wifi_interface_handle iface, mac_addr addr,
+        wifi_tdls_status *status);
+
+/* return the current HW + Firmware combination's TDLS capabilities */
+wifi_error wifi_get_tdls_capabilities(wifi_interface_handle iface,
+        wifi_tdls_capabilities *capabilities);
+#endif
diff --git a/libhardware_legacy/include/hardware_legacy/uevent.h b/libhardware_legacy/include/hardware_legacy/uevent.h
new file mode 100644
index 0000000..bedfff5
--- /dev/null
+++ b/libhardware_legacy/include/hardware_legacy/uevent.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2008 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 _HARDWARE_UEVENT_H
+#define _HARDWARE_UEVENT_H
+
+#if __cplusplus
+extern "C" {
+#endif
+
+int uevent_init();
+int uevent_get_fd();
+int uevent_next_event(char* buffer, int buffer_length);
+int uevent_add_native_handler(void (*handler)(void *data, const char *msg, int msg_len),
+                              void *handler_data);
+int uevent_remove_native_handler(void (*handler)(void *data, const char *msg, int msg_len));
+
+#if __cplusplus
+} // extern "C"
+#endif
+
+#endif // _HARDWARE_UEVENT_H
diff --git a/libhardware_legacy/include/hardware_legacy/wifi.h b/libhardware_legacy/include/hardware_legacy/wifi.h
new file mode 100644
index 0000000..93f0383
--- /dev/null
+++ b/libhardware_legacy/include/hardware_legacy/wifi.h
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2008 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 _WIFI_H
+#define _WIFI_H
+
+#if __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Load the Wi-Fi driver.
+ *
+ * @return 0 on success, < 0 on failure.
+ */
+int wifi_load_driver();
+
+/**
+ * Unload the Wi-Fi driver.
+ *
+ * @return 0 on success, < 0 on failure.
+ */
+int wifi_unload_driver();
+
+/**
+ * Check if the Wi-Fi driver is loaded.
+ * Check if the Wi-Fi driver is loaded.
+
+ * @return 0 on success, < 0 on failure.
+ */
+int is_wifi_driver_loaded();
+
+
+/**
+ * Start supplicant.
+ *
+ * @return 0 on success, < 0 on failure.
+ */
+int wifi_start_supplicant(int p2pSupported);
+
+/**
+ * Stop supplicant.
+ *
+ * @return 0 on success, < 0 on failure.
+ */
+int wifi_stop_supplicant(int p2pSupported);
+
+/**
+ * Open a connection to supplicant
+ *
+ * @return 0 on success, < 0 on failure.
+ */
+int wifi_connect_to_supplicant();
+
+/**
+ * Close connection to supplicant
+ *
+ * @return 0 on success, < 0 on failure.
+ */
+void wifi_close_supplicant_connection();
+
+/**
+ * wifi_wait_for_event() performs a blocking call to 
+ * get a Wi-Fi event and returns a string representing 
+ * a Wi-Fi event when it occurs.
+ *
+ * @param buf is the buffer that receives the event
+ * @param len is the maximum length of the buffer
+ *
+ * @returns number of bytes in buffer, 0 if no
+ * event (for instance, no connection), and less than 0
+ * if there is an error.
+ */
+int wifi_wait_for_event(char *buf, size_t len);
+
+/**
+ * wifi_command() issues a command to the Wi-Fi driver.
+ *
+ * Android extends the standard commands listed at
+ * /link http://hostap.epitest.fi/wpa_supplicant/devel/ctrl_iface_page.html
+ * to include support for sending commands to the driver:
+ *
+ * See wifi/java/android/net/wifi/WifiNative.java for the details of
+ * driver commands that are supported
+ *
+ * @param command is the string command (preallocated with 32 bytes)
+ * @param commandlen is command buffer length
+ * @param reply is a buffer to receive a reply string
+ * @param reply_len on entry, this is the maximum length of
+ *        the reply buffer. On exit, the number of
+ *        bytes in the reply buffer.
+ *
+ * @return 0 if successful, < 0 if an error.
+ */
+int wifi_command(const char *command, char *reply, size_t *reply_len);
+
+/**
+ * do_dhcp_request() issues a dhcp request and returns the acquired
+ * information. 
+ * 
+ * All IPV4 addresses/mask are in network byte order.
+ *
+ * @param ipaddr return the assigned IPV4 address
+ * @param gateway return the gateway being used
+ * @param mask return the IPV4 mask
+ * @param dns1 return the IPV4 address of a DNS server
+ * @param dns2 return the IPV4 address of a DNS server
+ * @param server return the IPV4 address of DHCP server
+ * @param lease return the length of lease in seconds.
+ *
+ * @return 0 if successful, < 0 if error.
+ */
+int do_dhcp_request(int *ipaddr, int *gateway, int *mask,
+                   int *dns1, int *dns2, int *server, int *lease);
+
+/**
+ * Return the error string of the last do_dhcp_request().
+ */
+const char *get_dhcp_error_string();
+
+/**
+ * Return the path to requested firmware
+ */
+#define WIFI_GET_FW_PATH_STA	0
+#define WIFI_GET_FW_PATH_AP	1
+#define WIFI_GET_FW_PATH_P2P	2
+const char *wifi_get_fw_path(int fw_type);
+
+/**
+ * Change the path to firmware for the wlan driver
+ */
+int wifi_change_fw_path(const char *fwpath);
+
+/**
+ * Check and create if necessary initial entropy file
+ */
+#define WIFI_ENTROPY_FILE	"/data/misc/wifi/entropy.bin"
+int ensure_entropy_file_exists();
+
+#if __cplusplus
+};  // extern "C"
+#endif
+
+#endif  // _WIFI_H
diff --git a/libhardware_legacy/include/hardware_legacy/wifi_config.h b/libhardware_legacy/include/hardware_legacy/wifi_config.h
new file mode 100644
index 0000000..8ad14f4
--- /dev/null
+++ b/libhardware_legacy/include/hardware_legacy/wifi_config.h
@@ -0,0 +1,47 @@
+#include "wifi_hal.h"

+

+#ifndef __WIFI_HAL_CONFIG_H

+#define __WIFI_HAL_CONFIG_H

+

+#ifdef __cplusplus

+extern "C"

+{

+#endif /* __cplusplus */

+

+#define CONFIG_MAJOR_VERSION      1

+#define CONFIG_MINOR_VERSION      0

+#define CONFIG_MICRO_VERSION      0

+

+typedef int wifi_radio;

+

+// whether the wifi chipset wakes at every dtim beacon or a multiple of the dtim period

+// if extended_dtim is set to 3, the STA shall wake up every 3 DTIM beacons

+wifi_error wifi_extended_dtim_config_set(wifi_request_id id,

+        wifi_interface_handle iface, int extended_dtim);

+

+//set the country code to driver

+wifi_error wifi_set_country_code(wifi_interface_handle iface, const char* country_code);

+

+//set the wifi_iface stats averaging factor used to calculate

+// statistics like average the TSF offset or average number of frame leaked

+// For instance, upon beacon reception:

+//    current_avg = ((beacon_TSF - TBTT) * factor + previous_avg * (0x10000 - factor) ) / 0x10000

+// For instance, when evaluating leaky APs:

+//    current_avg = ((num frame received within guard time) * factor + previous_avg * (0x10000 - factor)) / 0x10000

+

+wifi_error wifi_set_beacon_wifi_iface_stats_averaging_factor(wifi_request_id id, wifi_interface_handle iface,

+        u16 factor);

+

+// configure guard time, i.e. when implementing IEEE power management based on

+// frame control PM bit, how long driver waits before shutting down the radio and

+// after receiving an ACK for a data frame with PM bit set

+wifi_error wifi_set_guard_time(wifi_request_id id, wifi_interface_handle iface,

+        u32 guard_time);

+

+#ifdef __cplusplus

+}

+

+#endif /* __cplusplus */

+

+#endif /*__WIFI_HAL_STATS_ */

+

diff --git a/libhardware_legacy/include/hardware_legacy/wifi_hal.h b/libhardware_legacy/include/hardware_legacy/wifi_hal.h
new file mode 100644
index 0000000..a0ce8fd
--- /dev/null
+++ b/libhardware_legacy/include/hardware_legacy/wifi_hal.h
@@ -0,0 +1,267 @@
+/*
+ * Copyright (C) 2014 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 __WIFI_HAL_H__
+#define __WIFI_HAL_H__
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+#include <stdint.h>
+
+/* WiFi Common definitions */
+/* channel operating width */
+typedef enum {
+    WIFI_CHAN_WIDTH_20    = 0,
+    WIFI_CHAN_WIDTH_40    = 1,
+    WIFI_CHAN_WIDTH_80    = 2,
+    WIFI_CHAN_WIDTH_160   = 3,
+    WIFI_CHAN_WIDTH_80P80 = 4,
+    WIFI_CHAN_WIDTH_5     = 5,
+    WIFI_CHAN_WIDTH_10    = 6,
+    WIFI_CHAN_WIDTH_INVALID = -1
+} wifi_channel_width;
+
+typedef int wifi_radio;
+typedef int wifi_channel;
+
+typedef struct {
+    wifi_channel_width width;
+    int center_frequency0;
+    int center_frequency1;
+    int primary_frequency;
+} wifi_channel_spec;
+
+typedef enum {
+    WIFI_SUCCESS = 0,
+    WIFI_ERROR_NONE = 0,
+    WIFI_ERROR_UNKNOWN = -1,
+    WIFI_ERROR_UNINITIALIZED = -2,
+    WIFI_ERROR_NOT_SUPPORTED = -3,
+    WIFI_ERROR_NOT_AVAILABLE = -4,              // Not available right now, but try later
+    WIFI_ERROR_INVALID_ARGS = -5,
+    WIFI_ERROR_INVALID_REQUEST_ID = -6,
+    WIFI_ERROR_TIMED_OUT = -7,
+    WIFI_ERROR_TOO_MANY_REQUESTS = -8,          // Too many instances of this request
+    WIFI_ERROR_OUT_OF_MEMORY = -9
+} wifi_error;
+
+typedef unsigned char byte;
+typedef unsigned char u8;
+typedef signed char s8;
+typedef uint16_t u16;
+typedef uint32_t u32;
+typedef int32_t s32;
+typedef uint64_t u64;
+typedef int64_t s64;
+typedef int wifi_request_id;
+typedef int wifi_channel;                       // indicates channel frequency in MHz
+typedef int wifi_rssi;
+typedef byte mac_addr[6];
+typedef byte oui[3];
+typedef int64_t wifi_timestamp;                 // In microseconds (us)
+typedef int64_t wifi_timespan;                  // In nanoseconds  (ns)
+
+typedef struct wifi_info *wifi_handle;
+typedef struct wifi_interface_info *wifi_interface_handle;
+
+/* Initialize/Cleanup */
+
+wifi_error wifi_initialize(wifi_handle *handle);
+typedef void (*wifi_cleaned_up_handler) (wifi_handle handle);
+void wifi_cleanup(wifi_handle handle, wifi_cleaned_up_handler handler);
+void wifi_event_loop(wifi_handle handle);
+
+/* Error handling */
+void wifi_get_error_info(wifi_error err, const char **msg); // return a pointer to a static string
+
+/* Feature enums */
+#define WIFI_FEATURE_INFRA              0x0001      // Basic infrastructure mode
+#define WIFI_FEATURE_INFRA_5G           0x0002      // Support for 5 GHz Band
+#define WIFI_FEATURE_HOTSPOT            0x0004      // Support for GAS/ANQP
+#define WIFI_FEATURE_P2P                0x0008      // Wifi-Direct
+#define WIFI_FEATURE_SOFT_AP            0x0010      // Soft AP
+#define WIFI_FEATURE_GSCAN              0x0020      // Google-Scan APIs
+#define WIFI_FEATURE_NAN                0x0040      // Neighbor Awareness Networking
+#define WIFI_FEATURE_D2D_RTT            0x0080      // Device-to-device RTT
+#define WIFI_FEATURE_D2AP_RTT           0x0100      // Device-to-AP RTT
+#define WIFI_FEATURE_BATCH_SCAN         0x0200      // Batched Scan (legacy)
+#define WIFI_FEATURE_PNO                0x0400      // Preferred network offload
+#define WIFI_FEATURE_ADDITIONAL_STA     0x0800      // Support for two STAs
+#define WIFI_FEATURE_TDLS               0x1000      // Tunnel directed link setup
+#define WIFI_FEATURE_TDLS_OFFCHANNEL    0x2000      // Support for TDLS off channel
+#define WIFI_FEATURE_EPR                0x4000      // Enhanced power reporting
+#define WIFI_FEATURE_AP_STA             0x8000      // Support for AP STA Concurrency
+#define WIFI_FEATURE_LINK_LAYER_STATS  0x10000      // Link layer stats collection
+#define WIFI_FEATURE_LOGGER            0x20000      // WiFi Logger
+#define WIFI_FEATURE_HAL_EPNO          0x40000      // WiFi PNO enhanced
+#define WIFI_FEATURE_RSSI_MONITOR      0x80000      // RSSI Monitor
+#define WIFI_FEATURE_MKEEP_ALIVE      0x100000      // WiFi mkeep_alive
+
+// Add more features here
+
+
+typedef int feature_set;
+
+#define IS_MASK_SET(mask, flags)        (((flags) & (mask)) == (mask))
+#define IS_MASK_RESET(mask, flags)      (((flags) & (mask)) == 0)
+
+#define IS_SUPPORTED_FEATURE(feature, featureSet)       IS_MASK_SET(feature, fetureSet)
+#define IS_UNSUPPORTED_FEATURE(feature, featureSet)     IS_MASK_RESET(feature, fetureSet)
+
+/* Feature set */
+wifi_error wifi_get_supported_feature_set(wifi_interface_handle handle, feature_set *set);
+
+/*
+ * Each row represents a valid feature combination;
+ * all other combinations are invalid!
+ */
+wifi_error wifi_get_concurrency_matrix(wifi_interface_handle handle, int set_size_max,
+        feature_set set[], int *set_size);
+
+/* multiple interface support */
+
+wifi_error wifi_get_ifaces(wifi_handle handle, int *num_ifaces, wifi_interface_handle **ifaces);
+wifi_error wifi_get_iface_name(wifi_interface_handle iface, char *name, size_t size);
+
+/* Configuration events */
+
+typedef struct {
+    void (*on_country_code_changed)(char code[2]);      // We can get this from supplicant too
+
+    // More event handlers
+} wifi_event_handler;
+
+typedef struct {
+        void (*on_rssi_threshold_breached)(wifi_request_id id, u8 *cur_bssid, s8 cur_rssi);
+} wifi_rssi_event_handler;
+
+wifi_error wifi_set_iface_event_handler(wifi_request_id id, wifi_interface_handle iface, wifi_event_handler eh);
+wifi_error wifi_reset_iface_event_handler(wifi_request_id id, wifi_interface_handle iface);
+
+wifi_error wifi_set_nodfs_flag(wifi_interface_handle handle, u32 nodfs);
+
+/* include various feature headers */
+
+#include "gscan.h"
+#include "link_layer_stats.h"
+#include "rtt.h"
+#include "tdls.h"
+#include "wifi_logger.h"
+#include "wifi_config.h"
+#include "wifi_nan.h"
+#include "wifi_offload.h"
+
+//wifi HAL function pointer table
+typedef struct {
+    wifi_error (* wifi_initialize) (wifi_handle *);
+    void (* wifi_cleanup) (wifi_handle, wifi_cleaned_up_handler);
+    void (*wifi_event_loop)(wifi_handle);
+    void (* wifi_get_error_info) (wifi_error , const char **);
+    wifi_error (* wifi_get_supported_feature_set) (wifi_interface_handle, feature_set *);
+    wifi_error (* wifi_get_concurrency_matrix) (wifi_interface_handle, int, feature_set *, int *);
+    wifi_error (* wifi_set_scanning_mac_oui) (wifi_interface_handle, unsigned char *);
+    wifi_error (* wifi_get_supported_channels)(wifi_handle, int *, wifi_channel *);
+    wifi_error (* wifi_is_epr_supported)(wifi_handle);
+    wifi_error (* wifi_get_ifaces) (wifi_handle , int *, wifi_interface_handle **);
+    wifi_error (* wifi_get_iface_name) (wifi_interface_handle, char *name, size_t);
+    wifi_error (* wifi_set_iface_event_handler) (wifi_request_id,wifi_interface_handle ,
+            wifi_event_handler);
+    wifi_error (* wifi_reset_iface_event_handler) (wifi_request_id, wifi_interface_handle);
+    wifi_error (* wifi_start_gscan) (wifi_request_id, wifi_interface_handle, wifi_scan_cmd_params,
+            wifi_scan_result_handler);
+    wifi_error (* wifi_stop_gscan)(wifi_request_id, wifi_interface_handle);
+    wifi_error (* wifi_get_cached_gscan_results)(wifi_interface_handle, byte, int,
+            wifi_cached_scan_results *, int *);
+    wifi_error (* wifi_set_bssid_hotlist)(wifi_request_id, wifi_interface_handle,
+            wifi_bssid_hotlist_params, wifi_hotlist_ap_found_handler);
+    wifi_error (* wifi_reset_bssid_hotlist)(wifi_request_id, wifi_interface_handle);
+    wifi_error (* wifi_set_significant_change_handler)(wifi_request_id, wifi_interface_handle,
+            wifi_significant_change_params, wifi_significant_change_handler);
+    wifi_error (* wifi_reset_significant_change_handler)(wifi_request_id, wifi_interface_handle);
+    wifi_error (* wifi_get_gscan_capabilities)(wifi_interface_handle, wifi_gscan_capabilities *);
+    wifi_error (* wifi_set_link_stats) (wifi_interface_handle, wifi_link_layer_params);
+    wifi_error (* wifi_get_link_stats) (wifi_request_id,wifi_interface_handle,
+            wifi_stats_result_handler);
+    wifi_error (* wifi_clear_link_stats)(wifi_interface_handle,u32, u32 *, u8, u8 *);
+    wifi_error (* wifi_get_valid_channels)(wifi_interface_handle,int, int, wifi_channel *, int *);
+    wifi_error (* wifi_rtt_range_request)(wifi_request_id, wifi_interface_handle, unsigned,
+            wifi_rtt_config[], wifi_rtt_event_handler);
+    wifi_error (* wifi_rtt_range_cancel)(wifi_request_id,  wifi_interface_handle, unsigned,
+            mac_addr[]);
+    wifi_error (* wifi_get_rtt_capabilities)(wifi_interface_handle, wifi_rtt_capabilities *);
+    wifi_error (* wifi_set_nodfs_flag)(wifi_interface_handle, u32);
+    wifi_error (* wifi_start_logging)(wifi_interface_handle, u32, u32, u32, u32, char *);
+    wifi_error (* wifi_set_epno_list)(int, wifi_interface_info *, int, wifi_epno_network *,
+            wifi_epno_handler);
+    wifi_error (* wifi_set_country_code)(wifi_interface_handle, const char *);
+    wifi_error (* wifi_get_firmware_memory_dump)( wifi_interface_handle iface,
+            wifi_firmware_memory_dump_handler handler);
+    wifi_error (* wifi_set_log_handler)(wifi_request_id id, wifi_interface_handle iface,
+        wifi_ring_buffer_data_handler handler);
+    wifi_error (* wifi_reset_log_handler)(wifi_request_id id, wifi_interface_handle iface);
+    wifi_error (* wifi_set_alert_handler)(wifi_request_id id, wifi_interface_handle iface,
+        wifi_alert_handler handler);
+    wifi_error (* wifi_reset_alert_handler)(wifi_request_id id, wifi_interface_handle iface);
+    wifi_error (* wifi_get_firmware_version)(wifi_interface_handle iface, char *buffer,
+            int buffer_size);
+    wifi_error (* wifi_get_ring_buffers_status)(wifi_interface_handle iface,
+            u32 *num_rings, wifi_ring_buffer_status *status);
+    wifi_error (* wifi_get_logger_supported_feature_set)(wifi_interface_handle iface,
+            unsigned int *support);
+    wifi_error (* wifi_get_ring_data)(wifi_interface_handle iface, char *ring_name);
+    wifi_error (* wifi_enable_tdls)(wifi_interface_handle, mac_addr, wifi_tdls_params *,
+            wifi_tdls_handler);
+    wifi_error (* wifi_disable_tdls)(wifi_interface_handle, mac_addr);
+    wifi_error (*wifi_get_tdls_status) (wifi_interface_handle, mac_addr, wifi_tdls_status *);
+    wifi_error (*wifi_get_tdls_capabilities)(wifi_interface_handle iface,
+            wifi_tdls_capabilities *capabilities);
+    wifi_error (* wifi_get_driver_version)(wifi_interface_handle iface, char *buffer,
+            int buffer_size);
+    wifi_error (* wifi_set_passpoint_list)(wifi_request_id id, wifi_interface_handle iface,
+            int num, wifi_passpoint_network *networks, wifi_passpoint_event_handler handler);
+    wifi_error (* wifi_reset_passpoint_list)(wifi_request_id id, wifi_interface_handle iface);
+    wifi_error (*wifi_set_bssid_blacklist)(wifi_request_id id, wifi_interface_handle iface,
+                  wifi_bssid_params params);
+    wifi_error (*wifi_enable_lazy_roam)(wifi_request_id id,
+                wifi_interface_handle iface, int enable);
+    wifi_error (*wifi_set_bssid_preference)(wifi_request_id id, wifi_interface_handle iface,
+                                            int num_bssid, wifi_bssid_preference *prefs);
+    wifi_error (*wifi_set_gscan_roam_params)(wifi_request_id id, wifi_interface_handle iface,
+                                                wifi_roam_params * params);
+    wifi_error (*wifi_set_ssid_white_list)(wifi_request_id id, wifi_interface_handle iface,
+                               int num_networks, wifi_ssid *ssids);
+    wifi_error (*wifi_set_lci) (wifi_request_id id, wifi_interface_handle iface,
+	                             wifi_lci_information *lci);
+    wifi_error (*wifi_set_lcr) (wifi_request_id id, wifi_interface_handle iface,
+	                             wifi_lcr_information *lcr);
+    wifi_error (*wifi_start_sending_offloaded_packet)(wifi_request_id id,
+                                wifi_interface_handle iface, u8 *ip_packet, u16 ip_packet_len,
+                                u8 *src_mac_addr, u8 *dst_mac_addr, u32 period_msec);
+    wifi_error (*wifi_stop_sending_offloaded_packet)(wifi_request_id id,
+                                wifi_interface_handle iface);
+    wifi_error (*wifi_start_rssi_monitoring)(wifi_request_id id, wifi_interface_handle
+                        iface, s8 max_rssi, s8 min_rssi, wifi_rssi_event_handler eh);
+    wifi_error (*wifi_stop_rssi_monitoring)(wifi_request_id id, wifi_interface_handle iface);
+} wifi_hal_fn;
+wifi_error init_wifi_vendor_hal_func_table(wifi_hal_fn *fn);
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/libhardware_legacy/include/hardware_legacy/wifi_logger.h b/libhardware_legacy/include/hardware_legacy/wifi_logger.h
new file mode 100644
index 0000000..9823aa3
--- /dev/null
+++ b/libhardware_legacy/include/hardware_legacy/wifi_logger.h
@@ -0,0 +1,413 @@
+#include "wifi_hal.h"
+
+#ifndef __WIFI_HAL_LOGGER_H
+#define __WIFI_HAL_LOGGER_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+#define LOGGER_MAJOR_VERSION    1
+#define LOGGER_MINOR_VERSION    0
+#define LOGGER_MICRO_VERSION    0
+
+
+
+/**
+ * WiFi logger life cycle is as follow:
+ *
+ * - At initialization time, framework will call wifi_get_ring_buffers_status
+ *   so as to obtain the names and list of supported buffers.
+ * - When WiFi operation start framework will call wifi_start_logging
+ *   so as to trigger log collection.
+ * - Developper UI will provide an option to the user, so as it can set the verbose level
+ *   of individual buffer as reported by wifi_get_ring_buffers_status.
+ * - During wifi operations, driver will periodically report per ring data to framework
+ *   by invoking the on_ring_buffer_data call back.
+ * - when capturing a bug report, framework will indicate to driver that all the data
+ *   has to be uploaded, urgently, by calling wifi_get_ring_data.
+ *
+ * The data uploaded by driver will be stored by framework in separate files, with one stream
+ *   of file per ring.
+ * Framework will store the files in pcapng format, allowing for easy merging and parsing
+ *   with network analyzer tools.
+ */
+
+
+typedef int wifi_radio;
+typedef int wifi_ring_buffer_id;
+
+#define PER_PACKET_ENTRY_FLAGS_DIRECTION_TX  1    // 0: TX, 1: RX
+#define PER_PACKET_ENTRY_FLAGS_TX_SUCCESS    2    // whether packet was transmitted or
+                                                  // received/decrypted successfully
+#define PER_PACKET_ENTRY_FLAGS_80211_HEADER  4    // has full 802.11 header, else has 802.3 header
+#define PER_PACKET_ENTRY_FLAGS_PROTECTED     8    // whether packet was encrypted
+
+typedef struct {
+    u8 flags;
+    u8 tid;     // transmit or received tid
+    u16 MCS;    // modulation and bandwidth
+    u8 rssi;    // TX: RSSI of ACK for that packet
+                // RX: RSSI of packet
+    u8 num_retries;                   // number of attempted retries
+    u16 last_transmit_rate;           // last transmit rate in .5 mbps
+    u16 link_layer_transmit_sequence; // transmit/reeive sequence for that MPDU packet
+    u64 firmware_entry_timestamp;     // TX: firmware timestamp (us) when packet is queued within
+                                      // firmware buffer for SDIO/HSIC or into PCIe buffer
+                                      // RX: firmware receive timestamp
+    u64 start_contention_timestamp; // firmware timestamp (us) when packet start contending for the
+                                    // medium for the first time, at head of its AC queue,
+                                    // or as part of an MPDU or A-MPDU. This timestamp is
+                                    // not updated for each retry, only the first transmit attempt.
+    u64 transmit_success_timestamp; // fimrware timestamp (us) when packet is successfully
+                                    // transmitted or aborted because it has exhausted
+                                    // its maximum number of retries.
+    u8 data[0]; // packet data. The length of packet data is determined by the entry_size field of
+                // the wifi_ring_buffer_entry structure. It is expected that first bytes of the
+                // packet, or packet headers only (up to TCP or RTP/UDP headers)
+                // will be copied into the ring
+} __attribute__((packed)) wifi_ring_per_packet_status_entry;
+
+
+/* Below events refer to the wifi_connectivity_event ring and shall be supported */
+#define WIFI_EVENT_ASSOCIATION_REQUESTED    0  // driver receives association command from kernel
+#define WIFI_EVENT_AUTH_COMPLETE            1
+#define WIFI_EVENT_ASSOC_COMPLETE           2
+#define WIFI_EVENT_FW_AUTH_STARTED          3  // fw event indicating auth frames are sent
+#define WIFI_EVENT_FW_ASSOC_STARTED         4  // fw event indicating assoc frames are sent
+#define WIFI_EVENT_FW_RE_ASSOC_STARTED      5  // fw event indicating reassoc frames are sent
+#define WIFI_EVENT_DRIVER_SCAN_REQUESTED    6
+#define WIFI_EVENT_DRIVER_SCAN_RESULT_FOUND 7
+#define WIFI_EVENT_DRIVER_SCAN_COMPLETE     8
+#define WIFI_EVENT_G_SCAN_STARTED           9
+#define WIFI_EVENT_G_SCAN_COMPLETE          10
+#define WIFI_EVENT_DISASSOCIATION_REQUESTED 11
+#define WIFI_EVENT_RE_ASSOCIATION_REQUESTED 12
+#define WIFI_EVENT_ROAM_REQUESTED           13
+#define WIFI_EVENT_BEACON_RECEIVED          14  // received beacon from AP (event enabled
+                                                // only in verbose mode)
+#define WIFI_EVENT_ROAM_SCAN_STARTED        15  // firmware has triggered a roam scan (not g-scan)
+#define WIFI_EVENT_ROAM_SCAN_COMPLETE       16  // firmware has completed a roam scan (not g-scan)
+#define WIFI_EVENT_ROAM_SEARCH_STARTED      17  // firmware has started searching for roam
+                                                // candidates (with reason =xx)
+#define WIFI_EVENT_ROAM_SEARCH_STOPPED      18  // firmware has stopped searching for roam
+                                                // candidates (with reason =xx)
+#define WIFI_EVENT_CHANNEL_SWITCH_ANOUNCEMENT     20 // received channel switch anouncement from AP
+#define WIFI_EVENT_FW_EAPOL_FRAME_TRANSMIT_START  21 // fw start transmit eapol frame, with
+                                                     // EAPOL index 1-4
+#define WIFI_EVENT_FW_EAPOL_FRAME_TRANSMIT_STOP   22 // fw gives up eapol frame, with rate,
+                                                     // success/failure and number retries
+#define WIFI_EVENT_DRIVER_EAPOL_FRAME_TRANSMIT_REQUESTED 23 // kernel queue EAPOL for transmission
+                                                            // in driver with EAPOL index 1-4
+#define WIFI_EVENT_FW_EAPOL_FRAME_RECEIVED        24 // with rate, regardless of the fact that
+                                                     // EAPOL frame is accepted or rejected by fw
+#define WIFI_EVENT_DRIVER_EAPOL_FRAME_RECEIVED    26 // with rate, and eapol index, driver has
+                                                     // received EAPOL frame and will queue it up
+                                                     // to wpa_supplicant
+#define WIFI_EVENT_BLOCK_ACK_NEGOTIATION_COMPLETE 27 // with success/failure, parameters
+#define WIFI_EVENT_BT_COEX_BT_SCO_START     28
+#define WIFI_EVENT_BT_COEX_BT_SCO_STOP      29
+#define WIFI_EVENT_BT_COEX_BT_SCAN_START    30  // for paging/scan etc., when BT starts transmiting
+                                                // twice per BT slot
+#define WIFI_EVENT_BT_COEX_BT_SCAN_STOP     31
+#define WIFI_EVENT_BT_COEX_BT_HID_START     32
+#define WIFI_EVENT_BT_COEX_BT_HID_STOP      33
+#define WIFI_EVENT_ROAM_AUTH_STARTED        34  // fw sends auth frame in roaming to next candidate
+#define WIFI_EVENT_ROAM_AUTH_COMPLETE       35  // fw receive auth confirm from ap
+#define WIFI_EVENT_ROAM_ASSOC_STARTED       36  // firmware sends assoc/reassoc frame in
+                                                // roaming to next candidate
+#define WIFI_EVENT_ROAM_ASSOC_COMPLETE      37  // firmware receive assoc/reassoc confirm from ap
+#define WIFI_EVENT_G_SCAN_STOP              38  // firmware sends stop G_SCAN
+#define WIFI_EVENT_G_SCAN_CYCLE_STARTED     39  // firmware indicates G_SCAN scan cycle started
+#define WIFI_EVENT_G_SCAN_CYCLE_COMPLETED   40  // firmware indicates G_SCAN scan cycle completed
+#define WIFI_EVENT_G_SCAN_BUCKET_STARTED    41  // firmware indicates G_SCAN scan start
+                                                // for a particular bucket
+#define WIFI_EVENT_G_SCAN_BUCKET_COMPLETED  42  // firmware indicates G_SCAN scan completed for
+                                                // for a particular bucket
+#define WIFI_EVENT_G_SCAN_RESULTS_AVAILABLE 43  // Event received from firmware about G_SCAN scan
+                                                // results being available
+#define WIFI_EVENT_G_SCAN_CAPABILITIES      44  // Event received from firmware with G_SCAN
+                                                // capabilities
+#define WIFI_EVENT_ROAM_CANDIDATE_FOUND     45  // Event received from firmware when eligible
+                                                // candidate is found
+#define WIFI_EVENT_ROAM_SCAN_CONFIG         46  // Event received from firmware when roam scan
+                                                // configuration gets enabled or disabled
+
+/**
+ * Parameters of wifi logger events are TLVs
+ * Event parameters tags are defined as:
+ */
+#define WIFI_TAG_VENDOR_SPECIFIC    0   // take a byte stream as parameter
+#define WIFI_TAG_BSSID              1   // takes a 6 bytes MAC address as parameter
+#define WIFI_TAG_ADDR               2   // takes a 6 bytes MAC address as parameter
+#define WIFI_TAG_SSID               3   // takes a 32 bytes SSID address as parameter
+#define WIFI_TAG_STATUS             4   // takes an integer as parameter
+#define WIFI_TAG_CHANNEL_SPEC       5   // takes one or more wifi_channel_spec as parameter
+#define WIFI_TAG_WAKE_LOCK_EVENT    6   // takes a wake_lock_event struct as parameter
+#define WIFI_TAG_ADDR1              7   // takes a 6 bytes MAC address as parameter
+#define WIFI_TAG_ADDR2              8   // takes a 6 bytes MAC address as parameter
+#define WIFI_TAG_ADDR3              9   // takes a 6 bytes MAC address as parameter
+#define WIFI_TAG_ADDR4              10  // takes a 6 bytes MAC address as parameter
+#define WIFI_TAG_TSF                11  // take a 64 bits TSF value as parameter
+#define WIFI_TAG_IE                 12  // take one or more specific 802.11 IEs parameter,
+                                        // IEs are in turn indicated in TLV format as per 
+                                        // 802.11 spec
+#define WIFI_TAG_INTERFACE          13  // take interface name as parameter
+#define WIFI_TAG_REASON_CODE        14  // take a reason code as per 802.11 as parameter
+#define WIFI_TAG_RATE_MBPS          15  // take a wifi rate in 0.5 mbps
+#define WIFI_TAG_REQUEST_ID         16  // take an integer as parameter
+#define WIFI_TAG_BUCKET_ID          17  // take an integer as parameter
+#define WIFI_TAG_GSCAN_PARAMS       18  // takes a wifi_scan_cmd_params struct as parameter
+#define WIFI_TAG_GSCAN_CAPABILITIES 19  // takes a wifi_gscan_capabilities struct as parameter
+#define WIFI_TAG_SCAN_ID            20  // take an integer as parameter
+#define WIFI_TAG_RSSI               21  // take an integer as parameter
+#define WIFI_TAG_CHANNEL            22  // take an integer as parameter
+#define WIFI_TAG_LINK_ID            23  // take an integer as parameter
+#define WIFI_TAG_LINK_ROLE          24  // take an integer as parameter
+#define WIFI_TAG_LINK_STATE         25  // take an integer as parameter
+#define WIFI_TAG_LINK_TYPE          26  // take an integer as parameter
+#define WIFI_TAG_TSCO               27  // take an integer as parameter
+#define WIFI_TAG_RSCO               28  // take an integer as parameter
+#define WIFI_TAG_EAPOL_MESSAGE_TYPE 29  // take an integer as parameter
+                                        // M1-1, M2-2, M3-3, M4-4
+
+typedef struct {
+    u16 tag;
+    u16 length; // length of value
+    u8 value[0];
+} __attribute__((packed)) tlv_log;
+
+typedef struct {
+    u16 event;
+    tlv_log tlvs[0];   // separate parameter structure per event to be provided and optional data
+                       // the event_data is expected to include an official android part, with some
+                       // parameter as transmit rate, num retries, num scan result found etc...
+                       // as well, event_data can include a vendor proprietary part which is
+                       // understood by the developer only.
+} __attribute__((packed)) wifi_ring_buffer_driver_connectivity_event;
+
+
+/**
+ * Ring buffer name for power events ring. note that power event are extremely frequents
+ * and thus should be stored in their own ring/file so as not to clobber connectivity events.
+ */
+typedef struct {
+    int status;      // 0 taken, 1 released
+    int reason;      // reason why this wake lock is taken
+    char name[0];    // null terminated
+} __attribute__((packed)) wake_lock_event;
+
+typedef struct {
+    u16 event;
+    tlv_log tlvs[0];
+} __attribute__((packed)) wifi_power_event;
+
+
+/**
+ * This structure represent a logger entry within a ring buffer.
+ * Wifi driver are responsible to manage the ring buffer and write the debug
+ * information into those rings.
+ *
+ * In general, the debug entries can be used to store meaningful 802.11 information (SME, MLME,
+ * connection and packet statistics) as well as vendor proprietary data that is specific to a
+ * specific driver or chipset.
+ * Binary entries can be used so as to store packet data or vendor specific information and
+ * will be treated as blobs of data by android.
+ *
+ * A user land process will be started by framework so as to periodically retrieve the
+ * data logged by drivers into their ring buffer, store the data into log files and include
+ * the logs into android bugreports.
+ */
+enum {
+    RING_BUFFER_ENTRY_FLAGS_HAS_BINARY = (1 << (0)),    // set for binary entries
+    RING_BUFFER_ENTRY_FLAGS_HAS_TIMESTAMP = (1 << (1))  // set if 64 bits timestamp is present
+};
+
+enum {
+    ENTRY_TYPE_CONNECT_EVENT = 1,
+    ENTRY_TYPE_PKT,
+    ENTRY_TYPE_WAKE_LOCK,
+    ENTRY_TYPE_POWER_EVENT,
+    ENTRY_TYPE_DATA
+};
+
+typedef struct {
+    u16 entry_size; // the size of payload excluding the header.
+    u8 flags;
+    u8 type;        // entry type
+    u64 timestamp;  // present if has_timestamp bit is set.
+} __attribute__((packed)) wifi_ring_buffer_entry;
+
+#define WIFI_RING_BUFFER_FLAG_HAS_BINARY_ENTRIES 0x00000001   // set if binary entries are present
+#define WIFI_RING_BUFFER_FLAG_HAS_ASCII_ENTRIES  0x00000002   // set if ascii entries are present
+
+
+/* ring buffer params */
+/**
+ * written_bytes and read_bytes implement a producer consumer API
+ *     hence written_bytes >= read_bytes
+ * a modulo arithmetic of the buffer size has to be applied to those counters:
+ * actual offset into ring buffer = written_bytes % ring_buffer_byte_size
+ *
+ */
+typedef struct {
+    u8 name[32];
+    u32 flags;
+    wifi_ring_buffer_id ring_id; // unique integer representing the ring
+    u32 ring_buffer_byte_size;   // total memory size allocated for the buffer
+    u32 verbose_level;           // verbose level for ring buffer
+    u32 written_bytes;           // number of bytes that was written to the buffer by driver,
+                                 // monotonously increasing integer
+    u32 read_bytes;              // number of bytes that was read from the buffer by user land,
+                                 // monotonously increasing integer
+    u32 written_records;         // number of records that was written to the buffer by driver,
+                                 // monotonously increasing integer
+} wifi_ring_buffer_status;
+
+
+/**
+ * Callback for reporting ring data
+ *
+ * The ring buffer data collection is event based:
+ *   - Driver calls on_ring_buffer_data when new records are available, the wifi_ring_buffer_status
+ *     passed up to framework in the call back indicates to framework if more data is available in
+ *     the ring buffer. It is not expected that driver will necessarily always empty the ring
+ *     immediately as data is available, instead driver will report data every X seconds or if
+ *     N bytes are available.
+ *   - In the case where a bug report has to be captured, framework will require driver to upload
+ *     all data immediately. This is indicated to driver when framework calls wifi_get_ringdata.
+ *     When framework calls wifi_get_ring_data, driver will start sending all available data in the
+ *     indicated ring by repeatedly invoking the on_ring_buffer_data callback.
+ *
+ * The callback is called by log handler whenever ring data comes in driver.
+ */
+typedef struct {
+  void (*on_ring_buffer_data) (char *ring_name, char *buffer, int buffer_size,
+        wifi_ring_buffer_status *status);
+} wifi_ring_buffer_data_handler;
+
+/**
+ * API to set the log handler for getting ring data
+ *  - Only a single instance of log handler can be instantiated for each ring buffer.
+ */
+wifi_error wifi_set_log_handler(wifi_request_id id, wifi_interface_handle iface,
+    wifi_ring_buffer_data_handler handler);
+
+/* API to reset the log handler */
+wifi_error wifi_reset_log_handler(wifi_request_id id, wifi_interface_handle iface);
+
+
+/**
+ * Callback for reporting FW dump
+ *
+ * The buffer data collection is event based such as FW health check or FW dump.
+ * The callback is called by alert handler.
+ */
+typedef struct {
+   void (*on_alert) (wifi_request_id id, char *buffer, int buffer_size, int err_code);
+} wifi_alert_handler;
+
+/*
+ * API to set the alert handler for the alert case in Wi-Fi Chip
+ *  - Only a single instance of alert handler can be instantiated.
+ */
+wifi_error wifi_set_alert_handler(wifi_request_id id, wifi_interface_handle iface,
+    wifi_alert_handler handler);
+
+/* API to reset the alert handler */
+wifi_error wifi_reset_alert_handler(wifi_request_id id, wifi_interface_handle iface);
+
+/* API for framework to indicate driver has to upload and drain all data of a given ring */
+wifi_error wifi_get_ring_data(wifi_interface_handle iface, char *ring_name);
+
+
+/**
+ * API to trigger the debug collection.
+ *  Unless his API is invoked - logging is not triggered.
+ *  - Verbose_level 0 corresponds to no collection,
+ *    and it makes log handler stop by no more events from driver.
+ *  - Verbose_level 1 correspond to normal log level, with minimal user impact.
+ *    This is the default value.
+ *  - Verbose_level 2 are enabled when user is lazily trying to reproduce a problem,
+ *    wifi performances and power can be impacted but device should not otherwise be
+ *    significantly impacted.
+ *  - Verbose_level 3+ are used when trying to actively debug a problem.
+ *
+ * ring_name represent the name of the ring for which data collection shall start.
+ *
+ * flags: TBD parameter used to enable/disable specific events on a ring
+ * max_interval: maximum interval in seconds for driver to invoke on_ring_buffer_data,
+ *               ignore if zero
+ * min_data_size: minimum data size in buffer for driver to invoke on_ring_buffer_data,
+ *                ignore if zero
+ */
+wifi_error wifi_start_logging(wifi_interface_handle iface, u32 verbose_level, u32 flags,
+    u32 max_interval_sec, u32 min_data_size, char *ring_name);
+
+/**
+ * API to get the status of all ring buffers supported by driver.
+ *  - Caller is responsible to allocate / free ring buffer status.
+ *  - Maximum no of ring buffer would be 10.
+ */
+wifi_error wifi_get_ring_buffers_status(wifi_interface_handle iface, u32 *num_rings,
+    wifi_ring_buffer_status *status);
+
+/**
+ * Synchronous memory dump by user request.
+ *  - Caller is responsible to store memory dump data into a local,
+ *      e.g., /data/misc/wifi/memdump.bin
+ */
+typedef struct {
+    void (*on_firmware_memory_dump) (char *buffer, int buffer_size);
+} wifi_firmware_memory_dump_handler;
+
+/**
+ * API to collect a firmware memory dump for a given iface by async memdump event.
+ *  - Triggered by Alerthandler, esp. when FW problem or FW health check happens
+ *  - Caller is responsible to store fw dump data into a local,
+ *      e.g., /data/misc/wifi/alertdump-1.bin
+ */
+wifi_error wifi_get_firmware_memory_dump(wifi_interface_handle iface,
+    wifi_firmware_memory_dump_handler handler);
+
+/**
+ * API to collect a firmware version string.
+ *  - Caller is responsible to allocate / free a buffer to retrieve firmware verion info.
+ *  - Max string will be at most 256 bytes.
+ */
+wifi_error wifi_get_firmware_version(wifi_interface_handle iface, char *buffer, int buffer_size);
+
+/**
+ * API to collect a driver version string.
+ *  - Caller is responsible to allocate / free a buffer to retrieve driver verion info.
+ *  - Max string will be at most 256 bytes.
+ */
+wifi_error wifi_get_driver_version(wifi_interface_handle iface, char *buffer, int buffer_size);
+
+
+/* Feature set */
+enum {
+    WIFI_LOGGER_MEMORY_DUMP_SUPPORTED = (1 << (0)),             // Memory dump of FW
+    WIFI_LOGGER_PER_PACKET_TX_RX_STATUS_SUPPORTED = (1 << (1)), // PKT status
+    WIFI_LOGGER_CONNECT_EVENT_SUPPORTED = (1 << (2)),           // Connectivity event
+    WIFI_LOGGER_POWER_EVENT_SUPPORTED = (1 << (3)),             // POWER of Driver
+    WIFI_LOGGER_WAKE_LOCK_SUPPORTED = (1 << (4)),               // WAKE LOCK of Driver
+    WIFI_LOGGER_VERBOSE_SUPPORTED = (1 << (5)),                 // verbose log of FW
+    WIFI_LOGGER_WATCHDOG_TIMER_SUPPORTED = (1 << (6))           // monitor the health of FW
+};
+
+/**
+ * API to retrieve the current supportive features.
+ *  - An integer variable is enough to have bit mapping info by caller.
+ */
+wifi_error wifi_get_logger_supported_feature_set(wifi_interface_handle iface,
+    unsigned int *support);
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /*__WIFI_HAL_STATS_ */
+
diff --git a/libhardware_legacy/include/hardware_legacy/wifi_nan.h b/libhardware_legacy/include/hardware_legacy/wifi_nan.h
new file mode 100755
index 0000000..70e97f1
--- /dev/null
+++ b/libhardware_legacy/include/hardware_legacy/wifi_nan.h
@@ -0,0 +1,877 @@
+/*
+ * Copyright (C) 2014 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 __NAN_H__
+#define __NAN_H__
+
+#include "wifi_hal.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+/*****************************************************************************
+ * NAN Discovery Service Structures and Functions
+ *****************************************************************************/
+
+/*
+  Definitions
+  All multi-byte fields within all NAN protocol stack messages are assumed to be in Little Endian order.
+*/
+
+typedef int NanVersion;
+
+#define NAN_MAC_ADDR_LEN                6
+#define NAN_COUNTRY_STRING_LEN          3
+#define NAN_MAJOR_VERSION               1
+#define NAN_MINOR_VERSION               0
+#define NAN_MICRO_VERSION               0
+
+/* NAN Maximum Lengths */
+#define NAN_MAX_SERVICE_NAME_LEN                255
+#define NAN_MAX_MATCH_FILTER_LEN                255
+#define NAN_MAX_SERVICE_SPECIFIC_INFO_LEN       1024
+
+/*
+  Definition of various NanRequestType
+*/
+typedef enum {
+    NAN_REQUEST_ENABLE                  =0,
+    NAN_REQUEST_DISABLE                 =1,
+    NAN_REQUEST_PUBLISH                 =2,
+    NAN_REQUEST_PUBLISH_CANCEL          =3,
+    NAN_REQUEST_TRANSMIT_FOLLOWUP       =4,
+    NAN_REQUEST_SUBSCRIBE               =5,
+    NAN_REQUEST_SUBSCRIBE_CANCEL        =6,
+    NAN_REQUEST_STATS                   =7,
+    NAN_REQUEST_CONFIG                  =8,
+    NAN_REQUEST_TCA                     =9,
+    NAN_REQUEST_LAST                    =0xFFFF
+} NanRequestType;
+
+/*
+  Definition of various NanResponseType
+*/
+typedef enum {
+    NAN_RESPONSE_ENABLED                =0,
+    NAN_RESPONSE_DISABLED               =1,
+    NAN_RESPONSE_PUBLISH                =2,
+    NAN_RESPONSE_PUBLISH_CANCEL         =3,
+    NAN_RESPONSE_TRANSMIT_FOLLOWUP      =4,
+    NAN_RESPONSE_SUBSCRIBE              =5,
+    NAN_RESPONSE_SUBSCRIBE_CANCEL       =6,
+    NAN_RESPONSE_STATS                  =7,
+    NAN_RESPONSE_CONFIG                 =8,
+    NAN_RESPONSE_TCA                    =9,
+    NAN_RESPONSE_ERROR                  =10,
+    NAN_RESPONSE_UNKNOWN                =0xFFFF
+} NanResponseType;
+
+/*
+  Definition of various NanIndication(events)
+*/
+typedef enum {
+    NAN_INDICATION_PUBLISH_REPLIED         =0,
+    NAN_INDICATION_PUBLISH_TERMINATED      =1,
+    NAN_INDICATION_SUBSCRIBE_MATCH         =2,
+    NAN_INDICATION_SUBSCRIBE_UNMATCH       =3,
+    NAN_INDICATION_SUBSCRIBE_TERMINATED    =4,
+    NAN_INDICATION_DE_EVENT                =5,
+    NAN_INDICATION_FOLLOWUP                =6,
+    NAN_INDICATION_DISABLED                =7,
+    NAN_INDICATION_TCA                     =8,
+    NAN_INDICATION_UNKNOWN                 =0xFFFF
+} NanIndicationType;
+
+
+/* NAN Publish Types */
+typedef enum {
+    NAN_PUBLISH_TYPE_UNSOLICITED = 0,
+    NAN_PUBLISH_TYPE_SOLICITED,
+    NAN_PUBLISH_TYPE_UNSOLICITED_SOLICITED,
+    NAN_PUBLISH_TYPE_LAST,
+} NanPublishType;
+
+/* NAN Transmit Priorities */
+typedef enum {
+    NAN_TX_PRIORITY_LOW = 0,
+    NAN_TX_PRIORITY_NORMAL,
+    NAN_TX_PRIORITY_HIGH,
+    NAN_TX_PRIORITY_LAST
+} NanTxPriority;
+
+/* NAN Statistics Request ID Codes */
+typedef enum
+{
+    NAN_STATS_ID_FIRST = 0,
+    NAN_STATS_ID_DE_PUBLISH = NAN_STATS_ID_FIRST,
+    NAN_STATS_ID_DE_SUBSCRIBE,
+    NAN_STATS_ID_DE_MAC,
+    NAN_STATS_ID_DE_TIMING_SYNC,
+    NAN_STATS_ID_DE_DW,
+    NAN_STATS_ID_DE,
+    NAN_STATS_ID_LAST
+} NanStatsId;
+
+/* NAN Protocol Event ID Codes */
+typedef enum
+{
+    NAN_EVENT_ID_FIRST = 0,
+    NAN_EVENT_ID_SELF_STA_MAC_ADDR = NAN_EVENT_ID_FIRST,
+    NAN_EVENT_ID_STARTED_CLUSTER,
+    NAN_EVENT_ID_JOINED_CLUSTER,
+    NAN_EVENT_ID_LAST
+} NanEventId;
+
+/* TCA IDs */
+typedef enum
+{
+    NAN_TCA_ID_FIRST = 0,
+    NAN_TCA_ID_CLUSTER_SIZE = NAN_TCA_ID_FIRST,
+    NAN_TCA_ID_LAST
+} NanTcaId;
+
+/*
+  Various NAN Protocol Response code
+*/
+typedef enum
+{
+    /* NAN Protocol Response Codes */
+    NAN_STATUS_SUCCESS = 0,
+    NAN_STATUS_TIMEOUT,
+    NAN_STATUS_DE_FAILURE,
+    NAN_STATUS_INVALID_MSG_VERSION,
+    NAN_STATUS_INVALID_MSG_LEN,
+    NAN_STATUS_INVALID_MSG_ID,
+    NAN_STATUS_INVALID_HANDLE,
+    NAN_STATUS_NO_SPACE_AVAILABLE,
+    NAN_STATUS_INVALID_PUBLISH_TYPE,
+    NAN_STATUS_INVALID_TX_TYPE,
+    NAN_STATUS_INVALID_MATCH_ALGORITHM,
+    NAN_STATUS_DISABLE_IN_PROGRESS,
+    NAN_STATUS_INVALID_TLV_LEN,
+    NAN_STATUS_INVALID_TLV_TYPE,
+    NAN_STATUS_MISSING_TLV_TYPE,
+    NAN_STATUS_INVALID_TOTAL_TLVS_LEN,
+    NAN_STATUS_INVALID_MATCH_HANDLE,
+    NAN_STATUS_INVALID_TLV_VALUE,
+    NAN_STATUS_INVALID_TX_PRIORITY,
+    NAN_STATUS_INVALID_TCA_ID,
+    NAN_STATUS_INVALID_STATS_ID,
+
+    /* NAN Configuration Response codes */
+    NAN_STATUS_INVALID_RSSI_CLOSE_VALUE = 128,
+    NAN_STATUS_INVALID_RSSI_MEDIUM_VALUE,
+    NAN_STATUS_INVALID_HOP_COUNT_LIMIT,
+    NAN_STATUS_INVALID_CLUSTER_JOIN_COUNT,
+    NAN_STATUS_INVALID_MIN_WAKE_DW_DURATION_VALUE,
+    NAN_STATUS_INVALID_OFDM_DATA_RATE_VALUE,
+    NAN_STATUS_INVALID_RANDOM_FACTOR_UPDATE_TIME_VALUE,
+    NAN_STATUS_INVALID_MASTER_PREFERENCE_VALUE,
+    NAN_STATUS_INVALID_EARLY_DW_WAKE_INTERVAL_VALUE,
+    NAN_STATUS_INVALID_LOW_CLUSTER_ID_VALUE,
+    NAN_STATUS_INVALID_HIGH_CLUSTER_ID_VALUE,
+    NAN_STATUS_INVALID_INITIAL_SCAN_PERIOD,
+    NAN_STATUS_INVALID_ONGOING_SCAN_PERIOD,
+    NAN_STATUS_INVALID_RSSI_PROXIMITY_VALUE
+} NanStatusType;
+
+/*
+  Various NAN Terminated Indication Code
+*/
+typedef enum
+{
+    NAN_TERMINATED_REASON_INVALID = 0,
+    NAN_TERMINATED_REASON_TIMEOUT,
+    NAN_TERMINATED_REASON_USER_REQUEST,
+    NAN_TERMINATED_REASON_FAILURE,
+    NAN_TERMINATED_REASON_COUNT_REACHED,
+    NAN_TERMINATED_REASON_DE_SHUTDOWN,
+    NAN_TERMINATED_REASON_DISABLE_IN_PROGRESS
+} NanTerminatedStatus;
+
+/* NAN Transmit Types */
+typedef enum
+{
+    NAN_TX_TYPE_BROADCAST = 0,
+    NAN_TX_TYPE_UNICAST,
+    NAN_TX_TYPE_LAST
+} NanTxType;
+
+/* NAN Subscribe Type Bit */
+#define NAN_SUBSCRIBE_TYPE_PASSIVE  0
+#define NAN_SUBSCRIBE_TYPE_ACTIVE   1
+
+/* NAN Service Response Filter Attribute Bit */
+#define NAN_SRF_ATTR_BLOOM_FILTER       0
+#define NAN_SRF_ATTR_PARTIAL_MAC_ADDR   1
+
+/* NAN Service Response Filter Include Bit */
+#define NAN_SRF_INCLUDE_DO_NOT_RESPOND  0
+#define NAN_SRF_INCLUDE_RESPOND         1
+
+/* NAN Match Algorithms */
+typedef enum
+{
+    NAN_MATCH_ALG_FIRST = 0,
+    NAN_MATCH_ALG_MATCH_ONCE = NAN_MATCH_ALG_FIRST,
+    NAN_MATCH_ALG_MATCH_CONTINUOUS,
+    NAN_MATCH_ALG_LAST
+} NanMatchAlg;
+
+/* NAN Header */
+typedef struct {
+    /*
+    16-bit quantity which is allocated by the FW.
+    Pass the Handle as 0xFFFF if the Host would like to set up a new
+    Publish/Subscribe and the FW will pass back a valid handle in response msg.
+    To update an already opened Publish/Subscribe Host can pass a Handle
+    which has already been allocated by the FW.
+    */
+    u16 handle;
+
+    /*
+    16-bit quantity which is allocated in 2 contexts.  For all Request
+    messages the TransactionId is allocated by the Service Layer and
+    passed down to the DE.  In all Indication messages the TransactionId
+    field is allocated by the DE.  There is no correlation between the
+    TransactionIds allocated by the Service Layer and those allocated by the DE
+    */
+    u16 transaction_id;
+} NanHeader;
+
+/*
+  Enable Request Message Structure
+  The NanEnableReq message instructs the Discovery Engine to enter an operational state
+*/
+typedef struct {
+    NanHeader header;
+    u8 support_5g; /* default = 0 */
+    u16 cluster_low; /* default = 0 */
+    u16 cluster_high; /* default = 0 */
+    u8 sid_beacon; /* default = 0x80 */
+    u8 sync_disc_5g; /* default  = 1 i.e 5G Discovery frames only*/
+    u8 rssi_close; /* default = 60 (-60 dBm) */
+    u8 rssi_middle; /* default = 70 (-70 dBm) */
+    u8 rssi_proximity; /* default = 70 (-70 dBm) */
+    u8 hop_count_limit; /* default = 2 */
+    u8 random_time; /* default  = 120 (DWs) */
+    u8 master_pref; /* default = 0 */
+    u8 periodic_scan_interval; /* default = 20 seconds */
+    /* TBD: Google specific IE */
+}NanEnableRequest;
+
+/*
+  Disable Request Message Structure
+  The NanDisableReq message instructs the Discovery Engine to exit an operational state.
+*/
+typedef struct {
+    NanHeader header;
+}NanDisableRequest;
+
+/*
+  Publish Msg Structure
+  Message is used to request the DE to publish the Service Name
+  using the parameters passed into the Discovery Window
+*/
+typedef struct {
+    NanHeader header;
+    u16 ttl; /* how many seconds to run for. 0 means forever until canceled */
+    u16 period; /* periodicity of OTA unsolicited publish. Specified in increments of 500 ms */
+    u8 replied_event_flag; /* 1= RepliedEventInd needed, 0 = Not needed */
+    NanPublishType publish_type;/* 0= unsolicited, solicited = 1, 2= both */
+    NanTxType tx_type; /* 0 = broadcast, 1= unicast  if solicited publish */
+    u8 publish_count; /* number of OTA Publish, 0 means forever until canceled */
+    u16 service_name_len; /* length of service name */
+    u8 service_name[NAN_MAX_SERVICE_NAME_LEN];/* UTF-8 encoded string identifying the service */
+
+    /* Sequence of values which should be conveyed to the Discovery Engine of a
+    NAN Device that has invoked a Subscribe method corresponding to this Publish method
+    */
+    u16 service_specific_info_len;
+    u8 service_specific_info[NAN_MAX_SERVICE_SPECIFIC_INFO_LEN];
+
+    /* Ordered sequence of <length, value> pairs which specify further response conditions
+    beyond the service name used to filter subscribe messages to respond to.
+    This is only needed when the PT is set to NAN_SOLICITED or NAN_SOLICITED_UNSOLICITED.
+    */
+    u16 rx_match_filter_len;
+    u8 rx_match_filter[NAN_MAX_MATCH_FILTER_LEN];
+
+    /* Ordered sequence of <length, value> pairs to be included in the Discovery Frame.
+    If present it is always sent in a Discovery Frame
+    */
+    u16 tx_match_filter_len;
+    u8 tx_match_filter[NAN_MAX_MATCH_FILTER_LEN];
+}NanPublishRequest;
+
+/*
+  Publish Cancel Msg Structure
+  The PublishServiceCancelReq Message is used to request the DE to stop publishing
+  the Service Name identified by the handle in the message.
+*/
+typedef struct {
+    NanHeader header;
+}NanPublishCancelRequest;
+
+/*
+  NAN Subscribe Structure
+  The SubscribeServiceReq message is sent to the Discovery Engine
+  whenever the Upper layers would like to listen for a Service Name
+*/
+typedef struct {
+    NanHeader header;
+    u16 ttl; /* how many seconds to run for. 0 means forever until canceled */
+    u16 period;/* periodicity of OTA Active Subscribe. Units in increments of 500 ms , 0 = attempt every DW*/
+
+    /* Flag which specifies how the Subscribe request shall be processed. */
+    u8 subscribe_type; /* 0 - PASSIVE , 1- ACTIVE */
+
+    /* Flag which specifies on Active Subscribes how the Service Response Filter attribute is populated.*/
+    u8 serviceResponseFilter; /* 0 - Bloom Filter, 1 - MAC Addr */
+
+    /* Flag which specifies how the Service Response Filter Include bit is populated.*/
+    u8 serviceResponseInclude; /* 0=Do not respond if in the Address Set, 1= Respond */
+
+    /* Flag which specifies if the Service Response Filter should be used when creating Subscribes.*/
+    u8 useServiceResponseFilter; /* 0=Do not send the Service Response Filter,1= send */
+
+    /* Flag which specifies if the Service Specific Info is needed in the Publish message before creating the MatchIndication*/
+    u8 ssiRequiredForMatchIndication; /* 0=Not needed, 1= Required */
+
+    /* Field which allows the matching behavior to be controlled.  */
+    NanMatchAlg subscribe_match; /* 0 - Match Once, 1 - Match continuous */
+
+    /* The number of Subscribe Matches which should occur before the Subscribe request is automatically terminated.*/
+    u8 subscribe_count; /* If this value is 0 this field is not used by the DE.*/
+
+    u16 service_name_len;/* length of service name */
+    u8 service_name[NAN_MAX_SERVICE_NAME_LEN]; /* UTF-8 encoded string identifying the service */
+
+    /* Sequence of values which further specify the published service beyond the service name*/
+    u16 service_specific_info_len;
+    u8 service_specific_info[NAN_MAX_SERVICE_SPECIFIC_INFO_LEN];
+
+    /* Ordered sequence of <length, value> pairs used to filter out received publish discovery messages.
+    This can be sent both for a Passive or an Active Subscribe
+    */
+    u16 rx_match_filter_len;
+    u8 rx_match_filter[NAN_MAX_MATCH_FILTER_LEN];
+
+    /* Ordered sequence of <length, value> pairs  included in the Discovery Frame when an Active Subscribe is used.*/
+    u16 tx_match_filter_len;
+    u8 tx_match_filter[NAN_MAX_MATCH_FILTER_LEN];
+}NanSubscribeRequest;
+
+
+/*
+  NAN Subscribe Cancel Structure
+  The SubscribeCancelReq Message is used to request the DE to stop looking for the Service Name.
+*/
+typedef struct {
+    NanHeader header;
+}NanSubscribeCancelRequest;
+
+
+/*
+  Transmit follow up Structure
+  The TransmitFollowupReq message is sent to the DE to allow the sending of the Service_Specific_Info
+  to a particular MAC address.
+*/
+typedef struct {
+    NanHeader header;
+    u8 addr[NAN_MAC_ADDR_LEN]; /* Can be a broadcast/multicast or unicast address */
+    NanTxPriority priority; /* priority of the request 0 = low, 1=normal, 2=high */
+    u8 dw_or_faw; /* 0= send in a DW, 1=send in FAW */
+
+    /* Sequence of values which further specify the published service beyond the service name
+    Treated as service specific info in case dw_or_faw is set to 0
+    Treated as extended service specific info in case dw_or_faw is set to non-zero*/
+    u16 service_specific_info_len;
+    u8 service_specific_info[NAN_MAX_SERVICE_SPECIFIC_INFO_LEN];
+}NanTransmitFollowupRequest;
+
+/*
+  Stats Request structure
+  The Discovery Engine can be queried at runtime by the Host processor for statistics
+  concerning various parts of the Discovery Engine.
+*/
+typedef struct {
+    NanHeader header;
+    NanStatsId stats_id; /* NAN Statistics Request ID Codes */
+    u8 clear; /* 0= Do not clear the stats and return the current contents , 1= Clear the associated stats  */
+}NanStatsRequest;
+
+/*
+  Config Structure
+  The NanConfigurationReq message is sent by the Host to the
+  Discovery Engine in order to configure the Discovery Engine during runtime.
+*/
+typedef struct {
+    NanHeader header;
+    u8 sid_beacon; /* default = 0x80 */
+    u8 sync_disc_5g; /* default  = 1 i.e 5G Discovery frames only*/
+    u8 rssi_proximity; /* default = 70 (-70 dBm) */
+    u8 random_time; /* default  = 120 (DWs) */
+    u8 master_pref; /* default = 0 */
+    u8 periodic_scan_interval; /* default = 20 seconds */
+    /* The number of Additional Discovery Window slots in
+       increments of 16 ms.  Since each DW is 512 TUs apart
+       and the DW takes up 1 slot, the maximum number of additional
+       slots which can be specified is 31.  This is a hint to the
+       scheduler and there is no guarantee that all 31 slots will
+       be available because of MCC and BT Coexistence channel usage
+    */
+    u8 additional_disc_window_slots; /* default = 0.*/
+}NanConfigRequest;
+
+/*
+  TCA Structure
+  The Discovery Engine can be configured to send up Events whenever a configured
+  Threshold Crossing Alert (TCA) Id crosses an integral threshold in a particular direction.
+*/
+typedef struct {
+    NanHeader header;
+    NanTcaId tca_id; /* Nan Protocol Threshold Crossing Alert (TCA) Codes */
+
+    /* flag which control whether or not an event is generated for the Rising direction */
+    u8 rising_direction_evt_flag; /* 0 - no event, 1 - event */
+
+    /* flag which control whether or not an event is generated for the Falling direction */
+    u8 falling_direction_evt_flag;/* 0 - no event, 1 - event */
+
+    /* flag which requests a previous TCA request to be cleared from the DE */
+    u8 clear;/*0= Do not clear the TCA, 1=Clear the TCA */
+
+    /* 32 bit value which represents the threshold to be used.*/
+    u32 threshold;
+}NanTCARequest;
+
+/* Publish statistics. */
+typedef struct
+{
+    u32 validPublishServiceReqMsgs;
+    u32 validPublishServiceRspMsgs;
+    u32 validPublishServiceCancelReqMsgs;
+    u32 validPublishServiceCancelRspMsgs;
+    u32 validPublishRepliedIndMsgs;
+    u32 validPublishTerminatedIndMsgs;
+    u32 validActiveSubscribes;
+    u32 validMatches;
+    u32 validFollowups;
+    u32 invalidPublishServiceReqMsgs;
+    u32 invalidPublishServiceCancelReqMsgs;
+    u32 invalidActiveSubscribes;
+    u32 invalidMatches;
+    u32 invalidFollowups;
+    u32 publishCount;
+} NanPublishStats;
+
+/* Subscribe statistics. */
+typedef struct
+{
+    u32 validSubscribeServiceReqMsgs;
+    u32 validSubscribeServiceRspMsgs;
+    u32 validSubscribeServiceCancelReqMsgs;
+    u32 validSubscribeServiceCancelRspMsgs;
+    u32 validSubscribeTerminatedIndMsgs;
+    u32 validSubscribeMatchIndMsgs;
+    u32 validSubscribeUnmatchIndMsgs;
+    u32 validSolicitedPublishes;
+    u32 validMatches;
+    u32 validFollowups;
+    u32 invalidSubscribeServiceReqMsgs;
+    u32 invalidSubscribeServiceCancelReqMsgs;
+    u32 invalidSubscribeFollowupReqMsgs;
+    u32 invalidSolicitedPublishes;
+    u32 invalidMatches;
+    u32 invalidFollowups;
+    u32 subscribeCount;
+    u32 bloomFilterIndex;
+} NanSubscribeStats;
+
+/* NAN MAC Statistics. Used for MAC and DW statistics. */
+typedef struct
+{
+    /* RX stats */
+    u32 validFrames;
+    u32 validActionFrames;
+    u32 validBeaconFrames;
+    u32 ignoredActionFrames;
+    u32 ignoredBeaconFrames;
+    u32 invalidFrames;
+    u32 invalidActionFrames;
+    u32 invalidBeaconFrames;
+    u32 invalidMacHeaders;
+    u32 invalidPafHeaders;
+    u32 nonNanBeaconFrames;
+
+    u32 earlyActionFrames;
+    u32 inDwActionFrames;
+    u32 lateActionFrames;
+
+    /* TX stats */
+    u32 framesQueued;
+    u32 totalTRSpUpdates;
+    u32 completeByTRSp;
+    u32 completeByTp75DW;
+    u32 completeByTendDW;
+    u32 lateActionFramesTx;
+
+    /* Misc stats - ignored for DW. */
+    u32 twIncreases;
+    u32 twDecreases;
+    u32 twChanges;
+    u32 twHighwater;
+    u32 bloomFilterIndex;
+} NanMacStats;
+
+/* NAN Sync Statistics*/
+typedef struct
+{
+    u64 currTsf;
+    u64 myRank;
+    u64 currAmRank;
+    u64 lastAmRank;
+    u32 currAmBTT;
+    u32 lastAmBTT;
+    u8  currAmHopCount;
+    u8  currRole;
+    u16 currClusterId;
+
+    u64 timeSpentInCurrRole;
+    u64 totalTimeSpentAsMaster;
+    u64 totalTimeSpentAsNonMasterSync;
+    u64 totalTimeSpentAsNonMasterNonSync;
+    u32 transitionsToAnchorMaster;
+    u32 transitionsToMaster;
+    u32 transitionsToNonMasterSync;
+    u32 transitionsToNonMasterNonSync;
+    u32 amrUpdateCount;
+    u32 amrUpdateRankChangedCount;
+    u32 amrUpdateBTTChangedCount;
+    u32 amrUpdateHcChangedCount;
+    u32 amrUpdateNewDeviceCount;
+    u32 amrExpireCount;
+    u32 mergeCount;
+    u32 beaconsAboveHcLimit;
+    u32 beaconsBelowRssiThresh;
+    u32 beaconsIgnoredNoSpace;
+    u32 beaconsForOurCluster;
+    u32 beaconsForOtherCluster;
+    u32 beaconCancelRequests;
+    u32 beaconCancelFailures;
+    u32 beaconUpdateRequests;
+    u32 beaconUpdateFailures;
+    u32 syncBeaconTxAttempts;
+    u32 discBeaconTxAttempts;
+} NanSyncStats;
+
+/* NAN Misc DE Statistics */
+typedef struct
+{
+    u32 validErrorRspMsgs;
+    u32 validTransmitFollowupReqMsgs;
+    u32 validTransmitFollowupRspMsgs;
+    u32 validFollowupIndMsgs;
+    u32 validConfigurationReqMsgs;
+    u32 validConfigurationRspMsgs;
+    u32 validStatsReqMsgs;
+    u32 validStatsRspMsgs;
+    u32 validEnableReqMsgs;
+    u32 validEnableRspMsgs;
+    u32 validDisableReqMsgs;
+    u32 validDisableRspMsgs;
+    u32 validDisableIndMsgs;
+    u32 validEventIndMsgs;
+    u32 validTcaReqMsgs;
+    u32 validTcaRspMsgs;
+    u32 validTcaIndMsgs;
+    u32 invalidTransmitFollowupReqMsgs;
+    u32 invalidConfigurationReqMsgs;
+    u32 invalidStatsReqMsgs;
+    u32 invalidEnableReqMsgs;
+    u32 invalidDisableReqMsgs;
+    u32 invalidTcaReqMsgs;
+} NanDeStats;
+
+/*
+  Stats Response Message structure
+  The Discovery Engine response to a request by the Host for statistics.
+*/
+typedef struct {
+    NanStatsId stats_id;
+    union {
+        NanPublishStats publish_stats;
+        NanSubscribeStats subscribe_stats;
+        NanMacStats mac_stats;
+        NanSyncStats sync_stats;
+        NanDeStats de_stats;
+    }data;
+}NanStatsResponse;
+
+/*
+  NAN Response messages
+*/
+typedef struct {
+    NanHeader header;
+    u16 status; /* contains the result code */
+    u16 value; /* For error returns the value is returned which was in error */
+    NanResponseType response_type; /* NanResponseType Definitions */
+    union {
+        NanStatsResponse stats_response;
+    }body;
+}NanResponseMsg;
+
+
+/*
+  Publish Replied Indication
+  The PublishRepliedInd Message is sent by the DE when an Active Subscribe is
+  received over the air and it matches a Solicited PublishServiceReq which had
+  been created with the replied_event_flag set.
+*/
+typedef struct {
+    NanHeader header;
+    u8 addr[NAN_MAC_ADDR_LEN];
+}NanPublishRepliedInd;
+
+/*
+  Publish Terminated
+  The PublishTerminatedInd message is sent by the DE whenever a Publish
+  terminates from a user-specified timeout or a unrecoverable error in the DE.
+*/
+typedef struct {
+    NanHeader header;
+    NanTerminatedStatus reason;
+}NanPublishTerminatedInd;
+
+/*
+  Subscribe Match Indication
+  The SubscribeMatchInd message is sent once per responding MAC address whenever
+  the Discovery Engine detects a match for a previous SubscribeServiceReq.
+*/
+typedef struct {
+    NanHeader header;
+
+    /* a 16 bit Handle which is sent to the Application.  This handle will be sent in any subsequent
+    UnmatchInd messages rather than resending the Match_Filter/Service_Specific_Info TLVs
+    The Match_Handle is a DE resource and it is of limited quantity.  In the event that the DE
+    runs out of Match_Handles the DE will still send the SubscribeMatchInd message but will
+    set the Match_Handle to MATCH_HANDLE_MATCH_POOL_EXHAUSTED=0xFFFF
+    */
+    u16 match_handle;
+    u8 addr[NAN_MAC_ADDR_LEN];
+
+    /* Sequence of octets which were received in a Discovery Frame matching this
+    Subscribe Request.*/
+    u16 service_specific_info_len;
+    u8 service_specific_info[NAN_MAX_SERVICE_NAME_LEN];
+
+    /* Ordered sequence of <length, value> pairs received in the Discovery Frame
+    matching this Subscribe Request.*/
+    u16 sdf_match_filter_len;
+    u8 sdf_match_filter[NAN_MAX_MATCH_FILTER_LEN];
+}NanSubscribeMatchInd;
+
+/*
+  Subscribe UnMatch
+  The SubscribeUnmatchInd message is sent whenever the Discovery Engine detects that
+  a previously Matched Subscribed Service Name has been gone for too long.
+  If the previous SubscribeMatchInd message contained a Match_Handle equal to
+  MATCH_HANDLE_MATCH_POOL_EXHAUSTED then this message will not be sent to the Host.
+*/
+typedef struct {
+    NanHeader header;
+    /* 16 bit value sent by the DE in a previous SubscribeMatchInd to the application. */
+    u16 match_handle;
+}NanSubscribeUnmatchInd;
+
+/*
+  Subscribe Terminated
+  The SubscribeTerminatedInd message is sent by the DE whenever a
+  Subscribe terminates from a user-specified timeout or a unrecoverable error in the DE.
+*/
+typedef struct {
+    NanHeader header;
+    NanTerminatedStatus reason;
+}NanSubscribeTerminatedInd;
+
+/*
+  Followup Indication Message
+  The FollowupInd message is sent by the DE to the Host whenever it receives a
+  Followup message from another peer.
+*/
+typedef struct {
+    NanHeader header;
+    u8 addr[NAN_MAC_ADDR_LEN];
+
+    /* Flag which the DE uses to decide if received in a DW or a FAW*/
+    u8 dw_or_faw; /* 0=Received  in a DW, 1 = Received in a FAW*/
+
+    /* Sequence of values which further specify the published service beyond the service name
+    Service specific info in case dw_or_faw is set to 0
+    Extended service specific info in case dw_or_faw is set to non-zero*/
+    u16 service_specific_info_len;
+    u8 service_specific_info[NAN_MAX_SERVICE_SPECIFIC_INFO_LEN];
+}NanFollowupInd;
+
+/* Selfstaevent data*/
+typedef struct {
+    u8 addr[NAN_MAC_ADDR_LEN];
+}NanSelfStaEvent;
+
+/* joined or Started cluster data*/
+typedef struct {
+    u8 addr[NAN_MAC_ADDR_LEN];
+}NanClusterEventData;
+
+/*
+  Discovery Engine Event Indication
+  The Discovery Engine can inform the Host when significant events occur
+  The data following the EventId is dependent upon the EventId type.
+  In other words, each new event defined will carry a different
+  structure of information back to the host.
+*/
+typedef struct {
+    NanHeader header;
+    NanEventId event_id; /* NAN Protocol Event Codes */
+    union {
+        /* SelfStaEvent which will have 6 byte mac address
+           of the Discovery engine.*/
+        NanSelfStaEvent self_sta;
+        /* Cluster Event Data which will be obtained when the
+           device starts a new cluster or joins a cluster.
+           The event data will have 6 byte octet string of the
+           cluster started or joined.*/
+        NanClusterEventData cluster;
+    }data;
+}NanDiscEngEventInd;
+
+/* Cluster size TCA data*/
+typedef struct {
+    u16 cluster_size;
+}NanTcaClusterData;
+
+/*
+  NAN TCA Indication
+  The Discovery Engine can inform the Host when significant events occur.
+  The data following the TcaId is dependent upon the TcaId type.
+  In other words, each new event defined will carry a different structure
+  of information back to the host.
+*/
+typedef struct {
+    NanHeader header;
+    NanTcaId tca_id;
+    union {
+        /* This event in obtained when the cluser size threshold
+           is crossed. Event will have the cluster size */
+        NanTcaClusterData cluster;
+    }data;
+}NanTCAInd;
+
+/*
+  NAN Disabled Indication
+  The NanDisableInd message indicates to the upper layers that the Discovery
+  Engine has flushed all state and has been shutdown.  When this message is received
+  the DE is guaranteed to have left the NAN cluster it was part of and will have terminated
+  any in progress Publishes or Subscribes.
+*/
+typedef struct {
+    NanHeader header;
+    NanStatusType reason;
+}NanDisabledInd;
+
+/* Response and Event Callbacks */
+typedef struct {
+    /* NotifyResponse invoked to notify the status of the Request */
+    void (*NotifyResponse)(NanResponseMsg* rsp_data);
+    /* Various Events Callback */
+    void (*EventPublishReplied)(NanPublishRepliedInd* event);
+    void (*EventPublishTerminated)(NanPublishTerminatedInd* event);
+    void (*EventSubscribeMatch) (NanSubscribeMatchInd* event);
+    void (*EventSubscribeUnMatch) (NanSubscribeUnmatchInd* event);
+    void (*EventSubscribeTerminated) (NanSubscribeTerminatedInd* event);
+    void (*EventFollowup) (NanFollowupInd* event);
+    void (*EventDiscEngEvent) (NanDiscEngEventInd* event);
+    void (*EventDisabled) (NanDisabledInd* event);
+    void (*EventTca) (NanTCAInd* event);
+} NanCallbackHandler;
+
+
+/*  Function to send NAN request to the wifi driver.*/
+wifi_error nan_enable_request(wifi_request_id id,
+                              wifi_handle handle,
+                              NanEnableRequest* msg);
+
+/*  Function to send NAN request to the wifi driver.*/
+wifi_error nan_disable_request(wifi_request_id id,
+                               wifi_handle handle,
+                               NanDisableRequest* msg);
+
+/*  Function to send NAN request to the wifi driver.*/
+wifi_error nan_publish_request(wifi_request_id id,
+                               wifi_handle handle,
+                               NanPublishRequest* msg);
+
+/*  Function to send NAN request to the wifi driver.*/
+wifi_error nan_publish_cancel_request(wifi_request_id id,
+                                      wifi_handle handle,
+                                      NanPublishCancelRequest* msg);
+
+/*  Function to send NAN request to the wifi driver.*/
+wifi_error nan_subscribe_request(wifi_request_id id,
+                                 wifi_handle handle,
+                                 NanSubscribeRequest* msg);
+
+/*  Function to send NAN request to the wifi driver.*/
+wifi_error nan_subscribe_cancel_request(wifi_request_id id,
+                                        wifi_handle handle,
+                                        NanSubscribeCancelRequest* msg);
+
+/*  Function to send NAN request to the wifi driver.*/
+wifi_error nan_transmit_followup_request(wifi_request_id id,
+                                         wifi_handle handle,
+                                         NanTransmitFollowupRequest* msg);
+
+/*  Function to send NAN statistics request to the wifi driver.*/
+wifi_error nan_stats_request(wifi_request_id id,
+                             wifi_handle handle,
+                             NanStatsRequest* msg);
+
+/*  Function to send NAN configuration request to the wifi driver.*/
+wifi_error nan_config_request(wifi_request_id id,
+                              wifi_handle handle,
+                              NanConfigRequest* msg);
+
+/*  Function to send NAN request to the wifi driver.*/
+wifi_error nan_tca_request(wifi_request_id id,
+                           wifi_handle handle,
+                           NanTCARequest* msg);
+
+/*  Function to register NAN callback */
+wifi_error nan_register_handler(wifi_handle handle,
+                                NanCallbackHandler handlers);
+
+/*  Function to get version of the NAN HAL */
+wifi_error nan_get_version(wifi_handle handle,
+                           NanVersion* version);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __NAN_H__ */
diff --git a/libhardware_legacy/include/hardware_legacy/wifi_offload.h b/libhardware_legacy/include/hardware_legacy/wifi_offload.h
new file mode 100644
index 0000000..f0326f1
--- /dev/null
+++ b/libhardware_legacy/include/hardware_legacy/wifi_offload.h
@@ -0,0 +1,31 @@
+#include "wifi_hal.h"
+
+#ifndef __WIFI_HAL_OFFLOAD_H
+#define __WIFI_HAL_OFFLOAD_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+#define ETHER_ADDR_LEN		6	// Ethernet frame address length
+#define N_AVAIL_ID		3	// available mkeep_alive IDs from 1 to 3
+#define MKEEP_ALIVE_IP_PKT_MAX	256     // max size of IP packet for keep alive
+
+/**
+ * Send specified keep alive packet periodically.
+ */
+wifi_error wifi_start_sending_offloaded_packet(wifi_request_id id, wifi_interface_handle iface,
+        u8 *ip_packet, u16 ip_packet_len, u8 *src_mac_addr, u8 *dst_mac_addr, u32 period_msec);
+
+/**
+ * Stop sending keep alive packet.
+ */
+wifi_error wifi_stop_sending_offloaded_packet(wifi_request_id id, wifi_interface_handle iface);
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /*__WIFI_HAL_OFFLOAD_H */
diff --git a/libhardware_legacy/power/Android.mk b/libhardware_legacy/power/Android.mk
new file mode 100644
index 0000000..3e3ff5d
--- /dev/null
+++ b/libhardware_legacy/power/Android.mk
@@ -0,0 +1,3 @@
+# Copyright 2006 The Android Open Source Project
+
+LOCAL_SRC_FILES += power/power.c
diff --git a/libhardware_legacy/power/power.c b/libhardware_legacy/power/power.c
new file mode 100644
index 0000000..368de5b
--- /dev/null
+++ b/libhardware_legacy/power/power.c
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <hardware_legacy/power.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <pthread.h>
+
+#define LOG_TAG "power"
+#include <utils/Log.h>
+
+enum {
+    ACQUIRE_PARTIAL_WAKE_LOCK = 0,
+    RELEASE_WAKE_LOCK,
+    OUR_FD_COUNT
+};
+
+const char * const OLD_PATHS[] = {
+    "/sys/android_power/acquire_partial_wake_lock",
+    "/sys/android_power/release_wake_lock",
+};
+
+const char * const NEW_PATHS[] = {
+    "/sys/power/wake_lock",
+    "/sys/power/wake_unlock",
+};
+
+//XXX static pthread_once_t g_initialized = THREAD_ONCE_INIT;
+static int g_initialized = 0;
+static int g_fds[OUR_FD_COUNT];
+static int g_error = -1;
+
+static int
+open_file_descriptors(const char * const paths[])
+{
+    int i;
+    for (i=0; i<OUR_FD_COUNT; i++) {
+        int fd = open(paths[i], O_RDWR | O_CLOEXEC);
+        if (fd < 0) {
+            g_error = -errno;
+            fprintf(stderr, "fatal error opening \"%s\": %s\n", paths[i],
+                strerror(errno));
+            return -1;
+        }
+        g_fds[i] = fd;
+    }
+
+    g_error = 0;
+    return 0;
+}
+
+static inline void
+initialize_fds(void)
+{
+    // XXX: should be this:
+    //pthread_once(&g_initialized, open_file_descriptors);
+    // XXX: not this:
+    if (g_initialized == 0) {
+        if(open_file_descriptors(NEW_PATHS) < 0)
+            open_file_descriptors(OLD_PATHS);
+        g_initialized = 1;
+    }
+}
+
+int
+acquire_wake_lock(int lock, const char* id)
+{
+    initialize_fds();
+
+//    ALOGI("acquire_wake_lock lock=%d id='%s'\n", lock, id);
+
+    if (g_error) return g_error;
+
+    int fd;
+    size_t len;
+    ssize_t ret;
+
+    if (lock != PARTIAL_WAKE_LOCK) {
+        return -EINVAL;
+    }
+
+    fd = g_fds[ACQUIRE_PARTIAL_WAKE_LOCK];
+
+    ret = write(fd, id, strlen(id));
+    if (ret < 0) {
+        return -errno;
+    }
+
+    return ret;
+}
+
+int
+release_wake_lock(const char* id)
+{
+    initialize_fds();
+
+//    ALOGI("release_wake_lock id='%s'\n", id);
+
+    if (g_error) return g_error;
+
+    ssize_t len = write(g_fds[RELEASE_WAKE_LOCK], id, strlen(id));
+    if (len < 0) {
+        return -errno;
+    }
+    return len;
+}
diff --git a/libhardware_legacy/uevent/Android.mk b/libhardware_legacy/uevent/Android.mk
new file mode 100644
index 0000000..2d8b524
--- /dev/null
+++ b/libhardware_legacy/uevent/Android.mk
@@ -0,0 +1,3 @@
+# Copyright 2008 The Android Open Source Project
+
+LOCAL_SRC_FILES += uevent/uevent.c
diff --git a/libhardware_legacy/uevent/uevent.c b/libhardware_legacy/uevent/uevent.c
new file mode 100644
index 0000000..e40aa2e
--- /dev/null
+++ b/libhardware_legacy/uevent/uevent.c
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <hardware_legacy/uevent.h>
+
+#include <malloc.h>
+#include <string.h>
+#include <unistd.h>
+#include <poll.h>
+#include <pthread.h>
+
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/queue.h>
+#include <linux/netlink.h>
+
+
+LIST_HEAD(uevent_handler_head, uevent_handler) uevent_handler_list;
+pthread_mutex_t uevent_handler_list_lock = PTHREAD_MUTEX_INITIALIZER;
+
+struct uevent_handler {
+    void (*handler)(void *data, const char *msg, int msg_len);
+    void *handler_data;
+    LIST_ENTRY(uevent_handler) list;
+};
+
+static int fd = -1;
+
+/* Returns 0 on failure, 1 on success */
+int uevent_init()
+{
+    struct sockaddr_nl addr;
+    int sz = 64*1024;
+    int s;
+
+    memset(&addr, 0, sizeof(addr));
+    addr.nl_family = AF_NETLINK;
+    addr.nl_pid = getpid();
+    addr.nl_groups = 0xffffffff;
+
+    s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
+    if(s < 0)
+        return 0;
+
+    setsockopt(s, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz));
+
+    if(bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+        close(s);
+        return 0;
+    }
+
+    fd = s;
+    return (fd > 0);
+}
+
+int uevent_get_fd()
+{
+    return fd;
+}
+
+int uevent_next_event(char* buffer, int buffer_length)
+{
+    while (1) {
+        struct pollfd fds;
+        int nr;
+    
+        fds.fd = fd;
+        fds.events = POLLIN;
+        fds.revents = 0;
+        nr = poll(&fds, 1, -1);
+     
+        if(nr > 0 && (fds.revents & POLLIN)) {
+            int count = recv(fd, buffer, buffer_length, 0);
+            if (count > 0) {
+                struct uevent_handler *h;
+                pthread_mutex_lock(&uevent_handler_list_lock);
+                LIST_FOREACH(h, &uevent_handler_list, list)
+                    h->handler(h->handler_data, buffer, buffer_length);
+                pthread_mutex_unlock(&uevent_handler_list_lock);
+
+                return count;
+            } 
+        }
+    }
+    
+    // won't get here
+    return 0;
+}
+
+int uevent_add_native_handler(void (*handler)(void *data, const char *msg, int msg_len),
+                             void *handler_data)
+{
+    struct uevent_handler *h;
+
+    h = malloc(sizeof(struct uevent_handler));
+    if (h == NULL)
+        return -1;
+    h->handler = handler;
+    h->handler_data = handler_data;
+
+    pthread_mutex_lock(&uevent_handler_list_lock);
+    LIST_INSERT_HEAD(&uevent_handler_list, h, list);
+    pthread_mutex_unlock(&uevent_handler_list_lock);
+
+    return 0;
+}
+
+int uevent_remove_native_handler(void (*handler)(void *data, const char *msg, int msg_len))
+{
+    struct uevent_handler *h;
+    int err = -1;
+
+    pthread_mutex_lock(&uevent_handler_list_lock);
+    LIST_FOREACH(h, &uevent_handler_list, list) {
+        if (h->handler == handler) {
+            LIST_REMOVE(h, list);
+            err = 0;
+            break;
+       }
+    }
+    pthread_mutex_unlock(&uevent_handler_list_lock);
+
+    return err;
+}
diff --git a/libhardware_legacy/wifi/Android.mk b/libhardware_legacy/wifi/Android.mk
new file mode 100644
index 0000000..ed59b40
--- /dev/null
+++ b/libhardware_legacy/wifi/Android.mk
@@ -0,0 +1,44 @@
+# Copyright 2006 The Android Open Source Project
+
+ifdef WIFI_DRIVER_MODULE_PATH
+LOCAL_CFLAGS += -DWIFI_DRIVER_MODULE_PATH=\"$(WIFI_DRIVER_MODULE_PATH)\"
+endif
+ifdef WIFI_DRIVER_MODULE_ARG
+LOCAL_CFLAGS += -DWIFI_DRIVER_MODULE_ARG=\"$(WIFI_DRIVER_MODULE_ARG)\"
+endif
+ifdef WIFI_DRIVER_MODULE_NAME
+LOCAL_CFLAGS += -DWIFI_DRIVER_MODULE_NAME=\"$(WIFI_DRIVER_MODULE_NAME)\"
+endif
+ifdef WIFI_FIRMWARE_LOADER
+LOCAL_CFLAGS += -DWIFI_FIRMWARE_LOADER=\"$(WIFI_FIRMWARE_LOADER)\"
+endif
+ifdef WIFI_DRIVER_FW_PATH_STA
+LOCAL_CFLAGS += -DWIFI_DRIVER_FW_PATH_STA=\"$(WIFI_DRIVER_FW_PATH_STA)\"
+endif
+ifdef WIFI_DRIVER_FW_PATH_AP
+LOCAL_CFLAGS += -DWIFI_DRIVER_FW_PATH_AP=\"$(WIFI_DRIVER_FW_PATH_AP)\"
+endif
+ifdef WIFI_DRIVER_FW_PATH_P2P
+LOCAL_CFLAGS += -DWIFI_DRIVER_FW_PATH_P2P=\"$(WIFI_DRIVER_FW_PATH_P2P)\"
+endif
+ifdef WIFI_DRIVER_FW_PATH_PARAM
+LOCAL_CFLAGS += -DWIFI_DRIVER_FW_PATH_PARAM=\"$(WIFI_DRIVER_FW_PATH_PARAM)\"
+endif
+
+ifdef WIFI_DRIVER_STATE_CTRL_PARAM
+LOCAL_CFLAGS += -DWIFI_DRIVER_STATE_CTRL_PARAM=\"$(WIFI_DRIVER_STATE_CTRL_PARAM)\"
+endif
+ifdef WIFI_DRIVER_STATE_ON
+LOCAL_CFLAGS += -DWIFI_DRIVER_STATE_ON=\"$(WIFI_DRIVER_STATE_ON)\"
+endif
+ifdef WIFI_DRIVER_STATE_OFF
+LOCAL_CFLAGS += -DWIFI_DRIVER_STATE_OFF=\"$(WIFI_DRIVER_STATE_OFF)\"
+endif
+
+LOCAL_SRC_FILES += wifi/wifi.c
+
+ifdef WPA_SUPPLICANT_VERSION
+LOCAL_CFLAGS += -DLIBWPA_CLIENT_EXISTS
+LOCAL_SHARED_LIBRARIES += libwpa_client
+endif
+LOCAL_SHARED_LIBRARIES += libnetutils
diff --git a/libhardware_legacy/wifi/wifi.c b/libhardware_legacy/wifi/wifi.c
new file mode 100644
index 0000000..880f6fc
--- /dev/null
+++ b/libhardware_legacy/wifi/wifi.c
@@ -0,0 +1,834 @@
+/*
+ * Copyright 2008, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <dirent.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <poll.h>
+
+#include "hardware_legacy/wifi.h"
+#ifdef LIBWPA_CLIENT_EXISTS
+#include "libwpa_client/wpa_ctrl.h"
+#endif
+
+#define LOG_TAG "WifiHW"
+#include "cutils/log.h"
+#include "cutils/memory.h"
+#include "cutils/misc.h"
+#include "cutils/properties.h"
+#include "private/android_filesystem_config.h"
+
+#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
+#include <sys/_system_properties.h>
+
+extern int do_dhcp();
+extern int ifc_init();
+extern void ifc_close();
+extern char *dhcp_lasterror();
+extern void get_dhcp_info();
+extern int init_module(void *, unsigned long, const char *);
+extern int delete_module(const char *, unsigned int);
+void wifi_close_sockets();
+
+#ifndef LIBWPA_CLIENT_EXISTS
+#define WPA_EVENT_TERMINATING "CTRL-EVENT-TERMINATING "
+struct wpa_ctrl {};
+void wpa_ctrl_cleanup(void) {}
+struct wpa_ctrl *wpa_ctrl_open(const char *ctrl_path) { return NULL; }
+void wpa_ctrl_close(struct wpa_ctrl *ctrl) {}
+int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,
+	char *reply, size_t *reply_len, void (*msg_cb)(char *msg, size_t len))
+	{ return 0; }
+int wpa_ctrl_attach(struct wpa_ctrl *ctrl) { return 0; }
+int wpa_ctrl_detach(struct wpa_ctrl *ctrl) { return 0; }
+int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len)
+	{ return 0; }
+int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl) { return 0; }
+#endif
+
+static struct wpa_ctrl *ctrl_conn;
+static struct wpa_ctrl *monitor_conn;
+
+/* socket pair used to exit from a blocking read */
+static int exit_sockets[2];
+
+static char primary_iface[PROPERTY_VALUE_MAX];
+// TODO: use new ANDROID_SOCKET mechanism, once support for multiple
+// sockets is in
+
+#ifndef WIFI_DRIVER_MODULE_ARG
+#define WIFI_DRIVER_MODULE_ARG          ""
+#endif
+#ifndef WIFI_FIRMWARE_LOADER
+#define WIFI_FIRMWARE_LOADER		""
+#endif
+#define WIFI_TEST_INTERFACE		"sta"
+
+#ifndef WIFI_DRIVER_FW_PATH_STA
+#define WIFI_DRIVER_FW_PATH_STA		NULL
+#endif
+#ifndef WIFI_DRIVER_FW_PATH_AP
+#define WIFI_DRIVER_FW_PATH_AP		NULL
+#endif
+#ifndef WIFI_DRIVER_FW_PATH_P2P
+#define WIFI_DRIVER_FW_PATH_P2P		NULL
+#endif
+
+#ifndef WIFI_DRIVER_FW_PATH_PARAM
+#define WIFI_DRIVER_FW_PATH_PARAM	"/sys/module/wlan/parameters/fwpath"
+#endif
+
+#define WIFI_DRIVER_LOADER_DELAY	1000000
+
+static const char IFACE_DIR[]           = "/data/system/wpa_supplicant";
+#ifdef WIFI_DRIVER_MODULE_PATH
+static const char DRIVER_MODULE_NAME[]  = WIFI_DRIVER_MODULE_NAME;
+static const char DRIVER_MODULE_TAG[]   = WIFI_DRIVER_MODULE_NAME " ";
+static const char DRIVER_MODULE_PATH[]  = WIFI_DRIVER_MODULE_PATH;
+static const char DRIVER_MODULE_ARG[]   = WIFI_DRIVER_MODULE_ARG;
+#endif
+static const char FIRMWARE_LOADER[]     = WIFI_FIRMWARE_LOADER;
+static const char DRIVER_PROP_NAME[]    = "wlan.driver.status";
+static const char SUPPLICANT_NAME[]     = "wpa_supplicant";
+static const char SUPP_PROP_NAME[]      = "init.svc.wpa_supplicant";
+static const char P2P_SUPPLICANT_NAME[] = "p2p_supplicant";
+static const char P2P_PROP_NAME[]       = "init.svc.p2p_supplicant";
+static const char SUPP_CONFIG_TEMPLATE[]= "/system/etc/wifi/wpa_supplicant.conf";
+static const char SUPP_CONFIG_FILE[]    = "/data/misc/wifi/wpa_supplicant.conf";
+static const char P2P_CONFIG_FILE[]     = "/data/misc/wifi/p2p_supplicant.conf";
+static const char CONTROL_IFACE_PATH[]  = "/data/misc/wifi/sockets";
+static const char MODULE_FILE[]         = "/proc/modules";
+
+static const char IFNAME[]              = "IFNAME=";
+#define IFNAMELEN			(sizeof(IFNAME) - 1)
+static const char WPA_EVENT_IGNORE[]    = "CTRL-EVENT-IGNORE ";
+
+static const char SUPP_ENTROPY_FILE[]   = WIFI_ENTROPY_FILE;
+static unsigned char dummy_key[21] = { 0x02, 0x11, 0xbe, 0x33, 0x43, 0x35,
+                                       0x68, 0x47, 0x84, 0x99, 0xa9, 0x2b,
+                                       0x1c, 0xd3, 0xee, 0xff, 0xf1, 0xe2,
+                                       0xf3, 0xf4, 0xf5 };
+
+/* Is either SUPPLICANT_NAME or P2P_SUPPLICANT_NAME */
+static char supplicant_name[PROPERTY_VALUE_MAX];
+/* Is either SUPP_PROP_NAME or P2P_PROP_NAME */
+static char supplicant_prop_name[PROPERTY_KEY_MAX];
+
+static int insmod(const char *filename, const char *args)
+{
+    void *module;
+    unsigned int size;
+    int ret;
+
+    module = load_file(filename, &size);
+    if (!module)
+        return -1;
+
+    ret = init_module(module, size, args);
+
+    free(module);
+
+    return ret;
+}
+
+static int rmmod(const char *modname)
+{
+    int ret = -1;
+    int maxtry = 10;
+
+    while (maxtry-- > 0) {
+        ret = delete_module(modname, O_NONBLOCK | O_EXCL);
+        if (ret < 0 && errno == EAGAIN)
+            usleep(500000);
+        else
+            break;
+    }
+
+    if (ret != 0)
+        ALOGD("Unable to unload driver module \"%s\": %s\n",
+             modname, strerror(errno));
+    return ret;
+}
+
+int do_dhcp_request(int *ipaddr, int *gateway, int *mask,
+                    int *dns1, int *dns2, int *server, int *lease) {
+    /* For test driver, always report success */
+    if (strcmp(primary_iface, WIFI_TEST_INTERFACE) == 0)
+        return 0;
+
+    if (ifc_init() < 0)
+        return -1;
+
+    if (do_dhcp(primary_iface) < 0) {
+        ifc_close();
+        return -1;
+    }
+    ifc_close();
+    get_dhcp_info(ipaddr, gateway, mask, dns1, dns2, server, lease);
+    return 0;
+}
+
+const char *get_dhcp_error_string() {
+    return dhcp_lasterror();
+}
+
+#ifdef WIFI_DRIVER_STATE_CTRL_PARAM
+int wifi_change_driver_state(const char *state)
+{
+    int len;
+    int fd;
+    int ret = 0;
+
+    if (!state)
+        return -1;
+    fd = TEMP_FAILURE_RETRY(open(WIFI_DRIVER_STATE_CTRL_PARAM, O_WRONLY));
+    if (fd < 0) {
+        ALOGE("Failed to open driver state control param (%s)", strerror(errno));
+        return -1;
+    }
+    len = strlen(state) + 1;
+    if (TEMP_FAILURE_RETRY(write(fd, state, len)) != len) {
+        ALOGE("Failed to write driver state control param (%s)", strerror(errno));
+        ret = -1;
+    }
+    close(fd);
+    return ret;
+}
+#endif
+
+int is_wifi_driver_loaded() {
+    char driver_status[PROPERTY_VALUE_MAX];
+#ifdef WIFI_DRIVER_MODULE_PATH
+    FILE *proc;
+    char line[sizeof(DRIVER_MODULE_TAG)+10];
+#endif
+
+    if (!property_get(DRIVER_PROP_NAME, driver_status, NULL)
+            || strcmp(driver_status, "ok") != 0) {
+        return 0;  /* driver not loaded */
+    }
+#ifdef WIFI_DRIVER_MODULE_PATH
+    /*
+     * If the property says the driver is loaded, check to
+     * make sure that the property setting isn't just left
+     * over from a previous manual shutdown or a runtime
+     * crash.
+     */
+    if ((proc = fopen(MODULE_FILE, "r")) == NULL) {
+        ALOGW("Could not open %s: %s", MODULE_FILE, strerror(errno));
+        property_set(DRIVER_PROP_NAME, "unloaded");
+        return 0;
+    }
+    while ((fgets(line, sizeof(line), proc)) != NULL) {
+        if (strncmp(line, DRIVER_MODULE_TAG, strlen(DRIVER_MODULE_TAG)) == 0) {
+            fclose(proc);
+            return 1;
+        }
+    }
+    fclose(proc);
+    property_set(DRIVER_PROP_NAME, "unloaded");
+    return 0;
+#else
+    return 1;
+#endif
+}
+
+int wifi_load_driver()
+{
+#ifdef WIFI_DRIVER_MODULE_PATH
+    char driver_status[PROPERTY_VALUE_MAX];
+    int count = 100; /* wait at most 20 seconds for completion */
+
+    if (is_wifi_driver_loaded()) {
+        return 0;
+    }
+
+    if (insmod(DRIVER_MODULE_PATH, DRIVER_MODULE_ARG) < 0)
+        return -1;
+
+    if (strcmp(FIRMWARE_LOADER,"") == 0) {
+        /* usleep(WIFI_DRIVER_LOADER_DELAY); */
+        property_set(DRIVER_PROP_NAME, "ok");
+    }
+    else {
+        property_set("ctl.start", FIRMWARE_LOADER);
+    }
+    sched_yield();
+    while (count-- > 0) {
+        if (property_get(DRIVER_PROP_NAME, driver_status, NULL)) {
+            if (strcmp(driver_status, "ok") == 0)
+                return 0;
+            else if (strcmp(driver_status, "failed") == 0) {
+                wifi_unload_driver();
+                return -1;
+            }
+        }
+        usleep(200000);
+    }
+    property_set(DRIVER_PROP_NAME, "timeout");
+    wifi_unload_driver();
+    return -1;
+#else
+#ifdef WIFI_DRIVER_STATE_CTRL_PARAM
+    if (is_wifi_driver_loaded()) {
+        return 0;
+    }
+
+    if (wifi_change_driver_state(WIFI_DRIVER_STATE_ON) < 0)
+        return -1;
+#endif
+    property_set(DRIVER_PROP_NAME, "ok");
+    return 0;
+#endif
+}
+
+int wifi_unload_driver()
+{
+    usleep(200000); /* allow to finish interface down */
+#ifdef WIFI_DRIVER_MODULE_PATH
+    if (rmmod(DRIVER_MODULE_NAME) == 0) {
+        int count = 20; /* wait at most 10 seconds for completion */
+        while (count-- > 0) {
+            if (!is_wifi_driver_loaded())
+                break;
+            usleep(500000);
+        }
+        usleep(500000); /* allow card removal */
+        if (count) {
+            return 0;
+        }
+        return -1;
+    } else
+        return -1;
+#else
+#ifdef WIFI_DRIVER_STATE_CTRL_PARAM
+    if (is_wifi_driver_loaded()) {
+        if (wifi_change_driver_state(WIFI_DRIVER_STATE_OFF) < 0)
+            return -1;
+    }
+#endif
+    property_set(DRIVER_PROP_NAME, "unloaded");
+    return 0;
+#endif
+}
+
+int ensure_entropy_file_exists()
+{
+    int ret;
+    int destfd;
+
+    ret = access(SUPP_ENTROPY_FILE, R_OK|W_OK);
+    if ((ret == 0) || (errno == EACCES)) {
+        if ((ret != 0) &&
+            (chmod(SUPP_ENTROPY_FILE, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) != 0)) {
+            ALOGE("Cannot set RW to \"%s\": %s", SUPP_ENTROPY_FILE, strerror(errno));
+            return -1;
+        }
+        return 0;
+    }
+    destfd = TEMP_FAILURE_RETRY(open(SUPP_ENTROPY_FILE, O_CREAT|O_RDWR, 0660));
+    if (destfd < 0) {
+        ALOGE("Cannot create \"%s\": %s", SUPP_ENTROPY_FILE, strerror(errno));
+        return -1;
+    }
+
+    if (TEMP_FAILURE_RETRY(write(destfd, dummy_key, sizeof(dummy_key))) != sizeof(dummy_key)) {
+        ALOGE("Error writing \"%s\": %s", SUPP_ENTROPY_FILE, strerror(errno));
+        close(destfd);
+        return -1;
+    }
+    close(destfd);
+
+    /* chmod is needed because open() didn't set permisions properly */
+    if (chmod(SUPP_ENTROPY_FILE, 0660) < 0) {
+        ALOGE("Error changing permissions of %s to 0660: %s",
+             SUPP_ENTROPY_FILE, strerror(errno));
+        unlink(SUPP_ENTROPY_FILE);
+        return -1;
+    }
+
+    if (chown(SUPP_ENTROPY_FILE, AID_SYSTEM, AID_WIFI) < 0) {
+        ALOGE("Error changing group ownership of %s to %d: %s",
+             SUPP_ENTROPY_FILE, AID_WIFI, strerror(errno));
+        unlink(SUPP_ENTROPY_FILE);
+        return -1;
+    }
+    return 0;
+}
+
+int ensure_config_file_exists(const char *config_file)
+{
+    char buf[2048];
+    int srcfd, destfd;
+    struct stat sb;
+    int nread;
+    int ret;
+
+    ret = access(config_file, R_OK|W_OK);
+    if ((ret == 0) || (errno == EACCES)) {
+        if ((ret != 0) &&
+            (chmod(config_file, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) != 0)) {
+            ALOGE("Cannot set RW to \"%s\": %s", config_file, strerror(errno));
+            return -1;
+        }
+        return 0;
+    } else if (errno != ENOENT) {
+        ALOGE("Cannot access \"%s\": %s", config_file, strerror(errno));
+        return -1;
+    }
+
+    srcfd = TEMP_FAILURE_RETRY(open(SUPP_CONFIG_TEMPLATE, O_RDONLY));
+    if (srcfd < 0) {
+        ALOGE("Cannot open \"%s\": %s", SUPP_CONFIG_TEMPLATE, strerror(errno));
+        return -1;
+    }
+
+    destfd = TEMP_FAILURE_RETRY(open(config_file, O_CREAT|O_RDWR, 0660));
+    if (destfd < 0) {
+        close(srcfd);
+        ALOGE("Cannot create \"%s\": %s", config_file, strerror(errno));
+        return -1;
+    }
+
+    while ((nread = TEMP_FAILURE_RETRY(read(srcfd, buf, sizeof(buf)))) != 0) {
+        if (nread < 0) {
+            ALOGE("Error reading \"%s\": %s", SUPP_CONFIG_TEMPLATE, strerror(errno));
+            close(srcfd);
+            close(destfd);
+            unlink(config_file);
+            return -1;
+        }
+        TEMP_FAILURE_RETRY(write(destfd, buf, nread));
+    }
+
+    close(destfd);
+    close(srcfd);
+
+    /* chmod is needed because open() didn't set permisions properly */
+    if (chmod(config_file, 0660) < 0) {
+        ALOGE("Error changing permissions of %s to 0660: %s",
+             config_file, strerror(errno));
+        unlink(config_file);
+        return -1;
+    }
+
+    if (chown(config_file, AID_SYSTEM, AID_WIFI) < 0) {
+        ALOGE("Error changing group ownership of %s to %d: %s",
+             config_file, AID_WIFI, strerror(errno));
+        unlink(config_file);
+        return -1;
+    }
+    return 0;
+}
+
+int wifi_start_supplicant(int p2p_supported)
+{
+    char supp_status[PROPERTY_VALUE_MAX] = {'\0'};
+    int count = 200; /* wait at most 20 seconds for completion */
+    const prop_info *pi;
+    unsigned serial = 0, i;
+
+    if (p2p_supported) {
+        strcpy(supplicant_name, P2P_SUPPLICANT_NAME);
+        strcpy(supplicant_prop_name, P2P_PROP_NAME);
+
+        /* Ensure p2p config file is created */
+        if (ensure_config_file_exists(P2P_CONFIG_FILE) < 0) {
+            ALOGE("Failed to create a p2p config file");
+            return -1;
+        }
+
+    } else {
+        strcpy(supplicant_name, SUPPLICANT_NAME);
+        strcpy(supplicant_prop_name, SUPP_PROP_NAME);
+    }
+
+    /* Check whether already running */
+    if (property_get(supplicant_prop_name, supp_status, NULL)
+            && strcmp(supp_status, "running") == 0) {
+        return 0;
+    }
+
+    /* Before starting the daemon, make sure its config file exists */
+    if (ensure_config_file_exists(SUPP_CONFIG_FILE) < 0) {
+        ALOGE("Wi-Fi will not be enabled");
+        return -1;
+    }
+
+    if (ensure_entropy_file_exists() < 0) {
+        ALOGE("Wi-Fi entropy file was not created");
+    }
+
+    /* Clear out any stale socket files that might be left over. */
+    wpa_ctrl_cleanup();
+
+    /* Reset sockets used for exiting from hung state */
+    exit_sockets[0] = exit_sockets[1] = -1;
+
+    /*
+     * Get a reference to the status property, so we can distinguish
+     * the case where it goes stopped => running => stopped (i.e.,
+     * it start up, but fails right away) from the case in which
+     * it starts in the stopped state and never manages to start
+     * running at all.
+     */
+    pi = __system_property_find(supplicant_prop_name);
+    if (pi != NULL) {
+        serial = __system_property_serial(pi);
+    }
+    property_get("wifi.interface", primary_iface, WIFI_TEST_INTERFACE);
+
+    property_set("ctl.start", supplicant_name);
+    sched_yield();
+
+    while (count-- > 0) {
+        if (pi == NULL) {
+            pi = __system_property_find(supplicant_prop_name);
+        }
+        if (pi != NULL) {
+            /*
+             * property serial updated means that init process is scheduled
+             * after we sched_yield, further property status checking is based on this */
+            if (__system_property_serial(pi) != serial) {
+                __system_property_read(pi, NULL, supp_status);
+                if (strcmp(supp_status, "running") == 0) {
+                    return 0;
+                } else if (strcmp(supp_status, "stopped") == 0) {
+                    return -1;
+                }
+            }
+        }
+        usleep(100000);
+    }
+    return -1;
+}
+
+int wifi_stop_supplicant(int p2p_supported)
+{
+    char supp_status[PROPERTY_VALUE_MAX] = {'\0'};
+    int count = 50; /* wait at most 5 seconds for completion */
+
+    if (p2p_supported) {
+        strcpy(supplicant_name, P2P_SUPPLICANT_NAME);
+        strcpy(supplicant_prop_name, P2P_PROP_NAME);
+    } else {
+        strcpy(supplicant_name, SUPPLICANT_NAME);
+        strcpy(supplicant_prop_name, SUPP_PROP_NAME);
+    }
+
+    /* Check whether supplicant already stopped */
+    if (property_get(supplicant_prop_name, supp_status, NULL)
+        && strcmp(supp_status, "stopped") == 0) {
+        return 0;
+    }
+
+    property_set("ctl.stop", supplicant_name);
+    sched_yield();
+
+    while (count-- > 0) {
+        if (property_get(supplicant_prop_name, supp_status, NULL)) {
+            if (strcmp(supp_status, "stopped") == 0)
+                return 0;
+        }
+        usleep(100000);
+    }
+    ALOGE("Failed to stop supplicant");
+    return -1;
+}
+
+int wifi_connect_on_socket_path(const char *path)
+{
+    char supp_status[PROPERTY_VALUE_MAX] = {'\0'};
+
+    /* Make sure supplicant is running */
+    if (!property_get(supplicant_prop_name, supp_status, NULL)
+            || strcmp(supp_status, "running") != 0) {
+        ALOGE("Supplicant not running, cannot connect");
+        return -1;
+    }
+
+    ctrl_conn = wpa_ctrl_open(path);
+    if (ctrl_conn == NULL) {
+        ALOGE("Unable to open connection to supplicant on \"%s\": %s",
+             path, strerror(errno));
+        return -1;
+    }
+    monitor_conn = wpa_ctrl_open(path);
+    if (monitor_conn == NULL) {
+        wpa_ctrl_close(ctrl_conn);
+        ctrl_conn = NULL;
+        return -1;
+    }
+    if (wpa_ctrl_attach(monitor_conn) != 0) {
+        wpa_ctrl_close(monitor_conn);
+        wpa_ctrl_close(ctrl_conn);
+        ctrl_conn = monitor_conn = NULL;
+        return -1;
+    }
+
+    if (socketpair(AF_UNIX, SOCK_STREAM, 0, exit_sockets) == -1) {
+        wpa_ctrl_close(monitor_conn);
+        wpa_ctrl_close(ctrl_conn);
+        ctrl_conn = monitor_conn = NULL;
+        return -1;
+    }
+
+    return 0;
+}
+
+/* Establishes the control and monitor socket connections on the interface */
+int wifi_connect_to_supplicant()
+{
+    static char path[PATH_MAX];
+
+    if (access(IFACE_DIR, F_OK) == 0) {
+        snprintf(path, sizeof(path), "%s/%s", IFACE_DIR, primary_iface);
+    } else {
+        snprintf(path, sizeof(path), "@android:wpa_%s", primary_iface);
+    }
+    return wifi_connect_on_socket_path(path);
+}
+
+int wifi_send_command(const char *cmd, char *reply, size_t *reply_len)
+{
+    int ret;
+    if (ctrl_conn == NULL) {
+        ALOGV("Not connected to wpa_supplicant - \"%s\" command dropped.\n", cmd);
+        return -1;
+    }
+    ret = wpa_ctrl_request(ctrl_conn, cmd, strlen(cmd), reply, reply_len, NULL);
+    if (ret == -2) {
+        ALOGD("'%s' command timed out.\n", cmd);
+        /* unblocks the monitor receive socket for termination */
+        TEMP_FAILURE_RETRY(write(exit_sockets[0], "T", 1));
+        return -2;
+    } else if (ret < 0 || strncmp(reply, "FAIL", 4) == 0) {
+        return -1;
+    }
+    if (strncmp(cmd, "PING", 4) == 0) {
+        reply[*reply_len] = '\0';
+    }
+    return 0;
+}
+
+int wifi_supplicant_connection_active()
+{
+    char supp_status[PROPERTY_VALUE_MAX] = {'\0'};
+
+    if (property_get(supplicant_prop_name, supp_status, NULL)) {
+        if (strcmp(supp_status, "stopped") == 0)
+            return -1;
+    }
+
+    return 0;
+}
+
+int wifi_ctrl_recv(char *reply, size_t *reply_len)
+{
+    int res;
+    int ctrlfd = wpa_ctrl_get_fd(monitor_conn);
+    struct pollfd rfds[2];
+
+    memset(rfds, 0, 2 * sizeof(struct pollfd));
+    rfds[0].fd = ctrlfd;
+    rfds[0].events |= POLLIN;
+    rfds[1].fd = exit_sockets[1];
+    rfds[1].events |= POLLIN;
+    do {
+        res = TEMP_FAILURE_RETRY(poll(rfds, 2, 30000));
+        if (res < 0) {
+            ALOGE("Error poll = %d", res);
+            return res;
+        } else if (res == 0) {
+            /* timed out, check if supplicant is active
+             * or not ..
+             */
+            res = wifi_supplicant_connection_active();
+            if (res < 0)
+                return -2;
+        }
+    } while (res == 0);
+
+    if (rfds[0].revents & POLLIN) {
+        return wpa_ctrl_recv(monitor_conn, reply, reply_len);
+    }
+
+    /* it is not rfds[0], then it must be rfts[1] (i.e. the exit socket)
+     * or we timed out. In either case, this call has failed ..
+     */
+    return -2;
+}
+
+int wifi_wait_on_socket(char *buf, size_t buflen)
+{
+    size_t nread = buflen - 1;
+    int result;
+    char *match, *match2;
+
+    if (monitor_conn == NULL) {
+        return snprintf(buf, buflen, "IFNAME=%s %s - connection closed",
+                        primary_iface, WPA_EVENT_TERMINATING);
+    }
+
+    result = wifi_ctrl_recv(buf, &nread);
+
+    /* Terminate reception on exit socket */
+    if (result == -2) {
+        return snprintf(buf, buflen, "IFNAME=%s %s - connection closed",
+                        primary_iface, WPA_EVENT_TERMINATING);
+    }
+
+    if (result < 0) {
+        ALOGD("wifi_ctrl_recv failed: %s\n", strerror(errno));
+        return snprintf(buf, buflen, "IFNAME=%s %s - recv error",
+                        primary_iface, WPA_EVENT_TERMINATING);
+    }
+    buf[nread] = '\0';
+    /* Check for EOF on the socket */
+    if (result == 0 && nread == 0) {
+        /* Fabricate an event to pass up */
+        ALOGD("Received EOF on supplicant socket\n");
+        return snprintf(buf, buflen, "IFNAME=%s %s - signal 0 received",
+                        primary_iface, WPA_EVENT_TERMINATING);
+    }
+    /*
+     * Events strings are in the format
+     *
+     *     IFNAME=iface <N>CTRL-EVENT-XXX 
+     *        or
+     *     <N>CTRL-EVENT-XXX 
+     *
+     * where N is the message level in numerical form (0=VERBOSE, 1=DEBUG,
+     * etc.) and XXX is the event name. The level information is not useful
+     * to us, so strip it off.
+     */
+
+    if (strncmp(buf, IFNAME, IFNAMELEN) == 0) {
+        match = strchr(buf, ' ');
+        if (match != NULL) {
+            if (match[1] == '<') {
+                match2 = strchr(match + 2, '>');
+                if (match2 != NULL) {
+                    nread -= (match2 - match);
+                    memmove(match + 1, match2 + 1, nread - (match - buf) + 1);
+                }
+            }
+        } else {
+            return snprintf(buf, buflen, "%s", WPA_EVENT_IGNORE);
+        }
+    } else if (buf[0] == '<') {
+        match = strchr(buf, '>');
+        if (match != NULL) {
+            nread -= (match + 1 - buf);
+            memmove(buf, match + 1, nread + 1);
+            ALOGV("supplicant generated event without interface - %s\n", buf);
+        }
+    } else {
+        /* let the event go as is! */
+        ALOGW("supplicant generated event without interface and without message level - %s\n", buf);
+    }
+
+    return nread;
+}
+
+int wifi_wait_for_event(char *buf, size_t buflen)
+{
+    return wifi_wait_on_socket(buf, buflen);
+}
+
+void wifi_close_sockets()
+{
+    if (ctrl_conn != NULL) {
+        wpa_ctrl_close(ctrl_conn);
+        ctrl_conn = NULL;
+    }
+
+    if (monitor_conn != NULL) {
+        wpa_ctrl_close(monitor_conn);
+        monitor_conn = NULL;
+    }
+
+    if (exit_sockets[0] >= 0) {
+        close(exit_sockets[0]);
+        exit_sockets[0] = -1;
+    }
+
+    if (exit_sockets[1] >= 0) {
+        close(exit_sockets[1]);
+        exit_sockets[1] = -1;
+    }
+}
+
+void wifi_close_supplicant_connection()
+{
+    char supp_status[PROPERTY_VALUE_MAX] = {'\0'};
+    int count = 50; /* wait at most 5 seconds to ensure init has stopped stupplicant */
+
+    wifi_close_sockets();
+
+    while (count-- > 0) {
+        if (property_get(supplicant_prop_name, supp_status, NULL)) {
+            if (strcmp(supp_status, "stopped") == 0)
+                return;
+        }
+        usleep(100000);
+    }
+}
+
+int wifi_command(const char *command, char *reply, size_t *reply_len)
+{
+    return wifi_send_command(command, reply, reply_len);
+}
+
+const char *wifi_get_fw_path(int fw_type)
+{
+    switch (fw_type) {
+    case WIFI_GET_FW_PATH_STA:
+        return WIFI_DRIVER_FW_PATH_STA;
+    case WIFI_GET_FW_PATH_AP:
+        return WIFI_DRIVER_FW_PATH_AP;
+    case WIFI_GET_FW_PATH_P2P:
+        return WIFI_DRIVER_FW_PATH_P2P;
+    }
+    return NULL;
+}
+
+int wifi_change_fw_path(const char *fwpath)
+{
+    int len;
+    int fd;
+    int ret = 0;
+
+    if (!fwpath)
+        return ret;
+    fd = TEMP_FAILURE_RETRY(open(WIFI_DRIVER_FW_PATH_PARAM, O_WRONLY));
+    if (fd < 0) {
+        ALOGE("Failed to open wlan fw path param (%s)", strerror(errno));
+        return -1;
+    }
+    len = strlen(fwpath) + 1;
+    if (TEMP_FAILURE_RETRY(write(fd, fwpath, len)) != len) {
+        ALOGE("Failed to write wlan fw path param (%s)", strerror(errno));
+        ret = -1;
+    }
+    close(fd);
+    return ret;
+}