Merge "Fix security vulnerability in CryptoHal" into oc-dev
am: 20e00b3f96

Change-Id: I55c59bfe9a1d1e2444e4c5d7b244a0a99dae2b04
diff --git a/Android.bp b/Android.bp
index 53f8bec..b207a96 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1,20 +1,7 @@
-ndk_headers {
-    name: "libcamera2ndk_headers",
-    from: "include/camera/ndk/",
-    to: "camera",
-    srcs: ["include/camera/ndk/**/*.h"],
-    license: "NOTICE",
-}
-
-ndk_headers {
-    name: "libmediandk_headers",
-    from: "include/ndk/",
-    to: "media",
-    srcs: ["include/ndk/**/*.h"],
-    license: "NOTICE",
-}
-
 subdirs = [
-    "camera/ndk",
+    "camera",
+    "drm/*",
     "media/*",
+    "radio",
+    "soundtrigger",
 ]
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 361686c..5e4d81d 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -77,6 +77,7 @@
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/soundfx/libreverbwrapper.so)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/soundfx/libbundlewrapper.so)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/soundfx/libaudiopreprocessing.so)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/libmediacodecservice.so)
 
 # ************************************************
 # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
diff --git a/camera/Android.bp b/camera/Android.bp
new file mode 100644
index 0000000..c76ae50
--- /dev/null
+++ b/camera/Android.bp
@@ -0,0 +1,83 @@
+// Copyright 2010 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.
+
+subdirs = ["ndk"]
+
+cc_library_shared {
+    name: "libcamera_client",
+
+    aidl: {
+        export_aidl_headers: true,
+        local_include_dirs: ["aidl"],
+        include_dirs: [
+            "frameworks/native/aidl/gui",
+        ],
+    },
+
+    srcs: [
+        // AIDL files for camera interfaces
+        // The headers for these interfaces will be available to any modules that
+        // include libcamera_client, at the path "aidl/package/path/BnFoo.h"
+        "aidl/android/hardware/ICameraService.aidl",
+        "aidl/android/hardware/ICameraServiceListener.aidl",
+        "aidl/android/hardware/ICameraServiceProxy.aidl",
+        "aidl/android/hardware/camera2/ICameraDeviceCallbacks.aidl",
+        "aidl/android/hardware/camera2/ICameraDeviceUser.aidl",
+
+
+        // Source for camera interface parcelables, and manually-written interfaces
+        "Camera.cpp",
+        "CameraMetadata.cpp",
+        "CameraParameters.cpp",
+        "CaptureResult.cpp",
+        "CameraParameters2.cpp",
+        "ICamera.cpp",
+        "ICameraClient.cpp",
+        "ICameraRecordingProxy.cpp",
+        "ICameraRecordingProxyListener.cpp",
+        "camera2/CaptureRequest.cpp",
+        "camera2/OutputConfiguration.cpp",
+        "camera2/SubmitInfo.cpp",
+        "CameraBase.cpp",
+        "CameraUtils.cpp",
+        "VendorTagDescriptor.cpp",
+    ],
+
+    shared_libs: [
+        "libcutils",
+        "libutils",
+        "liblog",
+        "libbinder",
+        "libgui",
+        "libcamera_metadata",
+        "libnativewindow",
+    ],
+
+    include_dirs: [
+        "system/media/private/camera/include",
+        "frameworks/native/include/media/openmax",
+    ],
+    export_include_dirs: [
+         "include",
+         "include/camera"
+    ],
+    export_shared_lib_headers: ["libcamera_metadata"],
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+        "-Wextra",
+    ],
+
+}
diff --git a/camera/Android.mk b/camera/Android.mk
index 91d87ed..d9068c0 100644
--- a/camera/Android.mk
+++ b/camera/Android.mk
@@ -12,67 +12,4 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-CAMERA_CLIENT_LOCAL_PATH:= $(call my-dir)
 include $(call all-subdir-makefiles)
-include $(CLEAR_VARS)
-
-LOCAL_PATH := $(CAMERA_CLIENT_LOCAL_PATH)
-
-LOCAL_AIDL_INCLUDES := \
-    frameworks/av/camera/aidl \
-    frameworks/base/core/java \
-    frameworks/native/aidl/gui
-
-# AIDL files for camera interfaces
-# The headers for these interfaces will be available to any modules that
-# include libcamera_client, at the path "aidl/package/path/BnFoo.h"
-
-LOCAL_SRC_FILES := \
-    aidl/android/hardware/ICameraService.aidl \
-    aidl/android/hardware/ICameraServiceListener.aidl \
-    aidl/android/hardware/camera2/ICameraDeviceCallbacks.aidl \
-    aidl/android/hardware/camera2/ICameraDeviceUser.aidl
-
-# Source for camera interface parcelables, and manually-written interfaces
-
-LOCAL_SRC_FILES += \
-	Camera.cpp \
-	CameraMetadata.cpp \
-	CameraParameters.cpp \
-	CaptureResult.cpp \
-	CameraParameters2.cpp \
-	ICamera.cpp \
-	ICameraClient.cpp \
-	ICameraServiceProxy.cpp \
-	ICameraRecordingProxy.cpp \
-	ICameraRecordingProxyListener.cpp \
-	camera2/CaptureRequest.cpp \
-	camera2/OutputConfiguration.cpp \
-	camera2/SubmitInfo.cpp \
-	CameraBase.cpp \
-	CameraUtils.cpp \
-	VendorTagDescriptor.cpp
-
-LOCAL_SHARED_LIBRARIES := \
-	libcutils \
-	libutils \
-	liblog \
-	libbinder \
-	libgui \
-	libcamera_metadata \
-
-LOCAL_C_INCLUDES += \
-	system/media/camera/include \
-	system/media/private/camera/include \
-	frameworks/native/include/media/openmax \
-	$(LOCAL_PATH)/include/camera
-
-LOCAL_EXPORT_C_INCLUDE_DIRS := \
-	system/media/camera/include \
-	$(LOCAL_PATH)/include/camera
-
-LOCAL_CFLAGS += -Werror -Wall -Wextra
-
-LOCAL_MODULE:= libcamera_client
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/camera/ICameraServiceProxy.cpp b/camera/ICameraServiceProxy.cpp
deleted file mode 100644
index a9d0836..0000000
--- a/camera/ICameraServiceProxy.cpp
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2015 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 "BpCameraServiceProxy"
-
-#include <stdint.h>
-
-#include <binder/Parcel.h>
-
-#include <camera/ICameraServiceProxy.h>
-
-namespace android {
-
-class BpCameraServiceProxy: public BpInterface<ICameraServiceProxy> {
-public:
-    explicit BpCameraServiceProxy(const sp<IBinder>& impl)
-        : BpInterface<ICameraServiceProxy>(impl) {}
-
-    virtual void pingForUserUpdate() {
-        Parcel data;
-        data.writeInterfaceToken(ICameraServiceProxy::getInterfaceDescriptor());
-        remote()->transact(BnCameraServiceProxy::PING_FOR_USER_UPDATE, data, nullptr,
-                IBinder::FLAG_ONEWAY);
-    }
-
-    virtual void notifyCameraState(String16 cameraId, CameraState newCameraState) {
-        Parcel data;
-        data.writeInterfaceToken(ICameraServiceProxy::getInterfaceDescriptor());
-        data.writeString16(cameraId);
-        data.writeInt32(newCameraState);
-        remote()->transact(BnCameraServiceProxy::NOTIFY_CAMERA_STATE, data, nullptr,
-                IBinder::FLAG_ONEWAY);
-    }
-
-};
-
-
-IMPLEMENT_META_INTERFACE(CameraServiceProxy, "android.hardware.ICameraServiceProxy");
-
-status_t BnCameraServiceProxy::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
-        uint32_t flags) {
-    switch(code) {
-        case PING_FOR_USER_UPDATE: {
-            CHECK_INTERFACE(ICameraServiceProxy, data, reply);
-            pingForUserUpdate();
-            return NO_ERROR;
-        } break;
-        case NOTIFY_CAMERA_STATE: {
-            CHECK_INTERFACE(ICameraServiceProxy, data, reply);
-            String16 cameraId = data.readString16();
-            CameraState newCameraState =
-                static_cast<CameraState>(data.readInt32());
-            notifyCameraState(cameraId, newCameraState);
-            return NO_ERROR;
-        } break;
-        default:
-            return BBinder::onTransact(code, data, reply, flags);
-    }
-}
-}; // namespace android
diff --git a/camera/aidl/android/hardware/ICameraServiceProxy.aidl b/camera/aidl/android/hardware/ICameraServiceProxy.aidl
index 0e654d5..5dc23eb 100644
--- a/camera/aidl/android/hardware/ICameraServiceProxy.aidl
+++ b/camera/aidl/android/hardware/ICameraServiceProxy.aidl
@@ -31,7 +31,23 @@
     oneway void pingForUserUpdate();
 
     /**
-     * Update the status of a camera device
+     * Values for notifyCameraState newCameraState
      */
-     oneway void notifyCameraState(String cameraId, int newCameraState);
+    const int CAMERA_STATE_OPEN = 0;
+    const int CAMERA_STATE_ACTIVE = 1;
+    const int CAMERA_STATE_IDLE = 2;
+    const int CAMERA_STATE_CLOSED = 3;
+
+    /**
+     * Values for notifyCameraState facing
+     */
+    const int CAMERA_FACING_BACK = 0;
+    const int CAMERA_FACING_FRONT = 1;
+    const int CAMERA_FACING_EXTERNAL = 2;
+
+    /**
+     * Update the status of a camera device.
+     */
+    oneway void notifyCameraState(String cameraId, int facing, int newCameraState,
+            String clientName);
 }
diff --git a/camera/cameraserver/Android.mk b/camera/cameraserver/Android.mk
index d32e252..b8c94e6 100644
--- a/camera/cameraserver/Android.mk
+++ b/camera/cameraserver/Android.mk
@@ -30,8 +30,7 @@
 	android.hardware.camera.common@1.0 \
 	android.hardware.camera.provider@2.4 \
 	android.hardware.camera.device@1.0 \
-	android.hardware.camera.device@3.2 \
-	android.hidl.manager@1.0
+	android.hardware.camera.device@3.2
 
 LOCAL_MODULE:= cameraserver
 LOCAL_32_BIT_ONLY := true
diff --git a/camera/include/camera/ICameraServiceProxy.h b/camera/include/camera/ICameraServiceProxy.h
deleted file mode 100644
index 2613c01..0000000
--- a/camera/include/camera/ICameraServiceProxy.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2015 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_ICAMERASERVICEPROXY_H
-#define ANDROID_HARDWARE_ICAMERASERVICEPROXY_H
-
-#include <utils/RefBase.h>
-#include <binder/IInterface.h>
-#include <binder/Parcel.h>
-
-namespace android {
-
-/**
- * Interface from native camera service to managed-side camera service proxy.
- *
- * Keep in sync with frameworks/base/core/java/android/hardware/ICameraServiceProxy.aidl
- *
- */
-class ICameraServiceProxy : public IInterface {
-public:
-    enum {
-        PING_FOR_USER_UPDATE = IBinder::FIRST_CALL_TRANSACTION,
-        NOTIFY_CAMERA_STATE
-    };
-
-    enum CameraState {
-        CAMERA_STATE_OPEN,
-        CAMERA_STATE_ACTIVE,
-        CAMERA_STATE_IDLE,
-        CAMERA_STATE_CLOSED
-    };
-
-    DECLARE_META_INTERFACE(CameraServiceProxy);
-
-    virtual void pingForUserUpdate() = 0;
-    virtual void notifyCameraState(String16 cameraId, CameraState newCameraState) = 0;
-};
-
-class BnCameraServiceProxy: public BnInterface<ICameraServiceProxy>
-{
-public:
-    virtual status_t    onTransact( uint32_t code,
-                                    const Parcel& data,
-                                    Parcel* reply,
-                                    uint32_t flags = 0);
-};
-
-
-
-}; // namespace android
-
-#endif // ANDROID_HARDWARE_ICAMERASERVICEPROXY_H
diff --git a/camera/ndk/Android.bp b/camera/ndk/Android.bp
index ade0d72..97cf6bf 100644
--- a/camera/ndk/Android.bp
+++ b/camera/ndk/Android.bp
@@ -22,3 +22,11 @@
     first_version: "24",
     unversioned_until: "current",
 }
+
+ndk_headers {
+    name: "libcamera2ndk_headers",
+    from: "include/camera",
+    to: "camera",
+    srcs: ["include/camera/**/*.h"],
+    license: "NOTICE",
+}
diff --git a/camera/ndk/Android.mk b/camera/ndk/Android.mk
index 591dfc2..f5ff69d 100644
--- a/camera/ndk/Android.mk
+++ b/camera/ndk/Android.mk
@@ -33,9 +33,8 @@
 
 LOCAL_MODULE:= libcamera2ndk
 
-LOCAL_C_INCLUDES := \
-    frameworks/av/include/camera/ndk \
-    frameworks/av/include/ndk
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
 
 LOCAL_CFLAGS += -fvisibility=hidden -D EXPORT='__attribute__ ((visibility ("default")))'
 LOCAL_CFLAGS += -Wall -Wextra -Werror
@@ -49,7 +48,8 @@
     libcamera_client \
     libstagefright_foundation \
     libcutils \
-    libcamera_metadata
+    libcamera_metadata \
+    libmediandk
 
 include $(BUILD_SHARED_LIBRARY)
 
diff --git a/camera/ndk/NOTICE b/camera/ndk/NOTICE
new file mode 100644
index 0000000..152be20
--- /dev/null
+++ b/camera/ndk/NOTICE
@@ -0,0 +1,324 @@
+   =========================================================================
+   ==  NOTICE file corresponding to the section 4 d of                    ==
+   ==  the Apache License, Version 2.0,                                   ==
+   ==  in this case for the Android-specific code.                        ==
+   =========================================================================
+
+Android Code
+Copyright 2005-2008 The Android Open Source Project
+
+This product includes software developed as part of
+The Android Open Source Project (http://source.android.com).
+
+   =========================================================================
+   ==  NOTICE file corresponding to the section 4 d of                    ==
+   ==  the Apache License, Version 2.0,                                   ==
+   ==  in this case for Apache Commons code.                              ==
+   =========================================================================
+
+Apache Commons
+Copyright 1999-2006 The Apache Software Foundation
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
+
+   =========================================================================
+   ==  NOTICE file corresponding to the section 4 d of                    ==
+   ==  the Apache License, Version 2.0,                                   ==
+   ==  in this case for Jakarta Commons Logging.                          ==
+   =========================================================================
+
+Jakarta Commons Logging (JCL)
+Copyright 2005,2006 The Apache Software Foundation.
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
+
+   =========================================================================
+   ==  NOTICE file corresponding to the section 4 d of                    ==
+   ==  the Apache License, Version 2.0,                                   ==
+   ==  in this case for the Nuance code.                                  ==
+   =========================================================================
+
+These files are Copyright 2007 Nuance Communications, but released under
+the Apache2 License.
+
+   =========================================================================
+   ==  NOTICE file corresponding to the section 4 d of                    ==
+   ==  the Apache License, Version 2.0,                                   ==
+   ==  in this case for the Media Codecs code.                            ==
+   =========================================================================
+
+Media Codecs
+These files are Copyright 1998 - 2009 PacketVideo, but released under
+the Apache2 License.
+
+   =========================================================================
+   ==  NOTICE file corresponding to the section 4 d of                    ==
+   ==  the Apache License, Version 2.0,                                   ==
+   ==  in this case for the TagSoup code.                                 ==
+   =========================================================================
+
+This file is part of TagSoup and is Copyright 2002-2008 by John Cowan.
+
+TagSoup is licensed under the Apache License,
+Version 2.0.  You may obtain a copy of this license at
+http://www.apache.org/licenses/LICENSE-2.0 .  You may also have
+additional legal rights not granted by this license.
+
+TagSoup is distributed in the hope that it will be useful, but
+unless required by applicable law or agreed to in writing, TagSoup
+is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
+OF ANY KIND, either express or implied; not even the implied warranty
+of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+   =========================================================================
+   ==  NOTICE file corresponding to the section 4 d of                    ==
+   ==  the Apache License, Version 2.0,                                   ==
+   ==  in this case for Additional Codecs code.                           ==
+   =========================================================================
+
+Additional Codecs
+These files are Copyright 2003-2010 VisualOn, but released under
+the Apache2 License.
+
+  =========================================================================
+  ==  NOTICE file corresponding to the section 4 d of                    ==
+  ==  the Apache License, Version 2.0,                                   ==
+  ==  in this case for the Audio Effects code.                           ==
+  =========================================================================
+
+Audio Effects
+These files are Copyright (C) 2004-2010 NXP Software and
+Copyright (C) 2010 The Android Open Source Project, but released under
+the Apache2 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
+
+
+
+UNICODE, INC. LICENSE AGREEMENT - DATA FILES AND SOFTWARE
+
+Unicode Data Files include all data files under the directories
+http://www.unicode.org/Public/, http://www.unicode.org/reports/,
+and http://www.unicode.org/cldr/data/ . Unicode Software includes any
+source code published in the Unicode Standard or under the directories
+http://www.unicode.org/Public/, http://www.unicode.org/reports/, and
+http://www.unicode.org/cldr/data/.
+
+NOTICE TO USER: Carefully read the following legal agreement. BY
+DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING UNICODE INC.'S DATA
+FILES ("DATA FILES"), AND/OR SOFTWARE ("SOFTWARE"), YOU UNEQUIVOCALLY
+ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE TERMS AND CONDITIONS OF
+THIS AGREEMENT. IF YOU DO NOT AGREE, DO NOT DOWNLOAD, INSTALL, COPY,
+DISTRIBUTE OR USE THE DATA FILES OR SOFTWARE.
+
+COPYRIGHT AND PERMISSION NOTICE
+
+Copyright © 1991-2008 Unicode, Inc. All rights reserved. Distributed
+under the Terms of Use in http://www.unicode.org/copyright.html.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the Unicode data files and any associated documentation (the
+"Data Files") or Unicode software and any associated documentation (the
+"Software") to deal in the Data Files or Software without restriction,
+including without limitation the rights to use, copy, modify, merge,
+publish, distribute, and/or sell copies of the Data Files or Software,
+and to permit persons to whom the Data Files or Software are furnished to
+do so, provided that (a) the above copyright notice(s) and this permission
+notice appear with all copies of the Data Files or Software, (b) both the
+above copyright notice(s) and this permission notice appear in associated
+documentation, and (c) there is clear notice in each modified Data File
+or in the Software as well as in the documentation associated with the
+Data File(s) or Software that the data or software has been modified.
+
+THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
+INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
+OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
+OR PERFORMANCE OF THE DATA FILES OR SOFTWARE.
+
+Except as contained in this notice, the name of a copyright holder
+shall not be used in advertising or otherwise to promote the sale, use
+or other dealings in these Data Files or Software without prior written
+authorization of the copyright holder.
diff --git a/camera/ndk/NdkCameraCaptureSession.cpp b/camera/ndk/NdkCameraCaptureSession.cpp
index d6eff24..2a6b182 100644
--- a/camera/ndk/NdkCameraCaptureSession.cpp
+++ b/camera/ndk/NdkCameraCaptureSession.cpp
@@ -23,9 +23,9 @@
 #include <utils/StrongPointer.h>
 #include <utils/Trace.h>
 
-#include "NdkCameraDevice.h"
-#include <NdkCaptureRequest.h>
-#include <NdkCameraCaptureSession.h>
+#include <camera/NdkCameraDevice.h>
+#include <camera/NdkCaptureRequest.h>
+#include <camera/NdkCameraCaptureSession.h>
 #include "impl/ACameraCaptureSession.h"
 
 using namespace android;
diff --git a/camera/ndk/NdkCameraDevice.cpp b/camera/ndk/NdkCameraDevice.cpp
index 281d3e7..9f6d1f7 100644
--- a/camera/ndk/NdkCameraDevice.cpp
+++ b/camera/ndk/NdkCameraDevice.cpp
@@ -21,7 +21,7 @@
 #include <utils/Log.h>
 #include <utils/Trace.h>
 
-#include <NdkCameraDevice.h>
+#include <camera/NdkCameraDevice.h>
 #include "impl/ACameraCaptureSession.h"
 
 using namespace android;
diff --git a/camera/ndk/NdkCameraManager.cpp b/camera/ndk/NdkCameraManager.cpp
index ff15263..60b4763 100644
--- a/camera/ndk/NdkCameraManager.cpp
+++ b/camera/ndk/NdkCameraManager.cpp
@@ -21,7 +21,7 @@
 #include <utils/Log.h>
 #include <utils/Trace.h>
 
-#include <NdkCameraManager.h>
+#include <camera/NdkCameraManager.h>
 #include "impl/ACameraManager.h"
 
 using namespace android;
diff --git a/camera/ndk/NdkCameraMetadata.cpp b/camera/ndk/NdkCameraMetadata.cpp
index 85fe75b..65de81f 100644
--- a/camera/ndk/NdkCameraMetadata.cpp
+++ b/camera/ndk/NdkCameraMetadata.cpp
@@ -21,7 +21,7 @@
 #include <utils/Log.h>
 #include <utils/Trace.h>
 
-#include "NdkCameraMetadata.h"
+#include <camera/NdkCameraMetadata.h>
 #include "impl/ACameraMetadata.h"
 
 using namespace android;
diff --git a/camera/ndk/NdkCaptureRequest.cpp b/camera/ndk/NdkCaptureRequest.cpp
index 7c37955..5b4c180 100644
--- a/camera/ndk/NdkCaptureRequest.cpp
+++ b/camera/ndk/NdkCaptureRequest.cpp
@@ -21,7 +21,7 @@
 #include <utils/Log.h>
 #include <utils/Trace.h>
 
-#include "NdkCaptureRequest.h"
+#include <camera/NdkCaptureRequest.h>
 #include "impl/ACameraMetadata.h"
 #include "impl/ACaptureRequest.h"
 
diff --git a/camera/ndk/impl/ACameraCaptureSession.h b/camera/ndk/impl/ACameraCaptureSession.h
index f56219c..339c665 100644
--- a/camera/ndk/impl/ACameraCaptureSession.h
+++ b/camera/ndk/impl/ACameraCaptureSession.h
@@ -18,7 +18,7 @@
 
 #include <set>
 #include <hardware/camera3.h>
-#include <NdkCameraDevice.h>
+#include <camera/NdkCameraDevice.h>
 #include "ACameraDevice.h"
 
 using namespace android;
diff --git a/camera/ndk/impl/ACameraDevice.h b/camera/ndk/impl/ACameraDevice.h
index eb8028b..c566cd2 100644
--- a/camera/ndk/impl/ACameraDevice.h
+++ b/camera/ndk/impl/ACameraDevice.h
@@ -36,7 +36,7 @@
 #include <camera/camera2/OutputConfiguration.h>
 #include <camera/camera2/CaptureRequest.h>
 
-#include <NdkCameraDevice.h>
+#include <camera/NdkCameraDevice.h>
 #include "ACameraMetadata.h"
 
 namespace android {
diff --git a/camera/ndk/impl/ACameraManager.h b/camera/ndk/impl/ACameraManager.h
index 97e4fd9..4a172f3 100644
--- a/camera/ndk/impl/ACameraManager.h
+++ b/camera/ndk/impl/ACameraManager.h
@@ -17,7 +17,7 @@
 #ifndef _ACAMERA_MANAGER_H
 #define _ACAMERA_MANAGER_H
 
-#include "NdkCameraManager.h"
+#include <camera/NdkCameraManager.h>
 
 #include <android/hardware/ICameraService.h>
 #include <android/hardware/BnCameraServiceListener.h>
diff --git a/camera/ndk/impl/ACameraMetadata.cpp b/camera/ndk/impl/ACameraMetadata.cpp
index c0da592..7b33c32 100644
--- a/camera/ndk/impl/ACameraMetadata.cpp
+++ b/camera/ndk/impl/ACameraMetadata.cpp
@@ -20,7 +20,7 @@
 #include "ACameraMetadata.h"
 #include <utils/Vector.h>
 #include <system/graphics.h>
-#include "NdkImage.h"
+#include <media/NdkImage.h>
 
 using namespace android;
 
diff --git a/camera/ndk/impl/ACameraMetadata.h b/camera/ndk/impl/ACameraMetadata.h
index 8d050c4..143efc7 100644
--- a/camera/ndk/impl/ACameraMetadata.h
+++ b/camera/ndk/impl/ACameraMetadata.h
@@ -24,7 +24,7 @@
 #include <utils/Vector.h>
 #include <camera/CameraMetadata.h>
 
-#include "NdkCameraMetadata.h"
+#include <camera/NdkCameraMetadata.h>
 
 using namespace android;
 
diff --git a/camera/ndk/impl/ACaptureRequest.h b/camera/ndk/impl/ACaptureRequest.h
index 3ef6a84..e5b453e 100644
--- a/camera/ndk/impl/ACaptureRequest.h
+++ b/camera/ndk/impl/ACaptureRequest.h
@@ -16,7 +16,7 @@
 #ifndef _ACAPTURE_REQUEST_H
 #define _ACAPTURE_REQUEST_H
 
-#include "NdkCaptureRequest.h"
+#include <camera/NdkCaptureRequest.h>
 #include <set>
 
 using namespace android;
diff --git a/camera/include/camera/ndk/NdkCameraCaptureSession.h b/camera/ndk/include/camera/NdkCameraCaptureSession.h
similarity index 100%
rename from camera/include/camera/ndk/NdkCameraCaptureSession.h
rename to camera/ndk/include/camera/NdkCameraCaptureSession.h
diff --git a/camera/include/camera/ndk/NdkCameraDevice.h b/camera/ndk/include/camera/NdkCameraDevice.h
similarity index 100%
rename from camera/include/camera/ndk/NdkCameraDevice.h
rename to camera/ndk/include/camera/NdkCameraDevice.h
diff --git a/camera/include/camera/ndk/NdkCameraError.h b/camera/ndk/include/camera/NdkCameraError.h
similarity index 100%
rename from camera/include/camera/ndk/NdkCameraError.h
rename to camera/ndk/include/camera/NdkCameraError.h
diff --git a/camera/include/camera/ndk/NdkCameraManager.h b/camera/ndk/include/camera/NdkCameraManager.h
similarity index 100%
rename from camera/include/camera/ndk/NdkCameraManager.h
rename to camera/ndk/include/camera/NdkCameraManager.h
diff --git a/camera/include/camera/ndk/NdkCameraMetadata.h b/camera/ndk/include/camera/NdkCameraMetadata.h
similarity index 100%
rename from camera/include/camera/ndk/NdkCameraMetadata.h
rename to camera/ndk/include/camera/NdkCameraMetadata.h
diff --git a/camera/include/camera/ndk/NdkCameraMetadataTags.h b/camera/ndk/include/camera/NdkCameraMetadataTags.h
similarity index 100%
rename from camera/include/camera/ndk/NdkCameraMetadataTags.h
rename to camera/ndk/include/camera/NdkCameraMetadataTags.h
diff --git a/camera/include/camera/ndk/NdkCaptureRequest.h b/camera/ndk/include/camera/NdkCaptureRequest.h
similarity index 100%
rename from camera/include/camera/ndk/NdkCaptureRequest.h
rename to camera/ndk/include/camera/NdkCaptureRequest.h
diff --git a/cmds/screenrecord/Android.mk b/cmds/screenrecord/Android.mk
index a3b1a34..7aa684a 100644
--- a/cmds/screenrecord/Android.mk
+++ b/cmds/screenrecord/Android.mk
@@ -31,7 +31,7 @@
 LOCAL_C_INCLUDES := \
 	frameworks/av/media/libstagefright \
 	frameworks/av/media/libstagefright/include \
-	$(TOP)/frameworks/native/include/media/openmax \
+	frameworks/native/include/media/openmax \
 	external/jpeg
 
 LOCAL_CFLAGS := -Werror -Wall
diff --git a/cmds/stagefright/Android.mk b/cmds/stagefright/Android.mk
index ff5e5d3..f647ffd 100644
--- a/cmds/stagefright/Android.mk
+++ b/cmds/stagefright/Android.mk
@@ -16,7 +16,7 @@
 LOCAL_C_INCLUDES:= \
         frameworks/av/media/libstagefright \
         frameworks/av/media/libstagefright/include \
-        $(TOP)/frameworks/native/include/media/openmax \
+        frameworks/native/include/media/openmax \
         external/jpeg \
 
 LOCAL_CFLAGS += -Wno-multichar -Werror -Wall
@@ -40,8 +40,8 @@
 
 LOCAL_C_INCLUDES:= \
         frameworks/av/media/libstagefright \
-        $(TOP)/frameworks/native/include/media/openmax \
-        $(TOP)/frameworks/native/include/media/hardware
+        frameworks/native/include/media/openmax \
+        frameworks/native/include/media/hardware
 
 LOCAL_CFLAGS += -Wno-multichar -Werror -Wall
 
@@ -64,8 +64,8 @@
 
 LOCAL_C_INCLUDES:= \
         frameworks/av/media/libstagefright \
-        $(TOP)/frameworks/native/include/media/openmax \
-        $(TOP)/frameworks/native/include/media/hardware
+        frameworks/native/include/media/openmax \
+        frameworks/native/include/media/hardware
 
 LOCAL_CFLAGS += -Wno-multichar -Werror -Wall
 
@@ -89,7 +89,7 @@
 
 LOCAL_C_INCLUDES:= \
         frameworks/av/media/libstagefright \
-        $(TOP)/frameworks/native/include/media/openmax
+        frameworks/native/include/media/openmax
 
 LOCAL_CFLAGS += -Wno-multichar -Werror -Wall
 
@@ -112,7 +112,7 @@
 
 LOCAL_C_INCLUDES:= \
         frameworks/av/media/libstagefright \
-        $(TOP)/frameworks/native/include/media/openmax
+        frameworks/native/include/media/openmax
 
 LOCAL_CFLAGS += -Wno-multichar -Werror -Wall
 
@@ -136,7 +136,7 @@
 
 LOCAL_C_INCLUDES:= \
         frameworks/av/media/libstagefright \
-        $(TOP)/frameworks/native/include/media/openmax
+        frameworks/native/include/media/openmax
 
 LOCAL_CFLAGS += -Wno-multichar -Werror -Wall
 
@@ -168,10 +168,10 @@
         libRScpp \
 
 LOCAL_C_INCLUDES:= \
-        $(TOP)/frameworks/av/media/libstagefright \
-        $(TOP)/frameworks/native/include/media/openmax \
-        $(TOP)/frameworks/rs/cpp \
-        $(TOP)/frameworks/rs \
+        frameworks/av/media/libstagefright \
+        frameworks/native/include/media/openmax \
+        frameworks/rs/cpp \
+        frameworks/rs \
 
 intermediates := $(call intermediates-dir-for,STATIC_LIBRARIES,libRS,TARGET,)
 LOCAL_C_INCLUDES += $(intermediates)
@@ -185,6 +185,9 @@
 
 LOCAL_MODULE:= mediafilter
 
+LOCAL_SANITIZE := cfi
+LOCAL_SANITIZE_DIAG := cfi
+
 include $(BUILD_EXECUTABLE)
 
 ################################################################################
@@ -200,7 +203,7 @@
 
 LOCAL_C_INCLUDES:= \
         frameworks/av/media/libstagefright \
-        $(TOP)/frameworks/native/include/media/openmax
+        frameworks/native/include/media/openmax
 
 LOCAL_CFLAGS += -Wno-multichar -Werror -Wall
 
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index dfd5df7..d7c2e87 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -162,7 +162,7 @@
                        1,
                        mbuf->range_length(),
                        out),
-                (ssize_t)mbuf->range_length());
+                mbuf->range_length());
 
         mbuf->release();
         mbuf = NULL;
diff --git a/drm/common/Android.bp b/drm/common/Android.bp
new file mode 100644
index 0000000..0098c89
--- /dev/null
+++ b/drm/common/Android.bp
@@ -0,0 +1,39 @@
+//
+// Copyright (C) 2010 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.
+//
+
+cc_library_static {
+    name: "libdrmframeworkcommon",
+
+    srcs: [
+        "DrmConstraints.cpp",
+        "DrmMetadata.cpp",
+        "DrmConvertedStatus.cpp",
+        "DrmEngineBase.cpp",
+        "DrmInfo.cpp",
+        "DrmInfoRequest.cpp",
+        "DrmInfoStatus.cpp",
+        "DrmRights.cpp",
+        "DrmSupportInfo.cpp",
+        "IDrmManagerService.cpp",
+        "IDrmServiceListener.cpp",
+        "DrmInfoEvent.cpp",
+        "ReadWriteUtils.cpp",
+    ],
+
+    static_libs: ["libbinder"],
+
+    export_include_dirs: ["include"],
+}
diff --git a/drm/common/Android.mk b/drm/common/Android.mk
deleted file mode 100644
index ca3d2cd..0000000
--- a/drm/common/Android.mk
+++ /dev/null
@@ -1,45 +0,0 @@
-#
-# Copyright (C) 2010 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.
-#
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-    DrmConstraints.cpp \
-    DrmMetadata.cpp \
-    DrmConvertedStatus.cpp \
-    DrmEngineBase.cpp \
-    DrmInfo.cpp \
-    DrmInfoRequest.cpp \
-    DrmInfoStatus.cpp \
-    DrmRights.cpp \
-    DrmSupportInfo.cpp \
-    IDrmManagerService.cpp \
-    IDrmServiceListener.cpp \
-    DrmInfoEvent.cpp \
-    ReadWriteUtils.cpp
-
-LOCAL_STATIC_LIBRARIES := libbinder
-
-LOCAL_C_INCLUDES := \
-    $(TOP)/frameworks/av/include \
-    $(TOP)/frameworks/av/drm/libdrmframework/include \
-    $(TOP)/frameworks/av/drm/libdrmframework/plugins/common/include
-
-LOCAL_MODULE:= libdrmframeworkcommon
-
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_STATIC_LIBRARY)
diff --git a/drm/libdrmframework/plugins/common/include/DrmEngineBase.h b/drm/common/include/DrmEngineBase.h
similarity index 100%
rename from drm/libdrmframework/plugins/common/include/DrmEngineBase.h
rename to drm/common/include/DrmEngineBase.h
diff --git a/drm/libdrmframework/plugins/common/include/IDrmEngine.h b/drm/common/include/IDrmEngine.h
similarity index 100%
rename from drm/libdrmframework/plugins/common/include/IDrmEngine.h
rename to drm/common/include/IDrmEngine.h
diff --git a/drm/libdrmframework/include/IDrmManagerService.h b/drm/common/include/IDrmManagerService.h
similarity index 100%
rename from drm/libdrmframework/include/IDrmManagerService.h
rename to drm/common/include/IDrmManagerService.h
diff --git a/drm/libdrmframework/include/IDrmServiceListener.h b/drm/common/include/IDrmServiceListener.h
similarity index 100%
rename from drm/libdrmframework/include/IDrmServiceListener.h
rename to drm/common/include/IDrmServiceListener.h
diff --git a/drm/libdrmframework/include/ReadWriteUtils.h b/drm/common/include/ReadWriteUtils.h
similarity index 100%
rename from drm/libdrmframework/include/ReadWriteUtils.h
rename to drm/common/include/ReadWriteUtils.h
diff --git a/drm/drmserver/Android.bp b/drm/drmserver/Android.bp
new file mode 100644
index 0000000..c25a0a1
--- /dev/null
+++ b/drm/drmserver/Android.bp
@@ -0,0 +1,46 @@
+//
+// Copyright (C) 2010 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.
+//
+
+cc_binary {
+    name: "drmserver",
+
+    srcs: [
+        "main_drmserver.cpp",
+        "DrmManager.cpp",
+        "DrmManagerService.cpp",
+    ],
+
+    shared_libs: [
+        "libmedia",
+        "libutils",
+        "liblog",
+        "libbinder",
+        "libdl",
+        "libselinux",
+    ],
+
+    static_libs: ["libdrmframeworkcommon"],
+
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+    ],
+
+    compile_multilib: "32",
+
+    init_rc: ["drmserver.rc"],
+}
diff --git a/drm/drmserver/Android.mk b/drm/drmserver/Android.mk
deleted file mode 100644
index 3b8bb04..0000000
--- a/drm/drmserver/Android.mk
+++ /dev/null
@@ -1,49 +0,0 @@
-#
-# Copyright (C) 2010 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.
-#
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-    main_drmserver.cpp \
-    DrmManager.cpp \
-    DrmManagerService.cpp
-
-LOCAL_SHARED_LIBRARIES := \
-    libmedia \
-    libutils \
-    liblog \
-    libbinder \
-    libdl \
-    libselinux
-
-LOCAL_STATIC_LIBRARIES := libdrmframeworkcommon
-
-LOCAL_C_INCLUDES := \
-    $(TOP)/frameworks/av/include \
-    $(TOP)/frameworks/av/drm/libdrmframework/include \
-    $(TOP)/frameworks/av/drm/libdrmframework/plugins/common/include
-
-LOCAL_CFLAGS += -Wall -Wextra -Werror
-
-LOCAL_MODULE:= drmserver
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_32_BIT_ONLY := true
-
-LOCAL_INIT_RC := drmserver.rc
-
-include $(BUILD_EXECUTABLE)
diff --git a/drm/libdrmframework/include/DrmManager.h b/drm/drmserver/DrmManager.h
similarity index 100%
rename from drm/libdrmframework/include/DrmManager.h
rename to drm/drmserver/DrmManager.h
diff --git a/drm/libdrmframework/include/DrmManagerService.h b/drm/drmserver/DrmManagerService.h
similarity index 100%
rename from drm/libdrmframework/include/DrmManagerService.h
rename to drm/drmserver/DrmManagerService.h
diff --git a/drm/libdrmframework/include/PlugInManager.h b/drm/drmserver/PlugInManager.h
similarity index 100%
rename from drm/libdrmframework/include/PlugInManager.h
rename to drm/drmserver/PlugInManager.h
diff --git a/drm/libdrmframework/Android.bp b/drm/libdrmframework/Android.bp
new file mode 100644
index 0000000..43ba72b
--- /dev/null
+++ b/drm/libdrmframework/Android.bp
@@ -0,0 +1,42 @@
+//
+// Copyright (C) 2010 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.
+//
+
+cc_library_shared {
+    name: "libdrmframework",
+
+    srcs: [
+        "DrmManagerClientImpl.cpp",
+        "DrmManagerClient.cpp",
+        "NoOpDrmManagerClientImpl.cpp",
+    ],
+
+    shared_libs: [
+        "libutils",
+        "libcutils",
+        "liblog",
+        "libbinder",
+        "libdl",
+    ],
+
+    static_libs: ["libdrmframeworkcommon"],
+
+    export_include_dirs: ["include"],
+    export_static_lib_headers: ["libdrmframeworkcommon"],
+
+    cflags: ["-Werror"],
+}
+
+subdirs = ["plugins/*"]
diff --git a/drm/libdrmframework/Android.mk b/drm/libdrmframework/Android.mk
deleted file mode 100644
index cafcb94..0000000
--- a/drm/libdrmframework/Android.mk
+++ /dev/null
@@ -1,48 +0,0 @@
-#
-# Copyright (C) 2010 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.
-#
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-    DrmManagerClientImpl.cpp \
-    DrmManagerClient.cpp \
-    NoOpDrmManagerClientImpl.cpp
-
-LOCAL_MODULE:= libdrmframework
-
-LOCAL_SHARED_LIBRARIES := \
-    libutils \
-    libcutils \
-    liblog \
-    libbinder \
-    libdl
-
-LOCAL_STATIC_LIBRARIES := \
-    libdrmframeworkcommon
-
-LOCAL_C_INCLUDES += \
-    $(TOP)/frameworks/av/drm/libdrmframework/include \
-    $(TOP)/frameworks/av/include
-
-LOCAL_CFLAGS += -Werror
-
-
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_SHARED_LIBRARY)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/drm/libdrmframework/plugins/Android.mk b/drm/libdrmframework/plugins/Android.mk
deleted file mode 100644
index 9ee7961..0000000
--- a/drm/libdrmframework/plugins/Android.mk
+++ /dev/null
@@ -1,16 +0,0 @@
-#
-# Copyright (C) 2010 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 $(call all-subdir-makefiles)
diff --git a/drm/libdrmframework/plugins/common/Android.bp b/drm/libdrmframework/plugins/common/Android.bp
new file mode 100644
index 0000000..213e57f
--- /dev/null
+++ b/drm/libdrmframework/plugins/common/Android.bp
@@ -0,0 +1 @@
+subdirs = ["util"]
diff --git a/drm/libdrmframework/plugins/common/Android.mk b/drm/libdrmframework/plugins/common/Android.mk
deleted file mode 100644
index 9ee7961..0000000
--- a/drm/libdrmframework/plugins/common/Android.mk
+++ /dev/null
@@ -1,16 +0,0 @@
-#
-# Copyright (C) 2010 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 $(call all-subdir-makefiles)
diff --git a/drm/libdrmframework/plugins/common/util/Android.bp b/drm/libdrmframework/plugins/common/util/Android.bp
new file mode 100644
index 0000000..0c0b6f2
--- /dev/null
+++ b/drm/libdrmframework/plugins/common/util/Android.bp
@@ -0,0 +1,23 @@
+//
+// Copyright (C) 2010 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.
+//
+
+cc_library_static {
+    name: "libdrmutility",
+
+    srcs: ["src/MimeTypeUtil.cpp"],
+
+    export_include_dirs: ["include"],
+}
diff --git a/drm/libdrmframework/plugins/common/util/Android.mk b/drm/libdrmframework/plugins/common/util/Android.mk
deleted file mode 100644
index 2a7b01f..0000000
--- a/drm/libdrmframework/plugins/common/util/Android.mk
+++ /dev/null
@@ -1,42 +0,0 @@
-#
-# Copyright (C) 2010 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.
-#
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
-    src/MimeTypeUtil.cpp
-
-LOCAL_MODULE := libdrmutility
-
-base := frameworks/av
-
-LOCAL_C_INCLUDES += \
-    $(base)/include \
-    $(base)/include/drm \
-    $(base)/include/drm/plugins \
-    $(LOCAL_PATH)/include
-
-
-ifneq ($(TARGET_BUILD_VARIANT),user)
-LOCAL_C_INCLUDES += \
-    $(LOCAL_PATH)/tools
-
-endif
-
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_STATIC_LIBRARY)
diff --git a/drm/libdrmframework/plugins/forward-lock/Android.bp b/drm/libdrmframework/plugins/forward-lock/Android.bp
new file mode 100644
index 0000000..f884c14
--- /dev/null
+++ b/drm/libdrmframework/plugins/forward-lock/Android.bp
@@ -0,0 +1,4 @@
+subdirs = [
+    "FwdLockEngine",
+    "internal-format",
+]
diff --git a/drm/libdrmframework/plugins/forward-lock/Android.mk b/drm/libdrmframework/plugins/forward-lock/Android.mk
deleted file mode 100644
index 9ee7961..0000000
--- a/drm/libdrmframework/plugins/forward-lock/Android.mk
+++ /dev/null
@@ -1,16 +0,0 @@
-#
-# Copyright (C) 2010 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 $(call all-subdir-makefiles)
diff --git a/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.bp b/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.bp
new file mode 100644
index 0000000..3f0f5f7
--- /dev/null
+++ b/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.bp
@@ -0,0 +1,50 @@
+//
+// Copyright (C) 2010 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
+//2
+//      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.
+//
+
+cc_library_shared {
+    name: "libfwdlockengine",
+
+    cflags: [
+        "-DUSE_64BIT_DRM_API",
+        // The flag below turns on local debug printouts
+        //"-DDRM_OMA_FL_ENGINE_DEBUG",
+    ],
+
+    srcs: ["src/FwdLockEngine.cpp"],
+
+    shared_libs: [
+        "libicui18n",
+        "libicuuc",
+        "libutils",
+        "liblog",
+        "libdl",
+        "libcrypto",
+        "libssl",
+        "libdrmframework",
+    ],
+
+    static_libs: [
+        "libdrmutility",
+        "libdrmframeworkcommon",
+        "libfwdlock-common",
+        "libfwdlock-converter",
+        "libfwdlock-decoder",
+    ],
+
+    local_include_dirs: ["include"],
+
+    relative_install_path: "drm",
+}
diff --git a/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.mk b/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.mk
deleted file mode 100644
index 933464f..0000000
--- a/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.mk
+++ /dev/null
@@ -1,67 +0,0 @@
-#
-# Copyright (C) 2010 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.
-#
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-# The flag below turns on local debug printouts
-#LOCAL_CFLAGS += -DDRM_OMA_FL_ENGINE_DEBUG
-
-base := frameworks/av
-
-# Determine whether the DRM framework uses 64-bit data types for file offsets and do the same.
-ifneq ($(shell grep -c 'off64_t offset' $(base)/drm/libdrmframework/plugins/common/include/IDrmEngine.h), 0)
-LOCAL_CFLAGS += -DUSE_64BIT_DRM_API
-endif
-
-LOCAL_SRC_FILES:= \
-    src/FwdLockEngine.cpp
-
-LOCAL_MODULE := libfwdlockengine
-
-LOCAL_SHARED_LIBRARIES := \
-    libicui18n \
-    libicuuc \
-    libutils \
-    liblog \
-    libdl \
-    libcrypto \
-    libssl \
-    libdrmframework
-
-LOCAL_STATIC_LIBRARIES := \
-    libdrmutility \
-    libdrmframeworkcommon \
-    libfwdlock-common \
-    libfwdlock-converter \
-    libfwdlock-decoder
-
-
-
-LOCAL_C_INCLUDES += \
-    $(base)/include/drm \
-    $(base)/drm/libdrmframework/plugins/common/include \
-    $(base)/drm/libdrmframework/plugins/common/util/include \
-    $(base)/drm/libdrmframework/plugins/forward-lock/internal-format/common \
-    $(base)/drm/libdrmframework/plugins/forward-lock/internal-format/converter \
-    $(base)/drm/libdrmframework/plugins/forward-lock/internal-format/decoder \
-    $(LOCAL_PATH)/include
-
-LOCAL_MODULE_RELATIVE_PATH := drm
-
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/include/FwdLockEngine.h b/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/include/FwdLockEngine.h
index d222703..a571b3a 100644
--- a/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/include/FwdLockEngine.h
+++ b/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/include/FwdLockEngine.h
@@ -18,14 +18,14 @@
 #define __FWDLOCKENGINE_H__
 
 #include <DrmEngineBase.h>
-#include <DrmConstraints.h>
-#include <DrmRights.h>
-#include <DrmInfo.h>
-#include <DrmInfoStatus.h>
-#include <DrmConvertedStatus.h>
-#include <DrmInfoRequest.h>
-#include <DrmSupportInfo.h>
-#include <DrmInfoEvent.h>
+#include <drm/DrmConstraints.h>
+#include <drm/DrmRights.h>
+#include <drm/DrmInfo.h>
+#include <drm/DrmInfoStatus.h>
+#include <drm/DrmConvertedStatus.h>
+#include <drm/DrmInfoRequest.h>
+#include <drm/DrmSupportInfo.h>
+#include <drm/DrmInfoEvent.h>
 
 #include "SessionMap.h"
 #include "FwdLockConv.h"
diff --git a/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/src/FwdLockEngine.cpp b/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/src/FwdLockEngine.cpp
index a495616..830def9 100644
--- a/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/src/FwdLockEngine.cpp
+++ b/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/src/FwdLockEngine.cpp
@@ -20,17 +20,17 @@
 #include <errno.h>
 #include <stdio.h>
 #include <unistd.h>
-#include "drm_framework_common.h"
+#include <drm/drm_framework_common.h>
 #include <fcntl.h>
 #include <limits.h>
-#include <DrmRights.h>
-#include <DrmConstraints.h>
-#include <DrmMetadata.h>
-#include <DrmInfo.h>
-#include <DrmInfoStatus.h>
-#include <DrmInfoRequest.h>
-#include <DrmSupportInfo.h>
-#include <DrmConvertedStatus.h>
+#include <drm/DrmRights.h>
+#include <drm/DrmConstraints.h>
+#include <drm/DrmMetadata.h>
+#include <drm/DrmInfo.h>
+#include <drm/DrmInfoStatus.h>
+#include <drm/DrmInfoRequest.h>
+#include <drm/DrmSupportInfo.h>
+#include <drm/DrmConvertedStatus.h>
 #include <utils/String8.h>
 #include "FwdLockConv.h"
 #include "FwdLockFile.h"
diff --git a/drm/libdrmframework/plugins/forward-lock/internal-format/Android.bp b/drm/libdrmframework/plugins/forward-lock/internal-format/Android.bp
new file mode 100644
index 0000000..9f58e26
--- /dev/null
+++ b/drm/libdrmframework/plugins/forward-lock/internal-format/Android.bp
@@ -0,0 +1,5 @@
+subdirs = [
+    "common",
+    "converter",
+    "decoder",
+]
diff --git a/drm/libdrmframework/plugins/forward-lock/internal-format/Android.mk b/drm/libdrmframework/plugins/forward-lock/internal-format/Android.mk
deleted file mode 100644
index 9ee7961..0000000
--- a/drm/libdrmframework/plugins/forward-lock/internal-format/Android.mk
+++ /dev/null
@@ -1,16 +0,0 @@
-#
-# Copyright (C) 2010 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 $(call all-subdir-makefiles)
diff --git a/drm/libdrmframework/plugins/forward-lock/internal-format/common/Android.bp b/drm/libdrmframework/plugins/forward-lock/internal-format/common/Android.bp
new file mode 100644
index 0000000..698f278
--- /dev/null
+++ b/drm/libdrmframework/plugins/forward-lock/internal-format/common/Android.bp
@@ -0,0 +1,25 @@
+//
+// Copyright (C) 2010 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.
+//
+
+cc_library_static {
+    name: "libfwdlock-common",
+
+    srcs: ["FwdLockGlue.c"],
+
+    shared_libs: ["libcrypto"],
+
+    export_include_dirs: ["."],
+}
diff --git a/drm/libdrmframework/plugins/forward-lock/internal-format/common/Android.mk b/drm/libdrmframework/plugins/forward-lock/internal-format/common/Android.mk
deleted file mode 100644
index 3b4c8b4..0000000
--- a/drm/libdrmframework/plugins/forward-lock/internal-format/common/Android.mk
+++ /dev/null
@@ -1,29 +0,0 @@
-#
-# Copyright (C) 2010 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.
-#
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
-    FwdLockGlue.c
-
-LOCAL_SHARED_LIBRARIES := libcrypto
-
-LOCAL_MODULE := libfwdlock-common
-
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_STATIC_LIBRARY)
diff --git a/drm/libdrmframework/plugins/forward-lock/internal-format/converter/Android.bp b/drm/libdrmframework/plugins/forward-lock/internal-format/converter/Android.bp
new file mode 100644
index 0000000..33f2fe0
--- /dev/null
+++ b/drm/libdrmframework/plugins/forward-lock/internal-format/converter/Android.bp
@@ -0,0 +1,26 @@
+//
+// Copyright (C) 2010 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.
+//
+
+cc_library_static {
+    name: "libfwdlock-converter",
+
+    srcs: ["FwdLockConv.c"],
+
+    shared_libs: ["libcrypto"],
+    static_libs: ["libfwdlock-common"],
+
+    export_include_dirs: ["."],
+}
diff --git a/drm/libdrmframework/plugins/forward-lock/internal-format/converter/Android.mk b/drm/libdrmframework/plugins/forward-lock/internal-format/converter/Android.mk
deleted file mode 100644
index 2f51f0c..0000000
--- a/drm/libdrmframework/plugins/forward-lock/internal-format/converter/Android.mk
+++ /dev/null
@@ -1,32 +0,0 @@
-#
-# Copyright (C) 2010 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.
-#
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
-    FwdLockConv.c
-
-LOCAL_C_INCLUDES := \
-    frameworks/av/drm/libdrmframework/plugins/forward-lock/internal-format/common
-
-LOCAL_SHARED_LIBRARIES := libcrypto
-
-LOCAL_MODULE := libfwdlock-converter
-
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_STATIC_LIBRARY)
diff --git a/drm/libdrmframework/plugins/forward-lock/internal-format/decoder/Android.bp b/drm/libdrmframework/plugins/forward-lock/internal-format/decoder/Android.bp
new file mode 100644
index 0000000..b6d7a06
--- /dev/null
+++ b/drm/libdrmframework/plugins/forward-lock/internal-format/decoder/Android.bp
@@ -0,0 +1,26 @@
+//
+// Copyright (C) 2010 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.
+//
+
+cc_library_static {
+    name: "libfwdlock-decoder",
+
+    srcs: ["FwdLockFile.c"],
+
+    shared_libs: ["libcrypto"],
+    static_libs: ["libfwdlock-common"],
+
+    export_include_dirs: ["."],
+}
diff --git a/drm/libdrmframework/plugins/forward-lock/internal-format/decoder/Android.mk b/drm/libdrmframework/plugins/forward-lock/internal-format/decoder/Android.mk
deleted file mode 100644
index 3399ae5..0000000
--- a/drm/libdrmframework/plugins/forward-lock/internal-format/decoder/Android.mk
+++ /dev/null
@@ -1,32 +0,0 @@
-#
-# Copyright (C) 2010 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.
-#
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
-    FwdLockFile.c
-
-LOCAL_C_INCLUDES := \
-    frameworks/av/drm/libdrmframework/plugins/forward-lock/internal-format/common
-
-LOCAL_SHARED_LIBRARIES := libcrypto
-
-LOCAL_MODULE := libfwdlock-decoder
-
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_STATIC_LIBRARY)
diff --git a/drm/libdrmframework/plugins/passthru/Android.bp b/drm/libdrmframework/plugins/passthru/Android.bp
new file mode 100644
index 0000000..1dcf89c
--- /dev/null
+++ b/drm/libdrmframework/plugins/passthru/Android.bp
@@ -0,0 +1,36 @@
+//
+// Copyright (C) 2010 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.
+//
+
+cc_library_shared {
+    name: "libdrmpassthruplugin",
+
+    srcs: ["src/DrmPassthruPlugIn.cpp"],
+
+    static_libs: ["libdrmframeworkcommon"],
+
+    shared_libs: [
+        "libutils",
+        "liblog",
+        "libdl",
+    ],
+
+    local_include_dirs: ["include"],
+
+    cflags: [
+        // Set the following flag to enable the decryption passthru flow
+        //"-DENABLE_PASSTHRU_DECRYPTION",
+    ],
+}
diff --git a/drm/libdrmframework/plugins/passthru/Android.mk b/drm/libdrmframework/plugins/passthru/Android.mk
deleted file mode 100644
index cb3a2e2..0000000
--- a/drm/libdrmframework/plugins/passthru/Android.mk
+++ /dev/null
@@ -1,43 +0,0 @@
-#
-# Copyright (C) 2010 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.
-#
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-    src/DrmPassthruPlugIn.cpp
-
-LOCAL_MODULE := libdrmpassthruplugin
-
-LOCAL_STATIC_LIBRARIES := libdrmframeworkcommon
-
-LOCAL_SHARED_LIBRARIES := \
-    libutils \
-    liblog \
-    libdl
-
-
-LOCAL_C_INCLUDES += \
-    $(TOP)/frameworks/av/drm/libdrmframework/include \
-    $(TOP)/frameworks/av/drm/libdrmframework/plugins/passthru/include \
-    $(TOP)/frameworks/av/drm/libdrmframework/plugins/common/include \
-    $(TOP)/frameworks/av/include
-
-# Set the following flag to enable the decryption passthru flow
-#LOCAL_CFLAGS += -DENABLE_PASSTHRU_DECRYPTION
-
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/drm/libdrmframework/plugins/passthru/src/DrmPassthruPlugIn.cpp b/drm/libdrmframework/plugins/passthru/src/DrmPassthruPlugIn.cpp
index 7f5b0ec..d7f2d28 100644
--- a/drm/libdrmframework/plugins/passthru/src/DrmPassthruPlugIn.cpp
+++ b/drm/libdrmframework/plugins/passthru/src/DrmPassthruPlugIn.cpp
@@ -245,6 +245,8 @@
     decryptHandle->status = DRM_NO_ERROR;
     decryptHandle->decryptInfo = NULL;
     return DRM_NO_ERROR;
+#else
+    (void)(decryptHandle); // unused
 #endif
 
     return DRM_ERROR_CANNOT_HANDLE;
diff --git a/drm/libmediadrm/Android.bp b/drm/libmediadrm/Android.bp
new file mode 100644
index 0000000..66f5fc2
--- /dev/null
+++ b/drm/libmediadrm/Android.bp
@@ -0,0 +1,51 @@
+//
+// libmediadrm
+//
+
+cc_library_shared {
+    name: "libmediadrm",
+
+    aidl: {
+        local_include_dirs: ["aidl"],
+        export_aidl_headers: true,
+    },
+
+    srcs: [
+        "aidl/android/media/ICas.aidl",
+        "aidl/android/media/ICasListener.aidl",
+        "aidl/android/media/IDescrambler.aidl",
+        "aidl/android/media/IMediaCasService.aidl",
+
+        "CasImpl.cpp",
+        "DescramblerImpl.cpp",
+        "DrmPluginPath.cpp",
+        "DrmSessionManager.cpp",
+        "ICrypto.cpp",
+        "IDrm.cpp",
+        "IDrmClient.cpp",
+        "IMediaDrmService.cpp",
+        "MediaCasDefs.cpp",
+        "SharedLibrary.cpp",
+        "DrmHal.cpp",
+        "CryptoHal.cpp",
+    ],
+
+    shared_libs: [
+        "libbinder",
+        "libcutils",
+        "libdl",
+        "liblog",
+        "libmediautils",
+        "libstagefright_foundation",
+        "libutils",
+        "android.hardware.drm@1.0",
+        "libhidlbase",
+        "libhidlmemory",
+        "libhidltransport",
+    ],
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+    ],
+}
diff --git a/drm/libmediadrm/Android.mk b/drm/libmediadrm/Android.mk
deleted file mode 100644
index 5b56501..0000000
--- a/drm/libmediadrm/Android.mk
+++ /dev/null
@@ -1,62 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-#
-# libmediadrm
-#
-
-include $(CLEAR_VARS)
-
-LOCAL_AIDL_INCLUDES := \
-    frameworks/av/drm/libmediadrm/aidl
-
-LOCAL_SRC_FILES := \
-    aidl/android/media/ICas.aidl \
-    aidl/android/media/ICasListener.aidl \
-    aidl/android/media/IDescrambler.aidl \
-    aidl/android/media/IMediaCasService.aidl \
-
-LOCAL_SRC_FILES += \
-    CasImpl.cpp \
-    DescramblerImpl.cpp \
-    DrmPluginPath.cpp \
-    DrmSessionManager.cpp \
-    ICrypto.cpp \
-    IDrm.cpp \
-    IDrmClient.cpp \
-    IMediaDrmService.cpp \
-    MediaCasDefs.cpp \
-    SharedLibrary.cpp
-ifneq ($(DISABLE_TREBLE_DRM), true)
-LOCAL_SRC_FILES += \
-    DrmHal.cpp \
-    CryptoHal.cpp
-else
-LOCAL_SRC_FILES += \
-    Drm.cpp \
-    Crypto.cpp
-endif
-
-LOCAL_SHARED_LIBRARIES := \
-    libbinder \
-    libcutils \
-    libdl \
-    liblog \
-    libmediautils \
-    libstagefright_foundation \
-    libutils
-ifneq ($(DISABLE_TREBLE_DRM), true)
-LOCAL_SHARED_LIBRARIES += \
-    android.hidl.base@1.0 \
-    android.hardware.drm@1.0 \
-    libhidlbase \
-    libhidlmemory \
-    libhidltransport
-endif
-
-LOCAL_CFLAGS += -Werror -Wno-error=deprecated-declarations -Wall
-
-LOCAL_MODULE:= libmediadrm
-
-include $(BUILD_SHARED_LIBRARY)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/drm/libmediadrm/Crypto.cpp b/drm/libmediadrm/Crypto.cpp
deleted file mode 100644
index a5d7346..0000000
--- a/drm/libmediadrm/Crypto.cpp
+++ /dev/null
@@ -1,288 +0,0 @@
-/*
- * 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.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "Crypto"
-#include <utils/Log.h>
-#include <dirent.h>
-#include <dlfcn.h>
-
-#include <binder/IMemory.h>
-#include <media/Crypto.h>
-#include <media/DrmPluginPath.h>
-#include <media/hardware/CryptoAPI.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/AString.h>
-#include <media/stagefright/foundation/hexdump.h>
-#include <media/stagefright/MediaErrors.h>
-
-namespace android {
-
-KeyedVector<Vector<uint8_t>, String8> Crypto::mUUIDToLibraryPathMap;
-KeyedVector<String8, wp<SharedLibrary> > Crypto::mLibraryPathToOpenLibraryMap;
-Mutex Crypto::mMapLock;
-
-static bool operator<(const Vector<uint8_t> &lhs, const Vector<uint8_t> &rhs) {
-    if (lhs.size() < rhs.size()) {
-        return true;
-    } else if (lhs.size() > rhs.size()) {
-        return false;
-    }
-
-    return memcmp((void *)lhs.array(), (void *)rhs.array(), rhs.size()) < 0;
-}
-
-Crypto::Crypto()
-    : mInitCheck(NO_INIT),
-      mFactory(NULL),
-      mPlugin(NULL) {
-}
-
-Crypto::~Crypto() {
-    delete mPlugin;
-    mPlugin = NULL;
-    closeFactory();
-}
-
-void Crypto::closeFactory() {
-    delete mFactory;
-    mFactory = NULL;
-    mLibrary.clear();
-}
-
-status_t Crypto::initCheck() const {
-    return mInitCheck;
-}
-
-/*
- * Search the plugins directory for a plugin that supports the scheme
- * specified by uuid
- *
- * If found:
- *    mLibrary holds a strong pointer to the dlopen'd library
- *    mFactory is set to the library's factory method
- *    mInitCheck is set to OK
- *
- * If not found:
- *    mLibrary is cleared and mFactory are set to NULL
- *    mInitCheck is set to an error (!OK)
- */
-void Crypto::findFactoryForScheme(const uint8_t uuid[16]) {
-
-    closeFactory();
-
-    // lock static maps
-    Mutex::Autolock autoLock(mMapLock);
-
-    // first check cache
-    Vector<uint8_t> uuidVector;
-    uuidVector.appendArray(uuid, sizeof(uuid[0]) * 16);
-    ssize_t index = mUUIDToLibraryPathMap.indexOfKey(uuidVector);
-    if (index >= 0) {
-        if (loadLibraryForScheme(mUUIDToLibraryPathMap[index], uuid)) {
-            mInitCheck = OK;
-            return;
-        } else {
-            ALOGE("Failed to load from cached library path!");
-            mInitCheck = ERROR_UNSUPPORTED;
-            return;
-        }
-    }
-
-    // no luck, have to search
-    String8 dirPath(getDrmPluginPath());
-    String8 pluginPath;
-
-    DIR* pDir = opendir(dirPath.string());
-    if (pDir) {
-        struct dirent* pEntry;
-        while ((pEntry = readdir(pDir))) {
-
-            pluginPath = dirPath + "/" + pEntry->d_name;
-
-            if (pluginPath.getPathExtension() == ".so") {
-
-                if (loadLibraryForScheme(pluginPath, uuid)) {
-                    mUUIDToLibraryPathMap.add(uuidVector, pluginPath);
-                    mInitCheck = OK;
-                    closedir(pDir);
-                    return;
-                }
-            }
-        }
-
-        closedir(pDir);
-    }
-
-    // try the legacy libdrmdecrypt.so
-    pluginPath = "libdrmdecrypt.so";
-    if (loadLibraryForScheme(pluginPath, uuid)) {
-        mUUIDToLibraryPathMap.add(uuidVector, pluginPath);
-        mInitCheck = OK;
-        return;
-    }
-
-    mInitCheck = ERROR_UNSUPPORTED;
-}
-
-bool Crypto::loadLibraryForScheme(const String8 &path, const uint8_t uuid[16]) {
-
-    // get strong pointer to open shared library
-    ssize_t index = mLibraryPathToOpenLibraryMap.indexOfKey(path);
-    if (index >= 0) {
-        mLibrary = mLibraryPathToOpenLibraryMap[index].promote();
-    } else {
-        index = mLibraryPathToOpenLibraryMap.add(path, NULL);
-    }
-
-    if (!mLibrary.get()) {
-        mLibrary = new SharedLibrary(path);
-        if (!*mLibrary) {
-            ALOGE("loadLibraryForScheme failed:%s", mLibrary->lastError());
-            return false;
-        }
-
-        mLibraryPathToOpenLibraryMap.replaceValueAt(index, mLibrary);
-    }
-
-    typedef CryptoFactory *(*CreateCryptoFactoryFunc)();
-
-    CreateCryptoFactoryFunc createCryptoFactory =
-        (CreateCryptoFactoryFunc)mLibrary->lookup("createCryptoFactory");
-
-    if (createCryptoFactory == NULL ||
-        (mFactory = createCryptoFactory()) == NULL ||
-        !mFactory->isCryptoSchemeSupported(uuid)) {
-        ALOGE("createCryptoFactory failed:%s", mLibrary->lastError());
-        closeFactory();
-        return false;
-    }
-    return true;
-}
-
-bool Crypto::isCryptoSchemeSupported(const uint8_t uuid[16]) {
-    Mutex::Autolock autoLock(mLock);
-
-    if (mFactory && mFactory->isCryptoSchemeSupported(uuid)) {
-        return true;
-    }
-
-    findFactoryForScheme(uuid);
-    return (mInitCheck == OK);
-}
-
-status_t Crypto::createPlugin(
-        const uint8_t uuid[16], const void *data, size_t size) {
-    Mutex::Autolock autoLock(mLock);
-
-    if (mPlugin != NULL) {
-        return -EINVAL;
-    }
-
-    if (!mFactory || !mFactory->isCryptoSchemeSupported(uuid)) {
-        findFactoryForScheme(uuid);
-    }
-
-    if (mInitCheck != OK) {
-        return mInitCheck;
-    }
-
-    return mFactory->createPlugin(uuid, data, size, &mPlugin);
-}
-
-status_t Crypto::destroyPlugin() {
-    Mutex::Autolock autoLock(mLock);
-
-    if (mInitCheck != OK) {
-        return mInitCheck;
-    }
-
-    if (mPlugin == NULL) {
-        return -EINVAL;
-    }
-
-    delete mPlugin;
-    mPlugin = NULL;
-
-    return OK;
-}
-
-bool Crypto::requiresSecureDecoderComponent(const char *mime) const {
-    Mutex::Autolock autoLock(mLock);
-
-    if (mInitCheck != OK) {
-        return mInitCheck;
-    }
-
-    if (mPlugin == NULL) {
-        return -EINVAL;
-    }
-
-    return mPlugin->requiresSecureDecoderComponent(mime);
-}
-
-ssize_t Crypto::decrypt(const uint8_t key[16], const uint8_t iv[16],
-        CryptoPlugin::Mode mode, const CryptoPlugin::Pattern &pattern,
-        const sp<IMemory> &source, size_t offset,
-        const CryptoPlugin::SubSample *subSamples, size_t numSubSamples,
-        const ICrypto::DestinationBuffer &destination, AString *errorDetailMsg) {
-
-    Mutex::Autolock autoLock(mLock);
-
-    if (mInitCheck != OK) {
-        return mInitCheck;
-    }
-
-    if (mPlugin == NULL) {
-        return -EINVAL;
-    }
-
-    const void *srcPtr = static_cast<uint8_t *>(source->pointer()) + offset;
-
-    void *destPtr;
-    bool secure = false;
-    if (destination.mType == kDestinationTypeNativeHandle) {
-        destPtr = static_cast<void *>(destination.mHandle);
-        secure = true;
-    } else {
-        destPtr = destination.mSharedMemory->pointer();
-    }
-
-    ssize_t result = mPlugin->decrypt(secure, key, iv, mode, pattern, srcPtr, subSamples,
-            numSubSamples, destPtr, errorDetailMsg);
-
-    return result;
-}
-
-void Crypto::notifyResolution(uint32_t width, uint32_t height) {
-    Mutex::Autolock autoLock(mLock);
-
-    if (mInitCheck == OK && mPlugin != NULL) {
-        mPlugin->notifyResolution(width, height);
-    }
-}
-
-status_t Crypto::setMediaDrmSession(const Vector<uint8_t> &sessionId) {
-    Mutex::Autolock autoLock(mLock);
-
-    status_t result = NO_INIT;
-    if (mInitCheck == OK && mPlugin != NULL) {
-        result = mPlugin->setMediaDrmSession(sessionId);
-    }
-    return result;
-}
-
-}  // namespace android
diff --git a/drm/libmediadrm/Drm.cpp b/drm/libmediadrm/Drm.cpp
deleted file mode 100644
index 1004eb8..0000000
--- a/drm/libmediadrm/Drm.cpp
+++ /dev/null
@@ -1,799 +0,0 @@
-/*
- * Copyright (C) 2013 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_NDEBUG 0
-#define LOG_TAG "Drm"
-#include <utils/Log.h>
-
-#include <dirent.h>
-#include <dlfcn.h>
-
-#include <media/DrmPluginPath.h>
-#include <media/DrmSessionClientInterface.h>
-#include <media/DrmSessionManager.h>
-#include <media/Drm.h>
-#include <media/drm/DrmAPI.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/AString.h>
-#include <media/stagefright/foundation/hexdump.h>
-#include <media/stagefright/MediaErrors.h>
-#include <binder/IServiceManager.h>
-#include <binder/IPCThreadState.h>
-
-namespace android {
-
-static inline int getCallingPid() {
-    return IPCThreadState::self()->getCallingPid();
-}
-
-static bool checkPermission(const char* permissionString) {
-    if (getpid() == IPCThreadState::self()->getCallingPid()) return true;
-    bool ok = checkCallingPermission(String16(permissionString));
-    if (!ok) ALOGE("Request requires %s", permissionString);
-    return ok;
-}
-
-KeyedVector<Vector<uint8_t>, String8> Drm::mUUIDToLibraryPathMap;
-KeyedVector<String8, wp<SharedLibrary> > Drm::mLibraryPathToOpenLibraryMap;
-Mutex Drm::mMapLock;
-Mutex Drm::mLock;
-
-static bool operator<(const Vector<uint8_t> &lhs, const Vector<uint8_t> &rhs) {
-    if (lhs.size() < rhs.size()) {
-        return true;
-    } else if (lhs.size() > rhs.size()) {
-        return false;
-    }
-
-    return memcmp((void *)lhs.array(), (void *)rhs.array(), rhs.size()) < 0;
-}
-
-struct DrmSessionClient : public DrmSessionClientInterface {
-    explicit DrmSessionClient(Drm* drm) : mDrm(drm) {}
-
-    virtual bool reclaimSession(const Vector<uint8_t>& sessionId) {
-        sp<Drm> drm = mDrm.promote();
-        if (drm == NULL) {
-            return true;
-        }
-        status_t err = drm->closeSession(sessionId);
-        if (err != OK) {
-            return false;
-        }
-        drm->sendEvent(DrmPlugin::kDrmPluginEventSessionReclaimed, 0, &sessionId, NULL);
-        return true;
-    }
-
-protected:
-    virtual ~DrmSessionClient() {}
-
-private:
-    wp<Drm> mDrm;
-
-    DISALLOW_EVIL_CONSTRUCTORS(DrmSessionClient);
-};
-
-Drm::Drm()
-    : mInitCheck(NO_INIT),
-      mDrmSessionClient(new DrmSessionClient(this)),
-      mListener(NULL),
-      mFactory(NULL),
-      mPlugin(NULL) {
-}
-
-Drm::~Drm() {
-    DrmSessionManager::Instance()->removeDrm(mDrmSessionClient);
-    delete mPlugin;
-    mPlugin = NULL;
-    closeFactory();
-}
-
-void Drm::closeFactory() {
-    delete mFactory;
-    mFactory = NULL;
-    mLibrary.clear();
-}
-
-status_t Drm::initCheck() const {
-    return mInitCheck;
-}
-
-status_t Drm::setListener(const sp<IDrmClient>& listener)
-{
-    Mutex::Autolock lock(mEventLock);
-    if (mListener != NULL){
-        IInterface::asBinder(mListener)->unlinkToDeath(this);
-    }
-    if (listener != NULL) {
-        IInterface::asBinder(listener)->linkToDeath(this);
-    }
-    mListener = listener;
-    return NO_ERROR;
-}
-
-void Drm::sendEvent(DrmPlugin::EventType eventType, int extra,
-                    Vector<uint8_t> const *sessionId,
-                    Vector<uint8_t> const *data)
-{
-    mEventLock.lock();
-    sp<IDrmClient> listener = mListener;
-    mEventLock.unlock();
-
-    if (listener != NULL) {
-        Parcel obj;
-        writeByteArray(obj, sessionId);
-        writeByteArray(obj, data);
-
-        Mutex::Autolock lock(mNotifyLock);
-        listener->notify(eventType, extra, &obj);
-    }
-}
-
-void Drm::sendExpirationUpdate(Vector<uint8_t> const *sessionId,
-                               int64_t expiryTimeInMS)
-{
-    mEventLock.lock();
-    sp<IDrmClient> listener = mListener;
-    mEventLock.unlock();
-
-    if (listener != NULL) {
-        Parcel obj;
-        writeByteArray(obj, sessionId);
-        obj.writeInt64(expiryTimeInMS);
-
-        Mutex::Autolock lock(mNotifyLock);
-        listener->notify(DrmPlugin::kDrmPluginEventExpirationUpdate, 0, &obj);
-    }
-}
-
-void Drm::sendKeysChange(Vector<uint8_t> const *sessionId,
-                         Vector<DrmPlugin::KeyStatus> const *keyStatusList,
-                         bool hasNewUsableKey)
-{
-    mEventLock.lock();
-    sp<IDrmClient> listener = mListener;
-    mEventLock.unlock();
-
-    if (listener != NULL) {
-        Parcel obj;
-        writeByteArray(obj, sessionId);
-
-        size_t nkeys = keyStatusList->size();
-        obj.writeInt32(keyStatusList->size());
-        for (size_t i = 0; i < nkeys; ++i) {
-            const DrmPlugin::KeyStatus *keyStatus = &keyStatusList->itemAt(i);
-            writeByteArray(obj, &keyStatus->mKeyId);
-            obj.writeInt32(keyStatus->mType);
-        }
-        obj.writeInt32(hasNewUsableKey);
-
-        Mutex::Autolock lock(mNotifyLock);
-        listener->notify(DrmPlugin::kDrmPluginEventKeysChange, 0, &obj);
-    }
-}
-
-/*
- * Search the plugins directory for a plugin that supports the scheme
- * specified by uuid
- *
- * If found:
- *    mLibrary holds a strong pointer to the dlopen'd library
- *    mFactory is set to the library's factory method
- *    mInitCheck is set to OK
- *
- * If not found:
- *    mLibrary is cleared and mFactory are set to NULL
- *    mInitCheck is set to an error (!OK)
- */
-void Drm::findFactoryForScheme(const uint8_t uuid[16]) {
-
-    closeFactory();
-
-    // lock static maps
-    Mutex::Autolock autoLock(mMapLock);
-
-    // first check cache
-    Vector<uint8_t> uuidVector;
-    uuidVector.appendArray(uuid, sizeof(uuid[0]) * 16);
-    ssize_t index = mUUIDToLibraryPathMap.indexOfKey(uuidVector);
-    if (index >= 0) {
-        if (loadLibraryForScheme(mUUIDToLibraryPathMap[index], uuid)) {
-            mInitCheck = OK;
-            return;
-        } else {
-            ALOGE("Failed to load from cached library path!");
-            mInitCheck = ERROR_UNSUPPORTED;
-            return;
-        }
-    }
-
-    // no luck, have to search
-    String8 dirPath(getDrmPluginPath());
-    DIR* pDir = opendir(dirPath.string());
-
-    if (pDir == NULL) {
-        mInitCheck = ERROR_UNSUPPORTED;
-        ALOGE("Failed to open plugin directory %s", dirPath.string());
-        return;
-    }
-
-
-    struct dirent* pEntry;
-    while ((pEntry = readdir(pDir))) {
-
-        String8 pluginPath = dirPath + "/" + pEntry->d_name;
-
-        if (pluginPath.getPathExtension() == ".so") {
-
-            if (loadLibraryForScheme(pluginPath, uuid)) {
-                mUUIDToLibraryPathMap.add(uuidVector, pluginPath);
-                mInitCheck = OK;
-                closedir(pDir);
-                return;
-            }
-        }
-    }
-
-    closedir(pDir);
-
-    ALOGE("Failed to find drm plugin");
-    mInitCheck = ERROR_UNSUPPORTED;
-}
-
-bool Drm::loadLibraryForScheme(const String8 &path, const uint8_t uuid[16]) {
-
-    // get strong pointer to open shared library
-    ssize_t index = mLibraryPathToOpenLibraryMap.indexOfKey(path);
-    if (index >= 0) {
-        mLibrary = mLibraryPathToOpenLibraryMap[index].promote();
-    } else {
-        index = mLibraryPathToOpenLibraryMap.add(path, NULL);
-    }
-
-    if (!mLibrary.get()) {
-        mLibrary = new SharedLibrary(path);
-        if (!*mLibrary) {
-            return false;
-        }
-
-        mLibraryPathToOpenLibraryMap.replaceValueAt(index, mLibrary);
-    }
-
-    typedef DrmFactory *(*CreateDrmFactoryFunc)();
-
-    CreateDrmFactoryFunc createDrmFactory =
-        (CreateDrmFactoryFunc)mLibrary->lookup("createDrmFactory");
-
-    if (createDrmFactory == NULL ||
-        (mFactory = createDrmFactory()) == NULL ||
-        !mFactory->isCryptoSchemeSupported(uuid)) {
-        closeFactory();
-        return false;
-    }
-    return true;
-}
-
-bool Drm::isCryptoSchemeSupported(const uint8_t uuid[16], const String8 &mimeType) {
-
-    Mutex::Autolock autoLock(mLock);
-
-    if (!mFactory || !mFactory->isCryptoSchemeSupported(uuid)) {
-        findFactoryForScheme(uuid);
-        if (mInitCheck != OK) {
-            return false;
-        }
-    }
-
-    if (mimeType != "") {
-        return mFactory->isContentTypeSupported(mimeType);
-    }
-
-    return true;
-}
-
-status_t Drm::createPlugin(const uint8_t uuid[16],
-                           const String8& /* appPackageName */) {
-    Mutex::Autolock autoLock(mLock);
-
-    if (mPlugin != NULL) {
-        return -EINVAL;
-    }
-
-    if (!mFactory || !mFactory->isCryptoSchemeSupported(uuid)) {
-        findFactoryForScheme(uuid);
-    }
-
-    if (mInitCheck != OK) {
-        return mInitCheck;
-    }
-
-    status_t result = mFactory->createDrmPlugin(uuid, &mPlugin);
-    if (mPlugin) {
-        mPlugin->setListener(this);
-    } else {
-        ALOGE("Failed to create plugin");
-        return UNEXPECTED_NULL;
-    }
-    return result;
-}
-
-status_t Drm::destroyPlugin() {
-    Mutex::Autolock autoLock(mLock);
-
-    if (mInitCheck != OK) {
-        return mInitCheck;
-    }
-
-    if (mPlugin == NULL) {
-        return -EINVAL;
-    }
-
-    setListener(NULL);
-    delete mPlugin;
-    mPlugin = NULL;
-
-    return OK;
-}
-
-status_t Drm::openSession(Vector<uint8_t> &sessionId) {
-    Mutex::Autolock autoLock(mLock);
-
-    if (mInitCheck != OK) {
-        return mInitCheck;
-    }
-
-    if (mPlugin == NULL) {
-        return -EINVAL;
-    }
-
-    status_t err = mPlugin->openSession(sessionId);
-    if (err == ERROR_DRM_RESOURCE_BUSY) {
-        bool retry = false;
-        mLock.unlock();
-        // reclaimSession may call back to closeSession, since mLock is shared between Drm
-        // instances, we should unlock here to avoid deadlock.
-        retry = DrmSessionManager::Instance()->reclaimSession(getCallingPid());
-        mLock.lock();
-        if (mInitCheck != OK) {
-            return mInitCheck;
-        }
-
-        if (mPlugin == NULL) {
-            return -EINVAL;
-        }
-        if (retry) {
-            err = mPlugin->openSession(sessionId);
-        }
-    }
-    if (err == OK) {
-        DrmSessionManager::Instance()->addSession(getCallingPid(), mDrmSessionClient, sessionId);
-    }
-    return err;
-}
-
-status_t Drm::closeSession(Vector<uint8_t> const &sessionId) {
-    Mutex::Autolock autoLock(mLock);
-
-    if (mInitCheck != OK) {
-        return mInitCheck;
-    }
-
-    if (mPlugin == NULL) {
-        return -EINVAL;
-    }
-
-    status_t err = mPlugin->closeSession(sessionId);
-    if (err == OK) {
-        DrmSessionManager::Instance()->removeSession(sessionId);
-    }
-    return err;
-}
-
-status_t Drm::getKeyRequest(Vector<uint8_t> const &sessionId,
-                            Vector<uint8_t> const &initData,
-                            String8 const &mimeType, DrmPlugin::KeyType keyType,
-                            KeyedVector<String8, String8> const &optionalParameters,
-                            Vector<uint8_t> &request, String8 &defaultUrl,
-                            DrmPlugin::KeyRequestType *keyRequestType) {
-    Mutex::Autolock autoLock(mLock);
-
-    if (mInitCheck != OK) {
-        return mInitCheck;
-    }
-
-    if (mPlugin == NULL) {
-        return -EINVAL;
-    }
-
-    DrmSessionManager::Instance()->useSession(sessionId);
-
-    return mPlugin->getKeyRequest(sessionId, initData, mimeType, keyType,
-                                  optionalParameters, request, defaultUrl,
-                                  keyRequestType);
-}
-
-status_t Drm::provideKeyResponse(Vector<uint8_t> const &sessionId,
-                                 Vector<uint8_t> const &response,
-                                 Vector<uint8_t> &keySetId) {
-    Mutex::Autolock autoLock(mLock);
-
-    if (mInitCheck != OK) {
-        return mInitCheck;
-    }
-
-    if (mPlugin == NULL) {
-        return -EINVAL;
-    }
-
-    DrmSessionManager::Instance()->useSession(sessionId);
-
-    return mPlugin->provideKeyResponse(sessionId, response, keySetId);
-}
-
-status_t Drm::removeKeys(Vector<uint8_t> const &keySetId) {
-    Mutex::Autolock autoLock(mLock);
-
-    if (mInitCheck != OK) {
-        return mInitCheck;
-    }
-
-    if (mPlugin == NULL) {
-        return -EINVAL;
-    }
-
-    return mPlugin->removeKeys(keySetId);
-}
-
-status_t Drm::restoreKeys(Vector<uint8_t> const &sessionId,
-                          Vector<uint8_t> const &keySetId) {
-    Mutex::Autolock autoLock(mLock);
-
-    if (mInitCheck != OK) {
-        return mInitCheck;
-    }
-
-    if (mPlugin == NULL) {
-        return -EINVAL;
-    }
-
-    DrmSessionManager::Instance()->useSession(sessionId);
-
-    return mPlugin->restoreKeys(sessionId, keySetId);
-}
-
-status_t Drm::queryKeyStatus(Vector<uint8_t> const &sessionId,
-                             KeyedVector<String8, String8> &infoMap) const {
-    Mutex::Autolock autoLock(mLock);
-
-    if (mInitCheck != OK) {
-        return mInitCheck;
-    }
-
-    if (mPlugin == NULL) {
-        return -EINVAL;
-    }
-
-    DrmSessionManager::Instance()->useSession(sessionId);
-
-    return mPlugin->queryKeyStatus(sessionId, infoMap);
-}
-
-status_t Drm::getProvisionRequest(String8 const &certType, String8 const &certAuthority,
-                                  Vector<uint8_t> &request, String8 &defaultUrl) {
-    Mutex::Autolock autoLock(mLock);
-
-    if (mInitCheck != OK) {
-        return mInitCheck;
-    }
-
-    if (mPlugin == NULL) {
-        return -EINVAL;
-    }
-
-    return mPlugin->getProvisionRequest(certType, certAuthority,
-                                        request, defaultUrl);
-}
-
-status_t Drm::provideProvisionResponse(Vector<uint8_t> const &response,
-                                       Vector<uint8_t> &certificate,
-                                       Vector<uint8_t> &wrappedKey) {
-    Mutex::Autolock autoLock(mLock);
-
-    if (mInitCheck != OK) {
-        return mInitCheck;
-    }
-
-    if (mPlugin == NULL) {
-        return -EINVAL;
-    }
-
-    return mPlugin->provideProvisionResponse(response, certificate, wrappedKey);
-}
-
-status_t Drm::getSecureStops(List<Vector<uint8_t> > &secureStops) {
-    Mutex::Autolock autoLock(mLock);
-
-    if (mInitCheck != OK) {
-        return mInitCheck;
-    }
-
-    if (mPlugin == NULL) {
-        return -EINVAL;
-    }
-
-    return mPlugin->getSecureStops(secureStops);
-}
-
-status_t Drm::getSecureStop(Vector<uint8_t> const &ssid, Vector<uint8_t> &secureStop) {
-    Mutex::Autolock autoLock(mLock);
-
-    if (mInitCheck != OK) {
-        return mInitCheck;
-    }
-
-    if (mPlugin == NULL) {
-        return -EINVAL;
-    }
-
-    return mPlugin->getSecureStop(ssid, secureStop);
-}
-
-status_t Drm::releaseSecureStops(Vector<uint8_t> const &ssRelease) {
-    Mutex::Autolock autoLock(mLock);
-
-    if (mInitCheck != OK) {
-        return mInitCheck;
-    }
-
-    if (mPlugin == NULL) {
-        return -EINVAL;
-    }
-
-    return mPlugin->releaseSecureStops(ssRelease);
-}
-
-status_t Drm::releaseAllSecureStops() {
-    Mutex::Autolock autoLock(mLock);
-
-    if (mInitCheck != OK) {
-        return mInitCheck;
-    }
-
-    if (mPlugin == NULL) {
-        return -EINVAL;
-    }
-
-    return mPlugin->releaseAllSecureStops();
-}
-
-status_t Drm::getPropertyString(String8 const &name, String8 &value ) const {
-    Mutex::Autolock autoLock(mLock);
-
-    if (mInitCheck != OK) {
-        return mInitCheck;
-    }
-
-    if (mPlugin == NULL) {
-        return -EINVAL;
-    }
-
-    return mPlugin->getPropertyString(name, value);
-}
-
-status_t Drm::getPropertyByteArray(String8 const &name, Vector<uint8_t> &value ) const {
-    Mutex::Autolock autoLock(mLock);
-
-    if (mInitCheck != OK) {
-        return mInitCheck;
-    }
-
-    if (mPlugin == NULL) {
-        return -EINVAL;
-    }
-
-    return mPlugin->getPropertyByteArray(name, value);
-}
-
-status_t Drm::setPropertyString(String8 const &name, String8 const &value ) const {
-    Mutex::Autolock autoLock(mLock);
-
-    if (mInitCheck != OK) {
-        return mInitCheck;
-    }
-
-    if (mPlugin == NULL) {
-        return -EINVAL;
-    }
-
-    return mPlugin->setPropertyString(name, value);
-}
-
-status_t Drm::setPropertyByteArray(String8 const &name,
-                                   Vector<uint8_t> const &value ) const {
-    Mutex::Autolock autoLock(mLock);
-
-    if (mInitCheck != OK) {
-        return mInitCheck;
-    }
-
-    if (mPlugin == NULL) {
-        return -EINVAL;
-    }
-
-    return mPlugin->setPropertyByteArray(name, value);
-}
-
-
-status_t Drm::setCipherAlgorithm(Vector<uint8_t> const &sessionId,
-                                 String8 const &algorithm) {
-    Mutex::Autolock autoLock(mLock);
-
-    if (mInitCheck != OK) {
-        return mInitCheck;
-    }
-
-    if (mPlugin == NULL) {
-        return -EINVAL;
-    }
-
-    DrmSessionManager::Instance()->useSession(sessionId);
-
-    return mPlugin->setCipherAlgorithm(sessionId, algorithm);
-}
-
-status_t Drm::setMacAlgorithm(Vector<uint8_t> const &sessionId,
-                              String8 const &algorithm) {
-    Mutex::Autolock autoLock(mLock);
-
-    if (mInitCheck != OK) {
-        return mInitCheck;
-    }
-
-    if (mPlugin == NULL) {
-        return -EINVAL;
-    }
-
-    DrmSessionManager::Instance()->useSession(sessionId);
-
-    return mPlugin->setMacAlgorithm(sessionId, algorithm);
-}
-
-status_t Drm::encrypt(Vector<uint8_t> const &sessionId,
-                      Vector<uint8_t> const &keyId,
-                      Vector<uint8_t> const &input,
-                      Vector<uint8_t> const &iv,
-                      Vector<uint8_t> &output) {
-    Mutex::Autolock autoLock(mLock);
-
-    if (mInitCheck != OK) {
-        return mInitCheck;
-    }
-
-    if (mPlugin == NULL) {
-        return -EINVAL;
-    }
-
-    DrmSessionManager::Instance()->useSession(sessionId);
-
-    return mPlugin->encrypt(sessionId, keyId, input, iv, output);
-}
-
-status_t Drm::decrypt(Vector<uint8_t> const &sessionId,
-                      Vector<uint8_t> const &keyId,
-                      Vector<uint8_t> const &input,
-                      Vector<uint8_t> const &iv,
-                      Vector<uint8_t> &output) {
-    Mutex::Autolock autoLock(mLock);
-
-    if (mInitCheck != OK) {
-        return mInitCheck;
-    }
-
-    if (mPlugin == NULL) {
-        return -EINVAL;
-    }
-
-    DrmSessionManager::Instance()->useSession(sessionId);
-
-    return mPlugin->decrypt(sessionId, keyId, input, iv, output);
-}
-
-status_t Drm::sign(Vector<uint8_t> const &sessionId,
-                   Vector<uint8_t> const &keyId,
-                   Vector<uint8_t> const &message,
-                   Vector<uint8_t> &signature) {
-    Mutex::Autolock autoLock(mLock);
-
-    if (mInitCheck != OK) {
-        return mInitCheck;
-    }
-
-    if (mPlugin == NULL) {
-        return -EINVAL;
-    }
-
-    DrmSessionManager::Instance()->useSession(sessionId);
-
-    return mPlugin->sign(sessionId, keyId, message, signature);
-}
-
-status_t Drm::verify(Vector<uint8_t> const &sessionId,
-                     Vector<uint8_t> const &keyId,
-                     Vector<uint8_t> const &message,
-                     Vector<uint8_t> const &signature,
-                     bool &match) {
-    Mutex::Autolock autoLock(mLock);
-
-    if (mInitCheck != OK) {
-        return mInitCheck;
-    }
-
-    if (mPlugin == NULL) {
-        return -EINVAL;
-    }
-
-    DrmSessionManager::Instance()->useSession(sessionId);
-
-    return mPlugin->verify(sessionId, keyId, message, signature, match);
-}
-
-status_t Drm::signRSA(Vector<uint8_t> const &sessionId,
-                      String8 const &algorithm,
-                      Vector<uint8_t> const &message,
-                      Vector<uint8_t> const &wrappedKey,
-                      Vector<uint8_t> &signature) {
-    Mutex::Autolock autoLock(mLock);
-
-    if (mInitCheck != OK) {
-        return mInitCheck;
-    }
-
-    if (mPlugin == NULL) {
-        return -EINVAL;
-    }
-
-    if (!checkPermission("android.permission.ACCESS_DRM_CERTIFICATES")) {
-        return -EPERM;
-    }
-
-    DrmSessionManager::Instance()->useSession(sessionId);
-
-    return mPlugin->signRSA(sessionId, algorithm, message, wrappedKey, signature);
-}
-
-void Drm::binderDied(const wp<IBinder> &the_late_who __unused)
-{
-    mEventLock.lock();
-    mListener.clear();
-    mEventLock.unlock();
-
-    Mutex::Autolock autoLock(mLock);
-    delete mPlugin;
-    mPlugin = NULL;
-    closeFactory();
-}
-
-void Drm::writeByteArray(Parcel &obj, Vector<uint8_t> const *array)
-{
-    if (array && array->size()) {
-        obj.writeInt32(array->size());
-        obj.write(array->array(), array->size());
-    } else {
-        obj.writeInt32(0);
-    }
-}
-
-}  // namespace android
diff --git a/drm/libmediadrm/DrmHal.cpp b/drm/libmediadrm/DrmHal.cpp
index 386546f..074489a 100644
--- a/drm/libmediadrm/DrmHal.cpp
+++ b/drm/libmediadrm/DrmHal.cpp
@@ -245,6 +245,11 @@
                 plugin = hPlugin;
             }
         );
+
+    if (!hResult.isOk()) {
+        ALOGE("createPlugin remote call failed");
+    }
+
     return plugin;
 }
 
@@ -396,8 +401,11 @@
     if (mPlugin == NULL) {
         mInitCheck = ERROR_UNSUPPORTED;
     } else {
-        mInitCheck = OK;
-        mPlugin->setListener(this);
+        if (!mPlugin->setListener(this).isOk()) {
+            mInitCheck = DEAD_OBJECT;
+        } else {
+            mInitCheck = OK;
+        }
     }
 
     return mInitCheck;
@@ -411,12 +419,14 @@
     }
 
     setListener(NULL);
-    if (mPlugin != NULL) {
-        mPlugin->setListener(NULL);
-    }
-    mPlugin.clear();
     mInitCheck = NO_INIT;
 
+    if (mPlugin != NULL) {
+        if (!mPlugin->setListener(NULL).isOk()) {
+            mInitCheck = DEAD_OBJECT;
+        }
+    }
+    mPlugin.clear();
     return OK;
 }
 
@@ -472,11 +482,14 @@
         return mInitCheck;
     }
 
-    Status status = mPlugin->closeSession(toHidlVec(sessionId));
-    if (status == Status::OK) {
-        DrmSessionManager::Instance()->removeSession(sessionId);
+    Return<Status> status = mPlugin->closeSession(toHidlVec(sessionId));
+    if (status.isOk()) {
+        if (status == Status::OK) {
+            DrmSessionManager::Instance()->removeSession(sessionId);
+        }
+        return toStatusT(status);
     }
-    return toStatusT(status);
+    return DEAD_OBJECT;
 }
 
 status_t DrmHal::getKeyRequest(Vector<uint8_t> const &sessionId,
@@ -962,12 +975,16 @@
 void DrmHal::binderDied(const wp<IBinder> &the_late_who __unused)
 {
     Mutex::Autolock autoLock(mLock);
+
     setListener(NULL);
+    mInitCheck = NO_INIT;
+
     if (mPlugin != NULL) {
-        mPlugin->setListener(NULL);
+        if (!mPlugin->setListener(NULL).isOk()) {
+            mInitCheck = DEAD_OBJECT;
+        }
     }
     mPlugin.clear();
-    mInitCheck = NO_INIT;
 }
 
 void DrmHal::writeByteArray(Parcel &obj, hidl_vec<uint8_t> const &vec)
diff --git a/drm/mediadrm/Android.bp b/drm/mediadrm/Android.bp
new file mode 100644
index 0000000..b9f07f1
--- /dev/null
+++ b/drm/mediadrm/Android.bp
@@ -0,0 +1 @@
+subdirs = ["plugins/*"]
diff --git a/drm/mediadrm/plugins/clearkey/Android.bp b/drm/mediadrm/plugins/clearkey/Android.bp
new file mode 100644
index 0000000..2973fcf
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/Android.bp
@@ -0,0 +1,59 @@
+//
+// 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.
+//
+
+cc_library_shared {
+    name: "libdrmclearkeyplugin",
+
+    srcs: [
+        "AesCtrDecryptor.cpp",
+        "ClearKeyUUID.cpp",
+        "CreatePluginFactories.cpp",
+        "CryptoFactory.cpp",
+        "CryptoPlugin.cpp",
+        "DrmFactory.cpp",
+        "DrmPlugin.cpp",
+        "InitDataParser.cpp",
+        "JsonWebKey.cpp",
+        "Session.cpp",
+        "SessionLibrary.cpp",
+        "Utils.cpp",
+    ],
+
+    vendor: true,
+    relative_install_path: "mediadrm",
+
+    shared_libs: [
+        "libcrypto",
+        "liblog",
+        "libstagefright_foundation",
+        "libutils",
+    ],
+
+    static_libs: ["libjsmn"],
+
+    include_dirs: [
+        "frameworks/native/include",
+        "frameworks/av/include",
+    ],
+
+    export_include_dirs: ["."],
+    export_static_lib_headers: ["libjsmn"],
+}
+
+//########################################################################
+// Build unit tests
+
+subdirs = ["tests"]
diff --git a/drm/mediadrm/plugins/clearkey/Android.mk b/drm/mediadrm/plugins/clearkey/Android.mk
deleted file mode 100644
index 2efdcf5..0000000
--- a/drm/mediadrm/plugins/clearkey/Android.mk
+++ /dev/null
@@ -1,60 +0,0 @@
-#
-# 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.
-#
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
-    AesCtrDecryptor.cpp \
-    ClearKeyUUID.cpp \
-    CreatePluginFactories.cpp \
-    CryptoFactory.cpp \
-    CryptoPlugin.cpp \
-    DrmFactory.cpp \
-    DrmPlugin.cpp \
-    InitDataParser.cpp \
-    JsonWebKey.cpp \
-    Session.cpp \
-    SessionLibrary.cpp \
-    Utils.cpp \
-
-LOCAL_C_INCLUDES := \
-    external/jsmn \
-    frameworks/av/drm/mediadrm/plugins/clearkey \
-    frameworks/av/include \
-    frameworks/native/include \
-
-LOCAL_MODULE := libdrmclearkeyplugin
-
-LOCAL_PROPRIETARY_MODULE := true
-LOCAL_MODULE_RELATIVE_PATH := mediadrm
-
-LOCAL_SHARED_LIBRARIES := \
-    libcrypto \
-    liblog \
-    libstagefright_foundation \
-    libutils \
-
-LOCAL_STATIC_LIBRARIES := \
-    libjsmn \
-
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_SHARED_LIBRARY)
-
-#########################################################################
-# Build unit tests
-
-include $(LOCAL_PATH)/tests/Android.mk
diff --git a/drm/mediadrm/plugins/clearkey/tests/Android.bp b/drm/mediadrm/plugins/clearkey/tests/Android.bp
new file mode 100644
index 0000000..ac57d65
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/tests/Android.bp
@@ -0,0 +1,37 @@
+//
+// 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.
+//
+// ----------------------------------------------------------------
+// Builds ClearKey Drm Tests
+//
+
+cc_test {
+    name: "ClearKeyDrmUnitTest",
+    vendor: true,
+
+    srcs: [
+        "AesCtrDecryptorUnittest.cpp",
+        "InitDataParserUnittest.cpp",
+        "JsonWebKeyUnittest.cpp",
+    ],
+
+    shared_libs: [
+        "libcrypto",
+        "libdrmclearkeyplugin",
+        "liblog",
+        "libstagefright_foundation",
+        "libutils",
+    ],
+}
diff --git a/drm/mediadrm/plugins/clearkey/tests/Android.mk b/drm/mediadrm/plugins/clearkey/tests/Android.mk
deleted file mode 100644
index 392f218..0000000
--- a/drm/mediadrm/plugins/clearkey/tests/Android.mk
+++ /dev/null
@@ -1,43 +0,0 @@
-#
-# 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.
-#
-# ----------------------------------------------------------------
-# Builds ClearKey Drm Tests
-#
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := ClearKeyDrmUnitTest
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := \
-    AesCtrDecryptorUnittest.cpp \
-    InitDataParserUnittest.cpp \
-    JsonWebKeyUnittest.cpp \
-
-LOCAL_C_INCLUDES := \
-    external/jsmn \
-    frameworks/av/drm/mediadrm/plugins/clearkey \
-    frameworks/av/include \
-    frameworks/native/include \
-
-LOCAL_SHARED_LIBRARIES := \
-    libcrypto \
-    libdrmclearkeyplugin \
-    liblog \
-    libstagefright_foundation \
-    libutils \
-
-include $(BUILD_NATIVE_TEST)
diff --git a/drm/mediadrm/plugins/clearkey/tests/InitDataParserUnittest.cpp b/drm/mediadrm/plugins/clearkey/tests/InitDataParserUnittest.cpp
index e275108..84ed242 100644
--- a/drm/mediadrm/plugins/clearkey/tests/InitDataParserUnittest.cpp
+++ b/drm/mediadrm/plugins/clearkey/tests/InitDataParserUnittest.cpp
@@ -56,7 +56,7 @@
                               request.size());
         EXPECT_EQ(0, requestString.find(kRequestPrefix));
         EXPECT_EQ(requestString.size() - kRequestSuffix.size(),
-                  requestString.find(kRequestSuffix));
+                  (size_t)requestString.find(kRequestSuffix));
         for (size_t i = 0; i < expectedKeys.size(); ++i) {
             AString encodedIdAString;
             android::encodeBase64(expectedKeys[i], kKeyIdSize,
@@ -71,7 +71,7 @@
                                       const String8& mimeType) {
         Vector<uint8_t> request;
         ASSERT_NE(android::OK, attemptParse(initData, mimeType, &request));
-        EXPECT_EQ(0, request.size());
+        EXPECT_EQ(0u, request.size());
     }
 };
 
diff --git a/drm/mediadrm/plugins/mock/Android.bp b/drm/mediadrm/plugins/mock/Android.bp
new file mode 100644
index 0000000..7f44819
--- /dev/null
+++ b/drm/mediadrm/plugins/mock/Android.bp
@@ -0,0 +1,34 @@
+//
+// Copyright (C) 2013 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.
+//
+
+cc_library_shared {
+    name: "libmockdrmcryptoplugin",
+
+    srcs: ["MockDrmCryptoPlugin.cpp"],
+
+    vendor: true,
+    relative_install_path: "mediadrm",
+
+    shared_libs: [
+        "libutils",
+        "liblog",
+    ],
+
+    cflags: [
+        // Set the following flag to enable the decryption passthru flow
+        //"-DENABLE_PASSTHRU_DECRYPTION",
+    ],
+}
diff --git a/drm/mediadrm/plugins/mock/Android.mk b/drm/mediadrm/plugins/mock/Android.mk
deleted file mode 100644
index 26c245b..0000000
--- a/drm/mediadrm/plugins/mock/Android.mk
+++ /dev/null
@@ -1,39 +0,0 @@
-#
-# Copyright (C) 2013 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.
-#
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-    MockDrmCryptoPlugin.cpp
-
-LOCAL_MODULE := libmockdrmcryptoplugin
-
-LOCAL_PROPRIETARY_MODULE := true
-LOCAL_MODULE_RELATIVE_PATH := mediadrm
-
-LOCAL_SHARED_LIBRARIES := \
-    libutils liblog
-
-LOCAL_C_INCLUDES += \
-    $(TOP)/frameworks/av/include \
-    $(TOP)/frameworks/native/include/media
-
-# Set the following flag to enable the decryption passthru flow
-#LOCAL_CFLAGS += -DENABLE_PASSTHRU_DECRYPTION
-
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.cpp b/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.cpp
index c82b9d9..3b4145f 100644
--- a/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.cpp
+++ b/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.cpp
@@ -19,7 +19,7 @@
 #include <utils/Log.h>
 
 
-#include "drm/DrmAPI.h"
+#include "media/drm/DrmAPI.h"
 #include "MockDrmCryptoPlugin.h"
 #include "media/stagefright/MediaErrors.h"
 
@@ -730,7 +730,7 @@
 
     ssize_t MockDrmPlugin::findSession(Vector<uint8_t> const &sessionId) const
     {
-        ALOGD("findSession: nsessions=%u, size=%u", mSessions.size(), sessionId.size());
+        ALOGD("findSession: nsessions=%zu, size=%zu", mSessions.size(), sessionId.size());
         for (size_t i = 0; i < mSessions.size(); ++i) {
             if (memcmp(mSessions[i].array(), sessionId.array(), sessionId.size()) == 0) {
                 return i;
@@ -741,7 +741,7 @@
 
     ssize_t MockDrmPlugin::findKeySet(Vector<uint8_t> const &keySetId) const
     {
-        ALOGD("findKeySet: nkeySets=%u, size=%u", mKeySets.size(), keySetId.size());
+        ALOGD("findKeySet: nkeySets=%zu, size=%zu", mKeySets.size(), keySetId.size());
         for (size_t i = 0; i < mKeySets.size(); ++i) {
             if (memcmp(mKeySets[i].array(), keySetId.array(), keySetId.size()) == 0) {
                 return i;
@@ -792,8 +792,9 @@
     }
 
     ssize_t
-    MockCryptoPlugin::decrypt(bool secure, const uint8_t key[16], const uint8_t iv[16],
-            Mode mode, const Pattern &pattern, const void *srcPtr,
+    MockCryptoPlugin::decrypt(bool secure, const uint8_t key[DECRYPT_KEY_SIZE],
+            const uint8_t iv[DECRYPT_KEY_SIZE], Mode mode,
+            const Pattern &pattern, const void *srcPtr,
             const SubSample *subSamples, size_t numSubSamples,
             void *dstPtr, AString * /* errorDetailMsg */)
     {
@@ -801,8 +802,8 @@
               "pattern:{encryptBlocks=%d, skipBlocks=%d} src=%p, "
               "subSamples=%s, dst=%p)",
               (int)secure,
-              arrayToString(key, sizeof(key)).string(),
-              arrayToString(iv, sizeof(iv)).string(),
+              arrayToString(key, DECRYPT_KEY_SIZE).string(),
+              arrayToString(iv, DECRYPT_KEY_SIZE).string(),
               (int)mode, pattern.mEncryptBlocks, pattern.mSkipBlocks, srcPtr,
               subSamplesToString(subSamples, numSubSamples).string(),
               dstPtr);
diff --git a/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.h b/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.h
index 9f8db17..4178c03 100644
--- a/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.h
+++ b/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.h
@@ -16,8 +16,8 @@
 
 #include <utils/Mutex.h>
 
-#include "drm/DrmAPI.h"
-#include "hardware/CryptoAPI.h"
+#include "media/drm/DrmAPI.h"
+#include "media/hardware/CryptoAPI.h"
 
 extern "C" {
       android::DrmFactory *createDrmFactory();
@@ -158,9 +158,12 @@
 
         bool requiresSecureDecoderComponent(const char *mime) const;
 
+        static constexpr size_t DECRYPT_KEY_SIZE = 16;
+
         ssize_t decrypt(bool secure,
-            const uint8_t key[16], const uint8_t iv[16],
-            Mode mode, const Pattern &pattern, const void *srcPtr,
+            const uint8_t key[DECRYPT_KEY_SIZE],
+            const uint8_t iv[DECRYPT_KEY_SIZE], Mode mode,
+            const Pattern &pattern, const void *srcPtr,
             const SubSample *subSamples, size_t numSubSamples,
             void *dstPtr, AString *errorDetailMsg);
     private:
diff --git a/include/media/AudioClient.h b/include/media/AudioClient.h
new file mode 120000
index 0000000..a0530e4
--- /dev/null
+++ b/include/media/AudioClient.h
@@ -0,0 +1 @@
+../../media/libaudioclient/include/media/AudioClient.h
\ No newline at end of file
diff --git a/include/media/CasImpl.h b/include/media/CasImpl.h
index 0dd506c..726f1ce 100644
--- a/include/media/CasImpl.h
+++ b/include/media/CasImpl.h
@@ -27,7 +27,7 @@
 using namespace media;
 using namespace MediaCas;
 using binder::Status;
-class CasPlugin;
+struct CasPlugin;
 class SharedLibrary;
 
 class CasImpl : public BnCas {
diff --git a/include/media/DescramblerImpl.h b/include/media/DescramblerImpl.h
index c1c79b3..9f212ac 100644
--- a/include/media/DescramblerImpl.h
+++ b/include/media/DescramblerImpl.h
@@ -24,7 +24,7 @@
 using namespace media;
 using namespace MediaDescrambler;
 using binder::Status;
-class DescramblerPlugin;
+struct DescramblerPlugin;
 class SharedLibrary;
 
 class DescramblerImpl : public BnDescrambler {
diff --git a/include/media/Interpolator.h b/include/media/Interpolator.h
index 45a0585..703cf77 100644
--- a/include/media/Interpolator.h
+++ b/include/media/Interpolator.h
@@ -278,7 +278,7 @@
             if (res != NO_ERROR) {
                 return res;
             }
-            if (i > 0 && !(x > lastx) /* handle nan */
+            if ((i > 0 && !(x > lastx)) /* handle nan */
                     || y != y /* handle nan */) {
                 // This is a std::map object which imposes sorted order
                 // automatically on emplace.
diff --git a/include/media/MmapStreamInterface.h b/include/media/MmapStreamInterface.h
index 7dbc19e..d689e25 100644
--- a/include/media/MmapStreamInterface.h
+++ b/include/media/MmapStreamInterface.h
@@ -18,6 +18,7 @@
 #define ANDROID_AUDIO_MMAP_STREAM_INTERFACE_H
 
 #include <system/audio.h>
+#include <media/AudioClient.h>
 #include <utils/Errors.h>
 #include <utils/RefBase.h>
 
@@ -37,12 +38,6 @@
         DIRECTION_INPUT,       /**< open a capture mmap stream */
     } stream_direction_t;
 
-    class Client {
-     public:
-        uid_t clientUid;
-        pid_t clientPid;
-        String16 packageName;
-    };
     /**
      * Open a playback or capture stream in MMAP mode at the audio HAL.
      *
@@ -53,13 +48,14 @@
      * \param[in,out] config audio parameters (sampling rate, format ...) for the stream.
      *                       Requested parameters as input,
      *                       Actual parameters as output
-     * \param[in] client a Client struct describing the first client using this stream.
+     * \param[in] client a AudioClient struct describing the first client using this stream.
      * \param[in,out] deviceId audio device the stream should preferably be routed to/from
      *                       Requested as input,
      *                       Actual as output
      * \param[in] callback the MmapStreamCallback interface used by AudioFlinger to notify
      *                     condition changes affecting the stream operation
      * \param[out] interface the MmapStreamInterface interface controlling the created stream
+     * \param[out] same unique handle as the one used for the first client stream started.
      * \return OK if the stream was successfully created.
      *         NO_INIT if AudioFlinger is not properly initialized
      *         BAD_VALUE if the stream cannot be opened because of invalid arguments
@@ -68,10 +64,11 @@
     static status_t openMmapStream(stream_direction_t direction,
                                            const audio_attributes_t *attr,
                                            audio_config_base_t *config,
-                                           const Client& client,
+                                           const AudioClient& client,
                                            audio_port_handle_t *deviceId,
                                            const sp<MmapStreamCallback>& callback,
-                                           sp<MmapStreamInterface>& interface);
+                                           sp<MmapStreamInterface>& interface,
+                                           audio_port_handle_t *handle);
 
     /**
      * Retrieve information on the mmap buffer used for audio samples transfer.
@@ -105,13 +102,13 @@
      * Start a stream operating in mmap mode.
      * createMmapBuffer() must be called before calling start()
      *
-     * \param[in] client a Client struct describing the client starting on this stream.
+     * \param[in] client a AudioClient struct describing the client starting on this stream.
      * \param[out] handle unique handle for this instance. Used with stop().
      * \return OK in case of success.
      *         NO_INIT in case of initialization error
      *         INVALID_OPERATION if called out of sequence
      */
-    virtual status_t start(const Client& client, audio_port_handle_t *handle) = 0;
+    virtual status_t start(const AudioClient& client, audio_port_handle_t *handle) = 0;
 
     /**
      * Stop a stream operating in mmap mode.
diff --git a/include/media/VolumeShaper.h b/include/media/VolumeShaper.h
index e4c0b5b..302641f 100644
--- a/include/media/VolumeShaper.h
+++ b/include/media/VolumeShaper.h
@@ -32,11 +32,8 @@
 #define LOG_TAG "VolumeShaper"
 
 // turn on VolumeShaper logging
-#if 0
-#define VS_LOG ALOGD
-#else
-#define VS_LOG(...)
-#endif
+#define VS_LOGGING 0
+#define VS_LOG(...) ALOGD_IF(VS_LOGGING, __VA_ARGS__)
 
 namespace android {
 
@@ -128,18 +125,18 @@
             : Interpolator<S, T>()
             , RefBase()
             , mType(TYPE_SCALE)
+            , mId(-1)
             , mOptionFlags(OPTION_FLAG_NONE)
-            , mDurationMs(1000.)
-            , mId(-1) {
+            , mDurationMs(1000.) {
         }
 
         explicit Configuration(const Configuration &configuration)
             : Interpolator<S, T>(*static_cast<const Interpolator<S, T> *>(&configuration))
             , RefBase()
             , mType(configuration.mType)
+            , mId(configuration.mId)
             , mOptionFlags(configuration.mOptionFlags)
-            , mDurationMs(configuration.mDurationMs)
-            , mId(configuration.mId) {
+            , mDurationMs(configuration.mDurationMs) {
         }
 
         Type getType() const {
diff --git a/include/media/omx/1.0/WGraphicBufferSource.h b/include/media/omx/1.0/WGraphicBufferSource.h
index 397e576..bf3be9a 100644
--- a/include/media/omx/1.0/WGraphicBufferSource.h
+++ b/include/media/omx/1.0/WGraphicBufferSource.h
@@ -74,6 +74,7 @@
     BnStatus setTimeLapseConfig(double fps, double captureFps) override;
     BnStatus setStartTimeUs(int64_t startTimeUs) override;
     BnStatus setStopTimeUs(int64_t stopTimeUs) override;
+    BnStatus getStopTimeOffsetUs(int64_t *stopTimeOffsetUs) override;
     BnStatus setColorAspects(int32_t aspects) override;
     BnStatus setTimeOffsetUs(int64_t timeOffsetsUs) override;
     BnStatus signalEndOfInputStream() override;
diff --git a/include/media/stagefright b/include/media/stagefright
index ae324a8..5393f68 120000
--- a/include/media/stagefright
+++ b/include/media/stagefright
@@ -1 +1 @@
-../../media/libstagefright/include
\ No newline at end of file
+../../media/libstagefright/include/media/stagefright/
\ No newline at end of file
diff --git a/include/private/media/AudioTrackShared.h b/include/private/media/AudioTrackShared.h
index 7becf57..9da5ef3 100644
--- a/include/private/media/AudioTrackShared.h
+++ b/include/private/media/AudioTrackShared.h
@@ -172,7 +172,7 @@
                 // client write-only, server read-only
                 uint16_t    mSendLevel;      // Fixed point U4.12 so 0x1000 means 1.0
 
-                uint16_t    mPad2;           // unused
+                uint16_t    mPad2 __attribute__((__unused__)); // unused
 
                 // server write-only, client read
                 ExtendedTimestampQueue::Shared mExtendedTimestampQueue;
diff --git a/include/private/media/VideoFrame.h b/include/private/media/VideoFrame.h
index 5193d00..51050cd 100644
--- a/include/private/media/VideoFrame.h
+++ b/include/private/media/VideoFrame.h
@@ -30,8 +30,8 @@
 class VideoFrame
 {
 public:
-    VideoFrame(): mWidth(0), mHeight(0), mDisplayWidth(0), mDisplayHeight(0), mSize(0), mData(0),
-            mRotationAngle(0) {}
+    VideoFrame(): mWidth(0), mHeight(0), mDisplayWidth(0), mDisplayHeight(0), mSize(0),
+            mRotationAngle(0), mData(0) {}
 
     VideoFrame(const VideoFrame& copy) {
         mWidth = copy.mWidth;
diff --git a/include/radio/Radio.h b/include/radio/Radio.h
index a4dfdd1..fb4dd2f 100644
--- a/include/radio/Radio.h
+++ b/include/radio/Radio.h
@@ -79,7 +79,6 @@
 
             Mutex                   mLock;
             sp<IRadio>              mIRadio;
-            const radio_handle_t    mHandle;
             sp<RadioCallback>       mCallback;
 };
 
diff --git a/include/soundtrigger/SoundTrigger.h b/include/soundtrigger/SoundTrigger.h
index 9a05cac..7a29e31 100644
--- a/include/soundtrigger/SoundTrigger.h
+++ b/include/soundtrigger/SoundTrigger.h
@@ -72,7 +72,6 @@
 
             Mutex                               mLock;
             sp<ISoundTrigger>                   mISoundTrigger;
-            const sound_trigger_module_handle_t mModule;
             sp<SoundTriggerCallback>            mCallback;
 };
 
diff --git a/media/img_utils/Android.bp b/media/img_utils/Android.bp
new file mode 100644
index 0000000..64530e1
--- /dev/null
+++ b/media/img_utils/Android.bp
@@ -0,0 +1,60 @@
+// Copyright 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.
+
+cc_library_shared {
+    name: "libimg_utils",
+
+    srcs: [
+        "src/EndianUtils.cpp",
+        "src/FileInput.cpp",
+        "src/FileOutput.cpp",
+        "src/SortedEntryVector.cpp",
+        "src/Input.cpp",
+        "src/Output.cpp",
+        "src/Orderable.cpp",
+        "src/TiffIfd.cpp",
+        "src/TiffWritable.cpp",
+        "src/TiffWriter.cpp",
+        "src/TiffEntry.cpp",
+        "src/TiffEntryImpl.cpp",
+        "src/ByteArrayOutput.cpp",
+        "src/DngUtils.cpp",
+        "src/StripSource.cpp",
+    ],
+
+    shared_libs: [
+        "liblog",
+        "libutils",
+        "libcutils",
+    ],
+
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+        "-fvisibility=hidden",
+    ],
+
+    product_variables: {
+        debuggable: {
+            // Enable assert() in eng builds
+            cflags: [
+                "-UNDEBUG",
+                "-DLOG_NDEBUG=1",
+            ],
+        },
+    },
+
+    export_include_dirs: ["include"],
+}
diff --git a/media/img_utils/Android.mk b/media/img_utils/Android.mk
deleted file mode 100644
index 1cd00bd..0000000
--- a/media/img_utils/Android.mk
+++ /dev/null
@@ -1,15 +0,0 @@
-# Copyright 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.
-
-include $(call all-subdir-makefiles)
diff --git a/media/img_utils/src/Android.mk b/media/img_utils/src/Android.mk
deleted file mode 100644
index 4c6fe70..0000000
--- a/media/img_utils/src/Android.mk
+++ /dev/null
@@ -1,60 +0,0 @@
-# Copyright 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.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
-  EndianUtils.cpp \
-  FileInput.cpp \
-  FileOutput.cpp \
-  SortedEntryVector.cpp \
-  Input.cpp \
-  Output.cpp \
-  Orderable.cpp \
-  TiffIfd.cpp \
-  TiffWritable.cpp \
-  TiffWriter.cpp \
-  TiffEntry.cpp \
-  TiffEntryImpl.cpp \
-  ByteArrayOutput.cpp \
-  DngUtils.cpp \
-  StripSource.cpp \
-
-LOCAL_SHARED_LIBRARIES := \
-  liblog \
-  libutils \
-  libcutils \
-
-LOCAL_C_INCLUDES += \
-  $(LOCAL_PATH)/../include \
-  system/media/camera/include
-
-LOCAL_CFLAGS += \
-  -Wall \
-  -Wextra \
-  -Werror \
-  -fvisibility=hidden
-
-ifneq ($(filter userdebug eng,$(TARGET_BUILD_VARIANT)),)
-    # Enable assert() in eng builds
-    LOCAL_CFLAGS += -UNDEBUG -DLOG_NDEBUG=1
-endif
-
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/../include
-
-LOCAL_MODULE := libimg_utils
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libaaudio/examples/input_monitor/Android.mk b/media/libaaudio/examples/input_monitor/Android.mk
index b56328b..5053e7d 100644
--- a/media/libaaudio/examples/input_monitor/Android.mk
+++ b/media/libaaudio/examples/input_monitor/Android.mk
@@ -1,6 +1 @@
-# include $(call all-subdir-makefiles)
-
-# Just include static/ for now.
-LOCAL_PATH := $(call my-dir)
-#include $(LOCAL_PATH)/jni/Android.mk
-include $(LOCAL_PATH)/static/Android.mk
+include $(call all-subdir-makefiles)
diff --git a/media/libaaudio/examples/input_monitor/jni/Android.mk b/media/libaaudio/examples/input_monitor/jni/Android.mk
index 3e24f9f..9b1ce2c 100644
--- a/media/libaaudio/examples/input_monitor/jni/Android.mk
+++ b/media/libaaudio/examples/input_monitor/jni/Android.mk
@@ -11,7 +11,7 @@
 # NDK recommends using this kind of relative path instead of an absolute path.
 LOCAL_SRC_FILES:= ../src/input_monitor.cpp
 LOCAL_SHARED_LIBRARIES := libaaudio
-LOCAL_MODULE := input_monitor_ndk
+LOCAL_MODULE := input_monitor
 include $(BUILD_EXECUTABLE)
 
 include $(CLEAR_VARS)
@@ -23,11 +23,11 @@
 
 LOCAL_SRC_FILES:= ../src/input_monitor_callback.cpp
 LOCAL_SHARED_LIBRARIES := libaaudio
-LOCAL_MODULE := input_monitor_callback_ndk
+LOCAL_MODULE := input_monitor_callback
 include $(BUILD_EXECUTABLE)
 
 include $(CLEAR_VARS)
 LOCAL_MODULE := libaaudio_prebuilt
 LOCAL_SRC_FILES := libaaudio.so
 LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
-include $(PREBUILT_SHARED_LIBRARY)
\ No newline at end of file
+include $(PREBUILT_SHARED_LIBRARY)
diff --git a/media/libaaudio/examples/input_monitor/src/input_monitor.cpp b/media/libaaudio/examples/input_monitor/src/input_monitor.cpp
index 715c5f8..910b10c 100644
--- a/media/libaaudio/examples/input_monitor/src/input_monitor.cpp
+++ b/media/libaaudio/examples/input_monitor/src/input_monitor.cpp
@@ -22,33 +22,22 @@
 #include <stdlib.h>
 #include <math.h>
 #include <aaudio/AAudio.h>
+#include <aaudio/AAudioTesting.h>
 #include "AAudioExampleUtils.h"
 #include "AAudioSimpleRecorder.h"
 
-#define SAMPLE_RATE        48000
-
-#define NUM_SECONDS        10
-
+// TODO support FLOAT
+#define REQUIRED_FORMAT  AAUDIO_FORMAT_PCM_I16
 #define MIN_FRAMES_TO_READ 48  /* arbitrary, 1 msec at 48000 Hz */
 
-int main(int argc, char **argv)
+int main(int argc, const char **argv)
 {
-    (void)argc; // unused
-
+    AAudioArgsParser   argParser;
     aaudio_result_t result;
     AAudioSimpleRecorder recorder;
     int actualSamplesPerFrame;
     int actualSampleRate;
-    const aaudio_format_t requestedDataFormat = AAUDIO_FORMAT_PCM_I16;
-    aaudio_format_t actualDataFormat;
-
-    const int requestedInputChannelCount = 1; // Can affect whether we get a FAST path.
-
-    //aaudio_performance_mode_t requestedPerformanceMode = AAUDIO_PERFORMANCE_MODE_NONE;
-    const aaudio_performance_mode_t requestedPerformanceMode = AAUDIO_PERFORMANCE_MODE_LOW_LATENCY;
-    //aaudio_performance_mode_t requestedPerformanceMode = AAUDIO_PERFORMANCE_MODE_POWER_SAVING;
-    const aaudio_sharing_mode_t requestedSharingMode = AAUDIO_SHARING_MODE_SHARED;
-    //const aaudio_sharing_mode_t requestedSharingMode = AAUDIO_SHARING_MODE_EXCLUSIVE;
+    aaudio_format_t       actualDataFormat;
     aaudio_sharing_mode_t actualSharingMode;
 
     AAudioStream *aaudioStream = nullptr;
@@ -61,6 +50,7 @@
     int16_t *data = nullptr;
     float peakLevel = 0.0;
     int loopCounter = 0;
+    int32_t deviceId;
 
     // Make printf print immediately so that debug info is not stuck
     // in a buffer if we hang or crash.
@@ -68,27 +58,27 @@
 
     printf("%s - Monitor input level using AAudio\n", argv[0]);
 
-    recorder.setPerformanceMode(requestedPerformanceMode);
-    recorder.setSharingMode(requestedSharingMode);
+    argParser.setFormat(REQUIRED_FORMAT);
+    if (argParser.parseArgs(argc, argv)) {
+        return EXIT_FAILURE;
+    }
 
-    result = recorder.open(requestedInputChannelCount, 48000, requestedDataFormat,
-                           nullptr, nullptr, nullptr);
+    result = recorder.open(argParser);
     if (result != AAUDIO_OK) {
         fprintf(stderr, "ERROR -  recorder.open() returned %d\n", result);
         goto finish;
     }
     aaudioStream = recorder.getStream();
+    argParser.compareWithStream(aaudioStream);
+
+    deviceId = AAudioStream_getDeviceId(aaudioStream);
+    printf("deviceId = %d\n", deviceId);
 
     actualSamplesPerFrame = AAudioStream_getSamplesPerFrame(aaudioStream);
     printf("SamplesPerFrame = %d\n", actualSamplesPerFrame);
     actualSampleRate = AAudioStream_getSampleRate(aaudioStream);
     printf("SamplesPerFrame = %d\n", actualSampleRate);
 
-    actualSharingMode = AAudioStream_getSharingMode(aaudioStream);
-    printf("SharingMode: requested = %s, actual = %s\n",
-            getSharingModeText(requestedSharingMode),
-            getSharingModeText(actualSharingMode));
-
     // This is the number of frames that are written in one chunk by a DMA controller
     // or a DSP.
     framesPerBurst = AAudioStream_getFramesPerBurst(aaudioStream);
@@ -103,14 +93,12 @@
     printf("DataFormat: framesPerRead  = %d\n",framesPerRead);
 
     actualDataFormat = AAudioStream_getFormat(aaudioStream);
-    printf("DataFormat: requested      = %d, actual = %d\n", requestedDataFormat, actualDataFormat);
+    printf("DataFormat: requested      = %d, actual = %d\n",
+           REQUIRED_FORMAT, actualDataFormat);
     // TODO handle other data formats
-    assert(actualDataFormat == AAUDIO_FORMAT_PCM_I16);
+    assert(actualDataFormat == REQUIRED_FORMAT);
 
-    printf("PerformanceMode: requested = %d, actual = %d\n", requestedPerformanceMode,
-           AAudioStream_getPerformanceMode(aaudioStream));
-
-    // Allocate a buffer for the audio data.
+    // Allocate a buffer for the PCM_16 audio data.
     data = new(std::nothrow) int16_t[framesPerRead * actualSamplesPerFrame];
     if (data == nullptr) {
         fprintf(stderr, "ERROR - could not allocate data buffer\n");
@@ -129,11 +117,11 @@
     printf("after start, state = %s\n", AAudio_convertStreamStateToText(state));
 
     // Record for a while.
-    framesToRecord = actualSampleRate * NUM_SECONDS;
+    framesToRecord = actualSampleRate * argParser.getDurationSeconds();
     framesLeft = framesToRecord;
     while (framesLeft > 0) {
         // Read audio data from the stream.
-        const int64_t timeoutNanos = 100 * NANOS_PER_MILLISECOND;
+        const int64_t timeoutNanos = 1000 * NANOS_PER_MILLISECOND;
         int minFrames = (framesToRecord < framesPerRead) ? framesToRecord : framesPerRead;
         int actual = AAudioStream_read(aaudioStream, data, minFrames, timeoutNanos);
         if (actual < 0) {
@@ -169,6 +157,8 @@
         goto finish;
     }
 
+    argParser.compareWithStream(aaudioStream);
+
 finish:
     recorder.close();
     delete[] data;
diff --git a/media/libaaudio/examples/input_monitor/static/Android.mk b/media/libaaudio/examples/input_monitor/static/Android.mk
deleted file mode 100644
index 61fc3b8..0000000
--- a/media/libaaudio/examples/input_monitor/static/Android.mk
+++ /dev/null
@@ -1,37 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE_TAGS := examples
-LOCAL_C_INCLUDES := \
-    $(call include-path-for, audio-utils) \
-    frameworks/av/media/libaaudio/include \
-    frameworks/av/media/libaaudio/examples/utils
-
-# TODO reorganize folders to avoid using ../
-LOCAL_SRC_FILES:= ../src/input_monitor.cpp
-
-LOCAL_SHARED_LIBRARIES := libaudioutils libmedia \
-                          libbinder libcutils libutils \
-                          libaudioclient liblog libtinyalsa libaudiomanager
-LOCAL_STATIC_LIBRARIES := libaaudio
-
-LOCAL_MODULE := input_monitor
-include $(BUILD_EXECUTABLE)
-
-
-include $(CLEAR_VARS)
-LOCAL_MODULE_TAGS := tests
-LOCAL_C_INCLUDES := \
-    $(call include-path-for, audio-utils) \
-    frameworks/av/media/libaaudio/include \
-    frameworks/av/media/libaaudio/examples/utils
-
-LOCAL_SRC_FILES:= ../src/input_monitor_callback.cpp
-
-LOCAL_SHARED_LIBRARIES := libaudioutils libmedia \
-                          libbinder libcutils libutils \
-                          libaudioclient liblog libaudiomanager
-LOCAL_STATIC_LIBRARIES := libaaudio
-
-LOCAL_MODULE := input_monitor_callback
-include $(BUILD_EXECUTABLE)
diff --git a/media/libaaudio/examples/input_monitor/static/README.md b/media/libaaudio/examples/input_monitor/static/README.md
deleted file mode 100644
index 6e26d7b..0000000
--- a/media/libaaudio/examples/input_monitor/static/README.md
+++ /dev/null
@@ -1,2 +0,0 @@
-Makefile for building simple command line examples.
-They link with AAudio as a static library.
diff --git a/media/libaaudio/examples/loopback/jni/Android.mk b/media/libaaudio/examples/loopback/jni/Android.mk
index dc933e3..d78f286 100644
--- a/media/libaaudio/examples/loopback/jni/Android.mk
+++ b/media/libaaudio/examples/loopback/jni/Android.mk
@@ -4,7 +4,8 @@
 LOCAL_MODULE_TAGS := tests
 LOCAL_C_INCLUDES := \
     $(call include-path-for, audio-utils) \
-    frameworks/av/media/libaaudio/include
+    frameworks/av/media/libaaudio/include \
+    frameworks/av/media/libaaudio/examples/utils
 
 # NDK recommends using this kind of relative path instead of an absolute path.
 LOCAL_SRC_FILES:= ../src/loopback.cpp
diff --git a/media/libaaudio/examples/loopback/src/LoopbackAnalyzer.h b/media/libaaudio/examples/loopback/src/LoopbackAnalyzer.h
new file mode 100644
index 0000000..21cf341
--- /dev/null
+++ b/media/libaaudio/examples/loopback/src/LoopbackAnalyzer.h
@@ -0,0 +1,794 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Tools for measuring latency and for detecting glitches.
+ * These classes are pure math and can be used with any audio system.
+ */
+
+#ifndef AAUDIO_EXAMPLES_LOOPBACK_ANALYSER_H
+#define AAUDIO_EXAMPLES_LOOPBACK_ANALYSER_H
+
+#include <algorithm>
+#include <assert.h>
+#include <cctype>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+// Tag for machine readable results as property = value pairs
+#define LOOPBACK_RESULT_TAG      "RESULT: "
+#define LOOPBACK_SAMPLE_RATE     48000
+
+#define MILLIS_PER_SECOND        1000
+
+#define MAX_ZEROTH_PARTIAL_BINS  40
+
+static const float s_Impulse[] = {
+        0.0f, 0.0f, 0.0f, 0.0f, 0.2f, // silence on each side of the impulse
+        0.5f, 0.9999f, 0.0f, -0.9999, -0.5f, // bipolar
+        -0.2f, 0.0f, 0.0f, 0.0f, 0.0f
+};
+
+class PseudoRandom {
+public:
+    PseudoRandom() {}
+    PseudoRandom(int64_t seed)
+            :    mSeed(seed)
+    {}
+
+    /**
+     * Returns the next random double from -1.0 to 1.0
+     *
+     * @return value from -1.0 to 1.0
+     */
+     double nextRandomDouble() {
+        return nextRandomInteger() * (0.5 / (((int32_t)1) << 30));
+    }
+
+    /** Calculate random 32 bit number using linear-congruential method. */
+    int32_t nextRandomInteger() {
+        // Use values for 64-bit sequence from MMIX by Donald Knuth.
+        mSeed = (mSeed * (int64_t)6364136223846793005) + (int64_t)1442695040888963407;
+        return (int32_t) (mSeed >> 32); // The higher bits have a longer sequence.
+    }
+
+private:
+    int64_t mSeed = 99887766;
+};
+
+static double calculateCorrelation(const float *a,
+                                   const float *b,
+                                   int windowSize)
+{
+    double correlation = 0.0;
+    double sumProducts = 0.0;
+    double sumSquares = 0.0;
+
+    // Correlate a against b.
+    for (int i = 0; i < windowSize; i++) {
+        float s1 = a[i];
+        float s2 = b[i];
+        // Use a normalized cross-correlation.
+        sumProducts += s1 * s2;
+        sumSquares += ((s1 * s1) + (s2 * s2));
+    }
+
+    if (sumSquares >= 0.00000001) {
+        correlation = (float) (2.0 * sumProducts / sumSquares);
+    }
+    return correlation;
+}
+
+static int calculateCorrelations(const float *haystack, int haystackSize,
+                                 const float *needle, int needleSize,
+                                 float *results, int resultSize)
+{
+    int maxCorrelations = haystackSize - needleSize;
+    int numCorrelations = std::min(maxCorrelations, resultSize);
+
+    for (int ic = 0; ic < numCorrelations; ic++) {
+        double correlation = calculateCorrelation(&haystack[ic], needle, needleSize);
+        results[ic] = correlation;
+    }
+
+    return numCorrelations;
+}
+
+/*==========================================================================================*/
+/**
+ * Scan until we get a correlation of a single scan that goes over the tolerance level,
+ * peaks then drops back down.
+ */
+static double findFirstMatch(const float *haystack, int haystackSize,
+                             const float *needle, int needleSize, double threshold  )
+{
+    int ic;
+    // How many correlations can we calculate?
+    int numCorrelations = haystackSize - needleSize;
+    double maxCorrelation = 0.0;
+    int peakIndex = -1;
+    double location = -1.0;
+    const double backThresholdScaler = 0.5;
+
+    for (ic = 0; ic < numCorrelations; ic++) {
+        double correlation = calculateCorrelation(&haystack[ic], needle, needleSize);
+
+        if( (correlation > maxCorrelation) ) {
+            maxCorrelation = correlation;
+            peakIndex = ic;
+        }
+
+        //printf("PaQa_FindFirstMatch: ic = %4d, correlation = %8f, maxSum = %8f\n",
+        //    ic, correlation, maxSum );
+        // Are we past what we were looking for?
+        if((maxCorrelation > threshold) && (correlation < backThresholdScaler * maxCorrelation)) {
+            location = peakIndex;
+            break;
+        }
+    }
+
+    return location;
+}
+
+typedef struct LatencyReport_s {
+    double latencyInFrames;
+    double confidence;
+} LatencyReport;
+
+// Apply a technique similar to Harmonic Product Spectrum Analysis to find echo fundamental.
+// Using first echo instead of the original impulse for a better match.
+static int measureLatencyFromEchos(const float *haystack, int haystackSize,
+                            const float *needle, int needleSize,
+                            LatencyReport *report) {
+    const double threshold = 0.1;
+
+    // Find first peak
+    int first = (int) (findFirstMatch(haystack,
+                                      haystackSize,
+                                      needle,
+                                      needleSize,
+                                      threshold) + 0.5);
+
+    // Use first echo as the needle for the other echos because
+    // it will be more similar.
+    needle = &haystack[first];
+    int again = (int) (findFirstMatch(haystack,
+                                      haystackSize,
+                                      needle,
+                                      needleSize,
+                                      threshold) + 0.5);
+
+    printf("first = %d, again at %d\n", first, again);
+    first = again;
+
+    // Allocate results array
+    int remaining = haystackSize - first;
+    const int maxReasonableLatencyFrames = 48000 * 2; // arbitrary but generous value
+    int numCorrelations = std::min(remaining, maxReasonableLatencyFrames);
+    float *correlations = new float[numCorrelations];
+    float *harmonicSums = new float[numCorrelations](); // set to zero
+
+    // Generate correlation for every position.
+    numCorrelations = calculateCorrelations(&haystack[first], remaining,
+                                            needle, needleSize,
+                                            correlations, numCorrelations);
+
+    // Add higher harmonics mapped onto lower harmonics.
+    // This reinforces the "fundamental" echo.
+    const int numEchoes = 10;
+    for (int partial = 1; partial < numEchoes; partial++) {
+        for (int i = 0; i < numCorrelations; i++) {
+            harmonicSums[i / partial] += correlations[i] / partial;
+        }
+    }
+
+    // Find highest peak in correlation array.
+    float maxCorrelation = 0.0;
+    float sumOfPeaks = 0.0;
+    int peakIndex = 0;
+    const int skip = MAX_ZEROTH_PARTIAL_BINS; // skip low bins
+    for (int i = skip; i < numCorrelations; i++) {
+        if (harmonicSums[i] > maxCorrelation) {
+            maxCorrelation = harmonicSums[i];
+            sumOfPeaks += maxCorrelation;
+            peakIndex = i;
+            printf("maxCorrelation = %f at %d\n", maxCorrelation, peakIndex);
+        }
+    }
+
+    report->latencyInFrames = peakIndex;
+    if (sumOfPeaks < 0.0001) {
+        report->confidence = 0.0;
+    } else {
+        report->confidence = maxCorrelation / sumOfPeaks;
+    }
+
+    delete[] correlations;
+    delete[] harmonicSums;
+    return 0;
+}
+
+class AudioRecording
+{
+public:
+    AudioRecording() {
+    }
+    ~AudioRecording() {
+        delete[] mData;
+    }
+
+    void allocate(int maxFrames) {
+        delete[] mData;
+        mData = new float[maxFrames];
+        mMaxFrames = maxFrames;
+    }
+
+    // Write SHORT data from the first channel.
+    int write(int16_t *inputData, int inputChannelCount, int numFrames) {
+        // stop at end of buffer
+        if ((mFrameCounter + numFrames) > mMaxFrames) {
+            numFrames = mMaxFrames - mFrameCounter;
+        }
+        for (int i = 0; i < numFrames; i++) {
+            mData[mFrameCounter++] = inputData[i * inputChannelCount] * (1.0f / 32768);
+        }
+        return numFrames;
+    }
+
+    // Write FLOAT data from the first channel.
+    int write(float *inputData, int inputChannelCount, int numFrames) {
+        // stop at end of buffer
+        if ((mFrameCounter + numFrames) > mMaxFrames) {
+            numFrames = mMaxFrames - mFrameCounter;
+        }
+        for (int i = 0; i < numFrames; i++) {
+            mData[mFrameCounter++] = inputData[i * inputChannelCount];
+        }
+        return numFrames;
+    }
+
+    int size() {
+        return mFrameCounter;
+    }
+
+    float *getData() {
+        return mData;
+    }
+
+    int save(const char *fileName, bool writeShorts = true) {
+        int written = 0;
+        const int chunkSize = 64;
+        FILE *fid = fopen(fileName, "wb");
+        if (fid == NULL) {
+            return -errno;
+        }
+
+        if (writeShorts) {
+            int16_t buffer[chunkSize];
+            int32_t framesLeft = mFrameCounter;
+            int32_t cursor = 0;
+            while (framesLeft) {
+                int32_t framesToWrite = framesLeft < chunkSize ? framesLeft : chunkSize;
+                for (int i = 0; i < framesToWrite; i++) {
+                    buffer[i] = (int16_t) (mData[cursor++] * 32767);
+                }
+                written += fwrite(buffer, sizeof(int16_t), framesToWrite, fid);
+                framesLeft -= framesToWrite;
+            }
+        } else {
+            written = (int) fwrite(mData, sizeof(float), mFrameCounter, fid);
+        }
+        fclose(fid);
+        return written;
+    }
+
+private:
+    float  *mData = nullptr;
+    int32_t mFrameCounter = 0;
+    int32_t mMaxFrames = 0;
+};
+
+// ====================================================================================
+class LoopbackProcessor {
+public:
+    virtual ~LoopbackProcessor() = default;
+
+
+    virtual void reset() {}
+
+    virtual void process(float *inputData, int inputChannelCount,
+                 float *outputData, int outputChannelCount,
+                 int numFrames) = 0;
+
+
+    virtual void report() = 0;
+
+    virtual void printStatus() {};
+
+    virtual bool isDone() {
+        return false;
+    }
+
+    void setSampleRate(int32_t sampleRate) {
+        mSampleRate = sampleRate;
+    }
+
+    int32_t getSampleRate() {
+        return mSampleRate;
+    }
+
+    // Measure peak amplitude of buffer.
+    static float measurePeakAmplitude(float *inputData, int inputChannelCount, int numFrames) {
+        float peak = 0.0f;
+        for (int i = 0; i < numFrames; i++) {
+            float pos = fabs(*inputData);
+            if (pos > peak) {
+                peak = pos;
+            }
+            inputData += inputChannelCount;
+        }
+        return peak;
+    }
+
+
+private:
+    int32_t mSampleRate = LOOPBACK_SAMPLE_RATE;
+};
+
+class PeakDetector {
+public:
+    float process(float input) {
+        float output = mPrevious * mDecay;
+        if (input > output) {
+            output = input;
+        }
+        mPrevious = output;
+        return output;
+    }
+
+private:
+    float  mDecay = 0.99f;
+    float  mPrevious = 0.0f;
+};
+
+
+static void printAudioScope(float sample) {
+    const int maxStars = 80
+    ; // arbitrary, fits on one line
+    char c = '*';
+    if (sample < -1.0) {
+        sample = -1.0;
+        c = '$';
+    } else if (sample > 1.0) {
+        sample = 1.0;
+        c = '$';
+    }
+    int numSpaces = (int) (((sample + 1.0) * 0.5) * maxStars);
+    for (int i = 0; i < numSpaces; i++) {
+        putchar(' ');
+    }
+    printf("%c\n", c);
+}
+
+// ====================================================================================
+/**
+ * Measure latency given a loopback stream data.
+ * Uses a state machine to cycle through various stages including:
+ *
+ */
+class EchoAnalyzer : public LoopbackProcessor {
+public:
+
+    EchoAnalyzer() : LoopbackProcessor() {
+        audioRecorder.allocate(2 * LOOPBACK_SAMPLE_RATE);
+    }
+
+    void reset() override {
+        mDownCounter = 200;
+        mLoopCounter = 0;
+        mMeasuredLoopGain = 0.0f;
+        mEchoGain = 1.0f;
+        mState = STATE_INITIAL_SILENCE;
+    }
+
+    virtual bool isDone() {
+        return mState == STATE_DONE;
+    }
+
+    void setGain(float gain) {
+        mEchoGain = gain;
+    }
+
+    float getGain() {
+        return mEchoGain;
+    }
+
+    void report() override {
+
+        printf("EchoAnalyzer ---------------\n");
+        printf(LOOPBACK_RESULT_TAG "measured.gain          = %f\n", mMeasuredLoopGain);
+        printf(LOOPBACK_RESULT_TAG "echo.gain              = %f\n", mEchoGain);
+        printf(LOOPBACK_RESULT_TAG "frame.count            = %d\n", mFrameCounter);
+        printf(LOOPBACK_RESULT_TAG "test.state             = %d\n", mState);
+        if (mMeasuredLoopGain >= 0.9999) {
+            printf("   ERROR - clipping, turn down volume slightly\n");
+        } else {
+            const float *needle = s_Impulse;
+            int needleSize = (int) (sizeof(s_Impulse) / sizeof(float));
+            float *haystack = audioRecorder.getData();
+            int haystackSize = audioRecorder.size();
+            int result = measureLatencyFromEchos(haystack, haystackSize,
+                                                 needle, needleSize,
+                                                 &latencyReport);
+            if (latencyReport.confidence < 0.01) {
+                printf("   ERROR - confidence too low = %f\n", latencyReport.confidence);
+            } else {
+                double latencyMillis = 1000.0 * latencyReport.latencyInFrames / getSampleRate();
+                printf(LOOPBACK_RESULT_TAG "latency.frames        = %8.2f\n", latencyReport.latencyInFrames);
+                printf(LOOPBACK_RESULT_TAG "latency.msec          = %8.2f\n", latencyMillis);
+                printf(LOOPBACK_RESULT_TAG "latency.confidence    = %8.6f\n", latencyReport.confidence);
+            }
+        }
+
+        {
+#define ECHO_FILENAME "/data/oboe_echo.raw"
+            int written = audioRecorder.save(ECHO_FILENAME);
+            printf("Echo wrote %d mono samples to %s on Android device\n", written, ECHO_FILENAME);
+        }
+    }
+
+    void printStatus() override {
+        printf("state = %d, echo gain = %f ", mState, mEchoGain);
+    }
+
+    static void sendImpulse(float *outputData, int outputChannelCount) {
+        for (float sample : s_Impulse) {
+            *outputData = sample;
+            outputData += outputChannelCount;
+        }
+    }
+
+    void process(float *inputData, int inputChannelCount,
+                 float *outputData, int outputChannelCount,
+                 int numFrames) override {
+        int channelsValid = std::min(inputChannelCount, outputChannelCount);
+        float peak = 0.0f;
+        int numWritten;
+        int numSamples;
+
+        echo_state_t nextState = mState;
+
+        switch (mState) {
+            case STATE_INITIAL_SILENCE:
+                // Output silence at the beginning.
+                numSamples = numFrames * outputChannelCount;
+                for (int i = 0; i < numSamples; i++) {
+                    outputData[i] = 0;
+                }
+                if (mDownCounter-- <= 0) {
+                    nextState = STATE_MEASURING_GAIN;
+                    //printf("%5d: switch to STATE_MEASURING_GAIN\n", mLoopCounter);
+                    mDownCounter = 8;
+                }
+                break;
+
+            case STATE_MEASURING_GAIN:
+                sendImpulse(outputData, outputChannelCount);
+                peak = measurePeakAmplitude(inputData, inputChannelCount, numFrames);
+                // If we get several in a row then go to next state.
+                if (peak > mPulseThreshold) {
+                    if (mDownCounter-- <= 0) {
+                        nextState = STATE_WAITING_FOR_SILENCE;
+                        //printf("%5d: switch to STATE_WAITING_FOR_SILENCE, measured peak = %f\n",
+                        //       mLoopCounter, peak);
+                        mDownCounter = 8;
+                        mMeasuredLoopGain = peak;  // assumes original pulse amplitude is one
+                        // Calculate gain that will give us a nice decaying echo.
+                        mEchoGain = mDesiredEchoGain / mMeasuredLoopGain;
+                    }
+                } else {
+                    mDownCounter = 8;
+                }
+                break;
+
+            case STATE_WAITING_FOR_SILENCE:
+                // Output silence.
+                numSamples = numFrames * outputChannelCount;
+                for (int i = 0; i < numSamples; i++) {
+                    outputData[i] = 0;
+                }
+                peak = measurePeakAmplitude(inputData, inputChannelCount, numFrames);
+                // If we get several in a row then go to next state.
+                if (peak < mSilenceThreshold) {
+                    if (mDownCounter-- <= 0) {
+                        nextState = STATE_SENDING_PULSE;
+                        //printf("%5d: switch to STATE_SENDING_PULSE\n", mLoopCounter);
+                        mDownCounter = 8;
+                    }
+                } else {
+                    mDownCounter = 8;
+                }
+                break;
+
+            case STATE_SENDING_PULSE:
+                audioRecorder.write(inputData, inputChannelCount, numFrames);
+                sendImpulse(outputData, outputChannelCount);
+                nextState = STATE_GATHERING_ECHOS;
+                //printf("%5d: switch to STATE_GATHERING_ECHOS\n", mLoopCounter);
+                break;
+
+            case STATE_GATHERING_ECHOS:
+                numWritten = audioRecorder.write(inputData, inputChannelCount, numFrames);
+                peak = measurePeakAmplitude(inputData, inputChannelCount, numFrames);
+                if (peak > mMeasuredLoopGain) {
+                    mMeasuredLoopGain = peak;  // AGC might be raising gain so adjust it on the fly.
+                    // Recalculate gain that will give us a nice decaying echo.
+                    mEchoGain = mDesiredEchoGain / mMeasuredLoopGain;
+                }
+                // Echo input to output.
+                for (int i = 0; i < numFrames; i++) {
+                    int ic;
+                    for (ic = 0; ic < channelsValid; ic++) {
+                        outputData[ic] = inputData[ic] * mEchoGain;
+                    }
+                    for (; ic < outputChannelCount; ic++) {
+                        outputData[ic] = 0;
+                    }
+                    inputData += inputChannelCount;
+                    outputData += outputChannelCount;
+                }
+                if (numWritten  < numFrames) {
+                    nextState = STATE_DONE;
+                    //printf("%5d: switch to STATE_DONE\n", mLoopCounter);
+                }
+                break;
+
+            case STATE_DONE:
+            default:
+                break;
+        }
+
+        mState = nextState;
+        mLoopCounter++;
+    }
+
+private:
+
+    enum echo_state_t {
+        STATE_INITIAL_SILENCE,
+        STATE_MEASURING_GAIN,
+        STATE_WAITING_FOR_SILENCE,
+        STATE_SENDING_PULSE,
+        STATE_GATHERING_ECHOS,
+        STATE_DONE
+    };
+
+    int           mDownCounter = 500;
+    int           mLoopCounter = 0;
+    int           mLoopStart = 1000;
+    float         mPulseThreshold = 0.02f;
+    float         mSilenceThreshold = 0.002f;
+    float         mMeasuredLoopGain = 0.0f;
+    float         mDesiredEchoGain = 0.95f;
+    float         mEchoGain = 1.0f;
+    echo_state_t  mState = STATE_INITIAL_SILENCE;
+    int32_t       mFrameCounter = 0;
+
+    AudioRecording     audioRecorder;
+    LatencyReport      latencyReport;
+    PeakDetector       mPeakDetector;
+};
+
+
+// ====================================================================================
+/**
+ * Output a steady sinewave and analyze the return signal.
+ *
+ * Use a cosine transform to measure the predicted magnitude and relative phase of the
+ * looped back sine wave. Then generate a predicted signal and compare with the actual signal.
+ */
+class SineAnalyzer : public LoopbackProcessor {
+public:
+
+    void report() override {
+        printf("SineAnalyzer ------------------\n");
+        printf(LOOPBACK_RESULT_TAG "peak.amplitude     = %7.5f\n", mPeakAmplitude);
+        printf(LOOPBACK_RESULT_TAG "sine.magnitude     = %7.5f\n", mMagnitude);
+        printf(LOOPBACK_RESULT_TAG "phase.offset       = %7.5f\n", mPhaseOffset);
+        printf(LOOPBACK_RESULT_TAG "ref.phase          = %7.5f\n", mPhase);
+        printf(LOOPBACK_RESULT_TAG "frames.accumulated = %6d\n", mFramesAccumulated);
+        printf(LOOPBACK_RESULT_TAG "sine.period        = %6d\n", mPeriod);
+        printf(LOOPBACK_RESULT_TAG "test.state         = %6d\n", mState);
+        printf(LOOPBACK_RESULT_TAG "frame.count        = %6d\n", mFrameCounter);
+        // Did we ever get a lock?
+        bool gotLock = (mState == STATE_LOCKED) || (mGlitchCount > 0);
+        if (!gotLock) {
+            printf("ERROR - failed to lock on reference sine tone\n");
+        } else {
+            // Only print if meaningful.
+            printf(LOOPBACK_RESULT_TAG "glitch.count       = %6d\n", mGlitchCount);
+        }
+    }
+
+    void printStatus() override {
+        printf("  state = %d, glitches = %d,", mState, mGlitchCount);
+    }
+
+    double calculateMagnitude(double *phasePtr = NULL) {
+        if (mFramesAccumulated == 0) {
+            return 0.0;
+        }
+        double sinMean = mSinAccumulator / mFramesAccumulated;
+        double cosMean = mCosAccumulator / mFramesAccumulated;
+        double magnitude = 2.0 * sqrt( (sinMean * sinMean) + (cosMean * cosMean ));
+        if( phasePtr != NULL )
+        {
+            double phase = M_PI_2 - atan2( sinMean, cosMean );
+            *phasePtr = phase;
+        }
+        return magnitude;
+    }
+
+    /**
+     * @param inputData contains microphone data with sine signal feedback
+     * @param outputData contains the reference sine wave
+     */
+    void process(float *inputData, int inputChannelCount,
+                 float *outputData, int outputChannelCount,
+                 int numFrames) override {
+        float sample;
+        float peak = measurePeakAmplitude(inputData, inputChannelCount, numFrames);
+        if (peak > mPeakAmplitude) {
+            mPeakAmplitude = peak;
+        }
+
+        for (int i = 0; i < numFrames; i++) {
+            float sample = inputData[i * inputChannelCount];
+
+            float sinOut = sinf(mPhase);
+
+            switch (mState) {
+                case STATE_IMMUNE:
+                case STATE_WAITING_FOR_SIGNAL:
+                    break;
+                case STATE_WAITING_FOR_LOCK:
+                    mSinAccumulator += sample * sinOut;
+                    mCosAccumulator += sample * cosf(mPhase);
+                    mFramesAccumulated++;
+                    // Must be a multiple of the period or the calculation will not be accurate.
+                    if (mFramesAccumulated == mPeriod * 4) {
+                        mPhaseOffset = 0.0;
+                        mMagnitude = calculateMagnitude(&mPhaseOffset);
+                        if (mMagnitude > mThreshold) {
+                            if (fabs(mPreviousPhaseOffset - mPhaseOffset) < 0.001) {
+                                mState = STATE_LOCKED;
+                                //printf("%5d: switch to STATE_LOCKED\n", mFrameCounter);
+                            }
+                            mPreviousPhaseOffset = mPhaseOffset;
+                        }
+                        resetAccumulator();
+                    }
+                    break;
+
+                case STATE_LOCKED: {
+                    // Predict next sine value
+                    float predicted = sinf(mPhase + mPhaseOffset) * mMagnitude;
+                    // printf("    predicted = %f, actual = %f\n", predicted, sample);
+
+                    float diff = predicted - sample;
+                    if (fabs(diff) > mTolerance) {
+                        mGlitchCount++;
+                        //printf("%5d: Got a glitch # %d, predicted = %f, actual = %f\n",
+                        //       mFrameCounter, mGlitchCount, predicted, sample);
+                        mState = STATE_IMMUNE;
+                        //printf("%5d: switch to STATE_IMMUNE\n", mFrameCounter);
+                        mDownCounter = mPeriod;  // Set duration of IMMUNE state.
+                    }
+                } break;
+            }
+
+            // Output sine wave so we can measure it.
+            outputData[i * outputChannelCount] = (sinOut * mOutputAmplitude)
+                    + (mWhiteNoise.nextRandomDouble() * mNoiseAmplitude);
+            // printf("%5d: sin(%f) = %f, %f\n", i, mPhase, sinOut,  mPhaseIncrement);
+
+            // advance and wrap phase
+            mPhase += mPhaseIncrement;
+            if (mPhase > M_PI) {
+                mPhase -= (2.0 * M_PI);
+            }
+
+            mFrameCounter++;
+        }
+
+        // Do these once per buffer.
+        switch (mState) {
+            case STATE_IMMUNE:
+                mDownCounter -= numFrames;
+                if (mDownCounter <= 0) {
+                    mState = STATE_WAITING_FOR_SIGNAL;
+                    //printf("%5d: switch to STATE_WAITING_FOR_SIGNAL\n", mFrameCounter);
+                }
+                break;
+            case STATE_WAITING_FOR_SIGNAL:
+                if (peak > mThreshold) {
+                    mState = STATE_WAITING_FOR_LOCK;
+                    //printf("%5d: switch to STATE_WAITING_FOR_LOCK\n", mFrameCounter);
+                    resetAccumulator();
+                }
+                break;
+            case STATE_WAITING_FOR_LOCK:
+            case STATE_LOCKED:
+                break;
+        }
+
+    }
+
+    void resetAccumulator() {
+        mFramesAccumulated = 0;
+        mSinAccumulator = 0.0;
+        mCosAccumulator = 0.0;
+    }
+
+    void reset() override {
+        mGlitchCount = 0;
+        mState = STATE_IMMUNE;
+        mPhaseIncrement = 2.0 * M_PI / mPeriod;
+        printf("phaseInc = %f for period %d\n", mPhaseIncrement, mPeriod);
+        resetAccumulator();
+    }
+
+private:
+
+    enum sine_state_t {
+        STATE_IMMUNE,
+        STATE_WAITING_FOR_SIGNAL,
+        STATE_WAITING_FOR_LOCK,
+        STATE_LOCKED
+    };
+
+    int     mPeriod = 79;
+    double  mPhaseIncrement = 0.0;
+    double  mPhase = 0.0;
+    double  mPhaseOffset = 0.0;
+    double  mPreviousPhaseOffset = 0.0;
+    double  mMagnitude = 0.0;
+    double  mThreshold = 0.005;
+    double  mTolerance = 0.01;
+    int32_t mFramesAccumulated = 0;
+    double  mSinAccumulator = 0.0;
+    double  mCosAccumulator = 0.0;
+    int32_t mGlitchCount = 0;
+    double  mPeakAmplitude = 0.0;
+    int     mDownCounter = 4000;
+    int32_t mFrameCounter = 0;
+    float   mOutputAmplitude = 0.75;
+
+    int32_t mZeroCrossings = 0;
+
+    PseudoRandom  mWhiteNoise;
+    float   mNoiseAmplitude = 0.00; // Used to experiment with warbling caused by DRC.
+
+    sine_state_t  mState = STATE_IMMUNE;
+};
+
+
+#undef LOOPBACK_SAMPLE_RATE
+#undef LOOPBACK_RESULT_TAG
+
+#endif /* AAUDIO_EXAMPLES_LOOPBACK_ANALYSER_H */
diff --git a/media/libaaudio/examples/loopback/src/loopback.cpp b/media/libaaudio/examples/loopback/src/loopback.cpp
index 9f06ee7..144c941 100644
--- a/media/libaaudio/examples/loopback/src/loopback.cpp
+++ b/media/libaaudio/examples/loopback/src/loopback.cpp
@@ -14,219 +14,52 @@
  * limitations under the License.
  */
 
-// Play an impulse and then record it.
-// Measure the round trip latency.
+// Audio loopback tests to measure the round trip latency and glitches.
 
+#include <algorithm>
 #include <assert.h>
 #include <cctype>
 #include <math.h>
-#include <stdlib.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
 
 #include <aaudio/AAudio.h>
+#include <aaudio/AAudioTesting.h>
 
-#define INPUT_PEAK_THRESHOLD    0.1f
-#define SILENCE_FRAMES          10000
+#include "AAudioSimplePlayer.h"
+#include "AAudioSimpleRecorder.h"
+#include "AAudioExampleUtils.h"
+#include "LoopbackAnalyzer.h"
+
+// Tag for machine readable results as property = value pairs
+#define RESULT_TAG              "RESULT: "
 #define SAMPLE_RATE             48000
-#define NUM_SECONDS             7
+#define NUM_SECONDS             5
+#define NUM_INPUT_CHANNELS      1
 #define FILENAME                "/data/oboe_input.raw"
+#define APP_VERSION             "0.1.22"
 
-#define NANOS_PER_MICROSECOND ((int64_t)1000)
-#define NANOS_PER_MILLISECOND (NANOS_PER_MICROSECOND * 1000)
-#define MILLIS_PER_SECOND     1000
-#define NANOS_PER_SECOND      (NANOS_PER_MILLISECOND * MILLIS_PER_SECOND)
-
-class AudioRecorder
-{
-public:
-    AudioRecorder() {
-    }
-    ~AudioRecorder() {
-        delete[] mData;
-    }
-
-    void allocate(int maxFrames) {
-        delete[] mData;
-        mData = new float[maxFrames];
-        mMaxFrames = maxFrames;
-    }
-
-    void record(int16_t *inputData, int inputChannelCount, int numFrames) {
-        // stop at end of buffer
-        if ((mFrameCounter + numFrames) > mMaxFrames) {
-            numFrames = mMaxFrames - mFrameCounter;
-        }
-        for (int i = 0; i < numFrames; i++) {
-            mData[mFrameCounter++] = inputData[i * inputChannelCount] * (1.0f / 32768);
-        }
-    }
-
-    void record(float *inputData, int inputChannelCount, int numFrames) {
-        // stop at end of buffer
-        if ((mFrameCounter + numFrames) > mMaxFrames) {
-            numFrames = mMaxFrames - mFrameCounter;
-        }
-        for (int i = 0; i < numFrames; i++) {
-            mData[mFrameCounter++] = inputData[i * inputChannelCount];
-        }
-    }
-
-    int save(const char *fileName) {
-        FILE *fid = fopen(fileName, "wb");
-        if (fid == NULL) {
-            return errno;
-        }
-        int written = fwrite(mData, sizeof(float), mFrameCounter, fid);
-        fclose(fid);
-        return written;
-    }
-
-private:
-    float *mData = NULL;
-    int32_t mFrameCounter = 0;
-    int32_t mMaxFrames = 0;
-};
-
-// ====================================================================================
-// ========================= Loopback Processor =======================================
-// ====================================================================================
-class LoopbackProcessor {
-public:
-
-    // Calculate mean and standard deviation.
-    double calculateAverageLatency(double *deviation) {
-        if (mLatencyCount <= 0) {
-            return -1.0;
-        }
-        double sum = 0.0;
-        for (int i = 0; i < mLatencyCount; i++) {
-            sum += mLatencyArray[i];
-        }
-        double average = sum /  mLatencyCount;
-        sum = 0.0;
-        for (int i = 0; i < mLatencyCount; i++) {
-            double error = average - mLatencyArray[i];
-            sum += error * error; // squared
-        }
-        *deviation = sqrt(sum / mLatencyCount);
-        return average;
-    }
-
-    float getMaxAmplitude() const { return mMaxAmplitude; }
-    int   getMeasurementCount() const { return mLatencyCount; }
-    float getAverageAmplitude() const { return mAmplitudeTotal / mAmplitudeCount; }
-
-    // TODO Convert this to a feedback circuit and then use auto-correlation to measure the period.
-    void process(float *inputData, int inputChannelCount,
-            float *outputData, int outputChannelCount,
-            int numFrames) {
-        (void) outputChannelCount;
-
-        // Measure peak and average amplitude.
-        for (int i = 0; i < numFrames; i++) {
-            float sample = inputData[i * inputChannelCount];
-            if (sample > mMaxAmplitude) {
-                mMaxAmplitude = sample;
-            }
-            if (sample < 0) {
-                sample = 0 - sample;
-            }
-            mAmplitudeTotal += sample;
-            mAmplitudeCount++;
-        }
-
-        // Clear output.
-        memset(outputData, 0, numFrames * outputChannelCount * sizeof(float));
-
-        // Wait a while between hearing the pulse and starting a new one.
-        if (mState == STATE_SILENT) {
-            mCounter += numFrames;
-            if (mCounter > SILENCE_FRAMES) {
-                //printf("LoopbackProcessor send impulse, burst #%d\n", mBurstCounter);
-                // copy impulse
-                for (float sample : mImpulse) {
-                    *outputData = sample;
-                    outputData += outputChannelCount;
-                }
-                mState = STATE_LISTENING;
-                mCounter = 0;
-            }
-        }
-        // Start listening as soon as we send the impulse.
-        if (mState ==  STATE_LISTENING) {
-            for (int i = 0; i < numFrames; i++) {
-                float sample = inputData[i * inputChannelCount];
-                if (sample >= INPUT_PEAK_THRESHOLD) {
-                    mLatencyArray[mLatencyCount++] = mCounter;
-                    if (mLatencyCount >= MAX_LATENCY_VALUES) {
-                        mState = STATE_DONE;
-                    } else {
-                        mState = STATE_SILENT;
-                    }
-                    mCounter = 0;
-                    break;
-                } else {
-                    mCounter++;
-                }
-            }
-        }
-    }
-
-    void echo(float *inputData, int inputChannelCount,
-            float *outputData, int outputChannelCount,
-            int numFrames) {
-        int channelsValid = (inputChannelCount < outputChannelCount)
-            ? inputChannelCount : outputChannelCount;
-        for (int i = 0; i < numFrames; i++) {
-            int ic;
-            for (ic = 0; ic < channelsValid; ic++) {
-                outputData[ic] = inputData[ic];
-            }
-            for (ic = 0; ic < outputChannelCount; ic++) {
-                outputData[ic] = 0;
-            }
-            inputData += inputChannelCount;
-            outputData += outputChannelCount;
-        }
-    }
-private:
-    enum {
-        STATE_SILENT,
-        STATE_LISTENING,
-        STATE_DONE
-    };
-
-    enum {
-        MAX_LATENCY_VALUES = 64
-    };
-
-    int     mState = STATE_SILENT;
-    int32_t mCounter = 0;
-    int32_t mLatencyArray[MAX_LATENCY_VALUES];
-    int32_t mLatencyCount = 0;
-    float   mMaxAmplitude = 0;
-    float   mAmplitudeTotal = 0;
-    int32_t mAmplitudeCount = 0;
-    static const float mImpulse[5];
-};
-
-const float LoopbackProcessor::mImpulse[5] = {0.5f, 0.9f, 0.0f, -0.9f, -0.5f};
-
-// TODO make this a class that manages its own buffer allocation
 struct LoopbackData {
-    AAudioStream     *inputStream = nullptr;
-    int32_t           inputFramesMaximum = 0;
-    int16_t          *inputData = nullptr;
-    float            *conversionBuffer = nullptr;
-    int32_t           actualInputChannelCount = 0;
-    int32_t           actualOutputChannelCount = 0;
-    int32_t           inputBuffersToDiscard = 10;
+    AAudioStream      *inputStream = nullptr;
+    int32_t            inputFramesMaximum = 0;
+    int16_t           *inputData = nullptr;
+    int16_t            peakShort = 0;
+    float             *conversionBuffer = nullptr;
+    int32_t            actualInputChannelCount = 0;
+    int32_t            actualOutputChannelCount = 0;
+    int32_t            inputBuffersToDiscard = 10;
+    int32_t            minNumFrames = INT32_MAX;
+    int32_t            maxNumFrames = 0;
+    bool               isDone = false;
 
-    aaudio_result_t   inputError;
-    LoopbackProcessor loopbackProcessor;
-    AudioRecorder     audioRecorder;
+    aaudio_result_t    inputError = AAUDIO_OK;
+    aaudio_result_t    outputError = AAUDIO_OK;
+
+    SineAnalyzer       sineAnalyzer;
+    EchoAnalyzer       echoAnalyzer;
+    AudioRecording     audioRecorder;
+    LoopbackProcessor *loopbackProcessor;
 };
 
 static void convertPcm16ToFloat(const int16_t *source,
@@ -249,6 +82,7 @@
         int32_t numFrames
 ) {
     (void) outputStream;
+    aaudio_data_callback_result_t result = AAUDIO_CALLBACK_RESULT_CONTINUE;
     LoopbackData *myData = (LoopbackData *) userData;
     float  *outputData = (float  *) audioData;
 
@@ -260,6 +94,13 @@
         return AAUDIO_CALLBACK_RESULT_STOP;
     }
 
+    if (numFrames > myData->maxNumFrames) {
+        myData->maxNumFrames = numFrames;
+    }
+    if (numFrames < myData->minNumFrames) {
+        myData->minNumFrames = numFrames;
+    }
+
     if (myData->inputBuffersToDiscard > 0) {
         // Drain the input.
         do {
@@ -267,6 +108,8 @@
                                        numFrames, 0);
             if (framesRead < 0) {
                 myData->inputError = framesRead;
+                printf("ERROR in read = %d", framesRead);
+                result = AAUDIO_CALLBACK_RESULT_STOP;
             } else if (framesRead > 0) {
                 myData->inputBuffersToDiscard--;
             }
@@ -276,39 +119,62 @@
                                        numFrames, 0);
         if (framesRead < 0) {
             myData->inputError = framesRead;
+            printf("ERROR in read = %d", framesRead);
+            result = AAUDIO_CALLBACK_RESULT_STOP;
         } else if (framesRead > 0) {
-            // Process valid input data.
-            myData->audioRecorder.record(myData->inputData,
-                                         myData->actualInputChannelCount,
-                                         framesRead);
+
+            myData->audioRecorder.write(myData->inputData,
+                                        myData->actualInputChannelCount,
+                                        numFrames);
 
             int32_t numSamples = framesRead * myData->actualInputChannelCount;
             convertPcm16ToFloat(myData->inputData, myData->conversionBuffer, numSamples);
 
-            myData->loopbackProcessor.process(myData->conversionBuffer,
+            myData->loopbackProcessor->process(myData->conversionBuffer,
                                               myData->actualInputChannelCount,
                                               outputData,
                                               myData->actualOutputChannelCount,
                                               framesRead);
+            myData->isDone = myData->loopbackProcessor->isDone();
+            if (myData->isDone) {
+                result = AAUDIO_CALLBACK_RESULT_STOP;
+            }
         }
     }
 
-    return AAUDIO_CALLBACK_RESULT_CONTINUE;
+    return result;
+}
+
+static void MyErrorCallbackProc(
+        AAudioStream *stream __unused,
+        void *userData __unused,
+        aaudio_result_t error)
+{
+    printf("Error Callback, error: %d\n",(int)error);
+    LoopbackData *myData = (LoopbackData *) userData;
+    myData->outputError = error;
 }
 
 static void usage() {
-    printf("loopback: -b{burstsPerBuffer} -p{outputPerfMode} -P{inputPerfMode}\n");
-    printf("          -b{burstsPerBuffer} for example 2 for double buffered\n");
-    printf("          -p{outputPerfMode}  set output AAUDIO_PERFORMANCE_MODE*\n");
-    printf("          -P{inputPerfMode}   set input AAUDIO_PERFORMANCE_MODE*\n");
+    printf("loopback: -n{numBursts} -p{outPerf} -P{inPerf} -t{test} -g{gain} -f{freq}\n");
+    printf("          -c{inputChannels}\n");
+    printf("          -f{freq}  sine frequency\n");
+    printf("          -g{gain}  recirculating loopback gain\n");
+    printf("          -m enable MMAP mode\n");
+    printf("          -n{numBursts} buffer size, for example 2 for double buffered\n");
+    printf("          -p{outPerf}  set output AAUDIO_PERFORMANCE_MODE*\n");
+    printf("          -P{inPerf}   set input AAUDIO_PERFORMANCE_MODE*\n");
     printf("              n for _NONE\n");
     printf("              l for _LATENCY\n");
     printf("              p for _POWER_SAVING;\n");
+    printf("          -t{test}   select test mode\n");
+    printf("              m for sine magnitude\n");
+    printf("              e for echo latency (default)\n");
     printf("For example:  loopback -b2 -pl -Pn\n");
 }
 
 static aaudio_performance_mode_t parsePerformanceMode(char c) {
-    aaudio_performance_mode_t mode = AAUDIO_PERFORMANCE_MODE_NONE;
+    aaudio_performance_mode_t mode = AAUDIO_ERROR_ILLEGAL_ARGUMENT;
     c = tolower(c);
     switch (c) {
         case 'n':
@@ -321,208 +187,281 @@
             mode = AAUDIO_PERFORMANCE_MODE_POWER_SAVING;
             break;
         default:
-            printf("ERROR invalue performance mode %c\n", c);
+            printf("ERROR in value performance mode %c\n", c);
             break;
     }
     return mode;
 }
 
+enum {
+    TEST_SINE_MAGNITUDE = 0,
+    TEST_ECHO_LATENCY,
+};
+
+static int parseTestMode(char c) {
+    int testMode = TEST_ECHO_LATENCY;
+    c = tolower(c);
+    switch (c) {
+        case 'm':
+            testMode = TEST_SINE_MAGNITUDE;
+            break;
+        case 'e':
+            testMode = TEST_ECHO_LATENCY;
+            break;
+        default:
+            printf("ERROR in value test mode %c\n", c);
+            break;
+    }
+    return testMode;
+}
+
+void printAudioGraph(AudioRecording &recording, int numSamples) {
+    int32_t start = recording.size() / 2;
+    int32_t end = start + numSamples;
+    if (end >= recording.size()) {
+        end = recording.size() - 1;
+    }
+    float *data = recording.getData();
+    // Normalize data so we can see it better.
+    float maxSample = 0.01;
+    for (int32_t i = start; i < end; i++) {
+        float samplePos = fabs(data[i]);
+        if (samplePos > maxSample) {
+            maxSample = samplePos;
+        }
+    }
+    float gain = 0.98f / maxSample;
+    for (int32_t i = start; i < end; i++) {
+        float sample = data[i];
+        printf("%5.3f ", sample); // actual value
+        sample *= gain;
+        printAudioScope(sample);
+    }
+}
+
+
 // ====================================================================================
 // TODO break up this large main() function into smaller functions
 int main(int argc, const char **argv)
 {
-    aaudio_result_t result = AAUDIO_OK;
-    LoopbackData loopbackData;
-    AAudioStream *outputStream = nullptr;
 
-    const int requestedInputChannelCount = 1;
-    const int requestedOutputChannelCount = AAUDIO_UNSPECIFIED;
-    const int requestedSampleRate = SAMPLE_RATE;
-    int actualSampleRate = 0;
+    AAudioArgsParser     argParser;
+    AAudioSimplePlayer   player;
+    AAudioSimpleRecorder recorder;
+    LoopbackData         loopbackData;
+    AAudioStream        *outputStream = nullptr;
+
+    aaudio_result_t      result = AAUDIO_OK;
+    aaudio_sharing_mode_t requestedInputSharingMode     = AAUDIO_SHARING_MODE_SHARED;
+    int                   requestedInputChannelCount = NUM_INPUT_CHANNELS;
+    const int             requestedOutputChannelCount = AAUDIO_UNSPECIFIED;
+    int                   actualSampleRate = 0;
     const aaudio_format_t requestedInputFormat = AAUDIO_FORMAT_PCM_I16;
     const aaudio_format_t requestedOutputFormat = AAUDIO_FORMAT_PCM_FLOAT;
-    aaudio_format_t actualInputFormat;
-    aaudio_format_t actualOutputFormat;
+    aaudio_format_t       actualInputFormat;
+    aaudio_format_t       actualOutputFormat;
+    aaudio_performance_mode_t outputPerformanceLevel = AAUDIO_PERFORMANCE_MODE_LOW_LATENCY;
+    aaudio_performance_mode_t inputPerformanceLevel = AAUDIO_PERFORMANCE_MODE_LOW_LATENCY;
 
-    const aaudio_sharing_mode_t requestedSharingMode = AAUDIO_SHARING_MODE_EXCLUSIVE;
-    //const aaudio_sharing_mode_t requestedSharingMode = AAUDIO_SHARING_MODE_SHARED;
-    aaudio_sharing_mode_t       actualSharingMode;
+    int testMode = TEST_ECHO_LATENCY;
+    double gain = 1.0;
 
-    AAudioStreamBuilder  *builder = nullptr;
     aaudio_stream_state_t state = AAUDIO_STREAM_STATE_UNINITIALIZED;
     int32_t framesPerBurst = 0;
     float *outputData = NULL;
     double deviation;
     double latency;
-    aaudio_performance_mode_t outputPerformanceLevel = AAUDIO_PERFORMANCE_MODE_LOW_LATENCY;
-    aaudio_performance_mode_t inputPerformanceLevel = AAUDIO_PERFORMANCE_MODE_LOW_LATENCY;
-
     int32_t burstsPerBuffer = 1; // single buffered
 
-    for (int i = 1; i < argc; i++) {
-        const char *arg = argv[i];
-        if (arg[0] == '-') {
-            char option = arg[1];
-            switch (option) {
-                case 'b':
-                    burstsPerBuffer = atoi(&arg[2]);
-                    break;
-                case 'p':
-                    outputPerformanceLevel = parsePerformanceMode(arg[2]);
-                    break;
-                case 'P':
-                    inputPerformanceLevel = parsePerformanceMode(arg[2]);
-                    break;
-                default:
-                    usage();
-                    break;
-            }
-        } else {
-            break;
-        }
-    }
-
-    loopbackData.audioRecorder.allocate(NUM_SECONDS * SAMPLE_RATE);
-
     // Make printf print immediately so that debug info is not stuck
     // in a buffer if we hang or crash.
     setvbuf(stdout, NULL, _IONBF, (size_t) 0);
 
-    printf("%s - Audio loopback using AAudio\n", argv[0]);
+    printf("%s - Audio loopback using AAudio V" APP_VERSION "\n", argv[0]);
 
-    // Use an AAudioStreamBuilder to contain requested parameters.
-    result = AAudio_createStreamBuilder(&builder);
-    if (result < 0) {
-        goto finish;
+    for (int i = 1; i < argc; i++) {
+        const char *arg = argv[i];
+        if (argParser.parseArg(arg)) {
+            // Handle options that are not handled by the ArgParser
+            if (arg[0] == '-') {
+                char option = arg[1];
+                switch (option) {
+                    case 'C':
+                        requestedInputChannelCount = atoi(&arg[2]);
+                        break;
+                    case 'g':
+                        gain = atof(&arg[2]);
+                        break;
+                    case 'P':
+                        inputPerformanceLevel = parsePerformanceMode(arg[2]);
+                        break;
+                    case 'X':
+                        requestedInputSharingMode = AAUDIO_SHARING_MODE_EXCLUSIVE;
+                        break;
+                    case 't':
+                        testMode = parseTestMode(arg[2]);
+                        break;
+                    default:
+                        usage();
+                        exit(EXIT_FAILURE);
+                        break;
+                }
+            } else {
+                usage();
+                exit(EXIT_FAILURE);
+                break;
+            }
+        }
+
     }
 
-    // Request common stream properties.
-    AAudioStreamBuilder_setSampleRate(builder, requestedSampleRate);
-    AAudioStreamBuilder_setFormat(builder, requestedInputFormat);
-    AAudioStreamBuilder_setSharingMode(builder, requestedSharingMode);
-
-    // Open the input stream.
-    AAudioStreamBuilder_setDirection(builder, AAUDIO_DIRECTION_INPUT);
-    AAudioStreamBuilder_setPerformanceMode(builder, inputPerformanceLevel);
-    AAudioStreamBuilder_setChannelCount(builder, requestedInputChannelCount);
-
-    result = AAudioStreamBuilder_openStream(builder, &loopbackData.inputStream);
-    printf("AAudioStreamBuilder_openStream(input) returned %d = %s\n",
-           result, AAudio_convertResultToText(result));
-    if (result < 0) {
-        goto finish;
+    if (inputPerformanceLevel < 0) {
+        printf("illegal inputPerformanceLevel = %d\n", inputPerformanceLevel);
+        exit(EXIT_FAILURE);
     }
 
-    // Create an output stream using the Builder.
-    AAudioStreamBuilder_setDirection(builder, AAUDIO_DIRECTION_OUTPUT);
-    AAudioStreamBuilder_setFormat(builder, requestedOutputFormat);
-    AAudioStreamBuilder_setPerformanceMode(builder, outputPerformanceLevel);
-    AAudioStreamBuilder_setChannelCount(builder, requestedOutputChannelCount);
-    AAudioStreamBuilder_setDataCallback(builder, MyDataCallbackProc, &loopbackData);
+    int32_t requestedDuration = argParser.getDurationSeconds();
+    int32_t recordingDuration = std::min(60, requestedDuration);
+    loopbackData.audioRecorder.allocate(recordingDuration * SAMPLE_RATE);
 
-    result = AAudioStreamBuilder_openStream(builder, &outputStream);
-    printf("AAudioStreamBuilder_openStream(output) returned %d = %s\n",
-           result, AAudio_convertResultToText(result));
+    switch(testMode) {
+        case TEST_SINE_MAGNITUDE:
+            loopbackData.loopbackProcessor = &loopbackData.sineAnalyzer;
+            break;
+        case TEST_ECHO_LATENCY:
+            loopbackData.echoAnalyzer.setGain(gain);
+            loopbackData.loopbackProcessor = &loopbackData.echoAnalyzer;
+            break;
+        default:
+            exit(1);
+            break;
+    }
+
+    printf("OUTPUT stream ----------------------------------------\n");
+    argParser.setFormat(requestedOutputFormat);
+    result = player.open(argParser, MyDataCallbackProc, MyErrorCallbackProc, &loopbackData);
     if (result != AAUDIO_OK) {
+        fprintf(stderr, "ERROR -  player.open() returned %d\n", result);
         goto finish;
     }
+    outputStream = player.getStream();
+    argParser.compareWithStream(outputStream);
 
-    printf("Stream INPUT ---------------------\n");
-    loopbackData.actualInputChannelCount = AAudioStream_getChannelCount(loopbackData.inputStream);
-    printf("    channelCount: requested = %d, actual = %d\n", requestedInputChannelCount,
-           loopbackData.actualInputChannelCount);
-    printf("    framesPerBurst = %d\n", AAudioStream_getFramesPerBurst(loopbackData.inputStream));
+    actualOutputFormat = AAudioStream_getFormat(outputStream);
+    assert(actualOutputFormat == AAUDIO_FORMAT_PCM_FLOAT);
 
-    actualInputFormat = AAudioStream_getFormat(loopbackData.inputStream);
-    printf("    dataFormat: requested = %d, actual = %d\n", requestedInputFormat, actualInputFormat);
-    assert(actualInputFormat == AAUDIO_FORMAT_PCM_I16);
-
-    printf("Stream OUTPUT ---------------------\n");
-    // Check to see what kind of stream we actually got.
-    actualSampleRate = AAudioStream_getSampleRate(outputStream);
-    printf("    sampleRate: requested = %d, actual = %d\n", requestedSampleRate, actualSampleRate);
-
-    loopbackData.actualOutputChannelCount = AAudioStream_getChannelCount(outputStream);
-    printf("    channelCount: requested = %d, actual = %d\n", requestedOutputChannelCount,
-           loopbackData.actualOutputChannelCount);
-
-    actualSharingMode = AAudioStream_getSharingMode(outputStream);
-    printf("    sharingMode: requested = %d, actual = %d\n", requestedSharingMode, actualSharingMode);
+    printf("INPUT stream ----------------------------------------\n");
+    // Use different parameters for the input.
+    argParser.setNumberOfBursts(AAUDIO_UNSPECIFIED);
+    argParser.setFormat(requestedInputFormat);
+    argParser.setPerformanceMode(inputPerformanceLevel);
+    argParser.setChannelCount(requestedInputChannelCount);
+    argParser.setSharingMode(requestedInputSharingMode);
+    result = recorder.open(argParser);
+    if (result != AAUDIO_OK) {
+        fprintf(stderr, "ERROR -  recorder.open() returned %d\n", result);
+        goto finish;
+    }
+    loopbackData.inputStream = recorder.getStream();
+    argParser.compareWithStream(loopbackData.inputStream);
 
     // This is the number of frames that are read in one chunk by a DMA controller
     // or a DSP or a mixer.
     framesPerBurst = AAudioStream_getFramesPerBurst(outputStream);
-    printf("    framesPerBurst = %d\n", framesPerBurst);
 
-    printf("    bufferCapacity = %d\n", AAudioStream_getBufferCapacityInFrames(outputStream));
+    actualInputFormat = AAudioStream_getFormat(outputStream);
+    assert(actualInputFormat == AAUDIO_FORMAT_PCM_I16);
 
-    actualOutputFormat = AAudioStream_getFormat(outputStream);
-    printf("    dataFormat: requested = %d, actual = %d\n", requestedOutputFormat, actualOutputFormat);
-    assert(actualOutputFormat == AAUDIO_FORMAT_PCM_FLOAT);
+
+    loopbackData.actualInputChannelCount = recorder.getChannelCount();
+    loopbackData.actualOutputChannelCount = player.getChannelCount();
 
     // Allocate a buffer for the audio data.
     loopbackData.inputFramesMaximum = 32 * framesPerBurst;
+    loopbackData.inputBuffersToDiscard = 100;
 
-    loopbackData.inputData = new int16_t[loopbackData.inputFramesMaximum * loopbackData.actualInputChannelCount];
+    loopbackData.inputData = new int16_t[loopbackData.inputFramesMaximum
+                                         * loopbackData.actualInputChannelCount];
     loopbackData.conversionBuffer = new float[loopbackData.inputFramesMaximum *
                                               loopbackData.actualInputChannelCount];
 
-    result = AAudioStream_setBufferSizeInFrames(outputStream, burstsPerBuffer * framesPerBurst);
-    if (result < 0) { // may be positive buffer size
-        fprintf(stderr, "ERROR - AAudioStream_setBufferSize() returned %d\n", result);
-        goto finish;
-    }
-    printf("AAudioStream_setBufferSize() actual = %d\n",result);
+    loopbackData.loopbackProcessor->reset();
 
-    // Start output first so input stream runs low.
-    result = AAudioStream_requestStart(outputStream);
+    result = recorder.start();
     if (result != AAUDIO_OK) {
-        fprintf(stderr, "ERROR - AAudioStream_requestStart(output) returned %d = %s\n",
-                result, AAudio_convertResultToText(result));
+        printf("ERROR - AAudioStream_requestStart(input) returned %d = %s\n",
+               result, AAudio_convertResultToText(result));
         goto finish;
     }
 
-    result = AAudioStream_requestStart(loopbackData.inputStream);
+    result = player.start();
     if (result != AAUDIO_OK) {
-        fprintf(stderr, "ERROR - AAudioStream_requestStart(input) returned %d = %s\n",
-                result, AAudio_convertResultToText(result));
+        printf("ERROR - AAudioStream_requestStart(output) returned %d = %s\n",
+               result, AAudio_convertResultToText(result));
         goto finish;
     }
 
     printf("------- sleep while the callback runs --------------\n");
     fflush(stdout);
-    sleep(NUM_SECONDS);
-
+    for (int i = requestedDuration; i > 0 ; i--) {
+        if (loopbackData.inputError != AAUDIO_OK) {
+            printf("  ERROR on input stream\n");
+            break;
+        } else if (loopbackData.outputError != AAUDIO_OK) {
+                printf("  ERROR on output stream\n");
+                break;
+        } else if (loopbackData.isDone) {
+                printf("  test says it is done!\n");
+                break;
+        } else {
+            sleep(1);
+            printf("%4d: ", i);
+            loopbackData.loopbackProcessor->printStatus();
+            int64_t framesWritten = AAudioStream_getFramesWritten(loopbackData.inputStream);
+            int64_t framesRead = AAudioStream_getFramesRead(loopbackData.inputStream);
+            printf(" input written = %lld, read %lld, xruns = %d\n",
+                   (long long) framesWritten,
+                   (long long) framesRead,
+                   AAudioStream_getXRunCount(outputStream)
+            );
+        }
+    }
 
     printf("input error = %d = %s\n",
                 loopbackData.inputError, AAudio_convertResultToText(loopbackData.inputError));
 
     printf("AAudioStream_getXRunCount %d\n", AAudioStream_getXRunCount(outputStream));
-    printf("framesRead    = %d\n", (int) AAudioStream_getFramesRead(outputStream));
-    printf("framesWritten = %d\n", (int) AAudioStream_getFramesWritten(outputStream));
+    printf("framesRead    = %8d\n", (int) AAudioStream_getFramesRead(outputStream));
+    printf("framesWritten = %8d\n", (int) AAudioStream_getFramesWritten(outputStream));
+    printf("min numFrames = %8d\n", (int) loopbackData.minNumFrames);
+    printf("max numFrames = %8d\n", (int) loopbackData.maxNumFrames);
 
-    latency = loopbackData.loopbackProcessor.calculateAverageLatency(&deviation);
-    printf("measured peak    = %8.5f\n", loopbackData.loopbackProcessor.getMaxAmplitude());
-    printf("threshold        = %8.5f\n", INPUT_PEAK_THRESHOLD);
-    printf("measured average = %8.5f\n", loopbackData.loopbackProcessor.getAverageAmplitude());
-    printf("# latency measurements = %d\n", loopbackData.loopbackProcessor.getMeasurementCount());
-    printf("measured latency = %8.2f +/- %4.5f frames\n", latency, deviation);
-    printf("measured latency = %8.2f msec  <===== !!\n", (1000.0 * latency / actualSampleRate));
+    if (loopbackData.inputError == AAUDIO_OK) {
+        if (testMode == TEST_SINE_MAGNITUDE) {
+            printAudioGraph(loopbackData.audioRecorder, 200);
+        }
+        loopbackData.loopbackProcessor->report();
+    }
 
     {
         int written = loopbackData.audioRecorder.save(FILENAME);
-        printf("wrote %d samples to %s\n", written, FILENAME);
+        printf("main() wrote %d mono samples to %s on Android device\n", written, FILENAME);
     }
 
 finish:
-    AAudioStream_close(outputStream);
-    AAudioStream_close(loopbackData.inputStream);
+    player.close();
+    recorder.close();
     delete[] loopbackData.conversionBuffer;
     delete[] loopbackData.inputData;
     delete[] outputData;
-    AAudioStreamBuilder_delete(builder);
 
-    printf("exiting - AAudio result = %d = %s\n", result, AAudio_convertResultToText(result));
-    return (result != AAUDIO_OK) ? EXIT_FAILURE : EXIT_SUCCESS;
+    printf(RESULT_TAG "error = %d = %s\n", result, AAudio_convertResultToText(result));
+    if ((result != AAUDIO_OK)) {
+        printf("error %d = %s\n", result, AAudio_convertResultToText(result));
+        return EXIT_FAILURE;
+    } else {
+        printf("SUCCESS\n");
+        return EXIT_SUCCESS;
+    }
 }
 
diff --git a/media/libaaudio/examples/loopback/src/loopback.sh b/media/libaaudio/examples/loopback/src/loopback.sh
new file mode 100644
index 0000000..bc63125
--- /dev/null
+++ b/media/libaaudio/examples/loopback/src/loopback.sh
@@ -0,0 +1,14 @@
+#!/system/bin/sh
+# Run a loopback test in the background after a delay.
+# To run the script enter:
+#    adb shell "nohup sh /data/loopback.sh &"
+
+SLEEP_TIME=10
+TEST_COMMAND="aaudio_loopback -pl -Pl -C1 -n2 -m2 -tm -d5"
+
+echo "Plug in USB Mir and Fun Plug."
+echo "Test will start in ${SLEEP_TIME} seconds: ${TEST_COMMAND}"
+sleep ${SLEEP_TIME}
+date > /data/loopreport.txt
+${TEST_COMMAND} >> /data/loopreport.txt
+date >> /data/loopreport.txt
diff --git a/media/libaaudio/examples/utils/AAudioArgsParser.h b/media/libaaudio/examples/utils/AAudioArgsParser.h
new file mode 100644
index 0000000..46bc99e
--- /dev/null
+++ b/media/libaaudio/examples/utils/AAudioArgsParser.h
@@ -0,0 +1,296 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAUDIO_EXAMPLE_ARGS_PARSER_H
+#define AAUDIO_EXAMPLE_ARGS_PARSER_H
+
+#include <cctype>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <aaudio/AAudio.h>
+#include <aaudio/AAudioTesting.h>
+#include <AAudioExampleUtils.h>
+
+// TODO use this as a base class within AAudio
+class AAudioParameters {
+public:
+
+    /**
+     * This is also known as samplesPerFrame.
+     */
+    int32_t getChannelCount() const {
+        return mChannelCount;
+    }
+
+    void setChannelCount(int32_t channelCount) {
+        mChannelCount = channelCount;
+    }
+
+    int32_t getSampleRate() const {
+        return mSampleRate;
+    }
+
+    void setSampleRate(int32_t sampleRate) {
+        mSampleRate = sampleRate;
+    }
+
+    aaudio_format_t getFormat() const {
+        return mFormat;
+    }
+
+    void setFormat(aaudio_format_t format) {
+        mFormat = format;
+    }
+
+    aaudio_sharing_mode_t getSharingMode() const {
+        return mSharingMode;
+    }
+
+    void setSharingMode(aaudio_sharing_mode_t sharingMode) {
+        mSharingMode = sharingMode;
+    }
+
+    int32_t getBufferCapacity() const {
+        return mBufferCapacity;
+    }
+
+    void setBufferCapacity(int32_t frames) {
+        mBufferCapacity = frames;
+    }
+
+    int32_t getPerformanceMode() const {
+        return mPerformanceMode;
+    }
+
+    void setPerformanceMode(aaudio_performance_mode_t performanceMode) {
+        mPerformanceMode = performanceMode;
+    }
+
+    int32_t getDeviceId() const {
+        return mDeviceId;
+    }
+
+    void setDeviceId(int32_t deviceId) {
+        mDeviceId = deviceId;
+    }
+
+    int32_t getNumberOfBursts() const {
+        return mNumberOfBursts;
+    }
+
+    void setNumberOfBursts(int32_t numBursts) {
+        mNumberOfBursts = numBursts;
+    }
+
+    /**
+     * Apply these parameters to a stream builder.
+     * @param builder
+     */
+    void applyParameters(AAudioStreamBuilder *builder) const {
+        AAudioStreamBuilder_setChannelCount(builder, mChannelCount);
+        AAudioStreamBuilder_setFormat(builder, mFormat);
+        AAudioStreamBuilder_setSampleRate(builder, mSampleRate);
+        AAudioStreamBuilder_setBufferCapacityInFrames(builder, mBufferCapacity);
+        AAudioStreamBuilder_setDeviceId(builder, mDeviceId);
+        AAudioStreamBuilder_setSharingMode(builder, mSharingMode);
+        AAudioStreamBuilder_setPerformanceMode(builder, mPerformanceMode);
+    }
+
+private:
+    int32_t                    mChannelCount    = AAUDIO_UNSPECIFIED;
+    aaudio_format_t            mFormat          = AAUDIO_FORMAT_UNSPECIFIED;
+    int32_t                    mSampleRate      = AAUDIO_UNSPECIFIED;
+
+    int32_t                    mBufferCapacity  = AAUDIO_UNSPECIFIED;
+    int32_t                    mDeviceId        = AAUDIO_UNSPECIFIED;
+    aaudio_sharing_mode_t      mSharingMode     = AAUDIO_SHARING_MODE_SHARED;
+    aaudio_performance_mode_t  mPerformanceMode = AAUDIO_PERFORMANCE_MODE_NONE;
+
+    int32_t                    mNumberOfBursts  = AAUDIO_UNSPECIFIED;
+};
+
+class AAudioArgsParser : public AAudioParameters {
+public:
+    AAudioArgsParser() = default;
+    ~AAudioArgsParser() = default;
+
+    enum {
+        DEFAULT_DURATION_SECONDS = 5
+    };
+
+    /**
+     * @param arg
+     * @return true if the argument was not handled
+     */
+    bool parseArg(const char *arg) {
+        bool unrecognized = false;
+        if (arg[0] == '-') {
+            char option = arg[1];
+            switch (option) {
+                case 'b':
+                    setBufferCapacity(atoi(&arg[2]));
+                    break;
+                case 'c':
+                    setChannelCount(atoi(&arg[2]));
+                    break;
+                case 'd':
+                    mDurationSeconds = atoi(&arg[2]);
+                    break;
+                case 'm': {
+                    aaudio_policy_t policy = AAUDIO_POLICY_AUTO;
+                    if (strlen(arg) > 2) {
+                        policy = atoi(&arg[2]);
+                    }
+                    AAudio_setMMapPolicy(policy);
+                } break;
+                case 'n':
+                    setNumberOfBursts(atoi(&arg[2]));
+                    break;
+                case 'p':
+                    setPerformanceMode(parsePerformanceMode(arg[2]));
+                    break;
+                case 'r':
+                    setSampleRate(atoi(&arg[2]));
+                    break;
+                case 'x':
+                    setSharingMode(AAUDIO_SHARING_MODE_EXCLUSIVE);
+                    break;
+                default:
+                    unrecognized = true;
+                    break;
+            }
+        }
+        return unrecognized;
+    }
+
+    /**
+     *
+     * @param argc
+     * @param argv
+     * @return true if an unrecognized argument was passed
+     */
+    bool parseArgs(int argc, const char **argv) {
+        for (int i = 1; i < argc; i++) {
+            const char *arg = argv[i];
+            if (parseArg(arg)) {
+                usage();
+                return true;
+            }
+
+        }
+        return false;
+    }
+
+    static void usage() {
+        printf("-c{channels} -d{duration} -m -n{burstsPerBuffer} -p{perfMode} -r{rate} -x\n");
+        printf("      Default values are UNSPECIFIED unless otherwise stated.\n");
+        printf("      -b{bufferCapacity} frames\n");
+        printf("      -c{channels} for example 2 for stereo\n");
+        printf("      -d{duration} in seconds, default is %d\n", DEFAULT_DURATION_SECONDS);
+        printf("      -m{0|1|2|3} set MMAP policy\n");
+        printf("          0 = _UNSPECIFIED, default\n");
+        printf("          1 = _NEVER\n");
+        printf("          2 = _AUTO, also if -m is used with no number\n");
+        printf("          3 = _ALWAYS\n");
+        printf("      -n{numberOfBursts} for setBufferSize\n");
+        printf("      -p{performanceMode} set output AAUDIO_PERFORMANCE_MODE*, default NONE\n");
+        printf("          n for _NONE\n");
+        printf("          l for _LATENCY\n");
+        printf("          p for _POWER_SAVING;\n");
+        printf("      -r{sampleRate} for example 44100\n");
+        printf("      -x to use EXCLUSIVE mode\n");
+    }
+
+    static aaudio_performance_mode_t parsePerformanceMode(char c) {
+        aaudio_performance_mode_t mode = AAUDIO_PERFORMANCE_MODE_NONE;
+        switch (c) {
+            case 'n':
+                mode = AAUDIO_PERFORMANCE_MODE_NONE;
+                break;
+            case 'l':
+                mode = AAUDIO_PERFORMANCE_MODE_LOW_LATENCY;
+                break;
+            case 'p':
+                mode = AAUDIO_PERFORMANCE_MODE_POWER_SAVING;
+                break;
+            default:
+                printf("ERROR invalid performance mode %c\n", c);
+                break;
+        }
+        return mode;
+    }
+
+    /**
+     * Print stream parameters in comparison with requested values.
+     * @param stream
+     */
+    void compareWithStream(AAudioStream *stream) {
+
+        printf("  DeviceId:     requested = %d, actual = %d\n",
+               getDeviceId(), AAudioStream_getDeviceId(stream));
+
+        aaudio_stream_state_t state = AAudioStream_getState(stream);
+        printf("  State:        %s\n", AAudio_convertStreamStateToText(state));
+
+        // Check to see what kind of stream we actually got.
+        printf("  SampleRate:   requested = %d, actual = %d\n",
+               getSampleRate(), AAudioStream_getSampleRate(stream));
+
+        printf("  ChannelCount: requested = %d, actual = %d\n",
+               getChannelCount(), AAudioStream_getChannelCount(stream));
+
+        printf("  DataFormat:   requested = %d, actual = %d\n",
+               getFormat(), AAudioStream_getFormat(stream));
+
+        int32_t framesPerBurst = AAudioStream_getFramesPerBurst(stream);
+        int32_t sizeFrames = AAudioStream_getBufferSizeInFrames(stream);
+        printf("  Buffer:       burst     = %d\n", framesPerBurst);
+        if (framesPerBurst > 0) {
+            printf("  Buffer:       size      = %d = (%d * %d) + %d\n",
+                   sizeFrames,
+                   (sizeFrames / framesPerBurst),
+                   framesPerBurst,
+                   (sizeFrames % framesPerBurst));
+        }
+        printf("  Capacity:     requested = %d, actual = %d\n", getBufferCapacity(),
+               AAudioStream_getBufferCapacityInFrames(stream));
+
+        printf("  SharingMode:  requested = %s, actual = %s\n",
+               getSharingModeText(getSharingMode()),
+               getSharingModeText(AAudioStream_getSharingMode(stream)));
+
+        printf("  PerformanceMode: requested = %d, actual = %d\n",
+               getPerformanceMode(), AAudioStream_getPerformanceMode(stream));
+        printf("  Is MMAP used? %s\n", AAudioStream_isMMapUsed(stream)
+               ? "yes" : "no");
+
+    }
+
+    int32_t getDurationSeconds() const {
+        return mDurationSeconds;
+    }
+
+    void setDurationSeconds(int32_t seconds) {
+        mDurationSeconds = seconds;
+    }
+
+private:
+    int32_t      mDurationSeconds = DEFAULT_DURATION_SECONDS;
+};
+
+#endif // AAUDIO_EXAMPLE_ARGS_PARSER_H
diff --git a/media/libaaudio/examples/utils/AAudioSimplePlayer.h b/media/libaaudio/examples/utils/AAudioSimplePlayer.h
index aaeb25f..cc0cb34 100644
--- a/media/libaaudio/examples/utils/AAudioSimplePlayer.h
+++ b/media/libaaudio/examples/utils/AAudioSimplePlayer.h
@@ -23,12 +23,18 @@
 #include <sched.h>
 
 #include <aaudio/AAudio.h>
+#include "AAudioArgsParser.h"
 #include "SineGenerator.h"
 
 //#define SHARING_MODE  AAUDIO_SHARING_MODE_EXCLUSIVE
 #define SHARING_MODE  AAUDIO_SHARING_MODE_SHARED
 #define PERFORMANCE_MODE AAUDIO_PERFORMANCE_MODE_NONE
 
+// Arbitrary period for glitches, once per second at 48000 Hz.
+#define FORCED_UNDERRUN_PERIOD_FRAMES    48000
+// How long to sleep in a callback to cause an intentional glitch. For testing.
+#define FORCED_UNDERRUN_SLEEP_MICROS     (10 * 1000)
+
 /**
  * Simple wrapper for AAudio that opens an output stream either in callback or blocking write mode.
  */
@@ -55,15 +61,23 @@
         mRequestedPerformanceMode = requestedPerformanceMode;
     }
 
+    // TODO Extract a common base class for record and playback.
     /**
      * Also known as "sample rate"
      * Only call this after open() has been called.
      */
-    int32_t getFramesPerSecond() {
+    int32_t getFramesPerSecond() const {
+        return getSampleRate(); // alias
+    }
+
+    /**
+     * Only call this after open() has been called.
+     */
+    int32_t getSampleRate() const {
         if (mStream == nullptr) {
             return AAUDIO_ERROR_INVALID_STATE;
         }
-        return AAudioStream_getSampleRate(mStream);;
+        return AAudioStream_getSampleRate(mStream);
     }
 
     /**
@@ -73,57 +87,83 @@
         if (mStream == nullptr) {
             return AAUDIO_ERROR_INVALID_STATE;
         }
-        return AAudioStream_getChannelCount(mStream);;
+        return AAudioStream_getChannelCount(mStream);
     }
 
     /**
      * Open a stream
      */
+    aaudio_result_t open(const AAudioParameters &parameters,
+                         AAudioStream_dataCallback dataCallback = nullptr,
+                         AAudioStream_errorCallback errorCallback = nullptr,
+                         void *userContext = nullptr) {
+        aaudio_result_t result = AAUDIO_OK;
+
+        // Use an AAudioStreamBuilder to contain requested parameters.
+        AAudioStreamBuilder *builder = nullptr;
+        result = AAudio_createStreamBuilder(&builder);
+        if (result != AAUDIO_OK) return result;
+
+        parameters.applyParameters(builder); // apply args
+
+        AAudioStreamBuilder_setDirection(builder, AAUDIO_DIRECTION_OUTPUT);
+
+        if (dataCallback != nullptr) {
+            AAudioStreamBuilder_setDataCallback(builder, dataCallback, userContext);
+        }
+        if (errorCallback != nullptr) {
+            AAudioStreamBuilder_setErrorCallback(builder, errorCallback, userContext);
+        }
+        //AAudioStreamBuilder_setFramesPerDataCallback(builder, CALLBACK_SIZE_FRAMES);
+        //AAudioStreamBuilder_setBufferCapacityInFrames(builder, 48 * 8);
+
+        // Open an AAudioStream using the Builder.
+        result = AAudioStreamBuilder_openStream(builder, &mStream);
+
+        if (result == AAUDIO_OK) {
+            int32_t sizeInBursts = parameters.getNumberOfBursts();
+            if (sizeInBursts > 0) {
+                int32_t framesPerBurst = AAudioStream_getFramesPerBurst(mStream);
+                AAudioStream_setBufferSizeInFrames(mStream, sizeInBursts * framesPerBurst);
+            }
+        }
+
+        AAudioStreamBuilder_delete(builder);
+        return result;
+    }
+
     aaudio_result_t open(int channelCount, int sampSampleRate, aaudio_format_t format,
-                         AAudioStream_dataCallback dataProc, AAudioStream_errorCallback errorProc,
+                         AAudioStream_dataCallback dataProc,
+                         AAudioStream_errorCallback errorProc,
                          void *userContext) {
         aaudio_result_t result = AAUDIO_OK;
 
         // Use an AAudioStreamBuilder to contain requested parameters.
-        result = AAudio_createStreamBuilder(&mBuilder);
+        AAudioStreamBuilder *builder = nullptr;
+        result = AAudio_createStreamBuilder(&builder);
         if (result != AAUDIO_OK) return result;
 
-        //AAudioStreamBuilder_setSampleRate(mBuilder, 44100);
-        AAudioStreamBuilder_setPerformanceMode(mBuilder, mRequestedPerformanceMode);
-        AAudioStreamBuilder_setSharingMode(mBuilder, mRequestedSharingMode);
+        AAudioStreamBuilder_setDirection(builder, AAUDIO_DIRECTION_OUTPUT);
+        AAudioStreamBuilder_setPerformanceMode(builder, mRequestedPerformanceMode);
+        AAudioStreamBuilder_setSharingMode(builder, mRequestedSharingMode);
+
+        AAudioStreamBuilder_setChannelCount(builder, channelCount);
+        AAudioStreamBuilder_setSampleRate(builder, sampSampleRate);
+        AAudioStreamBuilder_setFormat(builder, format);
+
         if (dataProc != nullptr) {
-            AAudioStreamBuilder_setDataCallback(mBuilder, dataProc, userContext);
+            AAudioStreamBuilder_setDataCallback(builder, dataProc, userContext);
         }
         if (errorProc != nullptr) {
-            AAudioStreamBuilder_setErrorCallback(mBuilder, errorProc, userContext);
+            AAudioStreamBuilder_setErrorCallback(builder, errorProc, userContext);
         }
-        AAudioStreamBuilder_setChannelCount(mBuilder, channelCount);
-        AAudioStreamBuilder_setSampleRate(mBuilder, sampSampleRate);
-        AAudioStreamBuilder_setFormat(mBuilder, format);
-        //AAudioStreamBuilder_setFramesPerDataCallback(mBuilder, CALLBACK_SIZE_FRAMES);
-        AAudioStreamBuilder_setBufferCapacityInFrames(mBuilder, 48 * 8);
-
-        //aaudio_performance_mode_t perfMode = AAUDIO_PERFORMANCE_MODE_NONE;
-        aaudio_performance_mode_t perfMode = AAUDIO_PERFORMANCE_MODE_LOW_LATENCY;
-        //aaudio_performance_mode_t perfMode = AAUDIO_PERFORMANCE_MODE_POWER_SAVING;
-        AAudioStreamBuilder_setPerformanceMode(mBuilder, perfMode);
+        //AAudioStreamBuilder_setFramesPerDataCallback(builder, CALLBACK_SIZE_FRAMES);
+        //AAudioStreamBuilder_setBufferCapacityInFrames(builder, 48 * 8);
 
         // Open an AAudioStream using the Builder.
-        result = AAudioStreamBuilder_openStream(mBuilder, &mStream);
-        if (result != AAUDIO_OK) goto finish1;
+        result = AAudioStreamBuilder_openStream(builder, &mStream);
 
-        printf("AAudioStream_getFramesPerBurst() = %d\n",
-               AAudioStream_getFramesPerBurst(mStream));
-        printf("AAudioStream_getBufferSizeInFrames() = %d\n",
-               AAudioStream_getBufferSizeInFrames(mStream));
-        printf("AAudioStream_getBufferCapacityInFrames() = %d\n",
-               AAudioStream_getBufferCapacityInFrames(mStream));
-        printf("AAudioStream_getPerformanceMode() = %d, requested %d\n",
-               AAudioStream_getPerformanceMode(mStream), perfMode);
-
-     finish1:
-        AAudioStreamBuilder_delete(mBuilder);
-        mBuilder = nullptr;
+        AAudioStreamBuilder_delete(builder);
         return result;
     }
 
@@ -132,8 +172,6 @@
             printf("call AAudioStream_close(%p)\n", mStream);  fflush(stdout);
             AAudioStream_close(mStream);
             mStream = nullptr;
-            AAudioStreamBuilder_delete(mBuilder);
-            mBuilder = nullptr;
         }
         return AAUDIO_OK;
     }
@@ -178,7 +216,6 @@
     }
 
 private:
-    AAudioStreamBuilder      *mBuilder = nullptr;
     AAudioStream             *mStream = nullptr;
     aaudio_sharing_mode_t     mRequestedSharingMode = SHARING_MODE;
     aaudio_performance_mode_t mRequestedPerformanceMode = PERFORMANCE_MODE;
@@ -187,8 +224,13 @@
 typedef struct SineThreadedData_s {
     SineGenerator  sineOsc1;
     SineGenerator  sineOsc2;
+    int64_t        framesTotal = 0;
+    int64_t        nextFrameToGlitch = FORCED_UNDERRUN_PERIOD_FRAMES;
+    int32_t        minNumFrames = INT32_MAX;
+    int32_t        maxNumFrames = 0;
     int            scheduler;
-    bool           schedulerChecked;
+    bool           schedulerChecked = false;
+    bool           forceUnderruns = false;
 } SineThreadedData_t;
 
 // Callback function that fills the audio output buffer.
@@ -201,16 +243,33 @@
 
     // should not happen but just in case...
     if (userData == nullptr) {
-        fprintf(stderr, "ERROR - SimplePlayerDataCallbackProc needs userData\n");
+        printf("ERROR - SimplePlayerDataCallbackProc needs userData\n");
         return AAUDIO_CALLBACK_RESULT_STOP;
     }
     SineThreadedData_t *sineData = (SineThreadedData_t *) userData;
 
+    sineData->framesTotal += numFrames;
+
+    if (sineData->forceUnderruns) {
+        if (sineData->framesTotal > sineData->nextFrameToGlitch) {
+            usleep(FORCED_UNDERRUN_SLEEP_MICROS);
+            printf("Simulate glitch at %lld\n", (long long) sineData->framesTotal);
+            sineData->nextFrameToGlitch += FORCED_UNDERRUN_PERIOD_FRAMES;
+        }
+    }
+
     if (!sineData->schedulerChecked) {
         sineData->scheduler = sched_getscheduler(gettid());
         sineData->schedulerChecked = true;
     }
 
+    if (numFrames > sineData->maxNumFrames) {
+        sineData->maxNumFrames = numFrames;
+    }
+    if (numFrames < sineData->minNumFrames) {
+        sineData->minNumFrames = numFrames;
+    }
+
     int32_t samplesPerFrame = AAudioStream_getChannelCount(stream);
     // This code only plays on the first one or two channels.
     // TODO Support arbitrary number of channels.
diff --git a/media/libaaudio/examples/utils/AAudioSimpleRecorder.h b/media/libaaudio/examples/utils/AAudioSimpleRecorder.h
index 9e7c463..5ecac04 100644
--- a/media/libaaudio/examples/utils/AAudioSimpleRecorder.h
+++ b/media/libaaudio/examples/utils/AAudioSimpleRecorder.h
@@ -20,10 +20,12 @@
 #define AAUDIO_SIMPLE_RECORDER_H
 
 #include <aaudio/AAudio.h>
+#include "AAudioArgsParser.h"
 
 //#define SHARING_MODE  AAUDIO_SHARING_MODE_EXCLUSIVE
 #define SHARING_MODE  AAUDIO_SHARING_MODE_SHARED
 #define PERFORMANCE_MODE AAUDIO_PERFORMANCE_MODE_NONE
+
 /**
  * Simple wrapper for AAudio that opens an input stream either in callback or blocking read mode.
  */
@@ -54,22 +56,37 @@
      * Also known as "sample rate"
      * Only call this after open() has been called.
      */
-    int32_t getFramesPerSecond() {
-        if (mStream == nullptr) {
-            return AAUDIO_ERROR_INVALID_STATE;
-        }
-        return AAudioStream_getSampleRate(mStream);;
+    int32_t getFramesPerSecond() const {
+        return getSampleRate(); // alias
     }
 
     /**
      * Only call this after open() has been called.
      */
-    int32_t getSamplesPerFrame() {
+    int32_t getSampleRate() const {
         if (mStream == nullptr) {
             return AAUDIO_ERROR_INVALID_STATE;
         }
-        return AAudioStream_getSamplesPerFrame(mStream);;
+        return AAudioStream_getSampleRate(mStream);
     }
+
+    /**
+     * Only call this after open() has been called.
+     */
+    int32_t getChannelCount() {
+        if (mStream == nullptr) {
+            return AAUDIO_ERROR_INVALID_STATE;
+        }
+        return AAudioStream_getChannelCount(mStream);
+    }
+
+    /**
+     * @deprecated use getChannelCount()
+     */
+    int32_t getSamplesPerFrame() {
+        return getChannelCount();
+    }
+
     /**
      * Only call this after open() has been called.
      */
@@ -77,53 +94,85 @@
         if (mStream == nullptr) {
             return AAUDIO_ERROR_INVALID_STATE;
         }
-        return AAudioStream_getFramesRead(mStream);;
+        return AAudioStream_getFramesRead(mStream);
+    }
+
+    aaudio_result_t open(const AAudioParameters &parameters,
+                         AAudioStream_dataCallback dataCallback = nullptr,
+                         AAudioStream_errorCallback errorCallback = nullptr,
+                         void *userContext = nullptr) {
+        aaudio_result_t result = AAUDIO_OK;
+
+        // Use an AAudioStreamBuilder to contain requested parameters.
+        AAudioStreamBuilder *builder = nullptr;
+        result = AAudio_createStreamBuilder(&builder);
+        if (result != AAUDIO_OK) return result;
+
+        parameters.applyParameters(builder); // apply args
+
+        AAudioStreamBuilder_setDirection(builder, AAUDIO_DIRECTION_INPUT);
+
+        if (dataCallback != nullptr) {
+            AAudioStreamBuilder_setDataCallback(builder, dataCallback, userContext);
+        }
+        if (errorCallback != nullptr) {
+            AAudioStreamBuilder_setErrorCallback(builder, errorCallback, userContext);
+        }
+
+        // Open an AAudioStream using the Builder.
+        result = AAudioStreamBuilder_openStream(builder, &mStream);
+        if (result != AAUDIO_OK) {
+            fprintf(stderr, "ERROR - AAudioStreamBuilder_openStream() returned %d %s\n",
+                    result, AAudio_convertResultToText(result));
+        }
+
+        if (result == AAUDIO_OK) {
+            int32_t sizeInBursts = parameters.getNumberOfBursts();
+            if (sizeInBursts > 0) {
+                int32_t framesPerBurst = AAudioStream_getFramesPerBurst(mStream);
+                AAudioStream_setBufferSizeInFrames(mStream, sizeInBursts * framesPerBurst);
+            }
+        }
+
+        AAudioStreamBuilder_delete(builder);
+        return result;
     }
 
     /**
      * Open a stream
      */
     aaudio_result_t open(int channelCount, int sampSampleRate, aaudio_format_t format,
-                         AAudioStream_dataCallback dataProc, AAudioStream_errorCallback errorProc,
+                         AAudioStream_dataCallback dataProc,
+                         AAudioStream_errorCallback errorProc,
                          void *userContext) {
         aaudio_result_t result = AAUDIO_OK;
 
         // Use an AAudioStreamBuilder to contain requested parameters.
-        result = AAudio_createStreamBuilder(&mBuilder);
+        AAudioStreamBuilder *builder = nullptr;
+        result = AAudio_createStreamBuilder(&builder);
         if (result != AAUDIO_OK) return result;
 
-        AAudioStreamBuilder_setDirection(mBuilder, AAUDIO_DIRECTION_INPUT);
-        AAudioStreamBuilder_setPerformanceMode(mBuilder, mRequestedPerformanceMode);
-        AAudioStreamBuilder_setSharingMode(mBuilder, mRequestedSharingMode);
+        AAudioStreamBuilder_setDirection(builder, AAUDIO_DIRECTION_INPUT);
+        AAudioStreamBuilder_setPerformanceMode(builder, mRequestedPerformanceMode);
+        AAudioStreamBuilder_setSharingMode(builder, mRequestedSharingMode);
         if (dataProc != nullptr) {
-            AAudioStreamBuilder_setDataCallback(mBuilder, dataProc, userContext);
+            AAudioStreamBuilder_setDataCallback(builder, dataProc, userContext);
         }
         if (errorProc != nullptr) {
-            AAudioStreamBuilder_setErrorCallback(mBuilder, errorProc, userContext);
+            AAudioStreamBuilder_setErrorCallback(builder, errorProc, userContext);
         }
-        AAudioStreamBuilder_setChannelCount(mBuilder, channelCount);
-        AAudioStreamBuilder_setSampleRate(mBuilder, sampSampleRate);
-        AAudioStreamBuilder_setFormat(mBuilder, format);
+        AAudioStreamBuilder_setChannelCount(builder, channelCount);
+        AAudioStreamBuilder_setSampleRate(builder, sampSampleRate);
+        AAudioStreamBuilder_setFormat(builder, format);
 
         // Open an AAudioStream using the Builder.
-        result = AAudioStreamBuilder_openStream(mBuilder, &mStream);
+        result = AAudioStreamBuilder_openStream(builder, &mStream);
         if (result != AAUDIO_OK) {
             fprintf(stderr, "ERROR - AAudioStreamBuilder_openStream() returned %d %s\n",
                     result, AAudio_convertResultToText(result));
-            goto finish1;
         }
 
-        printf("AAudioStream_getFramesPerBurst() = %d\n",
-               AAudioStream_getFramesPerBurst(mStream));
-        printf("AAudioStream_getBufferSizeInFrames() = %d\n",
-               AAudioStream_getBufferSizeInFrames(mStream));
-        printf("AAudioStream_getBufferCapacityInFrames() = %d\n",
-               AAudioStream_getBufferCapacityInFrames(mStream));
-        return result;
-
-     finish1:
-        AAudioStreamBuilder_delete(mBuilder);
-        mBuilder = nullptr;
+        AAudioStreamBuilder_delete(builder);
         return result;
     }
 
@@ -132,8 +181,6 @@
             printf("call AAudioStream_close(%p)\n", mStream);  fflush(stdout);
             AAudioStream_close(mStream);
             mStream = nullptr;
-            AAudioStreamBuilder_delete(mBuilder);
-            mBuilder = nullptr;
         }
         return AAUDIO_OK;
     }
@@ -186,7 +233,6 @@
     }
 
 private:
-    AAudioStreamBuilder      *mBuilder = nullptr;
     AAudioStream             *mStream = nullptr;
     aaudio_sharing_mode_t     mRequestedSharingMode = SHARING_MODE;
     aaudio_performance_mode_t mRequestedPerformanceMode = PERFORMANCE_MODE;
diff --git a/media/libaaudio/examples/utils/dummy.cpp b/media/libaaudio/examples/utils/dummy.cpp
new file mode 100644
index 0000000..8ef7e36
--- /dev/null
+++ b/media/libaaudio/examples/utils/dummy.cpp
@@ -0,0 +1,5 @@
+/**
+ * Dummy file needed to get Android Studio to scan this folder.
+ */
+
+int g_DoNotUseThisVariable = 0;
diff --git a/media/libaaudio/examples/write_sine/jni/Android.mk b/media/libaaudio/examples/write_sine/jni/Android.mk
index c306ed3..d630e76 100644
--- a/media/libaaudio/examples/write_sine/jni/Android.mk
+++ b/media/libaaudio/examples/write_sine/jni/Android.mk
@@ -11,7 +11,7 @@
 # NDK recommends using this kind of relative path instead of an absolute path.
 LOCAL_SRC_FILES:= ../src/write_sine.cpp
 LOCAL_SHARED_LIBRARIES := libaaudio
-LOCAL_MODULE := write_sine_ndk
+LOCAL_MODULE := write_sine
 include $(BUILD_EXECUTABLE)
 
 include $(CLEAR_VARS)
@@ -23,7 +23,7 @@
 
 LOCAL_SRC_FILES:= ../src/write_sine_callback.cpp
 LOCAL_SHARED_LIBRARIES := libaaudio
-LOCAL_MODULE := write_sine_callback_ndk
+LOCAL_MODULE := write_sine_callback
 include $(BUILD_EXECUTABLE)
 
 include $(CLEAR_VARS)
diff --git a/media/libaaudio/examples/write_sine/src/write_sine.cpp b/media/libaaudio/examples/write_sine/src/write_sine.cpp
index 6522ba4..87fb40b 100644
--- a/media/libaaudio/examples/write_sine/src/write_sine.cpp
+++ b/media/libaaudio/examples/write_sine/src/write_sine.cpp
@@ -16,46 +16,32 @@
 
 // Play sine waves using AAudio.
 
-#include <stdio.h>
-#include <stdlib.h>
-#include <math.h>
 #include <aaudio/AAudio.h>
 #include <aaudio/AAudioTesting.h>
+#include <asm/fcntl.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
 #include "AAudioExampleUtils.h"
 #include "AAudioSimplePlayer.h"
+#include "AAudioArgsParser.h"
 
-#define SAMPLE_RATE           48000
-#define NUM_SECONDS           20
+#define NUM_SECONDS           4
 
-#define MMAP_POLICY              AAUDIO_UNSPECIFIED
-//#define MMAP_POLICY              AAUDIO_POLICY_NEVER
-//#define MMAP_POLICY              AAUDIO_POLICY_AUTO
-//#define MMAP_POLICY              AAUDIO_POLICY_ALWAYS
-
-#define REQUESTED_FORMAT         AAUDIO_FORMAT_PCM_I16
-
-#define REQUESTED_SHARING_MODE   AAUDIO_SHARING_MODE_SHARED
-//#define REQUESTED_SHARING_MODE   AAUDIO_SHARING_MODE_EXCLUSIVE
-
-
-int main(int argc, char **argv)
+int main(int argc, const char **argv)
 {
-    (void)argc; // unused
-
+    AAudioArgsParser   argParser;
     AAudioSimplePlayer player;
     SineThreadedData_t myData;
-    aaudio_result_t result = AAUDIO_OK;
+    aaudio_result_t    result = AAUDIO_OK;
 
-    const int requestedChannelCount = 2;
-    int actualChannelCount = 0;
-    const int requestedSampleRate = SAMPLE_RATE;
-    int actualSampleRate = 0;
-    aaudio_format_t requestedDataFormat = REQUESTED_FORMAT;
+    int32_t         actualChannelCount = 0;
+    int32_t         actualSampleRate = 0;
     aaudio_format_t actualDataFormat = AAUDIO_FORMAT_UNSPECIFIED;
-    aaudio_sharing_mode_t actualSharingMode = AAUDIO_SHARING_MODE_SHARED;
 
     AAudioStream *aaudioStream = nullptr;
-    aaudio_stream_state_t state = AAUDIO_STREAM_STATE_UNINITIALIZED;
     int32_t  framesPerBurst = 0;
     int32_t  framesPerWrite = 0;
     int32_t  bufferCapacity = 0;
@@ -65,56 +51,38 @@
     float   *floatData = nullptr;
     int16_t *shortData = nullptr;
 
+    int      testFd = -1;
+
     // Make printf print immediately so that debug info is not stuck
     // in a buffer if we hang or crash.
     setvbuf(stdout, nullptr, _IONBF, (size_t) 0);
 
-    printf("%s - Play a sine wave using AAudio\n", argv[0]);
+    printf("%s - Play a sine wave using AAudio V0.1.1\n", argv[0]);
 
-    AAudio_setMMapPolicy(MMAP_POLICY);
-    printf("requested MMapPolicy = %d\n", AAudio_getMMapPolicy());
+    if (argParser.parseArgs(argc, argv)) {
+        return EXIT_FAILURE;
+    }
 
-    player.setSharingMode(REQUESTED_SHARING_MODE);
-
-    result = player.open(requestedChannelCount, requestedSampleRate, requestedDataFormat,
-                         nullptr, nullptr, &myData);
+    result = player.open(argParser);
     if (result != AAUDIO_OK) {
         fprintf(stderr, "ERROR -  player.open() returned %d\n", result);
         goto finish;
     }
 
     aaudioStream = player.getStream();
-    // Request stream properties.
 
-    state = AAudioStream_getState(aaudioStream);
-    printf("after open, state = %s\n", AAudio_convertStreamStateToText(state));
+    argParser.compareWithStream(aaudioStream);
 
-    // Check to see what kind of stream we actually got.
+    actualChannelCount = AAudioStream_getChannelCount(aaudioStream);
     actualSampleRate = AAudioStream_getSampleRate(aaudioStream);
-    printf("SampleRate: requested = %d, actual = %d\n", requestedSampleRate, actualSampleRate);
+    actualDataFormat = AAudioStream_getFormat(aaudioStream);
 
     myData.sineOsc1.setup(440.0, actualSampleRate);
     myData.sineOsc2.setup(660.0, actualSampleRate);
 
-    actualChannelCount = AAudioStream_getChannelCount(aaudioStream);
-    printf("ChannelCount: requested = %d, actual = %d\n",
-            requestedChannelCount, actualChannelCount);
-
-    actualSharingMode = AAudioStream_getSharingMode(aaudioStream);
-    printf("SharingMode: requested = %s, actual = %s\n",
-            getSharingModeText(REQUESTED_SHARING_MODE),
-            getSharingModeText(actualSharingMode));
-
-    // This is the number of frames that are read in one chunk by a DMA controller
-    // or a DSP or a mixer.
-    framesPerBurst = AAudioStream_getFramesPerBurst(aaudioStream);
-    printf("Buffer: bufferSize     = %d\n", AAudioStream_getBufferSizeInFrames(aaudioStream));
-    bufferCapacity = AAudioStream_getBufferCapacityInFrames(aaudioStream);
-    printf("Buffer: bufferCapacity = %d, remainder = %d\n",
-           bufferCapacity, bufferCapacity % framesPerBurst);
-
     // Some DMA might use very short bursts of 16 frames. We don't need to write such small
     // buffers. But it helps to use a multiple of the burst size for predictable scheduling.
+    framesPerBurst = AAudioStream_getFramesPerBurst(aaudioStream);
     framesPerWrite = framesPerBurst;
     while (framesPerWrite < 48) {
         framesPerWrite *= 2;
@@ -122,13 +90,6 @@
     printf("Buffer: framesPerBurst = %d\n",framesPerBurst);
     printf("Buffer: framesPerWrite = %d\n",framesPerWrite);
 
-    printf("PerformanceMode        = %d\n", AAudioStream_getPerformanceMode(aaudioStream));
-    printf("is MMAP used?          = %s\n", AAudioStream_isMMapUsed(aaudioStream) ? "yes" : "no");
-
-    actualDataFormat = AAudioStream_getFormat(aaudioStream);
-    printf("DataFormat: requested  = %d, actual = %d\n", REQUESTED_FORMAT, actualDataFormat);
-    // TODO handle other data formats
-
     // Allocate a buffer for the audio data.
     if (actualDataFormat == AAUDIO_FORMAT_PCM_FLOAT) {
         floatData = new float[framesPerWrite * actualChannelCount];
@@ -139,6 +100,9 @@
         goto finish;
     }
 
+    testFd = open("/data/aaudio_temp.raw", O_CREAT | O_RDWR, S_IRWXU);
+    printf("testFd = %d, pid = %d\n", testFd, getpid());
+
     // Start the stream.
     printf("call player.start()\n");
     result = player.start();
@@ -147,11 +111,11 @@
         goto finish;
     }
 
-    state = AAudioStream_getState(aaudioStream);
-    printf("after start, state = %s\n", AAudio_convertStreamStateToText(state));
+    printf("after start, state = %s\n",
+            AAudio_convertStreamStateToText(AAudioStream_getState(aaudioStream)));
 
     // Play for a while.
-    framesToPlay = actualSampleRate * NUM_SECONDS;
+    framesToPlay = actualSampleRate * argParser.getDurationSeconds();
     framesLeft = framesToPlay;
     while (framesLeft > 0) {
 
@@ -220,7 +184,17 @@
     }
 
 finish:
+    printf("testFd = %d, fcntl before aaudio close returns 0x%08X\n",
+           testFd, fcntl(testFd, F_GETFD));
     player.close();
+    printf("testFd = %d, fcntl after aaudio close returns 0x%08X\n",
+           testFd, fcntl(testFd, F_GETFD));
+    if (::close(testFd) != 0) {
+        printf("ERROR SharedMemoryParcelable::close() of testFd = %d, errno = %s\n",
+               testFd, strerror(errno));
+    }
+    printf("testFd = %d, fcntl after close() returns 0x%08X\n", testFd, fcntl(testFd, F_GETFD));
+
     delete[] floatData;
     delete[] shortData;
     printf("exiting - AAudio result = %d = %s\n", result, AAudio_convertResultToText(result));
diff --git a/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp b/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp
index 69145aa..b5602e9 100644
--- a/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp
+++ b/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp
@@ -26,37 +26,42 @@
 #include <aaudio/AAudio.h>
 #include "AAudioExampleUtils.h"
 #include "AAudioSimplePlayer.h"
+#include "../../utils/AAudioSimplePlayer.h"
 
-#define NUM_SECONDS              5
-
-// Application data that gets passed to the callback.
-#define MAX_FRAME_COUNT_RECORDS    256
-
-int main(int argc, char **argv)
+int main(int argc, const char **argv)
 {
-    (void)argc; // unused
+    AAudioArgsParser   argParser;
     AAudioSimplePlayer player;
     SineThreadedData_t myData;
     aaudio_result_t result;
+    int32_t actualSampleRate;
 
     // Make printf print immediately so that debug info is not stuck
     // in a buffer if we hang or crash.
     setvbuf(stdout, nullptr, _IONBF, (size_t) 0);
-    printf("%s - Play a sine sweep using an AAudio callback\n", argv[0]);
+
+    printf("%s - Play a sine sweep using an AAudio callback V0.1.2\n", argv[0]);
 
     myData.schedulerChecked = false;
+    myData.forceUnderruns = false; // set true to test AAudioStream_getXRunCount()
 
-    result = player.open(2, 44100, AAUDIO_FORMAT_PCM_FLOAT,
+    if (argParser.parseArgs(argc, argv)) {
+        return EXIT_FAILURE;
+    }
+
+    result = player.open(argParser,
                          SimplePlayerDataCallbackProc, SimplePlayerErrorCallbackProc, &myData);
     if (result != AAUDIO_OK) {
         fprintf(stderr, "ERROR -  player.open() returned %d\n", result);
         goto error;
     }
-    printf("player.getFramesPerSecond() = %d\n", player.getFramesPerSecond());
-    printf("player.getChannelCount() = %d\n", player.getChannelCount());
-    myData.sineOsc1.setup(440.0, 48000);
+
+    argParser.compareWithStream(player.getStream());
+
+    actualSampleRate = player.getSampleRate();
+    myData.sineOsc1.setup(440.0, actualSampleRate);
     myData.sineOsc1.setSweep(300.0, 600.0, 5.0);
-    myData.sineOsc2.setup(660.0, 48000);
+    myData.sineOsc2.setup(660.0, actualSampleRate);
     myData.sineOsc2.setSweep(350.0, 900.0, 7.0);
 
 #if 0
@@ -73,8 +78,9 @@
         goto error;
     }
 
-    printf("Sleep for %d seconds while audio plays in a callback thread.\n", NUM_SECONDS);
-    for (int second = 0; second < NUM_SECONDS; second++)
+    printf("Sleep for %d seconds while audio plays in a callback thread.\n",
+           argParser.getDurationSeconds());
+    for (int second = 0; second < argParser.getDurationSeconds(); second++)
     {
         const struct timespec request = { .tv_sec = 1, .tv_nsec = 0 };
         (void) clock_nanosleep(CLOCK_MONOTONIC, 0 /*flags*/, &request, NULL /*remain*/);
@@ -92,7 +98,10 @@
             printf("Stream state is %d %s!\n", state, AAudio_convertStreamStateToText(state));
             break;
         }
-        printf("framesWritten = %d\n", (int) AAudioStream_getFramesWritten(player.getStream()));
+        printf("framesWritten = %d, underruns = %d\n",
+               (int) AAudioStream_getFramesWritten(player.getStream()),
+               (int) AAudioStream_getXRunCount(player.getStream())
+        );
     }
     printf("Woke up now.\n");
 
@@ -113,6 +122,9 @@
                SCHED_FIFO);
     }
 
+    printf("min numFrames = %8d\n", (int) myData.minNumFrames);
+    printf("max numFrames = %8d\n", (int) myData.maxNumFrames);
+
     printf("SUCCESS\n");
     return EXIT_SUCCESS;
 error:
diff --git a/media/libaaudio/examples/write_sine/static/Android.mk b/media/libaaudio/examples/write_sine/static/Android.mk
deleted file mode 100644
index 40dca34..0000000
--- a/media/libaaudio/examples/write_sine/static/Android.mk
+++ /dev/null
@@ -1,38 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE_TAGS := examples
-LOCAL_C_INCLUDES := \
-    $(call include-path-for, audio-utils) \
-    frameworks/av/media/libaaudio/src \
-    frameworks/av/media/libaaudio/include \
-    frameworks/av/media/libaaudio/examples/utils
-
-# NDK recommends using this kind of relative path instead of an absolute path.
-LOCAL_SRC_FILES:= ../src/write_sine.cpp
-
-LOCAL_SHARED_LIBRARIES := libaudioutils libmedia \
-                          libbinder libcutils libutils \
-                          libaudioclient liblog libtinyalsa libaudiomanager
-LOCAL_STATIC_LIBRARIES := libaaudio
-
-LOCAL_MODULE := write_sine
-include $(BUILD_EXECUTABLE)
-
-
-include $(CLEAR_VARS)
-LOCAL_MODULE_TAGS := tests
-LOCAL_C_INCLUDES := \
-    $(call include-path-for, audio-utils) \
-    frameworks/av/media/libaaudio/include \
-    frameworks/av/media/libaaudio/examples/utils
-
-LOCAL_SRC_FILES:= ../src/write_sine_callback.cpp
-
-LOCAL_SHARED_LIBRARIES := libaudioutils libmedia \
-                          libbinder libcutils libutils \
-                          libaudioclient liblog libaudiomanager
-LOCAL_STATIC_LIBRARIES := libaaudio
-
-LOCAL_MODULE := write_sine_callback
-include $(BUILD_EXECUTABLE)
diff --git a/media/libaaudio/examples/write_sine/static/README.md b/media/libaaudio/examples/write_sine/static/README.md
deleted file mode 100644
index 6e26d7b..0000000
--- a/media/libaaudio/examples/write_sine/static/README.md
+++ /dev/null
@@ -1,2 +0,0 @@
-Makefile for building simple command line examples.
-They link with AAudio as a static library.
diff --git a/media/libaaudio/src/Android.mk b/media/libaaudio/src/Android.mk
index 28c4d7f..cfcf27a 100644
--- a/media/libaaudio/src/Android.mk
+++ b/media/libaaudio/src/Android.mk
@@ -32,6 +32,7 @@
     core/AudioStream.cpp \
     core/AudioStreamBuilder.cpp \
     core/AAudioAudio.cpp \
+    core/AAudioStreamParameters.cpp \
     legacy/AudioStreamLegacy.cpp \
     legacy/AudioStreamRecord.cpp \
     legacy/AudioStreamTrack.cpp \
@@ -52,6 +53,7 @@
     binding/AAudioBinderClient.cpp \
     binding/AAudioStreamRequest.cpp \
     binding/AAudioStreamConfiguration.cpp \
+    binding/IAAudioClient.cpp \
     binding/IAAudioService.cpp \
     binding/RingBufferParcelable.cpp \
     binding/SharedMemoryParcelable.cpp \
@@ -89,6 +91,7 @@
 LOCAL_SRC_FILES = core/AudioStream.cpp \
     core/AudioStreamBuilder.cpp \
     core/AAudioAudio.cpp \
+    core/AAudioStreamParameters.cpp \
     legacy/AudioStreamLegacy.cpp \
     legacy/AudioStreamRecord.cpp \
     legacy/AudioStreamTrack.cpp \
@@ -109,6 +112,7 @@
     binding/AAudioBinderClient.cpp \
     binding/AAudioStreamRequest.cpp \
     binding/AAudioStreamConfiguration.cpp \
+    binding/IAAudioClient.cpp \
     binding/IAAudioService.cpp \
     binding/RingBufferParcelable.cpp \
     binding/SharedMemoryParcelable.cpp \
diff --git a/media/libaaudio/src/binding/AAudioBinderClient.cpp b/media/libaaudio/src/binding/AAudioBinderClient.cpp
index 435b30f..a268e49 100644
--- a/media/libaaudio/src/binding/AAudioBinderClient.cpp
+++ b/media/libaaudio/src/binding/AAudioBinderClient.cpp
@@ -19,75 +19,104 @@
 //#define LOG_NDEBUG 0
 #include <utils/Log.h>
 
+#include <binder/IInterface.h>
 #include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
 #include <utils/Mutex.h>
 #include <utils/RefBase.h>
 #include <utils/Singleton.h>
+#include <media/AudioSystem.h>
 
 #include <aaudio/AAudio.h>
 
 #include "AudioEndpointParcelable.h"
-#include "binding/AAudioStreamRequest.h"
-#include "binding/AAudioStreamConfiguration.h"
-#include "binding/IAAudioService.h"
-#include "binding/AAudioServiceMessage.h"
+#include "binding/AAudioBinderClient.h"
+//#include "binding/AAudioStreamRequest.h"
+//#include "binding/AAudioStreamConfiguration.h"
+//#include "binding/IAAudioService.h"
+//#include "binding/AAudioServiceMessage.h"
 
-#include "AAudioBinderClient.h"
-#include "AAudioServiceInterface.h"
+//#include "AAudioServiceInterface.h"
 
 using android::String16;
 using android::IServiceManager;
 using android::defaultServiceManager;
 using android::interface_cast;
+using android::IInterface;
 using android::IAAudioService;
 using android::Mutex;
 using android::sp;
+using android::wp;
 
 using namespace aaudio;
 
-static android::Mutex gServiceLock;
-static sp<IAAudioService>  gAAudioService;
-
 ANDROID_SINGLETON_STATIC_INSTANCE(AAudioBinderClient);
 
+AAudioBinderClient::AAudioBinderClient()
+        : AAudioServiceInterface()
+        , Singleton<AAudioBinderClient>() {
+
+    mAAudioClient = new AAudioClient(this);
+    ALOGV("AAudioBinderClient() created mAAudioClient = %p", mAAudioClient.get());
+}
+
+AAudioBinderClient::~AAudioBinderClient() {
+    Mutex::Autolock _l(mServiceLock);
+    if (mAAudioService != 0) {
+        IInterface::asBinder(mAAudioService)->unlinkToDeath(mAAudioClient);
+    }
+}
+
 // TODO Share code with other service clients.
 // Helper function to get access to the "AAudioService" service.
 // This code was modeled after frameworks/av/media/libaudioclient/AudioSystem.cpp
-static const sp<IAAudioService> getAAudioService() {
-    sp<IBinder> binder;
-    Mutex::Autolock _l(gServiceLock);
-    if (gAAudioService == 0) {
-        sp<IServiceManager> sm = defaultServiceManager();
-        // Try several times to get the service.
-        int retries = 4;
-        do {
-            binder = sm->getService(String16(AAUDIO_SERVICE_NAME)); // This will wait a while.
+const sp<IAAudioService> AAudioBinderClient::getAAudioService() {
+    sp<IAAudioService> aaudioService;
+    bool needToRegister = false;
+    {
+        Mutex::Autolock _l(mServiceLock);
+        if (mAAudioService == 0) {
+            sp<IBinder> binder;
+            sp<IServiceManager> sm = defaultServiceManager();
+            // Try several times to get the service.
+            int retries = 4;
+            do {
+                binder = sm->getService(String16(AAUDIO_SERVICE_NAME)); // This will wait a while.
+                if (binder != 0) {
+                    break;
+                }
+            } while (retries-- > 0);
+
             if (binder != 0) {
-                break;
+                // Ask for notification if the service dies.
+                status_t status = binder->linkToDeath(mAAudioClient);
+                // TODO review what we should do if this fails
+                if (status != NO_ERROR) {
+                    ALOGE("getAAudioService: linkToDeath(mAAudioClient = %p) returned %d",
+                          mAAudioClient.get(), status);
+                }
+                mAAudioService = interface_cast<IAAudioService>(binder);
+                needToRegister = true;
+                // Make sure callbacks can be received by mAAudioClient
+                android::ProcessState::self()->startThreadPool();
+            } else {
+                ALOGE("AAudioBinderClient could not connect to %s", AAUDIO_SERVICE_NAME);
             }
-        } while (retries-- > 0);
-
-        if (binder != 0) {
-            // TODO Add linkToDeath() like in frameworks/av/media/libaudioclient/AudioSystem.cpp
-            // TODO Create a DeathRecipient that disconnects all active streams.
-            gAAudioService = interface_cast<IAAudioService>(binder);
-        } else {
-            ALOGE("AudioStreamInternal could not get %s", AAUDIO_SERVICE_NAME);
         }
+        aaudioService = mAAudioService;
     }
-    return gAAudioService;
+    // Do this outside the mutex lock.
+    if (needToRegister && aaudioService != 0) { // new client?
+        aaudioService->registerClient(mAAudioClient);
+    }
+    return aaudioService;
 }
 
-static void dropAAudioService() {
-    Mutex::Autolock _l(gServiceLock);
-    gAAudioService.clear(); // force a reconnect
+void AAudioBinderClient::dropAAudioService() {
+    Mutex::Autolock _l(mServiceLock);
+    mAAudioService.clear(); // force a reconnect
 }
 
-AAudioBinderClient::AAudioBinderClient()
-        : AAudioServiceInterface()
-        , Singleton<AAudioBinderClient>() {}
-
-AAudioBinderClient::~AAudioBinderClient() {}
 
 /**
 * @param request info needed to create the stream
@@ -159,23 +188,19 @@
 * Manage the specified thread as a low latency audio thread.
 */
 aaudio_result_t AAudioBinderClient::registerAudioThread(aaudio_handle_t streamHandle,
-                                                        pid_t clientProcessId,
                                                         pid_t clientThreadId,
                                                         int64_t periodNanoseconds) {
     const sp<IAAudioService> &service = getAAudioService();
     if (service == 0) return AAUDIO_ERROR_NO_SERVICE;
     return service->registerAudioThread(streamHandle,
-                                        clientProcessId,
                                         clientThreadId,
                                         periodNanoseconds);
 }
 
 aaudio_result_t AAudioBinderClient::unregisterAudioThread(aaudio_handle_t streamHandle,
-                                                          pid_t clientProcessId,
                                                           pid_t clientThreadId) {
     const sp<IAAudioService> &service = getAAudioService();
     if (service == 0) return AAUDIO_ERROR_NO_SERVICE;
     return service->unregisterAudioThread(streamHandle,
-                                          clientProcessId,
                                           clientThreadId);
 }
diff --git a/media/libaaudio/src/binding/AAudioBinderClient.h b/media/libaaudio/src/binding/AAudioBinderClient.h
index e223376..89ae85c 100644
--- a/media/libaaudio/src/binding/AAudioBinderClient.h
+++ b/media/libaaudio/src/binding/AAudioBinderClient.h
@@ -17,6 +17,7 @@
 #ifndef ANDROID_AAUDIO_AAUDIO_BINDER_CLIENT_H
 #define ANDROID_AAUDIO_AAUDIO_BINDER_CLIENT_H
 
+#include <utils/RefBase.h>
 #include <utils/Singleton.h>
 
 #include <aaudio/AAudio.h>
@@ -25,14 +26,16 @@
 #include "binding/AAudioStreamRequest.h"
 #include "binding/AAudioStreamConfiguration.h"
 #include "binding/AudioEndpointParcelable.h"
+#include "binding/IAAudioService.h"
 
 /**
- * Implements the AAudioServiceInterface by talking to the actual service through Binder.
+ * Implements the AAudioServiceInterface by talking to the service through Binder.
  */
 
 namespace aaudio {
 
-class AAudioBinderClient : public AAudioServiceInterface
+class AAudioBinderClient : public virtual android::RefBase
+        , public AAudioServiceInterface
         , public android::Singleton<AAudioBinderClient> {
 
 public:
@@ -41,6 +44,12 @@
 
     virtual ~AAudioBinderClient();
 
+    const android::sp<android::IAAudioService> getAAudioService();
+
+    void dropAAudioService();
+
+    void registerClient(const android::sp<android::IAAudioClient>& client __unused) override {}
+
     /**
      * @param request info needed to create the stream
      * @param configuration contains resulting information about the created stream
@@ -82,13 +91,61 @@
      * TODO Consider passing this information as part of the startStream() call.
      */
     aaudio_result_t registerAudioThread(aaudio_handle_t streamHandle,
-                                                pid_t clientProcessId,
                                                 pid_t clientThreadId,
                                                 int64_t periodNanoseconds) override;
 
     aaudio_result_t unregisterAudioThread(aaudio_handle_t streamHandle,
-                                                  pid_t clientProcessId,
                                                   pid_t clientThreadId) override;
+
+    aaudio_result_t startClient(aaudio_handle_t streamHandle __unused,
+                                      const android::AudioClient& client __unused,
+                                      audio_port_handle_t *clientHandle) override {
+        return AAUDIO_ERROR_UNAVAILABLE;
+    }
+
+    aaudio_result_t stopClient(aaudio_handle_t streamHandle __unused,
+                               audio_port_handle_t clientHandle __unused)  override {
+        return AAUDIO_ERROR_UNAVAILABLE;
+    }
+
+    void onStreamChange(aaudio_handle_t handle, int32_t opcode, int32_t value) {
+        // TODO This is just a stub so we can have a client Binder to pass to the service.
+        // TODO Implemented in a later CL.
+        ALOGW("onStreamChange called!");
+    }
+
+    class AAudioClient : public android::IBinder::DeathRecipient , public android::BnAAudioClient
+    {
+    public:
+        AAudioClient(android::wp<AAudioBinderClient> aaudioBinderClient)
+            : mBinderClient(aaudioBinderClient) {
+        }
+
+        // implement DeathRecipient
+        virtual void binderDied(const android::wp<android::IBinder>& who __unused) {
+            android::sp<AAudioBinderClient> client = mBinderClient.promote();
+            if (client != 0) {
+                client->dropAAudioService();
+            }
+            ALOGW("AAudio service binderDied()!");
+        }
+
+        // implement BnAAudioClient
+        void onStreamChange(aaudio_handle_t handle, int32_t opcode, int32_t value) {
+            android::sp<AAudioBinderClient> client = mBinderClient.promote();
+            if (client != 0) {
+                client->onStreamChange(handle, opcode, value);
+            }
+        }
+    private:
+        android::wp<AAudioBinderClient> mBinderClient;
+    };
+
+
+    android::Mutex               mServiceLock;
+    android::sp<android::IAAudioService>  mAAudioService;
+    android::sp<AAudioClient>    mAAudioClient;
+
 };
 
 
diff --git a/media/libaaudio/src/binding/AAudioServiceDefinitions.h b/media/libaaudio/src/binding/AAudioServiceDefinitions.h
index 638544e..8a2303c 100644
--- a/media/libaaudio/src/binding/AAudioServiceDefinitions.h
+++ b/media/libaaudio/src/binding/AAudioServiceDefinitions.h
@@ -29,8 +29,9 @@
 
 namespace android {
 
-enum aaudio_commands_t {
-    OPEN_STREAM = IBinder::FIRST_CALL_TRANSACTION,
+enum aaudio_service_commands_t {
+    REGISTER_CLIENT = IBinder::FIRST_CALL_TRANSACTION,
+    OPEN_STREAM,
     CLOSE_STREAM,
     GET_STREAM_DESCRIPTION,
     START_STREAM,
@@ -41,6 +42,10 @@
     UNREGISTER_AUDIO_THREAD
 };
 
+enum aaudio_client_commands_t {
+    ON_STREAM_CHANGE = IBinder::FIRST_CALL_TRANSACTION
+};
+
 } // namespace android
 
 namespace aaudio {
diff --git a/media/libaaudio/src/binding/AAudioServiceInterface.h b/media/libaaudio/src/binding/AAudioServiceInterface.h
index 824e5bc..a64405b 100644
--- a/media/libaaudio/src/binding/AAudioServiceInterface.h
+++ b/media/libaaudio/src/binding/AAudioServiceInterface.h
@@ -17,10 +17,14 @@
 #ifndef ANDROID_AAUDIO_BINDING_AAUDIO_SERVICE_INTERFACE_H
 #define ANDROID_AAUDIO_BINDING_AAUDIO_SERVICE_INTERFACE_H
 
+#include <utils/StrongPointer.h>
+#include <media/AudioClient.h>
+
 #include "binding/AAudioServiceDefinitions.h"
 #include "binding/AAudioStreamRequest.h"
 #include "binding/AAudioStreamConfiguration.h"
 #include "binding/AudioEndpointParcelable.h"
+#include "binding/IAAudioClient.h"
 
 /**
  * This has the same methods as IAAudioService but without the Binder features.
@@ -36,6 +40,8 @@
     AAudioServiceInterface() {};
     virtual ~AAudioServiceInterface() = default;
 
+    virtual void registerClient(const android::sp<android::IAAudioClient>& client) = 0;
+
     /**
      * @param request info needed to create the stream
      * @param configuration contains information about the created stream
@@ -76,13 +82,18 @@
      * Manage the specified thread as a low latency audio thread.
      */
     virtual aaudio_result_t registerAudioThread(aaudio_handle_t streamHandle,
-                                                pid_t clientProcessId,
                                                 pid_t clientThreadId,
                                                 int64_t periodNanoseconds) = 0;
 
     virtual aaudio_result_t unregisterAudioThread(aaudio_handle_t streamHandle,
-                                                  pid_t clientProcessId,
                                                   pid_t clientThreadId) = 0;
+
+    virtual aaudio_result_t startClient(aaudio_handle_t streamHandle,
+                                      const android::AudioClient& client,
+                                      audio_port_handle_t *clientHandle) = 0;
+
+    virtual aaudio_result_t stopClient(aaudio_handle_t streamHandle,
+                                       audio_port_handle_t clientHandle) = 0;
 };
 
 } /* namespace aaudio */
diff --git a/media/libaaudio/src/binding/AAudioStreamConfiguration.cpp b/media/libaaudio/src/binding/AAudioStreamConfiguration.cpp
index 44edb1d..e763934 100644
--- a/media/libaaudio/src/binding/AAudioStreamConfiguration.cpp
+++ b/media/libaaudio/src/binding/AAudioStreamConfiguration.cpp
@@ -36,17 +36,17 @@
 
 status_t AAudioStreamConfiguration::writeToParcel(Parcel* parcel) const {
     status_t status;
-    status = parcel->writeInt32(mDeviceId);
+    status = parcel->writeInt32(getDeviceId());
     if (status != NO_ERROR) goto error;
-    status = parcel->writeInt32(mSampleRate);
+    status = parcel->writeInt32(getSampleRate());
     if (status != NO_ERROR) goto error;
-    status = parcel->writeInt32(mSamplesPerFrame);
+    status = parcel->writeInt32(getSamplesPerFrame());
     if (status != NO_ERROR) goto error;
-    status = parcel->writeInt32((int32_t) mSharingMode);
+    status = parcel->writeInt32((int32_t) getSharingMode());
     if (status != NO_ERROR) goto error;
-    status = parcel->writeInt32((int32_t) mAudioFormat);
+    status = parcel->writeInt32((int32_t) getFormat());
     if (status != NO_ERROR) goto error;
-    status = parcel->writeInt32(mBufferCapacity);
+    status = parcel->writeInt32(getBufferCapacity());
     if (status != NO_ERROR) goto error;
     return NO_ERROR;
 error:
@@ -55,57 +55,27 @@
 }
 
 status_t AAudioStreamConfiguration::readFromParcel(const Parcel* parcel) {
-    status_t status = parcel->readInt32(&mDeviceId);
+    int32_t value;
+    status_t status = parcel->readInt32(&value);
     if (status != NO_ERROR) goto error;
-    status = parcel->readInt32(&mSampleRate);
+    setDeviceId(value);
+    status = parcel->readInt32(&value);
     if (status != NO_ERROR) goto error;
-    status = parcel->readInt32(&mSamplesPerFrame);
+    setSampleRate(value);
+    status = parcel->readInt32(&value);
     if (status != NO_ERROR) goto error;
-    status = parcel->readInt32(&mSharingMode);
+    setSamplesPerFrame(value);
+    status = parcel->readInt32(&value);
     if (status != NO_ERROR) goto error;
-    status = parcel->readInt32(&mAudioFormat);
+    setSharingMode(value);
+    status = parcel->readInt32(&value);
     if (status != NO_ERROR) goto error;
-    status = parcel->readInt32(&mBufferCapacity);
+    setFormat(value);
+    status = parcel->readInt32(&value);
     if (status != NO_ERROR) goto error;
+    setBufferCapacity(value);
     return NO_ERROR;
 error:
     ALOGE("AAudioStreamConfiguration.readFromParcel(): read failed = %d", status);
     return status;
-}
-
-aaudio_result_t AAudioStreamConfiguration::validate() const {
-    // Validate results of the open.
-    if (mSampleRate < 0 || mSampleRate >= 8 * 48000) { // TODO review limits
-        ALOGE("AAudioStreamConfiguration.validate(): invalid sampleRate = %d", mSampleRate);
-        return AAUDIO_ERROR_INTERNAL;
-    }
-
-    if (mSamplesPerFrame < 1 || mSamplesPerFrame >= 32) { // TODO review limits
-        ALOGE("AAudioStreamConfiguration.validate() invalid samplesPerFrame = %d", mSamplesPerFrame);
-        return AAUDIO_ERROR_INTERNAL;
-    }
-
-    switch (mAudioFormat) {
-    case AAUDIO_FORMAT_PCM_I16:
-    case AAUDIO_FORMAT_PCM_FLOAT:
-        break;
-    default:
-        ALOGE("AAudioStreamConfiguration.validate() invalid audioFormat = %d", mAudioFormat);
-        return AAUDIO_ERROR_INTERNAL;
-    }
-
-    if (mBufferCapacity < 0) {
-        ALOGE("AAudioStreamConfiguration.validate() invalid mBufferCapacity = %d", mBufferCapacity);
-        return AAUDIO_ERROR_INTERNAL;
-    }
-    return AAUDIO_OK;
-}
-
-void AAudioStreamConfiguration::dump() const {
-    ALOGD("AAudioStreamConfiguration mDeviceId        = %d", mDeviceId);
-    ALOGD("AAudioStreamConfiguration mSampleRate      = %d", mSampleRate);
-    ALOGD("AAudioStreamConfiguration mSamplesPerFrame = %d", mSamplesPerFrame);
-    ALOGD("AAudioStreamConfiguration mSharingMode     = %d", (int)mSharingMode);
-    ALOGD("AAudioStreamConfiguration mAudioFormat     = %d", (int)mAudioFormat);
-    ALOGD("AAudioStreamConfiguration mBufferCapacity  = %d", mBufferCapacity);
-}
+}
\ No newline at end of file
diff --git a/media/libaaudio/src/binding/AAudioStreamConfiguration.h b/media/libaaudio/src/binding/AAudioStreamConfiguration.h
index 144595a..b324896 100644
--- a/media/libaaudio/src/binding/AAudioStreamConfiguration.h
+++ b/media/libaaudio/src/binding/AAudioStreamConfiguration.h
@@ -22,6 +22,7 @@
 #include <aaudio/AAudio.h>
 #include <binder/Parcel.h>
 #include <binder/Parcelable.h>
+#include "core/AAudioStreamParameters.h"
 
 using android::status_t;
 using android::Parcel;
@@ -29,74 +30,14 @@
 
 namespace aaudio {
 
-class AAudioStreamConfiguration : public Parcelable {
+class AAudioStreamConfiguration : public AAudioStreamParameters, public Parcelable {
 public:
     AAudioStreamConfiguration();
     virtual ~AAudioStreamConfiguration();
 
-    int32_t getDeviceId() const {
-        return mDeviceId;
-    }
-
-    void setDeviceId(int32_t deviceId) {
-        mDeviceId = deviceId;
-    }
-
-    int32_t getSampleRate() const {
-        return mSampleRate;
-    }
-
-    void setSampleRate(int32_t sampleRate) {
-        mSampleRate = sampleRate;
-    }
-
-    int32_t getSamplesPerFrame() const {
-        return mSamplesPerFrame;
-    }
-
-    void setSamplesPerFrame(int32_t samplesPerFrame) {
-        mSamplesPerFrame = samplesPerFrame;
-    }
-
-    aaudio_format_t getAudioFormat() const {
-        return mAudioFormat;
-    }
-
-    void setAudioFormat(aaudio_format_t audioFormat) {
-        mAudioFormat = audioFormat;
-    }
-
-    aaudio_sharing_mode_t getSharingMode() const {
-        return mSharingMode;
-    }
-
-    void setSharingMode(aaudio_sharing_mode_t sharingMode) {
-        mSharingMode = sharingMode;
-    }
-
-    int32_t getBufferCapacity() const {
-        return mBufferCapacity;
-    }
-
-    void setBufferCapacity(int32_t frames) {
-        mBufferCapacity = frames;
-    }
-
     virtual status_t writeToParcel(Parcel* parcel) const override;
 
     virtual status_t readFromParcel(const Parcel* parcel) override;
-
-    aaudio_result_t validate() const;
-
-    void dump() const;
-
-private:
-    int32_t               mDeviceId        = AAUDIO_UNSPECIFIED;
-    int32_t               mSampleRate      = AAUDIO_UNSPECIFIED;
-    int32_t               mSamplesPerFrame = AAUDIO_UNSPECIFIED;
-    aaudio_sharing_mode_t mSharingMode     = AAUDIO_SHARING_MODE_SHARED;
-    aaudio_format_t       mAudioFormat     = AAUDIO_FORMAT_UNSPECIFIED;
-    int32_t               mBufferCapacity  = AAUDIO_UNSPECIFIED;
 };
 
 } /* namespace aaudio */
diff --git a/media/libaaudio/src/binding/AAudioStreamRequest.cpp b/media/libaaudio/src/binding/AAudioStreamRequest.cpp
index a5c27b9..abdcf5b 100644
--- a/media/libaaudio/src/binding/AAudioStreamRequest.cpp
+++ b/media/libaaudio/src/binding/AAudioStreamRequest.cpp
@@ -45,16 +45,19 @@
 status_t AAudioStreamRequest::writeToParcel(Parcel* parcel) const {
     status_t status = parcel->writeInt32((int32_t) mUserId);
     if (status != NO_ERROR) goto error;
-    status = parcel->writeInt32((int32_t) mProcessId);
-    if (status != NO_ERROR) goto error;
+
     status = parcel->writeInt32((int32_t) mDirection);
     if (status != NO_ERROR) goto error;
 
     status = parcel->writeBool(mSharingModeMatchRequired);
     if (status != NO_ERROR) goto error;
 
+    status = parcel->writeBool(mInService);
+    if (status != NO_ERROR) goto error;
+
     status = mConfiguration.writeToParcel(parcel);
     if (status != NO_ERROR) goto error;
+
     return NO_ERROR;
 
 error:
@@ -70,17 +73,17 @@
 
     status = parcel->readInt32(&temp);
     if (status != NO_ERROR) goto error;
-    mProcessId = (pid_t) temp;
-
-    status = parcel->readInt32(&temp);
-    if (status != NO_ERROR) goto error;
     mDirection = (aaudio_direction_t) temp;
 
     status = parcel->readBool(&mSharingModeMatchRequired);
     if (status != NO_ERROR) goto error;
 
+    status = parcel->readBool(&mInService);
+    if (status != NO_ERROR) goto error;
+
     status = mConfiguration.readFromParcel(parcel);
     if (status != NO_ERROR) goto error;
+
     return NO_ERROR;
 
 error:
@@ -96,5 +99,7 @@
     ALOGD("AAudioStreamRequest mUserId    = %d", mUserId);
     ALOGD("AAudioStreamRequest mProcessId = %d", mProcessId);
     ALOGD("AAudioStreamRequest mDirection = %d", mDirection);
+    ALOGD("AAudioStreamRequest mSharingModeMatchRequired = %d", mSharingModeMatchRequired);
+    ALOGD("AAudioStreamRequest mInService = %d", mInService);
     mConfiguration.dump();
 }
diff --git a/media/libaaudio/src/binding/AAudioStreamRequest.h b/media/libaaudio/src/binding/AAudioStreamRequest.h
index 77138da..b0fa96a 100644
--- a/media/libaaudio/src/binding/AAudioStreamRequest.h
+++ b/media/libaaudio/src/binding/AAudioStreamRequest.h
@@ -68,7 +68,6 @@
         mSharingModeMatchRequired = required;
     }
 
-
     const AAudioStreamConfiguration &getConstantConfiguration() const {
         return mConfiguration;
     }
@@ -77,6 +76,14 @@
         return mConfiguration;
     }
 
+    bool isInService() const {
+        return mInService;
+    }
+
+    void setInService(bool inService) {
+        mInService = inService;
+    }
+
     virtual status_t writeToParcel(Parcel* parcel) const override;
 
     virtual status_t readFromParcel(const Parcel* parcel) override;
@@ -91,6 +98,7 @@
     pid_t                      mProcessId;
     aaudio_direction_t         mDirection;
     bool                       mSharingModeMatchRequired = false;
+    bool                       mInService = false; // Stream opened by AAudioservice
 };
 
 } /* namespace aaudio */
diff --git a/media/libaaudio/src/binding/AudioEndpointParcelable.cpp b/media/libaaudio/src/binding/AudioEndpointParcelable.cpp
index d05abb0..1a97555 100644
--- a/media/libaaudio/src/binding/AudioEndpointParcelable.cpp
+++ b/media/libaaudio/src/binding/AudioEndpointParcelable.cpp
@@ -28,6 +28,7 @@
 #include "binding/RingBufferParcelable.h"
 #include "binding/AudioEndpointParcelable.h"
 
+using android::base::unique_fd;
 using android::NO_ERROR;
 using android::status_t;
 using android::Parcel;
@@ -49,7 +50,8 @@
  * Add the file descriptor to the table.
  * @return index in table or negative error
  */
-int32_t AudioEndpointParcelable::addFileDescriptor(int fd, int32_t sizeInBytes) {
+int32_t AudioEndpointParcelable::addFileDescriptor(const unique_fd& fd,
+                                                   int32_t sizeInBytes) {
     if (mNumSharedMemories >= MAX_SHARED_MEMORIES) {
         return AAUDIO_ERROR_OUT_OF_RANGE;
     }
diff --git a/media/libaaudio/src/binding/AudioEndpointParcelable.h b/media/libaaudio/src/binding/AudioEndpointParcelable.h
index 993075c..aa8573f 100644
--- a/media/libaaudio/src/binding/AudioEndpointParcelable.h
+++ b/media/libaaudio/src/binding/AudioEndpointParcelable.h
@@ -20,6 +20,7 @@
 #include <stdint.h>
 
 //#include <sys/mman.h>
+#include <android-base/unique_fd.h>
 #include <binder/Parcel.h>
 #include <binder/Parcelable.h>
 
@@ -47,7 +48,7 @@
      * Add the file descriptor to the table.
      * @return index in table or negative error
      */
-    int32_t addFileDescriptor(int fd, int32_t sizeInBytes);
+    int32_t addFileDescriptor(const android::base::unique_fd& fd, int32_t sizeInBytes);
 
     virtual status_t writeToParcel(Parcel* parcel) const override;
 
diff --git a/media/libaaudio/src/binding/IAAudioClient.cpp b/media/libaaudio/src/binding/IAAudioClient.cpp
new file mode 100644
index 0000000..c69c4e8
--- /dev/null
+++ b/media/libaaudio/src/binding/IAAudioClient.cpp
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AAudio"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include <aaudio/AAudio.h>
+
+#include "binding/AAudioBinderClient.h"
+#include "binding/AAudioServiceDefinitions.h"
+#include "binding/IAAudioClient.h"
+#include "utility/AAudioUtilities.h"
+
+namespace android {
+
+using aaudio::aaudio_handle_t;
+
+/**
+ * This is used by the AAudio Service to talk to an AAudio Client.
+ *
+ * The order of parameters in the Parcels must match with code in AAudioClient.cpp.
+ */
+class BpAAudioClient : public BpInterface<IAAudioClient>
+{
+public:
+    explicit BpAAudioClient(const sp<IBinder>& impl)
+        : BpInterface<IAAudioClient>(impl)
+    {
+    }
+
+    void onStreamChange(aaudio_handle_t handle, int32_t opcode, int32_t value) override {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAAudioClient::getInterfaceDescriptor());
+        data.writeInt32(handle);
+        data.writeInt32(opcode);
+        data.writeInt32(value);
+        remote()->transact(ON_STREAM_CHANGE, data,  &reply, IBinder::FLAG_ONEWAY);
+    }
+
+};
+
+// Implement an interface to the service.
+IMPLEMENT_META_INTERFACE(AAudioClient, "IAAudioClient");
+
+// The order of parameters in the Parcels must match with code in BpAAudioClient
+
+status_t BnAAudioClient::onTransact(uint32_t code, const Parcel& data,
+                                        Parcel* reply, uint32_t flags) {
+    aaudio_handle_t streamHandle;
+    int32_t opcode = 0;
+    int32_t value = 0;
+    ALOGV("BnAAudioClient::onTransact(%u) %u", code, flags);
+
+    switch(code) {
+        case ON_STREAM_CHANGE: {
+            CHECK_INTERFACE(IAAudioClient, data, reply);
+            data.readInt32(&streamHandle);
+            data.readInt32(&opcode);
+            data.readInt32(&value);
+            onStreamChange(streamHandle, opcode, value);
+            ALOGD("BnAAudioClient onStreamChange(%x, %d, %d)", streamHandle, opcode, value);
+            return NO_ERROR;
+        } break;
+
+        default:
+            // ALOGW("BnAAudioClient::onTransact not handled %u", code);
+            return BBinder::onTransact(code, data, reply, flags);
+    }
+}
+
+} /* namespace android */
diff --git a/media/libaaudio/src/binding/IAAudioClient.h b/media/libaaudio/src/binding/IAAudioClient.h
new file mode 100644
index 0000000..21cc33b
--- /dev/null
+++ b/media/libaaudio/src/binding/IAAudioClient.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_AAUDIO_IAAUDIO_CLIENT_H
+#define ANDROID_AAUDIO_IAAUDIO_CLIENT_H
+
+#include <stdint.h>
+#include <binder/IInterface.h>
+
+#include <aaudio/AAudio.h>
+
+#include "utility/HandleTracker.h"
+
+namespace android {
+
+
+// Interface (our AIDL) - client methods called by service
+class IAAudioClient : public IInterface {
+public:
+
+    DECLARE_META_INTERFACE(AAudioClient);
+
+    virtual void onStreamChange(aaudio_handle_t handle, int32_t opcode, int32_t value) = 0;
+
+};
+
+class BnAAudioClient : public BnInterface<IAAudioClient> {
+public:
+    virtual status_t onTransact(uint32_t code, const Parcel& data,
+                                Parcel* reply, uint32_t flags = 0);
+};
+
+} /* namespace android */
+
+#endif //ANDROID_AAUDIO_IAAUDIO_SERVICE_H
diff --git a/media/libaaudio/src/binding/IAAudioService.cpp b/media/libaaudio/src/binding/IAAudioService.cpp
index b8ef611..b3c4934 100644
--- a/media/libaaudio/src/binding/IAAudioService.cpp
+++ b/media/libaaudio/src/binding/IAAudioService.cpp
@@ -14,7 +14,12 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "AAudio"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
 #include <aaudio/AAudio.h>
+#include <binder/IPCThreadState.h>
 
 #include "binding/AudioEndpointParcelable.h"
 #include "binding/AAudioStreamRequest.h"
@@ -40,16 +45,22 @@
     {
     }
 
-    virtual aaudio_handle_t openStream(const aaudio::AAudioStreamRequest &request,
-                                     aaudio::AAudioStreamConfiguration &configurationOutput) override {
+    void registerClient(const sp<IAAudioClient>& client) override
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAAudioService::getInterfaceDescriptor());
+        data.writeStrongBinder(IInterface::asBinder(client));
+        remote()->transact(REGISTER_CLIENT, data, &reply);
+    }
+
+    aaudio_handle_t openStream(const aaudio::AAudioStreamRequest &request,
+                               aaudio::AAudioStreamConfiguration &configurationOutput) override {
         Parcel data, reply;
         // send command
         data.writeInterfaceToken(IAAudioService::getInterfaceDescriptor());
-        ALOGV("BpAAudioService::client openStream --------------------");
         // request.dump();
         request.writeToParcel(&data);
         status_t err = remote()->transact(OPEN_STREAM, data, &reply);
-        ALOGV("BpAAudioService::client openStream returned %d", err);
         if (err != NO_ERROR) {
             ALOGE("BpAAudioService::client openStream transact failed %d", err);
             return AAudioConvert_androidToAAudioResult(err);
@@ -186,15 +197,13 @@
     }
 
     virtual aaudio_result_t registerAudioThread(aaudio_handle_t streamHandle,
-                                              pid_t clientProcessId,
-                                              pid_t clientThreadId,
-                                              int64_t periodNanoseconds)
+                                                pid_t clientThreadId,
+                                                int64_t periodNanoseconds)
     override {
         Parcel data, reply;
         // send command
         data.writeInterfaceToken(IAAudioService::getInterfaceDescriptor());
         data.writeInt32(streamHandle);
-        data.writeInt32((int32_t) clientProcessId);
         data.writeInt32((int32_t) clientThreadId);
         data.writeInt64(periodNanoseconds);
         status_t err = remote()->transact(REGISTER_AUDIO_THREAD, data, &reply);
@@ -208,14 +217,12 @@
     }
 
     virtual aaudio_result_t unregisterAudioThread(aaudio_handle_t streamHandle,
-                                                  pid_t clientProcessId,
                                                   pid_t clientThreadId)
     override {
         Parcel data, reply;
         // send command
         data.writeInterfaceToken(IAAudioService::getInterfaceDescriptor());
         data.writeInt32(streamHandle);
-        data.writeInt32((int32_t) clientProcessId);
         data.writeInt32((int32_t) clientThreadId);
         status_t err = remote()->transact(UNREGISTER_AUDIO_THREAD, data, &reply);
         if (err != NO_ERROR) {
@@ -237,43 +244,59 @@
 
 status_t BnAAudioService::onTransact(uint32_t code, const Parcel& data,
                                         Parcel* reply, uint32_t flags) {
-    aaudio_handle_t stream;
+    aaudio_handle_t streamHandle;
     aaudio::AAudioStreamRequest request;
     aaudio::AAudioStreamConfiguration configuration;
-    pid_t pid;
     pid_t tid;
     int64_t nanoseconds;
     aaudio_result_t result;
     ALOGV("BnAAudioService::onTransact(%i) %i", code, flags);
-    data.checkInterface(this);
 
     switch(code) {
+        case REGISTER_CLIENT: {
+            CHECK_INTERFACE(IAAudioService, data, reply);
+            sp<IAAudioClient> client = interface_cast<IAAudioClient>(
+                    data.readStrongBinder());
+            registerClient(client);
+            return NO_ERROR;
+        } break;
+
         case OPEN_STREAM: {
+            CHECK_INTERFACE(IAAudioService, data, reply);
             request.readFromParcel(&data);
-
-            //ALOGD("BnAAudioService::client openStream request dump --------------------");
-            //request.dump();
-
-            stream = openStream(request, configuration);
-            //ALOGD("BnAAudioService::onTransact OPEN_STREAM server handle = 0x%08X", stream);
-            reply->writeInt32(stream);
+            result = request.validate();
+            if (result != AAUDIO_OK) {
+                streamHandle = result;
+            } else {
+                //ALOGD("BnAAudioService::client openStream request dump --------------------");
+                //request.dump();
+                // Override the uid and pid from the client in case they are incorrect.
+                request.setUserId(IPCThreadState::self()->getCallingUid());
+                request.setProcessId(IPCThreadState::self()->getCallingPid());
+                streamHandle = openStream(request, configuration);
+                //ALOGD("BnAAudioService::onTransact OPEN_STREAM server handle = 0x%08X",
+                //        streamHandle);
+            }
+            reply->writeInt32(streamHandle);
             configuration.writeToParcel(reply);
             return NO_ERROR;
         } break;
 
         case CLOSE_STREAM: {
-            data.readInt32(&stream);
-            result = closeStream(stream);
+            CHECK_INTERFACE(IAAudioService, data, reply);
+            data.readInt32(&streamHandle);
+            result = closeStream(streamHandle);
             //ALOGD("BnAAudioService::onTransact CLOSE_STREAM 0x%08X, result = %d",
-            //      stream, result);
+            //      streamHandle, result);
             reply->writeInt32(result);
             return NO_ERROR;
         } break;
 
         case GET_STREAM_DESCRIPTION: {
-            data.readInt32(&stream);
+            CHECK_INTERFACE(IAAudioService, data, reply);
+            data.readInt32(&streamHandle);
             aaudio::AudioEndpointParcelable parcelable;
-            result = getStreamDescription(stream, parcelable);
+            result = getStreamDescription(streamHandle, parcelable);
             if (result != AAUDIO_OK) {
                 return AAudioConvert_aaudioToAndroidStatus(result);
             }
@@ -289,60 +312,64 @@
         } break;
 
         case START_STREAM: {
-            data.readInt32(&stream);
-            result = startStream(stream);
+            CHECK_INTERFACE(IAAudioService, data, reply);
+            data.readInt32(&streamHandle);
+            result = startStream(streamHandle);
             ALOGV("BnAAudioService::onTransact START_STREAM 0x%08X, result = %d",
-                    stream, result);
+                    streamHandle, result);
             reply->writeInt32(result);
             return NO_ERROR;
         } break;
 
         case PAUSE_STREAM: {
-            data.readInt32(&stream);
-            result = pauseStream(stream);
+            CHECK_INTERFACE(IAAudioService, data, reply);
+            data.readInt32(&streamHandle);
+            result = pauseStream(streamHandle);
             ALOGV("BnAAudioService::onTransact PAUSE_STREAM 0x%08X, result = %d",
-                  stream, result);
+                  streamHandle, result);
             reply->writeInt32(result);
             return NO_ERROR;
         } break;
 
         case STOP_STREAM: {
-            data.readInt32(&stream);
-            result = stopStream(stream);
+            CHECK_INTERFACE(IAAudioService, data, reply);
+            data.readInt32(&streamHandle);
+            result = stopStream(streamHandle);
             ALOGV("BnAAudioService::onTransact STOP_STREAM 0x%08X, result = %d",
-                  stream, result);
+                  streamHandle, result);
             reply->writeInt32(result);
             return NO_ERROR;
         } break;
 
         case FLUSH_STREAM: {
-            data.readInt32(&stream);
-            result = flushStream(stream);
+            CHECK_INTERFACE(IAAudioService, data, reply);
+            data.readInt32(&streamHandle);
+            result = flushStream(streamHandle);
             ALOGV("BnAAudioService::onTransact FLUSH_STREAM 0x%08X, result = %d",
-                    stream, result);
+                    streamHandle, result);
             reply->writeInt32(result);
             return NO_ERROR;
         } break;
 
         case REGISTER_AUDIO_THREAD: {
-            data.readInt32(&stream);
-            data.readInt32(&pid);
+            CHECK_INTERFACE(IAAudioService, data, reply);
+            data.readInt32(&streamHandle);
             data.readInt32(&tid);
             data.readInt64(&nanoseconds);
-            result = registerAudioThread(stream, pid, tid, nanoseconds);
+            result = registerAudioThread(streamHandle, tid, nanoseconds);
             ALOGV("BnAAudioService::onTransact REGISTER_AUDIO_THREAD 0x%08X, result = %d",
-                    stream, result);
+                    streamHandle, result);
             reply->writeInt32(result);
             return NO_ERROR;
         } break;
 
         case UNREGISTER_AUDIO_THREAD: {
-            data.readInt32(&stream);
-            data.readInt32(&pid);
+            CHECK_INTERFACE(IAAudioService, data, reply);
+            data.readInt32(&streamHandle);
             data.readInt32(&tid);
-            result = unregisterAudioThread(stream, pid, tid);
+            result = unregisterAudioThread(streamHandle, tid);
             ALOGV("BnAAudioService::onTransact UNREGISTER_AUDIO_THREAD 0x%08X, result = %d",
-                    stream, result);
+                    streamHandle, result);
             reply->writeInt32(result);
             return NO_ERROR;
         } break;
diff --git a/media/libaaudio/src/binding/IAAudioService.h b/media/libaaudio/src/binding/IAAudioService.h
index 44a5e12..30b3ead 100644
--- a/media/libaaudio/src/binding/IAAudioService.h
+++ b/media/libaaudio/src/binding/IAAudioService.h
@@ -28,18 +28,24 @@
 #include "binding/AudioEndpointParcelable.h"
 #include "binding/AAudioStreamRequest.h"
 #include "binding/AAudioStreamConfiguration.h"
+#include "binding/IAAudioClient.h"
 #include "utility/HandleTracker.h"
 
 namespace android {
 
 #define AAUDIO_SERVICE_NAME  "media.aaudio"
 
-// Interface (our AIDL) - Shared by server and client
+// Interface (our AIDL) - service methods called by client
 class IAAudioService : public IInterface {
 public:
 
     DECLARE_META_INTERFACE(AAudioService);
 
+    // Register an object to receive audio input/output change and track notifications.
+    // For a given calling pid, AAudio service disregards any registrations after the first.
+    // Thus the IAAudioClient must be a singleton per process.
+    virtual void registerClient(const sp<IAAudioClient>& client) = 0;
+
     /**
      * @param request info needed to create the stream
      * @param configuration contains information about the created stream
@@ -82,15 +88,12 @@
 
     /**
      * Manage the specified thread as a low latency audio thread.
-     * TODO Consider passing this information as part of the startStream() call.
      */
     virtual aaudio_result_t registerAudioThread(aaudio_handle_t streamHandle,
-                                              pid_t clientProcessId,
                                               pid_t clientThreadId,
                                               int64_t periodNanoseconds) = 0;
 
     virtual aaudio_result_t unregisterAudioThread(aaudio_handle_t streamHandle,
-                                                pid_t clientProcessId,
                                                 pid_t clientThreadId) = 0;
 };
 
diff --git a/media/libaaudio/src/binding/SharedMemoryParcelable.cpp b/media/libaaudio/src/binding/SharedMemoryParcelable.cpp
index 899eb04..90217ab 100644
--- a/media/libaaudio/src/binding/SharedMemoryParcelable.cpp
+++ b/media/libaaudio/src/binding/SharedMemoryParcelable.cpp
@@ -24,11 +24,13 @@
 #include <sys/mman.h>
 #include <aaudio/AAudio.h>
 
+#include <android-base/unique_fd.h>
 #include <binder/Parcelable.h>
 #include <utility/AAudioUtilities.h>
 
 #include "binding/SharedMemoryParcelable.h"
 
+using android::base::unique_fd;
 using android::NO_ERROR;
 using android::status_t;
 using android::Parcel;
@@ -39,17 +41,19 @@
 SharedMemoryParcelable::SharedMemoryParcelable() {}
 SharedMemoryParcelable::~SharedMemoryParcelable() {};
 
-void SharedMemoryParcelable::setup(int fd, int32_t sizeInBytes) {
-    mFd = fd;
+void SharedMemoryParcelable::setup(const unique_fd& fd, int32_t sizeInBytes) {
+    mFd.reset(dup(fd.get())); // store a duplicate fd
+    ALOGV("SharedMemoryParcelable::setup(%d -> %d, %d) this = %p\n",
+          fd.get(), mFd.get(), sizeInBytes, this);
     mSizeInBytes = sizeInBytes;
-
 }
 
 status_t SharedMemoryParcelable::writeToParcel(Parcel* parcel) const {
     status_t status = parcel->writeInt32(mSizeInBytes);
     if (status != NO_ERROR) return status;
     if (mSizeInBytes > 0) {
-        status = parcel->writeDupFileDescriptor(mFd);
+        ALOGV("SharedMemoryParcelable::writeToParcel() mFd = %d, this = %p\n", mFd.get(), this);
+        status = parcel->writeUniqueFileDescriptor(mFd);
         ALOGE_IF(status != NO_ERROR, "SharedMemoryParcelable writeDupFileDescriptor failed : %d",
                  status);
     }
@@ -62,15 +66,16 @@
         return status;
     }
     if (mSizeInBytes > 0) {
-        // Keep the original FD until you are done with the mFd.
-        // If you close it in here then it will prevent mFd from working.
-        mOriginalFd = parcel->readFileDescriptor();
-        ALOGV("SharedMemoryParcelable::readFromParcel() LEAK? mOriginalFd = %d\n", mOriginalFd);
-        mFd = fcntl(mOriginalFd, F_DUPFD_CLOEXEC, 0);
-        ALOGV("SharedMemoryParcelable::readFromParcel() LEAK? mFd = %d\n", mFd);
-        if (mFd == -1) {
-            status = -errno;
-            ALOGE("SharedMemoryParcelable readFromParcel fcntl() failed : %d", status);
+        // The Parcel owns the file descriptor and will close it later.
+        unique_fd mmapFd;
+        status = parcel->readUniqueFileDescriptor(&mmapFd);
+        if (status != NO_ERROR) {
+            ALOGE("SharedMemoryParcelable::readFromParcel() readUniqueFileDescriptor() failed : %d",
+                  status);
+        } else {
+            // Resolve the memory now while we still have the FD from the Parcel.
+            // Closing the FD will not affect the shared memory once mmap() has been called.
+            status = AAudioConvert_androidToAAudioResult(resolveSharedMemory(mmapFd));
         }
     }
     return status;
@@ -85,45 +90,50 @@
         }
         mResolvedAddress = MMAP_UNRESOLVED_ADDRESS;
     }
-    if (mFd != -1) {
-        ALOGV("SharedMemoryParcelable::close() LEAK? mFd = %d\n", mFd);
-        ::close(mFd);
-        mFd = -1;
-    }
-    if (mOriginalFd != -1) {
-        ALOGV("SharedMemoryParcelable::close() LEAK? mOriginalFd = %d\n", mOriginalFd);
-        ::close(mOriginalFd);
-        mOriginalFd = -1;
+    return AAUDIO_OK;
+}
+
+aaudio_result_t SharedMemoryParcelable::resolveSharedMemory(const unique_fd& fd) {
+    mResolvedAddress = (uint8_t *) mmap(0, mSizeInBytes, PROT_READ | PROT_WRITE,
+                                        MAP_SHARED, fd.get(), 0);
+    if (mResolvedAddress == MMAP_UNRESOLVED_ADDRESS) {
+        ALOGE("SharedMemoryParcelable mmap() failed for fd = %d, errno = %s",
+              fd.get(), strerror(errno));
+        return AAUDIO_ERROR_INTERNAL;
     }
     return AAUDIO_OK;
 }
 
 aaudio_result_t SharedMemoryParcelable::resolve(int32_t offsetInBytes, int32_t sizeInBytes,
                                               void **regionAddressPtr) {
-
     if (offsetInBytes < 0) {
         ALOGE("SharedMemoryParcelable illegal offsetInBytes = %d", offsetInBytes);
         return AAUDIO_ERROR_OUT_OF_RANGE;
     } else if ((offsetInBytes + sizeInBytes) > mSizeInBytes) {
         ALOGE("SharedMemoryParcelable out of range, offsetInBytes = %d, "
-              "sizeInBytes = %d, mSizeInBytes = %d",
+                      "sizeInBytes = %d, mSizeInBytes = %d",
               offsetInBytes, sizeInBytes, mSizeInBytes);
         return AAUDIO_ERROR_OUT_OF_RANGE;
     }
+
+    aaudio_result_t result = AAUDIO_OK;
+
     if (mResolvedAddress == MMAP_UNRESOLVED_ADDRESS) {
-        mResolvedAddress = (uint8_t *) mmap(0, mSizeInBytes, PROT_READ|PROT_WRITE,
-                                          MAP_SHARED, mFd, 0);
-        if (mResolvedAddress == MMAP_UNRESOLVED_ADDRESS) {
-            ALOGE("SharedMemoryParcelable mmap failed for fd = %d, errno = %s",
-                  mFd, strerror(errno));
-            return AAUDIO_ERROR_INTERNAL;
+        if (mFd.get() != -1) {
+            result = resolveSharedMemory(mFd);
+        } else {
+            ALOGE("SharedMemoryParcelable has no file descriptor for shared memory.");
+            result = AAUDIO_ERROR_INTERNAL;
         }
     }
-    *regionAddressPtr = mResolvedAddress + offsetInBytes;
-    ALOGV("SharedMemoryParcelable mResolvedAddress = %p", mResolvedAddress);
-    ALOGV("SharedMemoryParcelable offset by %d, *regionAddressPtr = %p",
-          offsetInBytes, *regionAddressPtr);
-    return AAUDIO_OK;
+
+    if (result == AAUDIO_OK && mResolvedAddress != MMAP_UNRESOLVED_ADDRESS) {
+        *regionAddressPtr = mResolvedAddress + offsetInBytes;
+        ALOGV("SharedMemoryParcelable mResolvedAddress = %p", mResolvedAddress);
+        ALOGV("SharedMemoryParcelable offset by %d, *regionAddressPtr = %p",
+              offsetInBytes, *regionAddressPtr);
+    }
+    return result;
 }
 
 int32_t SharedMemoryParcelable::getSizeInBytes() {
@@ -135,17 +145,11 @@
         ALOGE("SharedMemoryParcelable invalid mSizeInBytes = %d", mSizeInBytes);
         return AAUDIO_ERROR_OUT_OF_RANGE;
     }
-    if (mSizeInBytes > 0) {
-        if (mFd == -1) {
-            ALOGE("SharedMemoryParcelable uninitialized mFd = %d", mFd);
-            return AAUDIO_ERROR_INTERNAL;
-        }
-    }
     return AAUDIO_OK;
 }
 
 void SharedMemoryParcelable::dump() {
-    ALOGD("SharedMemoryParcelable mFd = %d", mFd);
+    ALOGD("SharedMemoryParcelable mFd = %d", mFd.get());
     ALOGD("SharedMemoryParcelable mSizeInBytes = %d", mSizeInBytes);
     ALOGD("SharedMemoryParcelable mResolvedAddress = %p", mResolvedAddress);
 }
diff --git a/media/libaaudio/src/binding/SharedMemoryParcelable.h b/media/libaaudio/src/binding/SharedMemoryParcelable.h
index 4b94b46..2a634e0 100644
--- a/media/libaaudio/src/binding/SharedMemoryParcelable.h
+++ b/media/libaaudio/src/binding/SharedMemoryParcelable.h
@@ -18,15 +18,12 @@
 #define ANDROID_AAUDIO_SHARED_MEMORY_PARCELABLE_H
 
 #include <stdint.h>
-
 #include <sys/mman.h>
+
+#include <android-base/unique_fd.h>
 #include <binder/Parcel.h>
 #include <binder/Parcelable.h>
 
-using android::status_t;
-using android::Parcel;
-using android::Parcelable;
-
 namespace aaudio {
 
 // Arbitrary limits for sanity checks. TODO remove after debugging.
@@ -37,17 +34,24 @@
 /**
  * This is a parcelable description of a shared memory referenced by a file descriptor.
  * It may be divided into several regions.
+ * The memory can be shared using Binder or simply shared between threads.
  */
-class SharedMemoryParcelable : public Parcelable {
+class SharedMemoryParcelable : public android::Parcelable {
 public:
     SharedMemoryParcelable();
     virtual ~SharedMemoryParcelable();
 
-    void setup(int fd, int32_t sizeInBytes);
+    /**
+     * Make a dup() of the fd and store it for later use.
+     *
+     * @param fd
+     * @param sizeInBytes
+     */
+    void setup(const android::base::unique_fd& fd, int32_t sizeInBytes);
 
-    virtual status_t writeToParcel(Parcel* parcel) const override;
+    virtual android::status_t writeToParcel(android::Parcel* parcel) const override;
 
-    virtual status_t readFromParcel(const Parcel* parcel) override;
+    virtual android::status_t readFromParcel(const android::Parcel* parcel) override;
 
     // mmap() shared memory
     aaudio_result_t resolve(int32_t offsetInBytes, int32_t sizeInBytes, void **regionAddressPtr);
@@ -55,8 +59,6 @@
     // munmap() any mapped memory
     aaudio_result_t close();
 
-    bool isFileDescriptorSafe();
-
     int32_t getSizeInBytes();
 
     aaudio_result_t validate();
@@ -67,10 +69,11 @@
 
 #define MMAP_UNRESOLVED_ADDRESS    reinterpret_cast<uint8_t*>(MAP_FAILED)
 
-    int      mFd = -1;
-    int      mOriginalFd = -1;
-    int32_t  mSizeInBytes = 0;
-    uint8_t *mResolvedAddress = MMAP_UNRESOLVED_ADDRESS;
+    aaudio_result_t resolveSharedMemory(const android::base::unique_fd& fd);
+
+    android::base::unique_fd   mFd;
+    int32_t     mSizeInBytes = 0;
+    uint8_t    *mResolvedAddress = MMAP_UNRESOLVED_ADDRESS;
 };
 
 } /* namespace aaudio */
diff --git a/media/libaaudio/src/client/AudioEndpoint.cpp b/media/libaaudio/src/client/AudioEndpoint.cpp
index 5cb642b..6ec285f 100644
--- a/media/libaaudio/src/client/AudioEndpoint.cpp
+++ b/media/libaaudio/src/client/AudioEndpoint.cpp
@@ -113,7 +113,8 @@
     return result;
 }
 
-aaudio_result_t AudioEndpoint::configure(const EndpointDescriptor *pEndpointDescriptor)
+aaudio_result_t AudioEndpoint::configure(const EndpointDescriptor *pEndpointDescriptor,
+                                         aaudio_direction_t   direction)
 {
     aaudio_result_t result = AudioEndpoint_validateDescriptor(pEndpointDescriptor);
     if (result != AAUDIO_OK) {
@@ -143,12 +144,20 @@
             descriptor->dataAddress
     );
 
-    // ============================ down data queue =============================
+    // ============================ data queue =============================
     descriptor = &pEndpointDescriptor->dataQueueDescriptor;
     ALOGV("AudioEndpoint::configure() data framesPerBurst = %d", descriptor->framesPerBurst);
-    ALOGV("AudioEndpoint::configure() data readCounterAddress = %p", descriptor->readCounterAddress);
-    mFreeRunning = descriptor->readCounterAddress == nullptr;
+    ALOGV("AudioEndpoint::configure() data readCounterAddress = %p",
+          descriptor->readCounterAddress);
+
+    // An example of free running is when the other side is read or written by hardware DMA
+    // or a DSP. It does not update its counter so we have to update it.
+    int64_t *remoteCounter = (direction == AAUDIO_DIRECTION_OUTPUT)
+                             ? descriptor->readCounterAddress // read by other side
+                             : descriptor->writeCounterAddress; // written by other side
+    mFreeRunning = (remoteCounter == nullptr);
     ALOGV("AudioEndpoint::configure() mFreeRunning = %d", mFreeRunning ? 1 : 0);
+
     int64_t *readCounterAddress = (descriptor->readCounterAddress == nullptr)
                                   ? &mDataReadCounter
                                   : descriptor->readCounterAddress;
@@ -173,13 +182,8 @@
     return mUpCommandQueue->read(commandPtr, 1);
 }
 
-aaudio_result_t AudioEndpoint::writeDataNow(const void *buffer, int32_t numFrames)
-{
-    return mDataQueue->write(buffer, numFrames);
-}
-
-void AudioEndpoint::getEmptyFramesAvailable(WrappingBuffer *wrappingBuffer) {
-    mDataQueue->getEmptyRoomAvailable(wrappingBuffer);
+int32_t AudioEndpoint::getEmptyFramesAvailable(WrappingBuffer *wrappingBuffer) {
+    return mDataQueue->getEmptyRoomAvailable(wrappingBuffer);
 }
 
 int32_t AudioEndpoint::getEmptyFramesAvailable()
@@ -187,7 +191,7 @@
     return mDataQueue->getFifoControllerBase()->getEmptyFramesAvailable();
 }
 
-void AudioEndpoint::getFullFramesAvailable(WrappingBuffer *wrappingBuffer)
+int32_t AudioEndpoint::getFullFramesAvailable(WrappingBuffer *wrappingBuffer)
 {
     return mDataQueue->getFullDataAvailable(wrappingBuffer);
 }
@@ -246,3 +250,7 @@
     return (int32_t)mDataQueue->getBufferCapacityInFrames();
 }
 
+void AudioEndpoint::dump() const {
+    ALOGD("AudioEndpoint: data readCounter  = %lld", (long long) mDataQueue->getReadCounter());
+    ALOGD("AudioEndpoint: data writeCounter = %lld", (long long) mDataQueue->getWriteCounter());
+}
diff --git a/media/libaaudio/src/client/AudioEndpoint.h b/media/libaaudio/src/client/AudioEndpoint.h
index 53ba033..81a4f7b 100644
--- a/media/libaaudio/src/client/AudioEndpoint.h
+++ b/media/libaaudio/src/client/AudioEndpoint.h
@@ -40,7 +40,8 @@
     /**
      * Configure based on the EndPointDescriptor_t.
      */
-    aaudio_result_t configure(const EndpointDescriptor *pEndpointDescriptor);
+    aaudio_result_t configure(const EndpointDescriptor *pEndpointDescriptor,
+                              aaudio_direction_t direction);
 
     /**
      * Read from a command passed up from the Server.
@@ -48,17 +49,11 @@
      */
     aaudio_result_t readUpCommand(AAudioServiceMessage *commandPtr);
 
-    /**
-     * Non-blocking write.
-     * @return framesWritten or a negative error code.
-     */
-    aaudio_result_t writeDataNow(const void *buffer, int32_t numFrames);
-
-    void getEmptyFramesAvailable(android::WrappingBuffer *wrappingBuffer);
+    int32_t getEmptyFramesAvailable(android::WrappingBuffer *wrappingBuffer);
 
     int32_t getEmptyFramesAvailable();
 
-    void getFullFramesAvailable(android::WrappingBuffer *wrappingBuffer);
+    int32_t getFullFramesAvailable(android::WrappingBuffer *wrappingBuffer);
 
     int32_t getFullFramesAvailable();
 
@@ -91,6 +86,8 @@
 
     int32_t getBufferCapacityInFrames() const;
 
+    void dump() const;
+
 private:
     android::FifoBuffer    *mUpCommandQueue;
     android::FifoBuffer    *mDataQueue;
diff --git a/media/libaaudio/src/client/AudioStreamInternal.cpp b/media/libaaudio/src/client/AudioStreamInternal.cpp
index 3a827f0..4c7d0f7 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternal.cpp
@@ -16,7 +16,7 @@
 
 // This file is used in both client and server processes.
 // This is needed to make sense of the logs more easily.
-#define LOG_TAG (mInService ? "AAudioService" : "AAudio")
+#define LOG_TAG (mInService ? "AudioStreamInternal_Service" : "AudioStreamInternal_Client")
 //#define LOG_NDEBUG 0
 #include <utils/Log.h>
 
@@ -28,10 +28,10 @@
 #include <binder/IServiceManager.h>
 
 #include <aaudio/AAudio.h>
+#include <cutils/properties.h>
 #include <utils/String16.h>
 #include <utils/Trace.h>
 
-#include "AudioClock.h"
 #include "AudioEndpointParcelable.h"
 #include "binding/AAudioStreamRequest.h"
 #include "binding/AAudioStreamConfiguration.h"
@@ -39,6 +39,7 @@
 #include "binding/AAudioServiceMessage.h"
 #include "core/AudioStreamBuilder.h"
 #include "fifo/FifoBuffer.h"
+#include "utility/AudioClock.h"
 #include "utility/LinearRamp.h"
 
 #include "AudioStreamInternal.h"
@@ -62,8 +63,14 @@
         , mAudioEndpoint()
         , mServiceStreamHandle(AAUDIO_HANDLE_INVALID)
         , mFramesPerBurst(16)
+        , mStreamVolume(1.0f)
+        , mInService(inService)
         , mServiceInterface(serviceInterface)
-        , mInService(inService) {
+        , mWakeupDelayNanos(AAudioProperty_getWakeupDelayMicros() * AAUDIO_NANOS_PER_MICROSECOND)
+        , mMinimumSleepNanos(AAudioProperty_getMinimumSleepMicros() * AAUDIO_NANOS_PER_MICROSECOND)
+        {
+    ALOGD("AudioStreamInternal(): mWakeupDelayNanos = %d, mMinimumSleepNanos = %d",
+          mWakeupDelayNanos, mMinimumSleepNanos);
 }
 
 AudioStreamInternal::~AudioStreamInternal() {
@@ -85,13 +92,14 @@
         setFormat(AAUDIO_FORMAT_PCM_FLOAT);
     }
     // Request FLOAT for the shared mixer.
-    request.getConfiguration().setAudioFormat(AAUDIO_FORMAT_PCM_FLOAT);
+    request.getConfiguration().setFormat(AAUDIO_FORMAT_PCM_FLOAT);
 
     // Build the request to send to the server.
     request.setUserId(getuid());
     request.setProcessId(getpid());
     request.setDirection(getDirection());
     request.setSharingModeMatchRequired(isSharingModeMatchRequired());
+    request.setInService(mInService);
 
     request.getConfiguration().setDeviceId(getDeviceId());
     request.getConfiguration().setSampleRate(getSampleRate());
@@ -114,9 +122,10 @@
         setSampleRate(configuration.getSampleRate());
         setSamplesPerFrame(configuration.getSamplesPerFrame());
         setDeviceId(configuration.getDeviceId());
+        setSharingMode(configuration.getSharingMode());
 
         // Save device format so we can do format conversion and volume scaling together.
-        mDeviceFormat = configuration.getAudioFormat();
+        mDeviceFormat = configuration.getFormat();
 
         result = mServiceInterface.getStreamDescription(mServiceStreamHandle, mEndPointParcelable);
         if (result != AAUDIO_OK) {
@@ -132,7 +141,7 @@
         }
 
         // Configure endpoint based on descriptor.
-        mAudioEndpoint.configure(&mEndpointDescriptor);
+        mAudioEndpoint.configure(&mEndpointDescriptor, getDirection());
 
         mFramesPerBurst = mEndpointDescriptor.dataQueueDescriptor.framesPerBurst;
         int32_t capacity = mEndpointDescriptor.dataQueueDescriptor.capacityInFrames;
@@ -153,13 +162,13 @@
         if (getDataCallbackProc()) {
             mCallbackFrames = builder.getFramesPerDataCallback();
             if (mCallbackFrames > getBufferCapacity() / 2) {
-                ALOGE("AudioStreamInternal.open(): framesPerCallback too large = %d, capacity = %d",
+                ALOGE("AudioStreamInternal::open(): framesPerCallback too big = %d, capacity = %d",
                       mCallbackFrames, getBufferCapacity());
                 mServiceInterface.closeStream(mServiceStreamHandle);
                 return AAUDIO_ERROR_OUT_OF_RANGE;
 
             } else if (mCallbackFrames < 0) {
-                ALOGE("AudioStreamInternal.open(): framesPerCallback negative");
+                ALOGE("AudioStreamInternal::open(): framesPerCallback negative");
                 mServiceInterface.closeStream(mServiceStreamHandle);
                 return AAUDIO_ERROR_OUT_OF_RANGE;
 
@@ -175,12 +184,16 @@
         }
 
         setState(AAUDIO_STREAM_STATE_OPEN);
+        // only connect to AudioManager if this is a playback stream running in client process
+        if (!mInService && getDirection() == AAUDIO_DIRECTION_OUTPUT) {
+            init(android::PLAYER_TYPE_AAUDIO, AUDIO_USAGE_MEDIA);
+        }
     }
     return result;
 }
 
 aaudio_result_t AudioStreamInternal::close() {
-    ALOGD("AudioStreamInternal.close(): mServiceStreamHandle = 0x%08X",
+    ALOGD("AudioStreamInternal::close(): mServiceStreamHandle = 0x%08X",
              mServiceStreamHandle);
     if (mServiceStreamHandle != AAUDIO_HANDLE_INVALID) {
         // Don't close a stream while it is running.
@@ -196,12 +209,14 @@
                 result, AAudio_convertResultToText(result));
             }
         }
+        setState(AAUDIO_STREAM_STATE_CLOSING);
         aaudio_handle_t serviceStreamHandle = mServiceStreamHandle;
         mServiceStreamHandle = AAUDIO_HANDLE_INVALID;
 
         mServiceInterface.closeStream(serviceStreamHandle);
         delete[] mCallbackBuffer;
         mCallbackBuffer = nullptr;
+        setState(AAUDIO_STREAM_STATE_CLOSED);
         return mEndPointParcelable.close();
     } else {
         return AAUDIO_ERROR_INVALID_HANDLE;
@@ -223,15 +238,20 @@
 aaudio_result_t AudioStreamInternal::requestStart()
 {
     int64_t startTime;
-    ALOGD("AudioStreamInternal(): start()");
+    ALOGD("AudioStreamInternal()::requestStart()");
     if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
         return AAUDIO_ERROR_INVALID_STATE;
     }
+    if (isActive()) {
+        return AAUDIO_ERROR_INVALID_STATE;
+    }
+    aaudio_stream_state_t originalState = getState();
+
+    setState(AAUDIO_STREAM_STATE_STARTING);
+    aaudio_result_t result = AAudioConvert_androidToAAudioResult(startWithStatus());
 
     startTime = AudioClock::getNanoseconds();
     mClockModel.start(startTime);
-    setState(AAUDIO_STREAM_STATE_STARTING);
-    aaudio_result_t result = mServiceInterface.startStream(mServiceStreamHandle);;
 
     if (result == AAUDIO_OK && getDataCallbackProc() != nullptr) {
         // Launch the callback loop thread.
@@ -241,6 +261,9 @@
         mCallbackEnabled.store(true);
         result = createThread(periodNanos, aaudio_callback_thread_proc, this);
     }
+    if (result != AAUDIO_OK) {
+        setState(originalState);
+    }
     return result;
 }
 
@@ -271,66 +294,17 @@
     }
 }
 
-aaudio_result_t AudioStreamInternal::requestPauseInternal()
-{
-    if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
-        ALOGE("AudioStreamInternal(): requestPauseInternal() mServiceStreamHandle invalid = 0x%08X",
-              mServiceStreamHandle);
-        return AAUDIO_ERROR_INVALID_STATE;
-    }
-
-    mClockModel.stop(AudioClock::getNanoseconds());
-    setState(AAUDIO_STREAM_STATE_PAUSING);
-    return mServiceInterface.pauseStream(mServiceStreamHandle);
-}
-
-aaudio_result_t AudioStreamInternal::requestPause()
-{
-    aaudio_result_t result = stopCallback();
-    if (result != AAUDIO_OK) {
-        return result;
-    }
-    result = requestPauseInternal();
-    return result;
-}
-
-aaudio_result_t AudioStreamInternal::requestFlush() {
-    if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
-        ALOGE("AudioStreamInternal(): requestFlush() mServiceStreamHandle invalid = 0x%08X",
-              mServiceStreamHandle);
-        return AAUDIO_ERROR_INVALID_STATE;
-    }
-
-    setState(AAUDIO_STREAM_STATE_FLUSHING);
-    return mServiceInterface.flushStream(mServiceStreamHandle);
-}
-
-// TODO for Play only
-void AudioStreamInternal::onFlushFromServer() {
-    ALOGD("AudioStreamInternal(): onFlushFromServer()");
-    int64_t readCounter = mAudioEndpoint.getDataReadCounter();
-    int64_t writeCounter = mAudioEndpoint.getDataWriteCounter();
-
-    // Bump offset so caller does not see the retrograde motion in getFramesRead().
-    int64_t framesFlushed = writeCounter - readCounter;
-    mFramesOffsetFromService += framesFlushed;
-
-    // Flush written frames by forcing writeCounter to readCounter.
-    // This is because we cannot move the read counter in the hardware.
-    mAudioEndpoint.setDataWriteCounter(readCounter);
-}
-
 aaudio_result_t AudioStreamInternal::requestStopInternal()
 {
     if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
-        ALOGE("AudioStreamInternal(): requestStopInternal() mServiceStreamHandle invalid = 0x%08X",
+        ALOGE("AudioStreamInternal::requestStopInternal() mServiceStreamHandle invalid = 0x%08X",
               mServiceStreamHandle);
         return AAUDIO_ERROR_INVALID_STATE;
     }
 
     mClockModel.stop(AudioClock::getNanoseconds());
     setState(AAUDIO_STREAM_STATE_STOPPING);
-    return mServiceInterface.stopStream(mServiceStreamHandle);
+    return AAudioConvert_androidToAAudioResult(stopWithStatus());
 }
 
 aaudio_result_t AudioStreamInternal::requestStop()
@@ -348,7 +322,6 @@
         return AAUDIO_ERROR_INVALID_STATE;
     }
     return mServiceInterface.registerAudioThread(mServiceStreamHandle,
-                                              getpid(),
                                               gettid(),
                                               getPeriodNanoseconds());
 }
@@ -357,7 +330,22 @@
     if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
         return AAUDIO_ERROR_INVALID_STATE;
     }
-    return mServiceInterface.unregisterAudioThread(mServiceStreamHandle, getpid(), gettid());
+    return mServiceInterface.unregisterAudioThread(mServiceStreamHandle, gettid());
+}
+
+aaudio_result_t AudioStreamInternal::startClient(const android::AudioClient& client,
+                                                 audio_port_handle_t *clientHandle) {
+    if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
+        return AAUDIO_ERROR_INVALID_STATE;
+    }
+    return mServiceInterface.startClient(mServiceStreamHandle, client, clientHandle);
+}
+
+aaudio_result_t AudioStreamInternal::stopClient(audio_port_handle_t clientHandle) {
+    if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
+        return AAUDIO_ERROR_INVALID_STATE;
+    }
+    return mServiceInterface.stopClient(mServiceStreamHandle, clientHandle);
 }
 
 aaudio_result_t AudioStreamInternal::getTimestamp(clockid_t clockId,
@@ -365,7 +353,7 @@
                            int64_t *timeNanoseconds) {
     // TODO Generate in server and pass to client. Return latest.
     int64_t time = AudioClock::getNanoseconds();
-    *framePosition = mClockModel.convertTimeToPosition(time);
+    *framePosition = mClockModel.convertTimeToPosition(time) + mFramesOffsetFromService;
     // TODO Get a more accurate timestamp from the service. This code just adds a fudge factor.
     *timeNanoseconds = time + (6 * AAUDIO_NANOS_PER_MILLISECOND);
     return AAUDIO_OK;
@@ -378,31 +366,28 @@
     return processCommands();
 }
 
-#if LOG_TIMESTAMPS
-static void AudioStreamInternal_logTimestamp(AAudioServiceMessage &command) {
+void AudioStreamInternal::logTimestamp(AAudioServiceMessage &command) {
     static int64_t oldPosition = 0;
     static int64_t oldTime = 0;
     int64_t framePosition = command.timestamp.position;
     int64_t nanoTime = command.timestamp.timestamp;
-    ALOGD("AudioStreamInternal() timestamp says framePosition = %08lld at nanoTime %lld",
+    ALOGD("AudioStreamInternal: timestamp says framePosition = %08lld at nanoTime %lld",
          (long long) framePosition,
          (long long) nanoTime);
     int64_t nanosDelta = nanoTime - oldTime;
     if (nanosDelta > 0 && oldTime > 0) {
         int64_t framesDelta = framePosition - oldPosition;
         int64_t rate = (framesDelta * AAUDIO_NANOS_PER_SECOND) / nanosDelta;
-        ALOGD("AudioStreamInternal() - framesDelta = %08lld", (long long) framesDelta);
-        ALOGD("AudioStreamInternal() - nanosDelta = %08lld", (long long) nanosDelta);
-        ALOGD("AudioStreamInternal() - measured rate = %lld", (long long) rate);
+        ALOGD("AudioStreamInternal: framesDelta = %08lld, nanosDelta = %08lld, rate = %lld",
+              (long long) framesDelta, (long long) nanosDelta, (long long) rate);
     }
     oldPosition = framePosition;
     oldTime = nanoTime;
 }
-#endif
 
 aaudio_result_t AudioStreamInternal::onTimestampFromServer(AAudioServiceMessage *message) {
 #if LOG_TIMESTAMPS
-    AudioStreamInternal_logTimestamp(*message);
+    logTimestamp(*message);
 #endif
     processTimestamp(message->timestamp.position, message->timestamp.timestamp);
     return AAUDIO_OK;
@@ -412,46 +397,48 @@
     aaudio_result_t result = AAUDIO_OK;
     switch (message->event.event) {
         case AAUDIO_SERVICE_EVENT_STARTED:
-            ALOGD("processCommands() got AAUDIO_SERVICE_EVENT_STARTED");
+            ALOGD("AudioStreamInternal::onEventFromServergot() AAUDIO_SERVICE_EVENT_STARTED");
             if (getState() == AAUDIO_STREAM_STATE_STARTING) {
                 setState(AAUDIO_STREAM_STATE_STARTED);
             }
             break;
         case AAUDIO_SERVICE_EVENT_PAUSED:
-            ALOGD("processCommands() got AAUDIO_SERVICE_EVENT_PAUSED");
+            ALOGD("AudioStreamInternal::onEventFromServergot() AAUDIO_SERVICE_EVENT_PAUSED");
             if (getState() == AAUDIO_STREAM_STATE_PAUSING) {
                 setState(AAUDIO_STREAM_STATE_PAUSED);
             }
             break;
         case AAUDIO_SERVICE_EVENT_STOPPED:
-            ALOGD("processCommands() got AAUDIO_SERVICE_EVENT_STOPPED");
+            ALOGD("AudioStreamInternal::onEventFromServergot() AAUDIO_SERVICE_EVENT_STOPPED");
             if (getState() == AAUDIO_STREAM_STATE_STOPPING) {
                 setState(AAUDIO_STREAM_STATE_STOPPED);
             }
             break;
         case AAUDIO_SERVICE_EVENT_FLUSHED:
-            ALOGD("processCommands() got AAUDIO_SERVICE_EVENT_FLUSHED");
+            ALOGD("AudioStreamInternal::onEventFromServer() got AAUDIO_SERVICE_EVENT_FLUSHED");
             if (getState() == AAUDIO_STREAM_STATE_FLUSHING) {
                 setState(AAUDIO_STREAM_STATE_FLUSHED);
                 onFlushFromServer();
             }
             break;
         case AAUDIO_SERVICE_EVENT_CLOSED:
-            ALOGD("processCommands() got AAUDIO_SERVICE_EVENT_CLOSED");
+            ALOGD("AudioStreamInternal::onEventFromServer() got AAUDIO_SERVICE_EVENT_CLOSED");
             setState(AAUDIO_STREAM_STATE_CLOSED);
             break;
         case AAUDIO_SERVICE_EVENT_DISCONNECTED:
             result = AAUDIO_ERROR_DISCONNECTED;
             setState(AAUDIO_STREAM_STATE_DISCONNECTED);
-            ALOGW("WARNING - processCommands() AAUDIO_SERVICE_EVENT_DISCONNECTED");
+            ALOGW("WARNING - AudioStreamInternal::onEventFromServer()"
+                          " AAUDIO_SERVICE_EVENT_DISCONNECTED");
             break;
         case AAUDIO_SERVICE_EVENT_VOLUME:
-            mVolumeRamp.setTarget((float) message->event.dataDouble);
-            ALOGD("processCommands() AAUDIO_SERVICE_EVENT_VOLUME %lf",
+            mStreamVolume = (float)message->event.dataDouble;
+            doSetVolume();
+            ALOGD("AudioStreamInternal::onEventFromServer() AAUDIO_SERVICE_EVENT_VOLUME %lf",
                      message->event.dataDouble);
             break;
         default:
-            ALOGW("WARNING - processCommands() Unrecognized event = %d",
+            ALOGW("WARNING - AudioStreamInternal::onEventFromServer() Unrecognized event = %d",
                  (int) message->event.event);
             break;
     }
@@ -491,29 +478,29 @@
 aaudio_result_t AudioStreamInternal::processData(void *buffer, int32_t numFrames,
                                                  int64_t timeoutNanoseconds)
 {
-    const char * traceName = (mInService) ? "aaWrtS" : "aaWrtC";
+    const char * traceName = "aaProc";
+    const char * fifoName = "aaRdy";
     ATRACE_BEGIN(traceName);
+    if (ATRACE_ENABLED()) {
+        int32_t fullFrames = mAudioEndpoint.getFullFramesAvailable();
+        ATRACE_INT(fifoName, fullFrames);
+    }
+
     aaudio_result_t result = AAUDIO_OK;
     int32_t loopCount = 0;
     uint8_t* audioData = (uint8_t*)buffer;
     int64_t currentTimeNanos = AudioClock::getNanoseconds();
-    int64_t deadlineNanos = currentTimeNanos + timeoutNanoseconds;
+    const int64_t entryTimeNanos = currentTimeNanos;
+    const int64_t deadlineNanos = currentTimeNanos + timeoutNanoseconds;
     int32_t framesLeft = numFrames;
 
-    int32_t fullFrames = mAudioEndpoint.getFullFramesAvailable();
-    if (ATRACE_ENABLED()) {
-        const char * traceName = (mInService) ? "aaFullS" : "aaFullC";
-        ATRACE_INT(traceName, fullFrames);
-    }
-
     // Loop until all the data has been processed or until a timeout occurs.
     while (framesLeft > 0) {
-        // The call to processDataNow() will not block. It will just read as much as it can.
+        // The call to processDataNow() will not block. It will just process as much as it can.
         int64_t wakeTimeNanos = 0;
         aaudio_result_t framesProcessed = processDataNow(audioData, framesLeft,
                                                   currentTimeNanos, &wakeTimeNanos);
         if (framesProcessed < 0) {
-            ALOGE("AudioStreamInternal::processData() loop: framesProcessed = %d", framesProcessed);
             result = framesProcessed;
             break;
         }
@@ -524,28 +511,52 @@
         if (timeoutNanoseconds == 0) {
             break; // don't block
         } else if (framesLeft > 0) {
-            // clip the wake time to something reasonable
-            if (wakeTimeNanos < currentTimeNanos) {
-                wakeTimeNanos = currentTimeNanos;
+            if (!mAudioEndpoint.isFreeRunning()) {
+                // If there is software on the other end of the FIFO then it may get delayed.
+                // So wake up just a little after we expect it to be ready.
+                wakeTimeNanos += mWakeupDelayNanos;
             }
+
             if (wakeTimeNanos > deadlineNanos) {
                 // If we time out, just return the framesWritten so far.
                 // TODO remove after we fix the deadline bug
-                ALOGE("AudioStreamInternal::processData(): timed out after %lld nanos",
+                ALOGW("AudioStreamInternal::processData(): entered at %lld nanos, currently %lld",
+                      (long long) entryTimeNanos, (long long) currentTimeNanos);
+                ALOGW("AudioStreamInternal::processData(): timed out after %lld nanos",
                       (long long) timeoutNanoseconds);
-                ALOGE("AudioStreamInternal::processData(): wakeTime = %lld, deadline = %lld nanos",
+                ALOGW("AudioStreamInternal::processData(): wakeTime = %lld, deadline = %lld nanos",
                       (long long) wakeTimeNanos, (long long) deadlineNanos);
-                ALOGE("AudioStreamInternal::processData(): past deadline by %d micros",
+                ALOGW("AudioStreamInternal::processData(): past deadline by %d micros",
                       (int)((wakeTimeNanos - deadlineNanos) / AAUDIO_NANOS_PER_MICROSECOND));
+                mClockModel.dump();
+                mAudioEndpoint.dump();
                 break;
             }
 
-            int64_t sleepForNanos = wakeTimeNanos - currentTimeNanos;
-            AudioClock::sleepForNanos(sleepForNanos);
+            currentTimeNanos = AudioClock::getNanoseconds();
+            int64_t earliestWakeTime = currentTimeNanos + mMinimumSleepNanos;
+            // Guarantee a minimum sleep time.
+            if (wakeTimeNanos < earliestWakeTime) {
+                wakeTimeNanos = earliestWakeTime;
+            }
+
+            if (ATRACE_ENABLED()) {
+                int32_t fullFrames = mAudioEndpoint.getFullFramesAvailable();
+                ATRACE_INT(fifoName, fullFrames);
+                int64_t sleepForNanos = wakeTimeNanos - currentTimeNanos;
+                ATRACE_INT("aaSlpNs", (int32_t)sleepForNanos);
+            }
+
+            AudioClock::sleepUntilNanoTime(wakeTimeNanos);
             currentTimeNanos = AudioClock::getNanoseconds();
         }
     }
 
+    if (ATRACE_ENABLED()) {
+        int32_t fullFrames = mAudioEndpoint.getFullFramesAvailable();
+        ATRACE_INT(fifoName, fullFrames);
+    }
+
     // return error or framesProcessed
     (void) loopCount;
     ATRACE_END();
@@ -588,3 +599,32 @@
 aaudio_result_t AudioStreamInternal::joinThread(void** returnArg) {
     return AudioStream::joinThread(returnArg, calculateReasonableTimeout(getFramesPerBurst()));
 }
+
+void AudioStreamInternal::doSetVolume() {
+    // No pan and only left volume is taken into account from IPLayer interface
+    mVolumeRamp.setTarget(mStreamVolume * mVolumeMultiplierL /* * mPanMultiplierL */);
+}
+
+
+//------------------------------------------------------------------------------
+// Implementation of PlayerBase
+status_t AudioStreamInternal::playerStart() {
+    return AAudioConvert_aaudioToAndroidStatus(mServiceInterface.startStream(mServiceStreamHandle));
+}
+
+status_t AudioStreamInternal::playerPause() {
+    return AAudioConvert_aaudioToAndroidStatus(mServiceInterface.pauseStream(mServiceStreamHandle));
+}
+
+status_t AudioStreamInternal::playerStop() {
+    return AAudioConvert_aaudioToAndroidStatus(mServiceInterface.stopStream(mServiceStreamHandle));
+}
+
+status_t AudioStreamInternal::playerSetVolume() {
+    doSetVolume();
+    return NO_ERROR;
+}
+
+void AudioStreamInternal::destroy() {
+    baseDestroy();
+}
diff --git a/media/libaaudio/src/client/AudioStreamInternal.h b/media/libaaudio/src/client/AudioStreamInternal.h
index a11f309..1b991de 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.h
+++ b/media/libaaudio/src/client/AudioStreamInternal.h
@@ -18,6 +18,7 @@
 #define ANDROID_AAUDIO_AUDIO_STREAM_INTERNAL_H
 
 #include <stdint.h>
+#include <media/PlayerBase.h>
 #include <aaudio/AAudio.h>
 
 #include "binding/IAAudioService.h"
@@ -26,6 +27,7 @@
 #include "client/IsochronousClockModel.h"
 #include "client/AudioEndpoint.h"
 #include "core/AudioStream.h"
+#include "utility/AudioClock.h"
 #include "utility/LinearRamp.h"
 
 using android::sp;
@@ -34,19 +36,14 @@
 namespace aaudio {
 
 // A stream that talks to the AAudioService or directly to a HAL.
-class AudioStreamInternal : public AudioStream {
+class AudioStreamInternal : public AudioStream, public android::PlayerBase  {
 
 public:
     AudioStreamInternal(AAudioServiceInterface  &serviceInterface, bool inService);
     virtual ~AudioStreamInternal();
 
-    // =========== Begin ABSTRACT methods ===========================
     aaudio_result_t requestStart() override;
 
-    aaudio_result_t requestPause() override;
-
-    aaudio_result_t requestFlush() override;
-
     aaudio_result_t requestStop() override;
 
     aaudio_result_t getTimestamp(clockid_t clockId,
@@ -54,7 +51,6 @@
                                        int64_t *timeNanoseconds) override;
 
     virtual aaudio_result_t updateStateWhileWaiting() override;
-    // =========== End ABSTRACT methods ===========================
 
     aaudio_result_t open(const AudioStreamBuilder &builder) override;
 
@@ -89,6 +85,14 @@
     // Calculate timeout based on framesPerBurst
     int64_t calculateReasonableTimeout();
 
+    //PlayerBase virtuals
+    virtual void destroy();
+
+    aaudio_result_t startClient(const android::AudioClient& client,
+                                audio_port_handle_t *clientHandle);
+
+    aaudio_result_t stopClient(audio_port_handle_t clientHandle);
+
 protected:
 
     aaudio_result_t processData(void *buffer,
@@ -109,21 +113,30 @@
 
     aaudio_result_t processCommands();
 
-    aaudio_result_t requestPauseInternal();
     aaudio_result_t requestStopInternal();
 
     aaudio_result_t stopCallback();
 
 
-    void onFlushFromServer();
+    virtual void onFlushFromServer() {}
 
     aaudio_result_t onEventFromServer(AAudioServiceMessage *message);
 
     aaudio_result_t onTimestampFromServer(AAudioServiceMessage *message);
 
+    void logTimestamp(AAudioServiceMessage &message);
+
     // Calculate timeout for an operation involving framesPerOperation.
     int64_t calculateReasonableTimeout(int32_t framesPerOperation);
 
+    void doSetVolume();
+
+    //PlayerBase virtuals
+    virtual status_t playerStart();
+    virtual status_t playerPause();
+    virtual status_t playerStop();
+    virtual status_t playerSetVolume();
+
     aaudio_format_t          mDeviceFormat = AAUDIO_FORMAT_UNSPECIFIED;
 
     IsochronousClockModel    mClockModel;      // timing model for chasing the HAL
@@ -135,6 +148,7 @@
     int32_t                  mXRunCount = 0;      // how many underrun events?
 
     LinearRamp               mVolumeRamp;
+    float                    mStreamVolume;
 
     // Offset from underlying frame position.
     int64_t                  mFramesOffsetFromService = 0; // offset for timestamps
@@ -142,6 +156,11 @@
     uint8_t                 *mCallbackBuffer = nullptr;
     int32_t                  mCallbackFrames = 0;
 
+    // The service uses this for SHARED mode.
+    bool                     mInService = false;  // Is this running in the client or the service?
+
+    AAudioServiceInterface  &mServiceInterface;   // abstract interface to the service
+
 private:
     /*
      * Asynchronous write with data conversion.
@@ -155,12 +174,13 @@
     // Adjust timing model based on timestamp from service.
     void processTimestamp(uint64_t position, int64_t time);
 
+    // Thread on other side of FIFO will have wakeup jitter.
+    // By delaying slightly we can avoid waking up before other side is ready.
+    const int32_t            mWakeupDelayNanos; // delay past typical wakeup jitter
+    const int32_t            mMinimumSleepNanos; // minimum sleep while polling
+
     AudioEndpointParcelable  mEndPointParcelable; // description of the buffers filled by service
     EndpointDescriptor       mEndpointDescriptor; // buffer description with resolved addresses
-    AAudioServiceInterface  &mServiceInterface;   // abstract interface to the service
-
-    // The service uses this for SHARED mode.
-    bool                     mInService = false;  // Is this running in the client or the service?
 };
 
 } /* namespace aaudio */
diff --git a/media/libaaudio/src/client/AudioStreamInternalCapture.cpp b/media/libaaudio/src/client/AudioStreamInternalCapture.cpp
index 93693bd..7b1e53e 100644
--- a/media/libaaudio/src/client/AudioStreamInternalCapture.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternalCapture.cpp
@@ -14,15 +14,19 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "AAudio"
+#define LOG_TAG (mInService ? "AAudioService" : "AAudio")
 //#define LOG_NDEBUG 0
 #include <utils/Log.h>
 
+#include <algorithm>
 #include <aaudio/AAudio.h>
 
 #include "client/AudioStreamInternalCapture.h"
 #include "utility/AudioClock.h"
 
+#define ATRACE_TAG ATRACE_TAG_AUDIO
+#include <utils/Trace.h>
+
 using android::WrappingBuffer;
 
 using namespace aaudio;
@@ -35,7 +39,6 @@
 
 AudioStreamInternalCapture::~AudioStreamInternalCapture() {}
 
-
 // Write the data, block if needed and timeoutMillis > 0
 aaudio_result_t AudioStreamInternalCapture::read(void *buffer, int32_t numFrames,
                                                int64_t timeoutNanoseconds)
@@ -51,6 +54,9 @@
         return result;
     }
 
+    const char *traceName = "aaRdNow";
+    ATRACE_BEGIN(traceName);
+
     if (mAudioEndpoint.isFreeRunning()) {
         //ALOGD("AudioStreamInternalCapture::processDataNow() - update remote counter");
         // Update data queue based on the timing model.
@@ -62,6 +68,9 @@
     // If the write index passed the read index then consider it an overrun.
     if (mAudioEndpoint.getEmptyFramesAvailable() < 0) {
         mXRunCount++;
+        if (ATRACE_ENABLED()) {
+            ATRACE_INT("aaOverRuns", mXRunCount);
+        }
     }
 
     // Read some data from the buffer.
@@ -69,6 +78,9 @@
     int32_t framesProcessed = readNowWithConversion(buffer, numFrames);
     //ALOGD("AudioStreamInternalCapture::processDataNow() - tried to read %d frames, read %d",
     //    numFrames, framesProcessed);
+    if (ATRACE_ENABLED()) {
+        ATRACE_INT("aaRead", framesProcessed);
+    }
 
     // Calculate an ideal time to wake up.
     if (wakeTimePtr != nullptr && framesProcessed >= 0) {
@@ -81,14 +93,14 @@
             case AAUDIO_STREAM_STATE_OPEN:
             case AAUDIO_STREAM_STATE_STARTING:
                 break;
-            case AAUDIO_STREAM_STATE_STARTED:   // When do we expect the next read burst to occur?
+            case AAUDIO_STREAM_STATE_STARTED:
             {
-                uint32_t burstSize = mFramesPerBurst;
-                if (burstSize < 32) {
-                    burstSize = 32; // TODO review
-                }
+                // When do we expect the next write burst to occur?
 
-                uint64_t nextReadPosition = mAudioEndpoint.getDataWriteCounter() + burstSize;
+                // Calculate frame position based off of the readCounter because
+                // the writeCounter might have just advanced in the background,
+                // causing us to sleep until a later burst.
+                int64_t nextReadPosition = mAudioEndpoint.getDataReadCounter() + mFramesPerBurst;
                 wakeTime = mClockModel.convertPositionToTime(nextReadPosition);
             }
                 break;
@@ -98,10 +110,8 @@
         *wakeTimePtr = wakeTime;
 
     }
-//    ALOGD("AudioStreamInternalCapture::readNow finished: now = %llu, read# = %llu, wrote# = %llu",
-//         (unsigned long long)currentNanoTime,
-//         (unsigned long long)mAudioEndpoint.getDataReadCounter(),
-//         (unsigned long long)mAudioEndpoint.getDownDataWriteCounter());
+
+    ATRACE_END();
     return framesProcessed;
 }
 
@@ -155,29 +165,27 @@
 
     int32_t framesProcessed = numFrames - framesLeft;
     mAudioEndpoint.advanceReadIndex(framesProcessed);
-    incrementFramesRead(framesProcessed);
 
     //ALOGD("AudioStreamInternalCapture::readNowWithConversion() returns %d", framesProcessed);
     return framesProcessed;
 }
 
-int64_t AudioStreamInternalCapture::getFramesWritten()
-{
-    int64_t frames =
-            mClockModel.convertTimeToPosition(AudioClock::getNanoseconds())
-            + mFramesOffsetFromService;
-    // Prevent retrograde motion.
-    if (frames < mLastFramesWritten) {
-        frames = mLastFramesWritten;
+int64_t AudioStreamInternalCapture::getFramesWritten() {
+    int64_t framesWrittenHardware;
+    if (isActive()) {
+        framesWrittenHardware = mClockModel.convertTimeToPosition(AudioClock::getNanoseconds());
     } else {
-        mLastFramesWritten = frames;
+        framesWrittenHardware = mAudioEndpoint.getDataWriteCounter();
     }
-    //ALOGD("AudioStreamInternalCapture::getFramesWritten() returns %lld", (long long)frames);
-    return frames;
+    // Prevent retrograde motion.
+    mLastFramesWritten = std::max(mLastFramesWritten,
+                                  framesWrittenHardware + mFramesOffsetFromService);
+    //ALOGD("AudioStreamInternalCapture::getFramesWritten() returns %lld",
+    //      (long long)mLastFramesWritten);
+    return mLastFramesWritten;
 }
 
-int64_t AudioStreamInternalCapture::getFramesRead()
-{
+int64_t AudioStreamInternalCapture::getFramesRead() {
     int64_t frames = mAudioEndpoint.getDataWriteCounter()
                                + mFramesOffsetFromService;
     //ALOGD("AudioStreamInternalCapture::getFramesRead() returns %lld", (long long)frames);
diff --git a/media/libaaudio/src/client/AudioStreamInternalPlay.cpp b/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
index fc9766f..31e0a40 100644
--- a/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
@@ -14,10 +14,14 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "AAudio"
+#define LOG_TAG (mInService ? "AAudioService" : "AAudio")
 //#define LOG_NDEBUG 0
 #include <utils/Log.h>
 
+#define ATRACE_TAG ATRACE_TAG_AUDIO
+
+#include <utils/Trace.h>
+
 #include "client/AudioStreamInternalPlay.h"
 #include "utility/AudioClock.h"
 
@@ -34,6 +38,55 @@
 AudioStreamInternalPlay::~AudioStreamInternalPlay() {}
 
 
+aaudio_result_t AudioStreamInternalPlay::requestPauseInternal()
+{
+    if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
+        ALOGE("AudioStreamInternal::requestPauseInternal() mServiceStreamHandle invalid = 0x%08X",
+              mServiceStreamHandle);
+        return AAUDIO_ERROR_INVALID_STATE;
+    }
+
+    mClockModel.stop(AudioClock::getNanoseconds());
+    setState(AAUDIO_STREAM_STATE_PAUSING);
+    return AAudioConvert_androidToAAudioResult(pauseWithStatus());
+}
+
+aaudio_result_t AudioStreamInternalPlay::requestPause()
+{
+    aaudio_result_t result = stopCallback();
+    if (result != AAUDIO_OK) {
+        return result;
+    }
+    result = requestPauseInternal();
+    return result;
+}
+
+aaudio_result_t AudioStreamInternalPlay::requestFlush() {
+    if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
+        ALOGE("AudioStreamInternal::requestFlush() mServiceStreamHandle invalid = 0x%08X",
+              mServiceStreamHandle);
+        return AAUDIO_ERROR_INVALID_STATE;
+    }
+
+    setState(AAUDIO_STREAM_STATE_FLUSHING);
+    return mServiceInterface.flushStream(mServiceStreamHandle);
+}
+
+void AudioStreamInternalPlay::onFlushFromServer() {
+    int64_t readCounter = mAudioEndpoint.getDataReadCounter();
+    int64_t writeCounter = mAudioEndpoint.getDataWriteCounter();
+
+    // Bump offset so caller does not see the retrograde motion in getFramesRead().
+    int64_t framesFlushed = writeCounter - readCounter;
+    mFramesOffsetFromService += framesFlushed;
+    ALOGD("AudioStreamInternal::onFlushFromServer() readN = %lld, writeN = %lld, offset = %lld",
+          (long long)readCounter, (long long)writeCounter, (long long)mFramesOffsetFromService);
+
+    // Flush written frames by forcing writeCounter to readCounter.
+    // This is because we cannot move the read counter in the hardware.
+    mAudioEndpoint.setDataWriteCounter(readCounter);
+}
+
 // Write the data, block if needed and timeoutMillis > 0
 aaudio_result_t AudioStreamInternalPlay::write(const void *buffer, int32_t numFrames,
                                            int64_t timeoutNanoseconds)
@@ -50,17 +103,23 @@
         return result;
     }
 
+    const char *traceName = "aaWrNow";
+    ATRACE_BEGIN(traceName);
+
+    // If a DMA channel or DSP is reading the other end then we have to update the readCounter.
     if (mAudioEndpoint.isFreeRunning()) {
-        //ALOGD("AudioStreamInternal::processDataNow() - update read counter");
         // Update data queue based on the timing model.
         int64_t estimatedReadCounter = mClockModel.convertTimeToPosition(currentNanoTime);
+        // ALOGD("AudioStreamInternal::processDataNow() - estimatedReadCounter = %d", (int)estimatedReadCounter);
         mAudioEndpoint.setDataReadCounter(estimatedReadCounter);
     }
-    // TODO else query from endpoint cuz set by actual reader, maybe
 
     // If the read index passed the write index then consider it an underrun.
     if (mAudioEndpoint.getFullFramesAvailable() < 0) {
         mXRunCount++;
+        if (ATRACE_ENABLED()) {
+            ATRACE_INT("aaUnderRuns", mXRunCount);
+        }
     }
 
     // Write some data to the buffer.
@@ -68,6 +127,9 @@
     int32_t framesWritten = writeNowWithConversion(buffer, numFrames);
     //ALOGD("AudioStreamInternal::processDataNow() - tried to write %d frames, wrote %d",
     //    numFrames, framesWritten);
+    if (ATRACE_ENABLED()) {
+        ATRACE_INT("aaWrote", framesWritten);
+    }
 
     // Calculate an ideal time to wake up.
     if (wakeTimePtr != nullptr && framesWritten >= 0) {
@@ -84,14 +146,15 @@
                     wakeTime = currentNanoTime;
                 }
                 break;
-            case AAUDIO_STREAM_STATE_STARTED:   // When do we expect the next read burst to occur?
+            case AAUDIO_STREAM_STATE_STARTED:
             {
-                uint32_t burstSize = mFramesPerBurst;
-                if (burstSize < 32) {
-                    burstSize = 32; // TODO review
-                }
+                // When do we expect the next read burst to occur?
 
-                uint64_t nextReadPosition = mAudioEndpoint.getDataReadCounter() + burstSize;
+                // Calculate frame position based off of the writeCounter because
+                // the readCounter might have just advanced in the background,
+                // causing us to sleep until a later burst.
+                int64_t nextReadPosition = mAudioEndpoint.getDataWriteCounter() + mFramesPerBurst
+                        - mAudioEndpoint.getBufferSizeInFrames();
                 wakeTime = mClockModel.convertPositionToTime(nextReadPosition);
             }
                 break;
@@ -101,10 +164,8 @@
         *wakeTimePtr = wakeTime;
 
     }
-//    ALOGD("AudioStreamInternal::processDataNow finished: now = %llu, read# = %llu, wrote# = %llu",
-//         (unsigned long long)currentNanoTime,
-//         (unsigned long long)mAudioEndpoint.getDataReadCounter(),
-//         (unsigned long long)mAudioEndpoint.getDownDataWriteCounter());
+
+    ATRACE_END();
     return framesWritten;
 }
 
@@ -119,7 +180,7 @@
 
     mAudioEndpoint.getEmptyFramesAvailable(&wrappingBuffer);
 
-    // Read data in one or two parts.
+    // Write data in one or two parts.
     int partIndex = 0;
     while (framesLeft > 0 && partIndex < WrappingBuffer::SIZE) {
         int32_t framesToWrite = framesLeft;
@@ -201,9 +262,6 @@
     int32_t framesWritten = numFrames - framesLeft;
     mAudioEndpoint.advanceWriteIndex(framesWritten);
 
-    if (framesWritten > 0) {
-        incrementFramesWritten(framesWritten);
-    }
     // ALOGD("AudioStreamInternal::writeNowWithConversion() returns %d", framesWritten);
     return framesWritten;
 }
@@ -211,25 +269,29 @@
 
 int64_t AudioStreamInternalPlay::getFramesRead()
 {
-    int64_t framesRead =
-            mClockModel.convertTimeToPosition(AudioClock::getNanoseconds())
-            + mFramesOffsetFromService;
+    int64_t framesReadHardware;
+    if (isActive()) {
+        framesReadHardware = mClockModel.convertTimeToPosition(AudioClock::getNanoseconds());
+    } else {
+        framesReadHardware = mAudioEndpoint.getDataReadCounter();
+    }
+    int64_t framesRead = framesReadHardware + mFramesOffsetFromService;
     // Prevent retrograde motion.
     if (framesRead < mLastFramesRead) {
         framesRead = mLastFramesRead;
     } else {
         mLastFramesRead = framesRead;
     }
-    ALOGD("AudioStreamInternal::getFramesRead() returns %lld", (long long)framesRead);
+    //ALOGD("AudioStreamInternalPlay::getFramesRead() returns %lld", (long long)framesRead);
     return framesRead;
 }
 
 int64_t AudioStreamInternalPlay::getFramesWritten()
 {
-    int64_t getFramesWritten = mAudioEndpoint.getDataWriteCounter()
+    int64_t framesWritten = mAudioEndpoint.getDataWriteCounter()
                                + mFramesOffsetFromService;
-    ALOGD("AudioStreamInternal::getFramesWritten() returns %lld", (long long)getFramesWritten);
-    return getFramesWritten;
+    //ALOGD("AudioStreamInternalPlay::getFramesWritten() returns %lld", (long long)framesWritten);
+    return framesWritten;
 }
 
 
@@ -239,6 +301,7 @@
     aaudio_data_callback_result_t callbackResult = AAUDIO_CALLBACK_RESULT_CONTINUE;
     AAudioStream_dataCallback appCallback = getDataCallbackProc();
     if (appCallback == nullptr) return NULL;
+    int64_t timeoutNanos = calculateReasonableTimeout(mCallbackFrames);
 
     // result might be a frame count
     while (mCallbackEnabled.load() && isActive() && (result >= 0)) {
@@ -250,10 +313,7 @@
                 mCallbackFrames);
 
         if (callbackResult == AAUDIO_CALLBACK_RESULT_CONTINUE) {
-            // Write audio data to stream.
-            int64_t timeoutNanos = calculateReasonableTimeout(mCallbackFrames);
-
-            // This is a BLOCKING WRITE!
+            // Write audio data to stream. This is a BLOCKING WRITE!
             result = write(mCallbackBuffer, mCallbackFrames, timeoutNanos);
             if ((result != mCallbackFrames)) {
                 ALOGE("AudioStreamInternalPlay(): callbackLoop: write() returned %d", result);
diff --git a/media/libaaudio/src/client/AudioStreamInternalPlay.h b/media/libaaudio/src/client/AudioStreamInternalPlay.h
index b043f67..e59d02c 100644
--- a/media/libaaudio/src/client/AudioStreamInternalPlay.h
+++ b/media/libaaudio/src/client/AudioStreamInternalPlay.h
@@ -33,6 +33,10 @@
     AudioStreamInternalPlay(AAudioServiceInterface  &serviceInterface, bool inService = false);
     virtual ~AudioStreamInternalPlay();
 
+    aaudio_result_t requestPause() override;
+
+    aaudio_result_t requestFlush() override;
+
     aaudio_result_t write(const void *buffer,
                           int32_t numFrames,
                           int64_t timeoutNanoseconds) override;
@@ -47,6 +51,11 @@
     }
 
 protected:
+
+    aaudio_result_t requestPauseInternal();
+
+    void onFlushFromServer() override;
+
 /**
  * Low level write that will not block. It will just write as much as it can.
  *
diff --git a/media/libaaudio/src/client/IsochronousClockModel.cpp b/media/libaaudio/src/client/IsochronousClockModel.cpp
index 1de33bb..4d0a7b8 100644
--- a/media/libaaudio/src/client/IsochronousClockModel.cpp
+++ b/media/libaaudio/src/client/IsochronousClockModel.cpp
@@ -41,6 +41,13 @@
 IsochronousClockModel::~IsochronousClockModel() {
 }
 
+void IsochronousClockModel::setPositionAndTime(int64_t framePosition, int64_t nanoTime) {
+    ALOGV("IsochronousClockModel::setPositionAndTime(%lld, %lld)",
+          (long long) framePosition, (long long) nanoTime);
+    mMarkerFramePosition = framePosition;
+    mMarkerNanoTime = nanoTime;
+}
+
 void IsochronousClockModel::start(int64_t nanoTime) {
     ALOGD("IsochronousClockModel::start(nanos = %lld)\n", (long long) nanoTime);
     mMarkerNanoTime = nanoTime;
@@ -49,8 +56,8 @@
 
 void IsochronousClockModel::stop(int64_t nanoTime) {
     ALOGD("IsochronousClockModel::stop(nanos = %lld)\n", (long long) nanoTime);
-    mMarkerNanoTime = nanoTime;
-    mMarkerFramePosition = convertTimeToPosition(nanoTime); // TODO should we do this?
+    setPositionAndTime(convertTimeToPosition(nanoTime), nanoTime);
+    // TODO should we set position?
     mState = STATE_STOPPED;
 }
 
@@ -79,15 +86,13 @@
     case STATE_STOPPED:
         break;
     case STATE_STARTING:
-        mMarkerFramePosition = framePosition;
-        mMarkerNanoTime = nanoTime;
+        setPositionAndTime(framePosition, nanoTime);
         mState = STATE_SYNCING;
         break;
     case STATE_SYNCING:
         // This will handle a burst of rapid transfer at the beginning.
         if (nanosDelta < expectedNanosDelta) {
-            mMarkerFramePosition = framePosition;
-            mMarkerNanoTime = nanoTime;
+            setPositionAndTime(framePosition, nanoTime);
         } else {
 //            ALOGD("processTimestamp() - advance to STATE_RUNNING");
             mState = STATE_RUNNING;
@@ -98,17 +103,15 @@
             // Earlier than expected timestamp.
             // This data is probably more accurate so use it.
             // or we may be drifting due to a slow HW clock.
-            mMarkerFramePosition = framePosition;
-            mMarkerNanoTime = nanoTime;
 //            ALOGD("processTimestamp() - STATE_RUNNING - %d < %d micros - EARLY",
 //                 (int) (nanosDelta / 1000), (int)(expectedNanosDelta / 1000));
+            setPositionAndTime(framePosition, nanoTime);
         } else if (nanosDelta > (expectedNanosDelta + mMaxLatenessInNanos)) {
             // Later than expected timestamp.
-            mMarkerFramePosition = framePosition;
-            mMarkerNanoTime = nanoTime - mMaxLatenessInNanos;
 //            ALOGD("processTimestamp() - STATE_RUNNING - %d > %d + %d micros - LATE",
 //                 (int) (nanosDelta / 1000), (int)(expectedNanosDelta / 1000),
 //                 (int) (mMaxLatenessInNanos / 1000));
+            setPositionAndTime(framePosition - mFramesPerBurst,  nanoTime - mMaxLatenessInNanos);
         }
         break;
     default:
@@ -131,8 +134,7 @@
     mMaxLatenessInNanos = (nanosLate > MIN_LATENESS_NANOS) ? nanosLate : MIN_LATENESS_NANOS;
 }
 
-int64_t IsochronousClockModel::convertDeltaPositionToTime(
-        int64_t framesDelta) const {
+int64_t IsochronousClockModel::convertDeltaPositionToTime(int64_t framesDelta) const {
     return (AAUDIO_NANOS_PER_SECOND * framesDelta) / mSampleRate;
 }
 
@@ -148,7 +150,7 @@
     int64_t nextBurstPosition = mFramesPerBurst * nextBurstIndex;
     int64_t framesDelta = nextBurstPosition - mMarkerFramePosition;
     int64_t nanosDelta = convertDeltaPositionToTime(framesDelta);
-    int64_t time = (int64_t) (mMarkerNanoTime + nanosDelta);
+    int64_t time = mMarkerNanoTime + nanosDelta;
 //    ALOGD("IsochronousClockModel::convertPositionToTime: pos = %llu --> time = %llu",
 //         (unsigned long long)framePosition,
 //         (unsigned long long)time);
@@ -171,3 +173,12 @@
 //         (long long) framesDelta, mFramesPerBurst);
     return position;
 }
+
+void IsochronousClockModel::dump() const {
+    ALOGD("IsochronousClockModel::mMarkerFramePosition = %lld", (long long) mMarkerFramePosition);
+    ALOGD("IsochronousClockModel::mMarkerNanoTime      = %lld", (long long) mMarkerNanoTime);
+    ALOGD("IsochronousClockModel::mSampleRate          = %6d", mSampleRate);
+    ALOGD("IsochronousClockModel::mFramesPerBurst      = %6d", mFramesPerBurst);
+    ALOGD("IsochronousClockModel::mMaxLatenessInNanos  = %6d", mMaxLatenessInNanos);
+    ALOGD("IsochronousClockModel::mState               = %6d", mState);
+}
diff --git a/media/libaaudio/src/client/IsochronousClockModel.h b/media/libaaudio/src/client/IsochronousClockModel.h
index 0314f55..585f53a 100644
--- a/media/libaaudio/src/client/IsochronousClockModel.h
+++ b/media/libaaudio/src/client/IsochronousClockModel.h
@@ -43,6 +43,8 @@
      */
     void setSampleRate(int32_t sampleRate);
 
+    void setPositionAndTime(int64_t framePosition, int64_t nanoTime);
+
     int32_t getSampleRate() const {
         return mSampleRate;
     }
@@ -86,6 +88,8 @@
      */
     int64_t convertDeltaTimeToPosition(int64_t nanosDelta) const;
 
+    void dump() const;
+
 private:
     enum clock_model_state_t {
         STATE_STOPPED,
diff --git a/media/libaaudio/src/core/AAudioAudio.cpp b/media/libaaudio/src/core/AAudioAudio.cpp
index 76f98fa..3f5de77 100644
--- a/media/libaaudio/src/core/AAudioAudio.cpp
+++ b/media/libaaudio/src/core/AAudioAudio.cpp
@@ -253,8 +253,10 @@
 AAUDIO_API aaudio_result_t  AAudioStream_requestStart(AAudioStream* stream)
 {
     AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
-    ALOGD("AAudioStream_requestStart(%p)", stream);
-    return audioStream->requestStart();
+    ALOGD("AAudioStream_requestStart(%p) called --------------", stream);
+    aaudio_result_t result = audioStream->requestStart();
+    ALOGD("AAudioStream_requestStart(%p) returned ------------", stream);
+    return result;
 }
 
 AAUDIO_API aaudio_result_t  AAudioStream_requestPause(AAudioStream* stream)
diff --git a/media/libaaudio/src/core/AAudioStreamParameters.cpp b/media/libaaudio/src/core/AAudioStreamParameters.cpp
new file mode 100644
index 0000000..65c2b46
--- /dev/null
+++ b/media/libaaudio/src/core/AAudioStreamParameters.cpp
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#define LOG_TAG "AAudio"
+#include <utils/Log.h>
+#include <hardware/audio.h>
+
+#include "AAudioStreamParameters.h"
+
+using namespace aaudio;
+
+// TODO These defines should be moved to a central place in audio.
+#define SAMPLES_PER_FRAME_MIN        1
+// TODO Remove 8 channel limitation.
+#define SAMPLES_PER_FRAME_MAX        FCC_8
+#define SAMPLE_RATE_HZ_MIN           8000
+// HDMI supports up to 32 channels at 1536000 Hz.
+#define SAMPLE_RATE_HZ_MAX           1600000
+
+AAudioStreamParameters::AAudioStreamParameters() {}
+AAudioStreamParameters::~AAudioStreamParameters() {}
+
+aaudio_result_t AAudioStreamParameters::validate() const {
+    if (mSamplesPerFrame != AAUDIO_UNSPECIFIED
+        && (mSamplesPerFrame < SAMPLES_PER_FRAME_MIN || mSamplesPerFrame > SAMPLES_PER_FRAME_MAX)) {
+        ALOGE("AAudioStreamParameters: channelCount out of range = %d", mSamplesPerFrame);
+        return AAUDIO_ERROR_OUT_OF_RANGE;
+    }
+
+    if (mDeviceId < 0) {
+        ALOGE("AAudioStreamParameters: deviceId out of range = %d", mDeviceId);
+        return AAUDIO_ERROR_OUT_OF_RANGE;
+    }
+
+    switch (mSharingMode) {
+        case AAUDIO_SHARING_MODE_EXCLUSIVE:
+        case AAUDIO_SHARING_MODE_SHARED:
+            break;
+        default:
+            ALOGE("AAudioStreamParameters: illegal sharingMode = %d", mSharingMode);
+            return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
+            // break;
+    }
+
+    switch (mAudioFormat) {
+        case AAUDIO_FORMAT_UNSPECIFIED:
+        case AAUDIO_FORMAT_PCM_I16:
+        case AAUDIO_FORMAT_PCM_FLOAT:
+            break; // valid
+        default:
+            ALOGE("AAudioStreamParameters: audioFormat not valid = %d", mAudioFormat);
+            return AAUDIO_ERROR_INVALID_FORMAT;
+            // break;
+    }
+
+    if (mSampleRate != AAUDIO_UNSPECIFIED
+        && (mSampleRate < SAMPLE_RATE_HZ_MIN || mSampleRate > SAMPLE_RATE_HZ_MAX)) {
+        ALOGE("AAudioStreamParameters: sampleRate out of range = %d", mSampleRate);
+        return AAUDIO_ERROR_INVALID_RATE;
+    }
+
+    if (mBufferCapacity < 0) {
+        ALOGE("AAudioStreamParameters: bufferCapacity out of range = %d", mBufferCapacity);
+        return AAUDIO_ERROR_OUT_OF_RANGE;
+    }
+
+    return AAUDIO_OK;
+}
+
+void AAudioStreamParameters::dump() const {
+    ALOGD("AAudioStreamParameters mDeviceId        = %d", mDeviceId);
+    ALOGD("AAudioStreamParameters mSampleRate      = %d", mSampleRate);
+    ALOGD("AAudioStreamParameters mSamplesPerFrame = %d", mSamplesPerFrame);
+    ALOGD("AAudioStreamParameters mSharingMode     = %d", (int)mSharingMode);
+    ALOGD("AAudioStreamParameters mAudioFormat     = %d", (int)mAudioFormat);
+    ALOGD("AAudioStreamParameters mBufferCapacity  = %d", mBufferCapacity);
+}
\ No newline at end of file
diff --git a/media/libaaudio/src/core/AAudioStreamParameters.h b/media/libaaudio/src/core/AAudioStreamParameters.h
new file mode 100644
index 0000000..97379cc
--- /dev/null
+++ b/media/libaaudio/src/core/AAudioStreamParameters.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAUDIO_STREAM_PARAMETERS_H
+#define AAUDIO_STREAM_PARAMETERS_H
+
+#include <stdint.h>
+
+#include <aaudio/AAudio.h>
+
+namespace aaudio {
+
+class AAudioStreamParameters {
+public:
+    AAudioStreamParameters();
+    virtual ~AAudioStreamParameters();
+
+    int32_t getDeviceId() const {
+        return mDeviceId;
+    }
+
+    void setDeviceId(int32_t deviceId) {
+        mDeviceId = deviceId;
+    }
+
+    int32_t getSampleRate() const {
+        return mSampleRate;
+    }
+
+    void setSampleRate(int32_t sampleRate) {
+        mSampleRate = sampleRate;
+    }
+
+    int32_t getSamplesPerFrame() const {
+        return mSamplesPerFrame;
+    }
+
+    /**
+     * This is also known as channelCount.
+     */
+    void setSamplesPerFrame(int32_t samplesPerFrame) {
+        mSamplesPerFrame = samplesPerFrame;
+    }
+
+    aaudio_format_t getFormat() const {
+        return mAudioFormat;
+    }
+
+    void setFormat(aaudio_format_t audioFormat) {
+        mAudioFormat = audioFormat;
+    }
+
+    aaudio_sharing_mode_t getSharingMode() const {
+        return mSharingMode;
+    }
+
+    void setSharingMode(aaudio_sharing_mode_t sharingMode) {
+        mSharingMode = sharingMode;
+    }
+
+    int32_t getBufferCapacity() const {
+        return mBufferCapacity;
+    }
+
+    void setBufferCapacity(int32_t frames) {
+        mBufferCapacity = frames;
+    }
+
+    virtual aaudio_result_t validate() const;
+
+    void dump() const;
+
+private:
+    int32_t                    mSamplesPerFrame = AAUDIO_UNSPECIFIED;
+    int32_t                    mSampleRate      = AAUDIO_UNSPECIFIED;
+    int32_t                    mDeviceId        = AAUDIO_UNSPECIFIED;
+    aaudio_sharing_mode_t      mSharingMode     = AAUDIO_SHARING_MODE_SHARED;
+    aaudio_format_t            mAudioFormat     = AAUDIO_FORMAT_UNSPECIFIED;
+    int32_t                    mBufferCapacity  = AAUDIO_UNSPECIFIED;
+};
+
+} /* namespace aaudio */
+
+#endif //AAUDIO_STREAM_PARAMETERS_H
\ No newline at end of file
diff --git a/media/libaaudio/src/core/AudioStream.cpp b/media/libaaudio/src/core/AudioStream.cpp
index e1e3c55..4859c69 100644
--- a/media/libaaudio/src/core/AudioStream.cpp
+++ b/media/libaaudio/src/core/AudioStream.cpp
@@ -36,8 +36,30 @@
     setPeriodNanoseconds(0);
 }
 
+static const char *AudioStream_convertSharingModeToShortText(aaudio_sharing_mode_t sharingMode) {
+    const char *result;
+    switch (sharingMode) {
+        case AAUDIO_SHARING_MODE_EXCLUSIVE:
+            result = "EX";
+            break;
+        case AAUDIO_SHARING_MODE_SHARED:
+            result = "SH";
+            break;
+        default:
+            result = "?!";
+            break;
+    }
+    return result;
+}
+
 aaudio_result_t AudioStream::open(const AudioStreamBuilder& builder)
 {
+    // Call here as well because the AAudioService will call this without calling build().
+    aaudio_result_t result = builder.validate();
+    if (result != AAUDIO_OK) {
+        return result;
+    }
+
     // Copy parameters from the Builder because the Builder may be deleted after this call.
     mSamplesPerFrame = builder.getSamplesPerFrame();
     mSampleRate = builder.getSampleRate();
@@ -56,44 +78,14 @@
     mErrorCallbackUserData = builder.getErrorCallbackUserData();
 
     // This is very helpful for debugging in the future. Please leave it in.
-    ALOGI("AudioStream::open() rate = %d, channels = %d, format = %d, sharing = %d, dir = %s",
-          mSampleRate, mSamplesPerFrame, mFormat, mSharingMode,
+    ALOGI("AudioStream::open() rate = %d, channels = %d, format = %d, sharing = %s, dir = %s",
+          mSampleRate, mSamplesPerFrame, mFormat,
+          AudioStream_convertSharingModeToShortText(mSharingMode),
           (getDirection() == AAUDIO_DIRECTION_OUTPUT) ? "OUTPUT" : "INPUT");
-    ALOGI("AudioStream::open() device = %d, perfMode = %d, callbackFrames = %d",
-          mDeviceId, mPerformanceMode, mFramesPerDataCallback);
-
-    // Check for values that are ridiculously out of range to prevent math overflow exploits.
-    // The service will do a better check.
-    if (mSamplesPerFrame < 0 || mSamplesPerFrame > 128) {
-        ALOGE("AudioStream::open(): samplesPerFrame out of range = %d", mSamplesPerFrame);
-        return AAUDIO_ERROR_OUT_OF_RANGE;
-    }
-
-    switch(mFormat) {
-        case AAUDIO_FORMAT_UNSPECIFIED:
-        case AAUDIO_FORMAT_PCM_I16:
-        case AAUDIO_FORMAT_PCM_FLOAT:
-            break; // valid
-        default:
-            ALOGE("AudioStream::open(): audioFormat not valid = %d", mFormat);
-            return AAUDIO_ERROR_INVALID_FORMAT;
-            // break;
-    }
-
-    if (mSampleRate != AAUDIO_UNSPECIFIED && (mSampleRate < 8000 || mSampleRate > 1000000)) {
-        ALOGE("AudioStream::open(): mSampleRate out of range = %d", mSampleRate);
-        return AAUDIO_ERROR_INVALID_RATE;
-    }
-
-    switch(mPerformanceMode) {
-        case AAUDIO_PERFORMANCE_MODE_NONE:
-        case AAUDIO_PERFORMANCE_MODE_POWER_SAVING:
-        case AAUDIO_PERFORMANCE_MODE_LOW_LATENCY:
-            break;
-        default:
-            ALOGE("AudioStream::open(): illegal performanceMode %d", mPerformanceMode);
-            return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
-    }
+    ALOGI("AudioStream::open() device = %d, perfMode = %d, callback: %s with frames = %d",
+          mDeviceId, mPerformanceMode,
+          (mDataCallbackProc == nullptr ? "OFF" : "ON"),
+          mFramesPerDataCallback);
 
     return AAUDIO_OK;
 }
diff --git a/media/libaaudio/src/core/AudioStream.h b/media/libaaudio/src/core/AudioStream.h
index 39c9f9c..e5fdcc6 100644
--- a/media/libaaudio/src/core/AudioStream.h
+++ b/media/libaaudio/src/core/AudioStream.h
@@ -48,8 +48,18 @@
      * Use waitForStateChange() to wait for completion.
      */
     virtual aaudio_result_t requestStart() = 0;
-    virtual aaudio_result_t requestPause() = 0;
-    virtual aaudio_result_t requestFlush() = 0;
+
+    virtual aaudio_result_t requestPause()
+    {
+        // Only implement this for OUTPUT streams.
+        return AAUDIO_ERROR_UNIMPLEMENTED;
+    }
+
+    virtual aaudio_result_t requestFlush() {
+        // Only implement this for OUTPUT streams.
+        return AAUDIO_ERROR_UNIMPLEMENTED;
+    }
+
     virtual aaudio_result_t requestStop() = 0;
 
     virtual aaudio_result_t getTimestamp(clockid_t clockId,
@@ -84,9 +94,7 @@
         return AAUDIO_OK;
     }
 
-    virtual aaudio_result_t setBufferSize(int32_t requestedFrames) {
-        return AAUDIO_ERROR_UNIMPLEMENTED;
-    }
+    virtual aaudio_result_t setBufferSize(int32_t requestedFrames) = 0;
 
     virtual aaudio_result_t createThread(int64_t periodNanoseconds,
                                        aaudio_audio_thread_proc_t threadProc,
@@ -186,13 +194,9 @@
         return AAudioConvert_formatToSizeInBytes(mFormat);
     }
 
-    virtual int64_t getFramesWritten() {
-        return mFramesWritten.get();
-    }
+    virtual int64_t getFramesWritten() = 0;
 
-    virtual int64_t getFramesRead() {
-        return mFramesRead.get();
-    }
+    virtual int64_t getFramesRead() = 0;
 
     AAudioStream_dataCallback getDataCallbackProc() const {
         return mDataCallbackProc;
@@ -218,27 +222,20 @@
 
     // ============== I/O ===========================
     // A Stream will only implement read() or write() depending on its direction.
-    virtual aaudio_result_t write(const void *buffer,
-                             int32_t numFrames,
-                             int64_t timeoutNanoseconds) {
+    virtual aaudio_result_t write(const void *buffer __unused,
+                             int32_t numFrames __unused,
+                             int64_t timeoutNanoseconds __unused) {
         return AAUDIO_ERROR_UNIMPLEMENTED;
     }
 
-    virtual aaudio_result_t read(void *buffer,
-                            int32_t numFrames,
-                            int64_t timeoutNanoseconds) {
+    virtual aaudio_result_t read(void *buffer __unused,
+                            int32_t numFrames __unused,
+                            int64_t timeoutNanoseconds __unused) {
         return AAUDIO_ERROR_UNIMPLEMENTED;
     }
 
 protected:
 
-    virtual int64_t incrementFramesWritten(int32_t frames) {
-        return mFramesWritten.increment(frames);
-    }
-
-    virtual int64_t incrementFramesRead(int32_t frames) {
-        return mFramesRead.increment(frames);
-    }
 
     /**
      * This should not be called after the open() call.
@@ -281,8 +278,6 @@
     std::atomic<bool>    mCallbackEnabled;
 
 protected:
-    MonotonicCounter     mFramesWritten;
-    MonotonicCounter     mFramesRead;
 
     void setPeriodNanoseconds(int64_t periodNanoseconds) {
         mPeriodNanoseconds.store(periodNanoseconds, std::memory_order_release);
diff --git a/media/libaaudio/src/core/AudioStreamBuilder.cpp b/media/libaaudio/src/core/AudioStreamBuilder.cpp
index 4262f27..43a1ef1 100644
--- a/media/libaaudio/src/core/AudioStreamBuilder.cpp
+++ b/media/libaaudio/src/core/AudioStreamBuilder.cpp
@@ -37,6 +37,19 @@
 #define AAUDIO_MMAP_POLICY_DEFAULT             AAUDIO_POLICY_NEVER
 #define AAUDIO_MMAP_EXCLUSIVE_POLICY_DEFAULT   AAUDIO_POLICY_NEVER
 
+// These values are for a pre-check before we ask the lower level service to open a stream.
+// So they are just outside the maximum conceivable range of value,
+// on the edge of being ridiculous.
+// TODO These defines should be moved to a central place in audio.
+#define SAMPLES_PER_FRAME_MIN        1
+// TODO Remove 8 channel limitation.
+#define SAMPLES_PER_FRAME_MAX        FCC_8
+#define SAMPLE_RATE_HZ_MIN           8000
+// HDMI supports up to 32 channels at 1536000 Hz.
+#define SAMPLE_RATE_HZ_MAX           1600000
+#define FRAMES_PER_DATA_CALLBACK_MIN 1
+#define FRAMES_PER_DATA_CALLBACK_MAX (1024 * 1024)
+
 /*
  * AudioStreamBuilder
  */
@@ -85,8 +98,17 @@
 // Exact behavior is controlled by MMapPolicy.
 aaudio_result_t AudioStreamBuilder::build(AudioStream** streamPtr) {
     AudioStream *audioStream = nullptr;
+    if (streamPtr == nullptr) {
+        ALOGE("AudioStreamBuilder::build() streamPtr is null");
+        return AAUDIO_ERROR_NULL;
+    }
     *streamPtr = nullptr;
 
+    aaudio_result_t result = validate();
+    if (result != AAUDIO_OK) {
+        return result;
+    }
+
     // The API setting is the highest priority.
     aaudio_policy_t mmapPolicy = AAudio_getMMapPolicy();
     // If not specified then get from a system property.
@@ -116,8 +138,13 @@
     bool allowMMap = mmapPolicy != AAUDIO_POLICY_NEVER;
     bool allowLegacy = mmapPolicy != AAUDIO_POLICY_ALWAYS;
 
-    aaudio_result_t result = builder_createStream(getDirection(), sharingMode,
-                                                  allowMMap, &audioStream);
+    // TODO Support other performance settings in MMAP mode.
+    // Disable MMAP if low latency not requested.
+    if (getPerformanceMode() != AAUDIO_PERFORMANCE_MODE_LOW_LATENCY) {
+        allowMMap = false;
+    }
+
+    result = builder_createStream(getDirection(), sharingMode, allowMMap, &audioStream);
     if (result == AAUDIO_OK) {
         // Open the stream using the parameters from the builder.
         result = audioStream->open(*this);
@@ -147,3 +174,45 @@
 
     return result;
 }
+
+aaudio_result_t AudioStreamBuilder::validate() const {
+
+    // Check for values that are ridiculously out of range to prevent math overflow exploits.
+    // The service will do a better check.
+    aaudio_result_t result = AAudioStreamParameters::validate();
+    if (result != AAUDIO_OK) {
+        return result;
+    }
+
+    switch (mDirection) {
+        case AAUDIO_DIRECTION_INPUT:
+        case AAUDIO_DIRECTION_OUTPUT:
+            break; // valid
+        default:
+            ALOGE("AudioStreamBuilder: direction not valid = %d", mDirection);
+            return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
+            // break;
+    }
+
+    switch (mPerformanceMode) {
+        case AAUDIO_PERFORMANCE_MODE_NONE:
+        case AAUDIO_PERFORMANCE_MODE_POWER_SAVING:
+        case AAUDIO_PERFORMANCE_MODE_LOW_LATENCY:
+            break;
+        default:
+            ALOGE("AudioStreamBuilder: illegal performanceMode = %d", mPerformanceMode);
+            return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
+            // break;
+    }
+
+    // Prevent ridiculous values from causing problems.
+    if (mFramesPerDataCallback != AAUDIO_UNSPECIFIED
+        && (mFramesPerDataCallback < FRAMES_PER_DATA_CALLBACK_MIN
+            || mFramesPerDataCallback > FRAMES_PER_DATA_CALLBACK_MAX)) {
+        ALOGE("AudioStreamBuilder: framesPerDataCallback out of range = %d",
+              mFramesPerDataCallback);
+        return AAUDIO_ERROR_OUT_OF_RANGE;
+    }
+
+    return AAUDIO_OK;
+}
diff --git a/media/libaaudio/src/core/AudioStreamBuilder.h b/media/libaaudio/src/core/AudioStreamBuilder.h
index fd416c4..6e548b1 100644
--- a/media/libaaudio/src/core/AudioStreamBuilder.h
+++ b/media/libaaudio/src/core/AudioStreamBuilder.h
@@ -21,6 +21,7 @@
 
 #include <aaudio/AAudio.h>
 
+#include "AAudioStreamParameters.h"
 #include "AudioStream.h"
 
 namespace aaudio {
@@ -28,24 +29,12 @@
 /**
  * Factory class for an AudioStream.
  */
-class AudioStreamBuilder {
+class AudioStreamBuilder : public AAudioStreamParameters {
 public:
     AudioStreamBuilder();
 
     ~AudioStreamBuilder();
 
-    int getSamplesPerFrame() const {
-        return mSamplesPerFrame;
-    }
-
-    /**
-     * This is also known as channelCount.
-     */
-    AudioStreamBuilder* setSamplesPerFrame(int samplesPerFrame) {
-        mSamplesPerFrame = samplesPerFrame;
-        return this;
-    }
-
     aaudio_direction_t getDirection() const {
         return mDirection;
     }
@@ -55,33 +44,6 @@
         return this;
     }
 
-    int32_t getSampleRate() const {
-        return mSampleRate;
-    }
-
-    AudioStreamBuilder* setSampleRate(int32_t sampleRate) {
-        mSampleRate = sampleRate;
-        return this;
-    }
-
-    aaudio_format_t getFormat() const {
-        return mFormat;
-    }
-
-    AudioStreamBuilder *setFormat(aaudio_format_t format) {
-        mFormat = format;
-        return this;
-    }
-
-    aaudio_sharing_mode_t getSharingMode() const {
-        return mSharingMode;
-    }
-
-    AudioStreamBuilder* setSharingMode(aaudio_sharing_mode_t sharingMode) {
-        mSharingMode = sharingMode;
-        return this;
-    }
-
     bool isSharingModeMatchRequired() const {
         return mSharingModeMatchRequired;
     }
@@ -91,15 +53,6 @@
         return this;
     }
 
-    int32_t getBufferCapacity() const {
-        return mBufferCapacity;
-    }
-
-    AudioStreamBuilder* setBufferCapacity(int32_t frames) {
-        mBufferCapacity = frames;
-        return this;
-    }
-
     int32_t getPerformanceMode() const {
         return mPerformanceMode;
     }
@@ -109,15 +62,6 @@
         return this;
     }
 
-    int32_t getDeviceId() const {
-        return mDeviceId;
-    }
-
-    AudioStreamBuilder* setDeviceId(int32_t deviceId) {
-        mDeviceId = deviceId;
-        return this;
-    }
-
     AAudioStream_dataCallback getDataCallbackProc() const {
         return mDataCallbackProc;
     }
@@ -165,15 +109,11 @@
 
     aaudio_result_t build(AudioStream **streamPtr);
 
+    virtual aaudio_result_t validate() const override;
+
 private:
-    int32_t                    mSamplesPerFrame = AAUDIO_UNSPECIFIED;
-    int32_t                    mSampleRate = AAUDIO_UNSPECIFIED;
-    int32_t                    mDeviceId = AAUDIO_UNSPECIFIED;
-    aaudio_sharing_mode_t      mSharingMode = AAUDIO_SHARING_MODE_SHARED;
     bool                       mSharingModeMatchRequired = false; // must match sharing mode requested
-    aaudio_format_t            mFormat = AAUDIO_FORMAT_UNSPECIFIED;
     aaudio_direction_t         mDirection = AAUDIO_DIRECTION_OUTPUT;
-    int32_t                    mBufferCapacity = AAUDIO_UNSPECIFIED;
     aaudio_performance_mode_t  mPerformanceMode = AAUDIO_PERFORMANCE_MODE_NONE;
 
     AAudioStream_dataCallback  mDataCallbackProc = nullptr;  // external callback functions
diff --git a/media/libaaudio/src/fifo/FifoBuffer.cpp b/media/libaaudio/src/fifo/FifoBuffer.cpp
index 6b4a772..8d2c62d 100644
--- a/media/libaaudio/src/fifo/FifoBuffer.cpp
+++ b/media/libaaudio/src/fifo/FifoBuffer.cpp
@@ -105,16 +105,18 @@
 
 }
 
-void FifoBuffer::getFullDataAvailable(WrappingBuffer *wrappingBuffer) {
+fifo_frames_t FifoBuffer::getFullDataAvailable(WrappingBuffer *wrappingBuffer) {
     fifo_frames_t framesAvailable = mFifo->getFullFramesAvailable();
     fifo_frames_t startIndex = mFifo->getReadIndex();
     fillWrappingBuffer(wrappingBuffer, framesAvailable, startIndex);
+    return framesAvailable;
 }
 
-void FifoBuffer::getEmptyRoomAvailable(WrappingBuffer *wrappingBuffer) {
+fifo_frames_t FifoBuffer::getEmptyRoomAvailable(WrappingBuffer *wrappingBuffer) {
     fifo_frames_t framesAvailable = mFifo->getEmptyFramesAvailable();
     fifo_frames_t startIndex = mFifo->getWriteIndex();
     fillWrappingBuffer(wrappingBuffer, framesAvailable, startIndex);
+    return framesAvailable;
 }
 
 fifo_frames_t FifoBuffer::read(void *buffer, fifo_frames_t numFrames) {
diff --git a/media/libaaudio/src/fifo/FifoBuffer.h b/media/libaaudio/src/fifo/FifoBuffer.h
index 2b262a1..a94e9b0 100644
--- a/media/libaaudio/src/fifo/FifoBuffer.h
+++ b/media/libaaudio/src/fifo/FifoBuffer.h
@@ -64,16 +64,18 @@
      * if the data is split across the end of the FIFO then set data2 and numFrames2.
      * Other wise set them to null
      * @param wrappingBuffer
+     * @return total full frames available
      */
-    void getFullDataAvailable(WrappingBuffer *wrappingBuffer);
+    fifo_frames_t getFullDataAvailable(WrappingBuffer *wrappingBuffer);
 
     /**
      * Return pointer to available empty frames in data1 and set size in numFrames1.
      * if the room is split across the end of the FIFO then set data2 and numFrames2.
      * Other wise set them to null
      * @param wrappingBuffer
+     * @return total empty frames available
      */
-    void getEmptyRoomAvailable(WrappingBuffer *wrappingBuffer);
+    fifo_frames_t getEmptyRoomAvailable(WrappingBuffer *wrappingBuffer);
 
     /**
      * Copy data from the FIFO into the buffer.
diff --git a/media/libaaudio/src/legacy/AudioStreamLegacy.h b/media/libaaudio/src/legacy/AudioStreamLegacy.h
index 0ded8e1..d2ef3c7 100644
--- a/media/libaaudio/src/legacy/AudioStreamLegacy.h
+++ b/media/libaaudio/src/legacy/AudioStreamLegacy.h
@@ -74,6 +74,15 @@
 
     virtual int64_t incrementClientFrameCounter(int32_t frames)  = 0;
 
+
+    virtual int64_t getFramesWritten() override {
+        return mFramesWritten.get();
+    }
+
+    virtual int64_t getFramesRead() override {
+        return mFramesRead.get();
+    }
+
 protected:
 
     class StreamDeviceCallback : public android::AudioSystem::AudioDeviceCallback
@@ -103,6 +112,17 @@
     void onStart() { mCallbackEnabled.store(true); }
     void onStop() { mCallbackEnabled.store(false); }
 
+    int64_t incrementFramesWritten(int32_t frames) {
+        return mFramesWritten.increment(frames);
+    }
+
+    int64_t incrementFramesRead(int32_t frames) {
+        return mFramesRead.increment(frames);
+    }
+
+    MonotonicCounter           mFramesWritten;
+    MonotonicCounter           mFramesRead;
+
     FixedBlockAdapter         *mBlockAdapter = nullptr;
     aaudio_wrapping_frames_t   mPositionWhenStarting = 0;
     int32_t                    mCallbackBufferSize = 0;
diff --git a/media/libaaudio/src/legacy/AudioStreamRecord.cpp b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
index 156e83d..8e8070c 100644
--- a/media/libaaudio/src/legacy/AudioStreamRecord.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
@@ -55,7 +55,7 @@
 
     // Try to create an AudioRecord
 
-    // TODO Support UNSPECIFIED in AudioTrack. For now, use stereo if unspecified.
+    // TODO Support UNSPECIFIED in AudioRecord. For now, use stereo if unspecified.
     int32_t samplesPerFrame = (getSamplesPerFrame() == AAUDIO_UNSPECIFIED)
                               ? 2 : getSamplesPerFrame();
     audio_channel_mask_t channelMask = audio_channel_in_mask_from_count(samplesPerFrame);
@@ -130,8 +130,8 @@
         return AAudioConvert_androidToAAudioResult(status);
     }
 
-    // Get the actual rate.
-    setSampleRate(mAudioRecord->getSampleRate());
+    // Get the actual values from the AudioRecord.
+    setSamplesPerFrame(mAudioRecord->channelCount());
     setFormat(AAudioConvert_androidToAAudioDataFormat(mAudioRecord->format()));
 
     int32_t actualSampleRate = mAudioRecord->getSampleRate();
@@ -223,18 +223,6 @@
     return AAUDIO_OK;
 }
 
-aaudio_result_t AudioStreamRecord::requestPause()
-{
-    // This does not make sense for an input stream.
-    // There is no real difference between pause() and stop().
-    return AAUDIO_ERROR_UNIMPLEMENTED;
-}
-
-aaudio_result_t AudioStreamRecord::requestFlush() {
-    // This does not make sense for an input stream.
-    return AAUDIO_ERROR_UNIMPLEMENTED;
-}
-
 aaudio_result_t AudioStreamRecord::requestStop() {
     if (mAudioRecord.get() == nullptr) {
         return AAUDIO_ERROR_INVALID_STATE;
diff --git a/media/libaaudio/src/legacy/AudioStreamRecord.h b/media/libaaudio/src/legacy/AudioStreamRecord.h
index 90000fc..2c6a7eb 100644
--- a/media/libaaudio/src/legacy/AudioStreamRecord.h
+++ b/media/libaaudio/src/legacy/AudioStreamRecord.h
@@ -41,8 +41,6 @@
     aaudio_result_t close() override;
 
     aaudio_result_t requestStart() override;
-    aaudio_result_t requestPause() override;
-    aaudio_result_t requestFlush() override;
     aaudio_result_t requestStop() override;
 
     virtual aaudio_result_t getTimestamp(clockid_t clockId,
diff --git a/media/libaaudio/src/legacy/AudioStreamTrack.cpp b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
index 7e39908..77f31e2 100644
--- a/media/libaaudio/src/legacy/AudioStreamTrack.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
@@ -423,7 +423,7 @@
     default:
         break;
     }
-    return AudioStream::getFramesRead();
+    return AudioStreamLegacy::getFramesRead();
 }
 
 aaudio_result_t AudioStreamTrack::getTimestamp(clockid_t clockId,
diff --git a/media/libaaudio/src/utility/AAudioUtilities.cpp b/media/libaaudio/src/utility/AAudioUtilities.cpp
index 164784d..2450920 100644
--- a/media/libaaudio/src/utility/AAudioUtilities.cpp
+++ b/media/libaaudio/src/utility/AAudioUtilities.cpp
@@ -208,9 +208,12 @@
     status_t status;
     switch (result) {
     case AAUDIO_ERROR_DISCONNECTED:
-    case AAUDIO_ERROR_INVALID_HANDLE:
+    case AAUDIO_ERROR_NO_SERVICE:
         status = DEAD_OBJECT;
         break;
+    case AAUDIO_ERROR_INVALID_HANDLE:
+        status = BAD_TYPE;
+        break;
     case AAUDIO_ERROR_INVALID_STATE:
         status = INVALID_OPERATION;
         break;
@@ -226,14 +229,16 @@
     case AAUDIO_ERROR_NULL:
         status = UNEXPECTED_NULL;
         break;
+    case AAUDIO_ERROR_UNAVAILABLE:
+        status = NOT_ENOUGH_DATA;
+        break;
+
     // TODO translate these result codes
     case AAUDIO_ERROR_INTERNAL:
     case AAUDIO_ERROR_UNIMPLEMENTED:
-    case AAUDIO_ERROR_UNAVAILABLE:
     case AAUDIO_ERROR_NO_FREE_HANDLES:
     case AAUDIO_ERROR_NO_MEMORY:
     case AAUDIO_ERROR_TIMEOUT:
-    case AAUDIO_ERROR_NO_SERVICE:
     default:
         status = UNKNOWN_ERROR;
         break;
@@ -257,15 +262,18 @@
     case INVALID_OPERATION:
         result = AAUDIO_ERROR_INVALID_STATE;
         break;
-        case UNEXPECTED_NULL:
-            result = AAUDIO_ERROR_NULL;
-            break;
-        case BAD_VALUE:
-            result = AAUDIO_ERROR_ILLEGAL_ARGUMENT;
-            break;
+    case UNEXPECTED_NULL:
+        result = AAUDIO_ERROR_NULL;
+        break;
+    case BAD_VALUE:
+        result = AAUDIO_ERROR_ILLEGAL_ARGUMENT;
+        break;
     case WOULD_BLOCK:
         result = AAUDIO_ERROR_WOULD_BLOCK;
         break;
+    case NOT_ENOUGH_DATA:
+        result = AAUDIO_ERROR_UNAVAILABLE;
+        break;
     default:
         result = AAUDIO_ERROR_INTERNAL;
         break;
@@ -361,12 +369,43 @@
     return prop;
 }
 
+int32_t AAudioProperty_getWakeupDelayMicros() {
+    const int32_t minMicros = 0; // arbitrary
+    const int32_t defaultMicros = 200; // arbitrary, based on some observed jitter
+    const int32_t maxMicros = 5000; // arbitrary, probably don't want more than 500
+    int32_t prop = property_get_int32(AAUDIO_PROP_WAKEUP_DELAY_USEC, defaultMicros);
+    if (prop < minMicros) {
+        ALOGW("AAudioProperty_getWakeupDelayMicros: clipped %d to %d", prop, minMicros);
+        prop = minMicros;
+    } else if (prop > maxMicros) {
+        ALOGW("AAudioProperty_getWakeupDelayMicros: clipped %d to %d", prop, maxMicros);
+        prop = maxMicros;
+    }
+    return prop;
+}
+
+int32_t AAudioProperty_getMinimumSleepMicros() {
+    const int32_t minMicros = 20; // arbitrary
+    const int32_t defaultMicros = 200; // arbitrary
+    const int32_t maxMicros = 2000; // arbitrary
+    int32_t prop = property_get_int32(AAUDIO_PROP_MINIMUM_SLEEP_USEC, defaultMicros);
+    if (prop < minMicros) {
+        ALOGW("AAudioProperty_getMinimumSleepMicros: clipped %d to %d", prop, minMicros);
+        prop = minMicros;
+    } else if (prop > maxMicros) {
+        ALOGW("AAudioProperty_getMinimumSleepMicros: clipped %d to %d", prop, maxMicros);
+        prop = maxMicros;
+    }
+    return prop;
+}
+
 int32_t AAudioProperty_getHardwareBurstMinMicros() {
     const int32_t defaultMicros = 1000; // arbitrary
     const int32_t maxMicros = 1000 * 1000; // arbitrary
     int32_t prop = property_get_int32(AAUDIO_PROP_HW_BURST_MIN_USEC, defaultMicros);
     if (prop < 1 || prop > maxMicros) {
-        ALOGE("AAudioProperty_getHardwareBurstMinMicros: invalid = %d", prop);
+        ALOGE("AAudioProperty_getHardwareBurstMinMicros: invalid = %d, use %d",
+              prop, defaultMicros);
         prop = defaultMicros;
     }
     return prop;
diff --git a/media/libaaudio/src/utility/AAudioUtilities.h b/media/libaaudio/src/utility/AAudioUtilities.h
index f894bc0..acd319b 100644
--- a/media/libaaudio/src/utility/AAudioUtilities.h
+++ b/media/libaaudio/src/utility/AAudioUtilities.h
@@ -17,6 +17,8 @@
 #ifndef UTILITY_AAUDIO_UTILITIES_H
 #define UTILITY_AAUDIO_UTILITIES_H
 
+#include <algorithm>
+#include <functional>
 #include <stdint.h>
 #include <sys/types.h>
 
@@ -193,13 +195,35 @@
 
 /**
  * Read system property.
- * @return number of bursts per mixer cycle
+ * @return number of bursts per AAudio service mixer cycle
  */
 int32_t AAudioProperty_getMixerBursts();
 
 #define AAUDIO_PROP_HW_BURST_MIN_USEC      "aaudio.hw_burst_min_usec"
 
 /**
+ * Read a system property that specifies the number of extra microseconds that a thread
+ * should sleep when waiting for another thread to service a FIFO. This is used
+ * to avoid the waking thread from being overly optimistic about the other threads
+ * wakeup timing. This value should be set high enough to cover typical scheduling jitter
+ * for a real-time thread.
+ *
+ * @return number of microseconds to delay the wakeup.
+ */
+int32_t AAudioProperty_getWakeupDelayMicros();
+
+#define AAUDIO_PROP_WAKEUP_DELAY_USEC      "aaudio.wakeup_delay_usec"
+
+/**
+ * Read a system property that specifies the minimum sleep time when polling the FIFO.
+ *
+ * @return minimum number of microseconds to sleep.
+ */
+int32_t AAudioProperty_getMinimumSleepMicros();
+
+#define AAUDIO_PROP_MINIMUM_SLEEP_USEC      "aaudio.minimum_sleep_usec"
+
+/**
  * Read system property.
  * This is handy in case the DMA is bursting too quickly for the CPU to keep up.
  * For example, there may be a DMA burst every 100 usec but you only
@@ -211,4 +235,27 @@
  */
 int32_t AAudioProperty_getHardwareBurstMinMicros();
 
+/**
+ * Try a function f until it returns true.
+ *
+ * The function is always called at least once.
+ *
+ * @param f the function to evaluate, which returns a bool.
+ * @param times the number of times to evaluate f.
+ * @param sleepMs the sleep time per check of f, if greater than 0.
+ * @return true if f() eventually returns true.
+ */
+static inline bool AAudio_tryUntilTrue(
+        std::function<bool()> f, int times, int sleepMs) {
+    static const useconds_t US_PER_MS = 1000;
+
+    sleepMs = std::max(sleepMs, 0);
+    for (;;) {
+        if (f()) return true;
+        if (times <= 1) return false;
+        --times;
+        usleep(sleepMs * US_PER_MS);
+    }
+}
+
 #endif //UTILITY_AAUDIO_UTILITIES_H
diff --git a/media/libaaudio/src/utility/HandleTracker.cpp b/media/libaaudio/src/utility/HandleTracker.cpp
index f957234..35ce95a 100644
--- a/media/libaaudio/src/utility/HandleTracker.cpp
+++ b/media/libaaudio/src/utility/HandleTracker.cpp
@@ -20,11 +20,15 @@
 #include <utils/Log.h>
 
 #include <assert.h>
+#include <functional>
+#include <iomanip>
 #include <new>
+#include <sstream>
 #include <stdint.h>
 #include <utils/Mutex.h>
 
 #include <aaudio/AAudio.h>
+#include "AAudioUtilities.h"
 #include "HandleTracker.h"
 
 using android::Mutex;
@@ -93,6 +97,47 @@
     return mHandleAddresses != nullptr;
 }
 
+
+
+std::string HandleTracker::dump() const {
+    if (!isInitialized()) {
+        return "HandleTracker is not initialized\n";
+    }
+
+    std::stringstream result;
+    const bool isLocked = AAudio_tryUntilTrue(
+            [this]()->bool { return mLock.tryLock(); } /* f */,
+            50 /* times */,
+            20 /* sleepMs */);
+    if (!isLocked) {
+        result << "HandleTracker may be deadlocked\n";
+    }
+
+    result << "HandleTracker:\n";
+    result << "  HandleHeaders:\n";
+    // atLineStart() can be changed to support an arbitrary line breaking algorithm;
+    // it should return true when a new line starts.
+    // For simplicity, we will use a constant 16 items per line.
+    const auto atLineStart = [](int index) -> bool {
+        // Magic constant of 0xf used for mask to detect start every 16 items.
+        return (index & 0xf) == 0; };
+    const auto atLineEnd = [this, &atLineStart](int index) -> bool {
+        return atLineStart(index + 1) || index == mMaxHandleCount - 1; };
+
+    for (int i = 0; i < mMaxHandleCount; ++i) {
+        if (atLineStart(i)) {
+            result << "    ";
+        }
+        result << std::hex << std::setw(4) << std::setfill('0') << mHandleHeaders[i]
+               << (atLineEnd(i) ? "\n" : " ");
+    }
+
+    if (isLocked) {
+        mLock.unlock();
+    }
+    return result.str();
+}
+
 handle_tracker_slot_t HandleTracker::allocateSlot_l() {
     void **allocated = mNextFreeAddress;
     if (allocated == nullptr) {
diff --git a/media/libaaudio/src/utility/HandleTracker.h b/media/libaaudio/src/utility/HandleTracker.h
index 23a73ed..a4c51c0 100644
--- a/media/libaaudio/src/utility/HandleTracker.h
+++ b/media/libaaudio/src/utility/HandleTracker.h
@@ -18,6 +18,7 @@
 #define UTILITY_HANDLE_TRACKER_H
 
 #include <stdint.h>
+#include <string>
 #include <utils/Mutex.h>
 
 typedef int32_t  aaudio_handle_t;
@@ -53,6 +54,18 @@
     bool isInitialized() const;
 
     /**
+     * Returns HandleTracker information.
+     *
+     * Will attempt to get the object lock, but will proceed
+     * even if it cannot.
+     *
+     * Each line of information ends with a newline.
+     *
+     * @return a string representing the HandleTracker info.
+     */
+    std::string dump() const;
+
+    /**
      * Store a pointer and return a handle that can be used to retrieve the pointer.
      *
      * It is safe to call put() or remove() from multiple threads.
@@ -99,7 +112,7 @@
     // This Mutex protects the linked list of free nodes.
     // The list is managed using mHandleAddresses and mNextFreeAddress.
     // The data in mHandleHeaders is only changed by put() and remove().
-    android::Mutex              mLock;
+    mutable android::Mutex      mLock;
 
     /**
      * Pull slot off of a list of empty slots.
diff --git a/media/libaaudio/tests/Android.mk b/media/libaaudio/tests/Android.mk
index afcdebf..e4eef06 100644
--- a/media/libaaudio/tests/Android.mk
+++ b/media/libaaudio/tests/Android.mk
@@ -6,9 +6,7 @@
     frameworks/av/media/libaaudio/include \
     frameworks/av/media/libaaudio/src
 LOCAL_SRC_FILES:= test_handle_tracker.cpp
-LOCAL_SHARED_LIBRARIES := libaudioclient libaudioutils libbinder \
-                          libcutils liblog libmedia libutils libaudiomanager
-LOCAL_STATIC_LIBRARIES := libaaudio
+LOCAL_SHARED_LIBRARIES := libaaudio
 LOCAL_MODULE := test_handle_tracker
 include $(BUILD_NATIVE_TEST)
 
@@ -18,9 +16,7 @@
     frameworks/av/media/libaaudio/include \
     frameworks/av/media/libaaudio/src
 LOCAL_SRC_FILES:= test_marshalling.cpp
-LOCAL_SHARED_LIBRARIES := libaudioclient libaudioutils libbinder \
-                          libcutils liblog libmedia libutils libaudiomanager
-LOCAL_STATIC_LIBRARIES := libaaudio
+LOCAL_SHARED_LIBRARIES := libaaudio libbinder libcutils libutils
 LOCAL_MODULE := test_aaudio_marshalling
 include $(BUILD_NATIVE_TEST)
 
@@ -30,9 +26,7 @@
     frameworks/av/media/libaaudio/include \
     frameworks/av/media/libaaudio/src
 LOCAL_SRC_FILES:= test_block_adapter.cpp
-LOCAL_SHARED_LIBRARIES := libaudioclient libaudioutils libbinder \
-                          libcutils liblog libmedia libutils libaudiomanager
-LOCAL_STATIC_LIBRARIES := libaaudio
+LOCAL_SHARED_LIBRARIES := libaaudio
 LOCAL_MODULE := test_block_adapter
 include $(BUILD_NATIVE_TEST)
 
@@ -42,9 +36,7 @@
     frameworks/av/media/libaaudio/include \
     frameworks/av/media/libaaudio/src
 LOCAL_SRC_FILES:= test_linear_ramp.cpp
-LOCAL_SHARED_LIBRARIES := libaudioclient libaudioutils libbinder \
-                          libcutils liblog libmedia libutils libaudiomanager
-LOCAL_STATIC_LIBRARIES := libaaudio
+LOCAL_SHARED_LIBRARIES := libaaudio
 LOCAL_MODULE := test_linear_ramp
 include $(BUILD_NATIVE_TEST)
 
@@ -54,8 +46,36 @@
     frameworks/av/media/libaaudio/include \
     frameworks/av/media/libaaudio/src
 LOCAL_SRC_FILES:= test_open_params.cpp
-LOCAL_SHARED_LIBRARIES := libaudioclient libaudioutils libbinder \
-                          libcutils liblog libmedia libutils libaudiomanager
-LOCAL_STATIC_LIBRARIES := libaaudio
+LOCAL_SHARED_LIBRARIES := libaaudio libbinder libcutils libutils
 LOCAL_MODULE := test_open_params
 include $(BUILD_NATIVE_TEST)
+
+include $(CLEAR_VARS)
+LOCAL_C_INCLUDES := \
+    $(call include-path-for, audio-utils) \
+    frameworks/av/media/libaaudio/include \
+    frameworks/av/media/libaaudio/src
+LOCAL_SRC_FILES:= test_no_close.cpp
+LOCAL_SHARED_LIBRARIES := libaaudio libbinder libcutils libutils
+LOCAL_MODULE := test_no_close
+include $(BUILD_NATIVE_TEST)
+
+include $(CLEAR_VARS)
+LOCAL_C_INCLUDES := \
+    $(call include-path-for, audio-utils) \
+    frameworks/av/media/libaaudio/include \
+    frameworks/av/media/libaaudio/src
+LOCAL_SRC_FILES:= test_recovery.cpp
+LOCAL_SHARED_LIBRARIES := libaaudio libbinder libcutils libutils
+LOCAL_MODULE := test_aaudio_recovery
+include $(BUILD_NATIVE_TEST)
+
+include $(CLEAR_VARS)
+LOCAL_C_INCLUDES := \
+    $(call include-path-for, audio-utils) \
+    frameworks/av/media/libaaudio/include \
+    frameworks/av/media/libaaudio/src
+LOCAL_SRC_FILES:= test_n_streams.cpp
+LOCAL_SHARED_LIBRARIES := libaaudio libbinder libcutils libutils
+LOCAL_MODULE := test_n_streams
+include $(BUILD_NATIVE_TEST)
diff --git a/media/libaaudio/tests/test_marshalling.cpp b/media/libaaudio/tests/test_marshalling.cpp
index 79beed6..c51fbce 100644
--- a/media/libaaudio/tests/test_marshalling.cpp
+++ b/media/libaaudio/tests/test_marshalling.cpp
@@ -19,6 +19,7 @@
 #include <stdlib.h>
 #include <math.h>
 
+#include <android-base/unique_fd.h>
 #include <binder/Parcel.h>
 #include <binder/Parcelable.h>
 #include <cutils/ashmem.h>
@@ -28,6 +29,7 @@
 #include <aaudio/AAudio.h>
 #include <binding/AudioEndpointParcelable.h>
 
+using android::base::unique_fd;
 using namespace android;
 using namespace aaudio;
 
@@ -48,7 +50,7 @@
     SharedMemoryParcelable sharedMemoryA;
     SharedMemoryParcelable sharedMemoryB;
     const size_t memSizeBytes = 840;
-    int fd = ashmem_create_region("TestMarshalling", memSizeBytes);
+    unique_fd fd(ashmem_create_region("TestMarshalling", memSizeBytes));
     ASSERT_LE(0, fd);
     sharedMemoryA.setup(fd, memSizeBytes);
     void *region1;
@@ -81,7 +83,7 @@
     SharedRegionParcelable sharedRegionA;
     SharedRegionParcelable sharedRegionB;
     const size_t memSizeBytes = 840;
-    int fd = ashmem_create_region("TestMarshalling", memSizeBytes);
+    unique_fd fd(ashmem_create_region("TestMarshalling", memSizeBytes));
     ASSERT_LE(0, fd);
     sharedMemories[0].setup(fd, memSizeBytes);
     int32_t regionOffset1 = 32;
@@ -119,7 +121,7 @@
     const int32_t counterSizeBytes = sizeof(int64_t);
     const size_t memSizeBytes = dataSizeBytes + (2 * counterSizeBytes);
 
-    int fd = ashmem_create_region("TestMarshalling", memSizeBytes);
+    unique_fd fd(ashmem_create_region("TestMarshalling Z", memSizeBytes));
     ASSERT_LE(0, fd);
     sharedMemories[0].setup(fd, memSizeBytes);
 
diff --git a/media/libaaudio/tests/test_n_streams.cpp b/media/libaaudio/tests/test_n_streams.cpp
new file mode 100644
index 0000000..271d024
--- /dev/null
+++ b/media/libaaudio/tests/test_n_streams.cpp
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Try to create as many streams as possible and report the maximum.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <aaudio/AAudio.h>
+#include <aaudio/AAudioTesting.h>
+
+//#define MMAP_POLICY              AAUDIO_UNSPECIFIED
+//#define MMAP_POLICY              AAUDIO_POLICY_NEVER
+#define MMAP_POLICY              AAUDIO_POLICY_AUTO
+//#define MMAP_POLICY              AAUDIO_POLICY_ALWAYS
+
+#define MAX_STREAMS   200
+
+aaudio_result_t testMaxStreams(aaudio_direction_t direction) {
+    aaudio_result_t result = AAUDIO_OK;
+    AAudioStreamBuilder *aaudioBuilder = nullptr;
+    AAudioStream *aaudioStreams[MAX_STREAMS];
+    int32_t numStreams = 0;
+
+    result = AAudio_createStreamBuilder(&aaudioBuilder);
+    if (result != AAUDIO_OK) {
+        return 1;
+    }
+
+    AAudioStreamBuilder_setDirection(aaudioBuilder, direction);
+
+    for (int i = 0; i < MAX_STREAMS; i++) {
+        // Create an AAudioStream using the Builder.
+        result = AAudioStreamBuilder_openStream(aaudioBuilder, &aaudioStreams[i]);
+        if (result != AAUDIO_OK) {
+            printf("ERROR could not open AAudio stream, %d %s\n",
+                   result, AAudio_convertResultToText(result));
+            break;
+        } else {
+            printf("AAudio stream[%2d] opened successfully. MMAP = %s\n",
+                   i, AAudioStream_isMMapUsed(aaudioStreams[i]) ? "YES" : "NO");
+            numStreams++;
+        }
+    }
+
+    printf("Created %d streams!\n", numStreams);
+
+    // Close all the streams.
+    for (int i = 0; i < numStreams; i++) {
+        result = AAudioStream_close(aaudioStreams[i]);
+        if (result != AAUDIO_OK) {
+            printf("ERROR could not close AAudio stream, %d %s\n",
+                   result, AAudio_convertResultToText(result));
+            break;
+        } else {
+            printf("AAudio stream[%2d] closed successfully.\n", i);
+        }
+    }
+
+    AAudioStreamBuilder_delete(aaudioBuilder);
+
+finish:
+    return result;
+}
+
+int main(int argc, char **argv) {
+    (void)argc; // unused
+    (void)argv; // unused
+
+    // Make printf print immediately so that debug info is not stuck
+    // in a buffer if we hang or crash.
+    setvbuf(stdout, NULL, _IONBF, (size_t) 0);
+
+    printf("Try to open a maximum of %d streams.\n", MAX_STREAMS);
+
+    AAudio_setMMapPolicy(MMAP_POLICY);
+    printf("requested MMapPolicy = %d\n", AAudio_getMMapPolicy());
+
+    printf("Test AAUDIO_DIRECTION_OUTPUT ---------\n");
+    aaudio_result_t result = testMaxStreams(AAUDIO_DIRECTION_OUTPUT);
+    if (result == AAUDIO_OK) {
+        printf("Test AAUDIO_DIRECTION_INPUT ---------\n");
+        result = testMaxStreams(AAUDIO_DIRECTION_INPUT);
+    }
+
+    return (result != AAUDIO_OK) ? EXIT_FAILURE : EXIT_SUCCESS;
+}
diff --git a/media/libaaudio/tests/test_no_close.cpp b/media/libaaudio/tests/test_no_close.cpp
new file mode 100644
index 0000000..2dbf153
--- /dev/null
+++ b/media/libaaudio/tests/test_no_close.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Try to create a resource leak in the server by opening a stream and then not closing it.
+// Return 0 if the stream opened, 1 if it failed.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <aaudio/AAudio.h>
+
+int main(int argc, char **argv)
+{
+    (void)argc; // unused
+    (void)argv; // unused
+
+    aaudio_result_t result = AAUDIO_OK;
+    AAudioStreamBuilder *aaudioBuilder = nullptr;
+    AAudioStream *aaudioStream = nullptr;
+
+    result = AAudio_createStreamBuilder(&aaudioBuilder);
+    if (result != AAUDIO_OK) {
+        goto finish;
+    }
+
+    // Create an AAudioStream using the Builder.
+    result = AAudioStreamBuilder_openStream(aaudioBuilder, &aaudioStream);
+    if (result != AAUDIO_OK) {
+        printf("ERROR could not open AAudio stream, %d\n", result);
+        goto finish;
+    } else {
+        printf("AAudio stream opened successfully.\n");
+    }
+
+    printf("Exit without closing the stream!\n");
+
+finish:
+    return (result != AAUDIO_OK) ? EXIT_FAILURE : EXIT_SUCCESS;
+}
+
diff --git a/media/libaaudio/tests/test_recovery.cpp b/media/libaaudio/tests/test_recovery.cpp
new file mode 100644
index 0000000..7268a30
--- /dev/null
+++ b/media/libaaudio/tests/test_recovery.cpp
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Play silence and recover from dead servers or disconnected devices.
+
+#include <stdio.h>
+
+#include <aaudio/AAudio.h>
+
+
+#define DEFAULT_TIMEOUT_NANOS  ((int64_t)1000000000)
+
+static const char *getSharingModeText(aaudio_sharing_mode_t mode) {
+    const char *modeText = "unknown";
+    switch (mode) {
+        case AAUDIO_SHARING_MODE_EXCLUSIVE:
+            modeText = "EXCLUSIVE";
+            break;
+        case AAUDIO_SHARING_MODE_SHARED:
+            modeText = "SHARED";
+            break;
+        default:
+            break;
+    }
+    return modeText;
+}
+
+int main(int argc, char **argv) {
+    (void) argc;
+    (void *)argv;
+
+    aaudio_result_t result = AAUDIO_OK;
+
+    int32_t triesLeft = 3;
+    int32_t bufferCapacity;
+    int32_t framesPerBurst = 0;
+    float *buffer = nullptr;
+
+    int32_t actualChannelCount = 0;
+    int32_t actualSampleRate = 0;
+    aaudio_format_t actualDataFormat = AAUDIO_FORMAT_PCM_FLOAT;
+    aaudio_sharing_mode_t actualSharingMode = AAUDIO_SHARING_MODE_SHARED;
+
+    AAudioStreamBuilder *aaudioBuilder = nullptr;
+    AAudioStream *aaudioStream = nullptr;
+
+    // Make printf print immediately so that debug info is not stuck
+    // in a buffer if we hang or crash.
+    setvbuf(stdout, nullptr, _IONBF, (size_t) 0);
+
+    printf("TestRecovery:\n");
+
+    // Use an AAudioStreamBuilder to contain requested parameters.
+    result = AAudio_createStreamBuilder(&aaudioBuilder);
+    if (result != AAUDIO_OK) {
+        printf("AAudio_createStreamBuilder returned %s",
+               AAudio_convertResultToText(result));
+        goto finish;
+    }
+
+    // Request stream properties.
+    AAudioStreamBuilder_setFormat(aaudioBuilder, AAUDIO_FORMAT_PCM_FLOAT);
+
+    while (triesLeft-- > 0) {
+        // Create an AAudioStream using the Builder.
+        result = AAudioStreamBuilder_openStream(aaudioBuilder, &aaudioStream);
+        if (result != AAUDIO_OK) {
+            printf("AAudioStreamBuilder_openStream returned %s",
+                   AAudio_convertResultToText(result));
+            goto finish;
+        }
+
+        // Check to see what kind of stream we actually got.
+        actualSampleRate = AAudioStream_getSampleRate(aaudioStream);
+        actualChannelCount = AAudioStream_getChannelCount(aaudioStream);
+        actualDataFormat = AAudioStream_getFormat(aaudioStream);
+
+        printf("-------- chans = %3d, rate = %6d format = %d\n",
+                actualChannelCount, actualSampleRate, actualDataFormat);
+
+        // This is the number of frames that are read in one chunk by a DMA controller
+        // or a DSP or a mixer.
+        framesPerBurst = AAudioStream_getFramesPerBurst(aaudioStream);
+        bufferCapacity = AAudioStream_getBufferCapacityInFrames(aaudioStream);
+        printf("         bufferCapacity = %d, framesPerBurst = %d\n",
+        bufferCapacity, framesPerBurst);
+
+        int samplesPerBurst = framesPerBurst * actualChannelCount;
+        buffer = new float[samplesPerBurst];
+
+        result = AAudioStream_requestStart(aaudioStream);
+        if (result != AAUDIO_OK) {
+            printf("AAudioStream_requestStart returned %s",
+                   AAudio_convertResultToText(result));
+            goto finish;
+        }
+
+        // Play silence for awhile.
+        int32_t framesMax = actualSampleRate * 20;
+        int64_t framesTotal = 0;
+        int64_t printAt = actualSampleRate;
+        while (result == AAUDIO_OK && framesTotal < framesMax) {
+            int32_t framesWritten = AAudioStream_write(aaudioStream,
+                                                       buffer, framesPerBurst,
+                                                       DEFAULT_TIMEOUT_NANOS);
+            if (framesWritten < 0) {
+                result = framesWritten;
+                printf("write() returned %s, frames = %d\n",
+                       AAudio_convertResultToText(result), (int)framesTotal);
+                printf("  frames = %d\n", (int)framesTotal);
+            } else if (framesWritten != framesPerBurst) {
+                printf("write() returned %d, frames = %d\n", framesWritten, (int)framesTotal);
+                result = AAUDIO_ERROR_TIMEOUT;
+            } else {
+                framesTotal += framesWritten;
+                if (framesTotal >= printAt) {
+                    printf("frames = %d\n", (int)framesTotal);
+                    printAt += actualSampleRate;
+                }
+            }
+        }
+        result = AAudioStream_requestStop(aaudioStream);
+        if (result != AAUDIO_OK) {
+            printf("AAudioStream_requestStop returned %s\n",
+                   AAudio_convertResultToText(result));
+        }
+        result = AAudioStream_close(aaudioStream);
+        if (result != AAUDIO_OK) {
+            printf("AAudioStream_close returned %s\n",
+                   AAudio_convertResultToText(result));
+        }
+        aaudioStream = nullptr;
+    }
+
+finish:
+    if (aaudioStream != nullptr) {
+        AAudioStream_close(aaudioStream);
+    }
+    AAudioStreamBuilder_delete(aaudioBuilder);
+    delete[] buffer;
+    printf("          result = %d = %s\n", result, AAudio_convertResultToText(result));
+}
diff --git a/media/libaudioclient/Android.bp b/media/libaudioclient/Android.bp
index d853946..61c946c 100644
--- a/media/libaudioclient/Android.bp
+++ b/media/libaudioclient/Android.bp
@@ -43,7 +43,6 @@
     // for memory heap analysis
     static_libs: [
         "libc_malloc_debug_backtrace",
-        "libc_logging",
     ],
     cflags: [
         "-Wall",
diff --git a/media/libaudioclient/AudioRecord.cpp b/media/libaudioclient/AudioRecord.cpp
index e749ac4..611cde7 100644
--- a/media/libaudioclient/AudioRecord.cpp
+++ b/media/libaudioclient/AudioRecord.cpp
@@ -69,7 +69,8 @@
     : mActive(false), mStatus(NO_INIT), mOpPackageName(opPackageName),
       mSessionId(AUDIO_SESSION_ALLOCATE),
       mPreviousPriority(ANDROID_PRIORITY_NORMAL), mPreviousSchedulingGroup(SP_DEFAULT),
-      mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE), mPortId(AUDIO_PORT_HANDLE_NONE)
+      mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE), mRoutedDeviceId(AUDIO_PORT_HANDLE_NONE),
+      mPortId(AUDIO_PORT_HANDLE_NONE)
 {
 }
 
@@ -503,10 +504,29 @@
     if (mInput == AUDIO_IO_HANDLE_NONE) {
         return AUDIO_PORT_HANDLE_NONE;
     }
-    return AudioSystem::getDeviceIdForIo(mInput);
+    // if the input stream does not have an active audio patch, use either the device initially
+    // selected by audio policy manager or the last routed device
+    audio_port_handle_t deviceId = AudioSystem::getDeviceIdForIo(mInput);
+    if (deviceId == AUDIO_PORT_HANDLE_NONE) {
+        deviceId = mRoutedDeviceId;
+    }
+    mRoutedDeviceId = deviceId;
+    return deviceId;
 }
 
 // -------------------------------------------------------------------------
+// TODO Move this macro to a common header file for enum to string conversion in audio framework.
+#define MEDIA_CASE_ENUM(name) case name: return #name
+const char * AudioRecord::convertTransferToText(transfer_type transferType) {
+    switch (transferType) {
+        MEDIA_CASE_ENUM(TRANSFER_DEFAULT);
+        MEDIA_CASE_ENUM(TRANSFER_CALLBACK);
+        MEDIA_CASE_ENUM(TRANSFER_OBTAIN);
+        MEDIA_CASE_ENUM(TRANSFER_SYNC);
+        default:
+            return "UNRECOGNIZED";
+    }
+}
 
 // must be called with mLock held
 status_t AudioRecord::openRecord_l(const Modulo<uint32_t> &epoch, const String16& opPackageName)
@@ -538,13 +558,14 @@
             .channel_mask = mChannelMask,
             .format = mFormat
         };
+    mRoutedDeviceId = mSelectedDeviceId;
     status = AudioSystem::getInputForAttr(&mAttributes, &input,
                                         mSessionId,
                                         // FIXME compare to AudioTrack
                                         mClientPid,
                                         mClientUid,
                                         &config,
-                                        mFlags, mSelectedDeviceId, &mPortId);
+                                        mFlags, &mRoutedDeviceId, &mPortId);
 
     if (status != NO_ERROR || input == AUDIO_IO_HANDLE_NONE) {
         ALOGE("Could not get audio input for session %d, record source %d, sample rate %u, "
@@ -590,12 +611,20 @@
             (mTransfer == TRANSFER_SYNC) ||
             // use case 3: obtain/release mode
             (mTransfer == TRANSFER_OBTAIN);
+        if (!useCaseAllowed) {
+            ALOGW("AUDIO_INPUT_FLAG_FAST denied, incompatible transfer = %s",
+                  convertTransferToText(mTransfer));
+        }
+
         // sample rates must also match
-        bool fastAllowed = useCaseAllowed && (mSampleRate == afSampleRate);
+        bool sampleRateAllowed = mSampleRate == afSampleRate;
+        if (!sampleRateAllowed) {
+            ALOGW("AUDIO_INPUT_FLAG_FAST denied, rates do not match %u Hz, require %u Hz",
+                  mSampleRate, afSampleRate);
+        }
+
+        bool fastAllowed = useCaseAllowed && sampleRateAllowed;
         if (!fastAllowed) {
-            ALOGW("AUDIO_INPUT_FLAG_FAST denied by client; transfer %d, "
-                "track %u Hz, input %u Hz",
-                mTransfer, mSampleRate, afSampleRate);
             mFlags = (audio_input_flags_t) (mFlags & ~(AUDIO_INPUT_FLAG_FAST |
                     AUDIO_INPUT_FLAG_RAW));
             AudioSystem::releaseInput(input, mSessionId);
@@ -1272,6 +1301,7 @@
     {
         AutoMutex _l(mMyLock);
         if (mPaused) {
+            // TODO check return value and handle or log
             mMyCond.wait(mMyLock);
             // caller will check for exitPending()
             return true;
@@ -1282,8 +1312,10 @@
         }
         if (mPausedInt) {
             if (mPausedNs > 0) {
+                // TODO check return value and handle or log
                 (void) mMyCond.waitRelative(mMyLock, mPausedNs);
             } else {
+                // TODO check return value and handle or log
                 mMyCond.wait(mMyLock);
             }
             mPausedInt = false;
diff --git a/media/libaudioclient/AudioSystem.cpp b/media/libaudioclient/AudioSystem.cpp
index 9ef1db7..2f710bd 100644
--- a/media/libaudioclient/AudioSystem.cpp
+++ b/media/libaudioclient/AudioSystem.cpp
@@ -819,7 +819,7 @@
                                         uid_t uid,
                                         const audio_config_t *config,
                                         audio_output_flags_t flags,
-                                        audio_port_handle_t selectedDeviceId,
+                                        audio_port_handle_t *selectedDeviceId,
                                         audio_port_handle_t *portId)
 {
     const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
@@ -863,7 +863,7 @@
                                 uid_t uid,
                                 const audio_config_base_t *config,
                                 audio_input_flags_t flags,
-                                audio_port_handle_t selectedDeviceId,
+                                audio_port_handle_t *selectedDeviceId,
                                 audio_port_handle_t *portId)
 {
     const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
@@ -1225,6 +1225,13 @@
     return aps->getMasterMono(mono);
 }
 
+float AudioSystem::getStreamVolumeDB(audio_stream_type_t stream, int index, audio_devices_t device)
+{
+    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+    if (aps == 0) return NAN;
+    return aps->getStreamVolumeDB(stream, index, device);
+}
+
 // ---------------------------------------------------------------------------
 
 int AudioSystem::AudioPolicyServiceClient::addAudioPortCallback(
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index ffb7703..b0b01db 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -184,6 +184,7 @@
       mPreviousSchedulingGroup(SP_DEFAULT),
       mPausedPosition(0),
       mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE),
+      mRoutedDeviceId(AUDIO_PORT_HANDLE_NONE),
       mPortId(AUDIO_PORT_HANDLE_NONE)
 {
     mAttributes.content_type = AUDIO_CONTENT_TYPE_UNKNOWN;
@@ -908,13 +909,13 @@
             effectiveRate, effectiveSpeed, effectivePitch);
 
     if (!isAudioPlaybackRateValid(playbackRateTemp)) {
-        ALOGV("setPlaybackRate(%f, %f) failed (effective rate out of bounds)",
+        ALOGW("setPlaybackRate(%f, %f) failed (effective rate out of bounds)",
                 playbackRate.mSpeed, playbackRate.mPitch);
         return BAD_VALUE;
     }
     // Check if the buffer size is compatible.
     if (!isSampleRateSpeedAllowed_l(effectiveRate, effectiveSpeed)) {
-        ALOGV("setPlaybackRate(%f, %f) failed (buffer size)",
+        ALOGW("setPlaybackRate(%f, %f) failed (buffer size)",
                 playbackRate.mSpeed, playbackRate.mPitch);
         return BAD_VALUE;
     }
@@ -922,13 +923,13 @@
     // Check resampler ratios are within bounds
     if ((uint64_t)effectiveRate > (uint64_t)mSampleRate *
             (uint64_t)AUDIO_RESAMPLER_DOWN_RATIO_MAX) {
-        ALOGV("setPlaybackRate(%f, %f) failed. Resample rate exceeds max accepted value",
+        ALOGW("setPlaybackRate(%f, %f) failed. Resample rate exceeds max accepted value",
                 playbackRate.mSpeed, playbackRate.mPitch);
         return BAD_VALUE;
     }
 
     if ((uint64_t)effectiveRate * (uint64_t)AUDIO_RESAMPLER_UP_RATIO_MAX < (uint64_t)mSampleRate) {
-        ALOGV("setPlaybackRate(%f, %f) failed. Resample rate below min accepted value",
+        ALOGW("setPlaybackRate(%f, %f) failed. Resample rate below min accepted value",
                         playbackRate.mSpeed, playbackRate.mPitch);
         return BAD_VALUE;
     }
@@ -1226,7 +1227,14 @@
     if (mOutput == AUDIO_IO_HANDLE_NONE) {
         return AUDIO_PORT_HANDLE_NONE;
     }
-    return AudioSystem::getDeviceIdForIo(mOutput);
+    // if the output stream does not have an active audio patch, use either the device initially
+    // selected by audio policy manager or the last routed device
+    audio_port_handle_t deviceId = AudioSystem::getDeviceIdForIo(mOutput);
+    if (deviceId == AUDIO_PORT_HANDLE_NONE) {
+        deviceId = mRoutedDeviceId;
+    }
+    mRoutedDeviceId = deviceId;
+    return deviceId;
 }
 
 status_t AudioTrack::attachAuxEffect(int effectId)
@@ -1247,9 +1255,41 @@
     return mStreamType;
 }
 
+uint32_t AudioTrack::latency()
+{
+    AutoMutex lock(mLock);
+    updateLatency_l();
+    return mLatency;
+}
+
 // -------------------------------------------------------------------------
 
 // must be called with mLock held
+void AudioTrack::updateLatency_l()
+{
+    status_t status = AudioSystem::getLatency(mOutput, &mAfLatency);
+    if (status != NO_ERROR) {
+        ALOGW("getLatency(%d) failed status %d", mOutput, status);
+    } else {
+        // FIXME don't believe this lie
+        mLatency = mAfLatency + (1000 * mFrameCount) / mSampleRate;
+    }
+}
+
+// TODO Move this macro to a common header file for enum to string conversion in audio framework.
+#define MEDIA_CASE_ENUM(name) case name: return #name
+const char * AudioTrack::convertTransferToText(transfer_type transferType) {
+    switch (transferType) {
+        MEDIA_CASE_ENUM(TRANSFER_DEFAULT);
+        MEDIA_CASE_ENUM(TRANSFER_CALLBACK);
+        MEDIA_CASE_ENUM(TRANSFER_OBTAIN);
+        MEDIA_CASE_ENUM(TRANSFER_SYNC);
+        MEDIA_CASE_ENUM(TRANSFER_SHARED);
+        default:
+            return "UNRECOGNIZED";
+    }
+}
+
 status_t AudioTrack::createTrack_l()
 {
     const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger();
@@ -1274,10 +1314,11 @@
     config.channel_mask = mChannelMask;
     config.format = mFormat;
     config.offload_info = mOffloadInfoCopy;
+    mRoutedDeviceId = mSelectedDeviceId;
     status = AudioSystem::getOutputForAttr(attr, &output,
                                            mSessionId, &streamType, mClientUid,
                                            &config,
-                                           mFlags, mSelectedDeviceId, &mPortId);
+                                           mFlags, &mRoutedDeviceId, &mPortId);
 
     if (status != NO_ERROR || output == AUDIO_IO_HANDLE_NONE) {
         ALOGE("Could not get audio output for session %d, stream type %d, usage %d, sample rate %u,"
@@ -1325,22 +1366,32 @@
 
     // Client can only express a preference for FAST.  Server will perform additional tests.
     if (mFlags & AUDIO_OUTPUT_FLAG_FAST) {
-        bool useCaseAllowed =
-            // either of these use cases:
-            // use case 1: shared buffer
-            (mSharedBuffer != 0) ||
+        // either of these use cases:
+        // use case 1: shared buffer
+        bool sharedBuffer = mSharedBuffer != 0;
+        bool transferAllowed =
             // use case 2: callback transfer mode
             (mTransfer == TRANSFER_CALLBACK) ||
             // use case 3: obtain/release mode
             (mTransfer == TRANSFER_OBTAIN) ||
             // use case 4: synchronous write
             ((mTransfer == TRANSFER_SYNC) && mThreadCanCallJava);
+
+        bool useCaseAllowed = sharedBuffer || transferAllowed;
+        if (!useCaseAllowed) {
+            ALOGW("AUDIO_OUTPUT_FLAG_FAST denied, not shared buffer and transfer = %s",
+                  convertTransferToText(mTransfer));
+        }
+
         // sample rates must also match
-        bool fastAllowed = useCaseAllowed && (mSampleRate == mAfSampleRate);
+        bool sampleRateAllowed = mSampleRate == mAfSampleRate;
+        if (!sampleRateAllowed) {
+            ALOGW("AUDIO_OUTPUT_FLAG_FAST denied, rates do not match %u Hz, require %u Hz",
+                  mSampleRate, mAfSampleRate);
+        }
+
+        bool fastAllowed = useCaseAllowed && sampleRateAllowed;
         if (!fastAllowed) {
-            ALOGW("AUDIO_OUTPUT_FLAG_FAST denied by client; transfer %d, "
-                "track %u Hz, output %u Hz",
-                mTransfer, mSampleRate, mAfSampleRate);
             mFlags = (audio_output_flags_t) (mFlags & ~AUDIO_OUTPUT_FLAG_FAST);
         }
     }
@@ -1416,6 +1467,9 @@
 
     pid_t tid = -1;
     if (mFlags & AUDIO_OUTPUT_FLAG_FAST) {
+        // It is currently meaningless to request SCHED_FIFO for a Java thread.  Even if the
+        // application-level code follows all non-blocking design rules, the language runtime
+        // doesn't also follow those rules, so the thread will not benefit overall.
         if (mAudioTrackThread != 0 && !mThreadCanCallJava) {
             tid = mAudioTrackThread->getTid();
         }
@@ -1541,11 +1595,9 @@
     }
 
     mAudioTrack->attachAuxEffect(mAuxEffectId);
-    // FIXME doesn't take into account speed or future sample rate changes (until restoreTrack)
-    // FIXME don't believe this lie
-    mLatency = mAfLatency + (1000*frameCount) / mSampleRate;
-
     mFrameCount = frameCount;
+    updateLatency_l();  // this refetches mAfLatency and sets mLatency
+
     // If IAudioTrack is re-created, don't let the requested frameCount
     // decrease.  This can confuse clients that cache frameCount().
     if (frameCount > mReqFrameCount) {
@@ -2315,8 +2367,9 @@
     return mPosition;
 }
 
-bool AudioTrack::isSampleRateSpeedAllowed_l(uint32_t sampleRate, float speed) const
+bool AudioTrack::isSampleRateSpeedAllowed_l(uint32_t sampleRate, float speed)
 {
+    updateLatency_l();
     // applicable for mixing tracks only (not offloaded or direct)
     if (mStaticProxy != 0) {
         return true; // static tracks do not have issues with buffer sizing.
@@ -2324,9 +2377,14 @@
     const size_t minFrameCount =
             calculateMinFrameCount(mAfLatency, mAfFrameCount, mAfSampleRate, sampleRate, speed
                 /*, 0 mNotificationsPerBufferReq*/);
-    ALOGV("isSampleRateSpeedAllowed_l mFrameCount %zu  minFrameCount %zu",
+    const bool allowed = mFrameCount >= minFrameCount;
+    ALOGD_IF(!allowed,
+            "isSampleRateSpeedAllowed_l denied "
+            "mAfLatency:%u  mAfFrameCount:%zu  mAfSampleRate:%u  sampleRate:%u  speed:%f "
+            "mFrameCount:%zu < minFrameCount:%zu",
+            mAfLatency, mAfFrameCount, mAfSampleRate, sampleRate, speed,
             mFrameCount, minFrameCount);
-    return mFrameCount >= minFrameCount;
+    return allowed;
 }
 
 status_t AudioTrack::setParameters(const String8& keyValuePairs)
@@ -2470,6 +2528,7 @@
             status = ets.getBestTimestamp(&timestamp, &location);
 
             if (status == OK) {
+                updateLatency_l();
                 // It is possible that the best location has moved from the kernel to the server.
                 // In this case we adjust the position from the previous computed latency.
                 if (location == ExtendedTimestamp::LOCATION_SERVER) {
@@ -2941,6 +3000,7 @@
     {
         AutoMutex _l(mMyLock);
         if (mPaused) {
+            // TODO check return value and handle or log
             mMyCond.wait(mMyLock);
             // caller will check for exitPending()
             return true;
@@ -2950,9 +3010,12 @@
             mPausedInt = false;
         }
         if (mPausedInt) {
+            // TODO use futex instead of condition, for event flag "or"
             if (mPausedNs > 0) {
+                // TODO check return value and handle or log
                 (void) mMyCond.waitRelative(mMyLock, mPausedNs);
             } else {
+                // TODO check return value and handle or log
                 mMyCond.wait(mMyLock);
             }
             mPausedInt = false;
diff --git a/media/libaudioclient/AudioTrackShared.cpp b/media/libaudioclient/AudioTrackShared.cpp
index 2ce6c63..08c37f8 100644
--- a/media/libaudioclient/AudioTrackShared.cpp
+++ b/media/libaudioclient/AudioTrackShared.cpp
@@ -111,7 +111,8 @@
 status_t ClientProxy::obtainBuffer(Buffer* buffer, const struct timespec *requested,
         struct timespec *elapsed)
 {
-    LOG_ALWAYS_FATAL_IF(buffer == NULL || buffer->mFrameCount == 0);
+    LOG_ALWAYS_FATAL_IF(buffer == NULL || buffer->mFrameCount == 0,
+            "%s: null or zero frame buffer, buffer:%p", __func__, buffer);
     struct timespec total;          // total elapsed time spent waiting
     total.tv_sec = 0;
     total.tv_nsec = 0;
@@ -345,7 +346,10 @@
         buffer->mNonContig = 0;
         return;
     }
-    LOG_ALWAYS_FATAL_IF(!(stepCount <= mUnreleased && mUnreleased <= mFrameCount));
+    LOG_ALWAYS_FATAL_IF(!(stepCount <= mUnreleased && mUnreleased <= mFrameCount),
+            "%s: mUnreleased out of range, "
+            "!(stepCount:%zu <= mUnreleased:%zu <= mFrameCount:%zu), BufferSizeInFrames:%u",
+            __func__, stepCount, mUnreleased, mFrameCount, getBufferSizeInFrames());
     mUnreleased -= stepCount;
     audio_track_cblk_t* cblk = mCblk;
     // Both of these barriers are required
@@ -674,7 +678,8 @@
 __attribute__((no_sanitize("integer")))
 status_t ServerProxy::obtainBuffer(Buffer* buffer, bool ackFlush)
 {
-    LOG_ALWAYS_FATAL_IF(buffer == NULL || buffer->mFrameCount == 0);
+    LOG_ALWAYS_FATAL_IF(buffer == NULL || buffer->mFrameCount == 0,
+            "%s: null or zero frame buffer, buffer:%p", __func__, buffer);
     if (mIsShutdown) {
         goto no_init;
     }
@@ -760,7 +765,10 @@
         buffer->mNonContig = 0;
         return;
     }
-    LOG_ALWAYS_FATAL_IF(!(stepCount <= mUnreleased && mUnreleased <= mFrameCount));
+    LOG_ALWAYS_FATAL_IF(!(stepCount <= mUnreleased && mUnreleased <= mFrameCount),
+            "%s: mUnreleased out of range, "
+            "!(stepCount:%zu <= mUnreleased:%zu <= mFrameCount:%zu)",
+            __func__, stepCount, mUnreleased, mFrameCount);
     mUnreleased -= stepCount;
     audio_track_cblk_t* cblk = mCblk;
     if (mIsOut) {
@@ -1029,7 +1037,9 @@
     }
     // As mFramesReady is the total remaining frames in the static audio track,
     // it is always larger or equal to avail.
-    LOG_ALWAYS_FATAL_IF(mFramesReady < (int64_t) avail);
+    LOG_ALWAYS_FATAL_IF(mFramesReady < (int64_t) avail,
+            "%s: mFramesReady out of range, mFramesReady:%lld < avail:%zu",
+            __func__, (long long)mFramesReady, avail);
     buffer->mNonContig = mFramesReady == INT64_MAX ? SIZE_MAX : clampToSize(mFramesReady - avail);
     if (!ackFlush) {
         mUnreleased = avail;
@@ -1040,8 +1050,14 @@
 void StaticAudioTrackServerProxy::releaseBuffer(Buffer* buffer)
 {
     size_t stepCount = buffer->mFrameCount;
-    LOG_ALWAYS_FATAL_IF(!((int64_t) stepCount <= mFramesReady));
-    LOG_ALWAYS_FATAL_IF(!(stepCount <= mUnreleased));
+    LOG_ALWAYS_FATAL_IF(!((int64_t) stepCount <= mFramesReady),
+            "%s: stepCount out of range, "
+            "!(stepCount:%zu <= mFramesReady:%lld)",
+            __func__, stepCount, (long long)mFramesReady);
+    LOG_ALWAYS_FATAL_IF(!(stepCount <= mUnreleased),
+            "%s: stepCount out of range, "
+            "!(stepCount:%zu <= mUnreleased:%zu)",
+            __func__, stepCount, mUnreleased);
     if (stepCount == 0) {
         // prevent accidental re-use of buffer
         buffer->mRaw = NULL;
diff --git a/media/libaudioclient/IAudioFlinger.cpp b/media/libaudioclient/IAudioFlinger.cpp
index 858b5cc..14feada 100644
--- a/media/libaudioclient/IAudioFlinger.cpp
+++ b/media/libaudioclient/IAudioFlinger.cpp
@@ -62,7 +62,7 @@
     SET_VOICE_VOLUME,
     GET_RENDER_POSITION,
     GET_INPUT_FRAMES_LOST,
-    NEW_AUDIO_SESSION_ID,
+    NEW_AUDIO_UNIQUE_ID,
     ACQUIRE_AUDIO_SESSION_ID,
     RELEASE_AUDIO_SESSION_ID,
     QUERY_NUM_EFFECTS,
@@ -80,7 +80,7 @@
     RELEASE_AUDIO_PATCH,
     LIST_AUDIO_PATCHES,
     SET_AUDIO_PORT_CONFIG,
-    GET_AUDIO_HW_SYNC,
+    GET_AUDIO_HW_SYNC_FOR_SESSION,
     SYSTEM_READY,
     FRAME_COUNT_HAL,
 };
@@ -628,8 +628,8 @@
         Parcel data, reply;
         data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
         data.writeInt32((int32_t) use);
-        status_t status = remote()->transact(NEW_AUDIO_SESSION_ID, data, &reply);
-        audio_unique_id_t id = AUDIO_SESSION_ALLOCATE;
+        status_t status = remote()->transact(NEW_AUDIO_UNIQUE_ID, data, &reply);
+        audio_unique_id_t id = AUDIO_UNIQUE_ID_ALLOCATE;
         if (status == NO_ERROR) {
             id = reply.readInt32();
         }
@@ -912,7 +912,7 @@
         Parcel data, reply;
         data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
         data.writeInt32(sessionId);
-        status_t status = remote()->transact(GET_AUDIO_HW_SYNC, data, &reply);
+        status_t status = remote()->transact(GET_AUDIO_HW_SYNC_FOR_SESSION, data, &reply);
         if (status != NO_ERROR) {
             return AUDIO_HW_SYNC_INVALID;
         }
@@ -1262,7 +1262,7 @@
             reply->writeInt32((int32_t) getInputFramesLost(ioHandle));
             return NO_ERROR;
         } break;
-        case NEW_AUDIO_SESSION_ID: {
+        case NEW_AUDIO_UNIQUE_ID: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
             reply->writeInt32(newAudioUniqueId((audio_unique_id_use_t) data.readInt32()));
             return NO_ERROR;
@@ -1466,7 +1466,7 @@
             reply->writeInt32(status);
             return NO_ERROR;
         } break;
-        case GET_AUDIO_HW_SYNC: {
+        case GET_AUDIO_HW_SYNC_FOR_SESSION: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
             reply->writeInt32(getAudioHwSyncForSession((audio_session_t) data.readInt32()));
             return NO_ERROR;
diff --git a/media/libaudioclient/IAudioPolicyService.cpp b/media/libaudioclient/IAudioPolicyService.cpp
index 300f040..f071a02 100644
--- a/media/libaudioclient/IAudioPolicyService.cpp
+++ b/media/libaudioclient/IAudioPolicyService.cpp
@@ -19,6 +19,7 @@
 #include <utils/Log.h>
 
 #include <stdint.h>
+#include <math.h>
 #include <sys/types.h>
 
 #include <binder/Parcel.h>
@@ -77,6 +78,7 @@
     SET_AUDIO_PORT_CALLBACK_ENABLED,
     SET_MASTER_MONO,
     GET_MASTER_MONO,
+    GET_STREAM_VOLUME_DB
 };
 
 #define MAX_ITEMS_PER_LIST 1024
@@ -191,7 +193,7 @@
                                         uid_t uid,
                                         const audio_config_t *config,
                                         audio_output_flags_t flags,
-                                        audio_port_handle_t selectedDeviceId,
+                                        audio_port_handle_t *selectedDeviceId,
                                         audio_port_handle_t *portId)
         {
             Parcel data, reply;
@@ -210,6 +212,10 @@
                 ALOGE("getOutputForAttr NULL output - shouldn't happen");
                 return BAD_VALUE;
             }
+            if (selectedDeviceId == NULL) {
+                ALOGE("getOutputForAttr NULL selectedDeviceId - shouldn't happen");
+                return BAD_VALUE;
+            }
             if (portId == NULL) {
                 ALOGE("getOutputForAttr NULL portId - shouldn't happen");
                 return BAD_VALUE;
@@ -230,7 +236,7 @@
             data.writeInt32(uid);
             data.write(config, sizeof(audio_config_t));
             data.writeInt32(static_cast <uint32_t>(flags));
-            data.writeInt32(selectedDeviceId);
+            data.writeInt32(*selectedDeviceId);
             data.writeInt32(*portId);
             status_t status = remote()->transact(GET_OUTPUT_FOR_ATTR, data, &reply);
             if (status != NO_ERROR) {
@@ -245,6 +251,7 @@
             if (stream != NULL) {
                 *stream = lStream;
             }
+            *selectedDeviceId = (audio_port_handle_t)reply.readInt32();
             *portId = (audio_port_handle_t)reply.readInt32();
             return status;
         }
@@ -294,7 +301,7 @@
                                      uid_t uid,
                                      const audio_config_base_t *config,
                                      audio_input_flags_t flags,
-                                     audio_port_handle_t selectedDeviceId,
+                                     audio_port_handle_t *selectedDeviceId,
                                      audio_port_handle_t *portId)
     {
         Parcel data, reply;
@@ -307,17 +314,22 @@
             ALOGE("getInputForAttr NULL input - shouldn't happen");
             return BAD_VALUE;
         }
+        if (selectedDeviceId == NULL) {
+            ALOGE("getInputForAttr NULL selectedDeviceId - shouldn't happen");
+            return BAD_VALUE;
+        }
         if (portId == NULL) {
             ALOGE("getInputForAttr NULL portId - shouldn't happen");
             return BAD_VALUE;
         }
         data.write(attr, sizeof(audio_attributes_t));
+        data.writeInt32(*input);
         data.writeInt32(session);
         data.writeInt32(pid);
         data.writeInt32(uid);
         data.write(config, sizeof(audio_config_base_t));
         data.writeInt32(flags);
-        data.writeInt32(selectedDeviceId);
+        data.writeInt32(*selectedDeviceId);
         data.writeInt32(*portId);
         status_t status = remote()->transact(GET_INPUT_FOR_ATTR, data, &reply);
         if (status != NO_ERROR) {
@@ -328,6 +340,7 @@
             return status;
         }
         *input = (audio_io_handle_t)reply.readInt32();
+        *selectedDeviceId = (audio_port_handle_t)reply.readInt32();
         *portId = (audio_port_handle_t)reply.readInt32();
         return NO_ERROR;
     }
@@ -815,6 +828,20 @@
         }
         return status;
     }
+
+    virtual float getStreamVolumeDB(audio_stream_type_t stream, int index, audio_devices_t device)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+        data.writeInt32(static_cast <int32_t>(stream));
+        data.writeInt32(static_cast <int32_t>(index));
+        data.writeUint32(static_cast <uint32_t>(device));
+        status_t status = remote()->transact(GET_STREAM_VOLUME_DB, data, &reply);
+        if (status != NO_ERROR) {
+            return NAN;
+        }
+        return reply.readFloat();
+    }
 };
 
 IMPLEMENT_META_INTERFACE(AudioPolicyService, "android.media.IAudioPolicyService");
@@ -953,10 +980,11 @@
             status_t status = getOutputForAttr(hasAttributes ? &attr : NULL,
                     &output, session, &stream, uid,
                     &config,
-                    flags, selectedDeviceId, &portId);
+                    flags, &selectedDeviceId, &portId);
             reply->writeInt32(status);
             reply->writeInt32(output);
             reply->writeInt32(stream);
+            reply->writeInt32(selectedDeviceId);
             reply->writeInt32(portId);
             return NO_ERROR;
         } break;
@@ -999,6 +1027,7 @@
             audio_attributes_t attr = {};
             data.read(&attr, sizeof(audio_attributes_t));
             sanetizeAudioAttributes(&attr);
+            audio_io_handle_t input = (audio_io_handle_t)data.readInt32();
             audio_session_t session = (audio_session_t)data.readInt32();
             pid_t pid = (pid_t)data.readInt32();
             uid_t uid = (uid_t)data.readInt32();
@@ -1008,13 +1037,13 @@
             audio_input_flags_t flags = (audio_input_flags_t) data.readInt32();
             audio_port_handle_t selectedDeviceId = (audio_port_handle_t) data.readInt32();
             audio_port_handle_t portId = (audio_port_handle_t)data.readInt32();
-            audio_io_handle_t input = AUDIO_IO_HANDLE_NONE;
             status_t status = getInputForAttr(&attr, &input, session, pid, uid,
                                               &config,
-                                              flags, selectedDeviceId, &portId);
+                                              flags, &selectedDeviceId, &portId);
             reply->writeInt32(status);
             if (status == NO_ERROR) {
                 reply->writeInt32(input);
+                reply->writeInt32(selectedDeviceId);
                 reply->writeInt32(portId);
             }
             return NO_ERROR;
@@ -1416,6 +1445,17 @@
             return NO_ERROR;
         } break;
 
+        case GET_STREAM_VOLUME_DB: {
+            CHECK_INTERFACE(IAudioPolicyService, data, reply);
+            audio_stream_type_t stream =
+                    static_cast <audio_stream_type_t>(data.readInt32());
+            int index = static_cast <int>(data.readInt32());
+            audio_devices_t device =
+                    static_cast <audio_devices_t>(data.readUint32());
+            reply->writeFloat(getStreamVolumeDB(stream, index, device));
+            return NO_ERROR;
+        }
+
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/media/libaudioclient/PlayerBase.cpp b/media/libaudioclient/PlayerBase.cpp
index cbef1b3..7868318 100644
--- a/media/libaudioclient/PlayerBase.cpp
+++ b/media/libaudioclient/PlayerBase.cpp
@@ -79,7 +79,7 @@
     }
 }
 
-//FIXME temporary method while some AudioTrack state is outside of this class
+//FIXME temporary method while some player state is outside of this class
 void PlayerBase::reportEvent(player_state_t event) {
     servicePlayerEvent(event);
 }
@@ -87,10 +87,30 @@
 status_t PlayerBase::startWithStatus() {
     status_t status = playerStart();
     if (status == NO_ERROR) {
-        ALOGD("PlayerBase::start() from IPlayer");
         servicePlayerEvent(PLAYER_STATE_STARTED);
     } else {
-        ALOGD("PlayerBase::start() no AudioTrack to start from IPlayer");
+        ALOGW("PlayerBase::start() error %d", status);
+    }
+    return status;
+}
+
+status_t PlayerBase::pauseWithStatus() {
+    status_t status = playerPause();
+    if (status == NO_ERROR) {
+        servicePlayerEvent(PLAYER_STATE_PAUSED);
+    } else {
+        ALOGW("PlayerBase::pause() error %d", status);
+    }
+    return status;
+}
+
+
+status_t PlayerBase::stopWithStatus() {
+    status_t status = playerStop();
+    if (status == NO_ERROR) {
+        servicePlayerEvent(PLAYER_STATE_STOPPED);
+    } else {
+        ALOGW("PlayerBase::stop() error %d", status);
     }
     return status;
 }
@@ -98,42 +118,36 @@
 //------------------------------------------------------------------------------
 // Implementation of IPlayer
 void PlayerBase::start() {
+    ALOGD("PlayerBase::start() from IPlayer");
     (void)startWithStatus();
 }
 
 void PlayerBase::pause() {
-    if (playerPause() == NO_ERROR) {
-        ALOGD("PlayerBase::pause() from IPlayer");
-        servicePlayerEvent(PLAYER_STATE_PAUSED);
-    } else {
-        ALOGD("PlayerBase::pause() no AudioTrack to pause from IPlayer");
-    }
+    ALOGD("PlayerBase::pause() from IPlayer");
+    (void)pauseWithStatus();
 }
 
 
 void PlayerBase::stop() {
-    if (playerStop() == NO_ERROR) {
-        ALOGD("PlayerBase::stop() from IPlayer");
-        servicePlayerEvent(PLAYER_STATE_STOPPED);
-    } else {
-        ALOGD("PlayerBase::stop() no AudioTrack to stop from IPlayer");
-    }
+    ALOGD("PlayerBase::stop() from IPlayer");
+    (void)stopWithStatus();
 }
 
 void PlayerBase::setVolume(float vol) {
+    ALOGD("PlayerBase::setVolume() from IPlayer");
     {
         Mutex::Autolock _l(mSettingsLock);
         mVolumeMultiplierL = vol;
         mVolumeMultiplierR = vol;
     }
-    if (playerSetVolume() == NO_ERROR) {
-        ALOGD("PlayerBase::setVolume() from IPlayer");
-    } else {
-        ALOGD("PlayerBase::setVolume() no AudioTrack for volume control from IPlayer");
+    status_t status = playerSetVolume();
+    if (status != NO_ERROR) {
+        ALOGW("PlayerBase::setVolume() error %d", status);
     }
 }
 
 void PlayerBase::setPan(float pan) {
+    ALOGD("PlayerBase::setPan() from IPlayer");
     {
         Mutex::Autolock _l(mSettingsLock);
         pan = min(max(-1.0f, pan), 1.0f);
@@ -145,10 +159,9 @@
             mPanMultiplierR = 1.0f + pan;
         }
     }
-    if (playerSetVolume() == NO_ERROR) {
-        ALOGD("PlayerBase::setPan() from IPlayer");
-    } else {
-        ALOGD("PlayerBase::setPan() no AudioTrack for volume control from IPlayer");
+    status_t status = playerSetVolume();
+    if (status != NO_ERROR) {
+        ALOGW("PlayerBase::setPan() error %d", status);
     }
 }
 
diff --git a/media/libaudioclient/include/media/AudioClient.h b/media/libaudioclient/include/media/AudioClient.h
new file mode 100644
index 0000000..9efd76d
--- /dev/null
+++ b/media/libaudioclient/include/media/AudioClient.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#ifndef ANDROID_AUDIO_CLIENT_H
+#define ANDROID_AUDIO_CLIENT_H
+
+#include <system/audio.h>
+#include <utils/String16.h>
+
+namespace android {
+
+class AudioClient {
+ public:
+    AudioClient() :
+        clientUid(-1), clientPid(-1), packageName("") {}
+
+    uid_t clientUid;
+    pid_t clientPid;
+    String16 packageName;
+};
+
+}; // namespace android
+
+#endif  // ANDROID_AUDIO_CLIENT_H
diff --git a/media/libaudioclient/include/media/AudioMixer.h b/media/libaudioclient/include/media/AudioMixer.h
index 87ada76..2bd2d01 100644
--- a/media/libaudioclient/include/media/AudioMixer.h
+++ b/media/libaudioclient/include/media/AudioMixer.h
@@ -286,7 +286,7 @@
         process_hook_t  hook;   // one of process__*, never NULL
         int32_t         *outputTemp;
         int32_t         *resampleTemp;
-        NBLog::Writer*  mLog;
+        NBLog::Writer*  mNBLogWriter;   // associated NBLog::Writer or &mDummyLog
         int32_t         reserved[1];
         // FIXME allocate dynamically to save some memory when maxNumTracks < MAX_NUM_TRACKS
         track_t         tracks[MAX_NUM_TRACKS] __attribute__((aligned(32)));
@@ -301,9 +301,11 @@
 
     const uint32_t  mSampleRate;
 
-    NBLog::Writer   mDummyLog;
+    NBLog::Writer   mDummyLogWriter;
 public:
-    void            setLog(NBLog::Writer* log);
+    // Called by FastMixer to inform AudioMixer of it's associated NBLog::Writer.
+    // FIXME It would be safer to use TLS for this, so we don't accidentally use wrong one.
+    void            setNBLogWriter(NBLog::Writer* log);
 private:
     state_t         mState __attribute__((aligned(32)));
 
diff --git a/media/libaudioclient/include/media/AudioPolicyHelper.h b/media/libaudioclient/include/media/AudioPolicyHelper.h
index 854057d..73ee0a7 100644
--- a/media/libaudioclient/include/media/AudioPolicyHelper.h
+++ b/media/libaudioclient/include/media/AudioPolicyHelper.h
@@ -18,9 +18,8 @@
 
 #include <system/audio.h>
 
-// TODO: fix this among dependencies
-__attribute__((unused))
-static audio_stream_type_t audio_attributes_to_stream_type(const audio_attributes_t *attr)
+static inline
+audio_stream_type_t audio_attributes_to_stream_type(const audio_attributes_t *attr)
 {
     // flags to stream type mapping
     if ((attr->flags & AUDIO_FLAG_AUDIBILITY_ENFORCED) == AUDIO_FLAG_AUDIBILITY_ENFORCED) {
@@ -65,9 +64,8 @@
     }
 }
 
-// TODO: fix this among dependencies
-__attribute__((unused))
-static void stream_type_to_audio_attributes(audio_stream_type_t streamType,
+static inline
+void stream_type_to_audio_attributes(audio_stream_type_t streamType,
                                      audio_attributes_t *attr) {
     memset(attr, 0, sizeof(audio_attributes_t));
 
diff --git a/media/libaudioclient/include/media/AudioRecord.h b/media/libaudioclient/include/media/AudioRecord.h
index 1b034b5..e6a5efb 100644
--- a/media/libaudioclient/include/media/AudioRecord.h
+++ b/media/libaudioclient/include/media/AudioRecord.h
@@ -334,6 +334,12 @@
      */
             status_t getTimestamp(ExtendedTimestamp *timestamp);
 
+    /**
+     * @param transferType
+     * @return text string that matches the enum name
+     */
+    static const char * convertTransferToText(transfer_type transferType);
+
     /* Returns a handle on the audio input used by this AudioRecord.
      *
      * Parameters:
@@ -655,7 +661,10 @@
 
     // For Device Selection API
     //  a value of AUDIO_PORT_HANDLE_NONE indicated default (AudioPolicyManager) routing.
-    audio_port_handle_t    mSelectedDeviceId;
+    audio_port_handle_t     mSelectedDeviceId; // Device requested by the application.
+    audio_port_handle_t     mRoutedDeviceId;   // Device actually selected by audio policy manager:
+                                              // May not match the app selection depending on other
+                                              // activity and connected devices
     sp<AudioSystem::AudioDeviceCallback> mDeviceCallback;
     audio_port_handle_t    mPortId;  // unique ID allocated by audio policy
 
diff --git a/media/libaudioclient/include/media/AudioSystem.h b/media/libaudioclient/include/media/AudioSystem.h
index 853d318..2e39d23 100644
--- a/media/libaudioclient/include/media/AudioSystem.h
+++ b/media/libaudioclient/include/media/AudioSystem.h
@@ -224,7 +224,7 @@
                                      uid_t uid,
                                      const audio_config_t *config,
                                      audio_output_flags_t flags,
-                                     audio_port_handle_t selectedDeviceId,
+                                     audio_port_handle_t *selectedDeviceId,
                                      audio_port_handle_t *portId);
     static status_t startOutput(audio_io_handle_t output,
                                 audio_stream_type_t stream,
@@ -245,7 +245,7 @@
                                     uid_t uid,
                                     const audio_config_base_t *config,
                                     audio_input_flags_t flags,
-                                    audio_port_handle_t selectedDeviceId,
+                                    audio_port_handle_t *selectedDeviceId,
                                     audio_port_handle_t *portId);
 
     static status_t startInput(audio_io_handle_t input,
@@ -338,6 +338,9 @@
     static status_t setMasterMono(bool mono);
     static status_t getMasterMono(bool *mono);
 
+    static float    getStreamVolumeDB(
+            audio_stream_type_t stream, int index, audio_devices_t device);
+
     // ----------------------------------------------------------------------------
 
     class AudioPortCallback : public RefBase
diff --git a/media/libaudioclient/include/media/AudioTrack.h b/media/libaudioclient/include/media/AudioTrack.h
index a4c8d53..b168fc9 100644
--- a/media/libaudioclient/include/media/AudioTrack.h
+++ b/media/libaudioclient/include/media/AudioTrack.h
@@ -326,7 +326,7 @@
      * This includes the latency due to AudioTrack buffer size, AudioMixer (if any)
      * and audio hardware driver.
      */
-            uint32_t    latency() const     { return mLatency; }
+            uint32_t    latency();
 
     /* Returns the number of application-level buffer underruns
      * since the AudioTrack was created.
@@ -564,6 +564,12 @@
      */
             status_t    reload();
 
+    /**
+     * @param transferType
+     * @return text string that matches the enum name
+     */
+            static const char * convertTransferToText(transfer_type transferType);
+
     /* Returns a handle on the audio output used by this AudioTrack.
      *
      * Parameters:
@@ -927,6 +933,8 @@
 
             // caller must hold lock on mLock for all _l methods
 
+            void updateLatency_l(); // updates mAfLatency and mLatency from AudioSystem cache
+
             status_t createTrack_l();
 
             // can only be called when mState != STATE_ACTIVE
@@ -962,7 +970,7 @@
             Modulo<uint32_t> updateAndGetPosition_l();
 
             // check sample rate and speed is compatible with AudioTrack
-            bool     isSampleRateSpeedAllowed_l(uint32_t sampleRate, float speed) const;
+            bool     isSampleRateSpeedAllowed_l(uint32_t sampleRate, float speed);
 
             void     restartIfDisabled();
 
@@ -1133,7 +1141,10 @@
 
     // For Device Selection API
     //  a value of AUDIO_PORT_HANDLE_NONE indicated default (AudioPolicyManager) routing.
-    audio_port_handle_t     mSelectedDeviceId;
+    audio_port_handle_t    mSelectedDeviceId; // Device requested by the application.
+    audio_port_handle_t    mRoutedDeviceId;   // Device actually selected by audio policy manager:
+                                              // May not match the app selection depending on other
+                                              // activity and connected devices.
 
     sp<VolumeHandler>       mVolumeHandler;
 
diff --git a/media/libaudioclient/include/media/IAudioPolicyService.h b/media/libaudioclient/include/media/IAudioPolicyService.h
index e8abafb..eec3e88 100644
--- a/media/libaudioclient/include/media/IAudioPolicyService.h
+++ b/media/libaudioclient/include/media/IAudioPolicyService.h
@@ -68,7 +68,7 @@
                                       uid_t uid,
                                       const audio_config_t *config,
                                       audio_output_flags_t flags,
-                                      audio_port_handle_t selectedDeviceId,
+                                      audio_port_handle_t *selectedDeviceId,
                                       audio_port_handle_t *portId) = 0;
     virtual status_t startOutput(audio_io_handle_t output,
                                  audio_stream_type_t stream,
@@ -86,7 +86,7 @@
                               uid_t uid,
                               const audio_config_base_t *config,
                               audio_input_flags_t flags,
-                              audio_port_handle_t selectedDeviceId,
+                              audio_port_handle_t *selectedDeviceId,
                               audio_port_handle_t *portId) = 0;
     virtual status_t startInput(audio_io_handle_t input,
                                 audio_session_t session) = 0;
@@ -169,6 +169,8 @@
 
     virtual status_t setMasterMono(bool mono) = 0;
     virtual status_t getMasterMono(bool *mono) = 0;
+    virtual float    getStreamVolumeDB(
+            audio_stream_type_t stream, int index, audio_devices_t device) = 0;
 };
 
 
diff --git a/media/libaudioclient/include/media/PlayerBase.h b/media/libaudioclient/include/media/PlayerBase.h
index fe1db7b..e63090b 100644
--- a/media/libaudioclient/include/media/PlayerBase.h
+++ b/media/libaudioclient/include/media/PlayerBase.h
@@ -48,6 +48,8 @@
 
 
             status_t startWithStatus();
+            status_t pauseWithStatus();
+            status_t stopWithStatus();
 
             //FIXME temporary method while some player state is outside of this class
             void reportEvent(player_state_t event);
diff --git a/media/libaudioprocessing/AudioMixer.cpp b/media/libaudioprocessing/AudioMixer.cpp
index 05b726a..238925d 100644
--- a/media/libaudioprocessing/AudioMixer.cpp
+++ b/media/libaudioprocessing/AudioMixer.cpp
@@ -27,7 +27,6 @@
 #include <utils/Errors.h>
 #include <utils/Log.h>
 
-#include <cutils/bitops.h>
 #include <cutils/compiler.h>
 #include <utils/Debug.h>
 
@@ -115,7 +114,7 @@
     mState.hook         = process__nop;
     mState.outputTemp   = NULL;
     mState.resampleTemp = NULL;
-    mState.mLog         = &mDummyLog;
+    mState.mNBLogWriter = &mDummyLogWriter;
     // mState.reserved
 
     // FIXME Most of the following initialization is probably redundant since
@@ -146,9 +145,9 @@
     delete [] mState.resampleTemp;
 }
 
-void AudioMixer::setLog(NBLog::Writer *log)
+void AudioMixer::setNBLogWriter(NBLog::Writer *logWriter)
 {
-    mState.mLog = log;
+    mState.mNBLogWriter = logWriter;
 }
 
 static inline audio_format_t selectMixerInFormat(audio_format_t inputFormat __unused) {
diff --git a/media/libcpustats/Android.bp b/media/libcpustats/Android.bp
new file mode 100644
index 0000000..8fcd8a4
--- /dev/null
+++ b/media/libcpustats/Android.bp
@@ -0,0 +1,22 @@
+cc_library_static {
+    name: "libcpustats",
+
+    srcs: [
+        "CentralTendencyStatistics.cpp",
+        "ThreadCpuUsage.cpp",
+    ],
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+    ],
+
+    host_supported: true,
+
+    target: {
+        darwin: {
+            enabled: false,
+        },
+    },
+
+}
diff --git a/media/libcpustats/Android.mk b/media/libcpustats/Android.mk
deleted file mode 100644
index b2d73ee..0000000
--- a/media/libcpustats/Android.mk
+++ /dev/null
@@ -1,13 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES :=     \
-        CentralTendencyStatistics.cpp \
-        ThreadCpuUsage.cpp
-
-LOCAL_MODULE := libcpustats
-
-LOCAL_CFLAGS := -Werror -Wall
-
-include $(BUILD_STATIC_LIBRARY)
diff --git a/media/libcpustats/ThreadCpuUsage.cpp b/media/libcpustats/ThreadCpuUsage.cpp
index b43b36c..4b7549f 100644
--- a/media/libcpustats/ThreadCpuUsage.cpp
+++ b/media/libcpustats/ThreadCpuUsage.cpp
@@ -26,6 +26,11 @@
 
 #include <cpustats/ThreadCpuUsage.h>
 
+// implemented by host, but not declared in <string.h> as FreeBSD does
+extern "C" {
+    extern size_t strlcpy(char *dst, const char *src, size_t dstsize);
+}
+
 namespace android {
 
 bool ThreadCpuUsage::setEnabled(bool isEnabled)
diff --git a/media/libeffects/downmix/Android.mk b/media/libeffects/downmix/Android.mk
index 09793d1..73f6ef5 100644
--- a/media/libeffects/downmix/Android.mk
+++ b/media/libeffects/downmix/Android.mk
@@ -23,4 +23,5 @@
 LOCAL_CFLAGS += -fvisibility=hidden
 LOCAL_CFLAGS += -Wall -Werror
 
+LOCAL_HEADER_LIBRARIES += libhardware_headers
 include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libeffects/loudness/Android.mk b/media/libeffects/loudness/Android.mk
index 4b1c584..712cbd5 100644
--- a/media/libeffects/loudness/Android.mk
+++ b/media/libeffects/loudness/Android.mk
@@ -5,20 +5,20 @@
 
 LOCAL_VENDOR_MODULE := true
 LOCAL_SRC_FILES:= \
-	EffectLoudnessEnhancer.cpp \
-	dsp/core/dynamic_range_compression.cpp
+    EffectLoudnessEnhancer.cpp \
+    dsp/core/dynamic_range_compression.cpp
 
 LOCAL_CFLAGS+= -O2 -fvisibility=hidden
 LOCAL_CFLAGS += -Wall -Werror
 
 LOCAL_SHARED_LIBRARIES := \
-	libcutils \
-	liblog \
+    libcutils \
+    liblog \
 
 LOCAL_MODULE_RELATIVE_PATH := soundfx
 LOCAL_MODULE:= libldnhncr
 
-LOCAL_C_INCLUDES := \
-	$(call include-path-for, audio-effects) \
+LOCAL_HEADER_LIBRARIES := \
+    libaudioeffects
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libeffects/lvm/wrapper/Android.mk b/media/libeffects/lvm/wrapper/Android.mk
index f92fb95..efd30fb 100644
--- a/media/libeffects/lvm/wrapper/Android.mk
+++ b/media/libeffects/lvm/wrapper/Android.mk
@@ -30,6 +30,7 @@
 	$(LOCAL_PATH)/../lib/Bundle/lib/ \
 	$(call include-path-for, audio-effects)
 
+LOCAL_HEADER_LIBRARIES += libhardware_headers
 include $(BUILD_SHARED_LIBRARY)
 
 
@@ -62,4 +63,5 @@
     $(LOCAL_PATH)/../lib/Reverb/lib/ \
     $(call include-path-for, audio-effects)
 
+LOCAL_HEADER_LIBRARIES += libhardware_headers
 include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libeffects/preprocessing/Android.mk b/media/libeffects/preprocessing/Android.mk
index 06d8237..358da8b 100644
--- a/media/libeffects/preprocessing/Android.mk
+++ b/media/libeffects/preprocessing/Android.mk
@@ -3,6 +3,7 @@
 # audio preprocessing wrapper
 include $(CLEAR_VARS)
 
+LOCAL_VENDOR_MODULE := true
 LOCAL_MODULE:= libaudiopreprocessing
 LOCAL_MODULE_TAGS := optional
 LOCAL_MODULE_RELATIVE_PATH := soundfx
@@ -31,4 +32,5 @@
 LOCAL_CFLAGS += -fvisibility=hidden
 LOCAL_CFLAGS += -Wall -Werror
 
+LOCAL_HEADER_LIBRARIES += libhardware_headers
 include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libeffects/visualizer/Android.mk b/media/libeffects/visualizer/Android.mk
index 8687e1b..70409de 100644
--- a/media/libeffects/visualizer/Android.mk
+++ b/media/libeffects/visualizer/Android.mk
@@ -22,4 +22,5 @@
 	$(call include-path-for, audio-effects)
 
 
+LOCAL_HEADER_LIBRARIES += libhardware_headers
 include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libmedia/Android.bp b/media/libmedia/Android.bp
index 11a498d..bbe97ee 100644
--- a/media/libmedia/Android.bp
+++ b/media/libmedia/Android.bp
@@ -13,8 +13,226 @@
         "-Wno-error=deprecated-declarations",
         "-Wall",
     ],
-    shared: {
-      shared_libs: ["libutils", "liblog"],
-    },
+    shared_libs: ["libutils", "liblog", "libgui"],
+    header_libs: [
+        "libmedia_headers",
+        "libaudioclient_headers",
+        "libaudio_system_headers",
+    ],
     clang: true,
 }
+
+// TODO(b/35449087): merge back with libmedia when OMX implementatoins
+// no longer use aidl wrappers (or remove OMX component form libmedia)
+cc_defaults {
+    name: "libmedia_omx_defaults",
+
+    srcs: [
+        "aidl/android/IGraphicBufferSource.aidl",
+        "aidl/android/IOMXBufferSource.aidl",
+
+        "IMediaCodecList.cpp",
+        "IMediaCodecService.cpp",
+        "IOMX.cpp",
+        "MediaCodecBuffer.cpp",
+        "MediaCodecInfo.cpp",
+        "MediaDefs.cpp",
+        "OMXBuffer.cpp",
+        "omx/1.0/WGraphicBufferSource.cpp",
+        "omx/1.0/WOmx.cpp",
+        "omx/1.0/WOmxBufferSource.cpp",
+        "omx/1.0/WOmxNode.cpp",
+        "omx/1.0/WOmxObserver.cpp",
+    ],
+
+    aidl: {
+        local_include_dirs: ["aidl"],
+        export_aidl_headers: true,
+    },
+
+    shared_libs: [
+        "android.hidl.memory@1.0",
+        "android.hidl.token@1.0-utils",
+        "android.hardware.media.omx@1.0",
+        "android.hardware.media@1.0",
+        "libbase",
+        "libbinder",
+        "libcutils",
+        "libgui",
+        "libhidlbase",
+        "libhidlmemory",
+        "libhidltransport",
+        "libhwbinder",
+        "liblog",
+        "libstagefright_foundation",
+        "libui",
+        "libutils",
+    ],
+
+    include_dirs: [
+        "frameworks/av/include", // for media/vndk/xmlparser/1.0/MediaCodecsXmlParser.h
+        "frameworks/av/include/media",
+        "frameworks/native/include", // for media/hardware/MetadataBufferType.h
+        "frameworks/native/include/media/openmax",
+        "frameworks/av/media/libstagefright",
+    ],
+
+    export_shared_lib_headers: [
+        "android.hidl.memory@1.0",
+        "android.hidl.token@1.0-utils",
+        "android.hardware.media.omx@1.0",
+        "android.hardware.media@1.0",
+        "libhidlmemory",
+        "libstagefright_foundation",
+        "libui",
+    ],
+
+    header_libs: [
+        "libmedia_headers",
+    ],
+
+    export_header_lib_headers: [
+        "libmedia_headers",
+    ],
+
+    export_include_dirs: [
+        "aidl",
+    ],
+
+    cflags: [
+        "-Werror",
+        "-Wno-error=deprecated-declarations",
+        "-Wall",
+    ],
+
+    sanitize: {
+        misc_undefined: [
+            "unsigned-integer-overflow",
+            "signed-integer-overflow",
+        ],
+        cfi: true,
+        diag: {
+            cfi: true,
+        },
+    },
+}
+
+cc_library_shared {
+    name: "libmedia_omx",
+    vendor_available: true,
+
+    defaults: ["libmedia_omx_defaults"],
+}
+
+cc_library_shared {
+    name: "libmedia",
+    defaults: ["libmedia_omx_defaults"],
+
+    srcs: [
+        "IDataSource.cpp",
+        "IHDCP.cpp",
+        "BufferingSettings.cpp",
+        "mediaplayer.cpp",
+        "IMediaHTTPConnection.cpp",
+        "IMediaHTTPService.cpp",
+        "IMediaExtractor.cpp",
+        "IMediaExtractorService.cpp",
+        "IMediaPlayerService.cpp",
+        "IMediaPlayerClient.cpp",
+        "IMediaRecorderClient.cpp",
+        "IMediaPlayer.cpp",
+        "IMediaRecorder.cpp",
+        "IMediaSource.cpp",
+        "IRemoteDisplay.cpp",
+        "IRemoteDisplayClient.cpp",
+        "IResourceManagerClient.cpp",
+        "IResourceManagerService.cpp",
+        "IStreamSource.cpp",
+        "MediaUtils.cpp",
+        "Metadata.cpp",
+        "mediarecorder.cpp",
+        "IMediaMetadataRetriever.cpp",
+        "mediametadataretriever.cpp",
+        "MidiDeviceInfo.cpp",
+        "MidiIoWrapper.cpp",
+        "JetPlayer.cpp",
+        "MediaScanner.cpp",
+        "MediaScannerClient.cpp",
+        "CharacterEncodingDetector.cpp",
+        "IMediaDeathNotifier.cpp",
+        "MediaProfiles.cpp",
+        "MediaResource.cpp",
+        "MediaResourcePolicy.cpp",
+        "Visualizer.cpp",
+        "StringArray.cpp",
+    ],
+
+    shared_libs: [
+        "libui",
+        "liblog",
+        "libcutils",
+        "libutils",
+        "libbinder",
+        "libsonivox",
+        "libicuuc",
+        "libicui18n",
+        "libexpat",
+        "libcamera_client",
+        "libstagefright_foundation",
+        "libgui",
+        "libdl",
+        "libaudioutils",
+        "libaudioclient",
+        "libmedia_helper",
+        "libmediadrm",
+        "libmediametrics",
+        "libbase",
+        "libhidlbase",
+        "libhidltransport",
+        "libhwbinder",
+        "libhidlmemory",
+        "android.hidl.memory@1.0",
+        "android.hardware.graphics.common@1.0",
+        "android.hardware.graphics.bufferqueue@1.0",
+    ],
+
+    export_shared_lib_headers: [
+        "libbinder",
+        "libicuuc",
+        "libicui18n",
+        "libsonivox",
+        "libmediadrm",
+        "android.hidl.memory@1.0",
+    ],
+
+    // for memory heap analysis
+    static_libs: [
+        "libc_malloc_debug_backtrace",
+    ],
+
+    include_dirs: [
+        "frameworks/native/include/media/openmax",
+        "frameworks/av/include/media/",
+        "frameworks/av/media/libstagefright",
+    ],
+
+    export_include_dirs: [
+        "include",
+    ],
+    cflags: [
+        "-Werror",
+        "-Wno-error=deprecated-declarations",
+        "-Wall",
+    ],
+
+    sanitize: {
+        misc_undefined: [
+            "unsigned-integer-overflow",
+            "signed-integer-overflow",
+        ],
+        cfi: true,
+        diag: {
+            cfi: true,
+        },
+    },
+}
diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk
deleted file mode 100644
index e667786..0000000
--- a/media/libmedia/Android.mk
+++ /dev/null
@@ -1,115 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_AIDL_INCLUDES := \
-    frameworks/av/media/libmedia/aidl
-
-LOCAL_SRC_FILES:= \
-    aidl/android/IGraphicBufferSource.aidl \
-    aidl/android/IOMXBufferSource.aidl
-
-LOCAL_SRC_FILES += \
-    IDataSource.cpp \
-    IHDCP.cpp \
-    BufferingSettings.cpp \
-    mediaplayer.cpp \
-    IMediaCodecList.cpp \
-    IMediaCodecService.cpp \
-    IMediaHTTPConnection.cpp \
-    IMediaHTTPService.cpp \
-    IMediaExtractor.cpp           \
-    IMediaExtractorService.cpp \
-    IMediaPlayerService.cpp \
-    IMediaPlayerClient.cpp \
-    IMediaRecorderClient.cpp \
-    IMediaPlayer.cpp \
-    IMediaRecorder.cpp \
-    IMediaSource.cpp \
-    IRemoteDisplay.cpp \
-    IRemoteDisplayClient.cpp \
-    IResourceManagerClient.cpp \
-    IResourceManagerService.cpp \
-    IStreamSource.cpp \
-    MediaCodecBuffer.cpp \
-    MediaCodecInfo.cpp \
-    MediaDefs.cpp \
-    MediaUtils.cpp \
-    Metadata.cpp \
-    mediarecorder.cpp \
-    IMediaMetadataRetriever.cpp \
-    mediametadataretriever.cpp \
-    MidiDeviceInfo.cpp \
-    MidiIoWrapper.cpp \
-    JetPlayer.cpp \
-    IOMX.cpp \
-    MediaScanner.cpp \
-    MediaScannerClient.cpp \
-    CharacterEncodingDetector.cpp \
-    IMediaDeathNotifier.cpp \
-    MediaProfiles.cpp \
-    MediaResource.cpp \
-    MediaResourcePolicy.cpp \
-    OMXBuffer.cpp \
-    Visualizer.cpp \
-    StringArray.cpp \
-    omx/1.0/WGraphicBufferSource.cpp \
-    omx/1.0/WOmx.cpp \
-    omx/1.0/WOmxBufferSource.cpp \
-    omx/1.0/WOmxNode.cpp \
-    omx/1.0/WOmxObserver.cpp \
-
-LOCAL_SHARED_LIBRARIES := \
-        libui liblog libcutils libutils libbinder libsonivox libicuuc libicui18n libexpat \
-        libcamera_client libstagefright_foundation \
-        libgui libdl libaudioutils libaudioclient \
-        libmedia_helper libmediadrm \
-        libmediametrics \
-        libbase \
-        libhidlbase \
-        libhidltransport \
-        libhwbinder \
-        libhidlmemory \
-        android.hidl.base@1.0 \
-        android.hidl.memory@1.0 \
-        android.hidl.token@1.0-utils \
-        android.hardware.graphics.common@1.0 \
-        android.hardware.graphics.bufferqueue@1.0 \
-        android.hardware.media@1.0 \
-        android.hardware.media.omx@1.0 \
-
-LOCAL_EXPORT_SHARED_LIBRARY_HEADERS := \
-        libbinder \
-        libsonivox \
-        libmediadrm \
-        android.hidl.token@1.0-utils \
-        android.hardware.media.omx@1.0 \
-        android.hidl.memory@1.0 \
-
-LOCAL_HEADER_LIBRARIES := libmedia_headers
-
-# for memory heap analysis
-LOCAL_STATIC_LIBRARIES := libc_malloc_debug_backtrace libc_logging
-
-LOCAL_MODULE:= libmedia
-
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-
-LOCAL_C_INCLUDES := \
-    $(TOP)/system/libhidl/base/include \
-    $(TOP)/frameworks/native/include/media/openmax \
-    $(TOP)/frameworks/av/include/media/ \
-    $(TOP)/frameworks/av/media/libmedia/aidl \
-    $(TOP)/frameworks/av/include \
-    $(TOP)/frameworks/native/include \
-    $(call include-path-for, audio-utils)
-
-LOCAL_EXPORT_C_INCLUDE_DIRS := \
-    frameworks/av/include/media \
-    frameworks/av/media/libmedia/aidl \
-
-LOCAL_CFLAGS += -Werror -Wno-error=deprecated-declarations -Wall
-LOCAL_SANITIZE := unsigned-integer-overflow signed-integer-overflow cfi
-LOCAL_SANITIZE_DIAG := cfi
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libmedia/MediaCodecInfo.cpp b/media/libmedia/MediaCodecInfo.cpp
index 62a7bdf..1f188f3 100644
--- a/media/libmedia/MediaCodecInfo.cpp
+++ b/media/libmedia/MediaCodecInfo.cpp
@@ -85,13 +85,13 @@
 }
 
 status_t MediaCodecInfo::Capabilities::writeToParcel(Parcel *parcel) const {
-    CHECK_LE(mProfileLevels.size(), INT32_MAX);
+    CHECK_LE(mProfileLevels.size(), static_cast<size_t>(INT32_MAX));
     parcel->writeInt32(mProfileLevels.size());
     for (size_t i = 0; i < mProfileLevels.size(); i++) {
         parcel->writeInt32(mProfileLevels.itemAt(i).mProfile);
         parcel->writeInt32(mProfileLevels.itemAt(i).mLevel);
     }
-    CHECK_LE(mColorFormats.size(), INT32_MAX);
+    CHECK_LE(mColorFormats.size(), static_cast<size_t>(INT32_MAX));
     parcel->writeInt32(mColorFormats.size());
     for (size_t i = 0; i < mColorFormats.size(); i++) {
         parcel->writeInt32(mColorFormats.itemAt(i));
diff --git a/media/libmedia/Visualizer.cpp b/media/libmedia/Visualizer.cpp
index 37bf0bd..4984b18 100644
--- a/media/libmedia/Visualizer.cpp
+++ b/media/libmedia/Visualizer.cpp
@@ -24,8 +24,6 @@
 #include <sys/types.h>
 #include <limits.h>
 
-#include <cutils/bitops.h>
-
 #include <media/Visualizer.h>
 #include <audio_utils/fixedfft.h>
 #include <utils/Thread.h>
diff --git a/media/libmedia/aidl/android/IGraphicBufferSource.aidl b/media/libmedia/aidl/android/IGraphicBufferSource.aidl
index f3c7abc..12c2767 100644
--- a/media/libmedia/aidl/android/IGraphicBufferSource.aidl
+++ b/media/libmedia/aidl/android/IGraphicBufferSource.aidl
@@ -31,6 +31,7 @@
     void setTimeLapseConfig(double fps, double captureFps);
     void setStartTimeUs(long startTimeUs);
     void setStopTimeUs(long stopTimeUs);
+    long getStopTimeOffsetUs();
     void setColorAspects(int aspects);
     void setTimeOffsetUs(long timeOffsetsUs);
     void signalEndOfInputStream();
diff --git a/media/libmedia/include/media/MediaRecorderBase.h b/media/libmedia/include/media/MediaRecorderBase.h
index 0b0f916..40dd9f9 100644
--- a/media/libmedia/include/media/MediaRecorderBase.h
+++ b/media/libmedia/include/media/MediaRecorderBase.h
@@ -45,7 +45,7 @@
                                const sp<ICameraRecordingProxy>& proxy) = 0;
     virtual status_t setPreviewSurface(const sp<IGraphicBufferProducer>& surface) = 0;
     virtual status_t setOutputFile(int fd) = 0;
-    virtual status_t setNextOutputFile(int fd) {return INVALID_OPERATION;}
+    virtual status_t setNextOutputFile(int /*fd*/) {return INVALID_OPERATION;}
     virtual status_t setOutputFileAuxiliary(int /*fd*/) {return INVALID_OPERATION;}
     virtual status_t setParameters(const String8& params) = 0;
     virtual status_t setListener(const sp<IMediaRecorderClient>& listener) = 0;
diff --git a/media/libmedia/include/media/OMXBuffer.h b/media/libmedia/include/media/OMXBuffer.h
index 6f79182..3e84858 100644
--- a/media/libmedia/include/media/OMXBuffer.h
+++ b/media/libmedia/include/media/OMXBuffer.h
@@ -19,7 +19,6 @@
 
 #include <cutils/native_handle.h>
 #include <media/IOMX.h>
-#include <system/window.h>
 #include <utils/StrongPointer.h>
 #include <hidl/HidlSupport.h>
 
diff --git a/media/libmedia/include/media/TypeConverter.h b/media/libmedia/include/media/TypeConverter.h
index cb8a307..84e22b1 100644
--- a/media/libmedia/include/media/TypeConverter.h
+++ b/media/libmedia/include/media/TypeConverter.h
@@ -203,7 +203,8 @@
     if (mask != 0) {
         bool first_flag = true;
         for (size_t i = 0; mTable[i].literal; i++) {
-            if (mTable[i].value != 0 && (mask & mTable[i].value) == mTable[i].value) {
+            uint32_t value = static_cast<uint32_t>(mTable[i].value);
+            if (mTable[i].value != 0 && ((mask & value) == value)) {
                 if (!first_flag) str += del;
                 first_flag = false;
                 str += mTable[i].literal;
@@ -228,6 +229,20 @@
 typedef TypeConverter<UsageTraits> UsageTypeConverter;
 typedef TypeConverter<SourceTraits> SourceTypeConverter;
 
+template<> const OutputDeviceConverter::Table OutputDeviceConverter::mTable[];
+template<> const InputDeviceConverter::Table InputDeviceConverter::mTable[];
+template<> const OutputFlagConverter::Table OutputFlagConverter::mTable[];
+template<> const InputFlagConverter::Table InputFlagConverter::mTable[];
+template<> const FormatConverter::Table FormatConverter::mTable[];
+template<> const OutputChannelConverter::Table OutputChannelConverter::mTable[];
+template<> const InputChannelConverter::Table InputChannelConverter::mTable[];
+template<> const ChannelIndexConverter::Table ChannelIndexConverter::mTable[];
+template<> const GainModeConverter::Table GainModeConverter::mTable[];
+template<> const StreamTypeConverter::Table StreamTypeConverter::mTable[];
+template<> const AudioModeConverter::Table AudioModeConverter::mTable[];
+template<> const UsageTypeConverter::Table UsageTypeConverter::mTable[];
+template<> const SourceTypeConverter::Table SourceTypeConverter::mTable[];
+
 bool deviceFromString(const std::string& literalDevice, audio_devices_t& device);
 
 bool deviceToString(audio_devices_t device, std::string& literalDevice);
diff --git a/media/libmedia/include/media/convert.h b/media/libmedia/include/media/convert.h
index 980b5d5..036c611 100644
--- a/media/libmedia/include/media/convert.h
+++ b/media/libmedia/include/media/convert.h
@@ -119,7 +119,7 @@
     /* Check for a '-' in string. If type is unsigned and a - is found, the
      * parsing fails. This is made necessary because "-1" is read as 65535 for
      * uint16_t, for example */
-    if (str.find("-") != std::string::npos
+    if (str.find('-') != std::string::npos
         && !std::numeric_limits<T>::is_signed) {
         return false;
     }
diff --git a/media/libmedia/omx/1.0/WGraphicBufferSource.cpp b/media/libmedia/omx/1.0/WGraphicBufferSource.cpp
index 4c543fa..31d1df9 100644
--- a/media/libmedia/omx/1.0/WGraphicBufferSource.cpp
+++ b/media/libmedia/omx/1.0/WGraphicBufferSource.cpp
@@ -67,6 +67,14 @@
     return toBinderStatus(mBase->setStopTimeUs(stopTimeUs));
 }
 
+BnStatus LWGraphicBufferSource::getStopTimeOffsetUs(
+        int64_t *stopTimeOffsetUs) {
+    return toBinderStatus(mBase->getStopTimeOffsetUs(
+            [stopTimeOffsetUs](auto, auto offsetUs) {
+                *stopTimeOffsetUs = offsetUs;
+            }));
+}
+
 BnStatus LWGraphicBufferSource::setColorAspects(
         int32_t aspects) {
     return toBinderStatus(mBase->setColorAspects(
diff --git a/media/libmedia/omx/1.0/WOmxNode.cpp b/media/libmedia/omx/1.0/WOmxNode.cpp
index 0933d1f..2cd8b76 100644
--- a/media/libmedia/omx/1.0/WOmxNode.cpp
+++ b/media/libmedia/omx/1.0/WOmxNode.cpp
@@ -47,7 +47,7 @@
     status_t transStatus = toStatusT(mBase->getParameter(
             toRawIndexType(index),
             tParams,
-            [&fnStatus, params, size](
+            [&fnStatus, params](
                     Status status, hidl_vec<uint8_t> const& outParams) {
                 fnStatus = toStatusT(status);
                 std::copy(
@@ -145,7 +145,7 @@
     status_t transStatus = toStatusT(mBase->allocateSecureBuffer(
             portIndex,
             static_cast<uint64_t>(size),
-            [&fnStatus, buffer, buffer_data, native_handle](
+            [&fnStatus, buffer, native_handle](
                     Status status,
                     uint32_t outBuffer,
                     hidl_handle const& outNativeHandle) {
diff --git a/media/libmediametrics/Android.bp b/media/libmediametrics/Android.bp
new file mode 100644
index 0000000..15dac59
--- /dev/null
+++ b/media/libmediametrics/Android.bp
@@ -0,0 +1,36 @@
+cc_library_shared {
+    name: "libmediametrics",
+
+    srcs: [
+        "IMediaAnalyticsService.cpp",
+        "MediaAnalyticsItem.cpp",
+    ],
+
+    shared_libs: [
+        "liblog",
+        "libcutils",
+        "libutils",
+        "libbinder",
+        "libstagefright_foundation",
+        "libbase",
+    ],
+
+    export_include_dirs: ["include"],
+
+    cflags: [
+        "-Werror",
+        "-Wno-error=deprecated-declarations",
+        "-Wall",
+    ],
+
+    sanitize: {
+        misc_undefined: [
+            "unsigned-integer-overflow",
+            "signed-integer-overflow",
+        ],
+        cfi: true,
+        diag: {
+            cfi: true,
+        },
+    },
+}
diff --git a/media/libmediametrics/Android.mk b/media/libmediametrics/Android.mk
deleted file mode 100644
index f8c4bb3..0000000
--- a/media/libmediametrics/Android.mk
+++ /dev/null
@@ -1,34 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES += \
-    IMediaAnalyticsService.cpp \
-    MediaAnalyticsItem.cpp \
-
-LOCAL_SHARED_LIBRARIES := \
-        liblog libcutils libutils libbinder \
-        libstagefright_foundation \
-        libbase \
-
-LOCAL_MODULE:= libmediametrics
-
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-
-LOCAL_C_INCLUDES := \
-    $(TOP)/system/libhidl/base/include \
-    $(TOP)/frameworks/native/include/media/openmax \
-    $(TOP)/frameworks/av/include/media/ \
-    $(TOP)/frameworks/av/media/libmedia/aidl \
-    $(TOP)/frameworks/av/include \
-    $(TOP)/frameworks/native/include \
-    $(call include-path-for, audio-utils)
-
-LOCAL_EXPORT_C_INCLUDE_DIRS := \
-    frameworks/av/include/media \
-
-LOCAL_CFLAGS += -Werror -Wno-error=deprecated-declarations -Wall
-LOCAL_SANITIZE := unsigned-integer-overflow signed-integer-overflow cfi
-LOCAL_SANITIZE_DIAG := cfi
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libmediaplayerservice/Android.mk b/media/libmediaplayerservice/Android.mk
index 7af7031..1fc74a9 100644
--- a/media/libmediaplayerservice/Android.mk
+++ b/media/libmediaplayerservice/Android.mk
@@ -49,15 +49,15 @@
 LOCAL_EXPORT_SHARED_LIBRARY_HEADERS := libmedia
 
 LOCAL_C_INCLUDES :=                                                 \
-    $(TOP)/frameworks/av/media/libstagefright/include               \
-    $(TOP)/frameworks/av/media/libstagefright/rtsp                  \
-    $(TOP)/frameworks/av/media/libstagefright/wifi-display          \
-    $(TOP)/frameworks/av/media/libstagefright/webm                  \
+    frameworks/av/media/libstagefright/include               \
+    frameworks/av/media/libstagefright/rtsp                  \
+    frameworks/av/media/libstagefright/wifi-display          \
+    frameworks/av/media/libstagefright/webm                  \
     $(LOCAL_PATH)/include/media                              \
-    $(TOP)/frameworks/av/include/camera                             \
-    $(TOP)/frameworks/native/include/media/openmax                  \
-    $(TOP)/frameworks/native/include/media/hardware                 \
-    $(TOP)/external/tremolo/Tremolo                                 \
+    frameworks/av/include/camera                             \
+    frameworks/native/include/media/openmax                  \
+    frameworks/native/include/media/hardware                 \
+    external/tremolo/Tremolo                                 \
 
 LOCAL_CFLAGS += -Werror -Wno-error=deprecated-declarations -Wall
 
@@ -65,6 +65,9 @@
 
 LOCAL_32_BIT_ONLY := true
 
+LOCAL_SANITIZE := cfi
+LOCAL_SANITIZE_DIAG := cfi
+
 include $(BUILD_SHARED_LIBRARY)
 
 include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index cb6404c..91887a1 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -2330,6 +2330,33 @@
             }
         }
     } else {
+        // VolumeShapers are not affected when a track moves between players for
+        // gapless playback (setNextMediaPlayer).
+        // We forward VolumeShaper operations that do not change configuration
+        // to the new player so that unducking may occur as expected.
+        // Unducking is an idempotent operation, same if applied back-to-back.
+        if (configuration->getType() == VolumeShaper::Configuration::TYPE_ID
+                && mNextOutput != nullptr) {
+            ALOGV("applyVolumeShaper: Attempting to forward missed operation: %s %s",
+                    configuration->toString().c_str(), operation->toString().c_str());
+            Mutex::Autolock nextLock(mNextOutput->mLock);
+
+            // recycled track should be forwarded from this AudioSink by switchToNextOutput
+            sp<AudioTrack> track = mNextOutput->mRecycledTrack;
+            if (track != nullptr) {
+                ALOGD("Forward VolumeShaper operation to recycled track %p", track.get());
+                (void)track->applyVolumeShaper(configuration, operation);
+            } else {
+                // There is a small chance that the unduck occurs after the next
+                // player has already started, but before it is registered to receive
+                // the unduck command.
+                track = mNextOutput->mTrack;
+                if (track != nullptr) {
+                    ALOGD("Forward VolumeShaper operation to track %p", track.get());
+                    (void)track->applyVolumeShaper(configuration, operation);
+                }
+            }
+        }
         status = mVolumeHandler->applyVolumeShaper(configuration, operation);
     }
     return status;
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index e1d762f..89354d6 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -1864,7 +1864,7 @@
         mStartTimeOffsetMs = mEncoderProfiles->getStartTimeOffsetMs(mCameraId);
     } else if (mVideoSource == VIDEO_SOURCE_SURFACE) {
         // surface source doesn't need large initial delay
-        mStartTimeOffsetMs = 200;
+        mStartTimeOffsetMs = 100;
     }
     if (mStartTimeOffsetMs > 0) {
         writer->setStartTimeOffsetMs(mStartTimeOffsetMs);
@@ -1982,10 +1982,12 @@
         mCameraSourceTimeLapse = NULL;
     }
 
-    if (mVideoEncoderSource != NULL) {
-        int64_t stopTimeUs = systemTime() / 1000;
-        sp<MetaData> meta = new MetaData;
-        err = mVideoEncoderSource->setStopStimeUs(stopTimeUs);
+    int64_t stopTimeUs = systemTime() / 1000;
+    for (const auto &source : { mAudioEncoderSource, mVideoEncoderSource }) {
+        if (source != nullptr && OK != source->setStopTimeUs(stopTimeUs)) {
+            ALOGW("Failed to set stopTime %lld us for %s",
+                    (long long)stopTimeUs, source->isVideo() ? "Video" : "Audio");
+        }
     }
 
     if (mWriter != NULL) {
diff --git a/media/libmediaplayerservice/include/MediaPlayerInterface.h b/media/libmediaplayerservice/include/MediaPlayerInterface.h
index 0ef3809..6d02cce 100644
--- a/media/libmediaplayerservice/include/MediaPlayerInterface.h
+++ b/media/libmediaplayerservice/include/MediaPlayerInterface.h
@@ -289,7 +289,7 @@
     }
 
     // Modular DRM
-    virtual status_t prepareDrm(const uint8_t uuid[16], const Vector<uint8_t>& drmSessionId) {
+    virtual status_t prepareDrm(const uint8_t /* uuid */[16], const Vector<uint8_t>& /* drmSessionId */) {
         return INVALID_OPERATION;
     }
     virtual status_t releaseDrm() {
diff --git a/media/libmediaplayerservice/nuplayer/Android.mk b/media/libmediaplayerservice/nuplayer/Android.mk
index 08c3cf8..c582631 100644
--- a/media/libmediaplayerservice/nuplayer/Android.mk
+++ b/media/libmediaplayerservice/nuplayer/Android.mk
@@ -17,14 +17,14 @@
         StreamingSource.cpp             \
 
 LOCAL_C_INCLUDES := \
-	$(TOP)/frameworks/av/media/libstagefright                     \
-	$(TOP)/frameworks/av/media/libstagefright/httplive            \
-	$(TOP)/frameworks/av/media/libstagefright/include             \
-	$(TOP)/frameworks/av/media/libstagefright/mpeg2ts             \
-	$(TOP)/frameworks/av/media/libstagefright/rtsp                \
-	$(TOP)/frameworks/av/media/libstagefright/timedtext           \
-	$(TOP)/frameworks/av/media/libmediaplayerservice              \
-	$(TOP)/frameworks/native/include/media/openmax
+	frameworks/av/media/libstagefright                     \
+	frameworks/av/media/libstagefright/httplive            \
+	frameworks/av/media/libstagefright/include             \
+	frameworks/av/media/libstagefright/mpeg2ts             \
+	frameworks/av/media/libstagefright/rtsp                \
+	frameworks/av/media/libstagefright/timedtext           \
+	frameworks/av/media/libmediaplayerservice              \
+	frameworks/native/include/media/openmax
 
 LOCAL_CFLAGS += -Werror -Wall
 
@@ -44,5 +44,7 @@
 
 LOCAL_MODULE_TAGS := eng
 
-include $(BUILD_STATIC_LIBRARY)
+LOCAL_SANITIZE := cfi
+LOCAL_SANITIZE_DIAG := cfi
 
+include $(BUILD_STATIC_LIBRARY)
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
index d83c406..aa21fff 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
@@ -1242,6 +1242,16 @@
         mAudioLastDequeueTimeUs = seekTimeUs;
     }
 
+    if (mSubtitleTrack.mSource != NULL) {
+        mSubtitleTrack.mPackets->clear();
+        mFetchSubtitleDataGeneration++;
+    }
+
+    if (mTimedTextTrack.mSource != NULL) {
+        mTimedTextTrack.mPackets->clear();
+        mFetchTimedTextDataGeneration++;
+    }
+
     // If currently buffering, post kWhatBufferingEnd first, so that
     // NuPlayer resumes. Otherwise, if cache hits high watermark
     // before new polling happens, no one will resume the playback.
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index 6ded392..6a09227 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -762,12 +762,13 @@
             }
 
             mDeferredActions.push_back(
-                    new FlushDecoderAction(FLUSH_CMD_FLUSH /* audio */,
+                    new FlushDecoderAction(
+                            (obj != NULL ? FLUSH_CMD_FLUSH : FLUSH_CMD_NONE) /* audio */,
                                            FLUSH_CMD_SHUTDOWN /* video */));
 
             mDeferredActions.push_back(new SetSurfaceAction(surface));
 
-            if (obj != NULL || mAudioDecoder != NULL) {
+            if (obj != NULL) {
                 if (mStarted) {
                     // Issue a seek to refresh the video screen only if started otherwise
                     // the extractor may not yet be started and will assert.
@@ -785,13 +786,13 @@
                 // again if possible.
                 mDeferredActions.push_back(
                         new SimpleAction(&NuPlayer::performScanSources));
-            }
 
-            // After a flush without shutdown, decoder is paused.
-            // Don't resume it until source seek is done, otherwise it could
-            // start pulling stale data too soon.
-            mDeferredActions.push_back(
-                    new ResumeDecoderAction(false /* needNotify */));
+                // After a flush without shutdown, decoder is paused.
+                // Don't resume it until source seek is done, otherwise it could
+                // start pulling stale data too soon.
+                mDeferredActions.push_back(
+                        new ResumeDecoderAction(false /* needNotify */));
+            }
 
             processDeferredActions();
             break;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
index 5775b43..758db1f 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
@@ -1110,7 +1110,7 @@
             // (Case 1)
             // Must be a multiple of the frame size.  If it is not a multiple of a frame size, it
             // needs to fail, as we should not carry over fractional frames between calls.
-            CHECK_EQ(copy % mAudioSink->frameSize(), 0);
+            CHECK_EQ(copy % mAudioSink->frameSize(), 0u);
 
             // (Case 2, 3, 4)
             // Return early to the caller.
diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
index 9264e49..8b3d0dc 100644
--- a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
@@ -544,7 +544,7 @@
         return;
     }
 
-    CHECK_EQ(msg->what(), (int)kWhatNotify);
+    CHECK_EQ(msg->what(), kWhatNotify);
 
     int32_t what;
     CHECK(msg->findInt32("what", &what));
diff --git a/media/libmediaplayerservice/tests/Android.mk b/media/libmediaplayerservice/tests/Android.mk
index dc761ec..0b9b85f 100644
--- a/media/libmediaplayerservice/tests/Android.mk
+++ b/media/libmediaplayerservice/tests/Android.mk
@@ -14,7 +14,6 @@
 	libmediaplayerservice \
 	libmediadrm \
 	libutils \
-	android.hidl.base@1.0 \
 	android.hardware.drm@1.0 \
 
 LOCAL_C_INCLUDES := \
diff --git a/media/libnbaio/NBLog.cpp b/media/libnbaio/NBLog.cpp
index de38e7f..ebb90c8 100644
--- a/media/libnbaio/NBLog.cpp
+++ b/media/libnbaio/NBLog.cpp
@@ -14,10 +14,85 @@
  * limitations under the License.
  */
 
+/*
+* Documentation: Workflow summary for histogram data processing:
+* For more details on FIFO, please see system/media/audio_utils; doxygen
+* TODO: add this documentation to doxygen once it is further developed
+* 1) writing the data to a buffer
+* onWork
+*     Called every period length (e.g., 4ms)
+*     Calls LOG_HIST_TS
+* LOG_HIST_TS
+*     Hashes file name and line number
+*     calls NBLOG::Writer::logHistTS once
+* NBLOG::Writer::logHistTS
+*     calls NBLOG::Writer::log on hash and current timestamp
+*     time is in CLOCK_MONOTONIC converted to ns
+* NBLOG::Writer::log(Event, const void*, size_t)
+*     Initializes Entry, a struct containing one log entry
+*     Entry contains the event type (mEvent), data length (mLength),
+*     and data pointer (mData)
+*     TODO: why mLength (max length of buffer data)  must be <= kMaxLength = 255?
+*     calls NBLOG::Writer::log(Entry *, bool)
+* NBLog::Writer::log(Entry *, bool)
+*     Calls copyEntryDataAt to format data as follows in temp array:
+*     [type][length][data ... ][length]
+*     calls audio_utils_fifo_writer.write on temp
+* audio_utils_fifo_writer.write
+*     calls obtain(), memcpy (reference in doxygen)
+*     returns number of frames written
+* ssize_t audio_utils_fifo_reader::obtain
+*     Determines readable buffer section via pointer arithmetic on reader
+*     and writer pointers
+*
+* 2) reading the data from shared memory
+* Thread::threadloop()
+*     TODO: add description?
+* NBLog::MergeThread::threadLoop()
+*     calls NBLog::Merger::merge
+* NBLog::Merger::merge
+*     for each reader in vector of class NamedReader,
+*     callsNamedReader::reader()->getSnapshot
+*     TODO: check whether the rest of this function is relevant
+* NBLog::Reader::getSnapshot
+*     copies snapshot of reader's fifo buffer into its own buffer
+*     calls mFifoReader->obtain to find readable data
+*     sets snapshot.begin() and .end() iterators to boundaries of valid entries
+*     moves the fifo reader index to after the last entry read
+*     in this case, the buffer is in shared memory. in (3), the buffer is private
+*
+* 3) reading the data from private buffer
+* MediaLogService::dump
+*     calls NBLog::Reader::dump(int) on instance of subclass mergeReader
+* NBLog::Reader::dump(int)
+*     calls getSnapshot on the current reader
+*     calls dump(int, size_t, Snapshot)
+* NBLog::Reader::dump(int, size, snapshot)
+*     iterates through snapshot's events and switches based on their type
+*     (string, timestamp, etc...)
+*     In the case of EVENT_HISTOGRAM_ENTRY_TS, adds a list of timestamp sequences
+*     (histogram entry) to NBLog::mHists
+*     In the case of EVENT_HISTOGRAM_FLUSH, calls drawHistogram on each element in
+*     the list and erases it
+*     TODO: when do these events occur?
+* NBLog::drawHistogram
+*     input: timestamp array
+*     buckets this to a histogram and prints
+*
+*/
+
 #define LOG_TAG "NBLog"
 //#define LOG_NDEBUG 0
 
+#include <algorithm>
 #include <climits>
+#include <deque>
+#include <fstream>
+// #include <inttypes.h>
+#include <iostream>
+#include <math.h>
+#include <numeric>
+#include <vector>
 #include <stdarg.h>
 #include <stdint.h>
 #include <stdio.h>
@@ -27,16 +102,18 @@
 #include <new>
 #include <audio_utils/roundup.h>
 #include <media/nbaio/NBLog.h>
+// #include <utils/CallStack.h> // used to print callstack
 #include <utils/Log.h>
 #include <utils/String8.h>
 
 #include <queue>
+#include <utility>
 
 namespace android {
 
-int NBLog::Entry::readAt(size_t offset) const
+int NBLog::Entry::copyEntryDataAt(size_t offset) const
 {
-    // FIXME This is too slow, despite the name it is used during writing
+    // FIXME This is too slow
     if (offset == 0)
         return mEvent;
     else if (offset == 1)
@@ -51,12 +128,29 @@
 
 // ---------------------------------------------------------------------------
 
-NBLog::FormatEntry::FormatEntry(const uint8_t *entry) : mEntry(entry) {
-    ALOGW_IF(entry[offsetof(struct entry, type)] != EVENT_START_FMT,
-        "Created format entry with invalid event type %d", entry[offsetof(struct entry, type)]);
+/*static*/
+std::unique_ptr<NBLog::AbstractEntry> NBLog::AbstractEntry::buildEntry(const uint8_t *ptr) {
+    const uint8_t type = EntryIterator(ptr)->type;
+    switch (type) {
+    case EVENT_START_FMT:
+        return std::make_unique<FormatEntry>(FormatEntry(ptr));
+    case EVENT_HISTOGRAM_FLUSH:
+    case EVENT_HISTOGRAM_ENTRY_TS:
+        return std::make_unique<HistogramEntry>(HistogramEntry(ptr));
+    default:
+        ALOGW("Tried to create AbstractEntry of type %d", type);
+        return nullptr;
+    }
 }
 
-NBLog::FormatEntry::FormatEntry(const NBLog::FormatEntry::iterator &it) : FormatEntry(it.ptr) {}
+NBLog::AbstractEntry::AbstractEntry(const uint8_t *entry) : mEntry(entry) {
+}
+
+// ---------------------------------------------------------------------------
+
+NBLog::EntryIterator NBLog::FormatEntry::begin() const {
+    return EntryIterator(mEntry);
+}
 
 const char *NBLog::FormatEntry::formatString() const {
     return (const char*) mEntry + offsetof(entry, data);
@@ -66,12 +160,14 @@
     return mEntry[offsetof(entry, length)];
 }
 
-NBLog::FormatEntry::iterator NBLog::FormatEntry::args() const {
+NBLog::EntryIterator NBLog::FormatEntry::args() const {
     auto it = begin();
     // skip start fmt
     ++it;
     // skip timestamp
     ++it;
+    // skip hash
+    ++it;
     // Skip author if present
     if (it->type == EVENT_AUTHOR) {
         ++it;
@@ -79,19 +175,33 @@
     return it;
 }
 
-timespec NBLog::FormatEntry::timestamp() const {
+int64_t NBLog::FormatEntry::timestamp() const {
     auto it = begin();
     // skip start fmt
     ++it;
-    return it.payload<timespec>();
+    return it.payload<int64_t>();
 }
 
-pid_t NBLog::FormatEntry::author() const {
+NBLog::log_hash_t NBLog::FormatEntry::hash() const {
     auto it = begin();
     // skip start fmt
     ++it;
     // skip timestamp
     ++it;
+    // unaligned 64-bit read not supported
+    log_hash_t hash;
+    memcpy(&hash, it->data, sizeof(hash));
+    return hash;
+}
+
+int NBLog::FormatEntry::author() const {
+    auto it = begin();
+    // skip start fmt
+    ++it;
+    // skip timestamp
+    ++it;
+    // skip hash
+    ++it;
     // if there is an author entry, return it, return -1 otherwise
     if (it->type == EVENT_AUTHOR) {
         return it.payload<int>();
@@ -99,12 +209,13 @@
     return -1;
 }
 
-NBLog::FormatEntry::iterator NBLog::FormatEntry::copyWithAuthor(
+NBLog::EntryIterator NBLog::FormatEntry::copyWithAuthor(
         std::unique_ptr<audio_utils_fifo_writer> &dst, int author) const {
     auto it = begin();
     // copy fmt start entry
     it.copyTo(dst);
     // copy timestamp
+    (++it).copyTo(dst);    // copy hash
     (++it).copyTo(dst);
     // insert author entry
     size_t authorEntrySize = NBLog::Entry::kOverhead + sizeof(author);
@@ -124,71 +235,103 @@
     return it;
 }
 
-void NBLog::FormatEntry::iterator::copyTo(std::unique_ptr<audio_utils_fifo_writer> &dst) const {
+void NBLog::EntryIterator::copyTo(std::unique_ptr<audio_utils_fifo_writer> &dst) const {
     size_t length = ptr[offsetof(entry, length)] + NBLog::Entry::kOverhead;
     dst->write(ptr, length);
 }
 
-void NBLog::FormatEntry::iterator::copyData(uint8_t *dst) const {
+void NBLog::EntryIterator::copyData(uint8_t *dst) const {
     memcpy((void*) dst, ptr + offsetof(entry, data), ptr[offsetof(entry, length)]);
 }
 
-NBLog::FormatEntry::iterator NBLog::FormatEntry::begin() const {
-    return iterator(mEntry);
-}
-
-NBLog::FormatEntry::iterator::iterator()
+NBLog::EntryIterator::EntryIterator()
     : ptr(nullptr) {}
 
-NBLog::FormatEntry::iterator::iterator(const uint8_t *entry)
+NBLog::EntryIterator::EntryIterator(const uint8_t *entry)
     : ptr(entry) {}
 
-NBLog::FormatEntry::iterator::iterator(const NBLog::FormatEntry::iterator &other)
+NBLog::EntryIterator::EntryIterator(const NBLog::EntryIterator &other)
     : ptr(other.ptr) {}
 
-const NBLog::FormatEntry::entry& NBLog::FormatEntry::iterator::operator*() const {
+const NBLog::entry& NBLog::EntryIterator::operator*() const {
     return *(entry*) ptr;
 }
 
-const NBLog::FormatEntry::entry* NBLog::FormatEntry::iterator::operator->() const {
+const NBLog::entry* NBLog::EntryIterator::operator->() const {
     return (entry*) ptr;
 }
 
-NBLog::FormatEntry::iterator& NBLog::FormatEntry::iterator::operator++() {
+NBLog::EntryIterator& NBLog::EntryIterator::operator++() {
     ptr += ptr[offsetof(entry, length)] + NBLog::Entry::kOverhead;
     return *this;
 }
 
-NBLog::FormatEntry::iterator& NBLog::FormatEntry::iterator::operator--() {
+NBLog::EntryIterator& NBLog::EntryIterator::operator--() {
     ptr -= ptr[NBLog::Entry::kPreviousLengthOffset] + NBLog::Entry::kOverhead;
     return *this;
 }
 
-NBLog::FormatEntry::iterator NBLog::FormatEntry::iterator::next() const {
-    iterator aux(*this);
+NBLog::EntryIterator NBLog::EntryIterator::next() const {
+    EntryIterator aux(*this);
     return ++aux;
 }
 
-NBLog::FormatEntry::iterator NBLog::FormatEntry::iterator::prev() const {
-    iterator aux(*this);
+NBLog::EntryIterator NBLog::EntryIterator::prev() const {
+    EntryIterator aux(*this);
     return --aux;
 }
 
-int NBLog::FormatEntry::iterator::operator-(const NBLog::FormatEntry::iterator &other) const {
+int NBLog::EntryIterator::operator-(const NBLog::EntryIterator &other) const {
     return ptr - other.ptr;
 }
 
-bool NBLog::FormatEntry::iterator::operator!=(const iterator &other) const {
+bool NBLog::EntryIterator::operator!=(const EntryIterator &other) const {
     return ptr != other.ptr;
 }
 
-bool NBLog::FormatEntry::iterator::hasConsistentLength() const {
+bool NBLog::EntryIterator::hasConsistentLength() const {
     return ptr[offsetof(entry, length)] == ptr[ptr[offsetof(entry, length)] +
         NBLog::Entry::kOverhead + NBLog::Entry::kPreviousLengthOffset];
 }
 
 // ---------------------------------------------------------------------------
 
+int64_t NBLog::HistogramEntry::timestamp() const {
+    return EntryIterator(mEntry).payload<HistTsEntry>().ts;
+}
+
+NBLog::log_hash_t NBLog::HistogramEntry::hash() const {
+    return EntryIterator(mEntry).payload<HistTsEntry>().hash;
+}
+
+int NBLog::HistogramEntry::author() const {
+    EntryIterator it(mEntry);
+    if (it->length == sizeof(HistTsEntryWithAuthor)) {
+        return it.payload<HistTsEntryWithAuthor>().author;
+    } else {
+        return -1;
+    }
+}
+
+NBLog::EntryIterator NBLog::HistogramEntry::copyWithAuthor(
+        std::unique_ptr<audio_utils_fifo_writer> &dst, int author) const {
+    // Current histogram entry has {type, length, struct HistTsEntry, length}.
+    // We now want {type, length, struct HistTsEntryWithAuthor, length}
+    uint8_t buffer[Entry::kOverhead + sizeof(HistTsEntryWithAuthor)];
+    // Copy content until the point we want to add the author
+    memcpy(buffer, mEntry, sizeof(entry) + sizeof(HistTsEntry));
+    // Copy the author
+    *(int*) (buffer + sizeof(entry) + sizeof(HistTsEntry)) = author;
+    // Update lengths
+    buffer[offsetof(entry, length)] = sizeof(HistTsEntryWithAuthor);
+    buffer[sizeof(buffer) + Entry::kPreviousLengthOffset] = sizeof(HistTsEntryWithAuthor);
+    // Write new buffer into FIFO
+    dst->write(buffer, sizeof(buffer));
+    return EntryIterator(mEntry).next();
+}
+
+// ---------------------------------------------------------------------------
+
 #if 0   // FIXME see note in NBLog.h
 NBLog::Timeline::Timeline(size_t size, void *shared)
     : mSize(roundup(size)), mOwn(shared == NULL),
@@ -301,13 +444,15 @@
     if (!mEnabled) {
         return;
     }
-    struct timespec ts;
-    if (!clock_gettime(CLOCK_MONOTONIC, &ts)) {
+    int64_t ts = get_monotonic_ns();
+    if (ts > 0) {
         log(EVENT_TIMESTAMP, &ts, sizeof(ts));
+    } else {
+        ALOGE("Failed to get timestamp");
     }
 }
 
-void NBLog::Writer::logTimestamp(const struct timespec &ts)
+void NBLog::Writer::logTimestamp(const int64_t ts)
 {
     if (!mEnabled) {
         return;
@@ -360,19 +505,57 @@
     log(&entry, true);
 }
 
-void NBLog::Writer::logFormat(const char *fmt, ...)
+void NBLog::Writer::logHash(log_hash_t hash)
+{
+    if (!mEnabled) {
+        return;
+    }
+    log(EVENT_HASH, &hash, sizeof(hash));
+}
+
+void NBLog::Writer::logHistTS(log_hash_t hash)
+{
+    if (!mEnabled) {
+        return;
+    }
+    HistTsEntry data;
+    data.hash = hash;
+    data.ts = get_monotonic_ns();
+    if (data.ts > 0) {
+        log(EVENT_HISTOGRAM_ENTRY_TS, &data, sizeof(data));
+    } else {
+        ALOGE("Failed to get timestamp");
+    }
+}
+
+void NBLog::Writer::logHistFlush(log_hash_t hash)
+{
+    if (!mEnabled) {
+        return;
+    }
+    HistTsEntry data;
+    data.hash = hash;
+    data.ts = get_monotonic_ns();
+    if (data.ts > 0) {
+        log(EVENT_HISTOGRAM_FLUSH, &data, sizeof(data));
+    } else {
+        ALOGE("Failed to get timestamp");
+    }
+}
+
+void NBLog::Writer::logFormat(const char *fmt, log_hash_t hash, ...)
 {
     if (!mEnabled) {
         return;
     }
 
     va_list ap;
-    va_start(ap, fmt);
-    Writer::logVFormat(fmt, ap);
+    va_start(ap, hash);
+    Writer::logVFormat(fmt, hash, ap);
     va_end(ap);
 }
 
-void NBLog::Writer::logVFormat(const char *fmt, va_list argp)
+void NBLog::Writer::logVFormat(const char *fmt, log_hash_t hash, va_list argp)
 {
     if (!mEnabled) {
         return;
@@ -381,8 +564,9 @@
     int i;
     double f;
     char* s;
-    struct timespec t;
+    int64_t t;
     Writer::logTimestamp();
+    Writer::logHash(hash);
     for (const char *p = fmt; *p != '\0'; p++) {
         // TODO: implement more complex formatting such as %.3f
         if (*p != '%') {
@@ -395,7 +579,7 @@
             break;
 
         case 't': // timestamp
-            t = va_arg(argp, struct timespec);
+            t = va_arg(argp, int64_t);
             Writer::logTimestamp(t);
             break;
 
@@ -440,40 +624,35 @@
         //      a confusion for a programmer debugging their code.
         return;
     }
-    switch (event) {
-    case EVENT_STRING:
-    case EVENT_TIMESTAMP:
-    case EVENT_INTEGER:
-    case EVENT_FLOAT:
-    case EVENT_PID:
-    case EVENT_START_FMT:
-        break;
-    case EVENT_RESERVED:
-    default:
+    // Ignore if invalid event
+    if (event == EVENT_RESERVED || event >= EVENT_UPPER_BOUND) {
         return;
     }
-    Entry entry(event, data, length);
-    log(&entry, true /*trusted*/);
+    Entry etr(event, data, length);
+    log(&etr, true /*trusted*/);
 }
 
-void NBLog::Writer::log(const NBLog::Entry *entry, bool trusted)
+void NBLog::Writer::log(const NBLog::Entry *etr, bool trusted)
 {
     if (!mEnabled) {
         return;
     }
     if (!trusted) {
-        log(entry->mEvent, entry->mData, entry->mLength);
+        log(etr->mEvent, etr->mData, etr->mLength);
         return;
     }
-    size_t need = entry->mLength + Entry::kOverhead;    // mEvent, mLength, data[length], mLength
-                                                        // need = number of bytes remaining to write
+    size_t need = etr->mLength + Entry::kOverhead;    // mEvent, mLength, data[mLength], mLength
+                                                      // need = number of bytes written to FIFO
 
     // FIXME optimize this using memcpy for the data part of the Entry.
     // The Entry could have a method copyTo(ptr, offset, size) to optimize the copy.
+    // checks size of a single log Entry: type, length, data pointer and ending
     uint8_t temp[Entry::kMaxLength + Entry::kOverhead];
+    // write this data to temp array
     for (size_t i = 0; i < need; i++) {
-        temp[i] = entry->readAt(i);
+        temp[i] = etr->copyEntryDataAt(i);
     }
+    // write to circular buffer
     mFifoWriter->write(temp, need);
 }
 
@@ -531,7 +710,7 @@
     Writer::logTimestamp();
 }
 
-void NBLog::LockedWriter::logTimestamp(const struct timespec &ts)
+void NBLog::LockedWriter::logTimestamp(const int64_t ts)
 {
     Mutex::Autolock _l(mLock);
     Writer::logTimestamp(ts);
@@ -568,6 +747,12 @@
     Writer::logEnd();
 }
 
+void NBLog::LockedWriter::logHash(log_hash_t hash)
+{
+    Mutex::Autolock _l(mLock);
+    Writer::logHash(hash);
+}
+
 bool NBLog::LockedWriter::isEnabled() const
 {
     Mutex::Autolock _l(mLock);
@@ -582,13 +767,19 @@
 
 // ---------------------------------------------------------------------------
 
+const std::set<NBLog::Event> NBLog::Reader::startingTypes {NBLog::Event::EVENT_START_FMT,
+                                                           NBLog::Event::EVENT_HISTOGRAM_ENTRY_TS};
+const std::set<NBLog::Event> NBLog::Reader::endingTypes   {NBLog::Event::EVENT_END_FMT,
+                                                           NBLog::Event::EVENT_HISTOGRAM_ENTRY_TS,
+                                                           NBLog::Event::EVENT_HISTOGRAM_FLUSH};
 NBLog::Reader::Reader(const void *shared, size_t size)
     : mShared((/*const*/ Shared *) shared), /*mIMemory*/
       mFd(-1), mIndent(0),
       mFifo(mShared != NULL ?
         new audio_utils_fifo(size, sizeof(uint8_t),
             mShared->mBuffer, mShared->mRear, NULL /*throttlesFront*/) : NULL),
-      mFifoReader(mFifo != NULL ? new audio_utils_fifo_reader(*mFifo) : NULL)
+      mFifoReader(mFifo != NULL ? new audio_utils_fifo_reader(*mFifo) : NULL),
+      findGlitch(false)
 {
 }
 
@@ -604,16 +795,50 @@
     delete mFifo;
 }
 
-uint8_t *NBLog::Reader::findLastEntryOfType(uint8_t *front, uint8_t *back, uint8_t type) {
+inline static int deltaMs(int64_t ns1, int64_t ns2) {
+    return (ns2 - ns1) / (1000 * 1000);
+}
+
+// Produces a log warning if the timing of recent buffer periods caused a glitch
+// Computes sum of running window of three buffer periods
+// Checks whether the buffer periods leave enough CPU time for the next one
+// e.g. if a buffer period is expected to be 4 ms and a buffer requires 3 ms of CPU time,
+// here are some glitch cases:
+// 4 + 4 + 6 ; 5 + 4 + 5; 2 + 2 + 10
+// TODO: develop this code to track changes in histogram distribution in addition
+// to / instead of glitches
+void NBLog::Reader::alertIfGlitch(const std::vector<int64_t> &samples) {
+    //TODO: measure kPeriodLen and kRatio from the data as they may change.
+    static const int kPeriodLen = 4; // current period length is ideally 4 ms
+    static const double kRatio = 0.75; // estimate of CPU time as ratio of period length
+    // DAC processing time for 4 ms buffer
+    static const int kPeriodTime = static_cast<int>(round(kPeriodLen * kRatio));
+    static const int kNumBuff = 3; // number of buffers considered in local history
+    std::deque<int> periods(kNumBuff, kPeriodLen);
+    for (size_t i = 2; i < samples.size(); ++i) { // skip first time entry
+        periods.push_front(deltaMs(samples[i - 1], samples[i]));
+        periods.pop_back();
+        // TODO: check that all glitch cases are covered
+        if (std::accumulate(periods.begin(), periods.end(), 0) > kNumBuff * kPeriodLen +
+            kPeriodLen - kPeriodTime) {
+                ALOGW("A glitch occurred");
+                periods.assign(kNumBuff, kPeriodLen);
+        }
+    }
+    return;
+}
+
+const uint8_t *NBLog::Reader::findLastEntryOfTypes(const uint8_t *front, const uint8_t *back,
+                                            const std::set<Event> &types) {
     while (back + Entry::kPreviousLengthOffset >= front) {
-        uint8_t *prev = back - back[Entry::kPreviousLengthOffset] - Entry::kOverhead;
-        if (prev < front || prev + prev[offsetof(FormatEntry::entry, length)] +
+        const uint8_t *prev = back - back[Entry::kPreviousLengthOffset] - Entry::kOverhead;
+        if (prev < front || prev + prev[offsetof(entry, length)] +
                             Entry::kOverhead != back) {
 
             // prev points to an out of limits or inconsistent entry
             return nullptr;
         }
-        if (prev[offsetof(FormatEntry::entry, type)] == type) {
+        if (types.find((const Event) prev[offsetof(entry, type)]) != types.end()) {
             return prev;
         }
         back = prev;
@@ -652,21 +877,21 @@
     // it ends in a complete entry (which is not an END_FMT). So is safe to traverse backwards.
     // TODO: handle client corruption (in the middle of a buffer)
 
-    uint8_t *back = snapshot->mData + availToRead;
-    uint8_t *front = snapshot->mData;
+    const uint8_t *back = snapshot->mData + availToRead;
+    const uint8_t *front = snapshot->mData;
 
     // Find last END_FMT. <back> is sitting on an entry which might be the middle of a FormatEntry.
     // We go backwards until we find an EVENT_END_FMT.
-    uint8_t *lastEnd = findLastEntryOfType(front, back, EVENT_END_FMT);
+    const uint8_t *lastEnd = findLastEntryOfTypes(front, back, endingTypes);
     if (lastEnd == nullptr) {
-        snapshot->mEnd = snapshot->mBegin = FormatEntry::iterator(front);
+        snapshot->mEnd = snapshot->mBegin = EntryIterator(front);
     } else {
         // end of snapshot points to after last END_FMT entry
-        snapshot->mEnd = FormatEntry::iterator(lastEnd + Entry::kOverhead);
+        snapshot->mEnd = EntryIterator(lastEnd).next();
         // find first START_FMT
-        uint8_t *firstStart = nullptr;
-        uint8_t *firstStartTmp = lastEnd;
-        while ((firstStartTmp = findLastEntryOfType(front, firstStartTmp, EVENT_START_FMT))
+        const uint8_t *firstStart = nullptr;
+        const uint8_t *firstStartTmp = snapshot->mEnd;
+        while ((firstStartTmp = findLastEntryOfTypes(front, firstStartTmp, startingTypes))
                 != nullptr) {
             firstStart = firstStartTmp;
         }
@@ -674,7 +899,7 @@
         if (firstStart == nullptr) {
             snapshot->mBegin = snapshot->mEnd;
         } else {
-            snapshot->mBegin = FormatEntry::iterator(firstStart);
+            snapshot->mBegin = EntryIterator(firstStart);
         }
     }
 
@@ -686,8 +911,37 @@
 
 }
 
+// writes sample deltas to file, either truncating or appending
+inline void writeHistToFile(const std::vector<int64_t> &samples, bool append) {
+    // name of file on audioserver
+    static const char* const kName = (char *)"/data/misc/audioserver/sample_results.txt";
+    // stores deltas between the samples
+    std::vector<int64_t> intervals;
+    for (size_t i = 1; i < samples.size(); ++i) {
+        intervals.push_back(deltaMs(samples[i - 1], samples[i]));
+    }
+    if (intervals.empty()) return;
+    // Deletes maximum value in a histogram. Temp quick fix.
+    // FIXME: need to find root cause of approx. 35th element from the end
+    // consistently being an outlier in the first histogram of a flush
+    // ALOGW("%" PRId64 "before", (int64_t) *(std::max_element(intervals.begin(), intervals.end())));
+    intervals.erase(std::max_element(intervals.begin(), intervals.end()));
+    // ALOGW("%" PRId64 "after", (int64_t) *(std::max_element(intervals.begin(), intervals.end())));
+    std::ofstream ofs;
+    ofs.open(kName, append ? std::ios::app : std::ios::trunc);
+    if (!ofs) {
+        ALOGW("couldn't open file %s", kName);
+        return;
+    }
+    for (size_t i = 0; i < intervals.size(); ++i) {
+        ofs << intervals[i] << "\n";
+    }
+    ofs.close();
+}
+
 void NBLog::Reader::dump(int fd, size_t indent, NBLog::Reader::Snapshot &snapshot)
 {
+  //  CallStack cs(LOG_TAG);
 #if 0
     struct timespec ts;
     time_t maxSec = -1;
@@ -712,11 +966,11 @@
     mFd = fd;
     mIndent = indent;
     String8 timestamp, body;
-    size_t lost = snapshot.lost() + (snapshot.begin() - FormatEntry::iterator(snapshot.data()));
+    size_t lost = snapshot.lost() + (snapshot.begin() - EntryIterator(snapshot.data()));
     if (lost > 0) {
         body.appendFormat("warning: lost %zu bytes worth of events", lost);
         // TODO timestamp empty here, only other choice to wait for the first timestamp event in the
-        //      log to push it out.  Consider keeping the timestamp/body between calls to readAt().
+        //      log to push it out.  Consider keeping the timestamp/body between calls to copyEntryDataAt().
         dumpLine(timestamp, body);
     }
 #if 0
@@ -730,6 +984,7 @@
     }
     bool deferredTimestamp = false;
 #endif
+
     for (auto entry = snapshot.begin(); entry != snapshot.end();) {
         switch (entry->type) {
 #if 0
@@ -798,9 +1053,53 @@
             break;
 #endif
         case EVENT_START_FMT:
-            // right now, this is the only supported case
             entry = handleFormat(FormatEntry(entry), &timestamp, &body);
             break;
+        case EVENT_HISTOGRAM_ENTRY_TS: {
+            HistTsEntryWithAuthor *data = (HistTsEntryWithAuthor *) (entry->data);
+            // TODO This memcpies are here to avoid unaligned memory access crash.
+            // There's probably a more efficient way to do it
+            log_hash_t hash;
+            memcpy(&hash, &(data->hash), sizeof(hash));
+            int64_t ts;
+            memcpy(&ts, &data->ts, sizeof(ts));
+            const std::pair<log_hash_t, int> key(hash, data->author);
+            // TODO might want to filter excessively high outliers, which are usually caused
+            // by the thread being inactive.
+            mHists[key].push_back(ts);
+            ++entry;
+            break;
+        }
+        // draws histograms stored in global Reader::mHists and erases them
+        case EVENT_HISTOGRAM_FLUSH: {
+            HistogramEntry histEntry(entry);
+            // Log timestamp
+            // Timestamp of call to drawHistogram, not when audio was generated
+            const int64_t ts = histEntry.timestamp();
+            timestamp.clear();
+            timestamp.appendFormat("[%d.%03d]", (int) (ts / (1000 * 1000 * 1000)),
+                            (int) ((ts / (1000 * 1000)) % 1000));
+            // Log histograms
+            setFindGlitch(true);
+            body.appendFormat("Histogram flush - ");
+            handleAuthor(histEntry, &body);
+            for (auto hist = mHists.begin(); hist != mHists.end();) {
+                if (hist->first.second == histEntry.author()) {
+                    body.appendFormat("%X", (int)hist->first.first);
+                    if (findGlitch) {
+                        alertIfGlitch(hist->second);
+                    }
+                    // set file to empty and write data for all histograms in this set
+                    writeHistToFile(hist->second, hist != mHists.begin());
+                    drawHistogram(&body, hist->second, true, indent);
+                    hist = mHists.erase(hist);
+                } else {
+                    ++hist;
+                }
+            }
+            ++entry;
+            break;
+        }
         case EVENT_END_FMT:
             body.appendFormat("warning: got to end format event");
             ++entry;
@@ -814,12 +1113,8 @@
 
         if (!body.isEmpty()) {
             dumpLine(timestamp, body);
-            // deferredTimestamp = false;
         }
     }
-    // if (deferredTimestamp) {
-    //     dumpLine(timestamp, body);
-    // }
 }
 
 void NBLog::Reader::dump(int fd, size_t indent)
@@ -844,11 +1139,23 @@
     return iMemory != 0 && mIMemory != 0 && iMemory->pointer() == mIMemory->pointer();
 }
 
+void NBLog::Reader::setFindGlitch(bool s)
+{
+    findGlitch = s;
+}
+
+bool NBLog::Reader::isFindGlitch() const
+{
+    return findGlitch;
+}
+
+// ---------------------------------------------------------------------------
+
 void NBLog::appendTimestamp(String8 *body, const void *data) {
-    struct timespec ts;
-    memcpy(&ts, data, sizeof(struct timespec));
-    body->appendFormat("[%d.%03d]", (int) ts.tv_sec,
-                    (int) (ts.tv_nsec / 1000000));
+    int64_t ts;
+    memcpy(&ts, data, sizeof(ts));
+    body->appendFormat("[%d.%03d]", (int) (ts / (1000 * 1000 * 1000)),
+                    (int) ((ts / (1000 * 1000)) % 1000));
 }
 
 void NBLog::appendInt(String8 *body, const void *data) {
@@ -868,20 +1175,42 @@
     body->appendFormat("<PID: %d, name: %.*s>", id, (int) (length - sizeof(pid_t)), name);
 }
 
-NBLog::FormatEntry::iterator NBLog::Reader::handleFormat(const FormatEntry &fmtEntry,
+String8 NBLog::bufferDump(const uint8_t *buffer, size_t size)
+{
+    String8 str;
+    str.append("[ ");
+    for(size_t i = 0; i < size; i++)
+    {
+        str.appendFormat("%d ", buffer[i]);
+    }
+    str.append("]");
+    return str;
+}
+
+String8 NBLog::bufferDump(const EntryIterator &it)
+{
+    return bufferDump(it, it->length + Entry::kOverhead);
+}
+
+NBLog::EntryIterator NBLog::Reader::handleFormat(const FormatEntry &fmtEntry,
                                                          String8 *timestamp,
                                                          String8 *body) {
     // log timestamp
-    struct timespec ts = fmtEntry.timestamp();
+    int64_t ts = fmtEntry.timestamp();
     timestamp->clear();
-    timestamp->appendFormat("[%d.%03d]", (int) ts.tv_sec,
-                    (int) (ts.tv_nsec / 1000000));
+    timestamp->appendFormat("[%d.%03d]", (int) (ts / (1000 * 1000 * 1000)),
+                    (int) ((ts / (1000 * 1000)) % 1000));
+
+    // log unique hash
+    log_hash_t hash = fmtEntry.hash();
+    // print only lower 16bit of hash as hex and line as int to reduce spam in the log
+    body->appendFormat("%.4X-%d ", (int)(hash >> 16) & 0xFFFF, (int) hash & 0xFFFF);
 
     // log author (if present)
     handleAuthor(fmtEntry, body);
 
     // log string
-    NBLog::FormatEntry::iterator arg = fmtEntry.args();
+    NBLog::EntryIterator arg = fmtEntry.args();
 
     const char* fmt = fmtEntry.formatString();
     size_t fmt_length = fmtEntry.formatStringLength();
@@ -954,10 +1283,127 @@
     return arg;
 }
 
-// ---------------------------------------------------------------------------
+static int widthOf(int x) {
+    int width = 0;
+    while (x > 0) {
+        ++width;
+        x /= 10;
+    }
+    return width;
+}
+
+static std::map<int, int> buildBuckets(const std::vector<int64_t> &samples) {
+    // TODO allow buckets of variable resolution
+    std::map<int, int> buckets;
+    for (size_t i = 1; i < samples.size(); ++i) {
+        ++buckets[deltaMs(samples[i - 1], samples[i])];
+    }
+    return buckets;
+}
+
+static inline uint32_t log2(uint32_t x) {
+    // This works for x > 0
+    return 31 - __builtin_clz(x);
+}
+
+// TODO put this function in separate file. Make it return a std::string instead of modifying body
+/*
+Example output:
+[54.234] Histogram flush - AudioOut_D:
+Histogram 33640BF1
+            [ 1][ 1][ 1][ 3][54][69][ 1][ 2][ 1]
+        64|                      []
+        32|                  []  []
+        16|                  []  []
+         8|                  []  []
+         4|                  []  []
+         2|______________[]__[]__[]______[]____
+              4   5   6   8   9  10  11  13  15
+Notice that all values that fall in the same row have the same height (65 and 127 are displayed
+identically). That's why exact counts are added at the top.
+*/
+void NBLog::Reader::drawHistogram(String8 *body,
+                                  const std::vector<int64_t> &samples,
+                                  bool logScale,
+                                  int indent,
+                                  int maxHeight) {
+    // this avoids some corner cases
+    if (samples.size() <= 1) {
+        return;
+    }
+    // temp code for debugging the outlier timestamp
+    const int kMaxMs = 100;
+    for (size_t i = 1; i < samples.size()-1; ++i) {
+        const int currDelta = deltaMs(samples[i - 1], samples[i]);
+        if (currDelta > kMaxMs) {
+            body->appendFormat("\nlocation: %zu, size: %zu, pos from end: %zu, %d\t", i,
+                           samples.size(), samples.size() - i, currDelta);
+        }
+    }
+    // FIXME: as can be seen when printing the values, the outlier timestamps typically occur
+    // in the first histogram 35 to 38 indices from the end (most often 35).
+    // TODO: build histogram buckets earlier and discard timestamps to save memory
+    std::map<int, int> buckets = buildBuckets(samples);
+    // TODO consider changing all ints to uint32_t or uint64_t
+
+    // underscores and spaces length corresponds to maximum width of histogram
+    static const int kLen = 40;
+    std::string underscores(kLen, '-');
+    std::string spaces(kLen, ' ');
+
+    auto it = buckets.begin();
+    int maxDelta = it->first;
+    int maxCount = it->second;
+    // Compute maximum values
+    while (++it != buckets.end()) {
+        if (it->first > maxDelta) {
+            maxDelta = it->first;
+        }
+        if (it->second > maxCount) {
+            maxCount = it->second;
+        }
+    }
+    int height = logScale ? log2(maxCount) + 1 : maxCount; // maxCount > 0, safe to call log2
+    const int leftPadding = widthOf(logScale ? pow(2, height) : maxCount);
+    const int colWidth = std::max(std::max(widthOf(maxDelta) + 1, 3), leftPadding + 2);
+    int scalingFactor = 1;
+    // scale data if it exceeds maximum height
+    if (height > maxHeight) {
+        scalingFactor = (height + maxHeight) / maxHeight;
+        height /= scalingFactor;
+    }
+    body->appendFormat("\n%*s", leftPadding + 11, "Occurrences");
+    // write histogram label line with bucket values
+    body->appendFormat("\n%*s", indent, " ");
+    body->appendFormat("%*s", leftPadding, " ");
+    for (auto const &x : buckets) {
+        body->appendFormat("%*d", colWidth, x.second);
+    }
+    // write histogram ascii art
+    body->appendFormat("\n%*s", indent, " ");
+    for (int row = height * scalingFactor; row >= 0; row -= scalingFactor) {
+        const int value = logScale ? (1 << row) : row;
+        body->appendFormat("%.*s", leftPadding, spaces.c_str());
+        for (auto const &x : buckets) {
+          body->appendFormat("%.*s%s", colWidth - 1, spaces.c_str(), x.second < value ? " " : "|");
+        }
+        body->appendFormat("\n%*s", indent, " ");
+    }
+    // print x-axis
+    const int columns = static_cast<int>(buckets.size());
+    body->appendFormat("%*c", leftPadding, ' ');
+    body->appendFormat("%.*s", (columns + 1) * colWidth, underscores.c_str());
+    body->appendFormat("\n%*s", indent, " ");
+
+    // write footer with bucket labels
+    body->appendFormat("%*s", leftPadding, " ");
+    for (auto const &x : buckets) {
+        body->appendFormat("%*d", colWidth, x.first);
+    }
+    body->appendFormat("%.*s%s", colWidth, spaces.c_str(), "ms\n");
+}
 
 NBLog::Merger::Merger(const void *shared, size_t size):
-      mBuffer(NULL),
       mShared((Shared *) shared),
       mFifo(mShared != NULL ?
         new audio_utils_fifo(size, sizeof(uint8_t),
@@ -966,6 +1412,8 @@
       {}
 
 void NBLog::Merger::addReader(const NBLog::NamedReader &reader) {
+    // FIXME This is called by binder thread in MediaLogService::registerWriter
+    //       but the access to shared variable mNamedReaders is not yet protected by a lock.
     mNamedReaders.push_back(reader);
 }
 
@@ -973,26 +1421,27 @@
 // composed by a timestamp and the index of the snapshot where the timestamp came from
 struct MergeItem
 {
-    struct timespec ts;
+    int64_t ts;
     int index;
-    MergeItem(struct timespec ts, int index): ts(ts), index(index) {}
+    MergeItem(int64_t ts, int index): ts(ts), index(index) {}
 };
 
 // operators needed for priority queue in merge
-bool operator>(const struct timespec &t1, const struct timespec &t2) {
-    return t1.tv_sec > t2.tv_sec || (t1.tv_sec == t2.tv_sec && t1.tv_nsec > t2.tv_nsec);
-}
+// bool operator>(const int64_t &t1, const int64_t &t2) {
+//     return t1.tv_sec > t2.tv_sec || (t1.tv_sec == t2.tv_sec && t1.tv_nsec > t2.tv_nsec);
+// }
 
 bool operator>(const struct MergeItem &i1, const struct MergeItem &i2) {
-    return i1.ts > i2.ts ||
-        (i1.ts.tv_sec == i2.ts.tv_sec && i1.ts.tv_nsec == i2.ts.tv_nsec && i1.index > i2.index);
+    return i1.ts > i2.ts || (i1.ts == i2.ts && i1.index > i2.index);
 }
 
 // Merge registered readers, sorted by timestamp
 void NBLog::Merger::merge() {
+    // FIXME This is called by merge thread
+    //       but the access to shared variable mNamedReaders is not yet protected by a lock.
     int nLogs = mNamedReaders.size();
     std::vector<std::unique_ptr<NBLog::Reader::Snapshot>> snapshots(nLogs);
-    std::vector<NBLog::FormatEntry::iterator> offsets(nLogs);
+    std::vector<NBLog::EntryIterator> offsets(nLogs);
     for (int i = 0; i < nLogs; ++i) {
         snapshots[i] = mNamedReaders[i].reader()->getSnapshot();
         offsets[i] = snapshots[i]->begin();
@@ -1004,7 +1453,7 @@
     for (int i = 0; i < nLogs; ++i)
     {
         if (offsets[i] != snapshots[i]->end()) {
-            timespec ts = FormatEntry(offsets[i]).timestamp();
+            int64_t ts = AbstractEntry::buildEntry(offsets[i])->timestamp();
             timestamps.emplace(ts, i);
         }
     }
@@ -1013,30 +1462,36 @@
         // find minimum timestamp
         int index = timestamps.top().index;
         // copy it to the log, increasing offset
-        offsets[index] = FormatEntry(offsets[index]).copyWithAuthor(mFifoWriter, index);
+        offsets[index] = AbstractEntry::buildEntry(offsets[index])->copyWithAuthor(mFifoWriter,
+                                                                                   index);
         // update data structures
         timestamps.pop();
         if (offsets[index] != snapshots[index]->end()) {
-            timespec ts = FormatEntry(offsets[index]).timestamp();
+            int64_t ts = AbstractEntry::buildEntry(offsets[index])->timestamp();
             timestamps.emplace(ts, index);
         }
     }
 }
 
-const std::vector<NBLog::NamedReader> *NBLog::Merger::getNamedReaders() const {
-    return &mNamedReaders;
+const std::vector<NBLog::NamedReader>& NBLog::Merger::getNamedReaders() const {
+    // FIXME This is returning a reference to a shared variable that needs a lock
+    return mNamedReaders;
 }
 
+// ---------------------------------------------------------------------------
+
 NBLog::MergeReader::MergeReader(const void *shared, size_t size, Merger &merger)
     : Reader(shared, size), mNamedReaders(merger.getNamedReaders()) {}
 
-size_t NBLog::MergeReader::handleAuthor(const NBLog::FormatEntry &fmtEntry, String8 *body) {
-    int author = fmtEntry.author();
-    const char* name = (*mNamedReaders)[author].name();
+void NBLog::MergeReader::handleAuthor(const NBLog::AbstractEntry &entry, String8 *body) {
+    int author = entry.author();
+    // FIXME Needs a lock
+    const char* name = mNamedReaders[author].name();
     body->appendFormat("%s: ", name);
-    return NBLog::Entry::kOverhead + sizeof(author);
 }
 
+// ---------------------------------------------------------------------------
+
 NBLog::MergeThread::MergeThread(NBLog::Merger &merger)
     : mMerger(merger),
       mTimeoutUs(0) {}
diff --git a/media/libnbaio/include/NBLog.h b/media/libnbaio/include/NBLog.h
index 59b77bd..785b9c2 100644
--- a/media/libnbaio/include/NBLog.h
+++ b/media/libnbaio/include/NBLog.h
@@ -24,6 +24,8 @@
 #include <utils/Mutex.h>
 #include <utils/threads.h>
 
+#include <map>
+#include <set>
 #include <vector>
 
 namespace android {
@@ -34,12 +36,16 @@
 
 public:
 
+typedef uint64_t log_hash_t;
+
+// FIXME Everything needed for client (writer API and registration) should be isolated
+//       from the rest of the implementation.
 class Writer;
 class Reader;
 
 private:
 
-enum Event {
+enum Event : uint8_t {
     EVENT_RESERVED,
     EVENT_STRING,               // ASCII string, not NUL-terminated
     // TODO: make timestamp optional
@@ -50,7 +56,13 @@
     EVENT_AUTHOR,               // author index (present in merged logs) tracks entry's original log
     EVENT_START_FMT,            // logFormat start event: entry includes format string, following
                                 // entries contain format arguments
+    EVENT_HASH,                 // unique HASH of log origin, originates from hash of file name
+                                // and line number
+    EVENT_HISTOGRAM_ENTRY_TS,   // single datum for timestamp histogram
+    EVENT_HISTOGRAM_FLUSH,      // show histogram on log
     EVENT_END_FMT,              // end of logFormat argument list
+
+    EVENT_UPPER_BOUND,          // to check for invalid events
 };
 
 
@@ -60,93 +72,146 @@
 // a formatted entry has the following structure:
 //    * START_FMT entry, containing the format string
 //    * TIMESTAMP entry
+//    * HASH entry
 //    * author entry of the thread that generated it (optional, present in merged log)
 //    * format arg1
 //    * format arg2
 //    * ...
 //    * END_FMT entry
 
-class FormatEntry {
+// entry representation in memory
+struct entry {
+    const uint8_t type;
+    const uint8_t length;
+    const uint8_t data[0];
+};
+
+// entry tail representation (after data)
+struct ending {
+    uint8_t length;
+    uint8_t next[0];
+};
+
+// entry iterator
+class EntryIterator {
 public:
-    // build a Format Entry starting in the given pointer
-    class iterator;
-    explicit FormatEntry(const uint8_t *entry);
-    explicit FormatEntry(const iterator &it);
+    EntryIterator();
+    explicit EntryIterator(const uint8_t *entry);
+    EntryIterator(const EntryIterator &other);
 
-    // entry representation in memory
-    struct entry {
-        const uint8_t type;
-        const uint8_t length;
-        const uint8_t data[0];
-    };
+    // dereference underlying entry
+    const entry&    operator*() const;
+    const entry*    operator->() const;
+    // advance to next entry
+    EntryIterator&       operator++(); // ++i
+    // back to previous entry
+    EntryIterator&       operator--(); // --i
+    EntryIterator        next() const;
+    EntryIterator        prev() const;
+    bool            operator!=(const EntryIterator &other) const;
+    int             operator-(const EntryIterator &other) const;
 
-    // entry tail representation (after data)
-    struct ending {
-        uint8_t length;
-        uint8_t next[0];
-    };
+    bool            hasConsistentLength() const;
+    void            copyTo(std::unique_ptr<audio_utils_fifo_writer> &dst) const;
+    void            copyData(uint8_t *dst) const;
 
-    // entry iterator
-    class iterator {
-    public:
-        iterator();
-        iterator(const uint8_t *entry);
-        iterator(const iterator &other);
+    template<typename T>
+    inline const T& payload() {
+        return *reinterpret_cast<const T *>(ptr + offsetof(entry, data));
+    }
 
-        // dereference underlying entry
-        const entry&    operator*() const;
-        const entry*    operator->() const;
-        // advance to next entry
-        iterator&       operator++(); // ++i
-        // back to previous entry
-        iterator&       operator--(); // --i
-        iterator        next() const;
-        iterator        prev() const;
-        bool            operator!=(const iterator &other) const;
-        int             operator-(const iterator &other) const;
+    inline operator const uint8_t*() const {
+        return ptr;
+    }
 
-        bool            hasConsistentLength() const;
-        void            copyTo(std::unique_ptr<audio_utils_fifo_writer> &dst) const;
-        void            copyData(uint8_t *dst) const;
+private:
+    const uint8_t  *ptr;
+};
 
-        template<typename T>
-        inline const T& payload() {
-            return *reinterpret_cast<const T *>(ptr + offsetof(entry, data));
-        }
+class AbstractEntry {
+public:
 
-    private:
-        friend class FormatEntry;
-        const uint8_t  *ptr;
-    };
+    // Entry starting in the given pointer
+    explicit AbstractEntry(const uint8_t *entry);
+    virtual ~AbstractEntry() {}
 
-    // Entry's format string
-    const char* formatString() const;
-
-    // Enrty's format string length
-    size_t      formatStringLength() const;
-
-    // Format arguments (excluding format string, timestamp and author)
-    iterator    args() const;
+    // build concrete entry of appropriate class from pointer
+    static std::unique_ptr<AbstractEntry> buildEntry(const uint8_t *ptr);
 
     // get format entry timestamp
-    timespec    timestamp() const;
+    // TODO consider changing to uint64_t
+    virtual int64_t      timestamp() const = 0;
+
+    // get format entry's unique id
+    virtual log_hash_t   hash() const = 0;
 
     // entry's author index (-1 if none present)
     // a Merger has a vector of Readers, author simply points to the index of the
     // Reader that originated the entry
-    int         author() const;
+    // TODO consider changing to uint32_t
+    virtual int          author() const = 0;
 
-    // copy entry, adding author before timestamp, returns size of original entry
-    iterator    copyWithAuthor(std::unique_ptr<audio_utils_fifo_writer> &dst, int author) const;
+    // copy entry, adding author before timestamp, returns iterator to end of entry
+    virtual EntryIterator    copyWithAuthor(std::unique_ptr<audio_utils_fifo_writer> &dst,
+                                       int author) const = 0;
 
-    iterator    begin() const;
-
-private:
+protected:
     // copies ordinary entry from src to dst, and returns length of entry
     // size_t      copyEntry(audio_utils_fifo_writer *dst, const iterator &it);
     const uint8_t  *mEntry;
 };
 
+class FormatEntry : public AbstractEntry {
+public:
+    // explicit FormatEntry(const EntryIterator &it);
+    explicit FormatEntry(const uint8_t *ptr) : AbstractEntry(ptr) {}
+    virtual ~FormatEntry() {}
+
+    EntryIterator begin() const;
+
+    // Entry's format string
+    const   char* formatString() const;
+
+    // Enrty's format string length
+            size_t      formatStringLength() const;
+
+    // Format arguments (excluding format string, timestamp and author)
+            EntryIterator    args() const;
+
+    // get format entry timestamp
+    virtual int64_t     timestamp() const override;
+
+    // get format entry's unique id
+    virtual log_hash_t  hash() const override;
+
+    // entry's author index (-1 if none present)
+    // a Merger has a vector of Readers, author simply points to the index of the
+    // Reader that originated the entry
+    virtual int         author() const override;
+
+    // copy entry, adding author before timestamp, returns size of original entry
+    virtual EntryIterator    copyWithAuthor(std::unique_ptr<audio_utils_fifo_writer> &dst,
+                                       int author) const override;
+
+};
+
+class HistogramEntry : public AbstractEntry {
+public:
+    explicit HistogramEntry(const uint8_t *ptr) : AbstractEntry(ptr) {
+    }
+    virtual ~HistogramEntry() {}
+
+    virtual int64_t     timestamp() const override;
+
+    virtual log_hash_t  hash() const override;
+
+    virtual int         author() const override;
+
+    virtual EntryIterator    copyWithAuthor(std::unique_ptr<audio_utils_fifo_writer> &dst,
+                                       int author) const override;
+
+};
+
 // ---------------------------------------------------------------------------
 
 // representation of a single log entry in private memory
@@ -155,7 +220,8 @@
         : mEvent(event), mLength(length), mData(data) { }
     /*virtual*/ ~Entry() { }
 
-    int     readAt(size_t offset) const;
+    // used during writing to format Entry information as follows: [type][length][data ... ][length]
+    int     copyEntryDataAt(size_t offset) const;
 
 private:
     friend class Writer;
@@ -165,12 +231,28 @@
     static const size_t kMaxLength = 255;
 public:
     // mEvent, mLength, mData[...], duplicate mLength
-    static const size_t kOverhead = sizeof(FormatEntry::entry) + sizeof(FormatEntry::ending);
+    static const size_t kOverhead = sizeof(entry) + sizeof(ending);
     // endind length of previous entry
-    static const size_t kPreviousLengthOffset = - sizeof(FormatEntry::ending) +
-                                                offsetof(FormatEntry::ending, length);
+    static const size_t kPreviousLengthOffset = - sizeof(ending) +
+                                                offsetof(ending, length);
 };
 
+struct HistTsEntry {
+    log_hash_t hash;
+    int64_t ts;
+}; //TODO __attribute__((packed));
+
+struct HistTsEntryWithAuthor {
+    log_hash_t hash;
+    int64_t ts;
+    int author;
+}; //TODO __attribute__((packed));
+
+struct HistIntEntry {
+    log_hash_t hash;
+    int value;
+}; //TODO __attribute__((packed));
+
 // representation of a single log entry in shared memory
 //  byte[0]             mEvent
 //  byte[1]             mLength
@@ -187,7 +269,8 @@
     static void    appendPID(String8 *body, const void *data, size_t length);
     static void    appendTimestamp(String8 *body, const void *data);
     static size_t  fmtEntryLength(const uint8_t *data);
-
+    static String8 bufferDump(const uint8_t *buffer, size_t size);
+    static String8 bufferDump(const EntryIterator &it);
 public:
 
 // Located in shared memory, must be POD.
@@ -244,19 +327,22 @@
 
     virtual ~Writer();
 
+    // FIXME needs comments, and some should be private
     virtual void    log(const char *string);
     virtual void    logf(const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
     virtual void    logvf(const char *fmt, va_list ap);
     virtual void    logTimestamp();
-    virtual void    logTimestamp(const struct timespec &ts);
+    virtual void    logTimestamp(const int64_t ts);
     virtual void    logInteger(const int x);
     virtual void    logFloat(const float x);
     virtual void    logPID();
-    virtual void    logFormat(const char *fmt, ...);
-    virtual void    logVFormat(const char *fmt, va_list ap);
+    virtual void    logFormat(const char *fmt, log_hash_t hash, ...);
+    virtual void    logVFormat(const char *fmt, log_hash_t hash, va_list ap);
     virtual void    logStart(const char *fmt);
     virtual void    logEnd();
-
+    virtual void    logHash(log_hash_t hash);
+    virtual void    logHistTS(log_hash_t hash);
+    virtual void    logHistFlush(log_hash_t hash);
 
     virtual bool    isEnabled() const;
 
@@ -269,7 +355,9 @@
 
 private:
     // 0 <= length <= kMaxLength
+    // writes a single Entry to the FIFO
     void    log(Event event, const void *data, size_t length);
+    // checks validity of an event before calling log above this one
     void    log(const Entry *entry, bool trusted = false);
 
     Shared* const   mShared;    // raw pointer to shared memory
@@ -298,12 +386,13 @@
     virtual void    logf(const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
     virtual void    logvf(const char *fmt, va_list ap);
     virtual void    logTimestamp();
-    virtual void    logTimestamp(const struct timespec &ts);
+    virtual void    logTimestamp(const int64_t ts);
     virtual void    logInteger(const int x);
     virtual void    logFloat(const float x);
     virtual void    logPID();
     virtual void    logStart(const char *fmt);
     virtual void    logEnd();
+    virtual void    logHash(log_hash_t hash);
 
     virtual bool    isEnabled() const;
     virtual bool    setEnabled(bool enabled);
@@ -334,18 +423,17 @@
 
         // iterator to beginning of readable segment of snapshot
         // data between begin and end has valid entries
-        FormatEntry::iterator begin() { return mBegin; }
+        EntryIterator begin() { return mBegin; }
 
         // iterator to end of readable segment of snapshot
-        FormatEntry::iterator end() { return mEnd; }
-
+        EntryIterator end() { return mEnd; }
 
     private:
         friend class Reader;
         uint8_t              *mData;
         size_t                mLost;
-        FormatEntry::iterator mBegin;
-        FormatEntry::iterator mEnd;
+        EntryIterator mBegin;
+        EntryIterator mEnd;
     };
 
     // Input parameter 'size' is the desired size of the timeline in byte units.
@@ -355,15 +443,22 @@
 
     virtual ~Reader();
 
+    void alertIfGlitch(const std::vector<int64_t> &samples);
+
     // get snapshot of readers fifo buffer, effectively consuming the buffer
     std::unique_ptr<Snapshot> getSnapshot();
     // dump a particular snapshot of the reader
     void     dump(int fd, size_t indent, Snapshot & snap);
-    // dump the current content of the reader's buffer
+    // dump the current content of the reader's buffer (call getSnapshot() and previous dump())
     void     dump(int fd, size_t indent = 0);
     bool     isIMemory(const sp<IMemory>& iMemory) const;
+    // if findGlitch is true, log warning when buffer periods caused glitch
+    void     setFindGlitch(bool s);
+    bool     isFindGlitch() const;
 
 private:
+    static const std::set<Event> startingTypes;
+    static const std::set<Event> endingTypes;
     /*const*/ Shared* const mShared;    // raw pointer to shared memory, actually const but not
                                         // declared as const because audio_utils_fifo() constructor
     sp<IMemory> mIMemory;       // ref-counted version, assigned only in constructor
@@ -374,19 +469,33 @@
     audio_utils_fifo_reader * const mFifoReader;    // used to read from FIFO,
                                                     // non-NULL unless constructor fails
 
+    // each pair contains a sequence of timestamps (one histogram's worth)
+    // pair's log_hash_t is the hash of the source code location where the timestamp was taken
+    // pair's int points to the Reader that originated the entry
+    std::map<std::pair<log_hash_t, int>, std::vector<int64_t>> mHists;
+    // TODO: it might be clearer, instead of a direct map from source location to vector of
+    // timestamps, if we instead first mapped from source location to an object that
+    // represented that location. And one_of its fields would be a vector of timestamps.
+    // That would allow us to record other information about the source location beyond timestamps.
     void    dumpLine(const String8& timestamp, String8& body);
 
-    FormatEntry::iterator   handleFormat(const FormatEntry &fmtEntry,
+    EntryIterator   handleFormat(const FormatEntry &fmtEntry,
                                          String8 *timestamp,
                                          String8 *body);
     // dummy method for handling absent author entry
-    virtual size_t handleAuthor(const FormatEntry &fmtEntry, String8 *body) { return 0; }
+    virtual void handleAuthor(const AbstractEntry& /*fmtEntry*/, String8* /*body*/) {}
+
+    static void drawHistogram(String8 *body, const std::vector<int64_t> &samples,
+                              bool logScale, int indent = 0, int maxHeight = 10);
 
     // Searches for the last entry of type <type> in the range [front, back)
     // back has to be entry-aligned. Returns nullptr if none enconuntered.
-    static uint8_t *findLastEntryOfType(uint8_t *front, uint8_t *back, uint8_t type);
+    static const uint8_t *findLastEntryOfTypes(const uint8_t *front, const uint8_t *back,
+                                         const std::set<Event> &types);
 
     static const size_t kSquashTimestamp = 5; // squash this many or more adjacent timestamps
+
+    bool findGlitch; // alert if a local buffer period sequence caused an audio glitch
 };
 
 // Wrapper for a reader with a name. Contains a pointer to the reader and a pointer to the name
@@ -417,27 +526,30 @@
     void addReader(const NamedReader &reader);
     // TODO add removeReader
     void merge();
-    const std::vector<NamedReader> *getNamedReaders() const;
+    // FIXME This is returning a reference to a shared variable that needs a lock
+    const std::vector<NamedReader>& getNamedReaders() const;
 private:
     // vector of the readers the merger is supposed to merge from.
     // every reader reads from a writer's buffer
+    // FIXME Needs to be protected by a lock
     std::vector<NamedReader> mNamedReaders;
-    uint8_t *mBuffer;
+
+    // TODO Need comments on all of these
     Shared * const mShared;
     std::unique_ptr<audio_utils_fifo> mFifo;
     std::unique_ptr<audio_utils_fifo_writer> mFifoWriter;
-
-    static struct timespec getTimestamp(const uint8_t *data);
 };
 
 class MergeReader : public Reader {
 public:
     MergeReader(const void *shared, size_t size, Merger &merger);
 private:
-    const std::vector<NamedReader> *mNamedReaders;
+    // FIXME Needs to be protected by a lock,
+    //       because even though our use of it is read-only there may be asynchronous updates
+    const std::vector<NamedReader>& mNamedReaders;
     // handle author entry by looking up the author's name and appending it to the body
     // returns number of bytes read from fmtEntry
-    size_t handleAuthor(const FormatEntry &fmtEntry, String8 *body);
+    void handleAuthor(const AbstractEntry &fmtEntry, String8 *body);
 };
 
 // MergeThread is a thread that contains a Merger. It works as a retriggerable one-shot:
@@ -479,6 +591,15 @@
 
 };  // class NBLog
 
+// TODO put somewhere else
+static inline int64_t get_monotonic_ns() {
+    timespec ts;
+    if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
+        return (uint64_t) ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
+    }
+    return 0; // should not happen.
+}
+
 }   // namespace android
 
 #endif  // ANDROID_MEDIA_NBLOG_H
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index d187ecb..01f09be 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -960,7 +960,9 @@
                             return NO_MEMORY;
                         }
                         hidlMem = mapMemory(hidlMemToken);
-
+                        if (hidlMem == nullptr) {
+                            return NO_MEMORY;
+                        }
                         err = mOMXNode->useBuffer(
                                 portIndex, hidlMemToken, &info.mBufferID);
                     } else {
@@ -1008,6 +1010,9 @@
                                 return NO_MEMORY;
                             }
                             hidlMem = mapMemory(hidlMemToken);
+                            if (hidlMem == nullptr) {
+                                return NO_MEMORY;
+                            }
                             info.mData = new SharedMemoryBuffer(format, hidlMem);
                             info.mMemRef = hidlMem;
                         } else {
@@ -7244,6 +7249,16 @@
             ALOGE("Failed to set parameter 'stop-time-us' (err %d)", err);
             return err;
         }
+
+        int64_t stopTimeOffsetUs;
+        err = statusFromBinderStatus(
+                mGraphicBufferSource->getStopTimeOffsetUs(&stopTimeOffsetUs));
+
+        if (err != OK) {
+            ALOGE("Failed to get stop time offset (err %d)", err);
+            return err;
+        }
+        mInputFormat->setInt64("android._stop-time-offset-us", stopTimeOffsetUs);
     }
 
     int32_t dummy;
diff --git a/media/libstagefright/Android.bp b/media/libstagefright/Android.bp
index 3d9341b..6cc1ace 100644
--- a/media/libstagefright/Android.bp
+++ b/media/libstagefright/Android.bp
@@ -1 +1,176 @@
-subdirs = ["foundation"]
+cc_library_headers {
+    name: "libstagefright_headers",
+    export_include_dirs: ["include"],
+    vendor_available: true,
+}
+
+cc_library_shared {
+    name: "libstagefright",
+
+    srcs: [
+        "ACodec.cpp",
+        "ACodecBufferChannel.cpp",
+        "AACExtractor.cpp",
+        "AACWriter.cpp",
+        "AMRExtractor.cpp",
+        "AMRWriter.cpp",
+        "AudioPlayer.cpp",
+        "AudioSource.cpp",
+        "BufferImpl.cpp",
+        "CallbackDataSource.cpp",
+        "CameraSource.cpp",
+        "CameraSourceTimeLapse.cpp",
+        "DataConverter.cpp",
+        "DataSource.cpp",
+        "DataURISource.cpp",
+        "ESDS.cpp",
+        "FileSource.cpp",
+        "FLACExtractor.cpp",
+        "FrameRenderTracker.cpp",
+        "HTTPBase.cpp",
+        "HevcUtils.cpp",
+        "JPEGSource.cpp",
+        "MP3Extractor.cpp",
+        "MPEG2TSWriter.cpp",
+        "MPEG4Extractor.cpp",
+        "MPEG4Writer.cpp",
+        "MediaAdapter.cpp",
+        "MediaClock.cpp",
+        "MediaCodec.cpp",
+        "MediaCodecList.cpp",
+        "MediaCodecListOverrides.cpp",
+        "MediaCodecSource.cpp",
+        "MediaExtractor.cpp",
+        "MediaSync.cpp",
+        "MidiExtractor.cpp",
+        "http/MediaHTTP.cpp",
+        "MediaMuxer.cpp",
+        "MediaSource.cpp",
+        "NuCachedSource2.cpp",
+        "NuMediaExtractor.cpp",
+        "OMXClient.cpp",
+        "OggExtractor.cpp",
+        "SampleIterator.cpp",
+        "SampleTable.cpp",
+        "SimpleDecodingSource.cpp",
+        "SkipCutBuffer.cpp",
+        "StagefrightMediaScanner.cpp",
+        "StagefrightMetadataRetriever.cpp",
+        "SurfaceMediaSource.cpp",
+        "SurfaceUtils.cpp",
+        "ThrottledSource.cpp",
+        "Utils.cpp",
+        "VBRISeeker.cpp",
+        "VideoFrameScheduler.cpp",
+        "WAVExtractor.cpp",
+        "XINGSeeker.cpp",
+        "avc_utils.cpp",
+    ],
+
+    include_dirs: [
+        "frameworks/native/include/media/openmax",
+        "frameworks/native/include/media/hardware",
+    ],
+
+    shared_libs: [
+        "libaudioutils",
+        "libbinder",
+        "libcamera_client",
+        "libcrypto",
+        "libcutils",
+        "libdl",
+        "libdrmframework",
+        "libexpat",
+        "libgui",
+        "liblog",
+        "libmedia",
+        "libaudioclient",
+        "libmediametrics",
+        "libmediautils",
+        "libnetd_client",
+        "libsonivox",
+        "libui",
+        "libutils",
+        "libvorbisidec",
+        "libmediadrm",
+        "libnativewindow",
+
+        "libmedia_helper",
+        "libstagefright_flacdec",
+        "libstagefright_foundation",
+        "libdl",
+        "libRScpp",
+        "libhidlbase",
+        "libhidlmemory",
+        "android.hidl.allocator@1.0",
+        "android.hidl.memory@1.0",
+        "android.hardware.media.omx@1.0",
+        "libstagefright_xmlparser@1.0",
+    ],
+
+    static_libs: [
+        "libstagefright_color_conversion",
+        "libyuv_static",
+        "libstagefright_aacenc",
+        "libstagefright_matroska",
+        "libstagefright_mediafilter",
+        "libstagefright_omx_utils",
+        "libstagefright_webm",
+        "libstagefright_timedtext",
+        "libvpx",
+        "libwebm",
+        "libstagefright_mpeg2ts",
+        "libstagefright_id3",
+        "libFLAC",
+    ],
+
+    export_shared_lib_headers: ["libmedia"],
+    export_include_dirs: [
+        ".",
+        "include",
+    ],
+
+    cflags: [
+        "-Wno-multichar",
+        "-Werror",
+        "-Wno-error=deprecated-declarations",
+        "-Wall",
+    ],
+
+    product_variables: {
+        debuggable: {
+            // enable experiments only in userdebug and eng builds
+            cflags: ["-DENABLE_STAGEFRIGHT_EXPERIMENTS"],
+        },
+    },
+
+    sanitize: {
+        cfi: true,
+        misc_undefined: [
+            "unsigned-integer-overflow",
+            "signed-integer-overflow",
+        ],
+        diag: {
+            cfi: true,
+        },
+    },
+}
+
+subdirs = [
+    "codecs/*",
+    "colorconversion",
+    "filters",
+    "flac/dec",
+    "foundation",
+    "http",
+    "httplive",
+    "id3",
+    "matroska",
+    "mpeg2ts",
+    "omx",
+    "rtsp",
+    "tests",
+    "timedtext",
+    "webm",
+    "wifi-display",
+]
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
deleted file mode 100644
index 372b11a..0000000
--- a/media/libstagefright/Android.mk
+++ /dev/null
@@ -1,145 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-
-LOCAL_SRC_FILES:=                         \
-        ACodec.cpp                        \
-        ACodecBufferChannel.cpp           \
-        AACExtractor.cpp                  \
-        AACWriter.cpp                     \
-        AMRExtractor.cpp                  \
-        AMRWriter.cpp                     \
-        AudioPlayer.cpp                   \
-        AudioSource.cpp                   \
-        BufferImpl.cpp                    \
-        CallbackDataSource.cpp            \
-        CameraSource.cpp                  \
-        CameraSourceTimeLapse.cpp         \
-        DataConverter.cpp                 \
-        DataSource.cpp                    \
-        DataURISource.cpp                 \
-        ESDS.cpp                          \
-        FileSource.cpp                    \
-        FLACExtractor.cpp                 \
-        FrameRenderTracker.cpp            \
-        HTTPBase.cpp                      \
-        HevcUtils.cpp                     \
-        JPEGSource.cpp                    \
-        MP3Extractor.cpp                  \
-        MPEG2TSWriter.cpp                 \
-        MPEG4Extractor.cpp                \
-        MPEG4Writer.cpp                   \
-        MediaAdapter.cpp                  \
-        MediaClock.cpp                    \
-        MediaCodec.cpp                    \
-        MediaCodecList.cpp                \
-        MediaCodecListOverrides.cpp       \
-        MediaCodecSource.cpp              \
-        MediaExtractor.cpp                \
-        MediaSync.cpp                     \
-        MidiExtractor.cpp                 \
-        http/MediaHTTP.cpp                \
-        MediaMuxer.cpp                    \
-        MediaSource.cpp                   \
-        NuCachedSource2.cpp               \
-        NuMediaExtractor.cpp              \
-        OMXClient.cpp                     \
-        OggExtractor.cpp                  \
-        SampleIterator.cpp                \
-        SampleTable.cpp                   \
-        SimpleDecodingSource.cpp          \
-        SkipCutBuffer.cpp                 \
-        StagefrightMediaScanner.cpp       \
-        StagefrightMetadataRetriever.cpp  \
-        SurfaceMediaSource.cpp            \
-        SurfaceUtils.cpp                  \
-        ThrottledSource.cpp               \
-        Utils.cpp                         \
-        VBRISeeker.cpp                    \
-        VideoFrameScheduler.cpp           \
-        WAVExtractor.cpp                  \
-        XINGSeeker.cpp                    \
-        avc_utils.cpp                     \
-
-LOCAL_C_INCLUDES:= \
-        $(TOP)/frameworks/av/include/media/ \
-        $(TOP)/frameworks/av/include/media/stagefright/timedtext \
-        $(TOP)/frameworks/native/include/media/hardware \
-        $(TOP)/frameworks/native/include/media/openmax \
-        $(TOP)/external/flac/include \
-        $(TOP)/external/tremolo \
-        $(TOP)/external/libvpx/libwebm \
-        $(TOP)/external/icu/icu4c/source/common \
-        $(TOP)/external/icu/icu4c/source/i18n \
-        $(TOP)/system/netd/include \
-        $(call include-path-for, audio-utils)
-
-LOCAL_SHARED_LIBRARIES := \
-        libaudioutils \
-        libbinder \
-        libcamera_client \
-        libcrypto \
-        libcutils \
-        libdl \
-        libdrmframework \
-        libexpat \
-        libgui \
-        liblog \
-        libmedia \
-        libaudioclient \
-        libmediametrics \
-        libmediautils \
-        libnetd_client \
-        libsonivox \
-        libstagefright_omx \
-        libui \
-        libutils \
-        libvorbisidec \
-        libmediadrm \
-        libnativewindow \
-
-LOCAL_STATIC_LIBRARIES := \
-        libstagefright_color_conversion \
-        libyuv_static \
-        libstagefright_aacenc \
-        libstagefright_matroska \
-        libstagefright_mediafilter \
-        libstagefright_webm \
-        libstagefright_timedtext \
-        libvpx \
-        libwebm \
-        libstagefright_mpeg2ts \
-        libstagefright_id3 \
-        libFLAC \
-
-LOCAL_SHARED_LIBRARIES += \
-        libmedia_helper \
-        libstagefright_foundation \
-        libdl \
-        libRScpp \
-        libhidlbase \
-        libhidlmemory \
-        android.hidl.allocator@1.0 \
-        android.hidl.memory@1.0 \
-        android.hardware.media.omx@1.0 \
-        libstagefright_xmlparser@1.0 \
-
-LOCAL_EXPORT_SHARED_LIBRARY_HEADERS := libmedia
-
-LOCAL_CFLAGS += -Wno-multichar -Werror -Wno-error=deprecated-declarations -Wall
-
-# enable experiments only in userdebug and eng builds
-ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT)))
-LOCAL_CFLAGS += -DENABLE_STAGEFRIGHT_EXPERIMENTS
-endif
-
-LOCAL_SANITIZE := unsigned-integer-overflow signed-integer-overflow cfi
-LOCAL_SANITIZE_DIAG := cfi
-
-LOCAL_MODULE:= libstagefright
-
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_SHARED_LIBRARY)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/media/libstagefright/AudioSource.cpp b/media/libstagefright/AudioSource.cpp
index 4ccd2d0..f2b1f10 100644
--- a/media/libstagefright/AudioSource.cpp
+++ b/media/libstagefright/AudioSource.cpp
@@ -58,13 +58,16 @@
       mOutSampleRate(outSampleRate > 0 ? outSampleRate : sampleRate),
       mTrackMaxAmplitude(false),
       mStartTimeUs(0),
+      mStopSystemTimeUs(-1),
+      mLastFrameTimestampUs(0),
       mMaxAmplitude(0),
       mPrevSampleTimeUs(0),
       mInitialReadTimeUs(0),
       mNumFramesReceived(0),
       mNumFramesSkipped(0),
       mNumFramesLost(0),
-      mNumClientOwnedBuffers(0) {
+      mNumClientOwnedBuffers(0),
+      mNoMoreFramesToRead(false) {
     ALOGV("sampleRate: %u, outSampleRate: %u, channelCount: %u",
             sampleRate, outSampleRate, channelCount);
     CHECK(channelCount == 1 || channelCount == 2);
@@ -175,6 +178,8 @@
     }
 
     mStarted = false;
+    mStopSystemTimeUs = -1;
+    mNoMoreFramesToRead = false;
     mFrameAvailableCondition.signal();
 
     mRecord->stop();
@@ -243,6 +248,9 @@
 
     while (mStarted && mBuffersReceived.empty()) {
         mFrameAvailableCondition.wait(mLock);
+        if (mNoMoreFramesToRead) {
+            return OK;
+        }
     }
     if (!mStarted) {
         return OK;
@@ -286,6 +294,21 @@
     return OK;
 }
 
+status_t AudioSource::setStopTimeUs(int64_t stopTimeUs) {
+    Mutex::Autolock autoLock(mLock);
+    ALOGV("Set stoptime: %lld us", (long long)stopTimeUs);
+
+    if (stopTimeUs < -1) {
+        ALOGE("Invalid stop time %lld us", (long long)stopTimeUs);
+        return BAD_VALUE;
+    } else if (stopTimeUs == -1) {
+        ALOGI("reset stopTime to be -1");
+    }
+
+    mStopSystemTimeUs = stopTimeUs;
+    return OK;
+}
+
 void AudioSource::signalBufferReturned(MediaBuffer *buffer) {
     ALOGV("signalBufferReturned: %p", buffer->data());
     Mutex::Autolock autoLock(mLock);
@@ -338,6 +361,14 @@
         return OK;
     }
 
+    if (mStopSystemTimeUs != -1 && timeUs >= mStopSystemTimeUs) {
+        ALOGV("Drop Audio frame at %lld  stop time: %lld us",
+                (long long)timeUs, (long long)mStopSystemTimeUs);
+        mNoMoreFramesToRead = true;
+        mFrameAvailableCondition.signal();
+        return OK;
+    }
+
     if (mNumFramesReceived == 0 && mPrevSampleTimeUs == 0) {
         mInitialReadTimeUs = timeUs;
         // Initial delay
@@ -346,6 +377,7 @@
         }
         mPrevSampleTimeUs = mStartTimeUs;
     }
+    mLastFrameTimestampUs = timeUs;
 
     size_t numLostBytes = 0;
     if (mNumFramesReceived > 0) {  // Ignore earlier frame lost
diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
index 1cd7693..6ed0d0e 100644
--- a/media/libstagefright/CameraSource.cpp
+++ b/media/libstagefright/CameraSource.cpp
@@ -220,6 +220,7 @@
       mNumFramesEncoded(0),
       mTimeBetweenFrameCaptureUs(0),
       mFirstFrameTimeUs(0),
+      mStopSystemTimeUs(-1),
       mNumFramesDropped(0),
       mNumGlitches(0),
       mGlitchDurationThresholdUs(200000),
@@ -879,6 +880,7 @@
     {
         Mutex::Autolock autoLock(mLock);
         mStarted = false;
+        mStopSystemTimeUs = -1;
         mFrameAvailableCondition.signal();
 
         int64_t token;
@@ -1103,12 +1105,33 @@
     return OK;
 }
 
+status_t CameraSource::setStopTimeUs(int64_t stopTimeUs) {
+    Mutex::Autolock autoLock(mLock);
+    ALOGV("Set stoptime: %lld us", (long long)stopTimeUs);
+
+    if (stopTimeUs < -1) {
+        ALOGE("Invalid stop time %lld us", (long long)stopTimeUs);
+        return BAD_VALUE;
+    } else if (stopTimeUs == -1) {
+        ALOGI("reset stopTime to be -1");
+    }
+
+    mStopSystemTimeUs = stopTimeUs;
+    return OK;
+}
+
 bool CameraSource::shouldSkipFrameLocked(int64_t timestampUs) {
     if (!mStarted || (mNumFramesReceived == 0 && timestampUs < mStartTimeUs)) {
         ALOGV("Drop frame at %lld/%lld us", (long long)timestampUs, (long long)mStartTimeUs);
         return true;
     }
 
+    if (mStopSystemTimeUs != -1 && timestampUs >= mStopSystemTimeUs) {
+        ALOGV("Drop Camera frame at %lld  stop time: %lld us",
+                (long long)timestampUs, (long long)mStopSystemTimeUs);
+        return true;
+    }
+
     // May need to skip frame or modify timestamp. Currently implemented
     // by the subclass CameraSourceTimeLapse.
     if (skipCurrentFrame(timestampUs)) {
diff --git a/media/libstagefright/MPEG2TSWriter.cpp b/media/libstagefright/MPEG2TSWriter.cpp
index b83b0a0..03ea959 100644
--- a/media/libstagefright/MPEG2TSWriter.cpp
+++ b/media/libstagefright/MPEG2TSWriter.cpp
@@ -710,7 +710,7 @@
     uint32_t crc = htonl(crc32(&buffer->data()[5], 12));
     memcpy(&buffer->data()[17], &crc, sizeof(crc));
 
-    CHECK_EQ(internalWrite(buffer->data(), buffer->size()), buffer->size());
+    CHECK_EQ(internalWrite(buffer->data(), buffer->size()), (ssize_t)buffer->size());
 }
 
 void MPEG2TSWriter::writeProgramMap() {
@@ -786,7 +786,7 @@
     uint32_t crc = htonl(crc32(&buffer->data()[5], 12+mSources.size()*5));
     memcpy(&buffer->data()[17+mSources.size()*5], &crc, sizeof(crc));
 
-    CHECK_EQ(internalWrite(buffer->data(), buffer->size()), buffer->size());
+    CHECK_EQ(internalWrite(buffer->data(), buffer->size()), (ssize_t)buffer->size());
 }
 
 void MPEG2TSWriter::writeAccessUnit(
@@ -891,7 +891,7 @@
 
     memcpy(ptr, accessUnit->data(), copy);
 
-    CHECK_EQ(internalWrite(buffer->data(), buffer->size()), buffer->size());
+    CHECK_EQ(internalWrite(buffer->data(), buffer->size()), (ssize_t)buffer->size());
 
     size_t offset = copy;
     while (offset < accessUnit->size()) {
@@ -937,7 +937,7 @@
 
         memcpy(ptr, accessUnit->data() + offset, copy);
         CHECK_EQ(internalWrite(buffer->data(), buffer->size()),
-                 buffer->size());
+                 (ssize_t)buffer->size());
 
         offset += copy;
     }
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index e4306a5..87abb6a 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -5207,6 +5207,7 @@
         FOURCC('3', 'g', 'p', '4'),
         FOURCC('m', 'p', '4', '1'),
         FOURCC('m', 'p', '4', '2'),
+        FOURCC('d', 'a', 's', 'h'),
 
         // Won't promise that the following file types can be played.
         // Just give these file types a chance.
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
old mode 100755
new mode 100644
index 223b166..93d4f57
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -112,6 +112,7 @@
     int64_t getDurationUs() const;
     int64_t getEstimatedTrackSizeBytes() const;
     void writeTrackHeader(bool use32BitOffset = true);
+    int64_t getMinCttsOffsetTimeUs();
     void bufferChunk(int64_t timestampUs);
     bool isAvc() const { return mIsAvc; }
     bool isHevc() const { return mIsHevc; }
@@ -140,7 +141,7 @@
             mTotalNumTableEntries(0),
             mNumValuesInCurrEntry(0),
             mCurrTableEntriesElement(NULL) {
-            CHECK_GT(mElementCapacity, 0);
+            CHECK_GT(mElementCapacity, 0u);
             // Ensure no integer overflow on allocation in add().
             CHECK_LT(ENTRY_SIZE, UINT32_MAX / mElementCapacity);
         }
@@ -168,7 +169,7 @@
                 --iterations;
             }
             CHECK(it != mTableEntryList.end());
-            CHECK_EQ(iterations, 0);
+            CHECK_EQ(iterations, 0u);
 
             (*it)[(pos % (mElementCapacity * ENTRY_SIZE))] = value;
         }
@@ -189,7 +190,7 @@
                 --iterations;
             }
             CHECK(it != mTableEntryList.end());
-            CHECK_EQ(iterations, 0);
+            CHECK_EQ(iterations, 0u);
 
             value = (*it)[(pos % (mElementCapacity * ENTRY_SIZE))];
             return true;
@@ -237,12 +238,12 @@
         // 2. followed by the values in the table enties in order
         // @arg writer the writer to actual write to the storage
         void write(MPEG4Writer *writer) const {
-            CHECK_EQ(mNumValuesInCurrEntry % ENTRY_SIZE, 0);
+            CHECK_EQ(mNumValuesInCurrEntry % ENTRY_SIZE, 0u);
             uint32_t nEntries = mTotalNumTableEntries;
             writer->writeInt32(nEntries);
             for (typename List<TYPE *>::iterator it = mTableEntryList.begin();
                 it != mTableEntryList.end(); ++it) {
-                CHECK_GT(nEntries, 0);
+                CHECK_GT(nEntries, 0u);
                 if (nEntries >= mElementCapacity) {
                     writer->write(*it, sizeof(TYPE) * ENTRY_SIZE, mElementCapacity);
                     nEntries -= mElementCapacity;
@@ -307,10 +308,17 @@
     ListTableEntries<uint32_t, 2> *mCttsTableEntries;
 
     int64_t mMinCttsOffsetTimeUs;
-    int64_t mMaxCttsOffsetTimeUs;
+    int64_t mMinCttsOffsetTicks;
+    int64_t mMaxCttsOffsetTicks;
 
-    // Save the last 10 frames' timestamp for debug.
-    std::list<std::pair<int64_t, int64_t>> mTimestampDebugHelper;
+    // Save the last 10 frames' timestamp and frame type for debug.
+    struct TimestampDebugHelperEntry {
+        int64_t pts;
+        int64_t dts;
+        std::string frameType;
+    };
+
+    std::list<TimestampDebugHelperEntry> mTimestampDebugHelper;
 
     // Sequence parameter set or picture parameter set
     struct AVCParamSet {
@@ -343,6 +351,7 @@
 
     void dumpTimeStamps();
 
+    int64_t getStartTimeOffsetTimeUs() const;
     int32_t getStartTimeOffsetScaledTime() const;
 
     static void *ThreadWrapper(void *me);
@@ -1133,9 +1142,22 @@
         writeUdtaBox();
     }
     writeMetaBox();
-    int32_t id = 1;
+    // Loop through all the tracks to get the global time offset if there is
+    // any ctts table appears in a video track.
+    int64_t minCttsOffsetTimeUs = kMaxCttsOffsetTimeUs;
     for (List<Track *>::iterator it = mTracks.begin();
-        it != mTracks.end(); ++it, ++id) {
+        it != mTracks.end(); ++it) {
+        minCttsOffsetTimeUs =
+            std::min(minCttsOffsetTimeUs, (*it)->getMinCttsOffsetTimeUs());
+    }
+    ALOGI("Ajust the moov start time from %lld us -> %lld us",
+            (long long)mStartTimestampUs,
+            (long long)(mStartTimestampUs + minCttsOffsetTimeUs - kMaxCttsOffsetTimeUs));
+    // Adjust the global start time.
+    mStartTimestampUs += minCttsOffsetTimeUs - kMaxCttsOffsetTimeUs;
+
+    for (List<Track *>::iterator it = mTracks.begin();
+        it != mTracks.end(); ++it) {
         (*it)->writeTrackHeader(mUse32BitOffset);
     }
     endBox();  // moov
@@ -1280,7 +1302,7 @@
 
         mOffset += length + 4;
     } else {
-        CHECK_LT(length, 65536);
+        CHECK_LT(length, 65536u);
 
         uint8_t x = length >> 8;
         ::write(mFd, &x, 1);
@@ -1340,7 +1362,7 @@
 }
 
 void MPEG4Writer::beginBox(const char *fourcc) {
-    CHECK_EQ(strlen(fourcc), 4);
+    CHECK_EQ(strlen(fourcc), 4u);
 
     mBoxes.push_back(mWriteMoovBoxToMemory?
             mMoovBoxBufferOffset: mOffset);
@@ -1391,7 +1413,7 @@
 }
 
 void MPEG4Writer::writeFourcc(const char *s) {
-    CHECK_EQ(strlen(s), 4);
+    CHECK_EQ(strlen(s), 4u);
     write(s, 1, 4);
 }
 
@@ -1625,10 +1647,14 @@
       mStssTableEntries(new ListTableEntries<uint32_t, 1>(1000)),
       mSttsTableEntries(new ListTableEntries<uint32_t, 2>(1000)),
       mCttsTableEntries(new ListTableEntries<uint32_t, 2>(1000)),
+      mMinCttsOffsetTimeUs(0),
+      mMinCttsOffsetTicks(0),
+      mMaxCttsOffsetTicks(0),
       mCodecSpecificData(NULL),
       mCodecSpecificDataSize(0),
       mGotAllCodecSpecificData(false),
       mReachedEOS(false),
+      mStartTimestampUs(-1),
       mRotation(0) {
     getCodecSpecificDataFromInputFormatIfPossible();
 
@@ -2135,13 +2161,17 @@
     if (mDone) {
         return OK;
     }
-    mDone = true;
+
     if (stopSource) {
         ALOGD("%s track source stopping", getTrackType());
         mSource->stop();
         ALOGD("%s track source stopped", getTrackType());
     }
 
+    // Set mDone to be true after sucessfully stop mSource as mSource may be still outputting
+    // buffers to the writer.
+    mDone = true;
+
     void *dummy;
     pthread_join(mThread, &dummy);
     status_t err = static_cast<status_t>(reinterpret_cast<uintptr_t>(dummy));
@@ -2521,12 +2551,12 @@
 }
 
 void MPEG4Writer::Track::dumpTimeStamps() {
-    ALOGE("Dumping %s track's last 10 frames timestamp ", getTrackType());
+    ALOGE("Dumping %s track's last 10 frames timestamp and frame type ", getTrackType());
     std::string timeStampString;
-    for (std::list<std::pair<int64_t, int64_t>>::iterator num = mTimestampDebugHelper.begin();
-            num != mTimestampDebugHelper.end(); ++num) {
-        timeStampString += "(" + std::to_string(num->first)+
-                "us, " + std::to_string(num->second) + "us) ";
+    for (std::list<TimestampDebugHelperEntry>::iterator entry = mTimestampDebugHelper.begin();
+            entry != mTimestampDebugHelper.end(); ++entry) {
+        timeStampString += "(" + std::to_string(entry->pts)+
+                "us, " + std::to_string(entry->dts) + "us " + entry->frameType + ") ";
     }
     ALOGE("%s", timeStampString.c_str());
 }
@@ -2736,9 +2766,9 @@
             previousPausedDurationUs += pausedDurationUs - lastDurationUs;
             mResumed = false;
         }
-        std::pair<int64_t, int64_t> timestampPair;
+        TimestampDebugHelperEntry timestampDebugEntry;
         timestampUs -= previousPausedDurationUs;
-        timestampPair.first = timestampUs;
+        timestampDebugEntry.pts = timestampUs;
         if (WARN_UNLESS(timestampUs >= 0ll, "for %s track", trackName)) {
             copy->release();
             mSource->stop();
@@ -2768,6 +2798,14 @@
             }
 
             mLastDecodingTimeUs = decodingTimeUs;
+            timestampDebugEntry.dts = decodingTimeUs;
+            timestampDebugEntry.frameType = isSync ? "Key frame" : "Non-Key frame";
+            // Insert the timestamp into the mTimestampDebugHelper
+            if (mTimestampDebugHelper.size() >= kTimestampDebugCount) {
+                mTimestampDebugHelper.pop_front();
+            }
+            mTimestampDebugHelper.push_back(timestampDebugEntry);
+
             cttsOffsetTimeUs =
                     timestampUs + kMaxCttsOffsetTimeUs - decodingTimeUs;
             if (WARN_UNLESS(cttsOffsetTimeUs >= 0ll, "for %s track", trackName)) {
@@ -2810,16 +2848,16 @@
 
             // Update ctts time offset range
             if (mStszTableEntries->count() == 0) {
-                mMinCttsOffsetTimeUs = currCttsOffsetTimeTicks;
-                mMaxCttsOffsetTimeUs = currCttsOffsetTimeTicks;
+                mMinCttsOffsetTicks = currCttsOffsetTimeTicks;
+                mMaxCttsOffsetTicks = currCttsOffsetTimeTicks;
             } else {
-                if (currCttsOffsetTimeTicks > mMaxCttsOffsetTimeUs) {
-                    mMaxCttsOffsetTimeUs = currCttsOffsetTimeTicks;
-                } else if (currCttsOffsetTimeTicks < mMinCttsOffsetTimeUs) {
-                    mMinCttsOffsetTimeUs = currCttsOffsetTimeTicks;
+                if (currCttsOffsetTimeTicks > mMaxCttsOffsetTicks) {
+                    mMaxCttsOffsetTicks = currCttsOffsetTimeTicks;
+                } else if (currCttsOffsetTimeTicks < mMinCttsOffsetTicks) {
+                    mMinCttsOffsetTicks = currCttsOffsetTimeTicks;
+                    mMinCttsOffsetTimeUs = cttsOffsetTimeUs;
                 }
             }
-
         }
 
         if (mOwner->isRealTimeRecording()) {
@@ -2897,12 +2935,6 @@
         lastDurationUs = timestampUs - lastTimestampUs;
         lastDurationTicks = currDurationTicks;
         lastTimestampUs = timestampUs;
-        timestampPair.second = timestampUs;
-        // Insert the timestamp into the mTimestampDebugHelper
-        if (mTimestampDebugHelper.size() >= kTimestampDebugCount) {
-            mTimestampDebugHelper.pop_front();
-        }
-        mTimestampDebugHelper.push_back(timestampPair);
 
         if (isSync != 0) {
             addOneStssTableEntry(mStszTableEntries->count());
@@ -3160,7 +3192,7 @@
 }
 
 int64_t MPEG4Writer::Track::getDurationUs() const {
-    return mTrackDurationUs;
+    return mTrackDurationUs + getStartTimeOffsetTimeUs();
 }
 
 int64_t MPEG4Writer::Track::getEstimatedTrackSizeBytes() const {
@@ -3215,6 +3247,16 @@
     mOwner->endBox();  // trak
 }
 
+int64_t MPEG4Writer::Track::getMinCttsOffsetTimeUs() {
+    // For video tracks with ctts table, this should return the minimum ctts
+    // offset in the table. For non-video tracks or video tracks without ctts
+    // table, this will return kMaxCttsOffsetTimeUs.
+    if (mMinCttsOffsetTicks == mMaxCttsOffsetTicks) {
+        return kMaxCttsOffsetTimeUs;
+    }
+    return mMinCttsOffsetTimeUs;
+}
+
 void MPEG4Writer::Track::writeStblBox(bool use32BitOffset) {
     mOwner->beginBox("stbl");
     mOwner->beginBox("stsd");
@@ -3365,10 +3407,10 @@
 void MPEG4Writer::Track::writeMp4aEsdsBox() {
     mOwner->beginBox("esds");
     CHECK(mCodecSpecificData);
-    CHECK_GT(mCodecSpecificDataSize, 0);
+    CHECK_GT(mCodecSpecificDataSize, 0u);
 
     // Make sure all sizes encode to a single byte.
-    CHECK_LT(mCodecSpecificDataSize + 23, 128);
+    CHECK_LT(mCodecSpecificDataSize + 23, 128u);
 
     mOwner->writeInt32(0);     // version=0, flags=0
     mOwner->writeInt8(0x03);   // ES_DescrTag
@@ -3407,10 +3449,10 @@
 
 void MPEG4Writer::Track::writeMp4vEsdsBox() {
     CHECK(mCodecSpecificData);
-    CHECK_GT(mCodecSpecificDataSize, 0);
+    CHECK_GT(mCodecSpecificDataSize, 0u);
 
     // Make sure all sizes encode to a single byte.
-    CHECK_LT(23 + mCodecSpecificDataSize, 128);
+    CHECK_LT(23 + mCodecSpecificDataSize, 128u);
 
     mOwner->beginBox("esds");
 
@@ -3602,7 +3644,7 @@
 
 void MPEG4Writer::Track::writeAvccBox() {
     CHECK(mCodecSpecificData);
-    CHECK_GE(mCodecSpecificDataSize, 5);
+    CHECK_GE(mCodecSpecificDataSize, 5u);
 
     // Patch avcc's lengthSize field to match the number
     // of bytes we use to indicate the size of a nal unit.
@@ -3616,7 +3658,7 @@
 
 void MPEG4Writer::Track::writeHvccBox() {
     CHECK(mCodecSpecificData);
-    CHECK_GE(mCodecSpecificDataSize, 5);
+    CHECK_GE(mCodecSpecificDataSize, 5u);
 
     // Patch avcc's lengthSize field to match the number
     // of bytes we use to indicate the size of a nal unit.
@@ -3644,30 +3686,41 @@
     mOwner->endBox();  // pasp
 }
 
-int32_t MPEG4Writer::Track::getStartTimeOffsetScaledTime() const {
+int64_t MPEG4Writer::Track::getStartTimeOffsetTimeUs() const {
     int64_t trackStartTimeOffsetUs = 0;
     int64_t moovStartTimeUs = mOwner->getStartTimestampUs();
-    if (mStartTimestampUs != moovStartTimeUs) {
+    if (mStartTimestampUs != -1 && mStartTimestampUs != moovStartTimeUs) {
         CHECK_GT(mStartTimestampUs, moovStartTimeUs);
         trackStartTimeOffsetUs = mStartTimestampUs - moovStartTimeUs;
     }
-    return (trackStartTimeOffsetUs *  mTimeScale + 500000LL) / 1000000LL;
+    return trackStartTimeOffsetUs;
+}
+
+int32_t MPEG4Writer::Track::getStartTimeOffsetScaledTime() const {
+    return (getStartTimeOffsetTimeUs() * mTimeScale + 500000LL) / 1000000LL;
 }
 
 void MPEG4Writer::Track::writeSttsBox() {
     mOwner->beginBox("stts");
     mOwner->writeInt32(0);  // version=0, flags=0
-    uint32_t duration;
-    CHECK(mSttsTableEntries->get(duration, 1));
-    duration = htonl(duration);  // Back to host byte order
-    mSttsTableEntries->set(htonl(duration + getStartTimeOffsetScaledTime()), 1);
+    if (mMinCttsOffsetTicks == mMaxCttsOffsetTicks) {
+        // For non-vdeio tracks or video tracks without ctts table,
+        // adjust duration of first sample for tracks to account for
+        // first sample not starting at the media start time.
+        // TODO: consider signaling this using some offset
+        // as this is not quite correct.
+        uint32_t duration;
+        CHECK(mSttsTableEntries->get(duration, 1));
+        duration = htonl(duration);  // Back to host byte order
+        mSttsTableEntries->set(htonl(duration + getStartTimeOffsetScaledTime()), 1);
+    }
     mSttsTableEntries->write(mOwner);
     mOwner->endBox();  // stts
 }
 
 void MPEG4Writer::Track::writeCttsBox() {
     // There is no B frame at all
-    if (mMinCttsOffsetTimeUs == mMaxCttsOffsetTimeUs) {
+    if (mMinCttsOffsetTicks == mMaxCttsOffsetTicks) {
         return;
     }
 
@@ -3677,11 +3730,12 @@
     }
 
     ALOGV("ctts box has %d entries with range [%" PRId64 ", %" PRId64 "]",
-            mCttsTableEntries->count(), mMinCttsOffsetTimeUs, mMaxCttsOffsetTimeUs);
+            mCttsTableEntries->count(), mMinCttsOffsetTicks, mMaxCttsOffsetTicks);
 
     mOwner->beginBox("ctts");
     mOwner->writeInt32(0);  // version=0, flags=0
-    int64_t delta = mMinCttsOffsetTimeUs - getStartTimeOffsetScaledTime();
+    int64_t deltaTimeUs = kMaxCttsOffsetTimeUs - getStartTimeOffsetTimeUs();
+    int64_t delta = (deltaTimeUs * mTimeScale + 500000LL) / 1000000LL;
     mCttsTableEntries->adjustEntries([delta](size_t /* ix */, uint32_t (&value)[2]) {
         // entries are <count, ctts> pairs; adjust only ctts
         uint32_t duration = htonl(value[1]); // back to host byte order
diff --git a/media/libstagefright/MediaCodecSource.cpp b/media/libstagefright/MediaCodecSource.cpp
index bb20850..d808e5b 100644
--- a/media/libstagefright/MediaCodecSource.cpp
+++ b/media/libstagefright/MediaCodecSource.cpp
@@ -44,6 +44,9 @@
 const int32_t kDefaultVideoEncoderDataSpace = HAL_DATASPACE_V0_BT709;
 
 const int kStopTimeoutUs = 300000; // allow 1 sec for shutting down encoder
+// allow maximum 1 sec for stop time offset. This limits the the delay in the
+// input source.
+const int kMaxStopTimeOffsetUs = 1000000;
 
 struct MediaCodecSource::Puller : public AHandler {
     explicit Puller(const sp<MediaSource> &source);
@@ -54,7 +57,7 @@
     void stopSource();
     void pause();
     void resume();
-
+    status_t setStopTimeUs(int64_t stopTimeUs);
     bool readBuffer(MediaBuffer **buffer);
 
 protected:
@@ -66,6 +69,7 @@
         kWhatStart = 'msta',
         kWhatStop,
         kWhatPull,
+        kWhatSetStopTimeUs,
     };
 
     sp<MediaSource> mSource;
@@ -161,6 +165,12 @@
     return err;
 }
 
+status_t MediaCodecSource::Puller::setStopTimeUs(int64_t stopTimeUs) {
+    sp<AMessage> msg = new AMessage(kWhatSetStopTimeUs, this);
+    msg->setInt64("stop-time-us", stopTimeUs);
+    return postSynchronouslyAndReturnError(msg);
+}
+
 status_t MediaCodecSource::Puller::start(const sp<MetaData> &meta, const sp<AMessage> &notify) {
     ALOGV("puller (%s) start", mIsAudio ? "audio" : "video");
     mLooper->start(
@@ -250,6 +260,20 @@
             break;
         }
 
+        case kWhatSetStopTimeUs:
+        {
+            sp<AReplyToken> replyID;
+            CHECK(msg->senderAwaitsResponse(&replyID));
+            int64_t stopTimeUs;
+            CHECK(msg->findInt64("stop-time-us", &stopTimeUs));
+            status_t err = mSource->setStopTimeUs(stopTimeUs);
+
+            sp<AMessage> response = new AMessage;
+            response->setInt32("err", err);
+            response->postReply(replyID);
+            break;
+        }
+
         case kWhatStop:
         {
             mSource->stop();
@@ -364,11 +388,8 @@
 }
 
 
-status_t MediaCodecSource::setStopStimeUs(int64_t stopTimeUs) {
-    if (!(mFlags & FLAG_USE_SURFACE_INPUT)) {
-        return OK;
-    }
-    sp<AMessage> msg = new AMessage(kWhatSetStopTimeOffset, mReflector);
+status_t MediaCodecSource::setStopTimeUs(int64_t stopTimeUs) {
+    sp<AMessage> msg = new AMessage(kWhatSetStopTimeUs, mReflector);
     msg->setInt64("stop-time-us", stopTimeUs);
     return postSynchronouslyAndReturnError(msg);
 }
@@ -986,12 +1007,29 @@
 
         mStopping = true;
 
+        int64_t timeoutUs = kStopTimeoutUs;
         // if using surface, signal source EOS and wait for EOS to come back.
         // otherwise, stop puller (which also clears the input buffer queue)
         // and wait for the EOS message. We cannot call source->stop() because
         // the encoder may still be processing input buffers.
         if (mFlags & FLAG_USE_SURFACE_INPUT) {
             mEncoder->signalEndOfInputStream();
+            // Increase the timeout if there is delay in the GraphicBufferSource
+            sp<AMessage> inputFormat;
+            int64_t stopTimeOffsetUs;
+            if (mEncoder->getInputFormat(&inputFormat) == OK &&
+                    inputFormat->findInt64("android._stop-time-offset-us", &stopTimeOffsetUs) &&
+                    stopTimeOffsetUs > 0) {
+                if (stopTimeOffsetUs > kMaxStopTimeOffsetUs) {
+                    ALOGW("Source stopTimeOffsetUs %lld too large, limit at %lld us",
+                        (long long)stopTimeOffsetUs, (long long)kMaxStopTimeOffsetUs);
+                    stopTimeOffsetUs = kMaxStopTimeOffsetUs;
+                }
+                timeoutUs += stopTimeOffsetUs;
+            } else {
+                // Use kMaxStopTimeOffsetUs if stop time offset is not provided by input source
+                timeoutUs = kMaxStopTimeOffsetUs;
+            }
         } else {
             mPuller->stop();
         }
@@ -999,7 +1037,7 @@
         // complete stop even if encoder/puller stalled
         sp<AMessage> timeoutMsg = new AMessage(kWhatStopStalled, mReflector);
         timeoutMsg->setInt32("generation", mGeneration);
-        timeoutMsg->post(kStopTimeoutUs);
+        timeoutMsg->post(timeoutUs);
         break;
     }
 
@@ -1055,7 +1093,7 @@
         response->postReply(replyID);
         break;
     }
-    case kWhatSetStopTimeOffset:
+    case kWhatSetStopTimeUs:
     {
         sp<AReplyToken> replyID;
         CHECK(msg->senderAwaitsResponse(&replyID));
@@ -1063,11 +1101,13 @@
         int64_t stopTimeUs;
         CHECK(msg->findInt64("stop-time-us", &stopTimeUs));
 
-        // Propagate the timestamp offset to GraphicBufferSource.
+        // Propagate the stop time to GraphicBufferSource.
         if (mFlags & FLAG_USE_SURFACE_INPUT) {
             sp<AMessage> params = new AMessage;
             params->setInt64("stop-time-us", stopTimeUs);
             err = mEncoder->setParameters(params);
+        } else {
+            err = mPuller->setStopTimeUs(stopTimeUs);
         }
 
         sp<AMessage> response = new AMessage;
diff --git a/media/libstagefright/MediaSync.cpp b/media/libstagefright/MediaSync.cpp
index 0cf6fbf..9278381 100644
--- a/media/libstagefright/MediaSync.cpp
+++ b/media/libstagefright/MediaSync.cpp
@@ -32,6 +32,8 @@
 
 #include <ui/GraphicBuffer.h>
 
+#include <system/window.h>
+
 // Maximum late time allowed for a video frame to be rendered. When a video
 // frame arrives later than this number, it will be discarded without rendering.
 static const int64_t kMaxAllowedVideoLateTimeUs = 40000ll;
diff --git a/media/libstagefright/SampleIterator.cpp b/media/libstagefright/SampleIterator.cpp
index 4134698..4f31c5f 100644
--- a/media/libstagefright/SampleIterator.cpp
+++ b/media/libstagefright/SampleIterator.cpp
@@ -282,7 +282,7 @@
 
         default:
         {
-            CHECK_EQ(mTable->mSampleSizeFieldSize, 4);
+            CHECK_EQ(mTable->mSampleSizeFieldSize, 4u);
 
             uint8_t x;
             if (mTable->mDataSource->readAt(
diff --git a/media/libstagefright/SimpleDecodingSource.cpp b/media/libstagefright/SimpleDecodingSource.cpp
index ea7d5af..90b8603 100644
--- a/media/libstagefright/SimpleDecodingSource.cpp
+++ b/media/libstagefright/SimpleDecodingSource.cpp
@@ -36,6 +36,12 @@
 
 //static
 sp<SimpleDecodingSource> SimpleDecodingSource::Create(
+        const sp<IMediaSource> &source, uint32_t flags) {
+    return SimpleDecodingSource::Create(source, flags, nullptr, nullptr);
+}
+
+//static
+sp<SimpleDecodingSource> SimpleDecodingSource::Create(
         const sp<IMediaSource> &source, uint32_t flags, const sp<ANativeWindow> &nativeWindow,
         const char *desiredCodec) {
     sp<Surface> surface = static_cast<Surface*>(nativeWindow.get());
diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
index 883a4dd..03dc9df 100644
--- a/media/libstagefright/StagefrightMetadataRetriever.cpp
+++ b/media/libstagefright/StagefrightMetadataRetriever.cpp
@@ -44,7 +44,7 @@
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/Utils.h>
 
-#include <CharacterEncodingDetector.h>
+#include <media/CharacterEncodingDetector.h>
 
 namespace android {
 
diff --git a/media/libstagefright/SurfaceMediaSource.cpp b/media/libstagefright/SurfaceMediaSource.cpp
index d0d82b3..d14e86b 100644
--- a/media/libstagefright/SurfaceMediaSource.cpp
+++ b/media/libstagefright/SurfaceMediaSource.cpp
@@ -96,13 +96,13 @@
     mFrameAvailableListener = listener;
 }
 
-void SurfaceMediaSource::dump(String8& result) const
+void SurfaceMediaSource::dumpState(String8& result) const
 {
     char buffer[1024];
-    dump(result, "", buffer, 1024);
+    dumpState(result, "", buffer, 1024);
 }
 
-void SurfaceMediaSource::dump(
+void SurfaceMediaSource::dumpState(
         String8& result,
         const char* /* prefix */,
         char* buffer,
@@ -166,7 +166,7 @@
         mMaxAcquiredBufferCount = bufferCount;
     }
 
-    CHECK_GT(mMaxAcquiredBufferCount, 1);
+    CHECK_GT(mMaxAcquiredBufferCount, 1u);
 
     status_t err =
         mConsumer->setMaxAcquiredBufferCount(mMaxAcquiredBufferCount);
@@ -185,7 +185,7 @@
     ALOGV("setMaxAcquiredBufferCount(%zu)", count);
     Mutex::Autolock lock(mMutex);
 
-    CHECK_GT(count, 1);
+    CHECK_GT(count, 1u);
     mMaxAcquiredBufferCount = count;
 
     return OK;
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
index 621c2ce..0aea8e1 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -1069,6 +1069,16 @@
         buffer->meta()->setInt32("csd", true);
         buffer->meta()->setInt64("timeUs", 0);
         msg->setBuffer("csd-2", buffer);
+    } else if (meta->findData(kKeyFlacMetadata, &type, &data, &size)) {
+        sp<ABuffer> buffer = new (std::nothrow) ABuffer(size);
+        if (buffer.get() == NULL || buffer->base() == NULL) {
+            return NO_MEMORY;
+        }
+        memcpy(buffer->data(), data, size);
+
+        buffer->meta()->setInt32("csd", true);
+        buffer->meta()->setInt64("timeUs", 0);
+        msg->setBuffer("csd-0", buffer);
     } else if (meta->findData(kKeyVp9CodecPrivate, &type, &data, &size)) {
         sp<ABuffer> buffer = new (std::nothrow) ABuffer(size);
         if (buffer.get() == NULL || buffer->base() == NULL) {
@@ -1552,6 +1562,7 @@
     { MEDIA_MIMETYPE_AUDIO_VORBIS,      AUDIO_FORMAT_VORBIS },
     { MEDIA_MIMETYPE_AUDIO_OPUS,        AUDIO_FORMAT_OPUS},
     { MEDIA_MIMETYPE_AUDIO_AC3,         AUDIO_FORMAT_AC3},
+    { MEDIA_MIMETYPE_AUDIO_FLAC,        AUDIO_FORMAT_FLAC},
     { 0, AUDIO_FORMAT_INVALID }
 };
 
diff --git a/media/libstagefright/avc_utils.cpp b/media/libstagefright/avc_utils.cpp
index 9b042d3..ea2433a 100644
--- a/media/libstagefright/avc_utils.cpp
+++ b/media/libstagefright/avc_utils.cpp
@@ -80,7 +80,16 @@
     for (size_t j = 0; j < sizeOfScalingList; ++j) {
         if (nextScale != 0) {
             signed delta_scale = parseSE(br);
-            nextScale = (lastScale + delta_scale + 256) % 256;
+            // ISO_IEC_14496-10_201402-ITU, 7.4.2.1.1.1, The value of delta_scale
+            // shall be in the range of −128 to +127, inclusive.
+            if (delta_scale < -128) {
+                ALOGW("delta_scale (%d) is below range, capped to -128", delta_scale);
+                delta_scale = -128;
+            } else if (delta_scale > 127) {
+                ALOGW("delta_scale (%d) is above range, capped to 127", delta_scale);
+                delta_scale = 127;
+            }
+            nextScale = (lastScale + (delta_scale + 256)) % 256;
         }
 
         lastScale = (nextScale == 0) ? lastScale : nextScale;
diff --git a/media/libstagefright/codecs/Android.mk b/media/libstagefright/codecs/Android.mk
deleted file mode 100644
index 2e43120..0000000
--- a/media/libstagefright/codecs/Android.mk
+++ /dev/null
@@ -1,4 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/media/libstagefright/codecs/aacdec/Android.bp b/media/libstagefright/codecs/aacdec/Android.bp
new file mode 100644
index 0000000..6e04c1e
--- /dev/null
+++ b/media/libstagefright/codecs/aacdec/Android.bp
@@ -0,0 +1,36 @@
+cc_library_shared {
+    name: "libstagefright_soft_aacdec",
+
+    srcs: [
+        "SoftAAC2.cpp",
+        "DrcPresModeWrap.cpp",
+    ],
+
+    include_dirs: [
+        "frameworks/av/media/libstagefright/include",
+        "frameworks/native/include/media/openmax",
+    ],
+
+    cflags: ["-Werror"],
+
+    sanitize: {
+        misc_undefined: [
+            "signed-integer-overflow",
+            "unsigned-integer-overflow",
+        ],
+        cfi: true,
+        diag: {
+            cfi: true,
+        },
+    },
+
+    static_libs: ["libFraunhoferAAC"],
+
+    shared_libs: [
+        "libstagefright_omx",
+        "libstagefright_foundation",
+        "libutils",
+        "libcutils",
+        "liblog",
+    ],
+}
diff --git a/media/libstagefright/codecs/aacdec/Android.mk b/media/libstagefright/codecs/aacdec/Android.mk
deleted file mode 100644
index 29c0f33..0000000
--- a/media/libstagefright/codecs/aacdec/Android.mk
+++ /dev/null
@@ -1,33 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
-      SoftAAC2.cpp \
-      DrcPresModeWrap.cpp
-
-LOCAL_C_INCLUDES := \
-      frameworks/av/media/libstagefright/include \
-      frameworks/native/include/media/openmax \
-      external/aac/libAACdec/include \
-      external/aac/libPCMutils/include \
-      external/aac/libFDK/include \
-      external/aac/libMpegTPDec/include \
-      external/aac/libSBRdec/include \
-      external/aac/libSYS/include
-
-LOCAL_CFLAGS :=
-
-LOCAL_CFLAGS += -Werror
-LOCAL_SANITIZE := signed-integer-overflow unsigned-integer-overflow cfi
-LOCAL_SANITIZE_DIAG := cfi
-
-LOCAL_STATIC_LIBRARIES := libFraunhoferAAC
-
-LOCAL_SHARED_LIBRARIES := \
-      libstagefright_omx libstagefright_foundation libutils libcutils liblog
-
-LOCAL_MODULE := libstagefright_soft_aacdec
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/codecs/aacenc/AACEncoder.cpp b/media/libstagefright/codecs/aacenc/AACEncoder.cpp
index 9e596ff..5656139 100644
--- a/media/libstagefright/codecs/aacenc/AACEncoder.cpp
+++ b/media/libstagefright/codecs/aacenc/AACEncoder.cpp
@@ -296,7 +296,7 @@
     memset(&inputData, 0, sizeof(inputData));
     inputData.Buffer = (unsigned char*) mInputFrame;
     inputData.Length = nSamples * sizeof(int16_t);
-    CHECK(VO_ERR_NONE == mApiHandle->SetInputData(mEncoderHandle,&inputData));
+    CHECK((VO_U32)VO_ERR_NONE == mApiHandle->SetInputData(mEncoderHandle,&inputData));
 
     VO_CODECBUFFER outputData;
     memset(&outputData, 0, sizeof(outputData));
diff --git a/media/libstagefright/codecs/aacenc/Android.bp b/media/libstagefright/codecs/aacenc/Android.bp
new file mode 100644
index 0000000..1a7ffca
--- /dev/null
+++ b/media/libstagefright/codecs/aacenc/Android.bp
@@ -0,0 +1,176 @@
+cc_library_static {
+    name: "libstagefright_aacenc",
+
+    srcs: [
+        "basic_op/basicop2.c",
+        "basic_op/oper_32b.c",
+
+        "AACEncoder.cpp",
+        "src/aac_rom.c",
+        "src/aacenc.c",
+        "src/aacenc_core.c",
+        "src/adj_thr.c",
+        "src/band_nrg.c",
+        "src/bit_cnt.c",
+        "src/bitbuffer.c",
+        "src/bitenc.c",
+        "src/block_switch.c",
+        "src/channel_map.c",
+        "src/dyn_bits.c",
+        "src/grp_data.c",
+        "src/interface.c",
+        "src/line_pe.c",
+        "src/ms_stereo.c",
+        "src/pre_echo_control.c",
+        "src/psy_configuration.c",
+        "src/psy_main.c",
+        "src/qc_main.c",
+        "src/quantize.c",
+        "src/sf_estim.c",
+        "src/spreading.c",
+        "src/stat_bits.c",
+        "src/tns.c",
+        "src/transform.c",
+        "src/memalign.c",
+    ],
+
+    arch: {
+        arm: {
+            srcs: [
+                "src/asm/ARMV5E/AutoCorrelation_v5.s",
+                "src/asm/ARMV5E/band_nrg_v5.s",
+                "src/asm/ARMV5E/CalcWindowEnergy_v5.s",
+                "src/asm/ARMV5E/PrePostMDCT_v5.s",
+                "src/asm/ARMV5E/R4R8First_v5.s",
+                "src/asm/ARMV5E/Radix4FFT_v5.s",
+            ],
+
+            cflags: [
+                "-DARMV5E",
+                "-DARM_INASM",
+                "-DARMV5_INASM",
+            ],
+
+            local_include_dirs: ["src/asm/ARMV5E"],
+
+            instruction_set: "arm",
+
+            armv7_a_neon: {
+                exclude_srcs: [
+                    "src/asm/ARMV5E/PrePostMDCT_v5.s",
+                    "src/asm/ARMV5E/R4R8First_v5.s",
+                    "src/asm/ARMV5E/Radix4FFT_v5.s",
+                ],
+                srcs: [
+                    "src/asm/ARMV7/PrePostMDCT_v7.s",
+                    "src/asm/ARMV7/R4R8First_v7.s",
+                    "src/asm/ARMV7/Radix4FFT_v7.s",
+                ],
+
+                cflags: [
+                    "-DARMV7Neon",
+                    "-DARMV6_INASM",
+                ],
+
+                local_include_dirs: ["src/asm/ARMV7"],
+            },
+        },
+    },
+
+    // libstagefright links this static library, so it probably isn't appropriate to
+    // link libstagefright.  However, this library includes libstagefright headers,
+    // and needs libbinder to be able to do so correctly.
+    shared_libs: [
+        "libbinder",
+        "libstagefright_enc_common",
+    ],
+
+    include_dirs: [
+        "frameworks/av/include",
+        "frameworks/av/media/libstagefright/include",
+    ],
+
+    local_include_dirs: [
+        "src",
+        "inc",
+        "basic_op",
+    ],
+
+    cflags: ["-Werror"],
+
+    sanitize: {
+        misc_undefined: [
+            "signed-integer-overflow",
+            "unsigned-integer-overflow",
+        ],
+    },
+
+}
+
+//###############################################################################
+
+cc_library_shared {
+    name: "libstagefright_soft_aacenc",
+
+    srcs: ["SoftAACEncoder2.cpp"],
+
+    include_dirs: [
+        "frameworks/av/media/libstagefright/include",
+        "frameworks/native/include/media/openmax",
+    ],
+
+    cflags: ["-Werror"],
+
+    sanitize: {
+        misc_undefined: [
+            "signed-integer-overflow",
+            "unsigned-integer-overflow",
+        ],
+        cfi: true,
+        diag: {
+            cfi: true,
+        },
+    },
+
+    static_libs: ["libFraunhoferAAC"],
+
+    shared_libs: [
+        "libstagefright_omx",
+        "libstagefright_foundation",
+        "libutils",
+        "liblog",
+    ],
+}
+
+cc_library_shared {
+    name: "libstagefright_soft_aacenc_visualon",
+
+    srcs: ["SoftAACEncoder.cpp"],
+
+    include_dirs: [
+        "frameworks/av/media/libstagefright/include",
+        "frameworks/native/include/media/openmax",
+    ],
+
+    cflags: [
+        "-DOSCL_IMPORT_REF=",
+        "-Werror",
+    ],
+
+    sanitize: {
+        misc_undefined: [
+            "signed-integer-overflow",
+            "unsigned-integer-overflow",
+        ],
+    },
+
+    static_libs: ["libstagefright_aacenc"],
+
+    shared_libs: [
+        "libstagefright_omx",
+        "libstagefright_foundation",
+        "libutils",
+        "liblog",
+        "libstagefright_enc_common",
+    ],
+}
diff --git a/media/libstagefright/codecs/aacenc/Android.mk b/media/libstagefright/codecs/aacenc/Android.mk
deleted file mode 100644
index 527687b..0000000
--- a/media/libstagefright/codecs/aacenc/Android.mk
+++ /dev/null
@@ -1,149 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-AAC_LIBRARY = fraunhofer
-
-LOCAL_SRC_FILES := basic_op/basicop2.c basic_op/oper_32b.c
-
-LOCAL_SRC_FILES += \
-	AACEncoder.cpp \
-	src/aac_rom.c \
-	src/aacenc.c \
-	src/aacenc_core.c \
-	src/adj_thr.c \
-	src/band_nrg.c \
-	src/bit_cnt.c \
-	src/bitbuffer.c \
-	src/bitenc.c \
-	src/block_switch.c \
-	src/channel_map.c \
-	src/dyn_bits.c \
-	src/grp_data.c \
-	src/interface.c \
-	src/line_pe.c \
-	src/ms_stereo.c \
-	src/pre_echo_control.c \
-	src/psy_configuration.c \
-	src/psy_main.c \
-	src/qc_main.c \
-	src/quantize.c \
-	src/sf_estim.c \
-	src/spreading.c \
-	src/stat_bits.c \
-	src/tns.c \
-	src/transform.c \
-	src/memalign.c
-
-ifneq ($(ARCH_ARM_HAVE_NEON),true)
-    LOCAL_SRC_FILES_arm := \
-        src/asm/ARMV5E/AutoCorrelation_v5.s \
-        src/asm/ARMV5E/band_nrg_v5.s \
-        src/asm/ARMV5E/CalcWindowEnergy_v5.s \
-        src/asm/ARMV5E/PrePostMDCT_v5.s \
-        src/asm/ARMV5E/R4R8First_v5.s \
-        src/asm/ARMV5E/Radix4FFT_v5.s
-
-    LOCAL_CFLAGS_arm := -DARMV5E -DARM_INASM -DARMV5_INASM
-    LOCAL_C_INCLUDES_arm := $(LOCAL_PATH)/src/asm/ARMV5E
-else
-    LOCAL_SRC_FILES_arm := \
-        src/asm/ARMV5E/AutoCorrelation_v5.s \
-        src/asm/ARMV5E/band_nrg_v5.s \
-        src/asm/ARMV5E/CalcWindowEnergy_v5.s \
-        src/asm/ARMV7/PrePostMDCT_v7.s \
-        src/asm/ARMV7/R4R8First_v7.s \
-        src/asm/ARMV7/Radix4FFT_v7.s
-    LOCAL_CFLAGS_arm := -DARMV5E -DARMV7Neon -DARM_INASM -DARMV5_INASM -DARMV6_INASM
-    LOCAL_C_INCLUDES_arm := $(LOCAL_PATH)/src/asm/ARMV5E
-    LOCAL_C_INCLUDES_arm += $(LOCAL_PATH)/src/asm/ARMV7
-endif
-
-LOCAL_MODULE := libstagefright_aacenc
-
-LOCAL_ARM_MODE := arm
-
-LOCAL_STATIC_LIBRARIES :=
-
-# libstagefright links this static library, so it probably isn't appropriate to
-# link libstagefright.  However, this library includes libstagefright headers,
-# and needs libbinder to be able to do so correctly.
-LOCAL_SHARED_LIBRARIES := libbinder
-
-LOCAL_C_INCLUDES := \
-	frameworks/av/include \
-	frameworks/av/media/libstagefright/include \
-	frameworks/av/media/libstagefright/codecs/common/include \
-	$(LOCAL_PATH)/src \
-	$(LOCAL_PATH)/inc \
-	$(LOCAL_PATH)/basic_op
-
-LOCAL_CFLAGS += -Werror
-LOCAL_SANITIZE := signed-integer-overflow unsigned-integer-overflow
-
-include $(BUILD_STATIC_LIBRARY)
-
-################################################################################
-
-include $(CLEAR_VARS)
-
-ifeq ($(AAC_LIBRARY), fraunhofer)
-
-  include $(CLEAR_VARS)
-
-  LOCAL_SRC_FILES := \
-          SoftAACEncoder2.cpp
-
-  LOCAL_C_INCLUDES := \
-          frameworks/av/media/libstagefright/include \
-          frameworks/native/include/media/openmax \
-          external/aac/libAACenc/include \
-          external/aac/libFDK/include \
-          external/aac/libMpegTPEnc/include \
-          external/aac/libSBRenc/include \
-          external/aac/libSYS/include
-
-  LOCAL_CFLAGS :=
-
-  LOCAL_CFLAGS += -Werror
-  LOCAL_SANITIZE := signed-integer-overflow unsigned-integer-overflow cfi
-  LOCAL_SANITIZE_DIAG := cfi
-
-  LOCAL_STATIC_LIBRARIES := libFraunhoferAAC
-
-  LOCAL_SHARED_LIBRARIES := \
-          libstagefright_omx libstagefright_foundation libutils liblog
-
-  LOCAL_MODULE := libstagefright_soft_aacenc
-  LOCAL_MODULE_TAGS := optional
-
-  include $(BUILD_SHARED_LIBRARY)
-
-else # visualon
-
-  LOCAL_SRC_FILES := \
-          SoftAACEncoder.cpp
-
-  LOCAL_C_INCLUDES := \
-          frameworks/av/media/libstagefright/include \
-          frameworks/av/media/libstagefright/codecs/common/include \
-          frameworks/native/include/media/openmax
-
-  LOCAL_CFLAGS := -DOSCL_IMPORT_REF=
-
-  LOCAL_CFLAGS += -Werror
-  LOCAL_SANITIZE := signed-integer-overflow unsigned-integer-overflow cfi
-  LOCAL_SANITIZE_DIAG := cfi
-
-  LOCAL_STATIC_LIBRARIES := \
-          libstagefright_aacenc
-
-  LOCAL_SHARED_LIBRARIES := \
-          libstagefright_omx libstagefright_foundation libutils liblog \
-          libstagefright_enc_common
-
-  LOCAL_MODULE := libstagefright_soft_aacenc
-  LOCAL_MODULE_TAGS := optional
-
-  include $(BUILD_SHARED_LIBRARY)
-
-endif # $(AAC_LIBRARY)
diff --git a/media/libstagefright/codecs/aacenc/SampleCode/Android.bp b/media/libstagefright/codecs/aacenc/SampleCode/Android.bp
new file mode 100644
index 0000000..c6ba4f3
--- /dev/null
+++ b/media/libstagefright/codecs/aacenc/SampleCode/Android.bp
@@ -0,0 +1,18 @@
+cc_binary {
+    name: "AACEncTest",
+
+    srcs: ["AAC_E_SAMPLES.c"],
+
+    arch: {
+        arm: {
+            instruction_set: "arm",
+        },
+    },
+
+    shared_libs: [
+        "libstagefright",
+        "libdl",
+    ],
+
+    static_libs: ["libstagefright_enc_common"],
+}
diff --git a/media/libstagefright/codecs/aacenc/SampleCode/Android.mk b/media/libstagefright/codecs/aacenc/SampleCode/Android.mk
deleted file mode 100644
index d06dcf6..0000000
--- a/media/libstagefright/codecs/aacenc/SampleCode/Android.mk
+++ /dev/null
@@ -1,23 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
-    AAC_E_SAMPLES.c \
-    ../../common/cmnMemory.c
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_MODULE := AACEncTest
-
-LOCAL_ARM_MODE := arm
-
-LOCAL_SHARED_LIBRARIES := \
-    libstagefright \
-    libdl
-
-LOCAL_C_INCLUDES := \
-    $(LOCAL_PATH)/ \
-    $(LOCAL_PATH)/../../common \
-    $(LOCAL_PATH)/../../common/include \
-
-include $(BUILD_EXECUTABLE)
diff --git a/media/libstagefright/codecs/aacenc/SoftAACEncoder.cpp b/media/libstagefright/codecs/aacenc/SoftAACEncoder.cpp
index 67c31af..0704294 100644
--- a/media/libstagefright/codecs/aacenc/SoftAACEncoder.cpp
+++ b/media/libstagefright/codecs/aacenc/SoftAACEncoder.cpp
@@ -65,7 +65,7 @@
     onReset();
 
     if (mEncoderHandle) {
-        CHECK_EQ(VO_ERR_NONE, mApiHandle->Uninit(mEncoderHandle));
+        CHECK_EQ((VO_U32)VO_ERR_NONE, mApiHandle->Uninit(mEncoderHandle));
         mEncoderHandle = NULL;
     }
 
@@ -333,7 +333,7 @@
     // We call this whenever sample rate, number of channels or bitrate change
     // in reponse to setParameter calls.
 
-    ALOGV("setAudioParams: %lu Hz, %lu channels, %lu bps",
+    ALOGV("setAudioParams: %u Hz, %u channels, %u bps",
          mSampleRate, mNumChannels, mBitRate);
 
     status_t err = setAudioSpecificConfigData();
@@ -383,12 +383,12 @@
     int32_t index;
     status_t err = getSampleRateTableIndex(mSampleRate, index);
     if (err != OK) {
-        ALOGE("Unsupported sample rate (%lu Hz)", mSampleRate);
+        ALOGE("Unsupported sample rate (%u Hz)", mSampleRate);
         return err;
     }
 
     if (mNumChannels > 2 || mNumChannels <= 0) {
-        ALOGE("Unsupported number of channels(%lu)", mNumChannels);
+        ALOGE("Unsupported number of channels(%u)", mNumChannels);
         return UNKNOWN_ERROR;
     }
 
@@ -399,7 +399,7 @@
     return OK;
 }
 
-void SoftAACEncoder::onQueueFilled(OMX_U32 portIndex) {
+void SoftAACEncoder::onQueueFilled(OMX_U32 /*portIndex*/) {
     if (mSignalledError) {
         return;
     }
@@ -520,7 +520,7 @@
         memset(&inputData, 0, sizeof(inputData));
         inputData.Buffer = (unsigned char *)mInputFrame;
         inputData.Length = numBytesPerInputFrame;
-        CHECK(VO_ERR_NONE ==
+        CHECK((VO_U32)VO_ERR_NONE ==
                 mApiHandle->SetInputData(mEncoderHandle, &inputData));
 
         VO_CODECBUFFER outputData;
diff --git a/media/libstagefright/codecs/aacenc/src/grp_data.c b/media/libstagefright/codecs/aacenc/src/grp_data.c
index 7861e1c..edfb95b 100644
--- a/media/libstagefright/codecs/aacenc/src/grp_data.c
+++ b/media/libstagefright/codecs/aacenc/src/grp_data.c
@@ -88,7 +88,6 @@
     offset += groupLen[grp] * FRAME_LEN_SHORT;
   }
   groupedSfbOffset[i] = FRAME_LEN_LONG;
-  i += 1;
 
   /* calculate minSnr */
   i = 0;
diff --git a/media/libstagefright/codecs/aacenc/src/ms_stereo.c b/media/libstagefright/codecs/aacenc/src/ms_stereo.c
index 1e4b227..ca028dc 100644
--- a/media/libstagefright/codecs/aacenc/src/ms_stereo.c
+++ b/media/libstagefright/codecs/aacenc/src/ms_stereo.c
@@ -94,8 +94,6 @@
 
       pnms = fixmul(nrgL, nrgR);
 
-      temp = (pnlr + 1) / ((pnms >> 8) + 1);
-
       temp = pnms - pnlr;
       if( temp > 0 ){
 
diff --git a/media/libstagefright/codecs/amrnb/Android.bp b/media/libstagefright/codecs/amrnb/Android.bp
new file mode 100644
index 0000000..b44c296
--- /dev/null
+++ b/media/libstagefright/codecs/amrnb/Android.bp
@@ -0,0 +1 @@
+subdirs = ["*"]
diff --git a/media/libstagefright/codecs/amrnb/Android.mk b/media/libstagefright/codecs/amrnb/Android.mk
deleted file mode 100644
index 2e43120..0000000
--- a/media/libstagefright/codecs/amrnb/Android.mk
+++ /dev/null
@@ -1,4 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/media/libstagefright/codecs/amrnb/common/Android.bp b/media/libstagefright/codecs/amrnb/common/Android.bp
new file mode 100644
index 0000000..c5ac558
--- /dev/null
+++ b/media/libstagefright/codecs/amrnb/common/Android.bp
@@ -0,0 +1,82 @@
+cc_library_shared {
+    name: "libstagefright_amrnb_common",
+
+    srcs: [
+        "src/add.cpp",
+        "src/az_lsp.cpp",
+        "src/bitno_tab.cpp",
+        "src/bitreorder_tab.cpp",
+        "src/bits2prm.cpp",
+        "src/c2_9pf_tab.cpp",
+        "src/copy.cpp",
+        "src/div_32.cpp",
+        "src/div_s.cpp",
+        "src/extract_h.cpp",
+        "src/extract_l.cpp",
+        "src/gains_tbl.cpp",
+        "src/gc_pred.cpp",
+        "src/gmed_n.cpp",
+        "src/grid_tbl.cpp",
+        "src/gray_tbl.cpp",
+        "src/int_lpc.cpp",
+        "src/inv_sqrt.cpp",
+        "src/inv_sqrt_tbl.cpp",
+        "src/l_abs.cpp",
+        "src/l_deposit_h.cpp",
+        "src/l_deposit_l.cpp",
+        "src/l_shr_r.cpp",
+        "src/log2.cpp",
+        "src/log2_norm.cpp",
+        "src/log2_tbl.cpp",
+        "src/lsfwt.cpp",
+        "src/lsp.cpp",
+        "src/lsp_az.cpp",
+        "src/lsp_lsf.cpp",
+        "src/lsp_lsf_tbl.cpp",
+        "src/lsp_tab.cpp",
+        "src/mult_r.cpp",
+        "src/norm_l.cpp",
+        "src/norm_s.cpp",
+        "src/ph_disp_tab.cpp",
+        "src/pow2.cpp",
+        "src/pow2_tbl.cpp",
+        "src/pred_lt.cpp",
+        "src/q_plsf.cpp",
+        "src/q_plsf_3.cpp",
+        "src/q_plsf_3_tbl.cpp",
+        "src/q_plsf_5.cpp",
+        "src/q_plsf_5_tbl.cpp",
+        "src/qua_gain_tbl.cpp",
+        "src/reorder.cpp",
+        "src/residu.cpp",
+        "src/round.cpp",
+        "src/set_zero.cpp",
+        "src/shr.cpp",
+        "src/shr_r.cpp",
+        "src/sqrt_l.cpp",
+        "src/sqrt_l_tbl.cpp",
+        "src/sub.cpp",
+        "src/syn_filt.cpp",
+        "src/vad1.cpp",
+        "src/weight_a.cpp",
+        "src/window_tab.cpp",
+    ],
+
+    export_include_dirs: ["include"],
+
+    cflags: [
+        "-DOSCL_UNUSED_ARG(x)=(void)(x)",
+        "-DOSCL_IMPORT_REF=",
+        "-DOSCL_EXPORT_REF=",
+
+        "-Werror",
+    ],
+
+    //addressing b/25409744
+    //sanitize: {
+    //    misc_undefined: [
+    //        "signed-integer-overflow",
+    //        "unsigned-integer-overflow",
+    //    ],
+    //},
+}
diff --git a/media/libstagefright/codecs/amrnb/common/Android.mk b/media/libstagefright/codecs/amrnb/common/Android.mk
deleted file mode 100644
index 0bb5724..0000000
--- a/media/libstagefright/codecs/amrnb/common/Android.mk
+++ /dev/null
@@ -1,76 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
-	src/add.cpp \
- 	src/az_lsp.cpp \
- 	src/bitno_tab.cpp \
- 	src/bitreorder_tab.cpp \
- 	src/bits2prm.cpp \
- 	src/c2_9pf_tab.cpp \
- 	src/copy.cpp \
- 	src/div_32.cpp \
- 	src/div_s.cpp \
- 	src/extract_h.cpp \
- 	src/extract_l.cpp \
- 	src/gains_tbl.cpp \
- 	src/gc_pred.cpp \
- 	src/gmed_n.cpp \
- 	src/grid_tbl.cpp \
- 	src/gray_tbl.cpp \
- 	src/int_lpc.cpp \
- 	src/inv_sqrt.cpp \
- 	src/inv_sqrt_tbl.cpp \
- 	src/l_abs.cpp \
- 	src/l_deposit_h.cpp \
- 	src/l_deposit_l.cpp \
- 	src/l_shr_r.cpp \
- 	src/log2.cpp \
- 	src/log2_norm.cpp \
- 	src/log2_tbl.cpp \
- 	src/lsfwt.cpp \
- 	src/lsp.cpp \
- 	src/lsp_az.cpp \
- 	src/lsp_lsf.cpp \
- 	src/lsp_lsf_tbl.cpp \
- 	src/lsp_tab.cpp \
- 	src/mult_r.cpp \
- 	src/norm_l.cpp \
- 	src/norm_s.cpp \
- 	src/ph_disp_tab.cpp \
- 	src/pow2.cpp \
- 	src/pow2_tbl.cpp \
- 	src/pred_lt.cpp \
- 	src/q_plsf.cpp \
- 	src/q_plsf_3.cpp \
- 	src/q_plsf_3_tbl.cpp \
- 	src/q_plsf_5.cpp \
- 	src/q_plsf_5_tbl.cpp \
- 	src/qua_gain_tbl.cpp \
- 	src/reorder.cpp \
- 	src/residu.cpp \
- 	src/round.cpp \
- 	src/set_zero.cpp \
- 	src/shr.cpp \
- 	src/shr_r.cpp \
- 	src/sqrt_l.cpp \
- 	src/sqrt_l_tbl.cpp \
- 	src/sub.cpp \
- 	src/syn_filt.cpp \
- 	src/vad1.cpp \
- 	src/weight_a.cpp \
- 	src/window_tab.cpp
-
-LOCAL_C_INCLUDES := \
-        $(LOCAL_PATH)/include
-
-LOCAL_CFLAGS := \
-        -D"OSCL_UNUSED_ARG(x)=(void)(x)" -DOSCL_IMPORT_REF= -DOSCL_EXPORT_REF=
-
-LOCAL_CFLAGS += -Werror
-#addressing b/25409744
-#LOCAL_SANITIZE := signed-integer-overflow unsigned-integer-overflow
-
-LOCAL_MODULE := libstagefright_amrnb_common
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/codecs/amrnb/dec/Android.bp b/media/libstagefright/codecs/amrnb/dec/Android.bp
new file mode 100644
index 0000000..996183b
--- /dev/null
+++ b/media/libstagefright/codecs/amrnb/dec/Android.bp
@@ -0,0 +1,126 @@
+cc_library_static {
+    name: "libstagefright_amrnbdec",
+
+    srcs: [
+        "src/a_refl.cpp",
+        "src/agc.cpp",
+        "src/amrdecode.cpp",
+        "src/b_cn_cod.cpp",
+        "src/bgnscd.cpp",
+        "src/c_g_aver.cpp",
+        "src/d1035pf.cpp",
+        "src/d2_11pf.cpp",
+        "src/d2_9pf.cpp",
+        "src/d3_14pf.cpp",
+        "src/d4_17pf.cpp",
+        "src/d8_31pf.cpp",
+        "src/d_gain_c.cpp",
+        "src/d_gain_p.cpp",
+        "src/d_plsf.cpp",
+        "src/d_plsf_3.cpp",
+        "src/d_plsf_5.cpp",
+        "src/dec_amr.cpp",
+        "src/dec_gain.cpp",
+        "src/dec_input_format_tab.cpp",
+        "src/dec_lag3.cpp",
+        "src/dec_lag6.cpp",
+        "src/dtx_dec.cpp",
+        "src/ec_gains.cpp",
+        "src/ex_ctrl.cpp",
+        "src/if2_to_ets.cpp",
+        "src/int_lsf.cpp",
+        "src/lsp_avg.cpp",
+        "src/ph_disp.cpp",
+        "src/post_pro.cpp",
+        "src/preemph.cpp",
+        "src/pstfilt.cpp",
+        "src/qgain475_tab.cpp",
+        "src/sp_dec.cpp",
+        "src/wmf_to_ets.cpp",
+    ],
+
+    include_dirs: ["frameworks/av/media/libstagefright/include"],
+    local_include_dirs: ["src"],
+
+    cflags: [
+        "-DOSCL_UNUSED_ARG(x)=(void)(x)",
+        "-DOSCL_IMPORT_REF=",
+
+        "-Werror",
+    ],
+
+    //sanitize: {
+    //    misc_undefined: [
+    //        "signed-integer-overflow",
+    //    ],
+    //},
+
+    shared_libs: ["libstagefright_amrnb_common"],
+}
+
+//###############################################################################
+
+cc_library_shared {
+    name: "libstagefright_soft_amrdec",
+
+    srcs: ["SoftAMR.cpp"],
+
+    include_dirs: [
+        "frameworks/av/media/libstagefright/include",
+        "frameworks/av/media/libstagefright/codecs/amrwb/src",
+        "frameworks/native/include/media/openmax",
+    ],
+    local_include_dirs: ["src"],
+
+    cflags: [
+        "-DOSCL_IMPORT_REF=",
+        "-Werror",
+    ],
+
+    //sanitize: {
+    //    misc_undefined: [
+    //        "signed-integer-overflow",
+    //    ],
+    //},
+    //LOCAL_SANITIZE := signed-integer-overflow
+
+    static_libs: [
+        "libstagefright_amrnbdec",
+        "libstagefright_amrwbdec",
+    ],
+
+    shared_libs: [
+        "libstagefright_omx",
+        "libstagefright_foundation",
+        "libutils",
+        "liblog",
+        "libstagefright_amrnb_common",
+    ],
+}
+
+//###############################################################################
+cc_test {
+    name: "libstagefright_amrnbdec_test",
+    gtest: false,
+
+    srcs: ["test/amrnbdec_test.cpp"],
+
+    local_include_dirs: ["src"],
+
+    static_libs: [
+        "libstagefright_amrnbdec",
+        "libsndfile",
+    ],
+
+    shared_libs: [
+        "libstagefright_amrnb_common",
+        "libaudioutils",
+        "liblog",
+    ],
+
+    //sanitize: {
+    //    misc_undefined: [
+    //        "signed-integer-overflow",
+    //    ],
+    //},
+}
diff --git a/media/libstagefright/codecs/amrnb/dec/Android.mk b/media/libstagefright/codecs/amrnb/dec/Android.mk
deleted file mode 100644
index 3959b80..0000000
--- a/media/libstagefright/codecs/amrnb/dec/Android.mk
+++ /dev/null
@@ -1,110 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
- 	src/a_refl.cpp \
- 	src/agc.cpp \
- 	src/amrdecode.cpp \
- 	src/b_cn_cod.cpp \
- 	src/bgnscd.cpp \
- 	src/c_g_aver.cpp \
- 	src/d1035pf.cpp \
- 	src/d2_11pf.cpp \
- 	src/d2_9pf.cpp \
- 	src/d3_14pf.cpp \
- 	src/d4_17pf.cpp \
- 	src/d8_31pf.cpp \
- 	src/d_gain_c.cpp \
- 	src/d_gain_p.cpp \
- 	src/d_plsf.cpp \
- 	src/d_plsf_3.cpp \
- 	src/d_plsf_5.cpp \
- 	src/dec_amr.cpp \
- 	src/dec_gain.cpp \
- 	src/dec_input_format_tab.cpp \
- 	src/dec_lag3.cpp \
- 	src/dec_lag6.cpp \
- 	src/dtx_dec.cpp \
- 	src/ec_gains.cpp \
- 	src/ex_ctrl.cpp \
- 	src/if2_to_ets.cpp \
- 	src/int_lsf.cpp \
- 	src/lsp_avg.cpp \
- 	src/ph_disp.cpp \
- 	src/post_pro.cpp \
- 	src/preemph.cpp \
- 	src/pstfilt.cpp \
- 	src/qgain475_tab.cpp \
- 	src/sp_dec.cpp \
- 	src/wmf_to_ets.cpp
-
-LOCAL_C_INCLUDES := \
-        frameworks/av/media/libstagefright/include \
-        $(LOCAL_PATH)/src \
-        $(LOCAL_PATH)/include \
-        $(LOCAL_PATH)/../common/include
-
-LOCAL_CFLAGS := \
-        -D"OSCL_UNUSED_ARG(x)=(void)(x)" -DOSCL_IMPORT_REF=
-
-LOCAL_CFLAGS += -Werror
-#LOCAL_SANITIZE := signed-integer-overflow
-
-LOCAL_MODULE := libstagefright_amrnbdec
-
-include $(BUILD_STATIC_LIBRARY)
-
-################################################################################
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
-        SoftAMR.cpp
-
-LOCAL_C_INCLUDES := \
-        frameworks/av/media/libstagefright/include \
-        frameworks/av/media/libstagefright/codecs/amrwb/src \
-        frameworks/native/include/media/openmax \
-        $(LOCAL_PATH)/src \
-        $(LOCAL_PATH)/include \
-        $(LOCAL_PATH)/../common/include \
-
-LOCAL_CFLAGS := -DOSCL_IMPORT_REF=
-
-LOCAL_CFLAGS += -Werror
-#LOCAL_SANITIZE := signed-integer-overflow
-
-LOCAL_STATIC_LIBRARIES := \
-        libstagefright_amrnbdec libstagefright_amrwbdec
-
-LOCAL_SHARED_LIBRARIES := \
-        libstagefright_omx libstagefright_foundation libutils liblog \
-        libstagefright_amrnb_common
-
-LOCAL_MODULE := libstagefright_soft_amrdec
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_SHARED_LIBRARY)
-
-################################################################################
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := \
-        test/amrnbdec_test.cpp
-
-LOCAL_C_INCLUDES := \
-        $(LOCAL_PATH)/src \
-        $(LOCAL_PATH)/../common/include \
-        $(call include-path-for, audio-utils)
-
-LOCAL_STATIC_LIBRARIES := \
-        libstagefright_amrnbdec libsndfile
-
-LOCAL_SHARED_LIBRARIES := \
-        libstagefright_amrnb_common libaudioutils liblog
-
-#LOCAL_SANITIZE := signed-integer-overflow
-
-LOCAL_MODULE := libstagefright_amrnbdec_test
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_EXECUTABLE)
diff --git a/media/libstagefright/codecs/amrnb/enc/Android.bp b/media/libstagefright/codecs/amrnb/enc/Android.bp
new file mode 100644
index 0000000..af0f8c2
--- /dev/null
+++ b/media/libstagefright/codecs/amrnb/enc/Android.bp
@@ -0,0 +1,135 @@
+cc_library_static {
+    name: "libstagefright_amrnbenc",
+
+    srcs: [
+        "src/amrencode.cpp",
+        "src/autocorr.cpp",
+        "src/c1035pf.cpp",
+        "src/c2_11pf.cpp",
+        "src/c2_9pf.cpp",
+        "src/c3_14pf.cpp",
+        "src/c4_17pf.cpp",
+        "src/c8_31pf.cpp",
+        "src/calc_cor.cpp",
+        "src/calc_en.cpp",
+        "src/cbsearch.cpp",
+        "src/cl_ltp.cpp",
+        "src/cod_amr.cpp",
+        "src/convolve.cpp",
+        "src/cor_h.cpp",
+        "src/cor_h_x.cpp",
+        "src/cor_h_x2.cpp",
+        "src/corrwght_tab.cpp",
+        "src/dtx_enc.cpp",
+        "src/enc_lag3.cpp",
+        "src/enc_lag6.cpp",
+        "src/enc_output_format_tab.cpp",
+        "src/ets_to_if2.cpp",
+        "src/ets_to_wmf.cpp",
+        "src/g_adapt.cpp",
+        "src/g_code.cpp",
+        "src/g_pitch.cpp",
+        "src/gain_q.cpp",
+        "src/hp_max.cpp",
+        "src/inter_36.cpp",
+        "src/inter_36_tab.cpp",
+        "src/l_comp.cpp",
+        "src/l_extract.cpp",
+        "src/l_negate.cpp",
+        "src/lag_wind.cpp",
+        "src/lag_wind_tab.cpp",
+        "src/levinson.cpp",
+        "src/lpc.cpp",
+        "src/ol_ltp.cpp",
+        "src/p_ol_wgh.cpp",
+        "src/pitch_fr.cpp",
+        "src/pitch_ol.cpp",
+        "src/pre_big.cpp",
+        "src/pre_proc.cpp",
+        "src/prm2bits.cpp",
+        "src/q_gain_c.cpp",
+        "src/q_gain_p.cpp",
+        "src/qgain475.cpp",
+        "src/qgain795.cpp",
+        "src/qua_gain.cpp",
+        "src/s10_8pf.cpp",
+        "src/set_sign.cpp",
+        "src/sid_sync.cpp",
+        "src/sp_enc.cpp",
+        "src/spreproc.cpp",
+        "src/spstproc.cpp",
+        "src/ton_stab.cpp",
+    ],
+
+    include_dirs: ["frameworks/av/media/libstagefright/include"],
+    local_include_dirs: ["src"],
+
+    cflags: [
+        "-DOSCL_UNUSED_ARG(x)=(void)(x)",
+        "-Werror",
+    ],
+
+    //addressing b/25409744
+    //sanitize: {
+    //    misc_undefined: [
+    //        "signed-integer-overflow",
+    //    ],
+    //},
+
+    shared_libs: ["libstagefright_amrnb_common"],
+}
+
+//###############################################################################
+
+cc_library_shared {
+    name: "libstagefright_soft_amrnbenc",
+
+    srcs: ["SoftAMRNBEncoder.cpp"],
+
+    include_dirs: [
+        "frameworks/av/media/libstagefright/include",
+        "frameworks/native/include/media/openmax",
+    ],
+    local_include_dirs: ["src"],
+
+    cflags: ["-Werror"],
+
+    //addressing b/25409744
+    //sanitize: {
+    //    misc_undefined: [
+    //        "signed-integer-overflow",
+    //    ],
+    //},
+
+    static_libs: ["libstagefright_amrnbenc"],
+
+    shared_libs: [
+        "libstagefright_omx",
+        "libstagefright_foundation",
+        "libutils",
+        "liblog",
+        "libstagefright_amrnb_common",
+    ],
+}
+
+//###############################################################################
+
+cc_test {
+    name: "libstagefright_amrnbenc_test",
+    gtest: false,
+
+    srcs: ["test/amrnb_enc_test.cpp"],
+
+    local_include_dirs: ["src"],
+
+    static_libs: ["libstagefright_amrnbenc"],
+
+    shared_libs: ["libstagefright_amrnb_common"],
+
+    //addressing b/25409744
+    //sanitize: {
+    //    misc_undefined: [
+    //        "signed-integer-overflow",
+    //    ],
+    //},
+}
diff --git a/media/libstagefright/codecs/amrnb/enc/Android.mk b/media/libstagefright/codecs/amrnb/enc/Android.mk
deleted file mode 100644
index af1efb9..0000000
--- a/media/libstagefright/codecs/amrnb/enc/Android.mk
+++ /dev/null
@@ -1,134 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
-	src/amrencode.cpp \
- 	src/autocorr.cpp \
- 	src/c1035pf.cpp \
- 	src/c2_11pf.cpp \
- 	src/c2_9pf.cpp \
- 	src/c3_14pf.cpp \
- 	src/c4_17pf.cpp \
- 	src/c8_31pf.cpp \
- 	src/calc_cor.cpp \
- 	src/calc_en.cpp \
- 	src/cbsearch.cpp \
- 	src/cl_ltp.cpp \
- 	src/cod_amr.cpp \
- 	src/convolve.cpp \
- 	src/cor_h.cpp \
- 	src/cor_h_x.cpp \
- 	src/cor_h_x2.cpp \
- 	src/corrwght_tab.cpp \
- 	src/dtx_enc.cpp \
- 	src/enc_lag3.cpp \
- 	src/enc_lag6.cpp \
- 	src/enc_output_format_tab.cpp \
- 	src/ets_to_if2.cpp \
- 	src/ets_to_wmf.cpp \
- 	src/g_adapt.cpp \
- 	src/g_code.cpp \
- 	src/g_pitch.cpp \
- 	src/gain_q.cpp \
- 	src/hp_max.cpp \
- 	src/inter_36.cpp \
- 	src/inter_36_tab.cpp \
- 	src/l_comp.cpp \
- 	src/l_extract.cpp \
- 	src/l_negate.cpp \
- 	src/lag_wind.cpp \
- 	src/lag_wind_tab.cpp \
- 	src/levinson.cpp \
- 	src/lpc.cpp \
- 	src/ol_ltp.cpp \
- 	src/p_ol_wgh.cpp \
- 	src/pitch_fr.cpp \
- 	src/pitch_ol.cpp \
- 	src/pre_big.cpp \
- 	src/pre_proc.cpp \
- 	src/prm2bits.cpp \
- 	src/q_gain_c.cpp \
- 	src/q_gain_p.cpp \
- 	src/qgain475.cpp \
- 	src/qgain795.cpp \
- 	src/qua_gain.cpp \
- 	src/s10_8pf.cpp \
- 	src/set_sign.cpp \
- 	src/sid_sync.cpp \
- 	src/sp_enc.cpp \
- 	src/spreproc.cpp \
- 	src/spstproc.cpp \
- 	src/ton_stab.cpp
-
-LOCAL_C_INCLUDES := \
-        frameworks/av/media/libstagefright/include \
-        $(LOCAL_PATH)/src \
-        $(LOCAL_PATH)/include \
-        $(LOCAL_PATH)/../common/include
-
-LOCAL_CFLAGS := \
-        -D"OSCL_UNUSED_ARG(x)=(void)(x)"
-
-LOCAL_CFLAGS += -Werror
-#addressing b/25409744
-#LOCAL_SANITIZE := signed-integer-overflow
-
-LOCAL_MODULE := libstagefright_amrnbenc
-
-include $(BUILD_STATIC_LIBRARY)
-
-################################################################################
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
-        SoftAMRNBEncoder.cpp
-
-LOCAL_C_INCLUDES := \
-        frameworks/av/media/libstagefright/include \
-        frameworks/native/include/media/openmax \
-        $(LOCAL_PATH)/src \
-        $(LOCAL_PATH)/include \
-        $(LOCAL_PATH)/../common/include \
-        $(LOCAL_PATH)/../common
-
-LOCAL_CFLAGS += -Werror
-#addressing b/25409744
-#LOCAL_SANITIZE := signed-integer-overflow
-
-LOCAL_STATIC_LIBRARIES := \
-        libstagefright_amrnbenc
-
-LOCAL_SHARED_LIBRARIES := \
-        libstagefright_omx libstagefright_foundation libutils liblog \
-        libstagefright_amrnb_common
-
-LOCAL_MODULE := libstagefright_soft_amrnbenc
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_SHARED_LIBRARY)
-
-################################################################################
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := \
-    test/amrnb_enc_test.cpp
-
-LOCAL_C_INCLUDES := \
-    $(LOCAL_PATH)/src \
-    $(LOCAL_PATH)/../common/include
-
-
-LOCAL_STATIC_LIBRARIES := \
-    libstagefright_amrnbenc
-
-LOCAL_SHARED_LIBRARIES := \
-    libstagefright_amrnb_common
-
-#addressing b/25409744
-#LOCAL_SANITIZE := signed-integer-overflow
-
-LOCAL_MODULE := libstagefright_amrnbenc_test
-LOCAL_MODULE_TAGS := tests
-
-include $(BUILD_EXECUTABLE)
diff --git a/media/libstagefright/codecs/amrwb/Android.bp b/media/libstagefright/codecs/amrwb/Android.bp
new file mode 100644
index 0000000..e261c04
--- /dev/null
+++ b/media/libstagefright/codecs/amrwb/Android.bp
@@ -0,0 +1,85 @@
+cc_library_static {
+    name: "libstagefright_amrwbdec",
+
+    srcs: [
+        "src/agc2_amr_wb.cpp",
+        "src/band_pass_6k_7k.cpp",
+        "src/dec_acelp_2p_in_64.cpp",
+        "src/dec_acelp_4p_in_64.cpp",
+        "src/dec_alg_codebook.cpp",
+        "src/dec_gain2_amr_wb.cpp",
+        "src/deemphasis_32.cpp",
+        "src/dtx_decoder_amr_wb.cpp",
+        "src/get_amr_wb_bits.cpp",
+        "src/highpass_400hz_at_12k8.cpp",
+        "src/highpass_50hz_at_12k8.cpp",
+        "src/homing_amr_wb_dec.cpp",
+        "src/interpolate_isp.cpp",
+        "src/isf_extrapolation.cpp",
+        "src/isp_az.cpp",
+        "src/isp_isf.cpp",
+        "src/lagconceal.cpp",
+        "src/low_pass_filt_7k.cpp",
+        "src/median5.cpp",
+        "src/mime_io.cpp",
+        "src/noise_gen_amrwb.cpp",
+        "src/normalize_amr_wb.cpp",
+        "src/oversamp_12k8_to_16k.cpp",
+        "src/phase_dispersion.cpp",
+        "src/pit_shrp.cpp",
+        "src/pred_lt4.cpp",
+        "src/preemph_amrwb_dec.cpp",
+        "src/pvamrwb_math_op.cpp",
+        "src/pvamrwbdecoder.cpp",
+        "src/q_gain2_tab.cpp",
+        "src/qisf_ns.cpp",
+        "src/qisf_ns_tab.cpp",
+        "src/qpisf_2s.cpp",
+        "src/qpisf_2s_tab.cpp",
+        "src/scale_signal.cpp",
+        "src/synthesis_amr_wb.cpp",
+        "src/voice_factor.cpp",
+        "src/wb_syn_filt.cpp",
+        "src/weight_amrwb_lpc.cpp",
+    ],
+
+    include_dirs: ["frameworks/av/media/libstagefright/include"],
+    local_include_dirs: ["src"],
+    export_include_dirs: ["include"],
+
+    cflags: [
+        "-DOSCL_UNUSED_ARG(x)=(void)(x)",
+        "-DOSCL_IMPORT_REF=",
+
+        "-Werror",
+    ],
+
+    sanitize: {
+        misc_undefined: [
+            "signed-integer-overflow",
+        ],
+    },
+}
+
+//###############################################################################
+cc_test {
+    name: "libstagefright_amrwbdec_test",
+    gtest: false,
+
+    srcs: ["test/amrwbdec_test.cpp"],
+
+    static_libs: [
+        "libstagefright_amrwbdec",
+        "libsndfile",
+    ],
+
+    local_include_dirs: ["src"],
+
+    shared_libs: ["libaudioutils"],
+
+    sanitize: {
+        misc_undefined: [
+            "signed-integer-overflow",
+        ],
+    },
+}
diff --git a/media/libstagefright/codecs/amrwb/Android.mk b/media/libstagefright/codecs/amrwb/Android.mk
deleted file mode 100644
index 73a1751..0000000
--- a/media/libstagefright/codecs/amrwb/Android.mk
+++ /dev/null
@@ -1,81 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
-	src/agc2_amr_wb.cpp \
- 	src/band_pass_6k_7k.cpp \
- 	src/dec_acelp_2p_in_64.cpp \
- 	src/dec_acelp_4p_in_64.cpp \
- 	src/dec_alg_codebook.cpp \
- 	src/dec_gain2_amr_wb.cpp \
- 	src/deemphasis_32.cpp \
- 	src/dtx_decoder_amr_wb.cpp \
- 	src/get_amr_wb_bits.cpp \
- 	src/highpass_400hz_at_12k8.cpp \
- 	src/highpass_50hz_at_12k8.cpp \
- 	src/homing_amr_wb_dec.cpp \
- 	src/interpolate_isp.cpp \
- 	src/isf_extrapolation.cpp \
- 	src/isp_az.cpp \
- 	src/isp_isf.cpp \
- 	src/lagconceal.cpp \
- 	src/low_pass_filt_7k.cpp \
- 	src/median5.cpp \
- 	src/mime_io.cpp \
- 	src/noise_gen_amrwb.cpp \
- 	src/normalize_amr_wb.cpp \
- 	src/oversamp_12k8_to_16k.cpp \
- 	src/phase_dispersion.cpp \
- 	src/pit_shrp.cpp \
- 	src/pred_lt4.cpp \
- 	src/preemph_amrwb_dec.cpp \
- 	src/pvamrwb_math_op.cpp \
- 	src/pvamrwbdecoder.cpp \
- 	src/q_gain2_tab.cpp \
- 	src/qisf_ns.cpp \
- 	src/qisf_ns_tab.cpp \
- 	src/qpisf_2s.cpp \
- 	src/qpisf_2s_tab.cpp \
- 	src/scale_signal.cpp \
- 	src/synthesis_amr_wb.cpp \
- 	src/voice_factor.cpp \
- 	src/wb_syn_filt.cpp \
- 	src/weight_amrwb_lpc.cpp
-
-LOCAL_C_INCLUDES := \
-        frameworks/av/media/libstagefright/include \
-        $(LOCAL_PATH)/src \
-        $(LOCAL_PATH)/include
-
-LOCAL_CFLAGS := \
-        -D"OSCL_UNUSED_ARG(x)=(void)(x)" -DOSCL_IMPORT_REF=
-
-LOCAL_CFLAGS += -Werror
-LOCAL_SANITIZE := signed-integer-overflow
-
-LOCAL_MODULE := libstagefright_amrwbdec
-
-include $(BUILD_STATIC_LIBRARY)
-
-################################################################################
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := \
-        test/amrwbdec_test.cpp
-
-LOCAL_C_INCLUDES := \
-        $(LOCAL_PATH)/src \
-        $(LOCAL_PATH)/include \
-        $(call include-path-for, audio-utils)
-
-LOCAL_STATIC_LIBRARIES := \
-        libstagefright_amrwbdec libsndfile
-
-LOCAL_SHARED_LIBRARIES := \
-        libaudioutils
-
-LOCAL_SANITIZE := signed-integer-overflow
-
-LOCAL_MODULE := libstagefright_amrwbdec_test
-LOCAL_MODULE_TAGS := tests
-
-include $(BUILD_EXECUTABLE)
diff --git a/media/libstagefright/codecs/amrwbenc/Android.bp b/media/libstagefright/codecs/amrwbenc/Android.bp
new file mode 100644
index 0000000..5c5a122
--- /dev/null
+++ b/media/libstagefright/codecs/amrwbenc/Android.bp
@@ -0,0 +1,180 @@
+cc_library_static {
+    name: "libstagefright_amrwbenc",
+
+    srcs: [
+        "src/autocorr.c",
+        "src/az_isp.c",
+        "src/bits.c",
+        "src/c2t64fx.c",
+        "src/c4t64fx.c",
+        "src/convolve.c",
+        "src/cor_h_x.c",
+        "src/decim54.c",
+        "src/deemph.c",
+        "src/dtx.c",
+        "src/g_pitch.c",
+        "src/gpclip.c",
+        "src/homing.c",
+        "src/hp400.c",
+        "src/hp50.c",
+        "src/hp6k.c",
+        "src/hp_wsp.c",
+        "src/int_lpc.c",
+        "src/isp_az.c",
+        "src/isp_isf.c",
+        "src/lag_wind.c",
+        "src/levinson.c",
+        "src/log2.c",
+        "src/lp_dec2.c",
+        "src/math_op.c",
+        "src/oper_32b.c",
+        "src/p_med_ol.c",
+        "src/pit_shrp.c",
+        "src/pitch_f4.c",
+        "src/pred_lt4.c",
+        "src/preemph.c",
+        "src/q_gain2.c",
+        "src/q_pulse.c",
+        "src/qisf_ns.c",
+        "src/qpisf_2s.c",
+        "src/random.c",
+        "src/residu.c",
+        "src/scale.c",
+        "src/stream.c",
+        "src/syn_filt.c",
+        "src/updt_tar.c",
+        "src/util.c",
+        "src/voAMRWBEnc.c",
+        "src/voicefac.c",
+        "src/wb_vad.c",
+        "src/weight_a.c",
+        "src/mem_align.c",
+    ],
+
+    arch: {
+        arm: {
+            srcs: [
+                "src/asm/ARMV5E/convolve_opt.s",
+                "src/asm/ARMV5E/cor_h_vec_opt.s",
+                "src/asm/ARMV5E/Deemph_32_opt.s",
+                "src/asm/ARMV5E/Dot_p_opt.s",
+                "src/asm/ARMV5E/Filt_6k_7k_opt.s",
+                "src/asm/ARMV5E/Norm_Corr_opt.s",
+                "src/asm/ARMV5E/pred_lt4_1_opt.s",
+                "src/asm/ARMV5E/residu_asm_opt.s",
+                "src/asm/ARMV5E/scale_sig_opt.s",
+                "src/asm/ARMV5E/Syn_filt_32_opt.s",
+                "src/asm/ARMV5E/syn_filt_opt.s",
+            ],
+
+            cflags: [
+                "-DARM",
+                "-DASM_OPT",
+            ],
+            local_include_dirs: ["src/asm/ARMV5E"],
+
+            instruction_set: "arm",
+
+            armv7_a_neon: {
+                exclude_srcs: [
+                    "src/asm/ARMV5E/convolve_opt.s",
+                    "src/asm/ARMV5E/cor_h_vec_opt.s",
+                    "src/asm/ARMV5E/Deemph_32_opt.s",
+                    "src/asm/ARMV5E/Dot_p_opt.s",
+                    "src/asm/ARMV5E/Filt_6k_7k_opt.s",
+                    "src/asm/ARMV5E/Norm_Corr_opt.s",
+                    "src/asm/ARMV5E/pred_lt4_1_opt.s",
+                    "src/asm/ARMV5E/residu_asm_opt.s",
+                    "src/asm/ARMV5E/scale_sig_opt.s",
+                    "src/asm/ARMV5E/Syn_filt_32_opt.s",
+                    "src/asm/ARMV5E/syn_filt_opt.s",
+                ],
+
+                srcs: [
+                    "src/asm/ARMV7/convolve_neon.s",
+                    "src/asm/ARMV7/cor_h_vec_neon.s",
+                    "src/asm/ARMV7/Deemph_32_neon.s",
+                    "src/asm/ARMV7/Dot_p_neon.s",
+                    "src/asm/ARMV7/Filt_6k_7k_neon.s",
+                    "src/asm/ARMV7/Norm_Corr_neon.s",
+                    "src/asm/ARMV7/pred_lt4_1_neon.s",
+                    "src/asm/ARMV7/residu_asm_neon.s",
+                    "src/asm/ARMV7/scale_sig_neon.s",
+                    "src/asm/ARMV7/Syn_filt_32_neon.s",
+                    "src/asm/ARMV7/syn_filt_neon.s",
+                ],
+
+                // don't actually generate neon instructions, see bug 26932980
+                cflags: [
+                    "-DARMV7",
+                    "-mfpu=vfpv3",
+                ],
+                local_include_dirs: [
+                    "src/asm/ARMV5E",
+                    "src/asm/ARMV7",
+                ],
+            },
+
+        },
+    },
+
+    include_dirs: [
+        "frameworks/av/include",
+        "frameworks/av/media/libstagefright/include",
+    ],
+
+    local_include_dirs: ["src"],
+    export_include_dirs: ["inc"],
+
+    shared_libs: [
+        "libstagefright_enc_common",
+    ],
+
+    cflags: ["-Werror"],
+    sanitize: {
+        cfi: true,
+        diag: {
+            cfi: true,
+        },
+    },
+
+}
+
+//###############################################################################
+
+cc_library_shared {
+    name: "libstagefright_soft_amrwbenc",
+
+    srcs: ["SoftAMRWBEncoder.cpp"],
+
+    include_dirs: [
+        "frameworks/av/media/libstagefright/include",
+        "frameworks/native/include/media/openmax",
+    ],
+
+    cflags: ["-Werror"],
+
+    sanitize: {
+        misc_undefined: [
+            "signed-integer-overflow",
+        ],
+        cfi: true,
+        diag: {
+            cfi: true,
+        },
+    },
+
+    static_libs: ["libstagefright_amrwbenc"],
+
+    shared_libs: [
+        "libstagefright_omx",
+        "libstagefright_foundation",
+        "libutils",
+        "liblog",
+        "libstagefright_enc_common",
+    ],
+}
+
+//###############################################################################
+
+subdirs = ["SampleCode"]
diff --git a/media/libstagefright/codecs/amrwbenc/Android.mk b/media/libstagefright/codecs/amrwbenc/Android.mk
deleted file mode 100644
index 262f6c8..0000000
--- a/media/libstagefright/codecs/amrwbenc/Android.mk
+++ /dev/null
@@ -1,138 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
-	src/autocorr.c \
-	src/az_isp.c \
-	src/bits.c \
-	src/c2t64fx.c \
-	src/c4t64fx.c \
-	src/convolve.c \
-	src/cor_h_x.c \
-	src/decim54.c \
-	src/deemph.c \
-	src/dtx.c \
-	src/g_pitch.c \
-	src/gpclip.c \
-	src/homing.c \
-	src/hp400.c \
-	src/hp50.c \
-	src/hp6k.c \
-	src/hp_wsp.c \
-	src/int_lpc.c \
-	src/isp_az.c \
-	src/isp_isf.c \
-	src/lag_wind.c \
-	src/levinson.c \
-	src/log2.c \
-	src/lp_dec2.c \
-	src/math_op.c \
-	src/oper_32b.c \
-	src/p_med_ol.c \
-	src/pit_shrp.c \
-	src/pitch_f4.c \
-	src/pred_lt4.c \
-	src/preemph.c \
-	src/q_gain2.c \
-	src/q_pulse.c \
-	src/qisf_ns.c \
-	src/qpisf_2s.c \
-	src/random.c \
-	src/residu.c \
-	src/scale.c \
-	src/stream.c \
-	src/syn_filt.c \
-	src/updt_tar.c \
-	src/util.c \
-	src/voAMRWBEnc.c \
-	src/voicefac.c \
-	src/wb_vad.c \
-	src/weight_a.c \
-	src/mem_align.c
-
-ifneq ($(ARCH_ARM_HAVE_NEON),true)
-    LOCAL_SRC_FILES_arm := \
-        src/asm/ARMV5E/convolve_opt.s \
-        src/asm/ARMV5E/cor_h_vec_opt.s \
-        src/asm/ARMV5E/Deemph_32_opt.s \
-        src/asm/ARMV5E/Dot_p_opt.s \
-        src/asm/ARMV5E/Filt_6k_7k_opt.s \
-        src/asm/ARMV5E/Norm_Corr_opt.s \
-        src/asm/ARMV5E/pred_lt4_1_opt.s \
-        src/asm/ARMV5E/residu_asm_opt.s \
-        src/asm/ARMV5E/scale_sig_opt.s \
-        src/asm/ARMV5E/Syn_filt_32_opt.s \
-        src/asm/ARMV5E/syn_filt_opt.s
-
-    LOCAL_CFLAGS_arm := -DARM -DASM_OPT
-    LOCAL_C_INCLUDES_arm = $(LOCAL_PATH)/src/asm/ARMV5E
-else
-    LOCAL_SRC_FILES_arm := \
-        src/asm/ARMV7/convolve_neon.s \
-        src/asm/ARMV7/cor_h_vec_neon.s \
-        src/asm/ARMV7/Deemph_32_neon.s \
-        src/asm/ARMV7/Dot_p_neon.s \
-        src/asm/ARMV7/Filt_6k_7k_neon.s \
-        src/asm/ARMV7/Norm_Corr_neon.s \
-        src/asm/ARMV7/pred_lt4_1_neon.s \
-        src/asm/ARMV7/residu_asm_neon.s \
-        src/asm/ARMV7/scale_sig_neon.s \
-        src/asm/ARMV7/Syn_filt_32_neon.s \
-        src/asm/ARMV7/syn_filt_neon.s
-
-    # don't actually generate neon instructions, see bug 26932980
-    LOCAL_CFLAGS_arm := -DARM -DARMV7 -DASM_OPT -mfpu=vfpv3
-    LOCAL_C_INCLUDES_arm := $(LOCAL_PATH)/src/asm/ARMV5E
-    LOCAL_C_INCLUDES_arm += $(LOCAL_PATH)/src/asm/ARMV7
-endif
-
-LOCAL_MODULE := libstagefright_amrwbenc
-
-LOCAL_ARM_MODE := arm
-
-LOCAL_STATIC_LIBRARIES :=
-
-LOCAL_SHARED_LIBRARIES :=
-
-LOCAL_C_INCLUDES := \
-	frameworks/av/include \
-	frameworks/av/media/libstagefright/include \
-	frameworks/av/media/libstagefright/codecs/common/include \
-	$(LOCAL_PATH)/src \
-	$(LOCAL_PATH)/inc
-
-LOCAL_CFLAGS += -Werror
-#LOCAL_SANITIZE := signed-integer-overflow
-
-include $(BUILD_STATIC_LIBRARY)
-
-################################################################################
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
-        SoftAMRWBEncoder.cpp
-
-LOCAL_C_INCLUDES := \
-	frameworks/av/media/libstagefright/include \
-	frameworks/av/media/libstagefright/codecs/common/include \
-	frameworks/native/include/media/openmax
-
-LOCAL_CFLAGS += -Werror
-LOCAL_SANITIZE := signed-integer-overflow cfi
-LOCAL_SANITIZE_DIAG := cfi
-
-LOCAL_STATIC_LIBRARIES := \
-        libstagefright_amrwbenc
-
-LOCAL_SHARED_LIBRARIES := \
-        libstagefright_omx libstagefright_foundation libutils liblog \
-        libstagefright_enc_common
-
-LOCAL_MODULE := libstagefright_soft_amrwbenc
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_SHARED_LIBRARY)
-
-################################################################################
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/media/libstagefright/codecs/amrwbenc/SampleCode/Android.bp b/media/libstagefright/codecs/amrwbenc/SampleCode/Android.bp
new file mode 100644
index 0000000..d52fed3
--- /dev/null
+++ b/media/libstagefright/codecs/amrwbenc/SampleCode/Android.bp
@@ -0,0 +1,28 @@
+cc_test {
+    name: "AMRWBEncTest",
+    gtest: false,
+
+    srcs: ["AMRWB_E_SAMPLE.c"],
+
+    arch: {
+        arm: {
+            instruction_set: "arm",
+        },
+    },
+
+    shared_libs: [
+        "libdl",
+    ],
+
+    static_libs: [
+        "libstagefright_amrwbenc",
+        "libstagefright_enc_common",
+    ],
+
+    sanitize: {
+        cfi: true,
+        diag: {
+            cfi: true,
+        },
+    },
+}
diff --git a/media/libstagefright/codecs/amrwbenc/SampleCode/Android.mk b/media/libstagefright/codecs/amrwbenc/SampleCode/Android.mk
deleted file mode 100644
index 65d69a2..0000000
--- a/media/libstagefright/codecs/amrwbenc/SampleCode/Android.mk
+++ /dev/null
@@ -1,30 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
-    AMRWB_E_SAMPLE.c \
-    ../../common/cmnMemory.c
-
-LOCAL_MODULE_TAGS := tests
-LOCAL_MODULE := AMRWBEncTest
-
-LOCAL_ARM_MODE := arm
-
-LOCAL_CFLAGS :=
-
-LOCAL_SHARED_LIBRARIES := \
-    libstagefright \
-    libdl
-
-LOCAL_STATIC_LIBRARIES := \
-    libstagefright_amrwbenc
-
-LOCAL_C_INCLUDES := \
-    $(LOCAL_PATH)/ \
-    $(LOCAL_PATH)/../../common \
-    $(LOCAL_PATH)/../../common/include
-
-include $(BUILD_EXECUTABLE)
-
-
-
diff --git a/media/libstagefright/codecs/amrwbenc/SoftAMRWBEncoder.cpp b/media/libstagefright/codecs/amrwbenc/SoftAMRWBEncoder.cpp
index f05f552..a644b66 100644
--- a/media/libstagefright/codecs/amrwbenc/SoftAMRWBEncoder.cpp
+++ b/media/libstagefright/codecs/amrwbenc/SoftAMRWBEncoder.cpp
@@ -59,7 +59,7 @@
 
 SoftAMRWBEncoder::~SoftAMRWBEncoder() {
     if (mEncoderHandle != NULL) {
-        CHECK_EQ(VO_ERR_NONE, mApiHandle->Uninit(mEncoderHandle));
+        CHECK_EQ((VO_U32)VO_ERR_NONE, mApiHandle->Uninit(mEncoderHandle));
         mEncoderHandle = NULL;
     }
 
@@ -431,7 +431,7 @@
         inputData.Buffer = (unsigned char *) mInputFrame;
         inputData.Length = mInputSize;
 
-        CHECK_EQ(VO_ERR_NONE,
+        CHECK_EQ((VO_U32)VO_ERR_NONE,
                  mApiHandle->SetInputData(mEncoderHandle, &inputData));
 
         VO_CODECBUFFER outputData;
diff --git a/media/libstagefright/codecs/avcdec/Android.bp b/media/libstagefright/codecs/avcdec/Android.bp
new file mode 100644
index 0000000..6b996a7
--- /dev/null
+++ b/media/libstagefright/codecs/avcdec/Android.bp
@@ -0,0 +1,33 @@
+cc_library_shared {
+    name: "libstagefright_soft_avcdec",
+
+    static_libs: ["libavcdec"],
+    srcs: ["SoftAVCDec.cpp"],
+
+    include_dirs: [
+        "external/libavc/decoder",
+        "external/libavc/common",
+        "frameworks/av/media/libstagefright/include",
+        "frameworks/native/include/media/openmax",
+    ],
+
+    shared_libs: [
+        "libmedia",
+        "libstagefright_omx",
+        "libstagefright_foundation",
+        "libutils",
+        "liblog",
+    ],
+
+    sanitize: {
+        misc_undefined: [
+            "signed-integer-overflow",
+        ],
+        cfi: true,
+        diag: {
+            cfi: true,
+        },
+    },
+
+    ldflags: ["-Wl,-Bsymbolic"],
+}
diff --git a/media/libstagefright/codecs/avcdec/Android.mk b/media/libstagefright/codecs/avcdec/Android.mk
deleted file mode 100644
index 8c894fd..0000000
--- a/media/libstagefright/codecs/avcdec/Android.mk
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifeq ($(if $(wildcard external/libh264),1,0),1)
-
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE            := libstagefright_soft_avcdec
-LOCAL_MODULE_TAGS       := optional
-
-LOCAL_STATIC_LIBRARIES  := libavcdec
-LOCAL_SRC_FILES         := SoftAVCDec.cpp
-
-LOCAL_C_INCLUDES := $(TOP)/external/libavc/decoder
-LOCAL_C_INCLUDES += $(TOP)/external/libavc/common
-LOCAL_C_INCLUDES += $(TOP)/frameworks/av/media/libstagefright/include
-LOCAL_C_INCLUDES += $(TOP)/frameworks/native/include/media/openmax
-
-LOCAL_SHARED_LIBRARIES  := libmedia
-LOCAL_SHARED_LIBRARIES  += libstagefright_omx
-LOCAL_SHARED_LIBRARIES  += libstagefright_foundation
-LOCAL_SHARED_LIBRARIES  += libutils
-LOCAL_SHARED_LIBRARIES  += liblog
-
-LOCAL_SANITIZE := signed-integer-overflow cfi
-
-LOCAL_SANITIZE_DIAG := cfi
-
-LOCAL_LDFLAGS := -Wl,-Bsymbolic
-
-include $(BUILD_SHARED_LIBRARY)
-
-#endif
diff --git a/media/libstagefright/codecs/avcenc/Android.bp b/media/libstagefright/codecs/avcenc/Android.bp
new file mode 100644
index 0000000..49021a9
--- /dev/null
+++ b/media/libstagefright/codecs/avcenc/Android.bp
@@ -0,0 +1,33 @@
+cc_library_shared {
+    name: "libstagefright_soft_avcenc",
+
+    static_libs: ["libavcenc"],
+    srcs: ["SoftAVCEnc.cpp"],
+
+    include_dirs: [
+        "external/libavc/encoder",
+        "external/libavc/common",
+        "frameworks/av/media/libstagefright/include",
+        "frameworks/native/include/media/hardware",
+        "frameworks/native/include/media/openmax",
+    ],
+
+    shared_libs: [
+        "libmedia",
+        "libstagefright_omx",
+        "libutils",
+        "liblog",
+    ],
+
+    sanitize: {
+        misc_undefined: [
+            "signed-integer-overflow",
+        ],
+        cfi: true,
+        diag: {
+            cfi: true,
+        },
+    },
+
+    ldflags: ["-Wl,-Bsymbolic"],
+}
diff --git a/media/libstagefright/codecs/avcenc/Android.mk b/media/libstagefright/codecs/avcenc/Android.mk
deleted file mode 100644
index 23ba208..0000000
--- a/media/libstagefright/codecs/avcenc/Android.mk
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifeq ($(if $(wildcard external/libh264),1,0),1)
-
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE            := libstagefright_soft_avcenc
-LOCAL_MODULE_TAGS       := optional
-
-LOCAL_STATIC_LIBRARIES  := libavcenc
-LOCAL_SRC_FILES         := SoftAVCEnc.cpp
-
-LOCAL_C_INCLUDES := $(TOP)/external/libavc/encoder
-LOCAL_C_INCLUDES += $(TOP)/external/libavc/common
-LOCAL_C_INCLUDES += $(TOP)/frameworks/av/media/libstagefright/include
-LOCAL_C_INCLUDES += $(TOP)/frameworks/native/include/media/hardware
-LOCAL_C_INCLUDES += $(TOP)/frameworks/native/include/media/openmax
-
-LOCAL_SHARED_LIBRARIES  := libmedia
-LOCAL_SHARED_LIBRARIES  += libstagefright_omx
-LOCAL_SHARED_LIBRARIES  += libutils
-LOCAL_SHARED_LIBRARIES  += liblog
-
-LOCAL_SANITIZE := signed-integer-overflow cfi
-
-LOCAL_SANITIZE_DIAG := cfi
-
-LOCAL_LDFLAGS := -Wl,-Bsymbolic
-
-include $(BUILD_SHARED_LIBRARY)
-
-#endif
diff --git a/media/libstagefright/codecs/common/Android.bp b/media/libstagefright/codecs/common/Android.bp
new file mode 100644
index 0000000..021e6af
--- /dev/null
+++ b/media/libstagefright/codecs/common/Android.bp
@@ -0,0 +1,15 @@
+cc_library {
+    name: "libstagefright_enc_common",
+
+    srcs: ["cmnMemory.c"],
+
+    arch: {
+        arm: {
+            instruction_set: "arm",
+        },
+    },
+
+    export_include_dirs: ["include"],
+
+    cflags: ["-Werror"],
+}
diff --git a/media/libstagefright/codecs/common/Android.mk b/media/libstagefright/codecs/common/Android.mk
deleted file mode 100644
index b0010ff..0000000
--- a/media/libstagefright/codecs/common/Android.mk
+++ /dev/null
@@ -1,22 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-
-
-LOCAL_SRC_FILES := cmnMemory.c
-
-LOCAL_MODULE := libstagefright_enc_common
-
-LOCAL_ARM_MODE := arm
-
-LOCAL_STATIC_LIBRARIES :=
-
-LOCAL_C_INCLUDES := \
-	$(LOCAL_PATH)/include
-
-LOCAL_CFLAGS += -Werror
-
-include $(BUILD_SHARED_LIBRARY)
-
-
-
diff --git a/media/libstagefright/codecs/flac/Android.bp b/media/libstagefright/codecs/flac/Android.bp
new file mode 100644
index 0000000..b44c296
--- /dev/null
+++ b/media/libstagefright/codecs/flac/Android.bp
@@ -0,0 +1 @@
+subdirs = ["*"]
diff --git a/media/libstagefright/codecs/flac/Android.mk b/media/libstagefright/codecs/flac/Android.mk
deleted file mode 100644
index 2e43120..0000000
--- a/media/libstagefright/codecs/flac/Android.mk
+++ /dev/null
@@ -1,4 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/media/libstagefright/codecs/flac/dec/Android.bp b/media/libstagefright/codecs/flac/dec/Android.bp
new file mode 100644
index 0000000..6ac264d
--- /dev/null
+++ b/media/libstagefright/codecs/flac/dec/Android.bp
@@ -0,0 +1,36 @@
+cc_library_shared {
+    name: "libstagefright_soft_flacdec",
+
+    srcs: [
+        "SoftFlacDecoder.cpp",
+    ],
+
+    include_dirs: [
+        "external/flac/include",
+        "frameworks/av/media/libstagefright/flac/dec",
+        "frameworks/av/media/libstagefright/include",
+        "frameworks/native/include/media/openmax",
+    ],
+
+    cflags: ["-Werror"],
+
+    sanitize: {
+        misc_undefined: [
+            "signed-integer-overflow",
+            "unsigned-integer-overflow",
+        ],
+        cfi: true,
+        diag: {
+            cfi: true,
+        },
+    },
+
+    shared_libs: [
+        "libcutils",
+        "liblog",
+        "libstagefright_flacdec",
+        "libstagefright_omx",
+        "libstagefright_foundation",
+        "libutils",
+    ],
+}
diff --git a/media/libstagefright/codecs/flac/dec/MODULE_LICENSE_APACHE2 b/media/libstagefright/codecs/flac/dec/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/media/libstagefright/codecs/flac/dec/MODULE_LICENSE_APACHE2
diff --git a/media/libstagefright/codecs/flac/dec/NOTICE b/media/libstagefright/codecs/flac/dec/NOTICE
new file mode 100644
index 0000000..c5b1efa
--- /dev/null
+++ b/media/libstagefright/codecs/flac/dec/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/media/libstagefright/codecs/flac/dec/SoftFlacDecoder.cpp b/media/libstagefright/codecs/flac/dec/SoftFlacDecoder.cpp
new file mode 100644
index 0000000..cff4a33
--- /dev/null
+++ b/media/libstagefright/codecs/flac/dec/SoftFlacDecoder.cpp
@@ -0,0 +1,397 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "SoftFlacDecoder"
+#include <utils/Log.h>
+
+#include "SoftFlacDecoder.h"
+#include <OMX_AudioExt.h>
+#include <OMX_IndexExt.h>
+
+#include <cutils/properties.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/MediaErrors.h>
+#include <utils/misc.h>
+
+namespace android {
+
+template<class T>
+static void InitOMXParams(T *params) {
+    params->nSize = sizeof(T);
+    params->nVersion.s.nVersionMajor = 1;
+    params->nVersion.s.nVersionMinor = 0;
+    params->nVersion.s.nRevision = 0;
+    params->nVersion.s.nStep = 0;
+}
+
+SoftFlacDecoder::SoftFlacDecoder(
+        const char *name,
+        const OMX_CALLBACKTYPE *callbacks,
+        OMX_PTR appData,
+        OMX_COMPONENTTYPE **component)
+    : SimpleSoftOMXComponent(name, callbacks, appData, component),
+      mFLACDecoder(NULL),
+      mHasStreamInfo(false),
+      mInputBufferCount(0),
+      mSignalledError(false),
+      mOutputPortSettingsChange(NONE) {
+    ALOGV("ctor:");
+    memset(&mStreamInfo, 0, sizeof(mStreamInfo));
+    initPorts();
+    initDecoder();
+}
+
+SoftFlacDecoder::~SoftFlacDecoder() {
+    ALOGV("dtor:");
+}
+
+void SoftFlacDecoder::initPorts() {
+    ALOGV("initPorts:");
+    OMX_PARAM_PORTDEFINITIONTYPE def;
+    InitOMXParams(&def);
+
+    def.nPortIndex = 0;
+    def.eDir = OMX_DirInput;
+    def.nBufferCountMin = kNumInputBuffers;
+    def.nBufferCountActual = def.nBufferCountMin;
+    def.nBufferSize = 32768;
+    def.bEnabled = OMX_TRUE;
+    def.bPopulated = OMX_FALSE;
+    def.eDomain = OMX_PortDomainAudio;
+    def.bBuffersContiguous = OMX_FALSE;
+    def.nBufferAlignment = 1;
+
+    def.format.audio.cMIMEType = const_cast<char *>("audio/flac");
+    def.format.audio.pNativeRender = NULL;
+    def.format.audio.bFlagErrorConcealment = OMX_FALSE;
+    def.format.audio.eEncoding = OMX_AUDIO_CodingFLAC;
+
+    addPort(def);
+
+    def.nPortIndex = 1;
+    def.eDir = OMX_DirOutput;
+    def.nBufferCountMin = kNumOutputBuffers;
+    def.nBufferCountActual = def.nBufferCountMin;
+    def.nBufferSize = 4096 * FLACDecoder::kMaxChannels;
+    def.bEnabled = OMX_TRUE;
+    def.bPopulated = OMX_FALSE;
+    def.eDomain = OMX_PortDomainAudio;
+    def.bBuffersContiguous = OMX_FALSE;
+    def.nBufferAlignment = 2;
+
+    def.format.audio.cMIMEType = const_cast<char *>("audio/raw");
+    def.format.audio.pNativeRender = NULL;
+    def.format.audio.bFlagErrorConcealment = OMX_FALSE;
+    def.format.audio.eEncoding = OMX_AUDIO_CodingPCM;
+
+    addPort(def);
+}
+
+void SoftFlacDecoder::initDecoder() {
+    ALOGV("initDecoder:");
+    mFLACDecoder = FLACDecoder::Create();
+    if (mFLACDecoder == NULL) {
+        ALOGE("initDecoder: failed to create FLACDecoder");
+        mSignalledError = true;
+    }
+}
+
+OMX_ERRORTYPE SoftFlacDecoder::initCheck() const {
+    if (mSignalledError) {
+        if (mFLACDecoder == NULL) {
+            ALOGE("initCheck: failed due to NULL encoder");
+            return OMX_ErrorDynamicResourcesUnavailable;
+        }
+        return OMX_ErrorUndefined;
+    }
+
+    return SimpleSoftOMXComponent::initCheck();
+}
+
+OMX_ERRORTYPE SoftFlacDecoder::internalGetParameter(
+        OMX_INDEXTYPE index, OMX_PTR params) {
+    ALOGV("internalGetParameter: index(%x)", index);
+    switch ((OMX_U32)index) {
+        case OMX_IndexParamAudioFlac:
+        {
+            OMX_AUDIO_PARAM_FLACTYPE *flacParams =
+                (OMX_AUDIO_PARAM_FLACTYPE *)params;
+
+            if (!isValidOMXParam(flacParams)) {
+                ALOGE("internalGetParameter(OMX_IndexParamAudioFlac): invalid omx params");
+                return OMX_ErrorBadParameter;
+            }
+
+            if (flacParams->nPortIndex != 0) {
+                ALOGE("internalGetParameter(OMX_IndexParamAudioFlac): bad port index");
+                return OMX_ErrorBadPortIndex;
+            }
+
+            flacParams->nCompressionLevel = 0;
+
+            if (isConfigured()) {
+                flacParams->nChannels = mStreamInfo.channels;
+                flacParams->nSampleRate = mStreamInfo.sample_rate;
+            } else {
+                flacParams->nChannels = 1;
+                flacParams->nSampleRate = 44100;
+            }
+
+            return OMX_ErrorNone;
+        }
+
+        case OMX_IndexParamAudioPcm:
+        {
+            OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams =
+                (OMX_AUDIO_PARAM_PCMMODETYPE *)params;
+
+            if (!isValidOMXParam(pcmParams)) {
+                ALOGE("internalGetParameter(OMX_IndexParamAudioPcm): invalid omx params");
+                return OMX_ErrorBadParameter;
+            }
+
+            if (pcmParams->nPortIndex != 1) {
+                ALOGE("internalGetParameter(OMX_IndexParamAudioPcm): bad port index");
+                return OMX_ErrorBadPortIndex;
+            }
+
+            pcmParams->eNumData = OMX_NumericalDataSigned;
+            pcmParams->eEndian = OMX_EndianBig;
+            pcmParams->bInterleaved = OMX_TRUE;
+            pcmParams->nBitPerSample = 16;
+            pcmParams->ePCMMode = OMX_AUDIO_PCMModeLinear;
+            pcmParams->eChannelMapping[0] = OMX_AUDIO_ChannelLF;
+            pcmParams->eChannelMapping[1] = OMX_AUDIO_ChannelRF;
+            pcmParams->eChannelMapping[2] = OMX_AUDIO_ChannelCF;
+            pcmParams->eChannelMapping[3] = OMX_AUDIO_ChannelLFE;
+            pcmParams->eChannelMapping[4] = OMX_AUDIO_ChannelLS;
+            pcmParams->eChannelMapping[5] = OMX_AUDIO_ChannelRS;
+
+            if (isConfigured()) {
+                pcmParams->nChannels = mStreamInfo.channels;
+                pcmParams->nSamplingRate = mStreamInfo.sample_rate;
+            } else {
+                pcmParams->nChannels = 1;
+                pcmParams->nSamplingRate = 44100;
+            }
+
+            return OMX_ErrorNone;
+        }
+
+        default:
+            return SimpleSoftOMXComponent::internalGetParameter(index, params);
+    }
+}
+
+OMX_ERRORTYPE SoftFlacDecoder::internalSetParameter(
+        OMX_INDEXTYPE index, const OMX_PTR params) {
+    ALOGV("internalSetParameter: index(%x)", (int)index);
+    switch ((int)index) {
+        case OMX_IndexParamStandardComponentRole:
+        {
+            const OMX_PARAM_COMPONENTROLETYPE *roleParams =
+                (const OMX_PARAM_COMPONENTROLETYPE *)params;
+
+            if (!isValidOMXParam(roleParams)) {
+                return OMX_ErrorBadParameter;
+            }
+
+            if (strncmp((const char *)roleParams->cRole,
+                        "audio_decoder.flac",
+                        OMX_MAX_STRINGNAME_SIZE - 1) != 0) {
+                return OMX_ErrorInvalidComponentName;
+            }
+
+            return OMX_ErrorNone;
+        }
+
+        case OMX_IndexParamAudioPcm:
+        {
+            const OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams =
+                (OMX_AUDIO_PARAM_PCMMODETYPE *)params;
+
+            if (!isValidOMXParam(pcmParams)) {
+                return OMX_ErrorBadParameter;
+            }
+
+            if (pcmParams->nPortIndex != 1) {
+                return OMX_ErrorBadPortIndex;
+            }
+
+            return OMX_ErrorNone;
+        }
+
+        default:
+            return SimpleSoftOMXComponent::internalSetParameter(index, params);
+    }
+}
+
+bool SoftFlacDecoder::isConfigured() const {
+    return mHasStreamInfo;
+}
+
+void SoftFlacDecoder::onQueueFilled(OMX_U32 /* portIndex */) {
+    ALOGV("onQueueFilled:");
+    if (mSignalledError || mOutputPortSettingsChange != NONE) {
+        return;
+    }
+
+    List<BufferInfo *> &inQueue = getPortQueue(0);
+    List<BufferInfo *> &outQueue = getPortQueue(1);
+
+    while (!inQueue.empty() && !outQueue.empty()) {
+        BufferInfo *inInfo = *inQueue.begin();
+        OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
+        uint8_t* inBuffer = inHeader->pBuffer + inHeader->nOffset;
+        uint32_t inBufferLength = inHeader->nFilledLen;
+        bool endOfInput = (inHeader->nFlags & OMX_BUFFERFLAG_EOS) != 0;
+
+        if (mInputBufferCount == 0 && !(inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG)) {
+            ALOGE("onQueueFilled: first buffer should have OMX_BUFFERFLAG_CODECCONFIG set");
+            inHeader->nFlags |= OMX_BUFFERFLAG_CODECCONFIG;
+        }
+        if ((inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG) != 0) {
+            status_t decoderErr = mFLACDecoder->parseMetadata(inBuffer, inBufferLength);
+            mInputBufferCount++;
+
+            if (decoderErr != OK && decoderErr != WOULD_BLOCK) {
+                ALOGE("onQueueFilled: FLACDecoder parseMetaData returns error %d", decoderErr);
+                mSignalledError = true;
+                notify(OMX_EventError, OMX_ErrorStreamCorrupt, decoderErr, NULL);
+                return;
+            }
+
+            inInfo->mOwnedByUs = false;
+            inQueue.erase(inQueue.begin());
+            notifyEmptyBufferDone(inHeader);
+
+            if (decoderErr == WOULD_BLOCK) {
+                continue;
+            }
+            mStreamInfo = mFLACDecoder->getStreamInfo();
+            mHasStreamInfo = true;
+
+            // Only send out port settings changed event if both sample rate
+            // and numChannels are valid.
+            if (mStreamInfo.sample_rate && mStreamInfo.channels) {
+                ALOGD("onQueueFilled: initially configuring decoder: %d Hz, %d channels",
+                    mStreamInfo.sample_rate, mStreamInfo.channels);
+
+                notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
+                mOutputPortSettingsChange = AWAITING_DISABLED;
+            }
+            return;
+        }
+
+        BufferInfo *outInfo = *outQueue.begin();
+        OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
+        short *outBuffer =
+                reinterpret_cast<short *>(outHeader->pBuffer + outHeader->nOffset);
+        size_t outBufferSize = outHeader->nAllocLen - outHeader->nOffset;
+
+        status_t decoderErr = mFLACDecoder->decodeOneFrame(
+                inBuffer, inBufferLength, outBuffer, &outBufferSize);
+        if (decoderErr != OK) {
+            ALOGE("onQueueFilled: FLACDecoder decodeOneFrame returns error %d", decoderErr);
+            mSignalledError = true;
+            notify(OMX_EventError, OMX_ErrorStreamCorrupt, decoderErr, NULL);
+            return;
+        }
+
+        mInputBufferCount++;
+        int64_t ts = inHeader->nTimeStamp;
+        inInfo->mOwnedByUs = false;
+        inQueue.erase(inQueue.begin());
+        notifyEmptyBufferDone(inHeader);
+
+        if (endOfInput) {
+            outHeader->nFlags = OMX_BUFFERFLAG_EOS;
+        } else if (outBufferSize == 0) {
+            continue;
+        } else {
+            outHeader->nFlags = 0;
+        }
+
+        outHeader->nFilledLen = outBufferSize;
+        outHeader->nTimeStamp = ts;
+
+        outInfo->mOwnedByUs = false;
+        outQueue.erase(outQueue.begin());
+        notifyFillBufferDone(outHeader);
+    }
+}
+
+void SoftFlacDecoder::onPortFlushCompleted(OMX_U32 portIndex) {
+    ALOGV("onPortFlushCompleted: portIndex(%u)", portIndex);
+    if (portIndex == 0) {
+        drainDecoder();
+    }
+}
+
+void SoftFlacDecoder::drainDecoder() {
+    mFLACDecoder->flush();
+}
+
+void SoftFlacDecoder::onReset() {
+    drainDecoder();
+
+    memset(&mStreamInfo, 0, sizeof(mStreamInfo));
+    mHasStreamInfo = false;
+    mInputBufferCount = 0;
+    mSignalledError = false;
+    mOutputPortSettingsChange = NONE;
+}
+
+void SoftFlacDecoder::onPortEnableCompleted(OMX_U32 portIndex, bool enabled) {
+    ALOGV("onPortEnableCompleted: portIndex(%u), enabled(%d)", portIndex, enabled);
+    if (portIndex != 1) {
+        return;
+    }
+
+    switch (mOutputPortSettingsChange) {
+        case NONE:
+            break;
+
+        case AWAITING_DISABLED:
+        {
+            CHECK(!enabled);
+            mOutputPortSettingsChange = AWAITING_ENABLED;
+            PortInfo *info = editPortInfo(1 /* portIndex */);
+            if (!info->mDef.bEnabled) {
+                info->mDef.nBufferSize = mStreamInfo.max_blocksize * mStreamInfo.channels * 2;
+            }
+            break;
+        }
+
+        default:
+        {
+            CHECK_EQ((int)mOutputPortSettingsChange, (int)AWAITING_ENABLED);
+            CHECK(enabled);
+            mOutputPortSettingsChange = NONE;
+            break;
+        }
+    }
+}
+
+}  // namespace android
+
+android::SoftOMXComponent *createSoftOMXComponent(
+        const char *name, const OMX_CALLBACKTYPE *callbacks,
+        OMX_PTR appData, OMX_COMPONENTTYPE **component) {
+    ALOGV("createSoftOMXComponent: flac decoder");
+    return new android::SoftFlacDecoder(name, callbacks, appData, component);
+}
diff --git a/media/libstagefright/codecs/flac/dec/SoftFlacDecoder.h b/media/libstagefright/codecs/flac/dec/SoftFlacDecoder.h
new file mode 100644
index 0000000..c09081d
--- /dev/null
+++ b/media/libstagefright/codecs/flac/dec/SoftFlacDecoder.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SOFT_FLAC_DECODER_H
+#define SOFT_FLAC_DECODER_H
+
+#include "FLACDecoder.h"
+#include "SimpleSoftOMXComponent.h"
+
+namespace android {
+
+struct SoftFlacDecoder : public SimpleSoftOMXComponent {
+    SoftFlacDecoder(const char *name,
+            const OMX_CALLBACKTYPE *callbacks,
+            OMX_PTR appData,
+            OMX_COMPONENTTYPE **component);
+
+    virtual OMX_ERRORTYPE initCheck() const override;
+
+protected:
+    virtual ~SoftFlacDecoder();
+
+    virtual OMX_ERRORTYPE internalGetParameter(
+            OMX_INDEXTYPE index, OMX_PTR params) override;
+
+    virtual OMX_ERRORTYPE internalSetParameter(
+            OMX_INDEXTYPE index, const OMX_PTR params) override;
+
+    virtual void onQueueFilled(OMX_U32 portIndex);
+    virtual void onPortFlushCompleted(OMX_U32 portIndex) override;
+    virtual void onPortEnableCompleted(OMX_U32 portIndex, bool enabled) override;
+    virtual void onReset() override;
+
+private:
+    enum {
+        kNumInputBuffers   = 4,
+        kNumOutputBuffers  = 4,
+    };
+
+    sp<FLACDecoder> mFLACDecoder;
+    FLAC__StreamMetadata_StreamInfo mStreamInfo;
+    bool mHasStreamInfo;
+    size_t mInputBufferCount;
+    bool mSignalledError;
+
+    enum {
+        NONE,
+        AWAITING_DISABLED,
+        AWAITING_ENABLED
+    } mOutputPortSettingsChange;
+
+    void initPorts();
+    void initDecoder();
+    bool isConfigured() const;
+    void drainDecoder();
+
+    DISALLOW_EVIL_CONSTRUCTORS(SoftFlacDecoder);
+};
+
+}  // namespace android
+
+#endif  // SOFT_FLAC_DECODER_H
diff --git a/media/libstagefright/codecs/flac/enc/Android.bp b/media/libstagefright/codecs/flac/enc/Android.bp
new file mode 100644
index 0000000..d1413f6
--- /dev/null
+++ b/media/libstagefright/codecs/flac/enc/Android.bp
@@ -0,0 +1,36 @@
+cc_library_shared {
+
+    srcs: ["SoftFlacEncoder.cpp"],
+
+    include_dirs: [
+        "frameworks/av/media/libstagefright/include",
+        "frameworks/native/include/media/openmax",
+        "external/flac/include",
+    ],
+
+    cflags: ["-Werror"],
+
+    sanitize: {
+        misc_undefined: [
+            "signed-integer-overflow",
+            "unsigned-integer-overflow",
+        ],
+        cfi: true,
+        diag: {
+            cfi: true,
+        },
+    },
+
+    shared_libs: [
+        "libmedia",
+        "libstagefright_omx",
+        "libstagefright_foundation",
+        "libutils",
+        "liblog",
+    ],
+
+    static_libs: ["libFLAC"],
+
+    name: "libstagefright_soft_flacenc",
+
+}
diff --git a/media/libstagefright/codecs/flac/enc/Android.mk b/media/libstagefright/codecs/flac/enc/Android.mk
deleted file mode 100644
index 8031bf6..0000000
--- a/media/libstagefright/codecs/flac/enc/Android.mk
+++ /dev/null
@@ -1,25 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
-        SoftFlacEncoder.cpp
-
-LOCAL_C_INCLUDES := \
-        frameworks/av/media/libstagefright/include \
-        frameworks/native/include/media/openmax \
-        external/flac/include
-
-LOCAL_CFLAGS += -Werror
-LOCAL_SANITIZE := signed-integer-overflow unsigned-integer-overflow cfi
-LOCAL_SANITIZE_DIAG := cfi
-
-LOCAL_SHARED_LIBRARIES := \
-        libmedia libstagefright_omx libstagefright_foundation libutils liblog
-
-LOCAL_STATIC_LIBRARIES := \
-        libFLAC \
-
-LOCAL_MODULE := libstagefright_soft_flacenc
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.h b/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.h
index 97361fa..6027f76 100644
--- a/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.h
+++ b/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.h
@@ -48,13 +48,10 @@
     virtual void onQueueFilled(OMX_U32 portIndex);
 
 private:
-
-    enum {
-        kNumBuffers = 2,
-        kMaxNumSamplesPerFrame = 1152,
-        kMaxInputBufferSize = kMaxNumSamplesPerFrame * sizeof(int16_t) * 2,
-        kMaxOutputBufferSize = 65536,    //TODO check if this can be reduced
-    };
+    const unsigned int kNumBuffers = 2;
+    const unsigned int kMaxNumSamplesPerFrame = 1152;
+    const unsigned int kMaxInputBufferSize = kMaxNumSamplesPerFrame * sizeof(int16_t) * 2;
+    const unsigned int kMaxOutputBufferSize = 65536;    //TODO check if this can be reduced
 
     bool mSignalledError;
 
diff --git a/media/libstagefright/codecs/g711/Android.bp b/media/libstagefright/codecs/g711/Android.bp
new file mode 100644
index 0000000..b44c296
--- /dev/null
+++ b/media/libstagefright/codecs/g711/Android.bp
@@ -0,0 +1 @@
+subdirs = ["*"]
diff --git a/media/libstagefright/codecs/g711/Android.mk b/media/libstagefright/codecs/g711/Android.mk
deleted file mode 100644
index 2e43120..0000000
--- a/media/libstagefright/codecs/g711/Android.mk
+++ /dev/null
@@ -1,4 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/media/libstagefright/codecs/g711/dec/Android.bp b/media/libstagefright/codecs/g711/dec/Android.bp
new file mode 100644
index 0000000..b78b689
--- /dev/null
+++ b/media/libstagefright/codecs/g711/dec/Android.bp
@@ -0,0 +1,30 @@
+cc_library_shared {
+    name: "libstagefright_soft_g711dec",
+
+    srcs: ["SoftG711.cpp"],
+
+    include_dirs: [
+        "frameworks/av/media/libstagefright/include",
+        "frameworks/native/include/media/openmax",
+    ],
+
+    shared_libs: [
+        "libmedia",
+        "libstagefright_omx",
+        "libutils",
+        "liblog",
+    ],
+
+    cflags: ["-Werror"],
+
+    sanitize: {
+        misc_undefined: [
+            "signed-integer-overflow",
+            "unsigned-integer-overflow",
+        ],
+        cfi: true,
+        diag: {
+            cfi: true,
+        },
+    },
+}
diff --git a/media/libstagefright/codecs/g711/dec/Android.mk b/media/libstagefright/codecs/g711/dec/Android.mk
deleted file mode 100644
index b9a1f8c..0000000
--- a/media/libstagefright/codecs/g711/dec/Android.mk
+++ /dev/null
@@ -1,21 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
-        SoftG711.cpp
-
-LOCAL_C_INCLUDES := \
-        frameworks/av/media/libstagefright/include \
-        frameworks/native/include/media/openmax
-
-LOCAL_SHARED_LIBRARIES := \
-        libmedia libstagefright_omx libutils liblog
-
-LOCAL_MODULE := libstagefright_soft_g711dec
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_CFLAGS += -Werror
-LOCAL_SANITIZE := signed-integer-overflow unsigned-integer-overflow cfi
-LOCAL_SANITIZE_DIAG := cfi
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/codecs/gsm/Android.bp b/media/libstagefright/codecs/gsm/Android.bp
new file mode 100644
index 0000000..b44c296
--- /dev/null
+++ b/media/libstagefright/codecs/gsm/Android.bp
@@ -0,0 +1 @@
+subdirs = ["*"]
diff --git a/media/libstagefright/codecs/gsm/Android.mk b/media/libstagefright/codecs/gsm/Android.mk
deleted file mode 100644
index 2e43120..0000000
--- a/media/libstagefright/codecs/gsm/Android.mk
+++ /dev/null
@@ -1,4 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/media/libstagefright/codecs/gsm/dec/Android.bp b/media/libstagefright/codecs/gsm/dec/Android.bp
new file mode 100644
index 0000000..8e86ad6
--- /dev/null
+++ b/media/libstagefright/codecs/gsm/dec/Android.bp
@@ -0,0 +1,33 @@
+cc_library_shared {
+    name: "libstagefright_soft_gsmdec",
+
+    srcs: ["SoftGSM.cpp"],
+
+    include_dirs: [
+        "frameworks/av/media/libstagefright/include",
+        "frameworks/native/include/media/openmax",
+        "external/libgsm/inc",
+    ],
+
+    cflags: ["-Werror"],
+
+    sanitize: {
+        misc_undefined: [
+            "signed-integer-overflow",
+            "unsigned-integer-overflow",
+        ],
+        cfi: true,
+        diag: {
+            cfi: true,
+        },
+    },
+
+    shared_libs: [
+        "libmedia",
+        "libstagefright_omx",
+        "libutils",
+        "liblog",
+    ],
+
+    static_libs: ["libgsm"],
+}
diff --git a/media/libstagefright/codecs/gsm/dec/Android.mk b/media/libstagefright/codecs/gsm/dec/Android.mk
deleted file mode 100644
index 401b56c..0000000
--- a/media/libstagefright/codecs/gsm/dec/Android.mk
+++ /dev/null
@@ -1,25 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
-        SoftGSM.cpp
-
-LOCAL_C_INCLUDES := \
-        frameworks/av/media/libstagefright/include \
-        frameworks/native/include/media/openmax \
-        external/libgsm/inc
-
-LOCAL_CFLAGS += -Werror
-LOCAL_SANITIZE := signed-integer-overflow unsigned-integer-overflow cfi
-LOCAL_SANITIZE_DIAG := cfi
-
-LOCAL_SHARED_LIBRARIES := \
-        libmedia libstagefright_omx libutils liblog
-
-LOCAL_STATIC_LIBRARIES := \
-        libgsm
-
-LOCAL_MODULE := libstagefright_soft_gsmdec
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/codecs/hevcdec/Android.bp b/media/libstagefright/codecs/hevcdec/Android.bp
new file mode 100644
index 0000000..cd75c97
--- /dev/null
+++ b/media/libstagefright/codecs/hevcdec/Android.bp
@@ -0,0 +1,36 @@
+cc_library_shared {
+    name: "libstagefright_soft_hevcdec",
+
+    static_libs: ["libhevcdec"],
+    srcs: ["SoftHEVC.cpp"],
+
+    include_dirs: [
+        "external/libhevc/decoder",
+        "external/libhevc/common",
+        "frameworks/av/media/libstagefright/include",
+        "frameworks/native/include/media/openmax",
+    ],
+
+    sanitize: {
+        misc_undefined: [
+            "signed-integer-overflow",
+        ],
+        cfi: true,
+        diag: {
+            cfi: true,
+        },
+    },
+
+    shared_libs: [
+        "libmedia",
+        "libstagefright_omx",
+        "libstagefright_foundation",
+        "libutils",
+        "liblog",
+    ],
+
+    // We need this because the current asm generates the following link error:
+    // requires unsupported dynamic reloc R_ARM_REL32; recompile with -fPIC
+    // Bug: 16853291
+    ldflags: ["-Wl,-Bsymbolic"],
+}
diff --git a/media/libstagefright/codecs/hevcdec/Android.mk b/media/libstagefright/codecs/hevcdec/Android.mk
deleted file mode 100644
index 11c1b89..0000000
--- a/media/libstagefright/codecs/hevcdec/Android.mk
+++ /dev/null
@@ -1,32 +0,0 @@
-ifeq ($(if $(wildcard external/libhevc),1,0),1)
-
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE            := libstagefright_soft_hevcdec
-LOCAL_MODULE_TAGS       := optional
-
-LOCAL_STATIC_LIBRARIES  := libhevcdec
-LOCAL_SRC_FILES         := SoftHEVC.cpp
-
-LOCAL_C_INCLUDES := $(TOP)/external/libhevc/decoder
-LOCAL_C_INCLUDES += $(TOP)/external/libhevc/common
-LOCAL_C_INCLUDES += $(TOP)/frameworks/av/media/libstagefright/include
-LOCAL_C_INCLUDES += $(TOP)/frameworks/native/include/media/openmax
-LOCAL_SANITIZE := signed-integer-overflow cfi
-LOCAL_SANITIZE_DIAG := cfi
-
-LOCAL_SHARED_LIBRARIES  := libmedia
-LOCAL_SHARED_LIBRARIES  += libstagefright_omx
-LOCAL_SHARED_LIBRARIES  += libstagefright_foundation
-LOCAL_SHARED_LIBRARIES  += libutils
-LOCAL_SHARED_LIBRARIES  += liblog
-
-# We need this because the current asm generates the following link error:
-# requires unsupported dynamic reloc R_ARM_REL32; recompile with -fPIC
-# Bug: 16853291
-LOCAL_LDFLAGS := -Wl,-Bsymbolic
-
-include $(BUILD_SHARED_LIBRARY)
-
-endif
diff --git a/media/libstagefright/codecs/m4v_h263/Android.bp b/media/libstagefright/codecs/m4v_h263/Android.bp
new file mode 100644
index 0000000..b44c296
--- /dev/null
+++ b/media/libstagefright/codecs/m4v_h263/Android.bp
@@ -0,0 +1 @@
+subdirs = ["*"]
diff --git a/media/libstagefright/codecs/m4v_h263/Android.mk b/media/libstagefright/codecs/m4v_h263/Android.mk
deleted file mode 100644
index 2e43120..0000000
--- a/media/libstagefright/codecs/m4v_h263/Android.mk
+++ /dev/null
@@ -1,4 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/media/libstagefright/codecs/m4v_h263/dec/Android.bp b/media/libstagefright/codecs/m4v_h263/dec/Android.bp
new file mode 100644
index 0000000..04ea075
--- /dev/null
+++ b/media/libstagefright/codecs/m4v_h263/dec/Android.bp
@@ -0,0 +1,106 @@
+cc_library_static {
+    name: "libstagefright_m4vh263dec",
+
+    srcs: [
+        "src/adaptive_smooth_no_mmx.cpp",
+        "src/bitstream.cpp",
+        "src/block_idct.cpp",
+        "src/cal_dc_scaler.cpp",
+        "src/chvr_filter.cpp",
+        "src/chv_filter.cpp",
+        "src/combined_decode.cpp",
+        "src/conceal.cpp",
+        "src/datapart_decode.cpp",
+        "src/dcac_prediction.cpp",
+        "src/dec_pred_intra_dc.cpp",
+        "src/deringing_chroma.cpp",
+        "src/deringing_luma.cpp",
+        "src/find_min_max.cpp",
+        "src/get_pred_adv_b_add.cpp",
+        "src/get_pred_outside.cpp",
+        "src/idct.cpp",
+        "src/idct_vca.cpp",
+        "src/mb_motion_comp.cpp",
+        "src/mb_utils.cpp",
+        "src/packet_util.cpp",
+        "src/post_filter.cpp",
+        "src/post_proc_semaphore.cpp",
+        "src/pp_semaphore_chroma_inter.cpp",
+        "src/pp_semaphore_luma.cpp",
+        "src/pvdec_api.cpp",
+        "src/scaling_tab.cpp",
+        "src/vlc_decode.cpp",
+        "src/vlc_dequant.cpp",
+        "src/vlc_tab.cpp",
+        "src/vop.cpp",
+        "src/zigzag_tab.cpp",
+    ],
+
+    include_dirs: [
+        "frameworks/av/media/libstagefright/include",
+        "frameworks/native/include/media/openmax",
+    ],
+
+    local_include_dirs: ["src"],
+    export_include_dirs: ["include"],
+
+    cflags: [
+        "-DOSCL_EXPORT_REF=",
+        "-DOSCL_IMPORT_REF=",
+
+        "-Werror",
+    ],
+
+    sanitize: {
+        misc_undefined: [
+            "signed-integer-overflow",
+        ],
+        cfi: true,
+        diag: {
+            cfi: true,
+        },
+    },
+}
+
+//###############################################################################
+
+cc_library_shared {
+    name: "libstagefright_soft_mpeg4dec",
+
+    srcs: ["SoftMPEG4.cpp"],
+
+    include_dirs: [
+        "frameworks/av/media/libstagefright/include",
+        "frameworks/native/include/media/openmax",
+    ],
+
+    local_include_dirs: ["src"],
+    export_include_dirs: ["include"],
+
+    cflags: [
+        "-DOSCL_EXPORT_REF=",
+        "-DOSCL_IMPORT_REF=",
+
+        "-Werror",
+    ],
+
+    static_libs: ["libstagefright_m4vh263dec"],
+
+    shared_libs: [
+        "libmedia",
+        "libstagefright_omx",
+        "libstagefright_foundation",
+        "libutils",
+        "liblog",
+    ],
+
+    sanitize: {
+        misc_undefined: [
+            "signed-integer-overflow",
+        ],
+        cfi: true,
+        diag: {
+            cfi: true,
+        },
+    },
+}
diff --git a/media/libstagefright/codecs/m4v_h263/dec/Android.mk b/media/libstagefright/codecs/m4v_h263/dec/Android.mk
deleted file mode 100644
index c20dc4d..0000000
--- a/media/libstagefright/codecs/m4v_h263/dec/Android.mk
+++ /dev/null
@@ -1,82 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
- 	src/adaptive_smooth_no_mmx.cpp \
- 	src/bitstream.cpp \
- 	src/block_idct.cpp \
- 	src/cal_dc_scaler.cpp \
- 	src/chvr_filter.cpp \
- 	src/chv_filter.cpp \
- 	src/combined_decode.cpp \
- 	src/conceal.cpp \
- 	src/datapart_decode.cpp \
- 	src/dcac_prediction.cpp \
- 	src/dec_pred_intra_dc.cpp \
- 	src/deringing_chroma.cpp \
- 	src/deringing_luma.cpp \
- 	src/find_min_max.cpp \
- 	src/get_pred_adv_b_add.cpp \
- 	src/get_pred_outside.cpp \
- 	src/idct.cpp \
- 	src/idct_vca.cpp \
- 	src/mb_motion_comp.cpp \
- 	src/mb_utils.cpp \
- 	src/packet_util.cpp \
- 	src/post_filter.cpp \
- 	src/post_proc_semaphore.cpp \
- 	src/pp_semaphore_chroma_inter.cpp \
- 	src/pp_semaphore_luma.cpp \
- 	src/pvdec_api.cpp \
- 	src/scaling_tab.cpp \
- 	src/vlc_decode.cpp \
- 	src/vlc_dequant.cpp \
- 	src/vlc_tab.cpp \
- 	src/vop.cpp \
- 	src/zigzag_tab.cpp
-
-
-LOCAL_MODULE := libstagefright_m4vh263dec
-
-LOCAL_C_INCLUDES := \
-	$(LOCAL_PATH)/src \
-	$(LOCAL_PATH)/include \
-	$(TOP)/frameworks/av/media/libstagefright/include \
-	$(TOP)/frameworks/native/include/media/openmax
-
-LOCAL_CFLAGS := -DOSCL_EXPORT_REF= -DOSCL_IMPORT_REF=
-
-LOCAL_CFLAGS += -Werror
-LOCAL_SANITIZE := signed-integer-overflow
-
-include $(BUILD_STATIC_LIBRARY)
-
-################################################################################
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
-        SoftMPEG4.cpp
-
-LOCAL_C_INCLUDES := \
-	$(LOCAL_PATH)/src \
-	$(LOCAL_PATH)/include \
-        frameworks/av/media/libstagefright/include \
-        frameworks/native/include/media/openmax
-
-LOCAL_CFLAGS := -DOSCL_EXPORT_REF= -DOSCL_IMPORT_REF=
-
-LOCAL_STATIC_LIBRARIES := \
-        libstagefright_m4vh263dec
-
-LOCAL_SHARED_LIBRARIES := \
-        libmedia libstagefright_omx libstagefright_foundation libutils liblog
-
-LOCAL_MODULE := libstagefright_soft_mpeg4dec
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_CFLAGS += -Werror
-LOCAL_SANITIZE := signed-integer-overflow cfi
-LOCAL_SANITIZE_DIAG := cfi
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/codecs/m4v_h263/enc/Android.bp b/media/libstagefright/codecs/m4v_h263/enc/Android.bp
new file mode 100644
index 0000000..da5b162
--- /dev/null
+++ b/media/libstagefright/codecs/m4v_h263/enc/Android.bp
@@ -0,0 +1,122 @@
+cc_library_static {
+    name: "libstagefright_m4vh263enc",
+
+    srcs: [
+        "src/bitstream_io.cpp",
+        "src/combined_encode.cpp",
+        "src/datapart_encode.cpp",
+        "src/dct.cpp",
+        "src/findhalfpel.cpp",
+        "src/fastcodemb.cpp",
+        "src/fastidct.cpp",
+        "src/fastquant.cpp",
+        "src/me_utils.cpp",
+        "src/mp4enc_api.cpp",
+        "src/rate_control.cpp",
+        "src/motion_est.cpp",
+        "src/motion_comp.cpp",
+        "src/sad.cpp",
+        "src/sad_halfpel.cpp",
+        "src/vlc_encode.cpp",
+        "src/vop.cpp",
+    ],
+
+    cflags: [
+        "-DBX_RC",
+        "-DOSCL_IMPORT_REF=",
+        "-DOSCL_UNUSED_ARG(x)=(void)(x)",
+        "-DOSCL_EXPORT_REF=",
+
+        "-Werror",
+    ],
+
+    include_dirs: [
+        "frameworks/av/media/libstagefright/include",
+        "frameworks/native/include/media/openmax",
+    ],
+    local_include_dirs: ["src"],
+    export_include_dirs: ["include"],
+
+    sanitize: {
+        misc_undefined: [
+            "signed-integer-overflow",
+        ],
+        cfi: true,
+        diag: {
+            cfi: true,
+        },
+    },
+}
+
+//###############################################################################
+
+cc_library_shared {
+    name: "libstagefright_soft_mpeg4enc",
+
+    srcs: ["SoftMPEG4Encoder.cpp"],
+
+    include_dirs: [
+        "frameworks/av/media/libstagefright/include",
+        "frameworks/native/include/media/openmax",
+        "frameworks/native/include/media/hardware",
+    ],
+    local_include_dirs: ["src"],
+    export_include_dirs: ["include"],
+
+    cflags: [
+        "-DBX_RC",
+        "-DOSCL_IMPORT_REF=",
+        "-DOSCL_UNUSED_ARG(x)=(void)(x)",
+        "-DOSCL_EXPORT_REF=",
+
+        "-Werror",
+    ],
+
+    static_libs: ["libstagefright_m4vh263enc"],
+
+    shared_libs: [
+        "libmedia",
+        "libstagefright_omx",
+        "libutils",
+        "liblog",
+    ],
+
+    sanitize: {
+        misc_undefined: [
+            "signed-integer-overflow",
+        ],
+        cfi: true,
+        diag: {
+            cfi: true,
+        },
+    },
+}
+
+//###############################################################################
+
+cc_test {
+    name: "libstagefright_m4vh263enc_test",
+    gtest: false,
+
+    srcs: ["test/m4v_h263_enc_test.cpp"],
+
+    local_include_dirs: ["src"],
+
+    cflags: [
+        "-DOSCL_EXPORT_REF=",
+        "-DOSCL_IMPORT_REF=",
+        "-DBX_RC",
+    ],
+
+    sanitize: {
+        misc_undefined: [
+            "signed-integer-overflow",
+        ],
+        cfi: true,
+        diag: {
+            cfi: true,
+        },
+    },
+
+    static_libs: ["libstagefright_m4vh263enc"],
+}
diff --git a/media/libstagefright/codecs/m4v_h263/enc/Android.mk b/media/libstagefright/codecs/m4v_h263/enc/Android.mk
deleted file mode 100644
index f950052..0000000
--- a/media/libstagefright/codecs/m4v_h263/enc/Android.mk
+++ /dev/null
@@ -1,99 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
-    src/bitstream_io.cpp \
-    src/combined_encode.cpp \
-    src/datapart_encode.cpp \
-    src/dct.cpp \
-    src/findhalfpel.cpp \
-    src/fastcodemb.cpp \
-    src/fastidct.cpp \
-    src/fastquant.cpp \
-    src/me_utils.cpp \
-    src/mp4enc_api.cpp \
-    src/rate_control.cpp \
-    src/motion_est.cpp \
-    src/motion_comp.cpp \
-    src/sad.cpp \
-    src/sad_halfpel.cpp \
-    src/vlc_encode.cpp \
-    src/vop.cpp
-
-
-LOCAL_MODULE := libstagefright_m4vh263enc
-
-LOCAL_CFLAGS := \
-    -DBX_RC \
-    -DOSCL_IMPORT_REF= -D"OSCL_UNUSED_ARG(x)=(void)(x)" -DOSCL_EXPORT_REF=
-
-LOCAL_C_INCLUDES := \
-    $(LOCAL_PATH)/src \
-    $(LOCAL_PATH)/include \
-    $(TOP)/frameworks/av/media/libstagefright/include \
-    $(TOP)/frameworks/native/include/media/openmax
-
-LOCAL_CFLAGS += -Werror
-LOCAL_SANITIZE := signed-integer-overflow
-
-include $(BUILD_STATIC_LIBRARY)
-
-################################################################################
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
-        SoftMPEG4Encoder.cpp
-
-LOCAL_C_INCLUDES := \
-        frameworks/av/media/libstagefright/include \
-        frameworks/native/include/media/openmax \
-        frameworks/native/include/media/hardware \
-        $(LOCAL_PATH)/src \
-        $(LOCAL_PATH)/include \
-        $(LOCAL_PATH)/../common/include \
-        $(LOCAL_PATH)/../common
-
-LOCAL_CFLAGS := \
-    -DBX_RC \
-    -DOSCL_IMPORT_REF= -D"OSCL_UNUSED_ARG(x)=(void)(x)" -DOSCL_EXPORT_REF=
-
-
-LOCAL_STATIC_LIBRARIES := \
-        libstagefright_m4vh263enc
-
-LOCAL_SHARED_LIBRARIES := \
-        libmedia \
-        libstagefright_omx \
-        libutils \
-        liblog \
-
-LOCAL_MODULE := libstagefright_soft_mpeg4enc
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_CFLAGS += -Werror
-LOCAL_SANITIZE := signed-integer-overflow cfi
-LOCAL_SANITIZE_DIAG := cfi
-
-include $(BUILD_SHARED_LIBRARY)
-
-################################################################################
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := \
-        test/m4v_h263_enc_test.cpp
-
-LOCAL_C_INCLUDES := \
-        $(LOCAL_PATH)/src \
-        $(LOCAL_PATH)/include
-
-LOCAL_CFLAGS := -DOSCL_EXPORT_REF= -DOSCL_IMPORT_REF= -DBX_RC
-LOCAL_SANITIZE := signed-integer-overflow
-
-LOCAL_STATIC_LIBRARIES := \
-        libstagefright_m4vh263enc
-
-LOCAL_MODULE := libstagefright_m4vh263enc_test
-LOCAL_MODULE_TAGS := tests
-
-include $(BUILD_EXECUTABLE)
diff --git a/media/libstagefright/codecs/mp3dec/Android.bp b/media/libstagefright/codecs/mp3dec/Android.bp
new file mode 100644
index 0000000..0d0a2c6
--- /dev/null
+++ b/media/libstagefright/codecs/mp3dec/Android.bp
@@ -0,0 +1,146 @@
+cc_library_static {
+    name: "libstagefright_mp3dec",
+
+    srcs: [
+        "src/pvmp3_normalize.cpp",
+        "src/pvmp3_alias_reduction.cpp",
+        "src/pvmp3_crc.cpp",
+        "src/pvmp3_decode_header.cpp",
+        "src/pvmp3_decode_huff_cw.cpp",
+        "src/pvmp3_getbits.cpp",
+        "src/pvmp3_dequantize_sample.cpp",
+        "src/pvmp3_framedecoder.cpp",
+        "src/pvmp3_get_main_data_size.cpp",
+        "src/pvmp3_get_side_info.cpp",
+        "src/pvmp3_get_scale_factors.cpp",
+        "src/pvmp3_mpeg2_get_scale_data.cpp",
+        "src/pvmp3_mpeg2_get_scale_factors.cpp",
+        "src/pvmp3_mpeg2_stereo_proc.cpp",
+        "src/pvmp3_huffman_decoding.cpp",
+        "src/pvmp3_huffman_parsing.cpp",
+        "src/pvmp3_tables.cpp",
+        "src/pvmp3_imdct_synth.cpp",
+        "src/pvmp3_mdct_6.cpp",
+        "src/pvmp3_dct_6.cpp",
+        "src/pvmp3_poly_phase_synthesis.cpp",
+        "src/pvmp3_equalizer.cpp",
+        "src/pvmp3_seek_synch.cpp",
+        "src/pvmp3_stereo_proc.cpp",
+        "src/pvmp3_reorder.cpp",
+
+        "src/pvmp3_polyphase_filter_window.cpp",
+        "src/pvmp3_mdct_18.cpp",
+        "src/pvmp3_dct_9.cpp",
+        "src/pvmp3_dct_16.cpp",
+    ],
+
+    arch: {
+        arm: {
+            exclude_srcs: [
+                "src/pvmp3_polyphase_filter_window.cpp",
+                "src/pvmp3_mdct_18.cpp",
+                "src/pvmp3_dct_9.cpp",
+                "src/pvmp3_dct_16.cpp",
+            ],
+            srcs: [
+                "src/asm/pvmp3_polyphase_filter_window_gcc.s",
+                "src/asm/pvmp3_mdct_18_gcc.s",
+                "src/asm/pvmp3_dct_9_gcc.s",
+                "src/asm/pvmp3_dct_16_gcc.s",
+            ],
+
+            instruction_set: "arm",
+        },
+    },
+
+    sanitize: {
+        misc_undefined: [
+            "signed-integer-overflow",
+        ],
+        cfi: true,
+        diag: {
+            cfi: true,
+        },
+    },
+
+    include_dirs: ["frameworks/av/media/libstagefright/include"],
+    local_include_dirs: ["src"],
+    export_include_dirs: ["include"],
+
+    cflags: [
+        "-DOSCL_UNUSED_ARG(x)=(void)(x)",
+        "-Werror",
+    ],
+}
+
+//###############################################################################
+
+cc_library_shared {
+    name: "libstagefright_soft_mp3dec",
+
+    srcs: ["SoftMP3.cpp"],
+
+    include_dirs: [
+        "frameworks/av/media/libstagefright/include",
+        "frameworks/native/include/media/openmax",
+    ],
+    local_include_dirs: [
+        "src",
+        "include",
+    ],
+
+    cflags: ["-Werror"],
+
+    sanitize: {
+        misc_undefined: [
+            "signed-integer-overflow",
+        ],
+        cfi: true,
+        diag: {
+            cfi: true,
+        },
+    },
+
+    shared_libs: [
+        "libmedia",
+        "libstagefright_omx",
+        "libstagefright_foundation",
+        "libutils",
+        "liblog",
+    ],
+
+    static_libs: ["libstagefright_mp3dec"],
+}
+
+//###############################################################################
+cc_test {
+    name: "libstagefright_mp3dec_test",
+    gtest: false,
+
+    srcs: [
+        "test/mp3dec_test.cpp",
+        "test/mp3reader.cpp",
+    ],
+
+    local_include_dirs: [
+        "src",
+        "include",
+    ],
+
+    sanitize: {
+        misc_undefined: [
+            "signed-integer-overflow",
+        ],
+        cfi: true,
+        diag: {
+            cfi: true,
+        },
+    },
+
+    static_libs: [
+        "libstagefright_mp3dec",
+        "libsndfile",
+    ],
+
+    shared_libs: ["libaudioutils"],
+}
diff --git a/media/libstagefright/codecs/mp3dec/Android.mk b/media/libstagefright/codecs/mp3dec/Android.mk
deleted file mode 100644
index 5d153d1..0000000
--- a/media/libstagefright/codecs/mp3dec/Android.mk
+++ /dev/null
@@ -1,114 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
-	src/pvmp3_normalize.cpp \
- 	src/pvmp3_alias_reduction.cpp \
- 	src/pvmp3_crc.cpp \
- 	src/pvmp3_decode_header.cpp \
- 	src/pvmp3_decode_huff_cw.cpp \
- 	src/pvmp3_getbits.cpp \
- 	src/pvmp3_dequantize_sample.cpp \
- 	src/pvmp3_framedecoder.cpp \
- 	src/pvmp3_get_main_data_size.cpp \
- 	src/pvmp3_get_side_info.cpp \
- 	src/pvmp3_get_scale_factors.cpp \
- 	src/pvmp3_mpeg2_get_scale_data.cpp \
- 	src/pvmp3_mpeg2_get_scale_factors.cpp \
- 	src/pvmp3_mpeg2_stereo_proc.cpp \
- 	src/pvmp3_huffman_decoding.cpp \
- 	src/pvmp3_huffman_parsing.cpp \
- 	src/pvmp3_tables.cpp \
- 	src/pvmp3_imdct_synth.cpp \
- 	src/pvmp3_mdct_6.cpp \
- 	src/pvmp3_dct_6.cpp \
- 	src/pvmp3_poly_phase_synthesis.cpp \
- 	src/pvmp3_equalizer.cpp \
- 	src/pvmp3_seek_synch.cpp \
- 	src/pvmp3_stereo_proc.cpp \
- 	src/pvmp3_reorder.cpp \
-
-LOCAL_SRC_FILES_arm += \
-	src/asm/pvmp3_polyphase_filter_window_gcc.s \
- 	src/asm/pvmp3_mdct_18_gcc.s \
- 	src/asm/pvmp3_dct_9_gcc.s \
-	src/asm/pvmp3_dct_16_gcc.s
-LOCAL_SRC_FILES_other_archs := \
- 	src/pvmp3_polyphase_filter_window.cpp \
- 	src/pvmp3_mdct_18.cpp \
- 	src/pvmp3_dct_9.cpp \
- 	src/pvmp3_dct_16.cpp
-
-LOCAL_SRC_FILES_arm64  := $(LOCAL_SRC_FILES_other_archs)
-LOCAL_SRC_FILES_mips   := $(LOCAL_SRC_FILES_other_archs)
-LOCAL_SRC_FILES_mips64 := $(LOCAL_SRC_FILES_other_archs)
-LOCAL_SRC_FILES_x86    := $(LOCAL_SRC_FILES_other_archs)
-LOCAL_SRC_FILES_x86_64 := $(LOCAL_SRC_FILES_other_archs)
-
-LOCAL_C_INCLUDES := \
-        frameworks/av/media/libstagefright/include \
-        $(LOCAL_PATH)/src \
-        $(LOCAL_PATH)/include
-
-LOCAL_CFLAGS := \
-        -D"OSCL_UNUSED_ARG(x)=(void)(x)"
-
-LOCAL_CFLAGS += -Werror
-LOCAL_SANITIZE := signed-integer-overflow
-
-LOCAL_MODULE := libstagefright_mp3dec
-
-LOCAL_ARM_MODE := arm
-
-include $(BUILD_STATIC_LIBRARY)
-
-################################################################################
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
-        SoftMP3.cpp
-
-LOCAL_C_INCLUDES := \
-        frameworks/av/media/libstagefright/include \
-        frameworks/native/include/media/openmax \
-        $(LOCAL_PATH)/src \
-        $(LOCAL_PATH)/include
-
-LOCAL_CFLAGS += -Werror
-LOCAL_SANITIZE := signed-integer-overflow cfi
-LOCAL_SANITIZE_DIAG := cfi
-
-LOCAL_SHARED_LIBRARIES := \
-        libmedia libstagefright_omx libstagefright_foundation libutils liblog
-
-LOCAL_STATIC_LIBRARIES := \
-        libstagefright_mp3dec
-
-LOCAL_MODULE := libstagefright_soft_mp3dec
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_SHARED_LIBRARY)
-
-################################################################################
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := \
-        test/mp3dec_test.cpp  \
-        test/mp3reader.cpp
-
-LOCAL_C_INCLUDES := \
-        $(LOCAL_PATH)/src \
-        $(LOCAL_PATH)/include \
-        $(LOCAL_PATH)/test/include \
-        $(call include-path-for, audio-utils)
-
-LOCAL_SANITIZE := signed-integer-overflow
-LOCAL_STATIC_LIBRARIES := \
-        libstagefright_mp3dec libsndfile
-
-LOCAL_SHARED_LIBRARIES := libaudioutils
-
-LOCAL_MODULE := libstagefright_mp3dec_test
-LOCAL_MODULE_TAGS := tests
-
-include $(BUILD_EXECUTABLE)
diff --git a/media/libstagefright/codecs/mp3dec/SoftMP3.cpp b/media/libstagefright/codecs/mp3dec/SoftMP3.cpp
index 0822c34..3def1f0 100644
--- a/media/libstagefright/codecs/mp3dec/SoftMP3.cpp
+++ b/media/libstagefright/codecs/mp3dec/SoftMP3.cpp
@@ -274,7 +274,7 @@
         mConfig->inputBufferUsedLength = 0;
 
         mConfig->outputFrameSize = kOutputBufferSize / sizeof(int16_t);
-        if ((int32)outHeader->nAllocLen < mConfig->outputFrameSize) {
+        if ((int32_t)outHeader->nAllocLen < mConfig->outputFrameSize) {
             ALOGE("input buffer too small: got %u, expected %u",
                 outHeader->nAllocLen, mConfig->outputFrameSize);
             android_errorWriteLog(0x534e4554, "27793371");
@@ -363,7 +363,7 @@
             mAnchorTimeUs + (mNumFramesOutput * 1000000ll) / mSamplingRate;
 
         if (inHeader) {
-            CHECK_GE(inHeader->nFilledLen, mConfig->inputBufferUsedLength);
+            CHECK_GE((int32_t)inHeader->nFilledLen, mConfig->inputBufferUsedLength);
 
             inHeader->nOffset += mConfig->inputBufferUsedLength;
             inHeader->nFilledLen -= mConfig->inputBufferUsedLength;
diff --git a/media/libstagefright/codecs/mpeg2dec/Android.bp b/media/libstagefright/codecs/mpeg2dec/Android.bp
new file mode 100644
index 0000000..0144581
--- /dev/null
+++ b/media/libstagefright/codecs/mpeg2dec/Android.bp
@@ -0,0 +1,33 @@
+cc_library_shared {
+    name: "libstagefright_soft_mpeg2dec",
+
+    static_libs: ["libmpeg2dec"],
+    srcs: ["SoftMPEG2.cpp"],
+
+    include_dirs: [
+        "external/libmpeg2/decoder",
+        "external/libmpeg2/common",
+        "frameworks/av/media/libstagefright/include",
+        "frameworks/native/include/media/openmax",
+    ],
+
+    shared_libs: [
+        "libmedia",
+        "libstagefright_omx",
+        "libstagefright_foundation",
+        "libutils",
+        "liblog",
+    ],
+
+    ldflags: ["-Wl,-Bsymbolic"],
+
+    sanitize: {
+        misc_undefined: [
+            "signed-integer-overflow",
+        ],
+        cfi: true,
+        diag: {
+            cfi: true,
+        },
+    },
+}
diff --git a/media/libstagefright/codecs/mpeg2dec/Android.mk b/media/libstagefright/codecs/mpeg2dec/Android.mk
deleted file mode 100644
index 0afc180..0000000
--- a/media/libstagefright/codecs/mpeg2dec/Android.mk
+++ /dev/null
@@ -1,29 +0,0 @@
-ifeq ($(if $(wildcard external/libmpeg2),1,0),1)
-
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE            := libstagefright_soft_mpeg2dec
-LOCAL_MODULE_TAGS       := optional
-
-LOCAL_STATIC_LIBRARIES  := libmpeg2dec
-LOCAL_SRC_FILES         := SoftMPEG2.cpp
-
-LOCAL_C_INCLUDES := $(TOP)/external/libmpeg2/decoder
-LOCAL_C_INCLUDES += $(TOP)/external/libmpeg2/common
-LOCAL_C_INCLUDES += $(TOP)/frameworks/av/media/libstagefright/include
-LOCAL_C_INCLUDES += $(TOP)/frameworks/native/include/media/openmax
-
-LOCAL_SHARED_LIBRARIES  := libmedia
-LOCAL_SHARED_LIBRARIES  += libstagefright_omx
-LOCAL_SHARED_LIBRARIES  += libstagefright_foundation
-LOCAL_SHARED_LIBRARIES  += libutils
-LOCAL_SHARED_LIBRARIES  += liblog
-
-LOCAL_LDFLAGS := -Wl,-Bsymbolic
-LOCAL_SANITIZE := signed-integer-overflow cfi
-LOCAL_SANITIZE_DIAG := cfi
-
-include $(BUILD_SHARED_LIBRARY)
-
-endif
diff --git a/media/libstagefright/codecs/on2/Android.bp b/media/libstagefright/codecs/on2/Android.bp
new file mode 100644
index 0000000..b44c296
--- /dev/null
+++ b/media/libstagefright/codecs/on2/Android.bp
@@ -0,0 +1 @@
+subdirs = ["*"]
diff --git a/media/libstagefright/codecs/on2/Android.mk b/media/libstagefright/codecs/on2/Android.mk
deleted file mode 100644
index 2e43120..0000000
--- a/media/libstagefright/codecs/on2/Android.mk
+++ /dev/null
@@ -1,4 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/media/libstagefright/codecs/on2/dec/Android.bp b/media/libstagefright/codecs/on2/dec/Android.bp
new file mode 100644
index 0000000..c4242c2
--- /dev/null
+++ b/media/libstagefright/codecs/on2/dec/Android.bp
@@ -0,0 +1,33 @@
+cc_library_shared {
+    name: "libstagefright_soft_vpxdec",
+
+    srcs: ["SoftVPX.cpp"],
+
+    include_dirs: [
+        "frameworks/av/media/libstagefright/include",
+        "frameworks/native/include/media/openmax",
+    ],
+
+    static_libs: ["libvpx"],
+
+    shared_libs: [
+        "libmedia",
+        "libstagefright_omx",
+        "libstagefright_foundation",
+        "libutils",
+        "liblog",
+    ],
+
+    cflags: ["-Werror"],
+
+    sanitize: {
+        misc_undefined: [
+            "signed-integer-overflow",
+            "unsigned-integer-overflow",
+        ],
+        cfi: true,
+        diag: {
+            cfi: true,
+        },
+    },
+}
diff --git a/media/libstagefright/codecs/on2/dec/Android.mk b/media/libstagefright/codecs/on2/dec/Android.mk
deleted file mode 100644
index 8bc7dbc..0000000
--- a/media/libstagefright/codecs/on2/dec/Android.mk
+++ /dev/null
@@ -1,27 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
-        SoftVPX.cpp
-
-LOCAL_C_INCLUDES := \
-        $(TOP)/external/libvpx/libvpx \
-        $(TOP)/external/libvpx/libvpx/vpx_codec \
-        $(TOP)/external/libvpx/libvpx/vpx_ports \
-        frameworks/av/media/libstagefright/include \
-        frameworks/native/include/media/openmax \
-
-LOCAL_STATIC_LIBRARIES := \
-        libvpx
-
-LOCAL_SHARED_LIBRARIES := \
-        libmedia libstagefright_omx libstagefright_foundation libutils liblog
-
-LOCAL_MODULE := libstagefright_soft_vpxdec
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_CFLAGS += -Werror
-LOCAL_SANITIZE := signed-integer-overflow unsigned-integer-overflow cfi
-LOCAL_SANITIZE_DIAG := cfi
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/codecs/on2/enc/Android.bp b/media/libstagefright/codecs/on2/enc/Android.bp
new file mode 100644
index 0000000..114c1be
--- /dev/null
+++ b/media/libstagefright/codecs/on2/enc/Android.bp
@@ -0,0 +1,35 @@
+cc_library_shared {
+    name: "libstagefright_soft_vpxenc",
+
+    srcs: [
+        "SoftVPXEncoder.cpp",
+        "SoftVP8Encoder.cpp",
+        "SoftVP9Encoder.cpp",
+    ],
+
+    include_dirs: [
+        "frameworks/av/media/libstagefright/include",
+        "frameworks/native/include/media/openmax",
+    ],
+
+    sanitize: {
+        misc_undefined: [
+            "signed-integer-overflow",
+            "unsigned-integer-overflow",
+        ],
+        cfi: true,
+        diag: {
+            cfi: true,
+        },
+    },
+
+    static_libs: ["libvpx"],
+
+    shared_libs: [
+        "libmedia",
+        "libstagefright_omx",
+        "libstagefright_foundation",
+        "libutils",
+        "liblog",
+    ],
+}
diff --git a/media/libstagefright/codecs/on2/enc/Android.mk b/media/libstagefright/codecs/on2/enc/Android.mk
deleted file mode 100644
index 747aae0..0000000
--- a/media/libstagefright/codecs/on2/enc/Android.mk
+++ /dev/null
@@ -1,29 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
-        SoftVPXEncoder.cpp \
-        SoftVP8Encoder.cpp \
-        SoftVP9Encoder.cpp
-
-LOCAL_C_INCLUDES := \
-        $(TOP)/external/libvpx/libvpx \
-        $(TOP)/external/libvpx/libvpx/vpx_codec \
-        $(TOP)/external/libvpx/libvpx/vpx_ports \
-        frameworks/av/media/libstagefright/include \
-        frameworks/native/include/media/openmax \
-
-LOCAL_SANITIZE := signed-integer-overflow unsigned-integer-overflow cfi
-
-LOCAL_SANITIZE_DIAG := cfi
-
-LOCAL_STATIC_LIBRARIES := \
-        libvpx
-
-LOCAL_SHARED_LIBRARIES := \
-        libmedia libstagefright_omx libstagefright_foundation libutils liblog \
-
-LOCAL_MODULE := libstagefright_soft_vpxenc
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/codecs/on2/h264dec/Android.bp b/media/libstagefright/codecs/on2/h264dec/Android.bp
new file mode 100644
index 0000000..95c2075
--- /dev/null
+++ b/media/libstagefright/codecs/on2/h264dec/Android.bp
@@ -0,0 +1,137 @@
+cc_library_shared {
+    name: "libstagefright_soft_h264dec",
+
+    srcs: [
+        "source/h264bsd_transform.c",
+        "source/h264bsd_util.c",
+        "source/h264bsd_byte_stream.c",
+        "source/h264bsd_seq_param_set.c",
+        "source/h264bsd_pic_param_set.c",
+        "source/h264bsd_slice_header.c",
+        "source/h264bsd_slice_data.c",
+        "source/h264bsd_macroblock_layer.c",
+        "source/h264bsd_stream.c",
+        "source/h264bsd_vlc.c",
+        "source/h264bsd_cavlc.c",
+        "source/h264bsd_nal_unit.c",
+        "source/h264bsd_neighbour.c",
+        "source/h264bsd_storage.c",
+        "source/h264bsd_slice_group_map.c",
+        "source/h264bsd_intra_prediction.c",
+        "source/h264bsd_inter_prediction.c",
+        "source/h264bsd_reconstruct.c",
+        "source/h264bsd_dpb.c",
+        "source/h264bsd_image.c",
+        "source/h264bsd_deblocking.c",
+        "source/h264bsd_conceal.c",
+        "source/h264bsd_vui.c",
+        "source/h264bsd_pic_order_cnt.c",
+        "source/h264bsd_decoder.c",
+        "source/H264SwDecApi.c",
+        "SoftAVC.cpp",
+    ],
+
+    arch: {
+        arm: {
+            instruction_set: "arm",
+
+            armv7_a_neon: {
+                cflags: [
+                    "-DH264DEC_NEON",
+                    "-DH264DEC_OMXDL",
+                ],
+                srcs: [
+                    "source/arm_neon_asm_gcc/h264bsdWriteMacroblock.S",
+                    "source/arm_neon_asm_gcc/h264bsdClearMbLayer.S",
+                    "source/arm_neon_asm_gcc/h264bsdFillRow7.S",
+                    "source/arm_neon_asm_gcc/h264bsdCountLeadingZeros.S",
+                    "source/arm_neon_asm_gcc/h264bsdFlushBits.S",
+
+                    "omxdl/arm_neon/vc/m4p10/src/omxVCM4P10_DeblockChroma_I.c",
+                    "omxdl/arm_neon/vc/m4p10/src/omxVCM4P10_DeblockLuma_I.c",
+                    "omxdl/arm_neon/vc/m4p10/src/omxVCM4P10_InterpolateChroma.c",
+                    "omxdl/arm_neon/vc/m4p10/src/armVCM4P10_CAVLCTables.c",
+                    "omxdl/arm_neon/vc/m4p10/src/omxVCM4P10_DecodeChromaDcCoeffsToPairCAVLC.c",
+                    "omxdl/arm_neon/vc/m4p10/src/omxVCM4P10_DecodeCoeffsToPairCAVLC.c",
+                    "omxdl/arm_neon/src/armCOMM_Bitstream.c",
+                    "omxdl/arm_neon/src/armCOMM.c",
+
+                    "omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_DeblockingChroma_unsafe_s.S",
+                    "omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_DeblockingLuma_unsafe_s.S",
+                    "omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_Interpolate_Chroma_s.S",
+                    "omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_Align_unsafe_s.S",
+                    "omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_Copy_unsafe_s.S",
+                    "omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_DiagCopy_unsafe_s.S",
+                    "omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_HalfDiagHorVer4x4_unsafe_s.S",
+                    "omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_HalfDiagVerHor4x4_unsafe_s.S",
+                    "omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_HalfHor4x4_unsafe_s.S",
+                    "omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_HalfVer4x4_unsafe_s.S",
+                    "omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_FilterDeblockingChroma_HorEdge_I_s.S",
+                    "omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_FilterDeblockingChroma_VerEdge_I_s.S",
+                    "omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_FilterDeblockingLuma_HorEdge_I_s.S",
+                    "omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_FilterDeblockingLuma_VerEdge_I_s.S",
+                    "omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_InterpolateLuma_s.S",
+                    "omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_Average_4x_Align_unsafe_s.S",
+                    "omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_DecodeCoeffsToPair_s.S",
+                    "omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_DequantTables_s.S",
+                    "omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_QuantTables_s.S",
+                    "omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_TransformResidual4x4_s.S",
+                    "omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_UnpackBlock4x4_s.S",
+                    "omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_TransformDequantLumaDCFromPair_s.S",
+                    "omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_PredictIntra_16x16_s.S",
+                    "omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_PredictIntra_4x4_s.S",
+                    "omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_PredictIntraChroma_8x8_s.S",
+                    "omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_DequantTransformResidualFromPairAndAdd_s.S",
+                    "omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_TransformDequantChromaDCFromPair_s.S",
+                ],
+
+                local_include_dirs: [
+                    "source/arm_neon_asm_gcc",
+
+                    "omxdl/arm_neon/api",
+                    "omxdl/arm_neon/vc/api",
+                    "omxdl/arm_neon/vc/m4p10/api",
+                ],
+            },
+        },
+    },
+
+    include_dirs: [
+        "frameworks/av/media/libstagefright/include",
+        "frameworks/native/include/media/openmax",
+    ],
+
+    export_include_dirs: ["inc"],
+
+    sanitize: {
+        misc_undefined: [
+            "signed-integer-overflow",
+        ],
+        cfi: true,
+        diag: {
+            cfi: true,
+        },
+    },
+
+    shared_libs: [
+        "libmedia",
+        "libstagefright_omx",
+        "libstagefright_foundation",
+        "libutils",
+        "liblog",
+    ],
+}
+
+//####################################################################
+// test utility: decoder
+//####################################################################
+//#
+//# Test application
+//#
+cc_binary {
+    name: "decoder",
+
+    srcs: ["source/DecTestBench.c"],
+
+    shared_libs: ["libstagefright_soft_h264dec"],
+}
diff --git a/media/libstagefright/codecs/on2/h264dec/Android.mk b/media/libstagefright/codecs/on2/h264dec/Android.mk
deleted file mode 100644
index 10147ec..0000000
--- a/media/libstagefright/codecs/on2/h264dec/Android.mk
+++ /dev/null
@@ -1,129 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_ARM_MODE := arm
-
-LOCAL_SRC_FILES := \
-	./source/h264bsd_transform.c \
-	./source/h264bsd_util.c \
-	./source/h264bsd_byte_stream.c \
-	./source/h264bsd_seq_param_set.c \
-	./source/h264bsd_pic_param_set.c \
-	./source/h264bsd_slice_header.c \
-	./source/h264bsd_slice_data.c \
-	./source/h264bsd_macroblock_layer.c \
-	./source/h264bsd_stream.c \
-	./source/h264bsd_vlc.c \
-	./source/h264bsd_cavlc.c \
-	./source/h264bsd_nal_unit.c \
-	./source/h264bsd_neighbour.c \
-	./source/h264bsd_storage.c \
-	./source/h264bsd_slice_group_map.c \
-	./source/h264bsd_intra_prediction.c \
-	./source/h264bsd_inter_prediction.c \
-	./source/h264bsd_reconstruct.c \
-	./source/h264bsd_dpb.c \
-	./source/h264bsd_image.c \
-	./source/h264bsd_deblocking.c \
-	./source/h264bsd_conceal.c \
-	./source/h264bsd_vui.c \
-	./source/h264bsd_pic_order_cnt.c \
-	./source/h264bsd_decoder.c \
-	./source/H264SwDecApi.c \
-	SoftAVC.cpp \
-
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/./inc \
-	frameworks/av/media/libstagefright/include \
-	frameworks/native/include/media/openmax \
-
-MY_ASM := \
-	./source/arm_neon_asm_gcc/h264bsdWriteMacroblock.S \
-	./source/arm_neon_asm_gcc/h264bsdClearMbLayer.S \
-	./source/arm_neon_asm_gcc/h264bsdFillRow7.S \
-	./source/arm_neon_asm_gcc/h264bsdCountLeadingZeros.S \
-	./source/arm_neon_asm_gcc/h264bsdFlushBits.S
-
-
-MY_OMXDL_C_SRC := \
-	./omxdl/arm_neon/vc/m4p10/src/omxVCM4P10_DeblockChroma_I.c \
-	./omxdl/arm_neon/vc/m4p10/src/omxVCM4P10_DeblockLuma_I.c \
-	./omxdl/arm_neon/vc/m4p10/src/omxVCM4P10_InterpolateChroma.c \
-	./omxdl/arm_neon/vc/m4p10/src/armVCM4P10_CAVLCTables.c \
-	./omxdl/arm_neon/vc/m4p10/src/omxVCM4P10_DecodeChromaDcCoeffsToPairCAVLC.c \
-	./omxdl/arm_neon/vc/m4p10/src/omxVCM4P10_DecodeCoeffsToPairCAVLC.c \
-	./omxdl/arm_neon/src/armCOMM_Bitstream.c \
-	./omxdl/arm_neon/src/armCOMM.c
-
-MY_OMXDL_ASM_SRC := \
-	./omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_DeblockingChroma_unsafe_s.S \
-	./omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_DeblockingLuma_unsafe_s.S \
-	./omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_Interpolate_Chroma_s.S \
-	./omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_Align_unsafe_s.S \
-	./omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_Copy_unsafe_s.S \
-	./omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_DiagCopy_unsafe_s.S \
-	./omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_HalfDiagHorVer4x4_unsafe_s.S \
-	./omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_HalfDiagVerHor4x4_unsafe_s.S \
-	./omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_HalfHor4x4_unsafe_s.S \
-	./omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_HalfVer4x4_unsafe_s.S \
-	./omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_FilterDeblockingChroma_HorEdge_I_s.S \
-	./omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_FilterDeblockingChroma_VerEdge_I_s.S \
-	./omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_FilterDeblockingLuma_HorEdge_I_s.S \
-	./omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_FilterDeblockingLuma_VerEdge_I_s.S \
-	./omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_InterpolateLuma_s.S \
-	./omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_Average_4x_Align_unsafe_s.S \
-	./omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_DecodeCoeffsToPair_s.S \
-	./omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_DequantTables_s.S \
-	./omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_QuantTables_s.S \
-	./omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_TransformResidual4x4_s.S \
-	./omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_UnpackBlock4x4_s.S \
-	./omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_TransformDequantLumaDCFromPair_s.S \
-	./omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_PredictIntra_16x16_s.S \
-	./omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_PredictIntra_4x4_s.S \
-	./omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_PredictIntraChroma_8x8_s.S \
-	./omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_DequantTransformResidualFromPairAndAdd_s.S \
-	./omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_TransformDequantChromaDCFromPair_s.S \
-
-
-ifeq ($(ARCH_ARM_HAVE_NEON),true)
-    LOCAL_ARM_NEON   := true
-    LOCAL_CFLAGS_arm     := -DH264DEC_NEON -DH264DEC_OMXDL
-    LOCAL_SRC_FILES_arm  := $(MY_ASM) $(MY_OMXDL_C_SRC) $(MY_OMXDL_ASM_SRC)
-    LOCAL_C_INCLUDES_arm := $(LOCAL_PATH)/./source/arm_neon_asm_gcc
-    LOCAL_C_INCLUDES_arm += $(LOCAL_PATH)/./omxdl/arm_neon/api \
-                        $(LOCAL_PATH)/./omxdl/arm_neon/vc/api \
-                        $(LOCAL_PATH)/./omxdl/arm_neon/vc/m4p10/api
-endif
-
-LOCAL_SANITIZE := signed-integer-overflow cfi
-
-LOCAL_SANITIZE_DIAG := cfi
-
-LOCAL_SHARED_LIBRARIES := \
-	libmedia libstagefright_omx libstagefright_foundation libutils liblog \
-
-LOCAL_MODULE := libstagefright_soft_h264dec
-
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_SHARED_LIBRARY)
-
-#####################################################################
-# test utility: decoder
-#####################################################################
-##
-## Test application
-##
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := ./source/DecTestBench.c
-
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/inc
-
-LOCAL_SHARED_LIBRARIES := libstagefright_soft_h264dec
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_MODULE := decoder
-
-include $(BUILD_EXECUTABLE)
diff --git a/media/libstagefright/codecs/opus/Android.bp b/media/libstagefright/codecs/opus/Android.bp
new file mode 100644
index 0000000..b44c296
--- /dev/null
+++ b/media/libstagefright/codecs/opus/Android.bp
@@ -0,0 +1 @@
+subdirs = ["*"]
diff --git a/media/libstagefright/codecs/opus/Android.mk b/media/libstagefright/codecs/opus/Android.mk
deleted file mode 100644
index 365b179..0000000
--- a/media/libstagefright/codecs/opus/Android.mk
+++ /dev/null
@@ -1,4 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
\ No newline at end of file
diff --git a/media/libstagefright/codecs/opus/dec/Android.bp b/media/libstagefright/codecs/opus/dec/Android.bp
new file mode 100644
index 0000000..5d9c4c8
--- /dev/null
+++ b/media/libstagefright/codecs/opus/dec/Android.bp
@@ -0,0 +1,30 @@
+cc_library_shared {
+    name: "libstagefright_soft_opusdec",
+
+    srcs: ["SoftOpus.cpp"],
+
+    include_dirs: [
+        "frameworks/av/media/libstagefright/include",
+        "frameworks/native/include/media/openmax",
+    ],
+
+    shared_libs: [
+        "libopus",
+        "libmedia",
+        "libstagefright_omx",
+        "libstagefright_foundation",
+        "libutils",
+        "liblog",
+    ],
+
+    sanitize: {
+        misc_undefined: [
+            "signed-integer-overflow",
+            "unsigned-integer-overflow",
+        ],
+        cfi: true,
+        diag: {
+            cfi: true,
+        },
+    },
+}
diff --git a/media/libstagefright/codecs/opus/dec/Android.mk b/media/libstagefright/codecs/opus/dec/Android.mk
deleted file mode 100644
index 5b887b3..0000000
--- a/media/libstagefright/codecs/opus/dec/Android.mk
+++ /dev/null
@@ -1,23 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
-        SoftOpus.cpp
-
-LOCAL_C_INCLUDES := \
-        external/libopus/include \
-        frameworks/av/media/libstagefright/include \
-        frameworks/native/include/media/openmax \
-
-LOCAL_SHARED_LIBRARIES := \
-        libopus libmedia libstagefright_omx \
-        libstagefright_foundation libutils liblog
-
-LOCAL_SANITIZE := signed-integer-overflow unsigned-integer-overflow cfi
-
-LOCAL_SANITIZE_DIAG := cfi
-
-LOCAL_MODULE := libstagefright_soft_opusdec
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/codecs/raw/Android.bp b/media/libstagefright/codecs/raw/Android.bp
new file mode 100644
index 0000000..c64027b
--- /dev/null
+++ b/media/libstagefright/codecs/raw/Android.bp
@@ -0,0 +1,30 @@
+cc_library_shared {
+    name: "libstagefright_soft_rawdec",
+
+    srcs: ["SoftRaw.cpp"],
+
+    include_dirs: [
+        "frameworks/av/media/libstagefright/include",
+        "frameworks/native/include/media/openmax",
+    ],
+
+    cflags: ["-Werror"],
+
+    sanitize: {
+        misc_undefined: [
+            "signed-integer-overflow",
+            "unsigned-integer-overflow",
+        ],
+        cfi: true,
+        diag: {
+            cfi: true,
+        },
+    },
+
+    shared_libs: [
+        "libstagefright_omx",
+        "libstagefright_foundation",
+        "libutils",
+        "liblog",
+    ],
+}
diff --git a/media/libstagefright/codecs/raw/Android.mk b/media/libstagefright/codecs/raw/Android.mk
deleted file mode 100644
index 5fe260b..0000000
--- a/media/libstagefright/codecs/raw/Android.mk
+++ /dev/null
@@ -1,21 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
-        SoftRaw.cpp
-
-LOCAL_C_INCLUDES := \
-        frameworks/av/media/libstagefright/include \
-        frameworks/native/include/media/openmax
-
-LOCAL_CFLAGS += -Werror
-LOCAL_SANITIZE := signed-integer-overflow unsigned-integer-overflow cfi
-LOCAL_SANITIZE_DIAG := cfi
-
-LOCAL_SHARED_LIBRARIES := \
-        libstagefright_omx libstagefright_foundation libutils liblog
-
-LOCAL_MODULE := libstagefright_soft_rawdec
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/codecs/vorbis/Android.bp b/media/libstagefright/codecs/vorbis/Android.bp
new file mode 100644
index 0000000..b44c296
--- /dev/null
+++ b/media/libstagefright/codecs/vorbis/Android.bp
@@ -0,0 +1 @@
+subdirs = ["*"]
diff --git a/media/libstagefright/codecs/vorbis/Android.mk b/media/libstagefright/codecs/vorbis/Android.mk
deleted file mode 100644
index 2e43120..0000000
--- a/media/libstagefright/codecs/vorbis/Android.mk
+++ /dev/null
@@ -1,4 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/media/libstagefright/codecs/vorbis/dec/Android.bp b/media/libstagefright/codecs/vorbis/dec/Android.bp
new file mode 100644
index 0000000..1a4de60
--- /dev/null
+++ b/media/libstagefright/codecs/vorbis/dec/Android.bp
@@ -0,0 +1,28 @@
+cc_library_shared {
+    name: "libstagefright_soft_vorbisdec",
+
+    srcs: ["SoftVorbis.cpp"],
+
+    include_dirs: [
+        "frameworks/av/media/libstagefright/include",
+        "frameworks/native/include/media/openmax",
+    ],
+
+    shared_libs: [
+        "libvorbisidec",
+        "libmedia",
+        "libstagefright_omx",
+        "libstagefright_foundation",
+        "libutils",
+        "liblog",
+    ],
+
+    cflags: ["-Werror"],
+
+    sanitize: {
+        misc_undefined: [
+            "signed-integer-overflow",
+            "unsigned-integer-overflow",
+        ],
+    },
+}
diff --git a/media/libstagefright/codecs/vorbis/dec/Android.mk b/media/libstagefright/codecs/vorbis/dec/Android.mk
deleted file mode 100644
index 3d72d3a..0000000
--- a/media/libstagefright/codecs/vorbis/dec/Android.mk
+++ /dev/null
@@ -1,22 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
-        SoftVorbis.cpp
-
-LOCAL_C_INCLUDES := \
-        external/tremolo \
-        frameworks/av/media/libstagefright/include \
-        frameworks/native/include/media/openmax \
-
-LOCAL_SHARED_LIBRARIES := \
-        libvorbisidec libmedia libstagefright_omx \
-        libstagefright_foundation libutils liblog
-
-LOCAL_MODULE := libstagefright_soft_vorbisdec
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_CFLAGS += -Werror
-LOCAL_SANITIZE := signed-integer-overflow unsigned-integer-overflow
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp b/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp
index be04e08..14dd250 100644
--- a/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp
+++ b/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp
@@ -23,6 +23,9 @@
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/MediaDefs.h>
 
+static int kDefaultChannelCount = 1;
+static int kDefaultSamplingRate = 48000;
+
 extern "C" {
     #include <Tremolo/codec_internal.h>
 
@@ -148,8 +151,8 @@
             vorbisParams->bDownmix = OMX_FALSE;
 
             if (!isConfigured()) {
-                vorbisParams->nChannels = 1;
-                vorbisParams->nSampleRate = 44100;
+                vorbisParams->nChannels = kDefaultChannelCount;
+                vorbisParams->nSampleRate = kDefaultSamplingRate;
             } else {
                 vorbisParams->nChannels = mVi->channels;
                 vorbisParams->nSampleRate = mVi->rate;
@@ -157,7 +160,6 @@
                 vorbisParams->nMinBitRate = mVi->bitrate_lower;
                 vorbisParams->nMaxBitRate = mVi->bitrate_upper;
             }
-
             return OMX_ErrorNone;
         }
 
@@ -183,8 +185,8 @@
             pcmParams->eChannelMapping[1] = OMX_AUDIO_ChannelRF;
 
             if (!isConfigured()) {
-                pcmParams->nChannels = 1;
-                pcmParams->nSamplingRate = 44100;
+                pcmParams->nChannels = kDefaultChannelCount;
+                pcmParams->nSamplingRate = kDefaultSamplingRate;
             } else {
                 pcmParams->nChannels = mVi->channels;
                 pcmParams->nSamplingRate = mVi->rate;
@@ -313,8 +315,12 @@
             mState = new vorbis_dsp_state;
             CHECK_EQ(0, vorbis_dsp_init(mState, mVi));
 
-            notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
-            mOutputPortSettingsChange = AWAITING_DISABLED;
+            if (mVi->rate != kDefaultSamplingRate ||
+                    mVi->channels != kDefaultChannelCount) {
+                ALOGV("vorbis: rate/channels changed: %ld/%d", mVi->rate, mVi->channels);
+                notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
+                mOutputPortSettingsChange = AWAITING_DISABLED;
+            }
         }
 
         inQueue.erase(inQueue.begin());
diff --git a/media/libstagefright/colorconversion/Android.bp b/media/libstagefright/colorconversion/Android.bp
new file mode 100644
index 0000000..16e9ded
--- /dev/null
+++ b/media/libstagefright/colorconversion/Android.bp
@@ -0,0 +1,31 @@
+cc_library_static {
+    name: "libstagefright_color_conversion",
+
+    srcs: [
+        "ColorConverter.cpp",
+        "SoftwareRenderer.cpp",
+    ],
+
+    include_dirs: [
+        "frameworks/native/include/media/openmax",
+    ],
+
+    shared_libs: [
+        "libui",
+        "libnativewindow",
+    ],
+
+    static_libs: ["libyuv_static"],
+
+    cflags: ["-Werror"],
+
+    sanitize: {
+        misc_undefined: [
+            "signed-integer-overflow",
+        ],
+        cfi: true,
+        diag: {
+            cfi: true,
+        },
+    },
+}
diff --git a/media/libstagefright/colorconversion/Android.mk b/media/libstagefright/colorconversion/Android.mk
deleted file mode 100644
index 1e7a4cc..0000000
--- a/media/libstagefright/colorconversion/Android.mk
+++ /dev/null
@@ -1,25 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:=                     \
-        ColorConverter.cpp            \
-        SoftwareRenderer.cpp
-
-LOCAL_C_INCLUDES := \
-        $(TOP)/frameworks/native/include/media/openmax \
-        $(TOP)/hardware/msm7k \
-        $(TOP)/external/libyuv/files/include
-
-LOCAL_SHARED_LIBRARIES := \
-        libui \
-
-LOCAL_STATIC_LIBRARIES := \
-        libyuv_static \
-
-LOCAL_CFLAGS += -Werror
-LOCAL_SANITIZE := signed-integer-overflow cfi
-LOCAL_SANITIZE_DIAG := cfi
-
-LOCAL_MODULE:= libstagefright_color_conversion
-
-include $(BUILD_STATIC_LIBRARY)
diff --git a/media/libstagefright/colorconversion/SoftwareRenderer.cpp b/media/libstagefright/colorconversion/SoftwareRenderer.cpp
index 536d40d..a07787a 100644
--- a/media/libstagefright/colorconversion/SoftwareRenderer.cpp
+++ b/media/libstagefright/colorconversion/SoftwareRenderer.cpp
@@ -30,10 +30,6 @@
 
 namespace android {
 
-static bool runningInEmulator() {
-    char prop[PROPERTY_VALUE_MAX];
-    return (property_get("ro.kernel.qemu", prop, NULL) > 0);
-}
 
 static int ALIGN(int x, int y) {
     // y must be a power of 2.
@@ -108,7 +104,7 @@
     size_t bufHeight = mCropHeight;
 
     // hardware has YUV12 and RGBA8888 support, so convert known formats
-    if (!runningInEmulator()) {
+    {
         switch (mColorFormat) {
             case OMX_COLOR_FormatYUV420Planar:
             case OMX_COLOR_FormatYUV420SemiPlanar:
@@ -205,7 +201,7 @@
 }
 
 std::list<FrameRenderTracker::Info> SoftwareRenderer::render(
-        const void *data, size_t size, int64_t mediaTimeUs, nsecs_t renderTimeNs,
+        const void *data, size_t , int64_t mediaTimeUs, nsecs_t renderTimeNs,
         void* /*platformPrivate*/, const sp<AMessage>& format) {
     resetFormatIfChanged(format);
     FrameRenderTracker::Info *info = NULL;
@@ -244,14 +240,15 @@
                 buf->stride, buf->height,
                 0, 0, mCropWidth - 1, mCropHeight - 1);
     } else if (mColorFormat == OMX_COLOR_FormatYUV420Planar) {
-        if ((size_t)mWidth * mHeight * 3 / 2 > size) {
-            goto skip_copying;
-        }
         const uint8_t *src_y = (const uint8_t *)data;
         const uint8_t *src_u =
                 (const uint8_t *)data + mWidth * mHeight;
         const uint8_t *src_v = src_u + (mWidth / 2 * mHeight / 2);
 
+        src_y +=mCropLeft + mCropTop * mWidth;
+        src_u +=(mCropLeft + mCropTop * mWidth / 2)/2;
+        src_v +=(mCropLeft + mCropTop * mWidth / 2)/2;
+
         uint8_t *dst_y = (uint8_t *)dst;
         size_t dst_y_size = buf->stride * buf->height;
         size_t dst_c_stride = ALIGN(buf->stride / 2, 16);
@@ -259,6 +256,10 @@
         uint8_t *dst_v = dst_y + dst_y_size;
         uint8_t *dst_u = dst_v + dst_c_size;
 
+        dst_y += mCropTop * buf->stride + mCropLeft;
+        dst_v += (mCropTop/2) * dst_c_stride + mCropLeft/2;
+        dst_u += (mCropTop/2) * dst_c_stride + mCropLeft/2;
+
         for (int y = 0; y < mCropHeight; ++y) {
             memcpy(dst_y, src_y, mCropWidth);
 
@@ -277,12 +278,12 @@
         }
     } else if (mColorFormat == OMX_TI_COLOR_FormatYUV420PackedSemiPlanar
             || mColorFormat == OMX_COLOR_FormatYUV420SemiPlanar) {
-        if ((size_t)mWidth * mHeight * 3 / 2 > size) {
-            goto skip_copying;
-        }
         const uint8_t *src_y = (const uint8_t *)data;
         const uint8_t *src_uv = (const uint8_t *)data
-                + mWidth * (mHeight - mCropTop / 2);
+                + mWidth * mHeight;
+
+        src_y += mCropLeft + mCropTop * mWidth;
+        src_uv += (mCropLeft + mCropTop * mWidth) / 2;
 
         uint8_t *dst_y = (uint8_t *)dst;
 
@@ -292,6 +293,10 @@
         uint8_t *dst_v = dst_y + dst_y_size;
         uint8_t *dst_u = dst_v + dst_c_size;
 
+        dst_y += mCropTop * buf->stride + mCropLeft;
+        dst_v += (mCropTop/2) * dst_c_stride + mCropLeft/2;
+        dst_u += (mCropTop/2) * dst_c_stride + mCropLeft/2;
+
         for (int y = 0; y < mCropHeight; ++y) {
             memcpy(dst_y, src_y, mCropWidth);
 
@@ -311,11 +316,8 @@
             dst_v += dst_c_stride;
         }
     } else if (mColorFormat == OMX_COLOR_Format24bitRGB888) {
-        if ((size_t)mWidth * mHeight * 3 > size) {
-            goto skip_copying;
-        }
-        uint8_t* srcPtr = (uint8_t*)data;
-        uint8_t* dstPtr = (uint8_t*)dst;
+        uint8_t* srcPtr = (uint8_t*)data + mWidth * mCropTop * 3 + mCropLeft * 3;
+        uint8_t* dstPtr = (uint8_t*)dst + buf->stride * mCropTop * 3 + mCropLeft * 3;
 
         for (size_t y = 0; y < (size_t)mCropHeight; ++y) {
             memcpy(dstPtr, srcPtr, mCropWidth * 3);
@@ -323,14 +325,11 @@
             dstPtr += buf->stride * 3;
         }
     } else if (mColorFormat == OMX_COLOR_Format32bitARGB8888) {
-        if ((size_t)mWidth * mHeight * 4 > size) {
-            goto skip_copying;
-        }
         uint8_t *srcPtr, *dstPtr;
 
         for (size_t y = 0; y < (size_t)mCropHeight; ++y) {
-            srcPtr = (uint8_t*)data + mWidth * 4 * y;
-            dstPtr = (uint8_t*)dst + buf->stride * 4 * y;
+            srcPtr = (uint8_t*)data + mWidth * 4 * (y + mCropTop) + mCropLeft * 4;
+            dstPtr = (uint8_t*)dst + buf->stride * 4 * (y + mCropTop) + mCropLeft * 4;
             for (size_t x = 0; x < (size_t)mCropWidth; ++x) {
                 uint8_t a = *srcPtr++;
                 for (size_t i = 0; i < 3; ++i) {   // copy RGB
@@ -340,11 +339,8 @@
             }
         }
     } else if (mColorFormat == OMX_COLOR_Format32BitRGBA8888) {
-        if ((size_t)mWidth * mHeight * 4 > size) {
-            goto skip_copying;
-        }
-        uint8_t* srcPtr = (uint8_t*)data;
-        uint8_t* dstPtr = (uint8_t*)dst;
+        uint8_t* srcPtr = (uint8_t*)data + mWidth * mCropTop * 4 + mCropLeft * 4;
+        uint8_t* dstPtr = (uint8_t*)dst + buf->stride * mCropTop * 4 + mCropLeft * 4;
 
         for (size_t y = 0; y < (size_t)mCropHeight; ++y) {
             memcpy(dstPtr, srcPtr, mCropWidth * 4);
diff --git a/media/libstagefright/data/media_codecs_google_audio.xml b/media/libstagefright/data/media_codecs_google_audio.xml
index b957b0c..632088a 100644
--- a/media/libstagefright/data/media_codecs_google_audio.xml
+++ b/media/libstagefright/data/media_codecs_google_audio.xml
@@ -61,6 +61,11 @@
             <Limit name="sample-rate" ranges="8000-96000" />
             <Limit name="bitrate" range="1-10000000" />
         </MediaCodec>
+        <MediaCodec name="OMX.google.flac.decoder" type="audio/flac">
+            <Limit name="channel-count" max="8" />
+            <Limit name="sample-rate" ranges="1-655350" />
+            <Limit name="bitrate" range="1-21000000" />
+        </MediaCodec>
     </Decoders>
     <Encoders>
         <MediaCodec name="OMX.google.aac.encoder" type="audio/mp4a-latm">
diff --git a/media/libstagefright/filters/Android.bp b/media/libstagefright/filters/Android.bp
new file mode 100644
index 0000000..e944224
--- /dev/null
+++ b/media/libstagefright/filters/Android.bp
@@ -0,0 +1,38 @@
+cc_library_static {
+    name: "libstagefright_mediafilter",
+
+    srcs: [
+        "ColorConvert.cpp",
+        "GraphicBufferListener.cpp",
+        "IntrinsicBlurFilter.cpp",
+        "MediaFilter.cpp",
+        "RSFilter.cpp",
+        "SaturationFilter.cpp",
+        "saturationARGB.rs",
+        "SimpleFilter.cpp",
+        "ZeroFilter.cpp",
+    ],
+
+    include_dirs: [
+        "frameworks/native/include/media/openmax",
+    ],
+
+    cflags: [
+        "-Wno-multichar",
+        "-Werror",
+        "-Wall",
+    ],
+
+    shared_libs: [
+        "libgui",
+        "libmedia",
+        "libhidlmemory",
+    ],
+
+    sanitize: {
+        cfi: true,
+        diag: {
+            cfi: true,
+        },
+    },
+}
diff --git a/media/libstagefright/filters/Android.mk b/media/libstagefright/filters/Android.mk
deleted file mode 100644
index d4ecfcc..0000000
--- a/media/libstagefright/filters/Android.mk
+++ /dev/null
@@ -1,35 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
-        ColorConvert.cpp          \
-        GraphicBufferListener.cpp \
-        IntrinsicBlurFilter.cpp   \
-        MediaFilter.cpp           \
-        RSFilter.cpp              \
-        SaturationFilter.cpp      \
-        saturationARGB.rs         \
-        SimpleFilter.cpp          \
-        ZeroFilter.cpp
-
-LOCAL_C_INCLUDES := \
-        $(TOP)/frameworks/native/include/media/openmax \
-        $(TOP)/frameworks/rs/cpp \
-        $(TOP)/frameworks/rs \
-
-intermediates := $(call intermediates-dir-for,STATIC_LIBRARIES,libRS,TARGET,)
-LOCAL_C_INCLUDES += $(intermediates)
-
-LOCAL_CFLAGS += -Wno-multichar -Werror -Wall
-
-LOCAL_SHARED_LIBRARIES := \
-        libgui \
-        libmedia \
-        libhidlmemory \
-
-LOCAL_MODULE:= libstagefright_mediafilter
-
-LOCAL_SANITIZE := cfi
-LOCAL_SANITIZE_DIAG := cfi
-
-include $(BUILD_STATIC_LIBRARY)
diff --git a/media/libstagefright/flac/dec/Android.bp b/media/libstagefright/flac/dec/Android.bp
new file mode 100644
index 0000000..284c25f
--- /dev/null
+++ b/media/libstagefright/flac/dec/Android.bp
@@ -0,0 +1,34 @@
+cc_library_shared {
+    name: "libstagefright_flacdec",
+
+    srcs: [
+        "FLACDecoder.cpp",
+    ],
+
+    include_dirs: [
+        "external/flac/include",
+        "frameworks/av/media/libstagefright/include",
+    ],
+
+    cflags: ["-Werror"],
+
+    sanitize: {
+        misc_undefined: [
+            "signed-integer-overflow",
+            "unsigned-integer-overflow",
+        ],
+        cfi: true,
+        diag: {
+            cfi: true,
+        },
+    },
+
+    static_libs: ["libFLAC"],
+
+    shared_libs: [
+        "libcutils",
+        "liblog",
+        "libstagefright_foundation",
+        "libutils",
+    ],
+}
diff --git a/media/libstagefright/flac/dec/FLACDecoder.cpp b/media/libstagefright/flac/dec/FLACDecoder.cpp
new file mode 100644
index 0000000..8c7137c
--- /dev/null
+++ b/media/libstagefright/flac/dec/FLACDecoder.cpp
@@ -0,0 +1,526 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "FLACDecoder"
+#include <utils/Log.h>
+
+#include "FLACDecoder.h"
+
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/hexdump.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MetaData.h>
+
+namespace android {
+
+// These are the corresponding callbacks with C++ calling conventions
+FLAC__StreamDecoderReadStatus FLACDecoder::readCallback(
+        FLAC__byte buffer[], size_t *bytes) {
+    if (mBuffer == nullptr || mBufferLen == 0) {
+        *bytes = 0;
+        return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
+    }
+
+    size_t actual = *bytes;
+    if (actual > mBufferDataSize - mBufferPos) {
+        actual = mBufferDataSize - mBufferPos;
+    }
+    memcpy(buffer, mBuffer + mBufferPos, actual);
+    mBufferPos += actual;
+    *bytes = actual;
+    return (actual == 0 ? FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM
+                        : FLAC__STREAM_DECODER_READ_STATUS_CONTINUE);
+}
+
+FLAC__StreamDecoderWriteStatus FLACDecoder::writeCallback(
+        const FLAC__Frame *frame, const FLAC__int32 * const buffer[])
+{
+    if (!mWriteRequested) {
+        ALOGE("writeCallback: unexpected");
+        return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+    }
+
+    mWriteRequested = false;
+    // FLAC decoder doesn't free or realloc buffer until next frame or finish
+    mWriteHeader = frame->header;
+    memmove(mWriteBuffer, buffer, sizeof(const FLAC__int32 * const) * getChannels());
+    mWriteCompleted = true;
+    return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
+}
+
+void FLACDecoder::metadataCallback(const FLAC__StreamMetadata *metadata)
+{
+    switch (metadata->type) {
+        case FLAC__METADATA_TYPE_STREAMINFO:
+        {
+            if (mStreamInfoValid) {
+                ALOGE("metadataCallback: unexpected STREAMINFO");
+            } else {
+                mStreamInfo = metadata->data.stream_info;
+                mStreamInfoValid = true;
+            }
+            break;
+        }
+
+        /* TODO: enable metadata parsing below.
+        case FLAC__METADATA_TYPE_VORBIS_COMMENT:
+        {
+            const FLAC__StreamMetadata_VorbisComment *vc;
+            vc = &metadata->data.vorbis_comment;
+            for (FLAC__uint32 i = 0; i < vc->num_comments; ++i) {
+                FLAC__StreamMetadata_VorbisComment_Entry *vce;
+                vce = &vc->comments[i];
+                if (mFileMetadata != 0 && vce->entry != NULL) {
+                    parseVorbisComment(mFileMetadata, (const char *) vce->entry,
+                            vce->length);
+                }
+            }
+            break;
+        }
+
+        case FLAC__METADATA_TYPE_PICTURE:
+        {
+            if (mFileMetadata != 0) {
+                const FLAC__StreamMetadata_Picture *p = &metadata->data.picture;
+                mFileMetadata->setData(kKeyAlbumArt,
+                        MetaData::TYPE_NONE, p->data, p->data_length);
+                mFileMetadata->setCString(kKeyAlbumArtMIME, p->mime_type);
+            }
+            break;
+        }
+        */
+
+        default:
+            ALOGW("metadataCallback: unexpected type %u", metadata->type);
+            break;
+    }
+}
+
+void FLACDecoder::errorCallback(FLAC__StreamDecoderErrorStatus status)
+{
+    ALOGE("errorCallback: status=%d", status);
+    mErrorStatus = status;
+}
+
+// Copy samples from FLAC native 32-bit non-interleaved to 16-bit interleaved.
+// These are candidates for optimization if needed.
+static void copyMono8(
+        short *dst,
+        const int * src[FLACDecoder::kMaxChannels],
+        unsigned nSamples,
+        unsigned /* nChannels */) {
+    for (unsigned i = 0; i < nSamples; ++i) {
+        *dst++ = src[0][i] << 8;
+    }
+}
+
+static void copyStereo8(
+        short *dst,
+        const int * src[FLACDecoder::kMaxChannels],
+        unsigned nSamples,
+        unsigned /* nChannels */) {
+    for (unsigned i = 0; i < nSamples; ++i) {
+        *dst++ = src[0][i] << 8;
+        *dst++ = src[1][i] << 8;
+    }
+}
+
+static void copyMultiCh8(
+        short *dst,
+        const int * src[FLACDecoder::kMaxChannels],
+        unsigned nSamples,
+        unsigned nChannels) {
+    for (unsigned i = 0; i < nSamples; ++i) {
+        for (unsigned c = 0; c < nChannels; ++c) {
+            *dst++ = src[c][i] << 8;
+        }
+    }
+}
+
+static void copyMono16(
+        short *dst,
+        const int * src[FLACDecoder::kMaxChannels],
+        unsigned nSamples,
+        unsigned /* nChannels */) {
+    for (unsigned i = 0; i < nSamples; ++i) {
+        *dst++ = src[0][i];
+    }
+}
+
+static void copyStereo16(
+        short *dst,
+        const int * src[FLACDecoder::kMaxChannels],
+        unsigned nSamples,
+        unsigned /* nChannels */) {
+    for (unsigned i = 0; i < nSamples; ++i) {
+        *dst++ = src[0][i];
+        *dst++ = src[1][i];
+    }
+}
+
+static void copyMultiCh16(
+        short *dst,
+        const int * src[FLACDecoder::kMaxChannels],
+        unsigned nSamples,
+        unsigned nChannels) {
+    for (unsigned i = 0; i < nSamples; ++i) {
+        for (unsigned c = 0; c < nChannels; ++c) {
+            *dst++ = src[c][i];
+        }
+    }
+}
+
+// TODO: 24-bit versions should do dithering or noise-shaping, here or in AudioFlinger
+static void copyMono24(
+        short *dst,
+        const int * src[FLACDecoder::kMaxChannels],
+        unsigned nSamples,
+        unsigned /* nChannels */) {
+    for (unsigned i = 0; i < nSamples; ++i) {
+        *dst++ = src[0][i] >> 8;
+    }
+}
+
+static void copyStereo24(
+        short *dst,
+        const int * src[FLACDecoder::kMaxChannels],
+        unsigned nSamples,
+        unsigned /* nChannels */) {
+    for (unsigned i = 0; i < nSamples; ++i) {
+        *dst++ = src[0][i] >> 8;
+        *dst++ = src[1][i] >> 8;
+    }
+}
+
+static void copyMultiCh24(
+        short *dst,
+        const int * src[FLACDecoder::kMaxChannels],
+        unsigned nSamples,
+        unsigned nChannels) {
+    for (unsigned i = 0; i < nSamples; ++i) {
+        for (unsigned c = 0; c < nChannels; ++c) {
+            *dst++ = src[c][i] >> 8;
+        }
+    }
+}
+
+// static
+sp<FLACDecoder> FLACDecoder::Create() {
+    sp<FLACDecoder> decoder = new FLACDecoder();
+    if (decoder->init() != OK) {
+        return NULL;
+    }
+    return decoder;
+}
+
+FLACDecoder::FLACDecoder()
+    : mDecoder(NULL),
+      mBuffer(NULL),
+      mBufferLen(0),
+      mBufferPos(0),
+      mBufferDataSize(0),
+      mStreamInfoValid(false),
+      mWriteRequested(false),
+      mWriteCompleted(false),
+      mErrorStatus((FLAC__StreamDecoderErrorStatus) -1),
+      mCopy(nullptr) {
+    ALOGV("ctor:");
+    memset(&mStreamInfo, 0, sizeof(mStreamInfo));
+    memset(&mWriteHeader, 0, sizeof(mWriteHeader));
+    memset(&mWriteBuffer, 0, sizeof(mWriteBuffer));
+}
+
+FLACDecoder::~FLACDecoder() {
+    ALOGV("dtor:");
+    if (mDecoder != NULL) {
+        FLAC__stream_decoder_delete(mDecoder);
+        mDecoder = NULL;
+    }
+    if (mBuffer != NULL) {
+        free(mBuffer);
+    }
+}
+
+status_t FLACDecoder::init() {
+    ALOGV("init:");
+    // setup libFLAC stream decoder
+    mDecoder = FLAC__stream_decoder_new();
+    if (mDecoder == NULL) {
+        ALOGE("init: failed to create libFLAC stream decoder");
+        return NO_INIT;
+    }
+    FLAC__stream_decoder_set_md5_checking(mDecoder, false);
+    FLAC__stream_decoder_set_metadata_ignore_all(mDecoder);
+    FLAC__stream_decoder_set_metadata_respond(
+            mDecoder, FLAC__METADATA_TYPE_STREAMINFO);
+    /*
+    FLAC__stream_decoder_set_metadata_respond(
+            mDecoder, FLAC__METADATA_TYPE_PICTURE);
+    FLAC__stream_decoder_set_metadata_respond(
+            mDecoder, FLAC__METADATA_TYPE_VORBIS_COMMENT);
+    */
+    static auto read_callback =
+        [] (const FLAC__StreamDecoder * /* decoder */,
+            FLAC__byte buffer[],
+            size_t *bytes,
+            void *client_data) -> FLAC__StreamDecoderReadStatus {
+            return ((FLACDecoder *) client_data)->readCallback(buffer, bytes); };
+
+    static auto write_callback =
+        [] (const FLAC__StreamDecoder * /* decoder */,
+            const FLAC__Frame *frame,
+            const FLAC__int32 * const buffer[],
+            void *client_data) -> FLAC__StreamDecoderWriteStatus {
+            return ((FLACDecoder *) client_data)->writeCallback(frame, buffer); };
+
+    static auto metadata_callback =
+        [] (const FLAC__StreamDecoder * /* decoder */,
+            const FLAC__StreamMetadata *metadata,
+            void *client_data) {
+            ((FLACDecoder *) client_data)->metadataCallback(metadata); };
+
+    static auto error_callback =
+        [] (const FLAC__StreamDecoder * /* decoder */,
+            FLAC__StreamDecoderErrorStatus status,
+            void *client_data) {
+            ((FLACDecoder *) client_data)->errorCallback(status); };
+
+    FLAC__StreamDecoderInitStatus initStatus =
+        FLAC__stream_decoder_init_stream(
+                mDecoder,
+                read_callback,
+                NULL /* seek_callback */,
+                NULL /* tell_callback */,
+                NULL /* length_callback */,
+                NULL /* eof_callback */,
+                write_callback,
+                metadata_callback,
+                error_callback,
+                (void *)this);
+    if (initStatus != FLAC__STREAM_DECODER_INIT_STATUS_OK) {
+        ALOGE("init: init_stream failed, returned %d", initStatus);
+        return NO_INIT;
+    }
+    return OK;
+}
+
+void FLACDecoder::flush() {
+    ALOGV("flush:");
+    mBufferPos = 0;
+    mBufferDataSize = 0;
+    mStreamInfoValid = false;
+    if (!FLAC__stream_decoder_reset(mDecoder)) {
+        ALOGE("flush: failed to reset FLAC stream decoder");
+    }
+}
+
+status_t FLACDecoder::parseMetadata(const uint8_t *inBuffer, size_t inBufferLen) {
+    ALOGV("parseMetadata: input size(%zu)", inBufferLen);
+    //hexdump(inBuffer, inBufferLen);
+
+    if (mStreamInfoValid) {
+        ALOGE("parseMetadata: already have full metadata blocks");
+        return ERROR_MALFORMED;
+    }
+
+    status_t err = addDataToBuffer(inBuffer, inBufferLen);
+    if (err != OK) {
+        ALOGE("parseMetadata: addDataToBuffer returns error %d", err);
+        return err;
+    }
+
+    if (!FLAC__stream_decoder_process_until_end_of_metadata(mDecoder)) {
+        if (!FLAC__stream_decoder_reset(mDecoder)) {
+            ALOGE("parseMetadata: failed to reset FLAC stream decoder");
+            return FAILED_TRANSACTION;
+        }
+        mBufferPos = 0;
+        ALOGV("parseMetadata: do not have full metadata blocks yet");
+        return WOULD_BLOCK;
+    }
+
+    if (!mStreamInfoValid) {
+        ALOGE("parseMetadata: missing STREAMINFO");
+        return ERROR_MALFORMED;
+    }
+
+    // check block size
+    if (getMaxBlockSize() == 0) {
+        ALOGE("wrong max blocksize %u", getMaxBlockSize());
+        mStreamInfoValid = false;
+        return ERROR_MALFORMED;
+    }
+
+    // check channel count
+    if (getChannels() == 0 || getChannels() > kMaxChannels) {
+        ALOGE("unsupported channel count %u", getChannels());
+        mStreamInfoValid = false;
+        return ERROR_MALFORMED;
+    }
+
+    // check bit depth
+    switch (getBitsPerSample()) {
+        case 8:
+        case 16:
+        case 24:
+            break;
+
+        default:
+            ALOGE("parseMetadata: unsupported bits per sample %u", getBitsPerSample());
+            mStreamInfoValid = false;
+            return ERROR_MALFORMED;
+    }
+
+    // configure the appropriate copy function, defaulting to trespass
+    static const struct {
+        unsigned mChannels;
+        unsigned mBitsPerSample;
+        void (*mCopy)(short *dst, const int * src[kMaxChannels],
+                unsigned nSamples, unsigned nChannels);
+    } table[] = {
+        { 1,  8, copyMono8     },
+        { 2,  8, copyStereo8   },
+        { 8,  8, copyMultiCh8  },
+        { 1, 16, copyMono16    },
+        { 2, 16, copyStereo16  },
+        { 8, 16, copyMultiCh16 },
+        { 1, 24, copyMono24    },
+        { 2, 24, copyStereo24  },
+        { 8, 24, copyMultiCh24 },
+    };
+    for (const auto &entry : table) {
+        if (entry.mChannels >= getChannels() &&
+                entry.mBitsPerSample == getBitsPerSample()) {
+            mCopy = entry.mCopy;
+            break;
+        }
+    }
+
+    // Now we have all metadata blocks.
+    mBufferPos = 0;
+    mBufferDataSize = 0;
+
+    return OK;
+}
+
+status_t FLACDecoder::decodeOneFrame(const uint8_t *inBuffer, size_t inBufferLen,
+        short *outBuffer, size_t *outBufferLen) {
+    ALOGV("decodeOneFrame: input size(%zu)", inBufferLen);
+
+    if (inBufferLen == 0) {
+        ALOGV("decodeOneFrame: no input data");
+        if (outBufferLen) {
+            *outBufferLen = 0;
+        }
+        return OK;
+    }
+
+    if (!mStreamInfoValid) {
+        ALOGW("decodeOneFrame: no streaminfo metadata block");
+    }
+
+    status_t err = addDataToBuffer(inBuffer, inBufferLen);
+    if (err != OK) {
+        ALOGW("decodeOneFrame: addDataToBuffer returns error %d", err);
+        return err;
+    }
+
+    mWriteRequested = true;
+    mWriteCompleted = false;
+    if (!FLAC__stream_decoder_process_single(mDecoder)) {
+        ALOGE("decodeOneFrame: process_single failed");
+        return ERROR_MALFORMED;
+    }
+    if (!mWriteCompleted) {
+        ALOGV("decodeOneFrame: write did not complete");
+        if (outBufferLen) {
+            *outBufferLen = 0;
+        }
+        return OK;
+    }
+
+    // frame header should be consistent with STREAMINFO
+    unsigned blocksize = mWriteHeader.blocksize;
+    if (blocksize == 0 || blocksize > getMaxBlockSize()) {
+        ALOGE("decodeOneFrame: write invalid blocksize %u", blocksize);
+        return ERROR_MALFORMED;
+    }
+    if (mWriteHeader.sample_rate != getSampleRate() ||
+        mWriteHeader.channels != getChannels() ||
+        mWriteHeader.bits_per_sample != getBitsPerSample()) {
+        ALOGE("decodeOneFrame: parameters are changed mid-stream: %d/%d/%d -> %d/%d/%d",
+                getSampleRate(), getChannels(), getBitsPerSample(),
+                mWriteHeader.sample_rate, mWriteHeader.channels, mWriteHeader.bits_per_sample);
+        return ERROR_MALFORMED;
+    }
+    if (mWriteHeader.number_type != FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER) {
+        ALOGE("decodeOneFrame: number type is %d, expected %d",
+                mWriteHeader.number_type, FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER);
+        return ERROR_MALFORMED;
+    }
+
+    size_t bufferSize = blocksize * getChannels() * sizeof(short);
+    if (bufferSize > *outBufferLen) {
+        ALOGW("decodeOneFrame: output buffer holds only partial frame %zu:%zu",
+                *outBufferLen, bufferSize);
+        blocksize = *outBufferLen / (getChannels() * sizeof(short));
+        bufferSize = blocksize * getChannels() * sizeof(short);
+    }
+
+    if (mCopy == nullptr) {
+        ALOGE("decodeOneFrame: format is not supported: channels(%d), BitsPerSample(%d)",
+                getChannels(), getBitsPerSample());
+        return ERROR_UNSUPPORTED;
+    }
+    // copy PCM from FLAC write buffer to output buffer, with interleaving
+    (*mCopy)(outBuffer, mWriteBuffer, blocksize, getChannels());
+    *outBufferLen = bufferSize;
+    return OK;
+}
+
+status_t FLACDecoder::addDataToBuffer(const uint8_t *inBuffer, size_t inBufferLen) {
+    // mBufferPos should be no larger than mBufferDataSize
+    if (inBufferLen > SIZE_MAX - (mBufferDataSize - mBufferPos)) {
+        ALOGE("addDataToBuffer: input buffer is too large");
+        return ERROR_MALFORMED;
+    }
+
+    if (inBufferLen > mBufferLen - mBufferDataSize) {
+        if (mBufferPos > 0) {
+            memmove(mBuffer, mBuffer + mBufferPos, mBufferDataSize - mBufferPos);
+            mBufferDataSize -= mBufferPos;
+            mBufferPos = 0;
+        }
+        if (inBufferLen > mBufferLen - mBufferDataSize) {
+            mBuffer = (uint8_t*)realloc(mBuffer, mBufferDataSize + inBufferLen);
+            if (mBuffer == nullptr) {
+                mBufferDataSize = 0;
+                mBufferLen = 0;
+                ALOGE("decodeOneFrame: failed to allocate memory for input buffer");
+                return NO_MEMORY;
+            }
+            mBufferLen = mBufferDataSize + inBufferLen;
+        }
+    }
+
+    memcpy(mBuffer + mBufferDataSize, inBuffer, inBufferLen);
+    mBufferDataSize += inBufferLen;
+    return OK;
+}
+
+}  // namespace android
diff --git a/media/libstagefright/flac/dec/FLACDecoder.h b/media/libstagefright/flac/dec/FLACDecoder.h
new file mode 100644
index 0000000..36282a8
--- /dev/null
+++ b/media/libstagefright/flac/dec/FLACDecoder.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef FLAC_DECODER_H_
+#define FLAC_DECODER_H_
+
+#include <media/stagefright/foundation/ABase.h>
+#include <utils/RefBase.h>
+#include <utils/String8.h>
+
+#include "FLAC/stream_decoder.h"
+
+namespace android {
+
+// packet based FLAC decoder, wrapps libFLAC stream decoder.
+class FLACDecoder : public RefBase {
+
+public:
+    enum {
+        kMaxChannels = 8,
+    };
+
+    static sp<FLACDecoder> Create();
+
+    FLAC__StreamMetadata_StreamInfo getStreamInfo() const {
+        return mStreamInfo;
+    }
+
+    status_t parseMetadata(const uint8_t *inBuffer, size_t inBufferLen);
+    status_t decodeOneFrame(const uint8_t *inBuffer, size_t inBufferLen,
+            short *outBuffer, size_t *outBufferLen);
+    void flush();
+
+protected:
+    FLACDecoder();
+    virtual ~FLACDecoder() override;
+
+private:
+    // stream properties
+    unsigned getMaxBlockSize() const {
+        return mStreamInfo.max_blocksize;
+    }
+    unsigned getSampleRate() const {
+        return mStreamInfo.sample_rate;
+    }
+    unsigned getChannels() const {
+        return mStreamInfo.channels;
+    }
+    unsigned getBitsPerSample() const {
+        return mStreamInfo.bits_per_sample;
+    }
+    FLAC__uint64 getTotalSamples() const {
+        return mStreamInfo.total_samples;
+    }
+
+    status_t addDataToBuffer(const uint8_t *inBuffer, size_t inBufferLen);
+
+    FLAC__StreamDecoder *mDecoder;
+
+    uint8_t *mBuffer;  // cache input bit stream data
+    size_t mBufferLen;  // the memory size of |mBuffer|
+    size_t mBufferPos;  // next byte to read in |mBuffer|
+    // size of input data stored in |mBuffer|, always started at offset 0
+    size_t mBufferDataSize;
+
+    // cached when the STREAMINFO metadata is parsed by libFLAC
+    FLAC__StreamMetadata_StreamInfo mStreamInfo;
+    bool mStreamInfoValid;
+
+    // cached when a decoded PCM block is "written" by libFLAC decoder
+    bool mWriteRequested;
+    bool mWriteCompleted;
+    FLAC__FrameHeader mWriteHeader;
+    FLAC__int32 const * mWriteBuffer[kMaxChannels];
+
+    // most recent error reported by libFLAC decoder
+    FLAC__StreamDecoderErrorStatus mErrorStatus;
+
+    void (*mCopy)(short *dst, const int *src[kMaxChannels], unsigned nSamples, unsigned nChannels);
+
+    status_t init();
+
+    // FLAC stream decoder callbacks as C++ instance methods
+    FLAC__StreamDecoderReadStatus readCallback(FLAC__byte buffer[], size_t *bytes);
+    FLAC__StreamDecoderWriteStatus writeCallback(
+            const FLAC__Frame *frame, const FLAC__int32 * const buffer[]);
+    void metadataCallback(const FLAC__StreamMetadata *metadata);
+    void errorCallback(FLAC__StreamDecoderErrorStatus status);
+
+    DISALLOW_EVIL_CONSTRUCTORS(FLACDecoder);
+};
+
+}  // namespace android
+
+#endif  // FLAC_DECODER_H_
diff --git a/media/libstagefright/flac/dec/MODULE_LICENSE_APACHE2 b/media/libstagefright/flac/dec/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/media/libstagefright/flac/dec/MODULE_LICENSE_APACHE2
diff --git a/media/libstagefright/flac/dec/NOTICE b/media/libstagefright/flac/dec/NOTICE
new file mode 100644
index 0000000..c5b1efa
--- /dev/null
+++ b/media/libstagefright/flac/dec/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/media/libstagefright/foundation/Android.bp b/media/libstagefright/foundation/Android.bp
index 9b2e7fa..91462c8 100644
--- a/media/libstagefright/foundation/Android.bp
+++ b/media/libstagefright/foundation/Android.bp
@@ -1,5 +1,43 @@
 cc_library_shared {
     name: "libstagefright_foundation",
+    vendor_available: true,
+
+    include_dirs: [
+        "frameworks/av/include",
+        "frameworks/native/include",
+    ],
+
+    local_include_dirs: [
+        "include/media/stagefright/foundation",
+    ],
+
+    export_include_dirs: [
+        "include",
+    ],
+
+    header_libs: [
+        "libhardware_headers",
+    ],
+
+    export_shared_lib_headers: [
+        "libbinder",
+        "libui",
+    ],
+
+    cflags: [
+        "-Wno-multichar",
+        "-Werror",
+        "-Wall",
+    ],
+
+    shared_libs: [
+        "libbinder",
+        "libutils",
+        "libui",
+        "libcutils",
+        "liblog",
+        "libpowermanager",
+    ],
 
     srcs: [
         "AAtomizer.cpp",
@@ -24,27 +62,15 @@
         "hexdump.cpp",
     ],
 
-    include_dirs: ["frameworks/av/include/media/stagefright/foundation"],
+    target: {
+        vendor: {
+            exclude_shared_libs: ["libpowermanager"],
+            exclude_srcs: ["AWakeLock.cpp"],
+        },
+    },
 
-    export_include_dirs: ["include"],
-
-    shared_libs: [
-        "libbinder",
-        "libutils",
-        "libui",
-        "libcutils",
-        "liblog",
-        "libpowermanager",
-    ],
-
-    export_shared_lib_headers: ["libbinder", "libui"],
-
-    cflags: [
-        "-Wno-multichar",
-        "-Werror",
-        "-Wall",
-    ],
     clang: true,
+
     sanitize: {
         misc_undefined: [
             "unsigned-integer-overflow",
@@ -52,7 +78,7 @@
         ],
         cfi: true,
         diag: {
-          cfi: true,
+            cfi: true,
         },
     },
 }
diff --git a/media/libstagefright/foundation/include b/media/libstagefright/foundation/include
deleted file mode 120000
index 3a1af68..0000000
--- a/media/libstagefright/foundation/include
+++ /dev/null
@@ -1 +0,0 @@
-../include/
\ No newline at end of file
diff --git a/media/libstagefright/include/foundation/AAtomizer.h b/media/libstagefright/foundation/include/media/stagefright/foundation/AAtomizer.h
similarity index 100%
rename from media/libstagefright/include/foundation/AAtomizer.h
rename to media/libstagefright/foundation/include/media/stagefright/foundation/AAtomizer.h
diff --git a/media/libstagefright/include/foundation/ABase.h b/media/libstagefright/foundation/include/media/stagefright/foundation/ABase.h
similarity index 100%
rename from media/libstagefright/include/foundation/ABase.h
rename to media/libstagefright/foundation/include/media/stagefright/foundation/ABase.h
diff --git a/media/libstagefright/include/foundation/ABitReader.h b/media/libstagefright/foundation/include/media/stagefright/foundation/ABitReader.h
similarity index 100%
rename from media/libstagefright/include/foundation/ABitReader.h
rename to media/libstagefright/foundation/include/media/stagefright/foundation/ABitReader.h
diff --git a/media/libstagefright/include/foundation/ABuffer.h b/media/libstagefright/foundation/include/media/stagefright/foundation/ABuffer.h
similarity index 100%
rename from media/libstagefright/include/foundation/ABuffer.h
rename to media/libstagefright/foundation/include/media/stagefright/foundation/ABuffer.h
diff --git a/media/libstagefright/include/foundation/AData.h b/media/libstagefright/foundation/include/media/stagefright/foundation/AData.h
similarity index 100%
rename from media/libstagefright/include/foundation/AData.h
rename to media/libstagefright/foundation/include/media/stagefright/foundation/AData.h
diff --git a/media/libstagefright/include/foundation/ADebug.h b/media/libstagefright/foundation/include/media/stagefright/foundation/ADebug.h
similarity index 97%
rename from media/libstagefright/include/foundation/ADebug.h
rename to media/libstagefright/foundation/include/media/stagefright/foundation/ADebug.h
index 9ad45f3..b498c91 100644
--- a/media/libstagefright/include/foundation/ADebug.h
+++ b/media/libstagefright/foundation/include/media/stagefright/foundation/ADebug.h
@@ -53,6 +53,9 @@
 #define LITERAL_TO_STRING_INTERNAL(x)    #x
 #define LITERAL_TO_STRING(x) LITERAL_TO_STRING_INTERNAL(x)
 
+#ifdef CHECK
+#undef CHECK
+#endif
 #define CHECK(condition)                                \
     LOG_ALWAYS_FATAL_IF(                                \
             !(condition),                               \
@@ -92,6 +95,15 @@
         }                                                               \
     } while (false)
 
+#ifdef CHECK_EQ
+#undef CHECK_EQ
+#undef CHECK_NE
+#undef CHECK_LE
+#undef CHECK_LT
+#undef CHECK_GE
+#undef CHECK_GT
+#endif
+
 #define CHECK_EQ(x,y)   CHECK_OP(x,y,EQ,==)
 #define CHECK_NE(x,y)   CHECK_OP(x,y,NE,!=)
 #define CHECK_LE(x,y)   CHECK_OP(x,y,LE,<=)
diff --git a/media/libstagefright/include/foundation/AHandler.h b/media/libstagefright/foundation/include/media/stagefright/foundation/AHandler.h
similarity index 100%
rename from media/libstagefright/include/foundation/AHandler.h
rename to media/libstagefright/foundation/include/media/stagefright/foundation/AHandler.h
diff --git a/media/libstagefright/include/foundation/AHandlerReflector.h b/media/libstagefright/foundation/include/media/stagefright/foundation/AHandlerReflector.h
similarity index 100%
rename from media/libstagefright/include/foundation/AHandlerReflector.h
rename to media/libstagefright/foundation/include/media/stagefright/foundation/AHandlerReflector.h
diff --git a/media/libstagefright/include/foundation/AHierarchicalStateMachine.h b/media/libstagefright/foundation/include/media/stagefright/foundation/AHierarchicalStateMachine.h
similarity index 100%
rename from media/libstagefright/include/foundation/AHierarchicalStateMachine.h
rename to media/libstagefright/foundation/include/media/stagefright/foundation/AHierarchicalStateMachine.h
diff --git a/media/libstagefright/include/foundation/ALookup.h b/media/libstagefright/foundation/include/media/stagefright/foundation/ALookup.h
similarity index 100%
rename from media/libstagefright/include/foundation/ALookup.h
rename to media/libstagefright/foundation/include/media/stagefright/foundation/ALookup.h
diff --git a/media/libstagefright/include/foundation/ALooper.h b/media/libstagefright/foundation/include/media/stagefright/foundation/ALooper.h
similarity index 100%
rename from media/libstagefright/include/foundation/ALooper.h
rename to media/libstagefright/foundation/include/media/stagefright/foundation/ALooper.h
diff --git a/media/libstagefright/include/foundation/ALooperRoster.h b/media/libstagefright/foundation/include/media/stagefright/foundation/ALooperRoster.h
similarity index 100%
rename from media/libstagefright/include/foundation/ALooperRoster.h
rename to media/libstagefright/foundation/include/media/stagefright/foundation/ALooperRoster.h
diff --git a/media/libstagefright/include/foundation/AMessage.h b/media/libstagefright/foundation/include/media/stagefright/foundation/AMessage.h
similarity index 100%
rename from media/libstagefright/include/foundation/AMessage.h
rename to media/libstagefright/foundation/include/media/stagefright/foundation/AMessage.h
diff --git a/media/libstagefright/include/foundation/ANetworkSession.h b/media/libstagefright/foundation/include/media/stagefright/foundation/ANetworkSession.h
similarity index 100%
rename from media/libstagefright/include/foundation/ANetworkSession.h
rename to media/libstagefright/foundation/include/media/stagefright/foundation/ANetworkSession.h
diff --git a/media/libstagefright/include/foundation/AString.h b/media/libstagefright/foundation/include/media/stagefright/foundation/AString.h
similarity index 100%
rename from media/libstagefright/include/foundation/AString.h
rename to media/libstagefright/foundation/include/media/stagefright/foundation/AString.h
diff --git a/media/libstagefright/include/foundation/AStringUtils.h b/media/libstagefright/foundation/include/media/stagefright/foundation/AStringUtils.h
similarity index 100%
rename from media/libstagefright/include/foundation/AStringUtils.h
rename to media/libstagefright/foundation/include/media/stagefright/foundation/AStringUtils.h
diff --git a/media/libstagefright/include/foundation/AUtils.h b/media/libstagefright/foundation/include/media/stagefright/foundation/AUtils.h
similarity index 100%
rename from media/libstagefright/include/foundation/AUtils.h
rename to media/libstagefright/foundation/include/media/stagefright/foundation/AUtils.h
diff --git a/media/libstagefright/include/foundation/AWakeLock.h b/media/libstagefright/foundation/include/media/stagefright/foundation/AWakeLock.h
similarity index 100%
rename from media/libstagefright/include/foundation/AWakeLock.h
rename to media/libstagefright/foundation/include/media/stagefright/foundation/AWakeLock.h
diff --git a/media/libstagefright/include/foundation/ColorUtils.h b/media/libstagefright/foundation/include/media/stagefright/foundation/ColorUtils.h
similarity index 100%
rename from media/libstagefright/include/foundation/ColorUtils.h
rename to media/libstagefright/foundation/include/media/stagefright/foundation/ColorUtils.h
diff --git a/media/libstagefright/include/foundation/FileDescriptor.h b/media/libstagefright/foundation/include/media/stagefright/foundation/FileDescriptor.h
similarity index 100%
rename from media/libstagefright/include/foundation/FileDescriptor.h
rename to media/libstagefright/foundation/include/media/stagefright/foundation/FileDescriptor.h
diff --git a/media/libstagefright/include/foundation/Flagged.h b/media/libstagefright/foundation/include/media/stagefright/foundation/Flagged.h
similarity index 100%
rename from media/libstagefright/include/foundation/Flagged.h
rename to media/libstagefright/foundation/include/media/stagefright/foundation/Flagged.h
diff --git a/media/libstagefright/include/foundation/MediaBufferBase.h b/media/libstagefright/foundation/include/media/stagefright/foundation/MediaBufferBase.h
similarity index 100%
rename from media/libstagefright/include/foundation/MediaBufferBase.h
rename to media/libstagefright/foundation/include/media/stagefright/foundation/MediaBufferBase.h
diff --git a/media/libstagefright/include/foundation/Mutexed.h b/media/libstagefright/foundation/include/media/stagefright/foundation/Mutexed.h
similarity index 100%
rename from media/libstagefright/include/foundation/Mutexed.h
rename to media/libstagefright/foundation/include/media/stagefright/foundation/Mutexed.h
diff --git a/media/libstagefright/include/foundation/ParsedMessage.h b/media/libstagefright/foundation/include/media/stagefright/foundation/ParsedMessage.h
similarity index 100%
rename from media/libstagefright/include/foundation/ParsedMessage.h
rename to media/libstagefright/foundation/include/media/stagefright/foundation/ParsedMessage.h
diff --git a/media/libstagefright/include/foundation/TypeTraits.h b/media/libstagefright/foundation/include/media/stagefright/foundation/TypeTraits.h
similarity index 100%
rename from media/libstagefright/include/foundation/TypeTraits.h
rename to media/libstagefright/foundation/include/media/stagefright/foundation/TypeTraits.h
diff --git a/media/libstagefright/include/foundation/base64.h b/media/libstagefright/foundation/include/media/stagefright/foundation/base64.h
similarity index 100%
rename from media/libstagefright/include/foundation/base64.h
rename to media/libstagefright/foundation/include/media/stagefright/foundation/base64.h
diff --git a/media/libstagefright/include/foundation/hexdump.h b/media/libstagefright/foundation/include/media/stagefright/foundation/hexdump.h
similarity index 100%
rename from media/libstagefright/include/foundation/hexdump.h
rename to media/libstagefright/foundation/include/media/stagefright/foundation/hexdump.h
diff --git a/media/libstagefright/http/Android.bp b/media/libstagefright/http/Android.bp
new file mode 100644
index 0000000..5d90b0a
--- /dev/null
+++ b/media/libstagefright/http/Android.bp
@@ -0,0 +1,43 @@
+cc_library_shared {
+    name: "libstagefright_http_support",
+
+    srcs: ["HTTPHelper.cpp"],
+
+    include_dirs: [
+        "frameworks/av/media/libstagefright",
+        "frameworks/native/include/media/openmax",
+        "frameworks/base/core/jni",
+    ],
+
+    shared_libs: [
+        "liblog",
+        "libutils",
+        "libbinder",
+        "libandroid_runtime",
+        "libmedia",
+    ],
+
+    export_include_dirs: ["."],
+
+    cflags: [
+        "-Wno-multichar",
+        "-Werror",
+        "-Wall",
+    ],
+
+    sanitize: {
+        misc_undefined: [
+            "signed-integer-overflow",
+        ],
+        cfi: true,
+        diag: {
+            cfi: true,
+        },
+    },
+
+    product_variables: {
+        pdk: {
+            enabled: false,
+        },
+    },
+}
diff --git a/media/libstagefright/http/Android.mk b/media/libstagefright/http/Android.mk
deleted file mode 100644
index 9c16f40..0000000
--- a/media/libstagefright/http/Android.mk
+++ /dev/null
@@ -1,30 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-ifneq ($(TARGET_BUILD_PDK), true)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:=       \
-        HTTPHelper.cpp          \
-
-LOCAL_C_INCLUDES:= \
-	$(TOP)/frameworks/av/media/libstagefright \
-	$(TOP)/frameworks/native/include/media/openmax \
-	$(TOP)/frameworks/base/core/jni \
-
-LOCAL_SHARED_LIBRARIES := \
-    liblog libutils libbinder \
-    libandroid_runtime \
-    libmedia
-
-LOCAL_MODULE:= libstagefright_http_support
-
-LOCAL_CFLAGS += -Wno-multichar
-
-LOCAL_CFLAGS += -Werror -Wall
-LOCAL_SANITIZE := signed-integer-overflow cfi
-LOCAL_SANITIZE_DIAG := cfi
-
-include $(BUILD_SHARED_LIBRARY)
-
-endif
diff --git a/media/libstagefright/httplive/Android.bp b/media/libstagefright/httplive/Android.bp
new file mode 100644
index 0000000..e415334
--- /dev/null
+++ b/media/libstagefright/httplive/Android.bp
@@ -0,0 +1,43 @@
+cc_library_shared {
+    name: "libstagefright_httplive",
+
+    srcs: [
+        "HTTPDownloader.cpp",
+        "LiveDataSource.cpp",
+        "LiveSession.cpp",
+        "M3UParser.cpp",
+        "PlaylistFetcher.cpp",
+    ],
+
+    include_dirs: [
+        "frameworks/av/media/libstagefright",
+        "frameworks/native/include/media/openmax",
+    ],
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+    ],
+
+    sanitize: {
+        misc_undefined: [
+            "signed-integer-overflow",
+            "unsigned-integer-overflow",
+        ],
+        cfi: true,
+        diag: {
+            cfi: true,
+        },
+    },
+
+    shared_libs: [
+        "liblog",
+        "libbinder",
+        "libcrypto",
+        "libcutils",
+        "libmedia",
+        "libstagefright",
+        "libstagefright_foundation",
+        "libutils",
+    ],
+}
diff --git a/media/libstagefright/httplive/Android.mk b/media/libstagefright/httplive/Android.mk
deleted file mode 100644
index 1903d10..0000000
--- a/media/libstagefright/httplive/Android.mk
+++ /dev/null
@@ -1,36 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:=               \
-        HTTPDownloader.cpp      \
-        LiveDataSource.cpp      \
-        LiveSession.cpp         \
-        M3UParser.cpp           \
-        PlaylistFetcher.cpp     \
-
-LOCAL_C_INCLUDES:= \
-	$(TOP)/frameworks/av/media/libstagefright \
-	$(TOP)/frameworks/native/include/media/openmax
-
-LOCAL_CFLAGS += -Werror -Wall
-LOCAL_SANITIZE := unsigned-integer-overflow signed-integer-overflow cfi
-LOCAL_SANITIZE_DIAG := cfi
-
-LOCAL_SHARED_LIBRARIES := \
-        liblog \
-        libbinder \
-        libcrypto \
-        libcutils \
-        libmedia \
-        libstagefright \
-        libstagefright_foundation \
-        libutils \
-
-LOCAL_MODULE:= libstagefright_httplive
-
-ifeq ($(TARGET_ARCH),arm)
-    LOCAL_CFLAGS += -Wno-psabi
-endif
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp
index e144942..143fd59 100644
--- a/media/libstagefright/httplive/LiveSession.cpp
+++ b/media/libstagefright/httplive/LiveSession.cpp
@@ -699,7 +699,7 @@
                     }
 
                     if (mContinuation != NULL) {
-                        CHECK_GT(mContinuationCounter, 0);
+                        CHECK_GT(mContinuationCounter, 0u);
                         if (--mContinuationCounter == 0) {
                             mContinuation->post();
                         }
@@ -1550,7 +1550,7 @@
                     mOrigBandwidthIndex, mCurBandwidthIndex);
         }
     }
-    CHECK_LT(mCurBandwidthIndex, mBandwidthItems.size());
+    CHECK_LT((size_t)mCurBandwidthIndex, mBandwidthItems.size());
     const BandwidthItem &item = mBandwidthItems.itemAt(mCurBandwidthIndex);
 
     uint32_t streamMask = 0; // streams that should be fetched by the new fetcher
diff --git a/media/libstagefright/id3/Android.bp b/media/libstagefright/id3/Android.bp
new file mode 100644
index 0000000..30008d9
--- /dev/null
+++ b/media/libstagefright/id3/Android.bp
@@ -0,0 +1,53 @@
+cc_library_static {
+    name: "libstagefright_id3",
+
+    srcs: ["ID3.cpp"],
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+    ],
+    sanitize: {
+        misc_undefined: [
+            "signed-integer-overflow",
+        ],
+        cfi: true,
+        diag: {
+            cfi: true,
+        },
+    },
+
+    shared_libs: ["libmedia"],
+}
+
+//###############################################################################
+
+cc_test {
+    name: "testid3",
+    gtest: false,
+
+    srcs: ["testid3.cpp"],
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+    ],
+
+    shared_libs: [
+        "libstagefright",
+        "libutils",
+        "liblog",
+        "libbinder",
+        "libstagefright_foundation",
+    ],
+
+    static_libs: ["libstagefright_id3"],
+
+    sanitize: {
+        cfi: true,
+        diag: {
+            cfi: true,
+        },
+    },
+
+}
diff --git a/media/libstagefright/id3/Android.mk b/media/libstagefright/id3/Android.mk
deleted file mode 100644
index 827703e..0000000
--- a/media/libstagefright/id3/Android.mk
+++ /dev/null
@@ -1,36 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
-	ID3.cpp
-
-LOCAL_CFLAGS += -Werror -Wall
-LOCAL_SANITIZE := unsigned-integer-overflow signed-integer-overflow cfi
-LOCAL_SANITIZE_DIAG := cfi
-
-LOCAL_SHARED_LIBRARIES := libmedia
-
-LOCAL_MODULE := libstagefright_id3
-
-include $(BUILD_STATIC_LIBRARY)
-
-################################################################################
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
-	testid3.cpp
-
-LOCAL_CFLAGS += -Werror -Wall
-
-LOCAL_SHARED_LIBRARIES := \
-	libstagefright libutils liblog libbinder libstagefright_foundation
-
-LOCAL_STATIC_LIBRARIES := \
-        libstagefright_id3
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_MODULE := testid3
-
-include $(BUILD_EXECUTABLE)
diff --git a/media/libstagefright/include/SoftVideoEncoderOMXComponent.h b/media/libstagefright/include/SoftVideoEncoderOMXComponent.h
index 02555a2..2d6f31b 100644
--- a/media/libstagefright/include/SoftVideoEncoderOMXComponent.h
+++ b/media/libstagefright/include/SoftVideoEncoderOMXComponent.h
@@ -21,7 +21,6 @@
 #include <media/IOMX.h>
 
 #include "SimpleSoftOMXComponent.h"
-#include <system/window.h>
 
 struct hw_module_t;
 
diff --git a/media/libstagefright/include/AACWriter.h b/media/libstagefright/include/media/stagefright/AACWriter.h
similarity index 100%
rename from media/libstagefright/include/AACWriter.h
rename to media/libstagefright/include/media/stagefright/AACWriter.h
diff --git a/media/libstagefright/include/ACodec.h b/media/libstagefright/include/media/stagefright/ACodec.h
similarity index 99%
rename from media/libstagefright/include/ACodec.h
rename to media/libstagefright/include/media/stagefright/ACodec.h
index 22b8657..d049df5 100644
--- a/media/libstagefright/include/ACodec.h
+++ b/media/libstagefright/include/media/stagefright/ACodec.h
@@ -15,7 +15,6 @@
  */
 
 #ifndef A_CODEC_H_
-
 #define A_CODEC_H_
 
 #include <stdint.h>
@@ -30,6 +29,7 @@
 #include <utils/NativeHandle.h>
 #include <OMX_Audio.h>
 #include <hardware/gralloc.h>
+#include <nativebase/nativebase.h>
 
 #define TRACK_BUFFER_TIMING     0
 
diff --git a/media/libstagefright/include/AMRWriter.h b/media/libstagefright/include/media/stagefright/AMRWriter.h
similarity index 100%
rename from media/libstagefright/include/AMRWriter.h
rename to media/libstagefright/include/media/stagefright/AMRWriter.h
diff --git a/media/libstagefright/include/AudioPlayer.h b/media/libstagefright/include/media/stagefright/AudioPlayer.h
similarity index 100%
rename from media/libstagefright/include/AudioPlayer.h
rename to media/libstagefright/include/media/stagefright/AudioPlayer.h
diff --git a/media/libstagefright/include/AudioSource.h b/media/libstagefright/include/media/stagefright/AudioSource.h
similarity index 95%
rename from media/libstagefright/include/AudioSource.h
rename to media/libstagefright/include/media/stagefright/AudioSource.h
index f20c2cd..1595be4 100644
--- a/media/libstagefright/include/AudioSource.h
+++ b/media/libstagefright/include/media/stagefright/AudioSource.h
@@ -53,6 +53,7 @@
 
     virtual status_t read(
             MediaBuffer **buffer, const ReadOptions *options = NULL);
+    virtual status_t setStopTimeUs(int64_t stopTimeUs);
 
     status_t dataCallback(const AudioRecord::Buffer& buffer);
     virtual void signalBufferReturned(MediaBuffer *buffer);
@@ -85,6 +86,8 @@
 
     bool mTrackMaxAmplitude;
     int64_t mStartTimeUs;
+    int64_t mStopSystemTimeUs;
+    int64_t mLastFrameTimestampUs;
     int16_t mMaxAmplitude;
     int64_t mPrevSampleTimeUs;
     int64_t mInitialReadTimeUs;
@@ -92,6 +95,7 @@
     int64_t mNumFramesSkipped;
     int64_t mNumFramesLost;
     int64_t mNumClientOwnedBuffers;
+    bool mNoMoreFramesToRead;
 
     List<MediaBuffer * > mBuffersReceived;
 
diff --git a/media/libstagefright/include/BufferProducerWrapper.h b/media/libstagefright/include/media/stagefright/BufferProducerWrapper.h
similarity index 100%
rename from media/libstagefright/include/BufferProducerWrapper.h
rename to media/libstagefright/include/media/stagefright/BufferProducerWrapper.h
diff --git a/media/libstagefright/include/CameraSource.h b/media/libstagefright/include/media/stagefright/CameraSource.h
similarity index 99%
rename from media/libstagefright/include/CameraSource.h
rename to media/libstagefright/include/media/stagefright/CameraSource.h
index aa56d27..2aaa884 100644
--- a/media/libstagefright/include/CameraSource.h
+++ b/media/libstagefright/include/media/stagefright/CameraSource.h
@@ -98,6 +98,7 @@
     virtual status_t stop() { return reset(); }
     virtual status_t read(
             MediaBuffer **buffer, const ReadOptions *options = NULL);
+    virtual status_t setStopTimeUs(int64_t stopTimeUs);
 
     /**
      * Check whether a CameraSource object is properly initialized.
@@ -253,6 +254,7 @@
     List<int64_t> mFrameTimes;
 
     int64_t mFirstFrameTimeUs;
+    int64_t mStopSystemTimeUs;
     int32_t mNumFramesDropped;
     int32_t mNumGlitches;
     int64_t mGlitchDurationThresholdUs;
diff --git a/media/libstagefright/include/CameraSourceTimeLapse.h b/media/libstagefright/include/media/stagefright/CameraSourceTimeLapse.h
similarity index 100%
rename from media/libstagefright/include/CameraSourceTimeLapse.h
rename to media/libstagefright/include/media/stagefright/CameraSourceTimeLapse.h
diff --git a/media/libstagefright/include/CodecBase.h b/media/libstagefright/include/media/stagefright/CodecBase.h
similarity index 99%
rename from media/libstagefright/include/CodecBase.h
rename to media/libstagefright/include/media/stagefright/CodecBase.h
index 845146d..0dd77ba 100644
--- a/media/libstagefright/include/CodecBase.h
+++ b/media/libstagefright/include/media/stagefright/CodecBase.h
@@ -40,7 +40,7 @@
 namespace android {
 using namespace media;
 class BufferChannelBase;
-class BufferProducerWrapper;
+struct BufferProducerWrapper;
 class MediaCodecBuffer;
 struct PersistentSurface;
 struct RenderedFrameInfo;
diff --git a/media/libstagefright/include/ColorConverter.h b/media/libstagefright/include/media/stagefright/ColorConverter.h
similarity index 100%
rename from media/libstagefright/include/ColorConverter.h
rename to media/libstagefright/include/media/stagefright/ColorConverter.h
diff --git a/media/libstagefright/include/DataSource.h b/media/libstagefright/include/media/stagefright/DataSource.h
similarity index 98%
rename from media/libstagefright/include/DataSource.h
rename to media/libstagefright/include/media/stagefright/DataSource.h
index 8f2c7eb..63eccea 100644
--- a/media/libstagefright/include/DataSource.h
+++ b/media/libstagefright/include/media/stagefright/DataSource.h
@@ -156,7 +156,7 @@
         if (numBytesRead == -1) { // If readAt() returns -1, there is an error.
             return false;
         }
-        if (numBytesRead < numBytesPerChunk) {
+        if (static_cast<size_t>(numBytesRead) < numBytesPerChunk) {
             // This case is triggered when the stream ends before the whole
             // chunk is read.
             x->appendArray(tmp, (size_t)numBytesRead / sizeof(T));
diff --git a/media/libstagefright/include/DataURISource.h b/media/libstagefright/include/media/stagefright/DataURISource.h
similarity index 100%
rename from media/libstagefright/include/DataURISource.h
rename to media/libstagefright/include/media/stagefright/DataURISource.h
diff --git a/media/libstagefright/include/DataUriSource.h b/media/libstagefright/include/media/stagefright/DataUriSource.h
similarity index 100%
rename from media/libstagefright/include/DataUriSource.h
rename to media/libstagefright/include/media/stagefright/DataUriSource.h
diff --git a/media/libstagefright/include/FileSource.h b/media/libstagefright/include/media/stagefright/FileSource.h
similarity index 100%
rename from media/libstagefright/include/FileSource.h
rename to media/libstagefright/include/media/stagefright/FileSource.h
diff --git a/media/libstagefright/include/FrameRenderTracker.h b/media/libstagefright/include/media/stagefright/FrameRenderTracker.h
similarity index 99%
rename from media/libstagefright/include/FrameRenderTracker.h
rename to media/libstagefright/include/media/stagefright/FrameRenderTracker.h
index 6cbf85d..044699c 100644
--- a/media/libstagefright/include/FrameRenderTracker.h
+++ b/media/libstagefright/include/media/stagefright/FrameRenderTracker.h
@@ -20,13 +20,14 @@
 
 #include <utils/RefBase.h>
 #include <utils/Timers.h>
-#include <system/window.h>
 
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AString.h>
 
 #include <list>
 
+struct ANativeWindowBuffer;
+
 namespace android {
 
 class Fence;
diff --git a/media/libstagefright/include/JPEGSource.h b/media/libstagefright/include/media/stagefright/JPEGSource.h
similarity index 100%
rename from media/libstagefright/include/JPEGSource.h
rename to media/libstagefright/include/media/stagefright/JPEGSource.h
diff --git a/media/libstagefright/include/MPEG2TSWriter.h b/media/libstagefright/include/media/stagefright/MPEG2TSWriter.h
similarity index 100%
rename from media/libstagefright/include/MPEG2TSWriter.h
rename to media/libstagefright/include/media/stagefright/MPEG2TSWriter.h
diff --git a/media/libstagefright/include/MPEG4Writer.h b/media/libstagefright/include/media/stagefright/MPEG4Writer.h
similarity index 98%
rename from media/libstagefright/include/MPEG4Writer.h
rename to media/libstagefright/include/media/stagefright/MPEG4Writer.h
index 39e7d01..dd357cc 100644
--- a/media/libstagefright/include/MPEG4Writer.h
+++ b/media/libstagefright/include/media/stagefright/MPEG4Writer.h
@@ -29,7 +29,7 @@
 
 namespace android {
 
-class AMessage;
+struct AMessage;
 class MediaBuffer;
 class MetaData;
 
@@ -83,6 +83,10 @@
         kWhatSwitch                          = 'swch',
     };
 
+    enum {
+        kMaxCttsOffsetTimeUs = 1000000LL,  // 1 second
+    };
+
     int  mFd;
     int mNextFd;
     sp<MetaData> mStartMeta;
diff --git a/media/libstagefright/include/MediaAdapter.h b/media/libstagefright/include/media/stagefright/MediaAdapter.h
similarity index 100%
rename from media/libstagefright/include/MediaAdapter.h
rename to media/libstagefright/include/media/stagefright/MediaAdapter.h
diff --git a/media/libstagefright/include/MediaBuffer.h b/media/libstagefright/include/media/stagefright/MediaBuffer.h
similarity index 98%
rename from media/libstagefright/include/MediaBuffer.h
rename to media/libstagefright/include/media/stagefright/MediaBuffer.h
index 2c0ebe7..e74410d 100644
--- a/media/libstagefright/include/MediaBuffer.h
+++ b/media/libstagefright/include/media/stagefright/MediaBuffer.h
@@ -223,7 +223,7 @@
         // Caution: atomic_int_fast32_t is 64 bits on LP64.
         std::atomic_int_least32_t mFlags;
         std::atomic_int_least32_t mRemoteRefcount;
-        int32_t unused[6]; // additional buffer space
+        int32_t unused[6] __attribute__((__unused__)); // additional buffer space
     };
 
     inline SharedControl *getSharedControl() const {
diff --git a/media/libstagefright/include/MediaBufferGroup.h b/media/libstagefright/include/media/stagefright/MediaBufferGroup.h
similarity index 100%
rename from media/libstagefright/include/MediaBufferGroup.h
rename to media/libstagefright/include/media/stagefright/MediaBufferGroup.h
diff --git a/media/libstagefright/include/MediaClock.h b/media/libstagefright/include/media/stagefright/MediaClock.h
similarity index 100%
rename from media/libstagefright/include/MediaClock.h
rename to media/libstagefright/include/media/stagefright/MediaClock.h
diff --git a/media/libstagefright/include/MediaCodec.h b/media/libstagefright/include/media/stagefright/MediaCodec.h
similarity index 100%
rename from media/libstagefright/include/MediaCodec.h
rename to media/libstagefright/include/media/stagefright/MediaCodec.h
diff --git a/media/libstagefright/include/MediaCodecList.h b/media/libstagefright/include/media/stagefright/MediaCodecList.h
similarity index 100%
rename from media/libstagefright/include/MediaCodecList.h
rename to media/libstagefright/include/media/stagefright/MediaCodecList.h
diff --git a/media/libstagefright/include/MediaCodecSource.h b/media/libstagefright/include/media/stagefright/MediaCodecSource.h
similarity index 91%
rename from media/libstagefright/include/MediaCodecSource.h
rename to media/libstagefright/include/media/stagefright/MediaCodecSource.h
index 5e99b78..3ac539e 100644
--- a/media/libstagefright/include/MediaCodecSource.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodecSource.h
@@ -54,11 +54,14 @@
     // MediaSource
     virtual status_t start(MetaData *params = NULL);
     virtual status_t stop();
-    virtual status_t pause(MetaData *params = NULL);
+    virtual status_t pause() { return pause(NULL); }
+    virtual status_t pause(MetaData *params);
     virtual sp<MetaData> getFormat();
     virtual status_t read(
             MediaBuffer **buffer,
             const ReadOptions *options = NULL);
+    virtual status_t setStopTimeUs(int64_t stopTimeUs);
+
 
     // MediaBufferObserver
     virtual void signalBufferReturned(MediaBuffer *buffer);
@@ -66,11 +69,7 @@
     // for AHandlerReflector
     void onMessageReceived(const sp<AMessage> &msg);
 
-    // Set GraphicBufferSource stop time. GraphicBufferSource will stop
-    // after receiving a buffer with timestamp larger or equal than stopTimeUs.
-    // All the buffers with timestamp larger or equal to stopTimeUs will be
-    // discarded. stopTimeUs uses SYSTEM_TIME_MONOTONIC time base.
-    status_t setStopStimeUs(int64_t stopTimeUs);
+
 
 protected:
     virtual ~MediaCodecSource();
@@ -85,7 +84,7 @@
         kWhatStop,
         kWhatPause,
         kWhatSetInputBufferTimeOffset,
-        kWhatSetStopTimeOffset,
+        kWhatSetStopTimeUs,
         kWhatGetFirstSampleSystemTimeUs,
         kWhatStopStalled,
     };
diff --git a/media/libstagefright/include/MediaDefs.h b/media/libstagefright/include/media/stagefright/MediaDefs.h
similarity index 100%
rename from media/libstagefright/include/MediaDefs.h
rename to media/libstagefright/include/media/stagefright/MediaDefs.h
diff --git a/media/libstagefright/include/MediaErrors.h b/media/libstagefright/include/media/stagefright/MediaErrors.h
similarity index 100%
rename from media/libstagefright/include/MediaErrors.h
rename to media/libstagefright/include/media/stagefright/MediaErrors.h
diff --git a/media/libstagefright/include/MediaExtractor.h b/media/libstagefright/include/media/stagefright/MediaExtractor.h
similarity index 97%
rename from media/libstagefright/include/MediaExtractor.h
rename to media/libstagefright/include/media/stagefright/MediaExtractor.h
index 073391f..a856b2b 100644
--- a/media/libstagefright/include/MediaExtractor.h
+++ b/media/libstagefright/include/media/stagefright/MediaExtractor.h
@@ -70,7 +70,7 @@
     }
     virtual void setUID(uid_t /*uid*/) {
     }
-    virtual status_t setMediaCas(const sp<ICas> &cas) override {
+    virtual status_t setMediaCas(const sp<ICas>& /*cas*/) override {
         return INVALID_OPERATION;
     }
 
diff --git a/media/libstagefright/include/MediaFilter.h b/media/libstagefright/include/media/stagefright/MediaFilter.h
similarity index 100%
rename from media/libstagefright/include/MediaFilter.h
rename to media/libstagefright/include/media/stagefright/MediaFilter.h
diff --git a/media/libstagefright/include/MediaHTTP.h b/media/libstagefright/include/media/stagefright/MediaHTTP.h
similarity index 100%
rename from media/libstagefright/include/MediaHTTP.h
rename to media/libstagefright/include/media/stagefright/MediaHTTP.h
diff --git a/media/libstagefright/include/MediaMuxer.h b/media/libstagefright/include/media/stagefright/MediaMuxer.h
similarity index 100%
rename from media/libstagefright/include/MediaMuxer.h
rename to media/libstagefright/include/media/stagefright/MediaMuxer.h
diff --git a/media/libstagefright/include/MediaSource.h b/media/libstagefright/include/media/stagefright/MediaSource.h
similarity index 73%
rename from media/libstagefright/include/MediaSource.h
rename to media/libstagefright/include/media/stagefright/MediaSource.h
index 1bd3ed0..14adb05 100644
--- a/media/libstagefright/include/MediaSource.h
+++ b/media/libstagefright/include/media/stagefright/MediaSource.h
@@ -75,6 +75,23 @@
         return ERROR_UNSUPPORTED;
     }
 
+    // The consumer of this media source requests the source stops sending
+    // buffers with timestamp larger than or equal to stopTimeUs. stopTimeUs
+    // must be in the same time base as the startTime passed in start(). If
+    // source does not support this request, ERROR_UNSUPPORTED will be returned.
+    // If stopTimeUs is invalid, BAD_VALUE will be returned. This could be
+    // called at any time even before source starts and it could be called
+    // multiple times. Setting stopTimeUs to be -1 will effectively cancel the stopTimeUs
+    // set previously. If stopTimeUs is larger than or equal to last buffer's timestamp,
+    // source will start to drop buffer when it gets a buffer with timestamp larger
+    // than or equal to stopTimeUs. If stopTimeUs is smaller than or equal to last
+    // buffer's timestamp, source will drop all the incoming buffers immediately.
+    // After setting stopTimeUs, source may still stop sending buffers with timestamp
+    // less than stopTimeUs if it is stopped by the consumer.
+    virtual status_t setStopTimeUs(int64_t /* stopTimeUs */) {
+        return ERROR_UNSUPPORTED;
+    }
+
 protected:
     virtual ~MediaSource();
 
diff --git a/media/libstagefright/include/MediaSync.h b/media/libstagefright/include/media/stagefright/MediaSync.h
similarity index 100%
rename from media/libstagefright/include/MediaSync.h
rename to media/libstagefright/include/media/stagefright/MediaSync.h
diff --git a/media/libstagefright/include/MediaWriter.h b/media/libstagefright/include/media/stagefright/MediaWriter.h
similarity index 96%
rename from media/libstagefright/include/MediaWriter.h
rename to media/libstagefright/include/media/stagefright/MediaWriter.h
index 9c30ffa..cd4af4d 100644
--- a/media/libstagefright/include/MediaWriter.h
+++ b/media/libstagefright/include/media/stagefright/MediaWriter.h
@@ -50,7 +50,7 @@
 
     virtual void setStartTimeOffsetMs(int /*ms*/) {}
     virtual int32_t getStartTimeOffsetMs() const { return 0; }
-    virtual status_t setNextFd(int fd) { return INVALID_OPERATION; }
+    virtual status_t setNextFd(int /*fd*/) { return INVALID_OPERATION; }
 
 protected:
     virtual ~MediaWriter() {}
diff --git a/media/libstagefright/include/MetaData.h b/media/libstagefright/include/media/stagefright/MetaData.h
similarity index 99%
rename from media/libstagefright/include/MetaData.h
rename to media/libstagefright/include/media/stagefright/MetaData.h
index 7afd22d..9676b97 100644
--- a/media/libstagefright/include/MetaData.h
+++ b/media/libstagefright/include/media/stagefright/MetaData.h
@@ -64,6 +64,7 @@
     kKeyOpusHeader        = 'ohdr',  // raw data
     kKeyOpusCodecDelay    = 'ocod',  // uint64_t (codec delay in ns)
     kKeyOpusSeekPreRoll   = 'ospr',  // uint64_t (seek preroll in ns)
+    kKeyFlacMetadata      = 'flMd',  // raw data
     kKeyVp9CodecPrivate   = 'vp9p',  // raw data (vp9 csd information)
     kKeyWantsNALFragments = 'NALf',
     kKeyIsSyncFrame       = 'sync',  // int32_t (bool)
diff --git a/media/libstagefright/include/NuMediaExtractor.h b/media/libstagefright/include/media/stagefright/NuMediaExtractor.h
similarity index 100%
rename from media/libstagefright/include/NuMediaExtractor.h
rename to media/libstagefright/include/media/stagefright/NuMediaExtractor.h
diff --git a/media/libstagefright/include/OMXClient.h b/media/libstagefright/include/media/stagefright/OMXClient.h
similarity index 100%
rename from media/libstagefright/include/OMXClient.h
rename to media/libstagefright/include/media/stagefright/OMXClient.h
diff --git a/media/libstagefright/include/PersistentSurface.h b/media/libstagefright/include/media/stagefright/PersistentSurface.h
similarity index 100%
rename from media/libstagefright/include/PersistentSurface.h
rename to media/libstagefright/include/media/stagefright/PersistentSurface.h
diff --git a/media/libstagefright/include/ProcessInfo.h b/media/libstagefright/include/media/stagefright/ProcessInfo.h
similarity index 100%
rename from media/libstagefright/include/ProcessInfo.h
rename to media/libstagefright/include/media/stagefright/ProcessInfo.h
diff --git a/media/libstagefright/include/ProcessInfoInterface.h b/media/libstagefright/include/media/stagefright/ProcessInfoInterface.h
similarity index 100%
rename from media/libstagefright/include/ProcessInfoInterface.h
rename to media/libstagefright/include/media/stagefright/ProcessInfoInterface.h
diff --git a/media/libstagefright/include/RemoteDataSource.h b/media/libstagefright/include/media/stagefright/RemoteDataSource.h
similarity index 100%
rename from media/libstagefright/include/RemoteDataSource.h
rename to media/libstagefright/include/media/stagefright/RemoteDataSource.h
diff --git a/media/libstagefright/include/RenderScriptWrapper.h b/media/libstagefright/include/media/stagefright/RenderScriptWrapper.h
similarity index 100%
rename from media/libstagefright/include/RenderScriptWrapper.h
rename to media/libstagefright/include/media/stagefright/RenderScriptWrapper.h
diff --git a/media/libstagefright/include/SimpleDecodingSource.h b/media/libstagefright/include/media/stagefright/SimpleDecodingSource.h
similarity index 93%
rename from media/libstagefright/include/SimpleDecodingSource.h
rename to media/libstagefright/include/media/stagefright/SimpleDecodingSource.h
index e6aee6a..a000fde 100644
--- a/media/libstagefright/include/SimpleDecodingSource.h
+++ b/media/libstagefright/include/media/stagefright/SimpleDecodingSource.h
@@ -17,8 +17,6 @@
 #ifndef SIMPLE_DECODING_SOURCE_H_
 #define SIMPLE_DECODING_SOURCE_H_
 
-#include <system/window.h>
-
 #include <media/stagefright/MediaSource.h>
 #include <media/stagefright/foundation/AString.h>
 #include <media/stagefright/foundation/Mutexed.h>
@@ -26,6 +24,8 @@
 #include <utils/Condition.h>
 #include <utils/StrongPointer.h>
 
+struct ANativeWindow;
+
 namespace android {
 
 struct ALooper;
@@ -45,10 +45,13 @@
     // does not support secure input or pausing.
     // if |desiredCodec| is given, use this specific codec.
     static sp<SimpleDecodingSource> Create(
-            const sp<IMediaSource> &source, uint32_t flags = 0,
-            const sp<ANativeWindow> &nativeWindow = NULL,
+            const sp<IMediaSource> &source, uint32_t flags,
+            const sp<ANativeWindow> &nativeWindow,
             const char *desiredCodec = NULL);
 
+    static sp<SimpleDecodingSource> Create(
+            const sp<IMediaSource> &source, uint32_t flags = 0);
+
     virtual ~SimpleDecodingSource();
 
     // starts this source (and it's underlying source). |params| is ignored.
diff --git a/media/libstagefright/include/SkipCutBuffer.h b/media/libstagefright/include/media/stagefright/SkipCutBuffer.h
similarity index 100%
rename from media/libstagefright/include/SkipCutBuffer.h
rename to media/libstagefright/include/media/stagefright/SkipCutBuffer.h
diff --git a/media/libstagefright/include/StagefrightMediaScanner.h b/media/libstagefright/include/media/stagefright/StagefrightMediaScanner.h
similarity index 100%
rename from media/libstagefright/include/StagefrightMediaScanner.h
rename to media/libstagefright/include/media/stagefright/StagefrightMediaScanner.h
diff --git a/media/libstagefright/include/SurfaceMediaSource.h b/media/libstagefright/include/media/stagefright/SurfaceMediaSource.h
similarity index 98%
rename from media/libstagefright/include/SurfaceMediaSource.h
rename to media/libstagefright/include/media/stagefright/SurfaceMediaSource.h
index ae19a75..d38c337 100644
--- a/media/libstagefright/include/SurfaceMediaSource.h
+++ b/media/libstagefright/include/media/stagefright/SurfaceMediaSource.h
@@ -106,8 +106,8 @@
     void setFrameAvailableListener(const sp<FrameAvailableListener>& listener);
 
     // dump our state in a String
-    void dump(String8& result) const;
-    void dump(String8& result, const char* prefix, char* buffer,
+    void dumpState(String8& result) const;
+    void dumpState(String8& result, const char* prefix, char* buffer,
                                                     size_t SIZE) const;
 
     // metaDataStoredInVideoBuffers tells the encoder what kind of metadata
diff --git a/media/libstagefright/include/SurfaceUtils.h b/media/libstagefright/include/media/stagefright/SurfaceUtils.h
similarity index 100%
rename from media/libstagefright/include/SurfaceUtils.h
rename to media/libstagefright/include/media/stagefright/SurfaceUtils.h
diff --git a/media/libstagefright/include/Utils.h b/media/libstagefright/include/media/stagefright/Utils.h
similarity index 100%
rename from media/libstagefright/include/Utils.h
rename to media/libstagefright/include/media/stagefright/Utils.h
diff --git a/media/libstagefright/include/VideoFrameScheduler.h b/media/libstagefright/include/media/stagefright/VideoFrameScheduler.h
similarity index 100%
rename from media/libstagefright/include/VideoFrameScheduler.h
rename to media/libstagefright/include/media/stagefright/VideoFrameScheduler.h
diff --git a/media/libstagefright/include/YUVCanvas.h b/media/libstagefright/include/media/stagefright/YUVCanvas.h
similarity index 100%
rename from media/libstagefright/include/YUVCanvas.h
rename to media/libstagefright/include/media/stagefright/YUVCanvas.h
diff --git a/media/libstagefright/include/YUVImage.h b/media/libstagefright/include/media/stagefright/YUVImage.h
similarity index 100%
rename from media/libstagefright/include/YUVImage.h
rename to media/libstagefright/include/media/stagefright/YUVImage.h
diff --git a/media/libstagefright/include/media/stagefright/foundation b/media/libstagefright/include/media/stagefright/foundation
new file mode 120000
index 0000000..b9fd3b3
--- /dev/null
+++ b/media/libstagefright/include/media/stagefright/foundation
@@ -0,0 +1 @@
+../../../foundation/include/media/stagefright/foundation/
\ No newline at end of file
diff --git a/media/libstagefright/matroska/Android.bp b/media/libstagefright/matroska/Android.bp
new file mode 100644
index 0000000..ec2fb4b
--- /dev/null
+++ b/media/libstagefright/matroska/Android.bp
@@ -0,0 +1,35 @@
+cc_library_static {
+    name: "libstagefright_matroska",
+
+    srcs: ["MatroskaExtractor.cpp"],
+
+    include_dirs: [
+        "external/flac/include",
+        "external/libvpx/libwebm",
+        "frameworks/native/include/media/openmax",
+        "frameworks/av/media/libstagefright/flac/dec",
+        "frameworks/av/media/libstagefright/include",
+    ],
+
+    cflags: [
+        "-Wno-multichar",
+        "-Werror",
+        "-Wall",
+    ],
+
+    sanitize: {
+        misc_undefined: [
+            "signed-integer-overflow",
+            "unsigned-integer-overflow",
+        ],
+        cfi: true,
+        diag: {
+            cfi: true,
+        },
+    },
+
+    shared_libs: [
+        "libmedia",
+        "libstagefright_flacdec"
+    ],
+}
diff --git a/media/libstagefright/matroska/Android.mk b/media/libstagefright/matroska/Android.mk
deleted file mode 100644
index 7de5dbe..0000000
--- a/media/libstagefright/matroska/Android.mk
+++ /dev/null
@@ -1,20 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:=                 \
-        MatroskaExtractor.cpp
-
-LOCAL_C_INCLUDES:= \
-        $(TOP)/external/libvpx/libwebm \
-        $(TOP)/frameworks/native/include/media/openmax \
-        $(TOP)/frameworks/av/media/libstagefright/include \
-
-LOCAL_CFLAGS += -Wno-multichar -Werror -Wall
-LOCAL_SANITIZE := unsigned-integer-overflow signed-integer-overflow cfi
-LOCAL_SANITIZE_DIAG := cfi
-
-LOCAL_SHARED_LIBRARIES := libmedia
-
-LOCAL_MODULE:= libstagefright_matroska
-
-include $(BUILD_STATIC_LIBRARY)
diff --git a/media/libstagefright/matroska/MatroskaExtractor.cpp b/media/libstagefright/matroska/MatroskaExtractor.cpp
index 81179d1..813a257 100644
--- a/media/libstagefright/matroska/MatroskaExtractor.cpp
+++ b/media/libstagefright/matroska/MatroskaExtractor.cpp
@@ -18,6 +18,7 @@
 #define LOG_TAG "MatroskaExtractor"
 #include <utils/Log.h>
 
+#include "FLACDecoder.h"
 #include "MatroskaExtractor.h"
 #include "avc_utils.h"
 
@@ -1051,6 +1052,37 @@
     return OK;
 }
 
+static status_t addFlacMetadata(
+        const sp<MetaData> &meta,
+        const void *codecPrivate, size_t codecPrivateSize) {
+    // hexdump(codecPrivate, codecPrivateSize);
+
+    meta->setData(kKeyFlacMetadata, 0, codecPrivate, codecPrivateSize);
+
+    int32_t maxInputSize = 64 << 10;
+    sp<FLACDecoder> flacDecoder = FLACDecoder::Create();
+    if (flacDecoder != NULL
+            && flacDecoder->parseMetadata((const uint8_t*)codecPrivate, codecPrivateSize) == OK) {
+        FLAC__StreamMetadata_StreamInfo streamInfo = flacDecoder->getStreamInfo();
+        maxInputSize = streamInfo.max_framesize;
+        if (maxInputSize == 0) {
+            // In case max framesize is not available, use raw data size as max framesize,
+            // assuming there is no expansion.
+            if (streamInfo.max_blocksize != 0
+                    && streamInfo.channels != 0
+                    && ((streamInfo.bits_per_sample + 7) / 8) >
+                        INT32_MAX / streamInfo.max_blocksize / streamInfo.channels) {
+                return ERROR_MALFORMED;
+            }
+            maxInputSize = ((streamInfo.bits_per_sample + 7) / 8)
+                * streamInfo.max_blocksize * streamInfo.channels;
+        }
+    }
+    meta->setInt32(kKeyMaxInputSize, maxInputSize);
+
+    return OK;
+}
+
 status_t MatroskaExtractor::synthesizeAVCC(TrackInfo *trackInfo, size_t index) {
     BlockIterator iter(this, trackInfo->mTrackNum, index);
     if (iter.eos()) {
@@ -1363,6 +1395,9 @@
                     mSeekPreRollNs = track->GetSeekPreRoll();
                 } else if (!strcmp("A_MPEG/L3", codecID)) {
                     meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG);
+                } else if (!strcmp("A_FLAC", codecID)) {
+                    meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_FLAC);
+                    err = addFlacMetadata(meta, codecPrivate, codecPrivateSize);
                 } else {
                     ALOGW("%s is not supported.", codecID);
                     continue;
diff --git a/media/libstagefright/mpeg2ts/Android.bp b/media/libstagefright/mpeg2ts/Android.bp
new file mode 100644
index 0000000..96eb5bf
--- /dev/null
+++ b/media/libstagefright/mpeg2ts/Android.bp
@@ -0,0 +1,39 @@
+cc_library_static {
+    name: "libstagefright_mpeg2ts",
+
+    srcs: [
+        "AnotherPacketSource.cpp",
+        "ATSParser.cpp",
+        "CasManager.cpp",
+        "ESQueue.cpp",
+        "HlsSampleDecryptor.cpp",
+        "MPEG2PSExtractor.cpp",
+        "MPEG2TSExtractor.cpp",
+    ],
+
+    include_dirs: [
+        "frameworks/av/media/libstagefright",
+        "frameworks/native/include/media/openmax",
+    ],
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+    ],
+
+    sanitize: {
+        misc_undefined: [
+            "unsigned-integer-overflow",
+            "signed-integer-overflow",
+        ],
+        cfi: true,
+        diag: {
+            cfi: true,
+        },
+    },
+
+    shared_libs: [
+        "libcrypto",
+        "libmedia",
+    ],
+}
diff --git a/media/libstagefright/mpeg2ts/Android.mk b/media/libstagefright/mpeg2ts/Android.mk
deleted file mode 100644
index 20acfe7..0000000
--- a/media/libstagefright/mpeg2ts/Android.mk
+++ /dev/null
@@ -1,32 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:=                 \
-        AnotherPacketSource.cpp   \
-        ATSParser.cpp             \
-        CasManager.cpp            \
-        ESQueue.cpp               \
-        HlsSampleDecryptor.cpp    \
-        MPEG2PSExtractor.cpp      \
-        MPEG2TSExtractor.cpp      \
-
-LOCAL_C_INCLUDES:= \
-	$(TOP)/frameworks/av/media/libstagefright \
-	$(TOP)/frameworks/native/include/media/openmax
-
-LOCAL_CFLAGS += -Werror -Wall
-LOCAL_SANITIZE := unsigned-integer-overflow signed-integer-overflow cfi
-LOCAL_SANITIZE_DIAG := cfi
-
-LOCAL_SHARED_LIBRARIES := \
-        libcrypto \
-        libmedia \
-
-LOCAL_MODULE:= libstagefright_mpeg2ts
-
-ifeq ($(TARGET_ARCH),arm)
-    LOCAL_CFLAGS += -Wno-psabi
-endif
-
-include $(BUILD_STATIC_LIBRARY)
diff --git a/media/libstagefright/omx/1.0/Omx.cpp b/media/libstagefright/omx/1.0/Omx.cpp
index 64b2c08..789379a 100644
--- a/media/libstagefright/omx/1.0/Omx.cpp
+++ b/media/libstagefright/omx/1.0/Omx.cpp
@@ -90,46 +90,49 @@
     using ::android::IOMXNode;
     using ::android::IOMXObserver;
 
-    Mutex::Autolock autoLock(mLock);
-    if (mLiveNodes.size() == kMaxNodeInstances) {
-        _hidl_cb(toStatus(NO_MEMORY), nullptr);
-        return Void();
-    }
-
-    sp<OMXNodeInstance> instance = new OMXNodeInstance(
-            this, new LWOmxObserver(observer), name.c_str());
-
-    OMX_COMPONENTTYPE *handle;
-    OMX_ERRORTYPE err = mMaster->makeComponentInstance(
-            name.c_str(), &OMXNodeInstance::kCallbacks,
-            instance.get(), &handle);
-
-    if (err != OMX_ErrorNone) {
-        LOG(ERROR) << "Failed to allocate omx component "
-                "'" << name.c_str() << "' "
-                " err=" << asString(err) <<
-                "(0x" << std::hex << unsigned(err) << ")";
-        _hidl_cb(toStatus(StatusFromOMXError(err)), nullptr);
-        return Void();
-    }
-    instance->setHandle(handle);
-    std::vector<AString> quirkVector;
-    if (mParser.getQuirks(name.c_str(), &quirkVector) == OK) {
-        uint32_t quirks = 0;
-        for (const AString quirk : quirkVector) {
-            if (quirk == "requires-allocate-on-input-ports") {
-                quirks |= kRequiresAllocateBufferOnInputPorts;
-            }
-            if (quirk == "requires-allocate-on-output-ports") {
-                quirks |= kRequiresAllocateBufferOnOutputPorts;
-            }
+    sp<OMXNodeInstance> instance;
+    {
+        Mutex::Autolock autoLock(mLock);
+        if (mLiveNodes.size() == kMaxNodeInstances) {
+            _hidl_cb(toStatus(NO_MEMORY), nullptr);
+            return Void();
         }
-        instance->setQuirks(quirks);
-    }
 
-    mLiveNodes.add(observer.get(), instance);
+        instance = new OMXNodeInstance(
+                this, new LWOmxObserver(observer), name.c_str());
+
+        OMX_COMPONENTTYPE *handle;
+        OMX_ERRORTYPE err = mMaster->makeComponentInstance(
+                name.c_str(), &OMXNodeInstance::kCallbacks,
+                instance.get(), &handle);
+
+        if (err != OMX_ErrorNone) {
+            LOG(ERROR) << "Failed to allocate omx component "
+                    "'" << name.c_str() << "' "
+                    " err=" << asString(err) <<
+                    "(0x" << std::hex << unsigned(err) << ")";
+            _hidl_cb(toStatus(StatusFromOMXError(err)), nullptr);
+            return Void();
+        }
+        instance->setHandle(handle);
+        std::vector<AString> quirkVector;
+        if (mParser.getQuirks(name.c_str(), &quirkVector) == OK) {
+            uint32_t quirks = 0;
+            for (const AString quirk : quirkVector) {
+                if (quirk == "requires-allocate-on-input-ports") {
+                    quirks |= kRequiresAllocateBufferOnInputPorts;
+                }
+                if (quirk == "requires-allocate-on-output-ports") {
+                    quirks |= kRequiresAllocateBufferOnOutputPorts;
+                }
+            }
+            instance->setQuirks(quirks);
+        }
+
+        mLiveNodes.add(observer.get(), instance);
+        mNode2Observer.add(instance.get(), observer.get());
+    }
     observer->linkToDeath(this, 0);
-    mNode2Observer.add(instance.get(), observer.get());
 
     _hidl_cb(toStatus(OK), new TWOmxNode(instance));
     return Void();
diff --git a/media/libstagefright/omx/1.0/WGraphicBufferProducer.cpp b/media/libstagefright/omx/1.0/WGraphicBufferProducer.cpp
index 650db8e..acda060 100644
--- a/media/libstagefright/omx/1.0/WGraphicBufferProducer.cpp
+++ b/media/libstagefright/omx/1.0/WGraphicBufferProducer.cpp
@@ -21,6 +21,7 @@
 #include "WGraphicBufferProducer.h"
 #include "WProducerListener.h"
 #include "Conversion.h"
+#include <system/window.h>
 
 namespace android {
 namespace hardware {
diff --git a/media/libstagefright/omx/1.0/WGraphicBufferSource.cpp b/media/libstagefright/omx/1.0/WGraphicBufferSource.cpp
index e876306..d8540f8 100644
--- a/media/libstagefright/omx/1.0/WGraphicBufferSource.cpp
+++ b/media/libstagefright/omx/1.0/WGraphicBufferSource.cpp
@@ -206,8 +206,10 @@
 
 Return<void> TWGraphicBufferSource::getStopTimeOffsetUs(
         getStopTimeOffsetUs_cb _hidl_cb) {
-    // TODO: Implement this when needed.
-    _hidl_cb(Status::OK, 0);
+    status_t status;
+    int64_t stopTimeOffsetUs;
+    status = mBase->getStopTimeOffsetUs(&stopTimeOffsetUs);
+    _hidl_cb(toStatus(status), stopTimeOffsetUs);
     return Void();
 }
 
diff --git a/media/libstagefright/omx/1.0/WOmxNode.cpp b/media/libstagefright/omx/1.0/WOmxNode.cpp
index d0680fb..6c0abc9 100644
--- a/media/libstagefright/omx/1.0/WOmxNode.cpp
+++ b/media/libstagefright/omx/1.0/WOmxNode.cpp
@@ -50,7 +50,7 @@
     status_t transStatus = toStatusT(mBase->getParameter(
             toRawIndexType(index),
             tParams,
-            [&fnStatus, params, size](
+            [&fnStatus, params](
                     Status status, hidl_vec<uint8_t> const& outParams) {
                 fnStatus = toStatusT(status);
                 std::copy(
@@ -148,7 +148,7 @@
     status_t transStatus = toStatusT(mBase->allocateSecureBuffer(
             portIndex,
             static_cast<uint64_t>(size),
-            [&fnStatus, buffer, buffer_data, native_handle](
+            [&fnStatus, buffer, native_handle](
                     Status status,
                     uint32_t outBuffer,
                     hidl_handle const& outNativeHandle) {
diff --git a/media/libstagefright/omx/Android.bp b/media/libstagefright/omx/Android.bp
new file mode 100644
index 0000000..2d921f9
--- /dev/null
+++ b/media/libstagefright/omx/Android.bp
@@ -0,0 +1,106 @@
+cc_library_shared {
+    name: "libstagefright_omx",
+    vendor_available: true,
+
+    srcs: [
+        "FrameDropper.cpp",
+        "GraphicBufferSource.cpp",
+        "BWGraphicBufferSource.cpp",
+        "OMX.cpp",
+        "OMXMaster.cpp",
+        "OMXNodeInstance.cpp",
+        "OMXUtils.cpp",
+        "SimpleSoftOMXComponent.cpp",
+        "SoftOMXComponent.cpp",
+        "SoftOMXPlugin.cpp",
+        "SoftVideoDecoderOMXComponent.cpp",
+        "SoftVideoEncoderOMXComponent.cpp",
+        "1.0/Omx.cpp",
+        "1.0/OmxStore.cpp",
+        "1.0/WGraphicBufferProducer.cpp",
+        "1.0/WProducerListener.cpp",
+        "1.0/WGraphicBufferSource.cpp",
+        "1.0/WOmxNode.cpp",
+        "1.0/WOmxObserver.cpp",
+        "1.0/WOmxBufferSource.cpp",
+    ],
+
+    include_dirs: [
+        "frameworks/av/include", // for media/vndk/xmlparser/1.0/MediaCodecsXmlParser.h
+        "frameworks/av/include/media/",
+        "frameworks/av/media/libstagefright",
+        "frameworks/av/media/libstagefright/include",
+        "frameworks/native/include", // for media/hardware/MetadataBufferType.h
+        "frameworks/native/include/media/hardware",
+        "frameworks/native/include/media/openmax",
+    ],
+
+    shared_libs: [
+        "libbase",
+        "libbinder",
+        "libmedia_omx",
+        "libutils",
+        "liblog",
+        "libui",
+        "libgui",
+        "libcutils",
+        "libstagefright_foundation",
+        "libdl",
+        "libhidlbase",
+        "libhidlmemory",
+        "libhidltransport",
+        "libnativewindow", // TODO(b/62923479): use header library
+        "libstagefright_xmlparser@1.0",
+        "android.hidl.memory@1.0",
+        "android.hidl.token@1.0-utils",
+        "android.hardware.media@1.0",
+        "android.hardware.media.omx@1.0",
+        "android.hardware.graphics.common@1.0",
+        "android.hardware.graphics.bufferqueue@1.0",
+    ],
+
+    export_shared_lib_headers: ["android.hidl.memory@1.0"],
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+        "-Wno-unused-parameter",
+        "-Wno-documentation",
+    ],
+
+    sanitize: {
+        misc_undefined: [
+            "signed-integer-overflow",
+            "unsigned-integer-overflow",
+        ],
+        cfi: true,
+        diag: {
+            cfi: true,
+        },
+    },
+}
+
+cc_library_static {
+    name: "libstagefright_omx_utils",
+    srcs: ["OMXUtils.cpp"],
+    include_dirs: [
+        "frameworks/av/media/libstagefright",
+        "frameworks/native/include/media/hardware",
+        "frameworks/native/include/media/openmax",
+    ],
+    shared_libs: ["libmedia"],
+    sanitize: {
+        misc_undefined: [
+            "signed-integer-overflow",
+            "unsigned-integer-overflow",
+        ],
+        cfi: true,
+        diag: {
+            cfi: true,
+        },
+    },
+}
+
+//###############################################################################
+
+subdirs = ["tests"]
diff --git a/media/libstagefright/omx/Android.mk b/media/libstagefright/omx/Android.mk
deleted file mode 100644
index 29e2ccc..0000000
--- a/media/libstagefright/omx/Android.mk
+++ /dev/null
@@ -1,69 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:=                          \
-        FrameDropper.cpp                   \
-        GraphicBufferSource.cpp            \
-        BWGraphicBufferSource.cpp          \
-        OMX.cpp                            \
-        OMXMaster.cpp                      \
-        OMXNodeInstance.cpp                \
-        OMXUtils.cpp                       \
-        SimpleSoftOMXComponent.cpp         \
-        SoftOMXComponent.cpp               \
-        SoftOMXPlugin.cpp                  \
-        SoftVideoDecoderOMXComponent.cpp   \
-        SoftVideoEncoderOMXComponent.cpp   \
-        1.0/Omx.cpp                        \
-        1.0/OmxStore.cpp                   \
-        1.0/WGraphicBufferProducer.cpp     \
-        1.0/WProducerListener.cpp          \
-        1.0/WGraphicBufferSource.cpp       \
-        1.0/WOmxNode.cpp                   \
-        1.0/WOmxObserver.cpp               \
-        1.0/WOmxBufferSource.cpp           \
-
-LOCAL_C_INCLUDES += \
-        $(TOP)/frameworks/av/media/libstagefright \
-        $(TOP)/frameworks/native/include/media/hardware \
-        $(TOP)/frameworks/native/include/media/openmax \
-        $(TOP)/system/libhidl/base/include \
-
-LOCAL_SHARED_LIBRARIES :=                         \
-        libbase                                   \
-        libbinder                                 \
-        libmedia                                  \
-        libutils                                  \
-        liblog                                    \
-        libui                                     \
-        libgui                                    \
-        libcutils                                 \
-        libstagefright_foundation                 \
-        libdl                                     \
-        libhidlbase                               \
-        libhidlmemory                             \
-        libstagefright_xmlparser@1.0              \
-        android.hidl.base@1.0                     \
-        android.hidl.memory@1.0                   \
-        android.hardware.media@1.0                \
-        android.hardware.media.omx@1.0            \
-        android.hardware.graphics.common@1.0      \
-        android.hardware.graphics.bufferqueue@1.0 \
-
-LOCAL_EXPORT_C_INCLUDES := \
-        $(TOP)/frameworks/av/include
-
-LOCAL_EXPORT_SHARED_LIBRARY_HEADERS := \
-        android.hidl.memory@1.0
-
-LOCAL_MODULE:= libstagefright_omx
-LOCAL_CFLAGS += -Werror -Wall -Wno-unused-parameter -Wno-documentation
-LOCAL_SANITIZE := unsigned-integer-overflow signed-integer-overflow cfi
-LOCAL_SANITIZE_DIAG := cfi
-
-include $(BUILD_SHARED_LIBRARY)
-
-################################################################################
-
-include $(call all-makefiles-under,$(LOCAL_PATH)/hal)
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/media/libstagefright/omx/BWGraphicBufferSource.cpp b/media/libstagefright/omx/BWGraphicBufferSource.cpp
index f2a454f..79f6d93 100644
--- a/media/libstagefright/omx/BWGraphicBufferSource.cpp
+++ b/media/libstagefright/omx/BWGraphicBufferSource.cpp
@@ -21,7 +21,7 @@
 #include <OMX_IndexExt.h>
 
 #include <media/OMXBuffer.h>
-#include <IOMX.h>
+#include <media/IOMX.h>
 
 #include "OMXUtils.h"
 #include "BWGraphicBufferSource.h"
@@ -160,6 +160,11 @@
     return Status::fromStatusT(mBase->setStopTimeUs(stopTimeUs));
 }
 
+::android::binder::Status BWGraphicBufferSource::getStopTimeOffsetUs(
+        int64_t *stopTimeOffsetUs) {
+    return Status::fromStatusT(mBase->getStopTimeOffsetUs(stopTimeOffsetUs));
+}
+
 ::android::binder::Status BWGraphicBufferSource::setColorAspects(
         int32_t aspects) {
     return Status::fromStatusT(mBase->setColorAspects(aspects));
diff --git a/media/libstagefright/omx/BWGraphicBufferSource.h b/media/libstagefright/omx/BWGraphicBufferSource.h
index 43763c2..0f78eb6 100644
--- a/media/libstagefright/omx/BWGraphicBufferSource.h
+++ b/media/libstagefright/omx/BWGraphicBufferSource.h
@@ -21,7 +21,7 @@
 #include <binder/Status.h>
 #include <android/BnGraphicBufferSource.h>
 #include <android/BnOMXBufferSource.h>
-#include <IOMX.h>
+#include <media/IOMX.h>
 
 #include "GraphicBufferSource.h"
 #include "IOmxNodeWrapper.h"
@@ -53,6 +53,7 @@
             double fps, double captureFps) override;
     Status setStartTimeUs(int64_t startTimeUs) override;
     Status setStopTimeUs(int64_t stopTimeUs) override;
+    Status getStopTimeOffsetUs(int64_t* stopTimeOffsetUs) override;
     Status setColorAspects(int32_t aspects) override;
     Status setTimeOffsetUs(int64_t timeOffsetsUs) override;
     Status signalEndOfInputStream() override;
diff --git a/media/libstagefright/omx/GraphicBufferSource.cpp b/media/libstagefright/omx/GraphicBufferSource.cpp
index 47d80bb..ef4d745 100644
--- a/media/libstagefright/omx/GraphicBufferSource.cpp
+++ b/media/libstagefright/omx/GraphicBufferSource.cpp
@@ -35,7 +35,7 @@
 #include "omx/OMXUtils.h"
 #include <OMX_Component.h>
 #include <OMX_IndexExt.h>
-#include "OMXBuffer.h"
+#include "media/OMXBuffer.h"
 
 #include <inttypes.h>
 #include "FrameDropper.h"
@@ -264,6 +264,7 @@
     mLastDataspace(HAL_DATASPACE_UNKNOWN),
     mExecuting(false),
     mSuspended(false),
+    mLastFrameTimestampUs(-1),
     mStopTimeUs(-1),
     mLastActionTimeUs(-1ll),
     mSkipFramesBeforeNs(-1ll),
@@ -649,6 +650,7 @@
         }
         ALOGV("buffer submitted [slot=%d, useCount=%ld] acquired=%d",
                 item.mBuffer->getSlot(), item.mBuffer.use_count(), mNumOutstandingAcquires);
+        mLastFrameTimestampUs = itemTimeUs;
     }
 
     return true;
@@ -1220,10 +1222,21 @@
     return OK;
 }
 
+status_t GraphicBufferSource::getStopTimeOffsetUs(int64_t *stopTimeOffsetUs) {
+    ALOGV("getStopTimeOffsetUs");
+    Mutex::Autolock autoLock(mMutex);
+    if (mStopTimeUs == -1) {
+        ALOGW("Fail to return stopTimeOffsetUs as stop time is not set");
+        return INVALID_OPERATION;
+    }
+    *stopTimeOffsetUs =
+        mLastFrameTimestampUs == -1 ? 0 : mStopTimeUs - mLastFrameTimestampUs;
+    return OK;
+}
+
 status_t GraphicBufferSource::setTimeLapseConfig(double fps, double captureFps) {
     ALOGV("setTimeLapseConfig: fps=%lg, captureFps=%lg",
             fps, captureFps);
-
     Mutex::Autolock autoLock(mMutex);
 
     if (mExecuting || !(fps > 0) || !(captureFps > 0)) {
diff --git a/media/libstagefright/omx/GraphicBufferSource.h b/media/libstagefright/omx/GraphicBufferSource.h
index 3df1aa1..29b51a8 100644
--- a/media/libstagefright/omx/GraphicBufferSource.h
+++ b/media/libstagefright/omx/GraphicBufferSource.h
@@ -172,6 +172,13 @@
     // and not submitted to encoder. timeUs uses SYSTEM_TIME_MONOTONIC time base.
     status_t setStopTimeUs(int64_t stopTimeUs);
 
+    // Gets the stop time offset in us. This is the time offset between latest buffer
+    // time and the stopTimeUs. If stop time is not set, INVALID_OPERATION will be returned.
+    // If return is OK, *stopTimeOffsetUs will contain the valid offset. Otherwise,
+    // *stopTimeOffsetUs will not be modified. Positive stopTimeOffsetUs means buffer time
+    // larger than stopTimeUs.
+    status_t getStopTimeOffsetUs(int64_t *stopTimeOffsetUs);
+
     // Sets the desired color aspects, e.g. to be used when producer does not specify a dataspace.
     status_t setColorAspects(int32_t aspectsPacked);
 
@@ -340,6 +347,8 @@
     // regardless of the metadata of those buffers
     bool areWeDiscardingAvailableBuffers_l();
 
+    int64_t mLastFrameTimestampUs;
+
     // Our BufferQueue interfaces. mProducer is passed to the producer through
     // getIGraphicBufferProducer, and mConsumer is used internally to retrieve
     // the buffers queued by the producer.
diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
index af88c23..63c1c80 100644
--- a/media/libstagefright/omx/OMXNodeInstance.cpp
+++ b/media/libstagefright/omx/OMXNodeInstance.cpp
@@ -1082,6 +1082,10 @@
                     break;
                 }
                 sp<IHidlMemory> hidlMemory = mapMemory(omxBuffer.mHidlMemory);
+                if (hidlMemory == nullptr) {
+                    ALOGE("OMXNodeInstance useBuffer() failed to map memory");
+                    return NO_MEMORY;
+                }
                 return useBuffer_l(portIndex, NULL, hidlMemory, buffer);
         }
         default:
diff --git a/media/libstagefright/omx/OMXUtils.cpp b/media/libstagefright/omx/OMXUtils.cpp
index ee6d1d5..a66d565 100644
--- a/media/libstagefright/omx/OMXUtils.cpp
+++ b/media/libstagefright/omx/OMXUtils.cpp
@@ -24,6 +24,7 @@
 #include <media/stagefright/foundation/AUtils.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/MediaDefs.h>
+#include <system/graphics-base.h>
 #include "OMXUtils.h"
 
 namespace android {
diff --git a/media/libstagefright/omx/SoftOMXPlugin.cpp b/media/libstagefright/omx/SoftOMXPlugin.cpp
index a773ca2..fccb12b 100644
--- a/media/libstagefright/omx/SoftOMXPlugin.cpp
+++ b/media/libstagefright/omx/SoftOMXPlugin.cpp
@@ -58,6 +58,7 @@
     { "OMX.google.vp8.encoder", "vpxenc", "video_encoder.vp8" },
     { "OMX.google.vp9.encoder", "vpxenc", "video_encoder.vp9" },
     { "OMX.google.raw.decoder", "rawdec", "audio_decoder.raw" },
+    { "OMX.google.flac.decoder", "flacdec", "audio_decoder.flac" },
     { "OMX.google.flac.encoder", "flacenc", "audio_encoder.flac" },
     { "OMX.google.gsm.decoder", "gsmdec", "audio_decoder.gsm" },
 };
diff --git a/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp b/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp
index 361cfb4..41d634a 100644
--- a/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp
+++ b/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp
@@ -36,6 +36,8 @@
 
 #include <hardware/gralloc.h>
 
+#include <nativebase/nativebase.h>
+
 #include <OMX_IndexExt.h>
 
 namespace android {
diff --git a/media/libstagefright/omx/tests/Android.bp b/media/libstagefright/omx/tests/Android.bp
new file mode 100644
index 0000000..8bcb99e
--- /dev/null
+++ b/media/libstagefright/omx/tests/Android.bp
@@ -0,0 +1,52 @@
+cc_test {
+    name: "omx_tests",
+    gtest: false,
+
+    srcs: ["OMXHarness.cpp"],
+
+    shared_libs: [
+        "libstagefright",
+        "libbinder",
+        "libmedia",
+        "libutils",
+        "liblog",
+        "libstagefright_foundation",
+        "libcutils",
+        "libhidlbase",
+        "libhidlmemory",
+        "libnativewindow",
+        "android.hidl.allocator@1.0",
+        "android.hidl.memory@1.0",
+        "android.hardware.media.omx@1.0",
+    ],
+
+    include_dirs: [
+        "frameworks/av/media/libstagefright",
+        "frameworks/native/include/media/openmax",
+    ],
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+    ],
+
+    compile_multilib: "32",
+}
+
+cc_test {
+    name: "FrameDropper_test",
+
+    srcs: ["FrameDropper_test.cpp"],
+
+    shared_libs: [
+        "libstagefright_omx",
+        "libutils",
+    ],
+
+    include_dirs: ["frameworks/av/media/libstagefright/omx"],
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+    ],
+}
diff --git a/media/libstagefright/omx/tests/Android.mk b/media/libstagefright/omx/tests/Android.mk
deleted file mode 100644
index 5941b94..0000000
--- a/media/libstagefright/omx/tests/Android.mk
+++ /dev/null
@@ -1,54 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES =       \
-        OMXHarness.cpp  \
-
-LOCAL_SHARED_LIBRARIES := \
-        libstagefright \
-        libbinder \
-        libmedia \
-        libutils \
-        liblog \
-        libstagefright_foundation \
-        libcutils \
-        libhidlbase \
-        libhidlmemory \
-        android.hidl.allocator@1.0 \
-        android.hidl.memory@1.0 \
-        android.hardware.media.omx@1.0 \
-
-LOCAL_C_INCLUDES := \
-        $(TOP)/frameworks/av/media/libstagefright \
-        $(TOP)/frameworks/native/include/media/openmax \
-        $(TOP)/system/libhidl/base/include \
-
-LOCAL_CFLAGS += -Werror -Wall
-
-LOCAL_MODULE := omx_tests
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_32_BIT_ONLY := true
-
-include $(BUILD_EXECUTABLE)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := FrameDropper_test
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := \
-        FrameDropper_test.cpp \
-
-LOCAL_SHARED_LIBRARIES := \
-        libstagefright_omx \
-        libutils \
-
-LOCAL_C_INCLUDES := \
-        frameworks/av/media/libstagefright/omx \
-
-LOCAL_CFLAGS += -Werror -Wall
-
-include $(BUILD_NATIVE_TEST)
diff --git a/media/libstagefright/omx/tests/OMXHarness.cpp b/media/libstagefright/omx/tests/OMXHarness.cpp
index fcc44d8..3266439 100644
--- a/media/libstagefright/omx/tests/OMXHarness.cpp
+++ b/media/libstagefright/omx/tests/OMXHarness.cpp
@@ -41,6 +41,7 @@
 #include <media/OMXBuffer.h>
 #include <android/hardware/media/omx/1.0/IOmx.h>
 #include <media/omx/1.0/WOmx.h>
+#include <system/window.h>
 
 #define DEFAULT_TIMEOUT         500000
 
diff --git a/media/libstagefright/rtsp/Android.bp b/media/libstagefright/rtsp/Android.bp
new file mode 100644
index 0000000..debd07e
--- /dev/null
+++ b/media/libstagefright/rtsp/Android.bp
@@ -0,0 +1,96 @@
+cc_library_static {
+    name: "libstagefright_rtsp",
+
+    srcs: [
+        "AAMRAssembler.cpp",
+        "AAVCAssembler.cpp",
+        "AH263Assembler.cpp",
+        "AMPEG2TSAssembler.cpp",
+        "AMPEG4AudioAssembler.cpp",
+        "AMPEG4ElementaryAssembler.cpp",
+        "APacketSource.cpp",
+        "ARawAudioAssembler.cpp",
+        "ARTPAssembler.cpp",
+        "ARTPConnection.cpp",
+        "ARTPSource.cpp",
+        "ARTPWriter.cpp",
+        "ARTSPConnection.cpp",
+        "ASessionDescription.cpp",
+        "SDPLoader.cpp",
+    ],
+
+    shared_libs: [
+        "libcrypto",
+        "libmedia",
+    ],
+
+    include_dirs: [
+        "frameworks/av/media/libstagefright",
+        "frameworks/native/include/media/openmax",
+    ],
+
+    arch: {
+        arm: {
+            cflags: ["-Wno-psabi"],
+        },
+    },
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+    ],
+
+    sanitize: {
+        misc_undefined: [
+            "signed-integer-overflow",
+            "unsigned-integer-overflow",
+        ],
+        cfi: true,
+        diag: {
+            cfi: true,
+        },
+    },
+}
+
+//###############################################################################
+
+cc_test {
+    name: "rtp_test",
+    gtest: false,
+    enabled: false,
+
+    srcs: ["rtp_test.cpp"],
+
+    shared_libs: [
+        "libstagefright",
+        "liblog",
+        "libutils",
+        "libbinder",
+        "libstagefright_foundation",
+        "libmedia",
+    ],
+
+    static_libs: ["libstagefright_rtsp"],
+
+    include_dirs: [
+        "frameworks/av/media/libstagefright",
+        "frameworks/av/cmds/stagefright",
+        "frameworks/native/include/media/openmax",
+    ],
+
+    cflags: [
+        "-Wno-multichar",
+        "-Werror",
+        "-Wall",
+    ],
+
+    sanitize: {
+        misc_undefined: [
+            "signed-integer-overflow",
+        ],
+        cfi: true,
+        diag: {
+            cfi: true,
+        },
+    },
+}
diff --git a/media/libstagefright/rtsp/Android.mk b/media/libstagefright/rtsp/Android.mk
deleted file mode 100644
index 3472e49..0000000
--- a/media/libstagefright/rtsp/Android.mk
+++ /dev/null
@@ -1,68 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:=       \
-        AAMRAssembler.cpp           \
-        AAVCAssembler.cpp           \
-        AH263Assembler.cpp          \
-        AMPEG2TSAssembler.cpp       \
-        AMPEG4AudioAssembler.cpp    \
-        AMPEG4ElementaryAssembler.cpp \
-        APacketSource.cpp           \
-        ARawAudioAssembler.cpp      \
-        ARTPAssembler.cpp           \
-        ARTPConnection.cpp          \
-        ARTPSource.cpp              \
-        ARTPWriter.cpp              \
-        ARTSPConnection.cpp         \
-        ASessionDescription.cpp     \
-        SDPLoader.cpp               \
-
-LOCAL_SHARED_LIBRARIES += libcrypto libmedia
-
-LOCAL_C_INCLUDES:= \
-	$(TOP)/frameworks/av/media/libstagefright \
-	$(TOP)/frameworks/native/include/media/openmax
-
-LOCAL_MODULE:= libstagefright_rtsp
-
-ifeq ($(TARGET_ARCH),arm)
-    LOCAL_CFLAGS += -Wno-psabi
-endif
-
-LOCAL_CFLAGS += -Werror -Wall
-LOCAL_SANITIZE := unsigned-integer-overflow signed-integer-overflow
-
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-
-include $(BUILD_STATIC_LIBRARY)
-
-################################################################################
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
-	rtp_test.cpp \
-
-LOCAL_SHARED_LIBRARIES := \
-	libstagefright liblog libutils libbinder libstagefright_foundation libmedia
-
-LOCAL_STATIC_LIBRARIES := \
-	libstagefright_rtsp
-
-LOCAL_C_INCLUDES := \
-	frameworks/av/media/libstagefright \
-	frameworks/av/cmds/stagefright \
-	$(TOP)/frameworks/native/include/media/openmax
-
-LOCAL_CFLAGS += -Wno-multichar -Werror -Wall
-LOCAL_SANITIZE := signed-integer-overflow
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_MODULE:= rtp_test
-
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-
-# include $(BUILD_EXECUTABLE)
diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h
index 5505aa4..c6c0245 100644
--- a/media/libstagefright/rtsp/MyHandler.h
+++ b/media/libstagefright/rtsp/MyHandler.h
@@ -33,6 +33,7 @@
 #include "ASessionDescription.h"
 
 #include <ctype.h>
+#include <cutils/properties.h>
 
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
@@ -135,7 +136,7 @@
           mCheckPending(false),
           mCheckGeneration(0),
           mCheckTimeoutGeneration(0),
-          mTryTCPInterleaving(false),
+          mTryTCPInterleaving(property_get_bool("rtp.transport.TCP", false)),
           mTryFakeRTCP(false),
           mReceivedFirstRTCPPacket(false),
           mReceivedFirstRTPPacket(false),
diff --git a/media/libstagefright/tests/Android.bp b/media/libstagefright/tests/Android.bp
new file mode 100644
index 0000000..35119c2
--- /dev/null
+++ b/media/libstagefright/tests/Android.bp
@@ -0,0 +1,68 @@
+// Build the unit tests.
+
+cc_test {
+    name: "SurfaceMediaSource_test",
+
+    srcs: [
+        "SurfaceMediaSource_test.cpp",
+        "DummyRecorder.cpp",
+    ],
+
+    shared_libs: [
+        "libEGL",
+        "libGLESv2",
+        "libbinder",
+        "libcutils",
+        "libgui",
+        "libmedia",
+        "libstagefright",
+        "libstagefright_foundation",
+        "libstagefright_omx",
+        "libsync",
+        "libui",
+        "libutils",
+        "liblog",
+    ],
+
+    include_dirs: [
+        "frameworks/av/media/libstagefright",
+        "frameworks/av/media/libstagefright/include",
+        "frameworks/native/include/media/openmax",
+        "frameworks/native/include/media/hardware",
+    ],
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+    ],
+
+    compile_multilib: "32",
+}
+
+cc_test {
+    name: "MediaCodecListOverrides_test",
+
+    srcs: ["MediaCodecListOverrides_test.cpp"],
+
+    shared_libs: [
+        "libmedia",
+        "libstagefright",
+        "libstagefright_foundation",
+        "libstagefright_omx",
+        "libutils",
+        "liblog",
+    ],
+
+    include_dirs: [
+        "frameworks/av/media/libstagefright",
+        "frameworks/av/media/libstagefright/include",
+        "frameworks/native/include/media/openmax",
+    ],
+
+    compile_multilib: "32",
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+    ],
+}
diff --git a/media/libstagefright/tests/Android.mk b/media/libstagefright/tests/Android.mk
deleted file mode 100644
index c6963b1..0000000
--- a/media/libstagefright/tests/Android.mk
+++ /dev/null
@@ -1,77 +0,0 @@
-# Build the unit tests.
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-
-LOCAL_MODULE := SurfaceMediaSource_test
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := \
-	SurfaceMediaSource_test.cpp \
-	DummyRecorder.cpp \
-
-LOCAL_SHARED_LIBRARIES := \
-	libEGL \
-	libGLESv2 \
-	libbinder \
-	libcutils \
-	libgui \
-	libmedia \
-	libstagefright \
-	libstagefright_foundation \
-	libstagefright_omx \
-	libsync \
-	libui \
-	libutils \
-	liblog
-
-LOCAL_C_INCLUDES := \
-	frameworks/av/media/libstagefright \
-	frameworks/av/media/libstagefright/include \
-	$(TOP)/frameworks/native/include/media/openmax \
-	$(TOP)/frameworks/native/include/media/hardware \
-
-LOCAL_CFLAGS += -Werror -Wall
-
-LOCAL_32_BIT_ONLY := true
-
-include $(BUILD_NATIVE_TEST)
-
-include $(CLEAR_VARS)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-
-LOCAL_MODULE := MediaCodecListOverrides_test
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := \
-	MediaCodecListOverrides_test.cpp \
-
-LOCAL_SHARED_LIBRARIES := \
-	libmedia \
-	libstagefright \
-	libstagefright_foundation \
-	libstagefright_omx \
-	libutils \
-	liblog
-
-LOCAL_C_INCLUDES := \
-	frameworks/av/media/libstagefright \
-	frameworks/av/media/libstagefright/include \
-	frameworks/native/include/media/openmax \
-
-LOCAL_32_BIT_ONLY := true
-
-LOCAL_CFLAGS += -Werror -Wall
-
-include $(BUILD_NATIVE_TEST)
-
-# Include subdirectory makefiles
-# ============================================================
-
-# If we're building with ONE_SHOT_MAKEFILE (mm, mmm), then what the framework
-# team really wants is to build the stuff defined by this makefile.
-ifeq (,$(ONE_SHOT_MAKEFILE))
-include $(call first-makefiles-under,$(LOCAL_PATH))
-endif
diff --git a/media/libstagefright/timedtext/Android.bp b/media/libstagefright/timedtext/Android.bp
new file mode 100644
index 0000000..a5ad6c6
--- /dev/null
+++ b/media/libstagefright/timedtext/Android.bp
@@ -0,0 +1,27 @@
+cc_library_static {
+    name: "libstagefright_timedtext",
+
+    srcs: ["TextDescriptions.cpp"],
+
+    cflags: [
+        "-Wno-multichar",
+        "-Werror",
+        "-Wall",
+    ],
+
+    sanitize: {
+        misc_undefined: [
+            "signed-integer-overflow",
+        ],
+        cfi: true,
+        diag: {
+            cfi: true,
+        },
+    },
+
+    include_dirs: [
+        "frameworks/av/media/libstagefright",
+    ],
+
+    shared_libs: ["libmedia"],
+}
diff --git a/media/libstagefright/timedtext/Android.mk b/media/libstagefright/timedtext/Android.mk
deleted file mode 100644
index 70ae46b..0000000
--- a/media/libstagefright/timedtext/Android.mk
+++ /dev/null
@@ -1,19 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:=                 \
-        TextDescriptions.cpp      \
-
-LOCAL_CFLAGS += -Wno-multichar -Werror -Wall
-LOCAL_SANITIZE := signed-integer-overflow cfi
-LOCAL_SANITIZE_DIAG := cfi
-
-LOCAL_C_INCLUDES:= \
-        $(TOP)/frameworks/av/include/media/stagefright/timedtext \
-        $(TOP)/frameworks/av/media/libstagefright
-
-LOCAL_SHARED_LIBRARIES := libmedia
-
-LOCAL_MODULE:= libstagefright_timedtext
-
-include $(BUILD_STATIC_LIBRARY)
diff --git a/media/libstagefright/webm/Android.bp b/media/libstagefright/webm/Android.bp
new file mode 100644
index 0000000..f968788
--- /dev/null
+++ b/media/libstagefright/webm/Android.bp
@@ -0,0 +1,37 @@
+cc_library_static {
+    name: "libstagefright_webm",
+
+    cppflags: ["-D__STDINT_LIMITS"],
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+    ],
+
+    sanitize: {
+        misc_undefined: [
+            "signed-integer-overflow",
+            "unsigned-integer-overflow",
+        ],
+        cfi: true,
+        diag: {
+            cfi: true,
+        },
+    },
+
+    srcs: [
+        "EbmlUtil.cpp",
+        "WebmElement.cpp",
+        "WebmFrame.cpp",
+        "WebmFrameThread.cpp",
+        "WebmWriter.cpp",
+    ],
+
+    include_dirs: ["frameworks/av/include"],
+
+    shared_libs: [
+        "libstagefright_foundation",
+        "libutils",
+        "liblog",
+    ],
+}
diff --git a/media/libstagefright/webm/Android.mk b/media/libstagefright/webm/Android.mk
deleted file mode 100644
index 0d55de9..0000000
--- a/media/libstagefright/webm/Android.mk
+++ /dev/null
@@ -1,26 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_CPPFLAGS += -D__STDINT_LIMITS
-
-LOCAL_CFLAGS += -Werror -Wall
-LOCAL_SANITIZE := unsigned-integer-overflow signed-integer-overflow cfi
-LOCAL_SANITIZE_DIAG := cfi
-
-LOCAL_SRC_FILES:= EbmlUtil.cpp        \
-                  WebmElement.cpp     \
-                  WebmFrame.cpp       \
-                  WebmFrameThread.cpp \
-                  WebmWriter.cpp
-
-
-LOCAL_C_INCLUDES += $(TOP)/frameworks/av/include
-
-LOCAL_SHARED_LIBRARIES += libstagefright_foundation \
-                          libstagefright \
-                          libutils \
-                          liblog
-
-LOCAL_MODULE:= libstagefright_webm
-
-include $(BUILD_STATIC_LIBRARY)
diff --git a/media/libstagefright/webm/WebmFrameThread.cpp b/media/libstagefright/webm/WebmFrameThread.cpp
index 77de3c8..71bfbc9 100644
--- a/media/libstagefright/webm/WebmFrameThread.cpp
+++ b/media/libstagefright/webm/WebmFrameThread.cpp
@@ -124,7 +124,7 @@
 
 void WebmFrameSinkThread::writeCluster(List<sp<WebmElement> >& children) {
     // children must contain at least one simpleblock and its timecode
-    CHECK_GE(children.size(), 2);
+    CHECK_GE(children.size(), 2u);
 
     uint64_t size;
     sp<WebmElement> cluster = new WebmMaster(kMkvCluster, children);
@@ -155,7 +155,7 @@
         // flushing the second to last frame before we check its type. A audio frame
         // should precede the aforementioned video key frame in the next sequence, a video
         // frame should be the last frame in the current (to-be-flushed) sequence.
-        CHECK_GE(n, 2);
+        CHECK_GE(n, 2u);
         n -= 2;
     }
 
diff --git a/media/libstagefright/webm/WebmWriter.cpp b/media/libstagefright/webm/WebmWriter.cpp
index 25d6821..d6c6930 100644
--- a/media/libstagefright/webm/WebmWriter.cpp
+++ b/media/libstagefright/webm/WebmWriter.cpp
@@ -488,7 +488,7 @@
             params->findInt32(kKeyBitRate, &bitRate);
         }
         mEstimatedCuesSize = estimateCuesSize(bitRate);
-        CHECK_GE(mEstimatedCuesSize, 8);
+        CHECK_GE(mEstimatedCuesSize, 8u);
         cues = new EbmlVoid(mEstimatedCuesSize);
     }
 
diff --git a/media/libstagefright/wifi-display/Android.bp b/media/libstagefright/wifi-display/Android.bp
new file mode 100644
index 0000000..fb08c5b
--- /dev/null
+++ b/media/libstagefright/wifi-display/Android.bp
@@ -0,0 +1,51 @@
+cc_library_shared {
+    name: "libstagefright_wfd",
+
+    srcs: [
+        "MediaSender.cpp",
+        "Parameters.cpp",
+        "rtp/RTPSender.cpp",
+        "source/Converter.cpp",
+        "source/MediaPuller.cpp",
+        "source/PlaybackSession.cpp",
+        "source/RepeaterSource.cpp",
+        "source/TSPacketizer.cpp",
+        "source/WifiDisplaySource.cpp",
+        "VideoFormats.cpp",
+    ],
+
+    include_dirs: [
+        "frameworks/av/media/libstagefright",
+        "frameworks/native/include/media/openmax",
+        "frameworks/native/include/media/hardware",
+        "frameworks/av/media/libstagefright/mpeg2ts",
+    ],
+
+    shared_libs: [
+        "libbinder",
+        "libcutils",
+        "liblog",
+        "libmedia",
+        "libstagefright",
+        "libstagefright_foundation",
+        "libui",
+        "libgui",
+        "libutils",
+    ],
+
+    cflags: [
+        "-Wno-multichar",
+        "-Werror",
+        "-Wall",
+    ],
+
+    sanitize: {
+        misc_undefined: [
+            "signed-integer-overflow",
+        ],
+        cfi: true,
+        diag: {
+            cfi: true,
+        },
+    },
+}
diff --git a/media/libstagefright/wifi-display/Android.mk b/media/libstagefright/wifi-display/Android.mk
deleted file mode 100644
index a1b4aec..0000000
--- a/media/libstagefright/wifi-display/Android.mk
+++ /dev/null
@@ -1,41 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-        MediaSender.cpp                 \
-        Parameters.cpp                  \
-        rtp/RTPSender.cpp               \
-        source/Converter.cpp            \
-        source/MediaPuller.cpp          \
-        source/PlaybackSession.cpp      \
-        source/RepeaterSource.cpp       \
-        source/TSPacketizer.cpp         \
-        source/WifiDisplaySource.cpp    \
-        VideoFormats.cpp                \
-
-LOCAL_C_INCLUDES:= \
-        $(TOP)/frameworks/av/media/libstagefright \
-        $(TOP)/frameworks/native/include/media/openmax \
-        $(TOP)/frameworks/native/include/media/hardware \
-        $(TOP)/frameworks/av/media/libstagefright/mpeg2ts \
-
-LOCAL_SHARED_LIBRARIES:= \
-        libbinder                       \
-        libcutils                       \
-        liblog                          \
-        libmedia                        \
-        libstagefright                  \
-        libstagefright_foundation       \
-        libui                           \
-        libutils                        \
-
-LOCAL_CFLAGS += -Wno-multichar -Werror -Wall
-LOCAL_SANITIZE := signed-integer-overflow cfi
-LOCAL_SANITIZE_DIAG := cfi
-
-LOCAL_MODULE:= libstagefright_wfd
-
-LOCAL_MODULE_TAGS:= optional
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/wifi-display/MediaSender.cpp b/media/libstagefright/wifi-display/MediaSender.cpp
index ae507fc..cc412f5 100644
--- a/media/libstagefright/wifi-display/MediaSender.cpp
+++ b/media/libstagefright/wifi-display/MediaSender.cpp
@@ -420,7 +420,7 @@
             CHECK(accessUnit->meta()->findInt32("rangeLength", &rangeLength));
             CHECK(accessUnit->meta()->findMessage("notify", &notify)
                     && notify != NULL);
-            CHECK_GE(accessUnit->size(), rangeLength);
+            CHECK_GE((int32_t)accessUnit->size(), rangeLength);
 
             sp<GraphicBuffer> grbuf(new GraphicBuffer(
                     rangeOffset + rangeLength /* width */, 1 /* height */,
diff --git a/media/libstagefright/wifi-display/rtp/RTPBase.h b/media/libstagefright/wifi-display/rtp/RTPBase.h
index 6178f00..194f1ee 100644
--- a/media/libstagefright/wifi-display/rtp/RTPBase.h
+++ b/media/libstagefright/wifi-display/rtp/RTPBase.h
@@ -36,10 +36,8 @@
         TRANSPORT_TCP_INTERLEAVED,
     };
 
-    enum {
-        // Really UDP _payload_ size
-        kMaxUDPPacketSize = 1472,   // 1472 good, 1473 bad on Android@Home
-    };
+    // Really UDP _payload_ size
+    const unsigned int kMaxUDPPacketSize = 1472;   // 1472 good, 1473 bad on Android@Home
 
     static int32_t PickRandomRTPPort();
 };
diff --git a/media/libstagefright/wifi-display/rtp/RTPSender.cpp b/media/libstagefright/wifi-display/rtp/RTPSender.cpp
index 83af393..ca9fdd2 100644
--- a/media/libstagefright/wifi-display/rtp/RTPSender.cpp
+++ b/media/libstagefright/wifi-display/rtp/RTPSender.cpp
@@ -247,7 +247,7 @@
 
 status_t RTPSender::queueTSPackets(
         const sp<ABuffer> &tsPackets, uint8_t packetType) {
-    CHECK_EQ(0, tsPackets->size() % 188);
+    CHECK_EQ(0u, tsPackets->size() % 188);
 
     int64_t timeUs;
     CHECK(tsPackets->meta()->findInt64("timeUs", &timeUs));
diff --git a/media/libstagefright/wifi-display/rtp/RTPSender.h b/media/libstagefright/wifi-display/rtp/RTPSender.h
index fefcab7..bedfd01 100644
--- a/media/libstagefright/wifi-display/rtp/RTPSender.h
+++ b/media/libstagefright/wifi-display/rtp/RTPSender.h
@@ -66,11 +66,9 @@
         kWhatRTCPNotify,
     };
 
-    enum {
-        kMaxNumTSPacketsPerRTPPacket = (kMaxUDPPacketSize - 12) / 188,
-        kMaxHistorySize              = 1024,
-        kSourceID                    = 0xdeadbeef,
-    };
+    const unsigned int kMaxNumTSPacketsPerRTPPacket = (kMaxUDPPacketSize - 12) / 188;
+    const unsigned int kMaxHistorySize              = 1024;
+    const unsigned int kSourceID                    = 0xdeadbeef;
 
     sp<ANetworkSession> mNetSession;
     sp<AMessage> mNotify;
diff --git a/media/libstagefright/wifi-display/source/TSPacketizer.cpp b/media/libstagefright/wifi-display/source/TSPacketizer.cpp
index 4c5ad17..865ba94 100644
--- a/media/libstagefright/wifi-display/source/TSPacketizer.cpp
+++ b/media/libstagefright/wifi-display/source/TSPacketizer.cpp
@@ -273,8 +273,8 @@
                 CHECK(mFormat->findInt32("profile-idc", &profileIdc));
                 CHECK(mFormat->findInt32("level-idc", &levelIdc));
                 CHECK(mFormat->findInt32("constraint-set", &constraintSet));
-                CHECK_GE(profileIdc, 0u);
-                CHECK_GE(levelIdc, 0u);
+                CHECK_GE(profileIdc, 0);
+                CHECK_GE(levelIdc, 0);
                 data[2] = profileIdc;    // profile_idc
                 data[3] = constraintSet; // constraint_set*
                 data[4] = levelIdc;      // level_idc
@@ -771,7 +771,7 @@
             program_info_length += mProgramInfoDescriptors.itemAt(i)->size();
         }
 
-        CHECK_LT(program_info_length, 0x400);
+        CHECK_LT(program_info_length, 0x400u);
         *ptr++ = 0xf0 | (program_info_length >> 8);
         *ptr++ = (program_info_length & 0xff);
 
@@ -795,7 +795,7 @@
             for (size_t i = 0; i < track->countDescriptors(); ++i) {
                 ES_info_length += track->descriptorAt(i)->size();
             }
-            CHECK_LE(ES_info_length, 0xfff);
+            CHECK_LE(ES_info_length, 0xfffu);
 
             *ptr++ = 0xf0 | (ES_info_length >> 8);
             *ptr++ = (ES_info_length & 0xff);
diff --git a/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp b/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp
index 9cda8dc..4695e5d 100644
--- a/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp
+++ b/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp
@@ -454,7 +454,7 @@
                 sp<ABuffer> data;
                 CHECK(msg->findBuffer("data", &data));
 
-                CHECK_LE(channel, 0xffu);
+                CHECK_LE(channel, 0xff);
                 CHECK_LE(data->size(), 0xffffu);
 
                 int32_t sessionID;
diff --git a/media/mtp/Android.bp b/media/mtp/Android.bp
new file mode 100644
index 0000000..5d5ae49
--- /dev/null
+++ b/media/mtp/Android.bp
@@ -0,0 +1,57 @@
+//
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_library_shared {
+    name: "libmtp",
+    srcs: [
+        "AsyncIO.cpp",
+        "MtpDataPacket.cpp",
+        "MtpDebug.cpp",
+        "MtpDevHandle.cpp",
+        "MtpDevice.cpp",
+        "MtpDeviceInfo.cpp",
+        "MtpEventPacket.cpp",
+        "MtpFfsHandle.cpp",
+        "MtpObjectInfo.cpp",
+        "MtpPacket.cpp",
+        "MtpProperty.cpp",
+        "MtpRequestPacket.cpp",
+        "MtpResponsePacket.cpp",
+        "MtpServer.cpp",
+        "MtpStorage.cpp",
+        "MtpStorageInfo.cpp",
+        "MtpStringBuffer.cpp",
+        "MtpUtils.cpp",
+    ],
+    export_include_dirs: ["."],
+    cflags: [
+        "-DMTP_DEVICE",
+        "-DMTP_HOST",
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+    ],
+    shared_libs: [
+        "libbase",
+        "libutils",
+        "liblog",
+        "libusbhost",
+    ],
+}
+
+subdirs = [
+    "tests",
+]
diff --git a/media/mtp/Android.mk b/media/mtp/Android.mk
deleted file mode 100644
index 58753ff..0000000
--- a/media/mtp/Android.mk
+++ /dev/null
@@ -1,49 +0,0 @@
-#
-# Copyright (C) 2010 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.
-#
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:=                                       \
-                  AsyncIO.cpp                           \
-                  MtpDataPacket.cpp                     \
-                  MtpDebug.cpp                          \
-                  MtpDevHandle.cpp                      \
-                  MtpDevice.cpp                         \
-                  MtpDeviceInfo.cpp                     \
-                  MtpEventPacket.cpp                    \
-                  MtpFfsHandle.cpp                      \
-                  MtpObjectInfo.cpp                     \
-                  MtpPacket.cpp                         \
-                  MtpProperty.cpp                       \
-                  MtpRequestPacket.cpp                  \
-                  MtpResponsePacket.cpp                 \
-                  MtpServer.cpp                         \
-                  MtpStorage.cpp                        \
-                  MtpStorageInfo.cpp                    \
-                  MtpStringBuffer.cpp                   \
-                  MtpUtils.cpp                          \
-
-LOCAL_MODULE:= libmtp
-
-LOCAL_CFLAGS := -DMTP_DEVICE -DMTP_HOST -Wall -Wextra -Werror
-
-LOCAL_SHARED_LIBRARIES := libbase libutils libcutils liblog libusbhost libbinder
-
-include $(BUILD_SHARED_LIBRARY)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/media/mtp/MtpServer.cpp b/media/mtp/MtpServer.cpp
index 5c33265..2180462 100644
--- a/media/mtp/MtpServer.cpp
+++ b/media/mtp/MtpServer.cpp
@@ -25,6 +25,7 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/stat.h>
+#include <sys/time.h>
 
 #define LOG_TAG "MtpServer"
 
@@ -113,7 +114,8 @@
         mSessionOpen(false),
         mSendObjectHandle(kInvalidObjectHandle),
         mSendObjectFormat(0),
-        mSendObjectFileSize(0)
+        mSendObjectFileSize(0),
+        mSendObjectModifiedTime(0)
 {
 }
 
@@ -999,6 +1001,7 @@
         // save the handle for the SendObject call, which should follow
         mSendObjectHandle = handle;
         mSendObjectFormat = format;
+        mSendObjectModifiedTime = modifiedTime;
     }
 
     mResponse.setParameter(1, storageID);
@@ -1015,6 +1018,7 @@
     mode_t mask;
     int ret, initialData;
     bool isCanceled = false;
+    struct stat sstat = {};
 
     auto start = std::chrono::steady_clock::now();
 
@@ -1070,7 +1074,17 @@
             isCanceled = true;
         }
     }
-    struct stat sstat;
+
+    if (mSendObjectModifiedTime) {
+        struct timespec newTime[2];
+        newTime[0].tv_nsec = UTIME_NOW;
+        newTime[1].tv_sec = mSendObjectModifiedTime;
+        newTime[1].tv_nsec = 0;
+        if (futimens(mfr.fd, newTime) < 0) {
+            ALOGW("changing modified time failed, %s", strerror(errno));
+        }
+    }
+
     fstat(mfr.fd, &sstat);
     close(mfr.fd);
 
@@ -1091,6 +1105,7 @@
             result == MTP_RESPONSE_OK);
     mSendObjectHandle = kInvalidObjectHandle;
     mSendObjectFormat = 0;
+    mSendObjectModifiedTime = 0;
 
     auto end = std::chrono::steady_clock::now();
     std::chrono::duration<double> diff = end - start;
diff --git a/media/mtp/MtpServer.h b/media/mtp/MtpServer.h
index 64d1b72..08a9e4a 100644
--- a/media/mtp/MtpServer.h
+++ b/media/mtp/MtpServer.h
@@ -78,6 +78,7 @@
     MtpObjectFormat     mSendObjectFormat;
     MtpString           mSendObjectFilePath;
     size_t              mSendObjectFileSize;
+    time_t              mSendObjectModifiedTime;
 
     Mutex               mMutex;
 
diff --git a/media/mtp/tests/Android.bp b/media/mtp/tests/Android.bp
new file mode 100644
index 0000000..fe7018b
--- /dev/null
+++ b/media/mtp/tests/Android.bp
@@ -0,0 +1,46 @@
+//
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_test {
+    name: "mtp_ffs_handle_test",
+    test_suites: ["device-tests"],
+    srcs: ["MtpFfsHandle_test.cpp"],
+    shared_libs: [
+        "libbase",
+        "libmtp",
+        "liblog",
+    ],
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+    ],
+}
+
+cc_test {
+    name: "async_io_test",
+    srcs: ["AsyncIO_test.cpp"],
+    shared_libs: [
+        "libbase",
+        "libmtp",
+        "liblog",
+    ],
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+    ],
+}
diff --git a/media/mtp/tests/Android.mk b/media/mtp/tests/Android.mk
deleted file mode 100644
index ace0d40..0000000
--- a/media/mtp/tests/Android.mk
+++ /dev/null
@@ -1,51 +0,0 @@
-# Build the unit tests.
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-
-LOCAL_MODULE := mtp_ffs_handle_test
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := \
-	MtpFfsHandle_test.cpp \
-
-LOCAL_SHARED_LIBRARIES := \
-	libbase \
-	libcutils \
-	libmedia \
-	libmtp \
-	libutils \
-	liblog
-
-LOCAL_C_INCLUDES := \
-	frameworks/av/media/mtp \
-
-LOCAL_CFLAGS += -Werror -Wall
-
-include $(BUILD_NATIVE_TEST)
-
-include $(CLEAR_VARS)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-
-LOCAL_MODULE := async_io_test
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := \
-	AsyncIO_test.cpp \
-
-LOCAL_SHARED_LIBRARIES := \
-	libbase \
-	libcutils \
-	libmedia \
-	libmtp \
-	libutils \
-	liblog
-
-LOCAL_C_INCLUDES := \
-	frameworks/av/media/mtp \
-
-LOCAL_CFLAGS += -Werror -Wall
-
-include $(BUILD_NATIVE_TEST)
diff --git a/media/mtp/tests/AndroidTest.xml b/media/mtp/tests/AndroidTest.xml
new file mode 100644
index 0000000..c1f4753
--- /dev/null
+++ b/media/mtp/tests/AndroidTest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for mtp_ffs_handle_test">
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push" value="mtp_ffs_handle_test->/data/local/tmp/mtp_ffs_handle_test" />
+    </target_preparer>
+    <option name="test-suite-tag" value="apct" />
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="mtp_ffs_handle_test" />
+    </test>
+</configuration>
\ No newline at end of file
diff --git a/media/ndk/Android.bp b/media/ndk/Android.bp
index 824872f..40974f3 100644
--- a/media/ndk/Android.bp
+++ b/media/ndk/Android.bp
@@ -22,3 +22,71 @@
     first_version: "21",
     unversioned_until: "current",
 }
+
+ndk_headers {
+    name: "libmediandk_headers",
+    from: "include/media",
+    to: "media",
+    srcs: ["include/media/**/*.h"],
+    license: "NOTICE",
+}
+
+cc_library_shared {
+    name: "libmediandk",
+
+    srcs: [
+        "NdkMediaCodec.cpp",
+        "NdkMediaCrypto.cpp",
+        "NdkMediaExtractor.cpp",
+        "NdkMediaFormat.cpp",
+        "NdkMediaMuxer.cpp",
+        "NdkMediaDrm.cpp",
+        "NdkImage.cpp",
+        "NdkImageReader.cpp",
+    ],
+
+    include_dirs: [
+        "bionic/libc/private",
+        "frameworks/base/core/jni",
+        "frameworks/native/include/media/openmax",
+        "system/media/camera/include",
+    ],
+
+    cflags: [
+        "-fvisibility=hidden",
+        "-DEXPORT=__attribute__((visibility(\"default\")))",
+
+        "-Werror",
+        "-Wall",
+    ],
+
+    static_libs: [
+        "libgrallocusage",
+    ],
+
+    shared_libs: [
+        "libbinder",
+        "libmedia",
+        "libmedia_jni",
+        "libmediadrm",
+        "libskia",
+        "libstagefright",
+        "libstagefright_foundation",
+        "liblog",
+        "libutils",
+        "libcutils",
+        "libandroid",
+        "libandroid_runtime",
+        "libbinder",
+        "libgui",
+        "libui",
+    ],
+
+    export_include_dirs: ["include"],
+
+    product_variables: {
+        pdk: {
+            enabled: false,
+        },
+    },
+}
diff --git a/media/ndk/Android.mk b/media/ndk/Android.mk
deleted file mode 100644
index 2c070af..0000000
--- a/media/ndk/Android.mk
+++ /dev/null
@@ -1,73 +0,0 @@
-#
-# 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.
-#
-
-LOCAL_PATH:= $(call my-dir)
-
-ifneq ($(TARGET_BUILD_PDK), true)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:=                                       \
-                  NdkMediaCodec.cpp                     \
-                  NdkMediaCrypto.cpp                    \
-                  NdkMediaExtractor.cpp                 \
-                  NdkMediaFormat.cpp                    \
-                  NdkMediaMuxer.cpp                     \
-                  NdkMediaDrm.cpp                       \
-                  NdkImage.cpp                          \
-                  NdkImageReader.cpp                    \
-
-LOCAL_MODULE:= libmediandk
-
-LOCAL_C_INCLUDES := \
-    bionic/libc/private \
-    external/piex \
-    frameworks/base/core/jni \
-    frameworks/base/media/jni \
-    frameworks/av/include/ndk \
-    frameworks/native/include \
-    frameworks/native/include/media/openmax \
-    system/media/camera/include \
-    $(call include-path-for, libhardware)/hardware \
-
-LOCAL_CFLAGS += -fvisibility=hidden -D EXPORT='__attribute__ ((visibility ("default")))'
-
-LOCAL_CFLAGS += -Werror -Wall
-
-LOCAL_STATIC_LIBRARIES := \
-    libgrallocusage \
-
-LOCAL_SHARED_LIBRARIES := \
-    libbinder \
-    libmedia \
-    libmedia_jni \
-    libmediadrm \
-    libskia \
-    libstagefright \
-    libstagefright_foundation \
-    liblog \
-    libutils \
-    libcutils \
-    libandroid \
-    libandroid_runtime \
-    libbinder \
-    libgui \
-    libui \
-    libandroid \
-
-include $(BUILD_SHARED_LIBRARY)
-
-endif
diff --git a/media/ndk/NOTICE b/media/ndk/NOTICE
new file mode 100644
index 0000000..152be20
--- /dev/null
+++ b/media/ndk/NOTICE
@@ -0,0 +1,324 @@
+   =========================================================================
+   ==  NOTICE file corresponding to the section 4 d of                    ==
+   ==  the Apache License, Version 2.0,                                   ==
+   ==  in this case for the Android-specific code.                        ==
+   =========================================================================
+
+Android Code
+Copyright 2005-2008 The Android Open Source Project
+
+This product includes software developed as part of
+The Android Open Source Project (http://source.android.com).
+
+   =========================================================================
+   ==  NOTICE file corresponding to the section 4 d of                    ==
+   ==  the Apache License, Version 2.0,                                   ==
+   ==  in this case for Apache Commons code.                              ==
+   =========================================================================
+
+Apache Commons
+Copyright 1999-2006 The Apache Software Foundation
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
+
+   =========================================================================
+   ==  NOTICE file corresponding to the section 4 d of                    ==
+   ==  the Apache License, Version 2.0,                                   ==
+   ==  in this case for Jakarta Commons Logging.                          ==
+   =========================================================================
+
+Jakarta Commons Logging (JCL)
+Copyright 2005,2006 The Apache Software Foundation.
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
+
+   =========================================================================
+   ==  NOTICE file corresponding to the section 4 d of                    ==
+   ==  the Apache License, Version 2.0,                                   ==
+   ==  in this case for the Nuance code.                                  ==
+   =========================================================================
+
+These files are Copyright 2007 Nuance Communications, but released under
+the Apache2 License.
+
+   =========================================================================
+   ==  NOTICE file corresponding to the section 4 d of                    ==
+   ==  the Apache License, Version 2.0,                                   ==
+   ==  in this case for the Media Codecs code.                            ==
+   =========================================================================
+
+Media Codecs
+These files are Copyright 1998 - 2009 PacketVideo, but released under
+the Apache2 License.
+
+   =========================================================================
+   ==  NOTICE file corresponding to the section 4 d of                    ==
+   ==  the Apache License, Version 2.0,                                   ==
+   ==  in this case for the TagSoup code.                                 ==
+   =========================================================================
+
+This file is part of TagSoup and is Copyright 2002-2008 by John Cowan.
+
+TagSoup is licensed under the Apache License,
+Version 2.0.  You may obtain a copy of this license at
+http://www.apache.org/licenses/LICENSE-2.0 .  You may also have
+additional legal rights not granted by this license.
+
+TagSoup is distributed in the hope that it will be useful, but
+unless required by applicable law or agreed to in writing, TagSoup
+is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
+OF ANY KIND, either express or implied; not even the implied warranty
+of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+   =========================================================================
+   ==  NOTICE file corresponding to the section 4 d of                    ==
+   ==  the Apache License, Version 2.0,                                   ==
+   ==  in this case for Additional Codecs code.                           ==
+   =========================================================================
+
+Additional Codecs
+These files are Copyright 2003-2010 VisualOn, but released under
+the Apache2 License.
+
+  =========================================================================
+  ==  NOTICE file corresponding to the section 4 d of                    ==
+  ==  the Apache License, Version 2.0,                                   ==
+  ==  in this case for the Audio Effects code.                           ==
+  =========================================================================
+
+Audio Effects
+These files are Copyright (C) 2004-2010 NXP Software and
+Copyright (C) 2010 The Android Open Source Project, but released under
+the Apache2 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
+
+
+
+UNICODE, INC. LICENSE AGREEMENT - DATA FILES AND SOFTWARE
+
+Unicode Data Files include all data files under the directories
+http://www.unicode.org/Public/, http://www.unicode.org/reports/,
+and http://www.unicode.org/cldr/data/ . Unicode Software includes any
+source code published in the Unicode Standard or under the directories
+http://www.unicode.org/Public/, http://www.unicode.org/reports/, and
+http://www.unicode.org/cldr/data/.
+
+NOTICE TO USER: Carefully read the following legal agreement. BY
+DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING UNICODE INC.'S DATA
+FILES ("DATA FILES"), AND/OR SOFTWARE ("SOFTWARE"), YOU UNEQUIVOCALLY
+ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE TERMS AND CONDITIONS OF
+THIS AGREEMENT. IF YOU DO NOT AGREE, DO NOT DOWNLOAD, INSTALL, COPY,
+DISTRIBUTE OR USE THE DATA FILES OR SOFTWARE.
+
+COPYRIGHT AND PERMISSION NOTICE
+
+Copyright © 1991-2008 Unicode, Inc. All rights reserved. Distributed
+under the Terms of Use in http://www.unicode.org/copyright.html.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the Unicode data files and any associated documentation (the
+"Data Files") or Unicode software and any associated documentation (the
+"Software") to deal in the Data Files or Software without restriction,
+including without limitation the rights to use, copy, modify, merge,
+publish, distribute, and/or sell copies of the Data Files or Software,
+and to permit persons to whom the Data Files or Software are furnished to
+do so, provided that (a) the above copyright notice(s) and this permission
+notice appear with all copies of the Data Files or Software, (b) both the
+above copyright notice(s) and this permission notice appear in associated
+documentation, and (c) there is clear notice in each modified Data File
+or in the Software as well as in the documentation associated with the
+Data File(s) or Software that the data or software has been modified.
+
+THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
+INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
+OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
+OR PERFORMANCE OF THE DATA FILES OR SOFTWARE.
+
+Except as contained in this notice, the name of a copyright holder
+shall not be used in advertising or otherwise to promote the sale, use
+or other dealings in these Data Files or Software without prior written
+authorization of the copyright holder.
diff --git a/media/ndk/NdkImagePriv.h b/media/ndk/NdkImagePriv.h
index e9073d5..e0f16da 100644
--- a/media/ndk/NdkImagePriv.h
+++ b/media/ndk/NdkImagePriv.h
@@ -25,7 +25,7 @@
 #include <gui/CpuConsumer.h>
 
 #include "NdkImageReaderPriv.h"
-#include "NdkImage.h"
+#include <media/NdkImage.h>
 
 
 using namespace android;
diff --git a/media/ndk/NdkImageReaderPriv.h b/media/ndk/NdkImageReaderPriv.h
index 35af169..989c1fd 100644
--- a/media/ndk/NdkImageReaderPriv.h
+++ b/media/ndk/NdkImageReaderPriv.h
@@ -19,7 +19,7 @@
 
 #include <inttypes.h>
 
-#include "NdkImageReader.h"
+#include <media/NdkImageReader.h>
 
 #include <utils/List.h>
 #include <utils/Mutex.h>
diff --git a/media/ndk/NdkMediaCodec.cpp b/media/ndk/NdkMediaCodec.cpp
index 6d02cf1..128edba 100644
--- a/media/ndk/NdkMediaCodec.cpp
+++ b/media/ndk/NdkMediaCodec.cpp
@@ -19,8 +19,8 @@
 //#define LOG_NDEBUG 0
 #define LOG_TAG "NdkMediaCodec"
 
-#include "NdkMediaCodec.h"
-#include "NdkMediaError.h"
+#include <media/NdkMediaCodec.h>
+#include <media/NdkMediaError.h>
 #include "NdkMediaCryptoPriv.h"
 #include "NdkMediaFormatPriv.h"
 
diff --git a/media/ndk/NdkMediaCrypto.cpp b/media/ndk/NdkMediaCrypto.cpp
index 32aabdd..d7193ca 100644
--- a/media/ndk/NdkMediaCrypto.cpp
+++ b/media/ndk/NdkMediaCrypto.cpp
@@ -18,8 +18,8 @@
 #define LOG_TAG "NdkMediaCrypto"
 
 
-#include "NdkMediaCrypto.h"
-#include "NdkMediaCodec.h"
+#include <media/NdkMediaCrypto.h>
+#include <media/NdkMediaCodec.h>
 #include "NdkMediaFormatPriv.h"
 
 
diff --git a/media/ndk/NdkMediaDrm.cpp b/media/ndk/NdkMediaDrm.cpp
index 7a9240b..51143ac 100644
--- a/media/ndk/NdkMediaDrm.cpp
+++ b/media/ndk/NdkMediaDrm.cpp
@@ -17,7 +17,7 @@
 //#define LOG_NDEBUG 0
 #define LOG_TAG "NdkMediaDrm"
 
-#include "NdkMediaDrm.h"
+#include <media/NdkMediaDrm.h>
 
 #include <cutils/properties.h>
 #include <utils/Log.h>
@@ -29,7 +29,7 @@
 #include <media/stagefright/MediaErrors.h>
 #include <binder/IServiceManager.h>
 #include <media/IMediaDrmService.h>
-#include <ndk/NdkMediaCrypto.h>
+#include <media/NdkMediaCrypto.h>
 
 
 using namespace android;
diff --git a/media/ndk/NdkMediaExtractor.cpp b/media/ndk/NdkMediaExtractor.cpp
index 805eafb..e677d00 100644
--- a/media/ndk/NdkMediaExtractor.cpp
+++ b/media/ndk/NdkMediaExtractor.cpp
@@ -18,8 +18,8 @@
 #define LOG_TAG "NdkMediaExtractor"
 
 
-#include "NdkMediaError.h"
-#include "NdkMediaExtractor.h"
+#include <media/NdkMediaError.h>
+#include <media/NdkMediaExtractor.h>
 #include "NdkMediaFormatPriv.h"
 
 
diff --git a/media/ndk/NdkMediaFormat.cpp b/media/ndk/NdkMediaFormat.cpp
index 5598d5d..ee27520 100644
--- a/media/ndk/NdkMediaFormat.cpp
+++ b/media/ndk/NdkMediaFormat.cpp
@@ -19,7 +19,7 @@
 
 #include <inttypes.h>
 
-#include "NdkMediaFormat.h"
+#include <media/NdkMediaFormat.h>
 
 #include <utils/Log.h>
 #include <utils/StrongPointer.h>
diff --git a/media/ndk/NdkMediaFormatPriv.h b/media/ndk/NdkMediaFormatPriv.h
index 02342d9..c6a6563 100644
--- a/media/ndk/NdkMediaFormatPriv.h
+++ b/media/ndk/NdkMediaFormatPriv.h
@@ -27,7 +27,7 @@
 #ifndef _NDK_MEDIA_FORMAT_PRIV_H
 #define _NDK_MEDIA_FORMAT_PRIV_H
 
-#include <NdkMediaFormat.h>
+#include <media/NdkMediaFormat.h>
 
 #ifdef __cplusplus
 extern "C" {
diff --git a/media/ndk/NdkMediaMuxer.cpp b/media/ndk/NdkMediaMuxer.cpp
index bbf33cd..80a4391 100644
--- a/media/ndk/NdkMediaMuxer.cpp
+++ b/media/ndk/NdkMediaMuxer.cpp
@@ -18,8 +18,8 @@
 #define LOG_TAG "NdkMediaMuxer"
 
 
-#include "NdkMediaMuxer.h"
-#include "NdkMediaCodec.h"
+#include <media/NdkMediaMuxer.h>
+#include <media/NdkMediaCodec.h>
 #include "NdkMediaFormatPriv.h"
 
 
diff --git a/include/ndk/NdkImage.h b/media/ndk/include/media/NdkImage.h
similarity index 100%
rename from include/ndk/NdkImage.h
rename to media/ndk/include/media/NdkImage.h
diff --git a/include/ndk/NdkImageReader.h b/media/ndk/include/media/NdkImageReader.h
similarity index 100%
rename from include/ndk/NdkImageReader.h
rename to media/ndk/include/media/NdkImageReader.h
diff --git a/include/ndk/NdkMediaCodec.h b/media/ndk/include/media/NdkMediaCodec.h
similarity index 100%
rename from include/ndk/NdkMediaCodec.h
rename to media/ndk/include/media/NdkMediaCodec.h
diff --git a/include/ndk/NdkMediaCrypto.h b/media/ndk/include/media/NdkMediaCrypto.h
similarity index 100%
rename from include/ndk/NdkMediaCrypto.h
rename to media/ndk/include/media/NdkMediaCrypto.h
diff --git a/include/ndk/NdkMediaDrm.h b/media/ndk/include/media/NdkMediaDrm.h
similarity index 100%
rename from include/ndk/NdkMediaDrm.h
rename to media/ndk/include/media/NdkMediaDrm.h
diff --git a/include/ndk/NdkMediaError.h b/media/ndk/include/media/NdkMediaError.h
similarity index 100%
rename from include/ndk/NdkMediaError.h
rename to media/ndk/include/media/NdkMediaError.h
diff --git a/include/ndk/NdkMediaExtractor.h b/media/ndk/include/media/NdkMediaExtractor.h
similarity index 100%
rename from include/ndk/NdkMediaExtractor.h
rename to media/ndk/include/media/NdkMediaExtractor.h
diff --git a/include/ndk/NdkMediaFormat.h b/media/ndk/include/media/NdkMediaFormat.h
similarity index 100%
rename from include/ndk/NdkMediaFormat.h
rename to media/ndk/include/media/NdkMediaFormat.h
diff --git a/include/ndk/NdkMediaMuxer.h b/media/ndk/include/media/NdkMediaMuxer.h
similarity index 100%
rename from include/ndk/NdkMediaMuxer.h
rename to media/ndk/include/media/NdkMediaMuxer.h
diff --git a/media/vndk/Android.bp b/media/vndk/Android.bp
index a233d6c..e93fd16 100644
--- a/media/vndk/Android.bp
+++ b/media/vndk/Android.bp
@@ -1,4 +1,4 @@
 subdirs = [
-    "*",
+    "xmlparser/1.0",
 ]
 
diff --git a/media/vndk/xmlparser/1.0/Android.bp b/media/vndk/xmlparser/1.0/Android.bp
index c48703c..2f10cb1 100644
--- a/media/vndk/xmlparser/1.0/Android.bp
+++ b/media/vndk/xmlparser/1.0/Android.bp
@@ -1,6 +1,6 @@
 cc_library_shared {
-
     name: "libstagefright_xmlparser@1.0",
+    vendor_available: true,
 
     srcs: [
         "MediaCodecsXmlParser.cpp",
diff --git a/media/vndk/xmlparser/Android.bp b/media/vndk/xmlparser/Android.bp
deleted file mode 100644
index a233d6c..0000000
--- a/media/vndk/xmlparser/Android.bp
+++ /dev/null
@@ -1,4 +0,0 @@
-subdirs = [
-    "*",
-]
-
diff --git a/radio/Android.bp b/radio/Android.bp
new file mode 100644
index 0000000..8e614f2
--- /dev/null
+++ b/radio/Android.bp
@@ -0,0 +1,37 @@
+// Copyright 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.
+
+cc_library_shared {
+    name: "libradio",
+
+    srcs: [
+        "Radio.cpp",
+        "IRadio.cpp",
+        "IRadioClient.cpp",
+        "IRadioService.cpp",
+    ],
+
+    shared_libs: [
+        "libcutils",
+        "libutils",
+        "liblog",
+        "libbinder",
+        "libradio_metadata",
+    ],
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+    ],
+}
diff --git a/radio/Android.mk b/radio/Android.mk
deleted file mode 100644
index be5d283..0000000
--- a/radio/Android.mk
+++ /dev/null
@@ -1,40 +0,0 @@
-# Copyright 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-	Radio.cpp \
-	IRadio.cpp \
-	IRadioClient.cpp \
-	IRadioService.cpp
-
-LOCAL_SHARED_LIBRARIES := \
-	libcutils \
-	libutils \
-	liblog \
-	libbinder \
-	libradio_metadata
-
-#LOCAL_C_INCLUDES += \
-	system/media/camera/include \
-	system/media/private/camera/include
-
-LOCAL_MODULE:= libradio
-
-LOCAL_CFLAGS := -Werror -Wall
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/radio/Radio.cpp b/radio/Radio.cpp
index fa39589..9ddd221 100644
--- a/radio/Radio.cpp
+++ b/radio/Radio.cpp
@@ -117,8 +117,8 @@
 
 
 // Radio
-Radio::Radio(radio_handle_t handle, const sp<RadioCallback>& callback)
-    : mHandle(handle), mCallback(callback)
+Radio::Radio(radio_handle_t /*handle*/, const sp<RadioCallback>& callback)
+    : mCallback(callback)
 {
 }
 
diff --git a/services/audioflinger/Android.mk b/services/audioflinger/Android.mk
index 0c620f4..d0454d4 100644
--- a/services/audioflinger/Android.mk
+++ b/services/audioflinger/Android.mk
@@ -34,8 +34,8 @@
     TypedLogger.cpp
 
 LOCAL_C_INCLUDES := \
-    $(TOPDIR)frameworks/av/services/audiopolicy \
-    $(TOPDIR)frameworks/av/services/medialog \
+    frameworks/av/services/audiopolicy \
+    frameworks/av/services/medialog \
     $(call include-path-for, audio-utils)
 
 LOCAL_SHARED_LIBRARIES := \
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 9f19dfd..0df9a39 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -41,7 +41,6 @@
 #include <utils/threads.h>
 #include <utils/Atomic.h>
 
-#include <cutils/bitops.h>
 #include <cutils/properties.h>
 
 #include <system/audio.h>
@@ -261,10 +260,11 @@
 status_t MmapStreamInterface::openMmapStream(MmapStreamInterface::stream_direction_t direction,
                                              const audio_attributes_t *attr,
                                              audio_config_base_t *config,
-                                             const MmapStreamInterface::Client& client,
+                                             const AudioClient& client,
                                              audio_port_handle_t *deviceId,
                                              const sp<MmapStreamCallback>& callback,
-                                             sp<MmapStreamInterface>& interface)
+                                             sp<MmapStreamInterface>& interface,
+                                             audio_port_handle_t *handle)
 {
     sp<AudioFlinger> af;
     {
@@ -274,7 +274,7 @@
     status_t ret = NO_INIT;
     if (af != 0) {
         ret = af->openMmapStream(
-                direction, attr, config, client, deviceId, callback, interface);
+                direction, attr, config, client, deviceId, callback, interface, handle);
     }
     return ret;
 }
@@ -282,10 +282,11 @@
 status_t AudioFlinger::openMmapStream(MmapStreamInterface::stream_direction_t direction,
                                       const audio_attributes_t *attr,
                                       audio_config_base_t *config,
-                                      const MmapStreamInterface::Client& client,
+                                      const AudioClient& client,
                                       audio_port_handle_t *deviceId,
                                       const sp<MmapStreamCallback>& callback,
-                                      sp<MmapStreamInterface>& interface)
+                                      sp<MmapStreamInterface>& interface,
+                                      audio_port_handle_t *handle)
 {
     status_t ret = initCheck();
     if (ret != NO_ERROR) {
@@ -294,7 +295,7 @@
 
     audio_session_t sessionId = (audio_session_t) newAudioUniqueId(AUDIO_UNIQUE_ID_USE_SESSION);
     audio_stream_type_t streamType = AUDIO_STREAM_DEFAULT;
-    audio_io_handle_t io;
+    audio_io_handle_t io = AUDIO_IO_HANDLE_NONE;
     audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE;
     if (direction == MmapStreamInterface::DIRECTION_OUTPUT) {
         audio_config_t fullConfig = AUDIO_CONFIG_INITIALIZER;
@@ -307,14 +308,14 @@
                                             &fullConfig,
                                             (audio_output_flags_t)(AUDIO_OUTPUT_FLAG_MMAP_NOIRQ |
                                                     AUDIO_OUTPUT_FLAG_DIRECT),
-                                            *deviceId, &portId);
+                                            deviceId, &portId);
     } else {
         ret = AudioSystem::getInputForAttr(attr, &io,
                                               sessionId,
                                               client.clientPid,
                                               client.clientUid,
                                               config,
-                                              AUDIO_INPUT_FLAG_MMAP_NOIRQ, *deviceId, &portId);
+                                              AUDIO_INPUT_FLAG_MMAP_NOIRQ, deviceId, &portId);
     }
     if (ret != NO_ERROR) {
         return ret;
@@ -326,6 +327,7 @@
     if (thread != 0) {
         interface = new MmapThreadHandle(thread);
         thread->configure(attr, streamType, sessionId, callback, portId);
+        *handle = portId;
     } else {
         ret = NO_INIT;
     }
@@ -340,7 +342,6 @@
     AUDIO_HARDWARE_MODULE_ID_A2DP,
     AUDIO_HARDWARE_MODULE_ID_USB,
 };
-#define ARRAY_SIZE(x) (sizeof((x))/sizeof(((x)[0])))
 
 AudioHwDevice* AudioFlinger::findSuitableHwDev_l(
         audio_module_handle_t module,
@@ -350,7 +351,7 @@
     // well known modules
     if (module == 0) {
         ALOGW("findSuitableHwDev_l() loading well know audio hw modules");
-        for (size_t i = 0; i < ARRAY_SIZE(audio_interfaces); i++) {
+        for (size_t i = 0; i < arraysize(audio_interfaces); i++) {
             loadHwModule_l(audio_interfaces[i]);
         }
         // then try to find a module supporting the requested device.
@@ -520,7 +521,7 @@
 #ifdef TEE_SINK
         // dump the serially shared record tee sink
         if (mRecordTeeSource != 0) {
-            dumpTee(fd, mRecordTeeSource);
+            dumpTee(fd, mRecordTeeSource, AUDIO_IO_HANDLE_NONE, 'C');
         }
 #endif
 
@@ -1192,25 +1193,10 @@
         String8 value;
         if (param.get(String8(AudioParameter::keyBtNrec), value) == NO_ERROR) {
             bool btNrecIsOff = (value == AudioParameter::valueOff);
-            if (mBtNrecIsOff != btNrecIsOff) {
+            if (mBtNrecIsOff.exchange(btNrecIsOff) != btNrecIsOff) {
                 for (size_t i = 0; i < mRecordThreads.size(); i++) {
-                    sp<RecordThread> thread = mRecordThreads.valueAt(i);
-                    audio_devices_t device = thread->inDevice();
-                    bool suspend = audio_is_bluetooth_sco_device(device) && btNrecIsOff;
-                    // collect all of the thread's session IDs
-                    KeyedVector<audio_session_t, bool> ids = thread->sessionIds();
-                    // suspend effects associated with those session IDs
-                    for (size_t j = 0; j < ids.size(); ++j) {
-                        audio_session_t sessionId = ids.keyAt(j);
-                        thread->setEffectSuspended(FX_IID_AEC,
-                                                   suspend,
-                                                   sessionId);
-                        thread->setEffectSuspended(FX_IID_NS,
-                                                   suspend,
-                                                   sessionId);
-                    }
+                    mRecordThreads.valueAt(i)->checkBtNrec();
                 }
-                mBtNrecIsOff = btNrecIsOff;
             }
         }
         String8 screenState;
@@ -1281,7 +1267,7 @@
         if (thread == NULL) {
             thread = (ThreadBase *)checkMmapThread_l(ioHandle);
             if (thread == NULL) {
-                String8("");
+                return String8("");
             }
         }
     }
@@ -3213,6 +3199,11 @@
 
 status_t AudioFlinger::putOrphanEffectChain_l(const sp<AudioFlinger::EffectChain>& chain)
 {
+    // clear possible suspended state before parking the chain so that it starts in default state
+    // when attached to a new record thread
+    chain->setEffectSuspended_l(FX_IID_AEC, false);
+    chain->setEffectSuspended_l(FX_IID_NS, false);
+
     audio_session_t session = chain->sessionId();
     ssize_t index = mOrphanEffectChains.indexOfKey(session);
     ALOGV("putOrphanEffectChain_l session %d index %zd", session, index);
@@ -3265,7 +3256,7 @@
 }
 
 #ifdef TEE_SINK
-void AudioFlinger::dumpTee(int fd, const sp<NBAIO_Source>& source, audio_io_handle_t id)
+void AudioFlinger::dumpTee(int fd, const sp<NBAIO_Source>& source, audio_io_handle_t id, char suffix)
 {
     NBAIO_Source *teeSource = source.get();
     if (teeSource != NULL) {
@@ -3327,7 +3318,8 @@
         struct tm tm;
         localtime_r(&tv.tv_sec, &tm);
         strftime(teeTime, sizeof(teeTime), "%Y%m%d%H%M%S", &tm);
-        snprintf(&teePath[teePathLen], sizeof(teePath) - teePathLen, "%s_%d.wav", teeTime, id);
+        snprintf(&teePath[teePathLen], sizeof(teePath) - teePathLen, "%s_%d_%c.wav", teeTime, id,
+                suffix);
         // if 2 dumpsys are done within 1 second, and rotation didn't work, then discard 2nd
         int teeFd = open(teePath, O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW, S_IRUSR | S_IWUSR);
         if (teeFd >= 0) {
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 75b4e4c..9023b2d 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -25,6 +25,8 @@
 #include <sys/types.h>
 #include <limits.h>
 
+#include <android-base/macros.h>
+
 #include <cutils/compiler.h>
 #include <cutils/properties.h>
 
@@ -71,12 +73,11 @@
 #include <powermanager/IPowerManager.h>
 
 #include <media/nbaio/NBLog.h>
+#include <private/media/AudioEffectShared.h>
 #include <private/media/AudioTrackShared.h>
 
 namespace android {
 
-struct audio_track_cblk_t;
-struct effect_param_cblk_t;
 class AudioMixer;
 class AudioBuffer;
 class AudioResampler;
@@ -293,12 +294,14 @@
     status_t openMmapStream(MmapStreamInterface::stream_direction_t direction,
                             const audio_attributes_t *attr,
                             audio_config_base_t *config,
-                            const MmapStreamInterface::Client& client,
+                            const AudioClient& client,
                             audio_port_handle_t *deviceId,
                             const sp<MmapStreamCallback>& callback,
-                            sp<MmapStreamInterface>& interface);
+                            sp<MmapStreamInterface>& interface,
+                            audio_port_handle_t *handle);
 private:
-    static const size_t kLogMemorySize = 40 * 1024;
+    // FIXME The 400 is temporarily too high until a leak of writers in media.log is fixed.
+    static const size_t kLogMemorySize = 400 * 1024;
     sp<MemoryDealer>    mLogMemoryDealer;   // == 0 when NBLog is disabled
     // When a log writer is unregistered, it is done lazily so that media.log can continue to see it
     // for as long as possible.  The memory is only freed when it is needed for another log writer.
@@ -347,12 +350,13 @@
                                         sync_event_callback_t callBack,
                                         const wp<RefBase>& cookie);
 
+    bool        btNrecIsOff() const { return mBtNrecIsOff.load(); }
+
+
 private:
 
                audio_mode_t getMode() const { return mMode; }
 
-                bool        btNrecIsOff() const { return mBtNrecIsOff; }
-
                             AudioFlinger() ANDROID_API;
     virtual                 ~AudioFlinger();
 
@@ -445,8 +449,8 @@
         sp<AudioFlinger>    audioFlinger() const { return mAudioFlinger; }
 
     private:
-                            Client(const Client&);
-                            Client& operator = (const Client&);
+        DISALLOW_COPY_AND_ASSIGN(Client);
+
         const sp<AudioFlinger> mAudioFlinger;
               sp<MemoryDealer> mMemoryDealer;
         const pid_t         mPid;
@@ -466,8 +470,7 @@
                 virtual     void        binderDied(const wp<IBinder>& who);
 
     private:
-                            NotificationClient(const NotificationClient&);
-                            NotificationClient& operator = (const NotificationClient&);
+        DISALLOW_COPY_AND_ASSIGN(NotificationClient);
 
         const sp<AudioFlinger>  mAudioFlinger;
         const pid_t             mPid;
@@ -595,7 +598,7 @@
         virtual status_t createMmapBuffer(int32_t minSizeFrames,
                                           struct audio_mmap_buffer_info *info);
         virtual status_t getMmapPosition(struct audio_mmap_position *position);
-        virtual status_t start(const MmapStreamInterface::Client& client,
+        virtual status_t start(const AudioClient& client,
                                          audio_port_handle_t *handle);
         virtual status_t stop(audio_port_handle_t handle);
         virtual status_t standby();
@@ -779,7 +782,7 @@
                 volatile atomic_uint_fast32_t       mNextUniqueIds[AUDIO_UNIQUE_ID_USE_MAX];
 
                 audio_mode_t                        mMode;
-                bool                                mBtNrecIsOff;
+                std::atomic_bool                    mBtNrecIsOff;
 
                 // protected by mLock
                 Vector<AudioSessionRef*> mAudioSessionRefs;
@@ -824,7 +827,7 @@
 
 #ifdef TEE_SINK
     // tee sink, if enabled by property, allows dumpsys to write most recent audio to .wav file
-    static void dumpTee(int fd, const sp<NBAIO_Source>& source, audio_io_handle_t id = 0);
+    static void dumpTee(int fd, const sp<NBAIO_Source>& source, audio_io_handle_t id, char suffix);
 
     // whether tee sink is enabled by property
     static bool mTeeSinkInputEnabled;
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index 60eca7e..f2c1c4f 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -21,11 +21,12 @@
 
 #include "Configuration.h"
 #include <utils/Log.h>
+#include <system/audio_effects/effect_aec.h>
+#include <system/audio_effects/effect_ns.h>
+#include <system/audio_effects/effect_visualizer.h>
 #include <audio_utils/primitives.h>
-#include <private/media/AudioEffectShared.h>
 #include <media/audiohal/EffectHalInterface.h>
 #include <media/audiohal/EffectsFactoryHalInterface.h>
-#include <system/audio_effects/effect_visualizer.h>
 
 #include "AudioFlinger.h"
 #include "ServiceUtilities.h"
@@ -1810,6 +1811,7 @@
                 idx_insert);
     }
     effect->configure();
+
     return NO_ERROR;
 }
 
@@ -2031,6 +2033,7 @@
             mSuspendedEffects.add(type->timeLow, desc);
             ALOGV("setEffectSuspended_l() add entry for %08x", type->timeLow);
         }
+
         if (desc->mRefCount++ == 0) {
             sp<EffectModule> effect = getEffectIfEnabled(type);
             if (effect != 0) {
@@ -2046,7 +2049,8 @@
         desc = mSuspendedEffects.valueAt(index);
         if (desc->mRefCount <= 0) {
             ALOGW("setEffectSuspended_l() restore refcount should not be 0 %d", desc->mRefCount);
-            desc->mRefCount = 1;
+            desc->mRefCount = 0;
+            return;
         }
         if (--desc->mRefCount == 0) {
             ALOGV("setEffectSuspended_l() remove entry for %08x", mSuspendedEffects.keyAt(index));
@@ -2124,6 +2128,17 @@
 const effect_uuid_t * const SL_IID_VOLUME = &SL_IID_VOLUME_;
 #endif //OPENSL_ES_H_
 
+/* static */
+bool AudioFlinger::EffectChain::isEffectEligibleForBtNrecSuspend(const effect_uuid_t *type)
+{
+    // Only NS and AEC are suspended when BtNRec is off
+    if ((memcmp(type, FX_IID_AEC, sizeof(effect_uuid_t)) == 0) ||
+        (memcmp(type, FX_IID_NS, sizeof(effect_uuid_t)) == 0)) {
+        return true;
+    }
+    return false;
+}
+
 bool AudioFlinger::EffectChain::isEffectEligibleForSuspend(const effect_descriptor_t& desc)
 {
     // auxiliary effects and visualizer are never suspended on output mix
@@ -2178,7 +2193,7 @@
         ALOGV("checkSuspendOnEffectEnabled() enable suspending fx %08x",
             effect->desc().type.timeLow);
         sp<SuspendedEffectDesc> desc = mSuspendedEffects.valueAt(index);
-        // if effect is requested to suspended but was not yet enabled, supend it now.
+        // if effect is requested to suspended but was not yet enabled, suspend it now.
         if (desc->mEffect == 0) {
             desc->mEffect = effect;
             effect->setEnabled(false);
diff --git a/services/audioflinger/Effects.h b/services/audioflinger/Effects.h
index 0755c52..e29798b 100644
--- a/services/audioflinger/Effects.h
+++ b/services/audioflinger/Effects.h
@@ -135,15 +135,14 @@
 
     void             dump(int fd, const Vector<String16>& args);
 
-protected:
+private:
     friend class AudioFlinger;      // for mHandles
     bool                mPinned;
 
     // Maximum time allocated to effect engines to complete the turn off sequence
     static const uint32_t MAX_DISABLE_TIME_MS = 10000;
 
-    EffectModule(const EffectModule&);
-    EffectModule& operator = (const EffectModule&);
+    DISALLOW_COPY_AND_ASSIGN(EffectModule);
 
     status_t start_l();
     status_t stop_l();
@@ -232,10 +231,9 @@
 
     void dumpToBuffer(char* buffer, size_t size);
 
-protected:
+private:
     friend class AudioFlinger;          // for mEffect, mHasControl, mEnabled
-    EffectHandle(const EffectHandle&);
-    EffectHandle& operator =(const EffectHandle&);
+    DISALLOW_COPY_AND_ASSIGN(EffectHandle);
 
     Mutex mLock;                        // protects IEffect method calls
     wp<EffectModule> mEffect;           // pointer to controlled EffectModule
@@ -333,7 +331,8 @@
     void setStrategy(uint32_t strategy)
             { mStrategy = strategy; }
 
-    // suspend effect of the given type
+    // suspend or restore effects of the specified type. The number of suspend requests is counted
+    // and restore occurs once all suspend requests are cancelled.
     void setEffectSuspended_l(const effect_uuid_t *type,
                               bool suspend);
     // suspend all eligible effects
@@ -366,16 +365,15 @@
 
     void dump(int fd, const Vector<String16>& args);
 
-protected:
+private:
     friend class AudioFlinger;  // for mThread, mEffects
-    EffectChain(const EffectChain&);
-    EffectChain& operator =(const EffectChain&);
+    DISALLOW_COPY_AND_ASSIGN(EffectChain);
 
     class SuspendedEffectDesc : public RefBase {
     public:
         SuspendedEffectDesc() : mRefCount(0) {}
 
-        int mRefCount;
+        int mRefCount;   // > 0 when suspended
         effect_uuid_t mType;
         wp<EffectModule> mEffect;
     };
@@ -391,6 +389,8 @@
     // types or implementations from the suspend/restore mechanism.
     bool isEffectEligibleForSuspend(const effect_descriptor_t& desc);
 
+    static bool isEffectEligibleForBtNrecSuspend(const effect_uuid_t *type);
+
     void clearInputBuffer_l(const sp<ThreadBase>& thread);
 
     void setThread(const sp<ThreadBase>& thread);
@@ -417,6 +417,6 @@
              // mSuspendedEffects lists all effects currently suspended in the chain.
              // Use effect type UUID timelow field as key. There is no real risk of identical
              // timeLow fields among effect type UUIDs.
-             // Updated by updateSuspendedSessions_l() only.
+             // Updated by setEffectSuspended_l() and setEffectSuspendedAll_l() only.
              KeyedVector< int, sp<SuspendedEffectDesc> > mSuspendedEffects;
 };
diff --git a/services/audioflinger/FastCapture.cpp b/services/audioflinger/FastCapture.cpp
index 873a9ad..d063772 100644
--- a/services/audioflinger/FastCapture.cpp
+++ b/services/audioflinger/FastCapture.cpp
@@ -57,7 +57,7 @@
     return mSQ.poll();
 }
 
-void FastCapture::setLog(NBLog::Writer *logWriter __unused)
+void FastCapture::setNBLogWriter(NBLog::Writer *logWriter __unused)
 {
 }
 
diff --git a/services/audioflinger/FastCapture.h b/services/audioflinger/FastCapture.h
index e258a4d..c3817c0 100644
--- a/services/audioflinger/FastCapture.h
+++ b/services/audioflinger/FastCapture.h
@@ -39,7 +39,7 @@
 
     // callouts
     virtual const FastThreadState *poll();
-    virtual void setLog(NBLog::Writer *logWriter);
+    virtual void setNBLogWriter(NBLog::Writer *logWriter);
     virtual void onIdle();
     virtual void onExit();
     virtual bool isSubClassCommand(FastThreadState::Command command);
diff --git a/services/audioflinger/FastMixer.cpp b/services/audioflinger/FastMixer.cpp
index 103e7f8..c4f1af3 100644
--- a/services/audioflinger/FastMixer.cpp
+++ b/services/audioflinger/FastMixer.cpp
@@ -41,6 +41,7 @@
 #include <audio_utils/format.h>
 #include <media/AudioMixer.h>
 #include "FastMixer.h"
+#include "TypedLogger.h"
 
 namespace android {
 
@@ -101,10 +102,12 @@
     return mSQ.poll();
 }
 
-void FastMixer::setLog(NBLog::Writer *logWriter)
+void FastMixer::setNBLogWriter(NBLog::Writer *logWriter)
 {
+    // FIXME If mMixer is set or changed prior to this, we don't inform correctly.
+    //       Should cache logWriter and re-apply it at the assignment to mMixer.
     if (mMixer != NULL) {
-        mMixer->setLog(logWriter);
+        mMixer->setNBLogWriter(logWriter);
     }
 }
 
@@ -135,6 +138,7 @@
 
 void FastMixer::onStateChange()
 {
+    LOG_HIST_FLUSH();
     const FastMixerState * const current = (const FastMixerState *) mCurrent;
     const FastMixerState * const previous = (const FastMixerState *) mPrevious;
     FastMixerDumpState * const dumpState = (FastMixerDumpState *) mDumpState;
@@ -188,6 +192,7 @@
             //       implementation; it would be better to have normal mixer allocate for us
             //       to avoid blocking here and to prevent possible priority inversion
             mMixer = new AudioMixer(frameCount, mSampleRate, FastMixerState::sMaxFastTracks);
+            // FIXME See the other FIXME at FastMixer::setNBLogWriter()
             const size_t mixerFrameSize = mSinkChannelCount
                     * audio_bytes_per_sample(mMixerBufferFormat);
             mMixerBufferSize = mixerFrameSize * frameCount;
@@ -330,6 +335,7 @@
 
 void FastMixer::onWork()
 {
+    LOG_HIST_TS();
     const FastMixerState * const current = (const FastMixerState *) mCurrent;
     FastMixerDumpState * const dumpState = (FastMixerDumpState *) mDumpState;
     const FastMixerState::Command command = mCommand;
diff --git a/services/audioflinger/FastMixer.h b/services/audioflinger/FastMixer.h
index bdfd8a0..930fa8d 100644
--- a/services/audioflinger/FastMixer.h
+++ b/services/audioflinger/FastMixer.h
@@ -46,7 +46,7 @@
 
     // callouts
     virtual const FastThreadState *poll();
-    virtual void setLog(NBLog::Writer *logWriter);
+    virtual void setNBLogWriter(NBLog::Writer *logWriter);
     virtual void onIdle();
     virtual void onExit();
     virtual bool isSubClassCommand(FastThreadState::Command command);
diff --git a/services/audioflinger/FastThread.cpp b/services/audioflinger/FastThread.cpp
index cf9fce3..85865b7 100644
--- a/services/audioflinger/FastThread.cpp
+++ b/services/audioflinger/FastThread.cpp
@@ -27,6 +27,7 @@
 #include <utils/Trace.h>
 #include "FastThread.h"
 #include "FastThreadDumpState.h"
+#include "TypedLogger.h"
 
 #define FAST_DEFAULT_NS    999999999L   // ~1 sec: default time to sleep
 #define FAST_HOT_IDLE_NS     1000000L   // 1 ms: time to sleep while hot idling
@@ -64,8 +65,8 @@
     /* mMeasuredWarmupTs({0, 0}), */
     mWarmupCycles(0),
     mWarmupConsecutiveInRangeCycles(0),
-    // mDummyLogWriter
-    mLogWriter(&mDummyLogWriter),
+    // mDummyNBLogWriter
+    mNBLogWriter(&mDummyNBLogWriter),
     mTimestampStatus(INVALID_OPERATION),
 
     mCommand(FastThreadState::INITIAL),
@@ -90,6 +91,9 @@
 
 bool FastThread::threadLoop()
 {
+    // LOGT now works even if tlNBLogWriter is nullptr, but we're considering changing that,
+    // so this initialization permits a future change to remove the check for nullptr.
+    tlNBLogWriter = &mDummyNBLogWriter;
     for (;;) {
 
         // either nanosleep, sched_yield, or busy wait
@@ -119,8 +123,9 @@
 
             // As soon as possible of learning of a new dump area, start using it
             mDumpState = next->mDumpState != NULL ? next->mDumpState : mDummyDumpState;
-            mLogWriter = next->mNBLogWriter != NULL ? next->mNBLogWriter : &mDummyLogWriter;
-            setLog(mLogWriter);
+            mNBLogWriter = next->mNBLogWriter != NULL ? next->mNBLogWriter : &mDummyNBLogWriter;
+            setNBLogWriter(mNBLogWriter);   // FastMixer informs its AudioMixer, FastCapture ignores
+            tlNBLogWriter = mNBLogWriter;
 
             // We want to always have a valid reference to the previous (non-idle) state.
             // However, the state queue only guarantees access to current and previous states.
@@ -218,7 +223,6 @@
         struct timespec newTs;
         int rc = clock_gettime(CLOCK_MONOTONIC, &newTs);
         if (rc == 0) {
-            //mLogWriter->logTimestamp(newTs);
             if (mOldTsValid) {
                 time_t sec = newTs.tv_sec - mOldTs.tv_sec;
                 long nsec = newTs.tv_nsec - mOldTs.tv_nsec;
diff --git a/services/audioflinger/FastThread.h b/services/audioflinger/FastThread.h
index 816b666..2a71414 100644
--- a/services/audioflinger/FastThread.h
+++ b/services/audioflinger/FastThread.h
@@ -41,7 +41,7 @@
     // callouts to subclass in same lexical order as they were in original FastMixer.cpp
     // FIXME need comments
     virtual const FastThreadState *poll() = 0;
-    virtual void setLog(NBLog::Writer *logWriter __unused) { }
+    virtual void setNBLogWriter(NBLog::Writer *logWriter __unused) { }
     virtual void onIdle() = 0;
     virtual void onExit() = 0;
     virtual bool isSubClassCommand(FastThreadState::Command command) = 0;
@@ -81,8 +81,8 @@
     struct timespec mMeasuredWarmupTs;  // how long did it take for warmup to complete
     uint32_t        mWarmupCycles;  // counter of number of loop cycles during warmup phase
     uint32_t        mWarmupConsecutiveInRangeCycles;    // number of consecutive cycles in range
-    NBLog::Writer   mDummyLogWriter;
-    NBLog::Writer*  mLogWriter;
+    NBLog::Writer   mDummyNBLogWriter;
+    NBLog::Writer*  mNBLogWriter;   // always non-nullptr: real NBLog::Writer* or &mDummyNBLogWriter
     status_t        mTimestampStatus;
 
     FastThreadState::Command mCommand;
diff --git a/services/audioflinger/MmapTracks.h b/services/audioflinger/MmapTracks.h
index e4fe8ac..2a27dfd 100644
--- a/services/audioflinger/MmapTracks.h
+++ b/services/audioflinger/MmapTracks.h
@@ -41,11 +41,10 @@
      static void        appendDumpHeader(String8& result);
             void        dump(char* buffer, size_t size);
 
-protected:
+private:
     friend class MmapThread;
 
-                MmapTrack(const MmapTrack&);
-                MmapTrack& operator = (const MmapTrack&);
+    DISALLOW_COPY_AND_ASSIGN(MmapTrack);
 
     // AudioBufferProvider interface
     virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer);
diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h
index f84ba08..3f1a0c0 100644
--- a/services/audioflinger/PlaybackTracks.h
+++ b/services/audioflinger/PlaybackTracks.h
@@ -94,8 +94,7 @@
     friend class DirectOutputThread;
     friend class OffloadThread;
 
-                        Track(const Track&);
-                        Track& operator = (const Track&);
+    DISALLOW_COPY_AND_ASSIGN(Track);
 
     // AudioBufferProvider interface
     virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer);
diff --git a/services/audioflinger/RecordTracks.h b/services/audioflinger/RecordTracks.h
index 72ebc93..3f83ca8 100644
--- a/services/audioflinger/RecordTracks.h
+++ b/services/audioflinger/RecordTracks.h
@@ -65,8 +65,7 @@
 private:
     friend class AudioFlinger;  // for mState
 
-                        RecordTrack(const RecordTrack&);
-                        RecordTrack& operator = (const RecordTrack&);
+    DISALLOW_COPY_AND_ASSIGN(RecordTrack);
 
     // AudioBufferProvider interface
     virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer);
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index a6857fe..65eccb6 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -100,10 +100,6 @@
     return a < b ? a : b;
 }
 
-#ifndef ARRAY_SIZE
-#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
-#endif
-
 namespace android {
 
 // retry counts for buffer fill timeout
@@ -995,13 +991,6 @@
     ALOGW("power manager service died !!!");
 }
 
-void AudioFlinger::ThreadBase::setEffectSuspended(
-        const effect_uuid_t *type, bool suspend, audio_session_t sessionId)
-{
-    Mutex::Autolock _l(mLock);
-    setEffectSuspended_l(type, suspend, sessionId);
-}
-
 void AudioFlinger::ThreadBase::setEffectSuspended_l(
         const effect_uuid_t *type, bool suspend, audio_session_t sessionId)
 {
@@ -1180,6 +1169,11 @@
         return BAD_VALUE;
     }
 
+    // always allow effects without processing load or latency
+    if ((desc->flags & EFFECT_FLAG_NO_PROCESS_MASK) == EFFECT_FLAG_NO_PROCESS) {
+        return NO_ERROR;
+    }
+
     switch (mType) {
     case MIXER: {
         // Reject any effect on mixer multichannel sinks.
@@ -1210,10 +1204,6 @@
                 }
             }
 
-            // always allow effects without processing load or latency
-            if ((desc->flags & EFFECT_FLAG_NO_PROCESS_MASK) == EFFECT_FLAG_NO_PROCESS) {
-                break;
-            }
             if (flags & AUDIO_OUTPUT_FLAG_RAW) {
                 ALOGW("checkEffectCompatibility_l(): effect %s on playback thread in raw mode",
                       desc->name);
@@ -1455,6 +1445,7 @@
     effect->setDevice(mInDevice);
     effect->setMode(mAudioFlinger->getMode());
     effect->setAudioSource(mAudioSource);
+
     return NO_ERROR;
 }
 
@@ -2045,7 +2036,7 @@
             pid_t callingPid = IPCThreadState::self()->getCallingPid();
             // we don't have CAP_SYS_NICE, nor do we want to have it as it's too powerful,
             // so ask activity manager to do this on our behalf
-            sendPrioConfigEvent_l(callingPid, tid, kPriorityAudioApp, true /*isForApp*/);
+            sendPrioConfigEvent_l(callingPid, tid, kPriorityAudioApp, true /*forApp*/);
         }
     }
 
@@ -2182,7 +2173,7 @@
         }
 
         char buffer[256];
-        track->dump(buffer, ARRAY_SIZE(buffer), false /* active */);
+        track->dump(buffer, arraysize(buffer), false /* active */);
         mLocalLog.log("addTrack_l    (%p) %s", track.get(), buffer + 4); // log for analysis
 
         status = NO_ERROR;
@@ -2212,7 +2203,7 @@
     track->triggerEvents(AudioSystem::SYNC_EVENT_PRESENTATION_COMPLETE);
 
     char buffer[256];
-    track->dump(buffer, ARRAY_SIZE(buffer), false /* active */);
+    track->dump(buffer, arraysize(buffer), false /* active */);
     mLocalLog.log("removeTrack_l (%p) %s", track.get(), buffer + 4); // log for analysis
 
     mTracks.remove(track);
@@ -2930,7 +2921,7 @@
 
 bool AudioFlinger::PlaybackThread::threadLoop()
 {
-    logWriterTLS = mNBLogWriter.get();
+    tlNBLogWriter = mNBLogWriter.get();
 
     Vector< sp<Track> > tracksToRemove;
 
@@ -2957,9 +2948,13 @@
 
     acquireWakeLock();
 
-    // mNBLogWriter->log can only be called while thread mutex mLock is held.
+    // mNBLogWriter logging APIs can only be called by a single thread, typically the
+    // thread associated with this PlaybackThread.
+    // If you want to share the mNBLogWriter with other threads (for example, binder threads)
+    // then all such threads must agree to hold a common mutex before logging.
     // So if you need to log when mutex is unlocked, set logString to a non-NULL string,
     // and then that string will be logged at the next convenient opportunity.
+    // See reference to logString below.
     const char *logString = NULL;
 
     // Estimated time for next buffer to be written to hal. This is used only on
@@ -2967,9 +2962,7 @@
     nsecs_t timeLoopNextNs = 0;
 
     checkSilentMode_l();
-#if 0
-    int z = 0; // used in logFormat example
-#endif
+
     while (!exitPending())
     {
         // Log merge requests are performed during AudioFlinger binder transactions, but
@@ -2986,6 +2979,7 @@
 
             processConfigEvents_l();
 
+            // See comment at declaration of logString for why this is done under mLock
             if (logString != NULL) {
                 mNBLogWriter->logTimestamp();
                 mNBLogWriter->log(logString);
@@ -3412,7 +3406,7 @@
                 removeTrack_l(track);
             } else { // inactive but not terminated
                 char buffer[256];
-                track->dump(buffer, ARRAY_SIZE(buffer), false /* active */);
+                track->dump(buffer, arraysize(buffer), false /* active */);
                 mLocalLog.log("removeTracks_l(%p) %s", track.get(), buffer + 4);
             }
         }
@@ -3738,7 +3732,7 @@
         // start the fast mixer
         mFastMixer->run("FastMixer", PRIORITY_URGENT_AUDIO);
         pid_t tid = mFastMixer->getTid();
-        sendPrioConfigEvent(getpid_cached, tid, kPriorityFastMixer, false);
+        sendPrioConfigEvent(getpid_cached, tid, kPriorityFastMixer, false /*forApp*/);
         stream()->setHalThreadPriority(kPriorityFastMixer);
 
 #ifdef AUDIO_WATCHDOG
@@ -3747,7 +3741,7 @@
         mAudioWatchdog->setDump(&mAudioWatchdogDump);
         mAudioWatchdog->run("AudioWatchdog", PRIORITY_URGENT_AUDIO);
         tid = mAudioWatchdog->getTid();
-        sendPrioConfigEvent(getpid_cached, tid, kPriorityFastMixer);
+        sendPrioConfigEvent(getpid_cached, tid, kPriorityFastMixer, false /*forApp*/);
 #endif
 
     }
@@ -4775,7 +4769,7 @@
 
 #ifdef TEE_SINK
     // Write the tee output to a .wav file
-    dumpTee(fd, mTeeSource, mId);
+    dumpTee(fd, mTeeSource, mId, 'M');
 #endif
 
 }
@@ -5948,6 +5942,7 @@
     // mPipeMemory
     // mFastCaptureNBLogWriter
     , mFastTrackAvail(false)
+    , mBtNrecSuspended(false)
 {
     snprintf(mThreadName, kThreadNameLength, "AudioIn_%X", id);
     mNBLogWriter = audioFlinger->newWriter_l(kLogSize, mThreadName);
@@ -5971,12 +5966,17 @@
     switch (kUseFastCapture) {
     case FastCapture_Never:
         initFastCapture = false;
+        ALOGV("%p kUseFastCapture = Never, initFastCapture = false", this);
         break;
     case FastCapture_Always:
         initFastCapture = true;
+        ALOGV("%p kUseFastCapture = Always, initFastCapture = true", this);
         break;
     case FastCapture_Static:
         initFastCapture = (mFrameCount * 1000) / mSampleRate < kMinNormalCaptureBufferSizeMs;
+        ALOGV("%p kUseFastCapture = Static, (%lld * 1000) / %u vs %u, initFastCapture = %d",
+                this, (long long)mFrameCount, mSampleRate, kMinNormalCaptureBufferSizeMs,
+                initFastCapture);
         break;
     // case FastCapture_Dynamic:
     }
@@ -5987,13 +5987,16 @@
         // quadruple-buffering of 20 ms each; this ensures we can sleep for 20ms in RecordThread
         size_t pipeFramesP2 = roundup(4 * FMS_20 * mSampleRate / 1000);
         size_t pipeSize = pipeFramesP2 * Format_frameSize(format);
-        void *pipeBuffer;
+        void *pipeBuffer = nullptr;
         const sp<MemoryDealer> roHeap(readOnlyHeap());
         sp<IMemory> pipeMemory;
         if ((roHeap == 0) ||
                 (pipeMemory = roHeap->allocate(pipeSize)) == 0 ||
-                (pipeBuffer = pipeMemory->pointer()) == NULL) {
-            ALOGE("not enough memory for pipe buffer size=%zu", pipeSize);
+                (pipeBuffer = pipeMemory->pointer()) == nullptr) {
+            ALOGE("not enough memory for pipe buffer size=%zu; "
+                    "roHeap=%p, pipeMemory=%p, pipeBuffer=%p; roHeapSize: %lld",
+                    pipeSize, roHeap.get(), pipeMemory.get(), pipeBuffer,
+                    (long long)kRecordThreadReadOnlyHeapSize);
             goto failed;
         }
         // pipe will be shared directly with fast clients, so clear to avoid leaking old information
@@ -6042,7 +6045,7 @@
         // start the fast capture
         mFastCapture->run("FastCapture", ANDROID_PRIORITY_URGENT_AUDIO);
         pid_t tid = mFastCapture->getTid();
-        sendPrioConfigEvent(getpid_cached, tid, kPriorityFastCapture, false);
+        sendPrioConfigEvent(getpid_cached, tid, kPriorityFastCapture, false /*forApp*/);
         stream()->setHalThreadPriority(kPriorityFastCapture);
 #ifdef AUDIO_WATCHDOG
         // FIXME
@@ -6635,19 +6638,19 @@
               audio_input_flags_t old = *flags;
               chain->checkInputFlagCompatibility(flags);
               if (old != *flags) {
-                  ALOGV("AUDIO_INPUT_FLAGS denied by effect old=%#x new=%#x",
-                          (int)old, (int)*flags);
+                  ALOGV("%p AUDIO_INPUT_FLAGS denied by effect old=%#x new=%#x",
+                          this, (int)old, (int)*flags);
               }
           }
           ALOGV_IF((*flags & AUDIO_INPUT_FLAG_FAST) != 0,
-                   "AUDIO_INPUT_FLAG_FAST accepted: frameCount=%zu mFrameCount=%zu",
-                   frameCount, mFrameCount);
+                   "%p AUDIO_INPUT_FLAG_FAST accepted: frameCount=%zu mFrameCount=%zu",
+                   this, frameCount, mFrameCount);
       } else {
-        ALOGV("AUDIO_INPUT_FLAG_FAST denied: frameCount=%zu mFrameCount=%zu mPipeFramesP2=%zu "
-                "format=%#x isLinear=%d channelMask=%#x sampleRate=%u mSampleRate=%u "
+        ALOGV("%p AUDIO_INPUT_FLAG_FAST denied: frameCount=%zu mFrameCount=%zu mPipeFramesP2=%zu "
+                "format=%#x isLinear=%d mFormat=%#x channelMask=%#x sampleRate=%u mSampleRate=%u "
                 "hasFastCapture=%d tid=%d mFastTrackAvail=%d",
-                frameCount, mFrameCount, mPipeFramesP2,
-                format, audio_is_linear_pcm(format), channelMask, sampleRate, mSampleRate,
+                this, frameCount, mFrameCount, mPipeFramesP2,
+                format, audio_is_linear_pcm(format), mFormat, channelMask, sampleRate, mSampleRate,
                 hasFastCapture(), tid, mFastTrackAvail);
         *flags = (audio_input_flags_t)(*flags & ~AUDIO_INPUT_FLAG_FAST);
       }
@@ -6704,17 +6707,11 @@
         }
         mTracks.add(track);
 
-        // disable AEC and NS if the device is a BT SCO headset supporting those pre processings
-        bool suspend = audio_is_bluetooth_sco_device(mInDevice) &&
-                        mAudioFlinger->btNrecIsOff();
-        setEffectSuspended_l(FX_IID_AEC, suspend, sessionId);
-        setEffectSuspended_l(FX_IID_NS, suspend, sessionId);
-
         if ((*flags & AUDIO_INPUT_FLAG_FAST) && (tid != -1)) {
             pid_t callingPid = IPCThreadState::self()->getCallingPid();
             // we don't have CAP_SYS_NICE, nor do we want to have it as it's too powerful,
             // so ask activity manager to do this on our behalf
-            sendPrioConfigEvent_l(callingPid, tid, kPriorityAudioApp, true);
+            sendPrioConfigEvent_l(callingPid, tid, kPriorityAudioApp, true /*forApp*/);
         }
     }
 
@@ -7072,6 +7069,26 @@
     buffer->frameCount = 0;
 }
 
+void AudioFlinger::RecordThread::checkBtNrec()
+{
+    Mutex::Autolock _l(mLock);
+    checkBtNrec_l();
+}
+
+void AudioFlinger::RecordThread::checkBtNrec_l()
+{
+    // disable AEC and NS if the device is a BT SCO headset supporting those
+    // pre processings
+    bool suspend = audio_is_bluetooth_sco_device(mInDevice) &&
+                        mAudioFlinger->btNrecIsOff();
+    if (mBtNrecSuspended.exchange(suspend) != suspend) {
+        for (size_t i = 0; i < mEffectChains.size(); i++) {
+            setEffectSuspended_l(FX_IID_AEC, suspend, mEffectChains[i]->sessionId());
+            setEffectSuspended_l(FX_IID_NS, suspend, mEffectChains[i]->sessionId());
+        }
+    }
+}
+
 
 bool AudioFlinger::RecordThread::checkForNewParameter_l(const String8& keyValuePair,
                                                         status_t& status)
@@ -7144,17 +7161,7 @@
             if (value != AUDIO_DEVICE_NONE) {
                 mPrevInDevice = value;
             }
-            // disable AEC and NS if the device is a BT SCO headset supporting those
-            // pre processings
-            if (mTracks.size() > 0) {
-                bool suspend = audio_is_bluetooth_sco_device(mInDevice) &&
-                                    mAudioFlinger->btNrecIsOff();
-                for (size_t i = 0; i < mTracks.size(); i++) {
-                    sp<RecordTrack> track = mTracks[i];
-                    setEffectSuspended_l(FX_IID_AEC, suspend, track->sessionId());
-                    setEffectSuspended_l(FX_IID_NS, suspend, track->sessionId());
-                }
-            }
+            checkBtNrec_l();
         }
     }
     if (param.getInt(String8(AudioParameter::keyInputSource), value) == NO_ERROR &&
@@ -7244,6 +7251,10 @@
     result = mInput->stream->getBufferSize(&mBufferSize);
     LOG_ALWAYS_FATAL_IF(result != OK, "Error retrieving buffer size from HAL: %d", result);
     mFrameCount = mBufferSize / mFrameSize;
+    ALOGV("%p RecordThread params: mChannelCount=%u, mFormat=%#x, mFrameSize=%lld, "
+            "mBufferSize=%lld, mFrameCount=%lld",
+            this, mChannelCount, mFormat, (long long)mFrameSize, (long long)mBufferSize,
+            (long long)mFrameCount);
     // This is the formula for calculating the temporary buffer size.
     // With 7 HAL buffers, we can guarantee ability to down-sample the input by ratio of 6:1 to
     // 1 full output buffer, regardless of the alignment of the available input.
@@ -7383,17 +7394,7 @@
         mEffectChains[i]->setDevice_l(mInDevice);
     }
 
-    // disable AEC and NS if the device is a BT SCO headset supporting those
-    // pre processings
-    if (mTracks.size() > 0) {
-        bool suspend = audio_is_bluetooth_sco_device(mInDevice) &&
-                            mAudioFlinger->btNrecIsOff();
-        for (size_t i = 0; i < mTracks.size(); i++) {
-            sp<RecordTrack> track = mTracks[i];
-            setEffectSuspended_l(FX_IID_AEC, suspend, track->sessionId());
-            setEffectSuspended_l(FX_IID_NS, suspend, track->sessionId());
-        }
-    }
+    checkBtNrec_l();
 
     // store new source and send to effects
     if (mAudioSource != patch->sinks[0].ext.mix.usecase.source) {
@@ -7512,7 +7513,7 @@
     return mThread->getMmapPosition(position);
 }
 
-status_t AudioFlinger::MmapThreadHandle::start(const MmapStreamInterface::Client& client,
+status_t AudioFlinger::MmapThreadHandle::start(const AudioClient& client,
         audio_port_handle_t *handle)
 
 {
@@ -7605,75 +7606,75 @@
     return mHalStream->getMmapPosition(position);
 }
 
-status_t AudioFlinger::MmapThread::start(const MmapStreamInterface::Client& client,
+status_t AudioFlinger::MmapThread::start(const AudioClient& client,
                                          audio_port_handle_t *handle)
 {
-    ALOGV("%s clientUid %d mStandby %d", __FUNCTION__, client.clientUid, mStandby);
+    ALOGV("%s clientUid %d mStandby %d mPortId %d *handle %d", __FUNCTION__,
+          client.clientUid, mStandby, mPortId, *handle);
     if (mHalStream == 0) {
         return NO_INIT;
     }
 
     status_t ret;
-    audio_session_t sessionId;
-    audio_port_handle_t portId;
 
-    if (mActiveTracks.size() == 0) {
+    if (*handle == mPortId) {
         // for the first track, reuse portId and session allocated when the stream was opened
         ret = mHalStream->start();
         if (ret != NO_ERROR) {
             ALOGE("%s: error mHalStream->start() = %d for first track", __FUNCTION__, ret);
             return ret;
         }
-        portId = mPortId;
-        sessionId = mSessionId;
         mStandby = false;
+        return NO_ERROR;
+    }
+
+    audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE;
+
+    audio_io_handle_t io = mId;
+    if (isOutput()) {
+        audio_config_t config = AUDIO_CONFIG_INITIALIZER;
+        config.sample_rate = mSampleRate;
+        config.channel_mask = mChannelMask;
+        config.format = mFormat;
+        audio_stream_type_t stream = streamType();
+        audio_output_flags_t flags =
+                (audio_output_flags_t)(AUDIO_OUTPUT_FLAG_MMAP_NOIRQ | AUDIO_OUTPUT_FLAG_DIRECT);
+        audio_port_handle_t deviceId = AUDIO_PORT_HANDLE_NONE;
+        ret = AudioSystem::getOutputForAttr(&mAttr, &io,
+                                            mSessionId,
+                                            &stream,
+                                            client.clientUid,
+                                            &config,
+                                            flags,
+                                            &deviceId,
+                                            &portId);
     } else {
-        // for other tracks than first one, get a new port ID from APM.
-        sessionId = (audio_session_t)mAudioFlinger->newAudioUniqueId(AUDIO_UNIQUE_ID_USE_SESSION);
-        audio_io_handle_t io;
-        if (isOutput()) {
-            audio_config_t config = AUDIO_CONFIG_INITIALIZER;
-            config.sample_rate = mSampleRate;
-            config.channel_mask = mChannelMask;
-            config.format = mFormat;
-            audio_stream_type_t stream = streamType();
-            audio_output_flags_t flags =
-                    (audio_output_flags_t)(AUDIO_OUTPUT_FLAG_MMAP_NOIRQ | AUDIO_OUTPUT_FLAG_DIRECT);
-            ret = AudioSystem::getOutputForAttr(&mAttr, &io,
-                                                sessionId,
-                                                &stream,
-                                                client.clientUid,
-                                                &config,
-                                                flags,
-                                                AUDIO_PORT_HANDLE_NONE,
-                                                &portId);
-        } else {
-            audio_config_base_t config;
-            config.sample_rate = mSampleRate;
-            config.channel_mask = mChannelMask;
-            config.format = mFormat;
-            ret = AudioSystem::getInputForAttr(&mAttr, &io,
-                                                  sessionId,
-                                                  client.clientPid,
-                                                  client.clientUid,
-                                                  &config,
-                                                  AUDIO_INPUT_FLAG_MMAP_NOIRQ,
-                                                  AUDIO_PORT_HANDLE_NONE,
-                                                  &portId);
-        }
-        // APM should not chose a different input or output stream for the same set of attributes
-        // and audo configuration
-        if (ret != NO_ERROR || io != mId) {
-            ALOGE("%s: error getting output or input from APM (error %d, io %d expected io %d)",
-                  __FUNCTION__, ret, io, mId);
-            return BAD_VALUE;
-        }
+        audio_config_base_t config;
+        config.sample_rate = mSampleRate;
+        config.channel_mask = mChannelMask;
+        config.format = mFormat;
+        audio_port_handle_t deviceId = AUDIO_PORT_HANDLE_NONE;
+        ret = AudioSystem::getInputForAttr(&mAttr, &io,
+                                              mSessionId,
+                                              client.clientPid,
+                                              client.clientUid,
+                                              &config,
+                                              AUDIO_INPUT_FLAG_MMAP_NOIRQ,
+                                              &deviceId,
+                                              &portId);
+    }
+    // APM should not chose a different input or output stream for the same set of attributes
+    // and audo configuration
+    if (ret != NO_ERROR || io != mId) {
+        ALOGE("%s: error getting output or input from APM (error %d, io %d expected io %d)",
+              __FUNCTION__, ret, io, mId);
+        return BAD_VALUE;
     }
 
     if (isOutput()) {
-        ret = AudioSystem::startOutput(mId, streamType(), sessionId);
+        ret = AudioSystem::startOutput(mId, streamType(), mSessionId);
     } else {
-        ret = AudioSystem::startInput(mId, sessionId);
+        ret = AudioSystem::startInput(mId, mSessionId);
     }
 
     // abort if start is rejected by audio policy manager
@@ -7681,9 +7682,9 @@
         ALOGE("%s: error start rejected by AudioPolicyManager = %d", __FUNCTION__, ret);
         if (mActiveTracks.size() != 0) {
             if (isOutput()) {
-                AudioSystem::releaseOutput(mId, streamType(), sessionId);
+                AudioSystem::releaseOutput(mId, streamType(), mSessionId);
             } else {
-                AudioSystem::releaseInput(mId, sessionId);
+                AudioSystem::releaseInput(mId, mSessionId);
             }
         } else {
             mHalStream->stop();
@@ -7691,11 +7692,11 @@
         return PERMISSION_DENIED;
     }
 
-    sp<MmapTrack> track = new MmapTrack(this, mSampleRate, mFormat, mChannelMask, sessionId,
+    sp<MmapTrack> track = new MmapTrack(this, mSampleRate, mFormat, mChannelMask, mSessionId,
                                         client.clientUid, portId);
 
     mActiveTracks.add(track);
-    sp<EffectChain> chain = getEffectChain_l(sessionId);
+    sp<EffectChain> chain = getEffectChain_l(mSessionId);
     if (chain != 0) {
         chain->setStrategy(AudioSystem::getStrategyForStream(streamType()));
         chain->incTrackCnt();
@@ -7703,10 +7704,9 @@
     }
 
     *handle = portId;
-
     broadcast_l();
 
-    ALOGV("%s DONE handle %d stream %p", __FUNCTION__, portId, mHalStream.get());
+    ALOGV("%s DONE handle %d stream %p", __FUNCTION__, *handle, mHalStream.get());
 
     return NO_ERROR;
 }
@@ -7719,6 +7719,11 @@
         return NO_INIT;
     }
 
+    if (handle == mPortId) {
+        mHalStream->stop();
+        return NO_ERROR;
+    }
+
     sp<MmapTrack> track;
     for (const sp<MmapTrack> &t : mActiveTracks) {
         if (handle == t->portId()) {
@@ -7734,14 +7739,10 @@
 
     if (isOutput()) {
         AudioSystem::stopOutput(mId, streamType(), track->sessionId());
-        if (mActiveTracks.size() != 0) {
-            AudioSystem::releaseOutput(mId, streamType(), track->sessionId());
-        }
+        AudioSystem::releaseOutput(mId, streamType(), track->sessionId());
     } else {
         AudioSystem::stopInput(mId, track->sessionId());
-        if (mActiveTracks.size() != 0) {
-            AudioSystem::releaseInput(mId, track->sessionId());
-        }
+        AudioSystem::releaseInput(mId, track->sessionId());
     }
 
     sp<EffectChain> chain = getEffectChain_l(track->sessionId());
@@ -7752,9 +7753,6 @@
 
     broadcast_l();
 
-    if (mActiveTracks.size() == 0) {
-        mHalStream->stop();
-    }
     return NO_ERROR;
 }
 
@@ -7857,17 +7855,34 @@
 {
     AudioParameter param = AudioParameter(keyValuePair);
     int value;
+    bool sendToHal = true;
     if (param.getInt(String8(AudioParameter::keyRouting), value) == NO_ERROR) {
+        audio_devices_t device = (audio_devices_t)value;
         // forward device change to effects that have requested to be
         // aware of attached audio device.
-        if (value != AUDIO_DEVICE_NONE) {
-            mOutDevice = value;
+        if (device != AUDIO_DEVICE_NONE) {
             for (size_t i = 0; i < mEffectChains.size(); i++) {
-                mEffectChains[i]->setDevice_l(mOutDevice);
+                mEffectChains[i]->setDevice_l(device);
             }
         }
+        if (audio_is_output_devices(device)) {
+            mOutDevice = device;
+            if (!isOutput()) {
+                sendToHal = false;
+            }
+        } else {
+            mInDevice = device;
+            if (device != AUDIO_DEVICE_NONE) {
+                mPrevInDevice = value;
+            }
+            // TODO: implement and call checkBtNrec_l();
+        }
     }
-    status = mHalStream->setParameters(keyValuePair);
+    if (sendToHal) {
+        status = mHalStream->setParameters(keyValuePair);
+    } else {
+        status = NO_ERROR;
+    }
 
     return false;
 }
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 80b368e..062bad6 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -229,8 +229,7 @@
         virtual     void        binderDied(const wp<IBinder>& who);
 
     private:
-                    PMDeathRecipient(const PMDeathRecipient&);
-                    PMDeathRecipient& operator = (const PMDeathRecipient&);
+        DISALLOW_COPY_AND_ASSIGN(PMDeathRecipient);
 
         wp<ThreadBase> mThread;
     };
@@ -362,11 +361,6 @@
                 virtual uint32_t getStrategyForSession_l(audio_session_t sessionId __unused)
                         { return 0; }
 
-                // suspend or restore effect according to the type of effect passed. a NULL
-                // type pointer means suspend all effects in the session
-                void setEffectSuspended(const effect_uuid_t *type,
-                                        bool suspend,
-                                        audio_session_t sessionId = AUDIO_SESSION_OUTPUT_MIX);
                 // check if some effects must be suspended/restored when an effect is enabled
                 // or disabled
                 void checkSuspendOnEffectEnabled(const sp<EffectModule>& effect,
@@ -418,10 +412,13 @@
                 void        releaseWakeLock_l();
                 void        updateWakeLockUids_l(const SortedVector<uid_t> &uids);
                 void        getPowerManager_l();
+                // suspend or restore effects of the specified type (or all if type is NULL)
+                // on a given session. The number of suspend requests is counted and restore
+                // occurs when all suspend requests are cancelled.
                 void setEffectSuspended_l(const effect_uuid_t *type,
                                           bool suspend,
                                           audio_session_t sessionId);
-                // updated mSuspendedSessions when an effect suspended or restored
+                // updated mSuspendedSessions when an effect is suspended or restored
                 void        updateSuspendedSessions_l(const effect_uuid_t *type,
                                                       bool suspend,
                                                       audio_session_t sessionId);
@@ -485,6 +482,7 @@
                 const sp<PMDeathRecipient> mDeathRecipient;
                 // list of suspended effects per session and per type. The first (outer) vector is
                 // keyed by session ID, the second (inner) by type UUID timeLow field
+                // Updated by updateSuspendedSessions_l() only.
                 KeyedVector< audio_session_t, KeyedVector< int, sp<SuspendedSessionDesc> > >
                                         mSuspendedSessions;
                 static const size_t     kLogSize = 4 * 1024;
@@ -901,7 +899,7 @@
 
     friend class AudioFlinger;      // for numerous
 
-    PlaybackThread& operator = (const PlaybackThread&);
+    DISALLOW_COPY_AND_ASSIGN(PlaybackThread);
 
     status_t    addTrack_l(const sp<Track>& track);
     bool        destroyTrack_l(const sp<Track>& track);
@@ -982,7 +980,7 @@
     sp<NBAIO_Source>        mTeeSource;
 #endif
     uint32_t                mScreenState;   // cached copy of gScreenState
-    static const size_t     kFastMixerLogSize = 4 * 1024;
+    static const size_t     kFastMixerLogSize = 8 * 1024;
     sp<NBLog::Writer>       mFastMixerNBLogWriter;
 
 
@@ -1388,6 +1386,8 @@
                         }
     virtual bool        isOutput() const override { return false; }
 
+            void        checkBtNrec();
+
 private:
             // Enter standby if not already in standby, and set mStandby flag
             void    standbyIfNotAlreadyInStandby();
@@ -1395,6 +1395,8 @@
             // Call the HAL standby method unconditionally, and don't change mStandby flag
             void    inputStandBy();
 
+            void    checkBtNrec_l();
+
             AudioStreamIn                       *mInput;
             SortedVector < sp<RecordTrack> >    mTracks;
             // mActiveTracks has dual roles:  it indicates the current active track(s), and
@@ -1454,6 +1456,8 @@
             sp<NBLog::Writer>                   mFastCaptureNBLogWriter;
 
             bool                                mFastTrackAvail;    // true if fast track available
+            // common state to all record threads
+            std::atomic_bool                    mBtNrecSuspended;
 };
 
 class MmapThread : public ThreadBase
@@ -1479,7 +1483,7 @@
     status_t createMmapBuffer(int32_t minSizeFrames,
                                       struct audio_mmap_buffer_info *info);
     status_t getMmapPosition(struct audio_mmap_position *position);
-    status_t start(const MmapStreamInterface::Client& client, audio_port_handle_t *handle);
+    status_t start(const AudioClient& client, audio_port_handle_t *handle);
     status_t stop(audio_port_handle_t handle);
     status_t standby();
 
diff --git a/services/audioflinger/TrackBase.h b/services/audioflinger/TrackBase.h
index e0c09f7..cb540ca 100644
--- a/services/audioflinger/TrackBase.h
+++ b/services/audioflinger/TrackBase.h
@@ -92,8 +92,7 @@
 
 
 protected:
-                        TrackBase(const TrackBase&);
-                        TrackBase& operator = (const TrackBase&);
+    DISALLOW_COPY_AND_ASSIGN(TrackBase);
 
     // AudioBufferProvider interface
     virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer) = 0;
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 301510c..9763bf2 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -234,7 +234,7 @@
 AudioFlinger::ThreadBase::TrackBase::~TrackBase()
 {
 #ifdef TEE_SINK
-    dumpTee(-1, mTeeSource, mId);
+    dumpTee(-1, mTeeSource, mId, 'T');
 #endif
     // delete the proxy before deleting the shared memory it refers to, to avoid dangling reference
     mServerProxy.clear();
diff --git a/services/audioflinger/TypedLogger.cpp b/services/audioflinger/TypedLogger.cpp
index e08f6f6..57c206b 100644
--- a/services/audioflinger/TypedLogger.cpp
+++ b/services/audioflinger/TypedLogger.cpp
@@ -23,5 +23,5 @@
 #include "TypedLogger.h"
 
 namespace android {
-thread_local NBLog::Writer *logWriterTLS;
+thread_local NBLog::Writer *tlNBLogWriter;
 }
diff --git a/services/audioflinger/TypedLogger.h b/services/audioflinger/TypedLogger.h
index 0b23c7c..2d84028 100644
--- a/services/audioflinger/TypedLogger.h
+++ b/services/audioflinger/TypedLogger.h
@@ -19,11 +19,84 @@
 #define ANDROID_TYPED_LOGGER_H
 
 #include <media/nbaio/NBLog.h>
-#define LOGT(fmt, ...) logWriterTLS->logFormat(fmt, ##__VA_ARGS__) // TODO: check null pointer
+#include <algorithm>
+
+/*
+Fowler-Noll-Vo (FNV-1a) hash function for the file name.
+Hashes at compile time. FNV-1a iterative function:
+
+hash = offset_basis
+for each byte to be hashed
+        hash = hash xor byte
+        hash = hash * FNV_prime
+return hash
+
+offset_basis and FNV_prime values depend on the size of the hash output
+Following values are defined by FNV and should not be changed arbitrarily
+*/
+
+template<typename T>
+constexpr T offset_basis();
+
+template<typename T>
+constexpr T FNV_prime();
+
+template<>
+constexpr uint32_t offset_basis<uint32_t>() {
+    return 2166136261u;
+}
+
+template<>
+constexpr uint32_t FNV_prime<uint32_t>() {
+    return 16777619u;
+}
+
+template<>
+constexpr uint64_t offset_basis<uint64_t>() {
+    return 14695981039346656037ull;
+}
+
+template<>
+constexpr uint64_t FNV_prime<uint64_t>() {
+    return 1099511628211ull;
+}
+
+template <typename T, size_t n>
+constexpr T fnv1a(const char (&file)[n], int i = n - 1) {
+    return i == -1 ? offset_basis<T>() : (fnv1a<T>(file, i - 1) ^ file[i]) * FNV_prime<T>();
+}
+
+template <size_t n>
+constexpr uint64_t hash(const char (&file)[n], uint32_t line) {
+    // Line numbers over or equal to 2^16 are clamped to 2^16 - 1. This way increases collisions
+    // compared to wrapping around, but is easy to identify because it doesn't produce aliasing.
+    // It's a very unlikely case anyways.
+    return ((fnv1a<uint64_t>(file) << 16) ^ ((fnv1a<uint64_t>(file) >> 32) & 0xFFFF0000)) |
+           std::min(line, 0xFFFFu);
+}
+
+// TODO Permit disabling of logging at compile-time.
+
+// TODO A non-nullptr dummy implementation that is a nop would be faster than checking for nullptr
+//      in the case when logging is enabled at compile-time and enabled at runtime, but it might be
+//      slower than nullptr check when logging is enabled at compile-time and disabled at runtime.
+
+// Write formatted entry to log
+#define LOGT(fmt, ...) do { NBLog::Writer *x = tlNBLogWriter; if (x != nullptr) \
+                                x->logFormat((fmt), hash(__FILE__, __LINE__), ##__VA_ARGS__); } \
+                                while (0)
+
+// Write histogram timestamp entry
+#define LOG_HIST_TS() do { NBLog::Writer *x = tlNBLogWriter; if (x != nullptr) \
+                                x->logHistTS(hash(__FILE__, __LINE__)); } while(0)
+
+// flush all histogram
+#define LOG_HIST_FLUSH() do { NBLog::Writer *x = tlNBLogWriter; if (x != nullptr) \
+                                x->logHistFlush(hash(__FILE__, __LINE__)); } while(0)
 
 namespace android {
 extern "C" {
-extern thread_local NBLog::Writer *logWriterTLS;
+extern thread_local NBLog::Writer *tlNBLogWriter;
 }
 } // namespace android
 
diff --git a/services/audiopolicy/Android.mk b/services/audiopolicy/Android.mk
index 7cd2b81..ad340e5 100644
--- a/services/audiopolicy/Android.mk
+++ b/services/audiopolicy/Android.mk
@@ -9,11 +9,11 @@
     service/AudioPolicyClientImpl.cpp
 
 LOCAL_C_INCLUDES := \
-    $(TOPDIR)frameworks/av/services/audioflinger \
+    frameworks/av/services/audioflinger \
     $(call include-path-for, audio-utils) \
-    $(TOPDIR)frameworks/av/services/audiopolicy/common/include \
-    $(TOPDIR)frameworks/av/services/audiopolicy/engine/interface \
-    $(TOPDIR)frameworks/av/services/audiopolicy/utilities
+    frameworks/av/services/audiopolicy/common/include \
+    frameworks/av/services/audiopolicy/engine/interface \
+    frameworks/av/services/audiopolicy/utilities
 
 LOCAL_SHARED_LIBRARIES := \
     libcutils \
@@ -58,7 +58,7 @@
     parameter-framework.policy \
     audio_policy_criteria.conf \
 
-LOCAL_C_INCLUDES += $(TOPDIR)frameworks/av/services/audiopolicy/engineconfigurable/include
+LOCAL_C_INCLUDES += frameworks/av/services/audiopolicy/engineconfigurable/include
 
 LOCAL_SHARED_LIBRARIES += libaudiopolicyengineconfigurable
 
@@ -69,9 +69,9 @@
 endif # ifeq ($(USE_CONFIGURABLE_AUDIO_POLICY), 1)
 
 LOCAL_C_INCLUDES += \
-    $(TOPDIR)frameworks/av/services/audiopolicy/common/include \
-    $(TOPDIR)frameworks/av/services/audiopolicy/engine/interface \
-    $(TOPDIR)frameworks/av/services/audiopolicy/utilities
+    frameworks/av/services/audiopolicy/common/include \
+    frameworks/av/services/audiopolicy/engine/interface \
+    frameworks/av/services/audiopolicy/utilities
 
 LOCAL_STATIC_LIBRARIES := \
     libaudiopolicycomponents
@@ -106,8 +106,8 @@
     libaudiopolicycomponents
 
 LOCAL_C_INCLUDES += \
-    $(TOPDIR)frameworks/av/services/audiopolicy/common/include \
-    $(TOPDIR)frameworks/av/services/audiopolicy/engine/interface
+    frameworks/av/services/audiopolicy/common/include \
+    frameworks/av/services/audiopolicy/engine/interface
 
 LOCAL_CFLAGS := -Wall -Werror
 
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index 60ed1d6..c868206 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -122,7 +122,7 @@
                                         uid_t uid,
                                         const audio_config_t *config,
                                         audio_output_flags_t flags,
-                                        int selectedDeviceId,
+                                        audio_port_handle_t *selectedDeviceId,
                                         audio_port_handle_t *portId) = 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,
@@ -144,7 +144,7 @@
                                      uid_t uid,
                                      const audio_config_base_t *config,
                                      audio_input_flags_t flags,
-                                     audio_port_handle_t selectedDeviceId,
+                                     audio_port_handle_t *selectedDeviceId,
                                      input_type_t *inputType,
                                      audio_port_handle_t *portId) = 0;
     // indicates to the audio policy manager that the input starts being used.
@@ -241,6 +241,9 @@
 
     virtual status_t setMasterMono(bool mono) = 0;
     virtual status_t getMasterMono(bool *mono) = 0;
+
+    virtual float    getStreamVolumeDB(
+                audio_stream_type_t stream, int index, audio_devices_t device) = 0;
 };
 
 
diff --git a/services/audiopolicy/common/managerdefinitions/Android.mk b/services/audiopolicy/common/managerdefinitions/Android.mk
index 7968103..e263c0c 100644
--- a/services/audiopolicy/common/managerdefinitions/Android.mk
+++ b/services/audiopolicy/common/managerdefinitions/Android.mk
@@ -33,9 +33,9 @@
 
 LOCAL_C_INCLUDES := \
     $(LOCAL_PATH)/include \
-    $(TOPDIR)frameworks/av/services/audiopolicy/common/include \
-    $(TOPDIR)frameworks/av/services/audiopolicy \
-    $(TOPDIR)frameworks/av/services/audiopolicy/utilities \
+    frameworks/av/services/audiopolicy/common/include \
+    frameworks/av/services/audiopolicy \
+    frameworks/av/services/audiopolicy/utilities \
 
 ifeq ($(USE_XML_AUDIO_POLICY_CONF), 1)
 
@@ -44,8 +44,8 @@
 LOCAL_SHARED_LIBRARIES += libicuuc libxml2
 
 LOCAL_C_INCLUDES += \
-    $(TOPDIR)external/libxml2/include \
-    $(TOPDIR)external/icu/icu4c/source/common
+    external/libxml2/include \
+    external/icu/icu4c/source/common
 
 else
 
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPort.h b/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
index ded2285..4f79ed2 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
@@ -71,7 +71,7 @@
 
     virtual void toAudioPort(struct audio_port *port) const;
 
-    virtual void importAudioPort(const sp<AudioPort>& port);
+    virtual void importAudioPort(const sp<AudioPort>& port, bool force = false);
 
     void addAudioProfile(const sp<AudioProfile> &profile) { mProfiles.add(profile); }
 
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioSession.h b/services/audiopolicy/common/managerdefinitions/include/AudioSession.h
index 18fba25..ca070cf 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioSession.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioSession.h
@@ -51,6 +51,7 @@
     audio_channel_mask_t channelMask() const { return mConfig.channel_mask; }
     audio_input_flags_t flags() const { return mFlags; }
     uid_t uid() const { return mUid; }
+    void setUid(uid_t uid) { mUid = uid; }
     bool matches(const sp<AudioSession> &other) const;
     bool isSoundTrigger() const { return mIsSoundTrigger; }
     uint32_t openCount() const { return mOpenCount; } ;
@@ -68,7 +69,7 @@
     const audio_source_t mInputSource;
     const struct audio_config_base mConfig;
     const audio_input_flags_t mFlags;
-    const uid_t mUid;
+    uid_t mUid;
     bool  mIsSoundTrigger;
     uint32_t  mOpenCount;
     uint32_t  mActiveCount;
diff --git a/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
index 9a52d22..1a644d7 100644
--- a/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
@@ -48,7 +48,7 @@
     // AudioPort
     virtual void attach(const sp<HwModule>& module);
     virtual void toAudioPort(struct audio_port *port) const;
-    virtual void importAudioPort(const sp<AudioPort>& port);
+    virtual void importAudioPort(const sp<AudioPort>& port, bool force = false);
 
     audio_port_handle_t getId() const;
     status_t dump(int fd, int spaces, int index, bool verbose = true) const;
diff --git a/services/audiopolicy/common/managerdefinitions/include/TypeConverter.h b/services/audiopolicy/common/managerdefinitions/include/TypeConverter.h
index 9e705aa..fc95eb9 100644
--- a/services/audiopolicy/common/managerdefinitions/include/TypeConverter.h
+++ b/services/audiopolicy/common/managerdefinitions/include/TypeConverter.h
@@ -49,4 +49,13 @@
 typedef TypeConverter<RouteFlagTraits> RouteFlagTypeConverter;
 typedef TypeConverter<RuleTraits> RuleTypeConverter;
 
+template <>
+const DeviceCategoryConverter::Table DeviceCategoryConverter::mTable[];
+template <>
+const MixTypeConverter::Table MixTypeConverter::mTable[];
+template <>
+const RouteFlagTypeConverter::Table RouteFlagTypeConverter::mTable[];
+template <>
+const RuleTypeConverter::Table RuleTypeConverter::mTable[];
+
 }; // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp
index 4be4ac7..cdaffe7 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp
@@ -128,7 +128,7 @@
     port->num_gains = i;
 }
 
-void AudioPort::importAudioPort(const sp<AudioPort>& port)
+void AudioPort::importAudioPort(const sp<AudioPort>& port, bool force __unused)
 {
     size_t indexToImport;
     for (indexToImport = 0; indexToImport < port->mProfiles.size(); indexToImport++) {
diff --git a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
index f0e48b6..a2c1165 100644
--- a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
@@ -263,7 +263,10 @@
     strncpy(port->ext.device.address, mAddress.string(), AUDIO_DEVICE_MAX_ADDRESS_LEN);
 }
 
-void DeviceDescriptor::importAudioPort(const sp<AudioPort>& port) {
+void DeviceDescriptor::importAudioPort(const sp<AudioPort>& port, bool force) {
+    if (!force && !port->hasDynamicAudioProfile()) {
+        return;
+    }
     AudioPort::importAudioPort(port);
     port->pickAudioProfile(mSamplingRate, mChannelMask, mFormat);
 }
diff --git a/services/audiopolicy/config/audio_policy_configuration_stub.xml b/services/audiopolicy/config/audio_policy_configuration_stub.xml
index a7747f8..26c381f 100644
--- a/services/audiopolicy/config/audio_policy_configuration_stub.xml
+++ b/services/audiopolicy/config/audio_policy_configuration_stub.xml
@@ -15,38 +15,9 @@
 -->
 
 <audioPolicyConfiguration version="1.0" xmlns:xi="http://www.w3.org/2001/XInclude">
-  <modules>
-        <module name="stub" halVersion="2.0">
-            <attachedDevices>
-                <item>Default Out</item>
-                <item>Default In</item>
-            </attachedDevices>
-            <defaultOutputDevice>Default Out</defaultOutputDevice>
-            <mixPorts>
-                <mixPort name="stub output" role="source" flags="AUDIO_OUTPUT_FLAG_PRIMARY">
-                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
-                             samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
-                </mixPort>
-
-                <mixPort name="stub input" role="sink">
-                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
-                             samplingRates="48000" channelMasks="AUDIO_CHANNEL_IN_STEREO"/>
-                </mixPort>
-            </mixPorts>
-            <devicePorts>
-                <devicePort tagName="Default Out" type="AUDIO_DEVICE_OUT_STUB" role="sink">
-                </devicePort>
-
-                <devicePort tagName="Default In" type="AUDIO_DEVICE_IN_STUB" role="source">
-                </devicePort>
-            </devicePorts>
-            <routes>
-                <route type="mix" sink="Default Out" sources="stub output"/>
-
-                <route type="mix" sink="stub input" sources="Default In"/>
-            </routes>
-
-        </module>
+    <modules>
+        <!-- Stub Audio HAL -->
+        <xi:include href="stub_audio_policy_configuration.xml"/>
 
         <!-- Remote Submix Audio HAL -->
         <xi:include href="r_submix_audio_policy_configuration.xml"/>
diff --git a/services/audiopolicy/config/stub_audio_policy_configuration.xml b/services/audiopolicy/config/stub_audio_policy_configuration.xml
new file mode 100644
index 0000000..17005d2
--- /dev/null
+++ b/services/audiopolicy/config/stub_audio_policy_configuration.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<module name="stub" halVersion="2.0">
+  <attachedDevices>
+    <item>Default Out</item>
+    <item>Default In</item>
+  </attachedDevices>
+  <defaultOutputDevice>Default Out</defaultOutputDevice>
+  <mixPorts>
+    <mixPort name="stub output" role="source" flags="AUDIO_OUTPUT_FLAG_PRIMARY">
+      <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+               samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+    </mixPort>
+
+    <mixPort name="stub input" role="sink">
+      <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+               samplingRates="48000" channelMasks="AUDIO_CHANNEL_IN_STEREO"/>
+    </mixPort>
+  </mixPorts>
+  <devicePorts>
+    <devicePort tagName="Default Out" type="AUDIO_DEVICE_OUT_STUB" role="sink">
+    </devicePort>
+
+    <devicePort tagName="Default In" type="AUDIO_DEVICE_IN_STUB" role="source">
+    </devicePort>
+  </devicePorts>
+  <routes>
+    <route type="mix" sink="Default Out" sources="stub output"/>
+
+    <route type="mix" sink="stub input" sources="Default In"/>
+  </routes>
+</module>
diff --git a/services/audiopolicy/config/usb_audio_policy_configuration.xml b/services/audiopolicy/config/usb_audio_policy_configuration.xml
index 1630a94..a487ecb 100644
--- a/services/audiopolicy/config/usb_audio_policy_configuration.xml
+++ b/services/audiopolicy/config/usb_audio_policy_configuration.xml
@@ -30,14 +30,18 @@
                      samplingRates="44100" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
         </devicePort>
         <devicePort tagName="USB Device Out" type="AUDIO_DEVICE_OUT_USB_DEVICE" role="sink"/>
+        <devicePort tagName="USB Headset Out" type="AUDIO_DEVICE_OUT_USB_HEADSET" role="sink"/>
         <devicePort tagName="USB Device In" type="AUDIO_DEVICE_IN_USB_DEVICE" role="source"/>
+        <devicePort tagName="USB Headset In" type="AUDIO_DEVICE_IN_USB_HEADSET" role="source"/>
     </devicePorts>
     <routes>
         <route type="mix" sink="USB Host Out"
                sources="usb_accessory output"/>
         <route type="mix" sink="USB Device Out"
                sources="usb_device output"/>
+        <route type="mix" sink="USB Headset Out"
+               sources="usb_device output"/>
         <route type="mix" sink="usb_device input"
-               sources="USB Device In"/>
+               sources="USB Device In,USB Headset In"/>
     </routes>
 </module>
diff --git a/services/audiopolicy/engineconfigurable/Android.mk b/services/audiopolicy/engineconfigurable/Android.mk
index 5b43347..c2105e9 100644
--- a/services/audiopolicy/engineconfigurable/Android.mk
+++ b/services/audiopolicy/engineconfigurable/Android.mk
@@ -16,9 +16,9 @@
     src/InputSource.cpp \
 
 audio_policy_engine_includes_common := \
-    $(TOPDIR)frameworks/av/services/audiopolicy/engineconfigurable/include \
-    $(TOPDIR)frameworks/av/services/audiopolicy/engineconfigurable/interface \
-    $(TOPDIR)frameworks/av/services/audiopolicy/engine/interface
+    frameworks/av/services/audiopolicy/engineconfigurable/include \
+    frameworks/av/services/audiopolicy/engineconfigurable/interface \
+    frameworks/av/services/audiopolicy/engine/interface
 
 LOCAL_CFLAGS += \
     -Wall \
@@ -33,7 +33,7 @@
     $(TARGET_OUT_HEADERS)/hw \
     $(call include-path-for, frameworks-av) \
     $(call include-path-for, audio-utils) \
-    $(TOPDIR)frameworks/av/services/audiopolicy/common/include
+    frameworks/av/services/audiopolicy/common/include
 
 LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
 
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Android.mk b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Android.mk
index 0e44f2c..3559cf1 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Android.mk
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Android.mk
@@ -21,9 +21,9 @@
     -fvisibility=hidden
 
 LOCAL_C_INCLUDES := \
-    $(TOPDIR)frameworks/av/services/audiopolicy/common/include \
-    $(TOPDIR)frameworks/av/services/audiopolicy/engineconfigurable/include \
-    $(TOPDIR)frameworks/av/services/audiopolicy/engineconfigurable/interface \
+    frameworks/av/services/audiopolicy/common/include \
+    frameworks/av/services/audiopolicy/engineconfigurable/include \
+    frameworks/av/services/audiopolicy/engineconfigurable/interface \
 
 LOCAL_SHARED_LIBRARIES := \
     libaudiopolicyengineconfigurable  \
diff --git a/services/audiopolicy/engineconfigurable/wrapper/Android.mk b/services/audiopolicy/engineconfigurable/wrapper/Android.mk
index 066ee0d..36e0f42 100644
--- a/services/audiopolicy/engineconfigurable/wrapper/Android.mk
+++ b/services/audiopolicy/engineconfigurable/wrapper/Android.mk
@@ -8,9 +8,9 @@
 
 LOCAL_C_INCLUDES := \
     $(LOCAL_PATH)/include \
-    $(TOPDIR)frameworks/av/services/audiopolicy/engineconfigurable/include \
-    $(TOPDIR)frameworks/av/services/audiopolicy/engineconfigurable/interface \
-    $(TOPDIR)frameworks/av/services/audiopolicy/utilities/convert \
+    frameworks/av/services/audiopolicy/engineconfigurable/include \
+    frameworks/av/services/audiopolicy/engineconfigurable/interface \
+    frameworks/av/services/audiopolicy/utilities/convert \
 
 LOCAL_SRC_FILES:= ParameterManagerWrapper.cpp
 
diff --git a/services/audiopolicy/enginedefault/Android.mk b/services/audiopolicy/enginedefault/Android.mk
index b37b379..cbbe306 100644
--- a/services/audiopolicy/enginedefault/Android.mk
+++ b/services/audiopolicy/enginedefault/Android.mk
@@ -11,7 +11,7 @@
 
 audio_policy_engine_includes_common := \
     $(LOCAL_PATH)/include \
-    $(TOPDIR)frameworks/av/services/audiopolicy/engine/interface
+    frameworks/av/services/audiopolicy/engine/interface
 
 LOCAL_CFLAGS += \
     -Wall \
@@ -27,7 +27,7 @@
     $(call include-path-for, frameworks-av) \
     $(call include-path-for, audio-utils) \
     $(call include-path-for, bionic) \
-    $(TOPDIR)frameworks/av/services/audiopolicy/common/include
+    frameworks/av/services/audiopolicy/common/include
 
 LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
 
diff --git a/services/audiopolicy/enginedefault/src/Engine.cpp b/services/audiopolicy/enginedefault/src/Engine.cpp
index 096ffd1..9bdb98c 100644
--- a/services/audiopolicy/enginedefault/src/Engine.cpp
+++ b/services/audiopolicy/enginedefault/src/Engine.cpp
@@ -277,8 +277,11 @@
                 device &= ~AUDIO_DEVICE_OUT_SPEAKER;
             }
         } else if (outputs.isStreamActive(
-                                AUDIO_STREAM_MUSIC, SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY)) {
-            // while media is playing (or has recently played), use the same device
+                                AUDIO_STREAM_MUSIC, SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY)
+                    || outputs.isStreamActive(
+                            AUDIO_STREAM_ACCESSIBILITY, SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY))
+        {
+            // while media/a11y is playing (or has recently played), use the same device
             device = getDeviceForStrategyInt(
                     STRATEGY_MEDIA, availableOutputDevices, availableInputDevices, outputs);
         } else {
@@ -552,6 +555,15 @@
                 AUDIO_POLICY_FORCE_HDMI_SYSTEM_AUDIO_ENFORCED)) {
             device &= ~AUDIO_DEVICE_OUT_SPEAKER;
         }
+
+        // for STRATEGY_SONIFICATION:
+        // if SPEAKER was selected, and SPEAKER_SAFE is available, use SPEAKER_SAFE instead
+        if ((strategy == STRATEGY_SONIFICATION) &&
+                (device & AUDIO_DEVICE_OUT_SPEAKER) &&
+                (availableOutputDevicesType & AUDIO_DEVICE_OUT_SPEAKER_SAFE)) {
+            device |= AUDIO_DEVICE_OUT_SPEAKER_SAFE;
+            device &= ~AUDIO_DEVICE_OUT_SPEAKER;
+        }
         } break;
 
     default:
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index e8e531a..78f195d 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -54,6 +54,11 @@
 //FIXME: workaround for truncated touch sounds
 // to be removed when the problem is handled by system UI
 #define TOUCH_SOUND_FIXED_DELAY_MS 100
+
+// Largest difference in dB on earpiece in call between the voice volume and another
+// media / notification / system volume.
+constexpr float IN_CALL_EARPIECE_HEADROOM_DB = 3.f;
+
 // ----------------------------------------------------------------------------
 // AudioPolicyInterface implementation
 // ----------------------------------------------------------------------------
@@ -709,7 +714,8 @@
     // only retain flags that will drive the direct output profile selection
     // if explicitly requested
     static const uint32_t kRelevantFlags =
-            (AUDIO_OUTPUT_FLAG_HW_AV_SYNC | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD);
+            (AUDIO_OUTPUT_FLAG_HW_AV_SYNC | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD |
+             AUDIO_OUTPUT_FLAG_VOIP_RX);
     flags =
         (audio_output_flags_t)((flags & kRelevantFlags) | AUDIO_OUTPUT_FLAG_DIRECT);
 
@@ -768,7 +774,7 @@
                                               uid_t uid,
                                               const audio_config_t *config,
                                               audio_output_flags_t flags,
-                                              audio_port_handle_t selectedDeviceId,
+                                              audio_port_handle_t *selectedDeviceId,
                                               audio_port_handle_t *portId)
 {
     audio_attributes_t attributes;
@@ -812,16 +818,18 @@
     ALOGV("getOutputForAttr() usage=%d, content=%d, tag=%s flags=%08x"
             " session %d selectedDeviceId %d",
             attributes.usage, attributes.content_type, attributes.tags, attributes.flags,
-            session, selectedDeviceId);
+            session, *selectedDeviceId);
 
     *stream = streamTypefromAttributesInt(&attributes);
 
     // Explicit routing?
     sp<DeviceDescriptor> deviceDesc;
-    for (size_t i = 0; i < mAvailableOutputDevices.size(); i++) {
-        if (mAvailableOutputDevices[i]->getId() == selectedDeviceId) {
-            deviceDesc = mAvailableOutputDevices[i];
-            break;
+    if (*selectedDeviceId != AUDIO_PORT_HANDLE_NONE) {
+        for (size_t i = 0; i < mAvailableOutputDevices.size(); i++) {
+            if (mAvailableOutputDevices[i]->getId() == *selectedDeviceId) {
+                deviceDesc = mAvailableOutputDevices[i];
+                break;
+            }
         }
     }
     mOutputRoutes.addRoute(session, *stream, SessionRoute::SOURCE_TYPE_NA, deviceDesc, uid);
@@ -844,6 +852,12 @@
         return INVALID_OPERATION;
     }
 
+    DeviceVector outputDevices = mAvailableOutputDevices.getDevicesFromType(device);
+    *selectedDeviceId = outputDevices.size() > 0 ? outputDevices.itemAt(0)->getId()
+            : AUDIO_PORT_HANDLE_NONE;
+
+    ALOGV("  getOutputForAttr() returns output %d selectedDeviceId %d", *output, *selectedDeviceId);
+
     return NO_ERROR;
 }
 
@@ -923,6 +937,11 @@
     }
     if (stream == AUDIO_STREAM_TTS) {
         flags = AUDIO_OUTPUT_FLAG_TTS;
+    } else if (stream == AUDIO_STREAM_VOICE_CALL &&
+               audio_is_linear_pcm(format)) {
+        flags = (audio_output_flags_t)(AUDIO_OUTPUT_FLAG_VOIP_RX |
+                                       AUDIO_OUTPUT_FLAG_DIRECT);
+        ALOGV("Set VoIP and Direct output flags for PCM format");
     }
 
     sp<IOProfile> profile;
@@ -1078,8 +1097,6 @@
     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("  getOutputForDevice() returns output %d", output);
-
     return output;
 }
 
@@ -1474,7 +1491,7 @@
                                              uid_t uid,
                                              const audio_config_base_t *config,
                                              audio_input_flags_t flags,
-                                             audio_port_handle_t selectedDeviceId,
+                                             audio_port_handle_t *selectedDeviceId,
                                              input_type_t *inputType,
                                              audio_port_handle_t *portId)
 {
@@ -1482,6 +1499,43 @@
             "session %d, flags %#x",
           attr->source, config->sample_rate, config->format, config->channel_mask, session, flags);
 
+    // special case for mmap capture: if an input IO handle is specified, we reuse this input if
+    // possible
+    if ((flags & AUDIO_INPUT_FLAG_MMAP_NOIRQ) == AUDIO_INPUT_FLAG_MMAP_NOIRQ &&
+            *input != AUDIO_IO_HANDLE_NONE) {
+        ssize_t index = mInputs.indexOfKey(*input);
+        if (index < 0) {
+            ALOGW("getInputForAttr() unknown MMAP input %d", *input);
+            return BAD_VALUE;
+        }
+        sp<AudioInputDescriptor> inputDesc = mInputs.valueAt(index);
+        sp<AudioSession> audioSession = inputDesc->getAudioSession(session);
+        if (audioSession == 0) {
+            ALOGW("getInputForAttr() unknown session %d on input %d", session, *input);
+            return BAD_VALUE;
+        }
+        // For MMAP mode, the first call to getInputForAttr() is made on behalf of audioflinger.
+        // The second call is for the first active client and sets the UID. Any further call
+        // corresponds to a new client and is only permitted from the same UId.
+        if (audioSession->openCount() == 1) {
+            audioSession->setUid(uid);
+        } else if (audioSession->uid() != uid) {
+            ALOGW("getInputForAttr() bad uid %d for session %d uid %d",
+                  uid, session, audioSession->uid());
+            return INVALID_OPERATION;
+        }
+        audioSession->changeOpenCount(1);
+        *inputType = API_INPUT_LEGACY;
+        if (*portId == AUDIO_PORT_HANDLE_NONE) {
+            *portId = AudioPort::getNextUniqueId();
+        }
+        DeviceVector inputDevices = mAvailableInputDevices.getDevicesFromType(inputDesc->mDevice);
+        *selectedDeviceId = inputDevices.size() > 0 ? inputDevices.itemAt(0)->getId()
+                : AUDIO_PORT_HANDLE_NONE;
+        ALOGI("%s reusing MMAP input %d for session %d", __FUNCTION__, *input, session);
+        return NO_ERROR;
+    }
+
     *input = AUDIO_IO_HANDLE_NONE;
     *inputType = API_INPUT_INVALID;
 
@@ -1504,10 +1558,12 @@
 
     // Explicit routing?
     sp<DeviceDescriptor> deviceDesc;
-    for (size_t i = 0; i < mAvailableInputDevices.size(); i++) {
-        if (mAvailableInputDevices[i]->getId() == selectedDeviceId) {
-            deviceDesc = mAvailableInputDevices[i];
-            break;
+    if (*selectedDeviceId != AUDIO_PORT_HANDLE_NONE) {
+        for (size_t i = 0; i < mAvailableInputDevices.size(); i++) {
+            if (mAvailableInputDevices[i]->getId() == *selectedDeviceId) {
+                deviceDesc = mAvailableInputDevices[i];
+                break;
+            }
         }
     }
     mInputRoutes.addRoute(session, SessionRoute::STREAM_TYPE_NA, inputSource, deviceDesc, uid);
@@ -1558,7 +1614,13 @@
         return INVALID_OPERATION;
     }
 
-    ALOGV("getInputForAttr() returns input type = %d", *inputType);
+    DeviceVector inputDevices = mAvailableInputDevices.getDevicesFromType(device);
+    *selectedDeviceId = inputDevices.size() > 0 ? inputDevices.itemAt(0)->getId()
+            : AUDIO_PORT_HANDLE_NONE;
+
+    ALOGV("getInputForAttr() returns input %d type %d selectedDeviceId %d",
+            *input, *inputType, *selectedDeviceId);
+
     return NO_ERROR;
 }
 
@@ -1588,6 +1650,9 @@
         } else {
             halInputSource = AUDIO_SOURCE_VOICE_RECOGNITION;
         }
+    } else if (inputSource == AUDIO_SOURCE_VOICE_COMMUNICATION &&
+               audio_is_linear_pcm(format)) {
+        flags = (audio_input_flags_t)(flags | AUDIO_INPUT_FLAG_VOIP_TX);
     }
 
     // find a compatible input profile (not necessarily identical in parameters)
@@ -1790,6 +1855,40 @@
     return true;
 }
 
+// FIXME: remove when concurrent capture is ready. This is a hack to work around bug b/63083537.
+bool AudioPolicyManager::soundTriggerSupportsConcurrentCapture() {
+    if (!mHasComputedSoundTriggerSupportsConcurrentCapture) {
+        bool soundTriggerSupportsConcurrentCapture = false;
+        unsigned int numModules = 0;
+        struct sound_trigger_module_descriptor* nModules = NULL;
+
+        status_t status = SoundTrigger::listModules(nModules, &numModules);
+        if (status == NO_ERROR && numModules != 0) {
+            nModules = (struct sound_trigger_module_descriptor*) calloc(
+                    numModules, sizeof(struct sound_trigger_module_descriptor));
+            if (nModules == NULL) {
+              // We failed to malloc the buffer, so just say no for now, and hope that we have more
+              // ram the next time this function is called.
+              ALOGE("Failed to allocate buffer for module descriptors");
+              return false;
+            }
+
+            status = SoundTrigger::listModules(nModules, &numModules);
+            if (status == NO_ERROR) {
+                soundTriggerSupportsConcurrentCapture = true;
+                for (size_t i = 0; i < numModules; ++i) {
+                    soundTriggerSupportsConcurrentCapture &=
+                            nModules[i].properties.concurrent_capture;
+                }
+            }
+            free(nModules);
+        }
+        mSoundTriggerSupportsConcurrentCapture = soundTriggerSupportsConcurrentCapture;
+        mHasComputedSoundTriggerSupportsConcurrentCapture = true;
+    }
+    return mSoundTriggerSupportsConcurrentCapture;
+}
+
 
 status_t AudioPolicyManager::startInput(audio_io_handle_t input,
                                         audio_session_t session,
@@ -1839,6 +1938,11 @@
                 continue;
             }
 
+            if ((audioSession->flags() & AUDIO_INPUT_FLAG_MMAP_NOIRQ) != 0 &&
+                    activeDesc->getId() == inputDesc->getId()) {
+                continue;
+            }
+
             audio_source_t activeSource = activeDesc->inputSource(true);
             if (audioSession->inputSource() == AUDIO_SOURCE_HOTWORD) {
                 if (activeSource == AUDIO_SOURCE_HOTWORD) {
@@ -1862,6 +1966,12 @@
             }
         }
 
+        // We only need to check if the sound trigger session supports concurrent capture if the
+        // input is also a sound trigger input. Otherwise, we should preempt any hotword stream
+        // that's running.
+        const bool allowConcurrentWithSoundTrigger =
+            inputDesc->isSoundTrigger() ? soundTriggerSupportsConcurrentCapture() : false;
+
         // if capture is allowed, preempt currently active HOTWORD captures
         for (size_t i = 0; i < activeInputs.size(); i++) {
             sp<AudioInputDescriptor> activeDesc = activeInputs[i];
@@ -1870,6 +1980,10 @@
                 continue;
             }
 
+            if (allowConcurrentWithSoundTrigger && activeDesc->isSoundTrigger()) {
+                continue;
+            }
+
             audio_source_t activeSource = activeDesc->inputSource(true);
             if (activeSource == AUDIO_SOURCE_HOTWORD) {
                 AudioSessionCollection activeSessions =
@@ -2140,7 +2254,8 @@
                 continue;
             }
             routing_strategy curStrategy = getStrategy((audio_stream_type_t)curStream);
-            audio_devices_t curStreamDevice = getDeviceForStrategy(curStrategy, false /*fromCache*/);
+            audio_devices_t curStreamDevice = Volume::getDeviceForVolume(getDeviceForStrategy(
+                    curStrategy, false /*fromCache*/));
             if ((device != AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME) &&
                     ((curStreamDevice & device) == 0)) {
                 continue;
@@ -2151,7 +2266,7 @@
                 applyVolume = (curDevice & curStreamDevice) != 0;
             } else {
                 applyVolume = !mVolumeCurves->hasVolumeIndexForDevice(
-                        stream, Volume::getDeviceForVolume(curStreamDevice));
+                        stream, curStreamDevice);
             }
 
             if (applyVolume) {
@@ -3365,6 +3480,12 @@
     return NO_ERROR;
 }
 
+float AudioPolicyManager::getStreamVolumeDB(
+        audio_stream_type_t stream, int index, audio_devices_t device)
+{
+    return computeVolume(stream, index, device);
+}
+
 status_t AudioPolicyManager::disconnectAudioSource(const sp<AudioSourceDescriptor>& sourceDesc)
 {
     ALOGV("%s handle %d", __FUNCTION__, sourceDesc->getHandle());
@@ -3459,7 +3580,8 @@
     mBeaconMuted(false),
     mTtsOutputAvailable(false),
     mMasterMono(false),
-    mMusicEffectOutput(AUDIO_IO_HANDLE_NONE)
+    mMusicEffectOutput(AUDIO_IO_HANDLE_NONE),
+    mHasComputedSoundTriggerSupportsConcurrentCapture(false)
 {
     mUidCached = getuid();
     mpClientInterface = clientInterface;
@@ -3647,7 +3769,7 @@
                         sp<DeviceDescriptor> devDesc = mAvailableInputDevices[index];
                         if (!devDesc->isAttached()) {
                             devDesc->attach(mHwModules[i]);
-                            devDesc->importAudioPort(inProfile);
+                            devDesc->importAudioPort(inProfile, true);
                         }
                     }
                 }
@@ -4010,8 +4132,8 @@
                 continue;
             }
 
-            ALOGV("opening output for device %08x with params %s profile %p",
-                                                      device, address.string(), profile.get());
+            ALOGV("opening output for device %08x with params %s profile %p name %s",
+                  device, address.string(), profile.get(), profile->getName().string());
             desc = new SwAudioOutputDescriptor(profile, mpClientInterface);
             desc->mDevice = device;
             audio_config_t config = AUDIO_CONFIG_INITIALIZER;
@@ -4260,6 +4382,10 @@
             config.channel_mask = desc->mChannelMask;
             config.format = desc->mFormat;
             audio_io_handle_t input = AUDIO_IO_HANDLE_NONE;
+
+            ALOGV("opening inputput for device %08x with params %s profile %p name %s",
+                  desc->mDevice, address.string(), profile.get(), profile->getName().string());
+
             status_t status = mpClientInterface->openInput(profile->getModuleHandle(),
                                                            &input,
                                                            &config,
@@ -5227,6 +5353,30 @@
         return ringVolumeDB - 4 > volumeDB ? ringVolumeDB - 4 : volumeDB;
     }
 
+    // in-call: always cap earpiece volume by voice volume + some low headroom
+    if ((stream != AUDIO_STREAM_VOICE_CALL) && (device & AUDIO_DEVICE_OUT_EARPIECE) && isInCall()) {
+        switch (stream) {
+        case AUDIO_STREAM_SYSTEM:
+        case AUDIO_STREAM_RING:
+        case AUDIO_STREAM_MUSIC:
+        case AUDIO_STREAM_ALARM:
+        case AUDIO_STREAM_NOTIFICATION:
+        case AUDIO_STREAM_ENFORCED_AUDIBLE:
+        case AUDIO_STREAM_DTMF:
+        case AUDIO_STREAM_ACCESSIBILITY: {
+            const float maxVoiceVolDb = computeVolume(AUDIO_STREAM_VOICE_CALL, index, device)
+                    + IN_CALL_EARPIECE_HEADROOM_DB;
+            if (volumeDB > maxVoiceVolDb) {
+                ALOGV("computeVolume() stream %d at vol=%f overriden by stream %d at vol=%f",
+                        stream, volumeDB, AUDIO_STREAM_VOICE_CALL, maxVoiceVolDb);
+                volumeDB = maxVoiceVolDb;
+            }
+            } break;
+        default:
+            break;
+        }
+    }
+
     // 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 notifications volume by 6dB
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index c831d46..82c4c35 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -116,7 +116,7 @@
                                           uid_t uid,
                                           const audio_config_t *config,
                                           audio_output_flags_t flags,
-                                          audio_port_handle_t selectedDeviceId,
+                                          audio_port_handle_t *selectedDeviceId,
                                           audio_port_handle_t *portId);
         virtual status_t startOutput(audio_io_handle_t output,
                                      audio_stream_type_t stream,
@@ -133,7 +133,7 @@
                                          uid_t uid,
                                          const audio_config_base_t *config,
                                          audio_input_flags_t flags,
-                                         audio_port_handle_t selectedDeviceId,
+                                         audio_port_handle_t *selectedDeviceId,
                                          input_type_t *inputType,
                                          audio_port_handle_t *portId);
 
@@ -234,6 +234,8 @@
 
         virtual status_t setMasterMono(bool mono);
         virtual status_t getMasterMono(bool *mono);
+        virtual float    getStreamVolumeDB(
+                    audio_stream_type_t stream, int index, audio_devices_t device);
 
         // return the strategy corresponding to a given stream type
         routing_strategy getStrategy(audio_stream_type_t stream) const;
@@ -669,6 +671,10 @@
             param.addInt(String8(AudioParameter::keyMonoOutput), (int)mMasterMono);
             mpClientInterface->setParameters(output, param.toString());
         }
+
+        bool soundTriggerSupportsConcurrentCapture();
+        bool mSoundTriggerSupportsConcurrentCapture;
+        bool mHasComputedSoundTriggerSupportsConcurrentCapture;
 };
 
 };
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index 2f7b1fb..f60030d 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -167,7 +167,7 @@
                                               uid_t uid,
                                               const audio_config_t *config,
                                               audio_output_flags_t flags,
-                                              audio_port_handle_t selectedDeviceId,
+                                              audio_port_handle_t *selectedDeviceId,
                                               audio_port_handle_t *portId)
 {
     if (mAudioPolicyManager == NULL) {
@@ -277,7 +277,7 @@
                                              uid_t uid,
                                              const audio_config_base_t *config,
                                              audio_input_flags_t flags,
-                                             audio_port_handle_t selectedDeviceId,
+                                             audio_port_handle_t *selectedDeviceId,
                                              audio_port_handle_t *portId)
 {
     if (mAudioPolicyManager == NULL) {
@@ -771,4 +771,16 @@
     return mAudioPolicyManager->getMasterMono(mono);
 }
 
+
+float AudioPolicyService::getStreamVolumeDB(
+            audio_stream_type_t stream, int index, audio_devices_t device)
+{
+    if (mAudioPolicyManager == NULL) {
+        return NAN;
+    }
+    Mutex::Autolock _l(mLock);
+    return mAudioPolicyManager->getStreamVolumeDB(stream, index, device);
+}
+
+
 }; // namespace android
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index 9a083f4..35542f1 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -82,7 +82,7 @@
                                       uid_t uid,
                                       const audio_config_t *config,
                                       audio_output_flags_t flags,
-                                      audio_port_handle_t selectedDeviceId,
+                                      audio_port_handle_t *selectedDeviceId,
                                       audio_port_handle_t *portId);
     virtual status_t startOutput(audio_io_handle_t output,
                                  audio_stream_type_t stream,
@@ -100,7 +100,7 @@
                                      uid_t uid,
                                      const audio_config_base_t *config,
                                      audio_input_flags_t flags,
-                                     audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE,
+                                     audio_port_handle_t *selectedDeviceId = NULL,
                                      audio_port_handle_t *portId = NULL);
     virtual status_t startInput(audio_io_handle_t input,
                                 audio_session_t session);
@@ -202,6 +202,9 @@
     virtual status_t setMasterMono(bool mono);
     virtual status_t getMasterMono(bool *mono);
 
+    virtual float    getStreamVolumeDB(
+                audio_stream_type_t stream, int index, audio_devices_t device);
+
             status_t doStopOutput(audio_io_handle_t output,
                                   audio_stream_type_t stream,
                                   audio_session_t session);
diff --git a/services/camera/libcameraservice/Android.mk b/services/camera/libcameraservice/Android.mk
index 502ac5d..f1cdea3 100644
--- a/services/camera/libcameraservice/Android.mk
+++ b/services/camera/libcameraservice/Android.mk
@@ -77,8 +77,7 @@
     android.hardware.camera.common@1.0 \
     android.hardware.camera.provider@2.4 \
     android.hardware.camera.device@1.0 \
-    android.hardware.camera.device@3.2 \
-    android.hidl.manager@1.0
+    android.hardware.camera.device@3.2
 
 LOCAL_EXPORT_SHARED_LIBRARY_HEADERS := libbinder libcamera_client libfmq
 
@@ -91,6 +90,9 @@
 
 LOCAL_CFLAGS += -Wall -Wextra -Werror
 
+# Workaround for invalid unused-lambda-capture warning http://b/38349491
+LOCAL_CLANG_CFLAGS += -Wno-error=unused-lambda-capture
+
 LOCAL_MODULE:= libcameraservice
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index c2b71a2..20bd5e4 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -73,6 +73,7 @@
 using binder::Status;
 using hardware::ICamera;
 using hardware::ICameraClient;
+using hardware::ICameraServiceProxy;
 using hardware::ICameraServiceListener;
 using hardware::camera::common::V1_0::CameraDeviceStatus;
 using hardware::camera::common::V1_0::TorchModeStatus;
@@ -231,29 +232,33 @@
 
     for (auto& cameraId : mCameraProviderManager->getCameraDeviceIds()) {
         String8 id8 = String8(cameraId.c_str());
+        bool cameraFound = false;
         {
+
             Mutex::Autolock lock(mCameraStatesLock);
             auto iter = mCameraStates.find(id8);
             if (iter != mCameraStates.end()) {
-                continue;
+                cameraFound = true;
             }
         }
 
-        hardware::camera::common::V1_0::CameraResourceCost cost;
-        res = mCameraProviderManager->getResourceCost(cameraId, &cost);
-        if (res != OK) {
-            ALOGE("Failed to query device resource cost: %s (%d)", strerror(-res), res);
-            continue;
-        }
-        std::set<String8> conflicting;
-        for (size_t i = 0; i < cost.conflictingDevices.size(); i++) {
-            conflicting.emplace(String8(cost.conflictingDevices[i].c_str()));
-        }
+        if (!cameraFound) {
+            hardware::camera::common::V1_0::CameraResourceCost cost;
+            res = mCameraProviderManager->getResourceCost(cameraId, &cost);
+            if (res != OK) {
+                ALOGE("Failed to query device resource cost: %s (%d)", strerror(-res), res);
+                continue;
+            }
+            std::set<String8> conflicting;
+            for (size_t i = 0; i < cost.conflictingDevices.size(); i++) {
+                conflicting.emplace(String8(cost.conflictingDevices[i].c_str()));
+            }
 
-        {
-            Mutex::Autolock lock(mCameraStatesLock);
-            mCameraStates.emplace(id8,
-                std::make_shared<CameraState>(id8, cost.resourceCost, conflicting));
+            {
+                Mutex::Autolock lock(mCameraStatesLock);
+                mCameraStates.emplace(id8,
+                    std::make_shared<CameraState>(id8, cost.resourceCost, conflicting));
+            }
         }
 
         onDeviceStatusChanged(id8, CameraDeviceStatus::PRESENT);
@@ -2209,7 +2214,7 @@
 
     // Transition device state to OPEN
     sCameraService->updateProxyDeviceState(ICameraServiceProxy::CAMERA_STATE_OPEN,
-            mCameraIdStr);
+            mCameraIdStr, mCameraFacing, mClientPackageName);
 
     return OK;
 }
@@ -2233,7 +2238,7 @@
 
         // Transition device state to CLOSED
         sCameraService->updateProxyDeviceState(ICameraServiceProxy::CAMERA_STATE_CLOSED,
-                mCameraIdStr);
+                mCameraIdStr, mCameraFacing, mClientPackageName);
     }
     // Always stop watching, even if no camera op is active
     if (mOpsCallback != NULL) {
@@ -2737,12 +2742,12 @@
     onStatusUpdatedLocked(cameraId, status);
 }
 
-void CameraService::updateProxyDeviceState(ICameraServiceProxy::CameraState newState,
-        const String8& cameraId) {
+void CameraService::updateProxyDeviceState(int newState,
+        const String8& cameraId, int facing, const String16& clientName) {
     sp<ICameraServiceProxy> proxyBinder = getCameraServiceProxy();
     if (proxyBinder == nullptr) return;
     String16 id(cameraId);
-    proxyBinder->notifyCameraState(id, newState);
+    proxyBinder->notifyCameraState(id, newState, facing, clientName);
 }
 
 status_t CameraService::getTorchStatusLocked(
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 87603a3..6d5dde8 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -19,6 +19,7 @@
 
 #include <android/hardware/BnCameraService.h>
 #include <android/hardware/ICameraServiceListener.h>
+#include <android/hardware/ICameraServiceProxy.h>
 
 #include <cutils/multiuser.h>
 #include <utils/Vector.h>
@@ -26,7 +27,6 @@
 #include <binder/AppOpsManager.h>
 #include <binder/BinderService.h>
 #include <binder/IAppOpsCallback.h>
-#include <camera/ICameraServiceProxy.h>
 #include <hardware/camera.h>
 
 #include <android/hardware/camera/common/1.0/types.h>
@@ -182,8 +182,10 @@
      * the camera proxy service in the system service
      */
     static void         updateProxyDeviceState(
-            ICameraServiceProxy::CameraState newState,
-            const String8& cameraId);
+            int newState,
+            const String8& cameraId,
+            int facing,
+            const String16& clientName);
 
     /////////////////////////////////////////////////////////////////////
     // CameraDeviceFactory functionality
@@ -772,7 +774,7 @@
     static StatusInternal mapToInternal(hardware::camera::common::V1_0::CameraDeviceStatus status);
     static int32_t mapToInterface(StatusInternal status);
 
-    static sp<ICameraServiceProxy> getCameraServiceProxy();
+    static sp<hardware::ICameraServiceProxy> getCameraServiceProxy();
     static void pingCameraServiceProxy();
 
 };
diff --git a/services/camera/libcameraservice/api1/CameraClient.cpp b/services/camera/libcameraservice/api1/CameraClient.cpp
index 075c2e3..a407d0b 100644
--- a/services/camera/libcameraservice/api1/CameraClient.cpp
+++ b/services/camera/libcameraservice/api1/CameraClient.cpp
@@ -256,8 +256,8 @@
     disableMsgType(CAMERA_MSG_ALL_MSGS);
     mHardware->stopPreview();
     sCameraService->updateProxyDeviceState(
-        ICameraServiceProxy::CAMERA_STATE_IDLE,
-        String8::format("%d", mCameraId));
+            hardware::ICameraServiceProxy::CAMERA_STATE_IDLE,
+            mCameraIdStr, mCameraFacing, mClientPackageName);
     mHardware->cancelPicture();
     // Release the hardware resources.
     mHardware->release();
@@ -418,8 +418,8 @@
     result = mHardware->startPreview();
     if (result == NO_ERROR) {
         sCameraService->updateProxyDeviceState(
-            ICameraServiceProxy::CAMERA_STATE_ACTIVE,
-            String8::format("%d", mCameraId));
+            hardware::ICameraServiceProxy::CAMERA_STATE_ACTIVE,
+            mCameraIdStr, mCameraFacing, mClientPackageName);
     }
     return result;
 }
@@ -461,8 +461,8 @@
     disableMsgType(CAMERA_MSG_PREVIEW_FRAME);
     mHardware->stopPreview();
     sCameraService->updateProxyDeviceState(
-        ICameraServiceProxy::CAMERA_STATE_IDLE,
-        String8::format("%d", mCameraId));
+        hardware::ICameraServiceProxy::CAMERA_STATE_IDLE,
+        mCameraIdStr, mCameraFacing, mClientPackageName);
     mPreviewBuffer.clear();
 }
 
@@ -960,8 +960,8 @@
     // Shutters only happen in response to takePicture, so mark device as
     // idle now, until preview is restarted
     sCameraService->updateProxyDeviceState(
-        ICameraServiceProxy::CAMERA_STATE_IDLE,
-        String8::format("%d", mCameraId));
+        hardware::ICameraServiceProxy::CAMERA_STATE_IDLE,
+        mCameraIdStr, mCameraFacing, mClientPackageName);
 
     mLock.unlock();
 }
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.h b/services/camera/libcameraservice/api2/CameraDeviceClient.h
index 2bf73a0..e8fc080 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.h
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.h
@@ -85,7 +85,7 @@
 
     virtual binder::Status endConfigure(int operatingMode) override;
 
-    // Returns -EBUSY if device is not idle
+    // Returns -EBUSY if device is not idle or in error state
     virtual binder::Status deleteStream(int streamId) override;
 
     virtual binder::Status createStream(
diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.cpp b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
index 32ee273..51ef160 100644
--- a/services/camera/libcameraservice/common/Camera2ClientBase.cpp
+++ b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
@@ -248,7 +248,8 @@
 void Camera2ClientBase<TClientBase>::notifyIdle() {
     if (mDeviceActive) {
         getCameraService()->updateProxyDeviceState(
-            ICameraServiceProxy::CAMERA_STATE_IDLE, TClientBase::mCameraIdStr);
+            hardware::ICameraServiceProxy::CAMERA_STATE_IDLE, TClientBase::mCameraIdStr,
+            TClientBase::mCameraFacing, TClientBase::mClientPackageName);
     }
     mDeviceActive = false;
 
@@ -263,7 +264,8 @@
 
     if (!mDeviceActive) {
         getCameraService()->updateProxyDeviceState(
-            ICameraServiceProxy::CAMERA_STATE_ACTIVE, TClientBase::mCameraIdStr);
+            hardware::ICameraServiceProxy::CAMERA_STATE_ACTIVE, TClientBase::mCameraIdStr,
+            TClientBase::mCameraFacing, TClientBase::mClientPackageName);
     }
     mDeviceActive = true;
 
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index e8b9b20..69b1d7d 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -138,13 +138,15 @@
                 requestQueueRet.description().c_str());
         return DEAD_OBJECT;
     }
+
+    std::unique_ptr<ResultMetadataQueue>& resQueue = mResultMetadataQueue;
     auto resultQueueRet = session->getCaptureResultMetadataQueue(
-        [&queue = mResultMetadataQueue](const auto& descriptor) {
-            queue = std::make_unique<ResultMetadataQueue>(descriptor);
-            if (!queue->isValid() ||  queue->availableToWrite() <= 0) {
+        [&resQueue](const auto& descriptor) {
+            resQueue = std::make_unique<ResultMetadataQueue>(descriptor);
+            if (!resQueue->isValid() || resQueue->availableToWrite() <= 0) {
                 ALOGE("HAL returns empty result metadata fmq, not use it");
-                queue = nullptr;
-                // Don't use the queue onwards.
+                resQueue = nullptr;
+                // Don't use the resQueue onwards.
             }
         });
     if (!resultQueueRet.isOk()) {
@@ -153,7 +155,7 @@
         return DEAD_OBJECT;
     }
 
-    mInterface = std::make_unique<HalInterface>(session, queue);
+    mInterface = new HalInterface(session, queue);
     std::string providerType;
     mVendorTagId = manager->getProviderTagIdLocked(mId.string());
 
@@ -182,7 +184,7 @@
     mTagMonitor.initialize(mVendorTagId);
 
     /** Start up request queue thread */
-    mRequestThread = new RequestThread(this, mStatusTracker, mInterface.get());
+    mRequestThread = new RequestThread(this, mStatusTracker, mInterface);
     res = mRequestThread->run(String8::format("C3Dev-%s-ReqQueue", mId.string()).string());
     if (res != OK) {
         SET_ERR_L("Unable to start request queue thread: %s (%d)",
@@ -237,7 +239,8 @@
     ALOGI("%s: E", __FUNCTION__);
 
     status_t res = OK;
-
+    std::vector<wp<Camera3StreamInterface>> streams;
+    nsecs_t maxExpectedDuration = getExpectedInFlightDuration();
     {
         Mutex::Autolock l(mLock);
         if (mStatus == STATUS_UNINITIALIZED) return res;
@@ -249,9 +252,10 @@
                 SET_ERR_L("Can't stop streaming");
                 // Continue to close device even in case of error
             } else {
-                res = waitUntilStateThenRelock(/*active*/ false, kShutdownTimeout);
+                res = waitUntilStateThenRelock(/*active*/ false, maxExpectedDuration);
                 if (res != OK) {
-                    SET_ERR_L("Timeout waiting for HAL to drain");
+                    SET_ERR_L("Timeout waiting for HAL to drain (% " PRIi64 " ns)",
+                            maxExpectedDuration);
                     // Continue to close device even in case of error
                 }
             }
@@ -269,8 +273,13 @@
             mRequestThread->requestExit();
         }
 
-        mOutputStreams.clear();
-        mInputStream.clear();
+        streams.reserve(mOutputStreams.size() + (mInputStream != nullptr ? 1 : 0));
+        for (size_t i = 0; i < mOutputStreams.size(); i++) {
+            streams.push_back(mOutputStreams[i]);
+        }
+        if (mInputStream != nullptr) {
+            streams.push_back(mInputStream);
+        }
     }
 
     // Joining done without holding mLock, otherwise deadlocks may ensue
@@ -289,11 +298,8 @@
     HalInterface* interface;
     {
         Mutex::Autolock l(mLock);
-
         mRequestThread.clear();
         mStatusTracker.clear();
-        mBufferManager.clear();
-
         interface = mInterface.get();
     }
 
@@ -301,12 +307,26 @@
     // wait on assorted callbacks,etc, to complete before it can return.
     interface->close();
 
+    flushInflightRequests();
+
     {
         Mutex::Autolock l(mLock);
         mInterface->clear();
+        mOutputStreams.clear();
+        mInputStream.clear();
+        mDeletedStreams.clear();
+        mBufferManager.clear();
         internalUpdateStatusLocked(STATUS_UNINITIALIZED);
     }
 
+    for (auto& weakStream : streams) {
+        sp<Camera3StreamInterface> stream = weakStream.promote();
+        if (stream != nullptr) {
+            ALOGE("%s: Stream %d leaked! strong reference (%d)!",
+                    __FUNCTION__, stream->getId(), stream->getStrongCount() - 1);
+        }
+    }
+
     ALOGI("%s: X", __FUNCTION__);
     return res;
 }
@@ -834,6 +854,15 @@
 hardware::Return<void> Camera3Device::processCaptureResult(
         const hardware::hidl_vec<
                 hardware::camera::device::V3_2::CaptureResult>& results) {
+    // Ideally we should grab mLock, but that can lead to deadlock, and
+    // it's not super important to get up to date value of mStatus for this
+    // warning print, hence skipping the lock here
+    if (mStatus == STATUS_ERROR) {
+        // Per API contract, HAL should act as closed after device error
+        // But mStatus can be set to error by framework as well, so just log
+        // a warning here.
+        ALOGW("%s: received capture result in error state.", __FUNCTION__);
+    }
 
     if (mProcessCaptureResultLock.tryLock() != OK) {
         // This should never happen; it indicates a wrong client implementation
@@ -965,6 +994,16 @@
 
 hardware::Return<void> Camera3Device::notify(
         const hardware::hidl_vec<hardware::camera::device::V3_2::NotifyMsg>& msgs) {
+    // Ideally we should grab mLock, but that can lead to deadlock, and
+    // it's not super important to get up to date value of mStatus for this
+    // warning print, hence skipping the lock here
+    if (mStatus == STATUS_ERROR) {
+        // Per API contract, HAL should act as closed after device error
+        // But mStatus can be set to error by framework as well, so just log
+        // a warning here.
+        ALOGW("%s: received notify message in error state.", __FUNCTION__);
+    }
+
     for (const auto& msg : msgs) {
         notify(msg);
     }
@@ -1102,6 +1141,7 @@
         uint32_t width, uint32_t height, int format, int *id) {
     ATRACE_CALL();
     Mutex::Autolock il(mInterfaceLock);
+    nsecs_t maxExpectedDuration = getExpectedInFlightDuration();
     Mutex::Autolock l(mLock);
     ALOGV("Camera %s: Creating new input stream %d: %d x %d, format %d",
             mId.string(), mNextStreamId, width, height, format);
@@ -1122,7 +1162,7 @@
             break;
         case STATUS_ACTIVE:
             ALOGV("%s: Stopping activity to reconfigure streams", __FUNCTION__);
-            res = internalPauseAndWaitLocked();
+            res = internalPauseAndWaitLocked(maxExpectedDuration);
             if (res != OK) {
                 SET_ERR_L("Can't pause captures to reconfigure streams!");
                 return res;
@@ -1189,6 +1229,7 @@
         int streamSetId, bool isShared, uint32_t consumerUsage) {
     ATRACE_CALL();
     Mutex::Autolock il(mInterfaceLock);
+    nsecs_t maxExpectedDuration = getExpectedInFlightDuration();
     Mutex::Autolock l(mLock);
     ALOGV("Camera %s: Creating new stream %d: %d x %d, format %d, dataspace %d rotation %d"
             " consumer usage 0x%x, isShared %d", mId.string(), mNextStreamId, width, height, format,
@@ -1210,7 +1251,7 @@
             break;
         case STATUS_ACTIVE:
             ALOGV("%s: Stopping activity to reconfigure streams", __FUNCTION__);
-            res = internalPauseAndWaitLocked();
+            res = internalPauseAndWaitLocked(maxExpectedDuration);
             if (res != OK) {
                 SET_ERR_L("Can't pause captures to reconfigure streams!");
                 return res;
@@ -1389,6 +1430,12 @@
         return -EBUSY;
     }
 
+    if (mStatus == STATUS_ERROR) {
+        ALOGW("%s: Camera %s: deleteStream not allowed in ERROR state",
+                __FUNCTION__, mId.string());
+        return -EBUSY;
+    }
+
     sp<Camera3StreamInterface> deletedStream;
     ssize_t outputStreamIdx = mOutputStreams.indexOfKey(id);
     if (mInputStream != NULL && id == mInputStream->getId()) {
@@ -1455,59 +1502,66 @@
     }
 
     Mutex::Autolock il(mInterfaceLock);
-    Mutex::Autolock l(mLock);
 
-    switch (mStatus) {
-        case STATUS_ERROR:
-            CLOGE("Device has encountered a serious error");
-            return INVALID_OPERATION;
-        case STATUS_UNINITIALIZED:
-            CLOGE("Device is not initialized!");
-            return INVALID_OPERATION;
-        case STATUS_UNCONFIGURED:
-        case STATUS_CONFIGURED:
-        case STATUS_ACTIVE:
-            // OK
-            break;
-        default:
-            SET_ERR_L("Unexpected status: %d", mStatus);
-            return INVALID_OPERATION;
-    }
+    {
+        Mutex::Autolock l(mLock);
+        switch (mStatus) {
+            case STATUS_ERROR:
+                CLOGE("Device has encountered a serious error");
+                return INVALID_OPERATION;
+            case STATUS_UNINITIALIZED:
+                CLOGE("Device is not initialized!");
+                return INVALID_OPERATION;
+            case STATUS_UNCONFIGURED:
+            case STATUS_CONFIGURED:
+            case STATUS_ACTIVE:
+                // OK
+                break;
+            default:
+                SET_ERR_L("Unexpected status: %d", mStatus);
+                return INVALID_OPERATION;
+        }
 
-    if (!mRequestTemplateCache[templateId].isEmpty()) {
-        *request = mRequestTemplateCache[templateId];
-        return OK;
+        if (!mRequestTemplateCache[templateId].isEmpty()) {
+            *request = mRequestTemplateCache[templateId];
+            return OK;
+        }
     }
 
     camera_metadata_t *rawRequest;
     status_t res = mInterface->constructDefaultRequestSettings(
             (camera3_request_template_t) templateId, &rawRequest);
-    if (res == BAD_VALUE) {
-        ALOGI("%s: template %d is not supported on this camera device",
-              __FUNCTION__, templateId);
-        return res;
-    } else if (res != OK) {
-        CLOGE("Unable to construct request template %d: %s (%d)",
-                templateId, strerror(-res), res);
-        return res;
+
+    {
+        Mutex::Autolock l(mLock);
+        if (res == BAD_VALUE) {
+            ALOGI("%s: template %d is not supported on this camera device",
+                  __FUNCTION__, templateId);
+            return res;
+        } else if (res != OK) {
+            CLOGE("Unable to construct request template %d: %s (%d)",
+                    templateId, strerror(-res), res);
+            return res;
+        }
+
+        set_camera_metadata_vendor_id(rawRequest, mVendorTagId);
+        mRequestTemplateCache[templateId].acquire(rawRequest);
+
+        *request = mRequestTemplateCache[templateId];
     }
-
-    set_camera_metadata_vendor_id(rawRequest, mVendorTagId);
-    mRequestTemplateCache[templateId].acquire(rawRequest);
-
-    *request = mRequestTemplateCache[templateId];
     return OK;
 }
 
 status_t Camera3Device::waitUntilDrained() {
     ATRACE_CALL();
     Mutex::Autolock il(mInterfaceLock);
+    nsecs_t maxExpectedDuration = getExpectedInFlightDuration();
     Mutex::Autolock l(mLock);
 
-    return waitUntilDrainedLocked();
+    return waitUntilDrainedLocked(maxExpectedDuration);
 }
 
-status_t Camera3Device::waitUntilDrainedLocked() {
+status_t Camera3Device::waitUntilDrainedLocked(nsecs_t maxExpectedDuration) {
     switch (mStatus) {
         case STATUS_UNINITIALIZED:
         case STATUS_UNCONFIGURED:
@@ -1523,9 +1577,9 @@
             SET_ERR_L("Unexpected status: %d",mStatus);
             return INVALID_OPERATION;
     }
-
-    ALOGV("%s: Camera %s: Waiting until idle", __FUNCTION__, mId.string());
-    status_t res = waitUntilStateThenRelock(/*active*/ false, kShutdownTimeout);
+    ALOGV("%s: Camera %s: Waiting until idle (%" PRIi64 "ns)", __FUNCTION__, mId.string(),
+            maxExpectedDuration);
+    status_t res = waitUntilStateThenRelock(/*active*/ false, maxExpectedDuration);
     if (res != OK) {
         SET_ERR_L("Error waiting for HAL to drain: %s (%d)", strerror(-res),
                 res);
@@ -1541,15 +1595,16 @@
 }
 
 // Pause to reconfigure
-status_t Camera3Device::internalPauseAndWaitLocked() {
+status_t Camera3Device::internalPauseAndWaitLocked(nsecs_t maxExpectedDuration) {
     mRequestThread->setPaused(true);
     mPauseStateNotify = true;
 
-    ALOGV("%s: Camera %s: Internal wait until idle", __FUNCTION__, mId.string());
-    status_t res = waitUntilStateThenRelock(/*active*/ false, kShutdownTimeout);
+    ALOGV("%s: Camera %s: Internal wait until idle (% " PRIi64 " ns)", __FUNCTION__, mId.string(),
+          maxExpectedDuration);
+    status_t res = waitUntilStateThenRelock(/*active*/ false, maxExpectedDuration);
     if (res != OK) {
         SET_ERR_L("Can't idle device in %f seconds!",
-                kShutdownTimeout/1e9);
+                maxExpectedDuration/1e9);
     }
 
     return res;
@@ -2295,7 +2350,9 @@
 
     mErrorCause = errorCause;
 
-    mRequestThread->setPaused(true);
+    if (mRequestThread != nullptr) {
+        mRequestThread->setPaused(true);
+    }
     internalUpdateStatusLocked(STATUS_ERROR);
 
     // Notify upstream about a device error
@@ -2316,19 +2373,24 @@
 
 status_t Camera3Device::registerInFlight(uint32_t frameNumber,
         int32_t numBuffers, CaptureResultExtras resultExtras, bool hasInput,
-        bool hasAppCallback) {
+        bool hasAppCallback, nsecs_t maxExpectedDuration) {
     ATRACE_CALL();
     Mutex::Autolock l(mInFlightLock);
 
     ssize_t res;
     res = mInFlightMap.add(frameNumber, InFlightRequest(numBuffers, resultExtras, hasInput,
-            hasAppCallback));
+            hasAppCallback, maxExpectedDuration));
     if (res < 0) return res;
 
     if (mInFlightMap.size() == 1) {
-        mStatusTracker->markComponentActive(mInFlightStatusId);
+        // hold mLock to prevent race with disconnect
+        Mutex::Autolock l(mLock);
+        if (mStatusTracker != nullptr) {
+            mStatusTracker->markComponentActive(mInFlightStatusId);
+        }
     }
 
+    mExpectedInflightDuration += maxExpectedDuration;
     return OK;
 }
 
@@ -2349,12 +2411,18 @@
 }
 
 void Camera3Device::removeInFlightMapEntryLocked(int idx) {
+    nsecs_t duration = mInFlightMap.valueAt(idx).maxExpectedDuration;
     mInFlightMap.removeItemsAt(idx, 1);
 
     // Indicate idle inFlightMap to the status tracker
     if (mInFlightMap.size() == 0) {
-        mStatusTracker->markComponentIdle(mInFlightStatusId, Fence::NO_FENCE);
+        // hold mLock to prevent race with disconnect
+        Mutex::Autolock l(mLock);
+        if (mStatusTracker != nullptr) {
+            mStatusTracker->markComponentIdle(mInFlightStatusId, Fence::NO_FENCE);
+        }
     }
+    mExpectedInflightDuration -= duration;
 }
 
 void Camera3Device::removeInFlightRequestIfReadyLocked(int idx) {
@@ -2365,6 +2433,25 @@
     nsecs_t sensorTimestamp = request.sensorTimestamp;
     nsecs_t shutterTimestamp = request.shutterTimestamp;
 
+    bool skipResultMetadata = false;
+    if (request.requestStatus != OK) {
+        switch (request.requestStatus) {
+            case CAMERA3_MSG_ERROR_DEVICE:
+            case CAMERA3_MSG_ERROR_REQUEST:
+            case CAMERA3_MSG_ERROR_RESULT:
+                skipResultMetadata = true;
+                break;
+            case CAMERA3_MSG_ERROR_BUFFER:
+                //Result metadata should return in this case.
+                skipResultMetadata = false;
+                break;
+            default:
+                SET_ERR("Unknown error message: %d", request.requestStatus);
+                skipResultMetadata = false;
+                break;
+        }
+    }
+
     // Check if it's okay to remove the request from InFlightMap:
     // In the case of a successful request:
     //      all input and output buffers, all result metadata, shutter callback
@@ -2372,7 +2459,7 @@
     // In the case of a unsuccessful request:
     //      all input and output buffers arrived.
     if (request.numBuffersLeft == 0 &&
-            (request.requestStatus != OK ||
+            (skipResultMetadata ||
             (request.haveResultMetadata && shutterTimestamp != 0))) {
         ATRACE_ASYNC_END("frame capture", frameNumber);
 
@@ -2407,6 +2494,98 @@
     }
 }
 
+void Camera3Device::flushInflightRequests() {
+    { // First return buffers cached in mInFlightMap
+        Mutex::Autolock l(mInFlightLock);
+        for (size_t idx = 0; idx < mInFlightMap.size(); idx++) {
+            const InFlightRequest &request = mInFlightMap.valueAt(idx);
+            returnOutputBuffers(request.pendingOutputBuffers.array(),
+                request.pendingOutputBuffers.size(), 0);
+        }
+        mInFlightMap.clear();
+        mExpectedInflightDuration = 0;
+    }
+
+    // Then return all inflight buffers not returned by HAL
+    std::vector<std::pair<int32_t, int32_t>> inflightKeys;
+    mInterface->getInflightBufferKeys(&inflightKeys);
+
+    int32_t inputStreamId = (mInputStream != nullptr) ? mInputStream->getId() : -1;
+    for (auto& pair : inflightKeys) {
+        int32_t frameNumber = pair.first;
+        int32_t streamId = pair.second;
+        buffer_handle_t* buffer;
+        status_t res = mInterface->popInflightBuffer(frameNumber, streamId, &buffer);
+        if (res != OK) {
+            ALOGE("%s: Frame %d: No in-flight buffer for stream %d",
+                    __FUNCTION__, frameNumber, streamId);
+            continue;
+        }
+
+        camera3_stream_buffer_t streamBuffer;
+        streamBuffer.buffer = buffer;
+        streamBuffer.status = CAMERA3_BUFFER_STATUS_ERROR;
+        streamBuffer.acquire_fence = -1;
+        streamBuffer.release_fence = -1;
+
+        // First check if the buffer belongs to deleted stream
+        bool streamDeleted = false;
+        for (auto& stream : mDeletedStreams) {
+            if (streamId == stream->getId()) {
+                streamDeleted = true;
+                // Return buffer to deleted stream
+                camera3_stream* halStream = stream->asHalStream();
+                streamBuffer.stream = halStream;
+                switch (halStream->stream_type) {
+                    case CAMERA3_STREAM_OUTPUT:
+                        res = stream->returnBuffer(streamBuffer, /*timestamp*/ 0);
+                        if (res != OK) {
+                            ALOGE("%s: Can't return output buffer for frame %d to"
+                                  " stream %d: %s (%d)",  __FUNCTION__,
+                                  frameNumber, streamId, strerror(-res), res);
+                        }
+                        break;
+                    case CAMERA3_STREAM_INPUT:
+                        res = stream->returnInputBuffer(streamBuffer);
+                        if (res != OK) {
+                            ALOGE("%s: Can't return input buffer for frame %d to"
+                                  " stream %d: %s (%d)",  __FUNCTION__,
+                                  frameNumber, streamId, strerror(-res), res);
+                        }
+                        break;
+                    default: // Bi-direcitonal stream is deprecated
+                        ALOGE("%s: stream %d has unknown stream type %d",
+                                __FUNCTION__, streamId, halStream->stream_type);
+                        break;
+                }
+                break;
+            }
+        }
+        if (streamDeleted) {
+            continue;
+        }
+
+        // Then check against configured streams
+        if (streamId == inputStreamId) {
+            streamBuffer.stream = mInputStream->asHalStream();
+            res = mInputStream->returnInputBuffer(streamBuffer);
+            if (res != OK) {
+                ALOGE("%s: Can't return input buffer for frame %d to"
+                      " stream %d: %s (%d)",  __FUNCTION__,
+                      frameNumber, streamId, strerror(-res), res);
+            }
+        } else {
+            ssize_t idx = mOutputStreams.indexOfKey(streamId);
+            if (idx == NAME_NOT_FOUND) {
+                ALOGE("%s: Output stream id %d not found!", __FUNCTION__, streamId);
+                continue;
+            }
+            streamBuffer.stream = mOutputStreams.valueAt(idx)->asHalStream();
+            returnOutputBuffers(&streamBuffer, /*size*/1, /*timestamp*/ 0);
+        }
+    }
+}
+
 void Camera3Device::insertResultLocked(CaptureResult *result,
         uint32_t frameNumber) {
     if (result == nullptr) return;
@@ -3322,6 +3501,20 @@
     return res;
 }
 
+void Camera3Device::HalInterface::getInflightBufferKeys(
+        std::vector<std::pair<int32_t, int32_t>>* out) {
+    std::lock_guard<std::mutex> lock(mInflightLock);
+    out->clear();
+    out->reserve(mInflightBufferMap.size());
+    for (auto& pair : mInflightBufferMap) {
+        uint64_t key = pair.first;
+        int32_t streamId = key & 0xFFFFFFFF;
+        int32_t frameNumber = (key >> 32) & 0xFFFFFFFF;
+        out->push_back(std::make_pair(frameNumber, streamId));
+    }
+    return;
+}
+
 status_t Camera3Device::HalInterface::pushInflightBufferLocked(
         int32_t frameNumber, int32_t streamId, buffer_handle_t *buffer, int acquireFence) {
     uint64_t key = static_cast<uint64_t>(frameNumber) << 32 | static_cast<uint64_t>(streamId);
@@ -3396,7 +3589,7 @@
 
 Camera3Device::RequestThread::RequestThread(wp<Camera3Device> parent,
         sp<StatusTracker> statusTracker,
-        HalInterface* interface) :
+        sp<HalInterface> interface) :
         Thread(/*canCallJava*/false),
         mParent(parent),
         mStatusTracker(statusTracker),
@@ -3571,7 +3764,8 @@
             // Abort the input buffers for reprocess requests.
             if ((*it)->mInputStream != NULL) {
                 camera3_stream_buffer_t inputBuffer;
-                status_t res = (*it)->mInputStream->getInputBuffer(&inputBuffer);
+                status_t res = (*it)->mInputStream->getInputBuffer(&inputBuffer,
+                        /*respectHalLimit*/ false);
                 if (res != OK) {
                     ALOGW("%s: %d: couldn't get input buffer while clearing the request "
                             "list: %s (%d)", __FUNCTION__, __LINE__, strerror(-res), res);
@@ -3793,6 +3987,42 @@
     return true;
 }
 
+nsecs_t Camera3Device::RequestThread::calculateMaxExpectedDuration(const camera_metadata_t *request) {
+    nsecs_t maxExpectedDuration = kDefaultExpectedDuration;
+    camera_metadata_ro_entry_t e = camera_metadata_ro_entry_t();
+    find_camera_metadata_ro_entry(request,
+            ANDROID_CONTROL_AE_MODE,
+            &e);
+    if (e.count == 0) return maxExpectedDuration;
+
+    switch (e.data.u8[0]) {
+        case ANDROID_CONTROL_AE_MODE_OFF:
+            find_camera_metadata_ro_entry(request,
+                    ANDROID_SENSOR_EXPOSURE_TIME,
+                    &e);
+            if (e.count > 0) {
+                maxExpectedDuration = e.data.i64[0];
+            }
+            find_camera_metadata_ro_entry(request,
+                    ANDROID_SENSOR_FRAME_DURATION,
+                    &e);
+            if (e.count > 0) {
+                maxExpectedDuration = std::max(e.data.i64[0], maxExpectedDuration);
+            }
+            break;
+        default:
+            find_camera_metadata_ro_entry(request,
+                    ANDROID_CONTROL_AE_TARGET_FPS_RANGE,
+                    &e);
+            if (e.count > 1) {
+                maxExpectedDuration = 1e9 / e.data.u8[0];
+            }
+            break;
+    }
+
+    return maxExpectedDuration;
+}
+
 bool Camera3Device::RequestThread::threadLoop() {
     ATRACE_CALL();
     status_t res;
@@ -4013,7 +4243,8 @@
         res = parent->registerInFlight(halRequest->frame_number,
                 totalNumBuffers, captureRequest->mResultExtras,
                 /*hasInput*/halRequest->input_buffer != NULL,
-                hasCallback);
+                hasCallback,
+                calculateMaxExpectedDuration(halRequest->settings));
         ALOGVV("%s: registered in flight requestId = %" PRId32 ", frameNumber = %" PRId64
                ", burstId = %" PRId32 ".",
                 __FUNCTION__,
@@ -4067,6 +4298,12 @@
     return false;
 }
 
+nsecs_t Camera3Device::getExpectedInFlightDuration() {
+    Mutex::Autolock al(mInFlightLock);
+    return mExpectedInflightDuration > kMinInflightDuration ?
+            mExpectedInflightDuration : kMinInflightDuration;
+}
+
 void Camera3Device::RequestThread::cleanUpFailedRequests(bool sendRequestError) {
     if (mNextRequests.empty()) {
         return;
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index bfb58c6..d700e03 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -187,10 +187,11 @@
 
     static const size_t        kDumpLockAttempts  = 10;
     static const size_t        kDumpSleepDuration = 100000; // 0.10 sec
-    static const nsecs_t       kShutdownTimeout   = 5000000000; // 5 sec
     static const nsecs_t       kActiveTimeout     = 500000000;  // 500 ms
-    static const size_t        kInFlightWarnLimit = 20;
+    static const size_t        kInFlightWarnLimit = 30;
     static const size_t        kInFlightWarnLimitHighSpeed = 256; // batch size 32 * pipe depth 8
+    static const nsecs_t       kDefaultExpectedDuration = 100000000; // 100 ms
+    static const nsecs_t       kMinInflightDuration = 5000000000; // 5 s
     // SCHED_FIFO priority for request submission thread in HFR mode
     static const int           kRequestThreadPriority = 1;
 
@@ -265,6 +266,10 @@
         status_t popInflightBuffer(int32_t frameNumber, int32_t streamId,
                 /*out*/ buffer_handle_t **buffer);
 
+        // Get a vector of (frameNumber, streamId) pair of currently inflight
+        // buffers
+        void getInflightBufferKeys(std::vector<std::pair<int32_t, int32_t>>* out);
+
       private:
         camera3_device_t *mHal3Device;
         sp<hardware::camera::device::V3_2::ICameraDeviceSession> mHidlSession;
@@ -333,7 +338,7 @@
         std::vector<std::pair<int, uint64_t>> mFreedBuffers;
     };
 
-    std::unique_ptr<HalInterface> mInterface;
+    sp<HalInterface> mInterface;
 
     CameraMetadata             mDeviceInfo;
 
@@ -481,7 +486,7 @@
      * CameraDeviceBase interface we shouldn't need to.
      * Must be called with mLock and mInterfaceLock both held.
      */
-    status_t internalPauseAndWaitLocked();
+    status_t internalPauseAndWaitLocked(nsecs_t maxExpectedDuration);
 
     /**
      * Resume work after internalPauseAndWaitLocked()
@@ -507,7 +512,7 @@
      *
      * Need to be called with mLock and mInterfaceLock held.
      */
-    status_t waitUntilDrainedLocked();
+    status_t waitUntilDrainedLocked(nsecs_t maxExpectedDuration);
 
     /**
      * Do common work for setting up a streaming or single capture request.
@@ -624,7 +629,7 @@
 
         RequestThread(wp<Camera3Device> parent,
                 sp<camera3::StatusTracker> statusTracker,
-                HalInterface* interface);
+                sp<HalInterface> interface);
         ~RequestThread();
 
         void     setNotificationListener(wp<NotificationListener> listener);
@@ -772,9 +777,12 @@
         // send request in mNextRequests to HAL in a batch. Return true = sucssess
         bool sendRequestsBatch();
 
+        // Calculate the expected maximum duration for a request
+        nsecs_t calculateMaxExpectedDuration(const camera_metadata_t *request);
+
         wp<Camera3Device>  mParent;
         wp<camera3::StatusTracker>  mStatusTracker;
-        HalInterface*      mInterface;
+        sp<HalInterface>   mInterface;
 
         wp<NotificationListener> mListener;
 
@@ -873,6 +881,11 @@
         // is not for constrained high speed recording, this flag will also be true.
         bool hasCallback;
 
+        // Maximum expected frame duration for this request.
+        // For manual captures, equal to the max of requested exposure time and frame duration
+        // For auto-exposure modes, equal to 1/(lower end of target FPS range)
+        nsecs_t maxExpectedDuration;
+
         // Default constructor needed by KeyedVector
         InFlightRequest() :
                 shutterTimestamp(0),
@@ -881,11 +894,12 @@
                 haveResultMetadata(false),
                 numBuffersLeft(0),
                 hasInputBuffer(false),
-                hasCallback(true) {
+                hasCallback(true),
+                maxExpectedDuration(kDefaultExpectedDuration) {
         }
 
         InFlightRequest(int numBuffers, CaptureResultExtras extras, bool hasInput,
-                bool hasAppCallback) :
+                bool hasAppCallback, nsecs_t maxDuration) :
                 shutterTimestamp(0),
                 sensorTimestamp(0),
                 requestStatus(OK),
@@ -893,20 +907,31 @@
                 numBuffersLeft(numBuffers),
                 resultExtras(extras),
                 hasInputBuffer(hasInput),
-                hasCallback(hasAppCallback) {
+                hasCallback(hasAppCallback),
+                maxExpectedDuration(maxDuration) {
         }
     };
 
     // Map from frame number to the in-flight request state
     typedef KeyedVector<uint32_t, InFlightRequest> InFlightMap;
 
-    Mutex                  mInFlightLock; // Protects mInFlightMap
+
+    Mutex                  mInFlightLock; // Protects mInFlightMap and
+                                          // mExpectedInflightDuration
     InFlightMap            mInFlightMap;
+    nsecs_t                mExpectedInflightDuration = 0;
     int                    mInFlightStatusId;
 
+
     status_t registerInFlight(uint32_t frameNumber,
             int32_t numBuffers, CaptureResultExtras resultExtras, bool hasInput,
-            bool callback);
+            bool callback, nsecs_t maxExpectedDuration);
+
+    /**
+     * Returns the maximum expected time it'll take for all currently in-flight
+     * requests to complete, based on their settings
+     */
+    nsecs_t getExpectedInFlightDuration();
 
     /**
      * Tracking for idle detection
@@ -1023,6 +1048,10 @@
     // Remove the in-flight request of the given index from mInFlightMap
     // if it's no longer needed. It must only be called with mInFlightLock held.
     void removeInFlightRequestIfReadyLocked(int idx);
+    // Remove all in-flight requests and return all buffers.
+    // This is used after HAL interface is closed to cleanup any request/buffers
+    // not returned by HAL.
+    void flushInflightRequests();
 
     /**** End scope for mInFlightLock ****/
 
diff --git a/services/camera/libcameraservice/device3/Camera3InputStream.cpp b/services/camera/libcameraservice/device3/Camera3InputStream.cpp
index 4eb15ad..ff2dcef 100644
--- a/services/camera/libcameraservice/device3/Camera3InputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3InputStream.cpp
@@ -293,8 +293,18 @@
 void Camera3InputStream::onBufferFreed(const wp<GraphicBuffer>& gb) {
     const sp<GraphicBuffer> buffer = gb.promote();
     if (buffer != nullptr) {
-        if (mBufferFreedListener != nullptr) {
-            mBufferFreedListener->onBufferFreed(mId, buffer->handle);
+        camera3_stream_buffer streamBuffer =
+                {nullptr, &buffer->handle, 0, -1, -1};
+        // Check if this buffer is outstanding.
+        if (isOutstandingBuffer(streamBuffer)) {
+            ALOGV("%s: Stream %d: Trying to free a buffer that is still being "
+                    "processed.", __FUNCTION__, mId);
+            return;
+        }
+
+        sp<Camera3StreamBufferFreedListener> callback = mBufferFreedListener.promote();
+        if (callback != nullptr) {
+            callback->onBufferFreed(mId, buffer->handle);
         }
     } else {
         ALOGE("%s: GraphicBuffer is freed before onBufferFreed callback finishes!", __FUNCTION__);
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
index e15aa43..b02cd6a 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
@@ -727,7 +727,7 @@
 
 void Camera3OutputStream::onBuffersRemovedLocked(
         const std::vector<sp<GraphicBuffer>>& removedBuffers) {
-    Camera3StreamBufferFreedListener* callback = mBufferFreedListener;
+    sp<Camera3StreamBufferFreedListener> callback = mBufferFreedListener.promote();
     if (callback != nullptr) {
         for (auto gb : removedBuffers) {
             callback->onBufferFreed(mId, gb->handle);
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.cpp b/services/camera/libcameraservice/device3/Camera3Stream.cpp
index ba352c4..9e6ac79 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Stream.cpp
@@ -479,6 +479,7 @@
     if (res == OK) {
         fireBufferListenersLocked(*buffer, /*acquired*/true, /*output*/true);
         if (buffer->buffer) {
+            Mutex::Autolock l(mOutstandingBuffersLock);
             mOutstandingBuffers.push_back(*buffer->buffer);
         }
     }
@@ -486,11 +487,13 @@
     return res;
 }
 
-bool Camera3Stream::isOutstandingBuffer(const camera3_stream_buffer &buffer) {
+bool Camera3Stream::isOutstandingBuffer(const camera3_stream_buffer &buffer) const{
     if (buffer.buffer == nullptr) {
         return false;
     }
 
+    Mutex::Autolock l(mOutstandingBuffersLock);
+
     for (auto b : mOutstandingBuffers) {
         if (b == *buffer.buffer) {
             return true;
@@ -504,6 +507,8 @@
         return;
     }
 
+    Mutex::Autolock l(mOutstandingBuffersLock);
+
     for (auto b = mOutstandingBuffers.begin(); b != mOutstandingBuffers.end(); b++) {
         if (*b == *buffer.buffer) {
             mOutstandingBuffers.erase(b);
@@ -523,6 +528,8 @@
         return BAD_VALUE;
     }
 
+    removeOutstandingBuffer(buffer);
+
     /**
      * TODO: Check that the state is valid first.
      *
@@ -540,11 +547,10 @@
     // buffer to be returned.
     mOutputBufferReturnedSignal.signal();
 
-    removeOutstandingBuffer(buffer);
     return res;
 }
 
-status_t Camera3Stream::getInputBuffer(camera3_stream_buffer *buffer) {
+status_t Camera3Stream::getInputBuffer(camera3_stream_buffer *buffer, bool respectHalLimit) {
     ATRACE_CALL();
     Mutex::Autolock l(mLock);
     status_t res = OK;
@@ -557,7 +563,7 @@
     }
 
     // Wait for new buffer returned back if we are running into the limit.
-    if (getHandoutInputBufferCountLocked() == camera3_stream::max_buffers) {
+    if (getHandoutInputBufferCountLocked() == camera3_stream::max_buffers && respectHalLimit) {
         ALOGV("%s: Already dequeued max input buffers (%d), wait for next returned one.",
                 __FUNCTION__, camera3_stream::max_buffers);
         res = mInputBufferReturnedSignal.waitRelative(mLock, kWaitForBufferDuration);
@@ -574,6 +580,7 @@
     if (res == OK) {
         fireBufferListenersLocked(*buffer, /*acquired*/true, /*output*/false);
         if (buffer->buffer) {
+            Mutex::Autolock l(mOutstandingBuffersLock);
             mOutstandingBuffers.push_back(*buffer->buffer);
         }
     }
@@ -591,13 +598,14 @@
         return BAD_VALUE;
     }
 
+    removeOutstandingBuffer(buffer);
+
     status_t res = returnInputBufferLocked(buffer);
     if (res == OK) {
         fireBufferListenersLocked(buffer, /*acquired*/false, /*output*/false);
         mInputBufferReturnedSignal.signal();
     }
 
-    removeOutstandingBuffer(buffer);
     return res;
 }
 
@@ -744,7 +752,7 @@
 }
 
 void Camera3Stream::setBufferFreedListener(
-        Camera3StreamBufferFreedListener* listener) {
+        wp<Camera3StreamBufferFreedListener> listener) {
     Mutex::Autolock l(mLock);
     // Only allow set listener during stream configuration because stream is guaranteed to be IDLE
     // at this state, so setBufferFreedListener won't collide with onBufferFreed callbacks
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.h b/services/camera/libcameraservice/device3/Camera3Stream.h
index b5a9c5d..44fe6b6 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.h
+++ b/services/camera/libcameraservice/device3/Camera3Stream.h
@@ -308,8 +308,10 @@
      * For bidirectional streams, this method applies to the input-side
      * buffers.
      *
+     * Normally this call will block until the handed out buffer count is less than the stream
+     * max buffer count; if respectHalLimit is set to false, this is ignored.
      */
-    status_t         getInputBuffer(camera3_stream_buffer *buffer);
+    status_t         getInputBuffer(camera3_stream_buffer *buffer, bool respectHalLimit = true);
 
     /**
      * Return a buffer to the stream after use by the HAL.
@@ -369,7 +371,7 @@
 
     // Setting listener will remove previous listener (if exists)
     virtual void     setBufferFreedListener(
-            Camera3StreamBufferFreedListener* listener) override;
+            wp<Camera3StreamBufferFreedListener> listener) override;
 
     /**
      * Return if the buffer queue of the stream is abandoned.
@@ -414,7 +416,7 @@
             android_dataspace dataSpace, camera3_stream_rotation_t rotation,
             int setId);
 
-    Camera3StreamBufferFreedListener* mBufferFreedListener;
+    wp<Camera3StreamBufferFreedListener> mBufferFreedListener;
 
     /**
      * Interface to be implemented by derived classes
@@ -459,6 +461,9 @@
     // INVALID_OPERATION if they cannot be obtained.
     virtual status_t getEndpointUsage(uint32_t *usage) const = 0;
 
+    // Return whether the buffer is in the list of outstanding buffers.
+    bool isOutstandingBuffer(const camera3_stream_buffer& buffer) const;
+
     // Tracking for idle state
     wp<StatusTracker> mStatusTracker;
     // Status tracker component ID
@@ -481,9 +486,6 @@
 
     status_t        cancelPrepareLocked();
 
-    // Return whether the buffer is in the list of outstanding buffers.
-    bool isOutstandingBuffer(const camera3_stream_buffer& buffer);
-
     // Remove the buffer from the list of outstanding buffers.
     void removeOutstandingBuffer(const camera3_stream_buffer& buffer);
 
@@ -500,6 +502,7 @@
     // Number of buffers allocated on last prepare call.
     size_t mLastMaxCount;
 
+    mutable Mutex mOutstandingBuffersLock;
     // Outstanding buffers dequeued from the stream's buffer queue.
     List<buffer_handle_t> mOutstandingBuffers;
 
diff --git a/services/camera/libcameraservice/device3/Camera3StreamBufferFreedListener.h b/services/camera/libcameraservice/device3/Camera3StreamBufferFreedListener.h
index 478a752..104cd22 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamBufferFreedListener.h
+++ b/services/camera/libcameraservice/device3/Camera3StreamBufferFreedListener.h
@@ -24,7 +24,7 @@
 
 namespace camera3 {
 
-class Camera3StreamBufferFreedListener {
+class Camera3StreamBufferFreedListener : public virtual RefBase {
 public:
     // onBufferFreed is called when a buffer is no longer being managed
     // by this stream. This will not be called in events when all
diff --git a/services/camera/libcameraservice/device3/Camera3StreamInterface.h b/services/camera/libcameraservice/device3/Camera3StreamInterface.h
index 37b7c36..0544a1b 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamInterface.h
+++ b/services/camera/libcameraservice/device3/Camera3StreamInterface.h
@@ -232,8 +232,10 @@
      * For bidirectional streams, this method applies to the input-side
      * buffers.
      *
+     * Normally this call will block until the handed out buffer count is less than the stream
+     * max buffer count; if respectHalLimit is set to false, this is ignored.
      */
-    virtual status_t getInputBuffer(camera3_stream_buffer *buffer) = 0;
+    virtual status_t getInputBuffer(camera3_stream_buffer *buffer, bool respectHalLimit = true) = 0;
 
     /**
      * Return a buffer to the stream after use by the HAL.
@@ -296,7 +298,7 @@
      * Client is responsible to keep the listener object alive throughout the lifecycle of this
      * Camera3Stream.
      */
-    virtual void setBufferFreedListener(Camera3StreamBufferFreedListener* listener) = 0;
+    virtual void setBufferFreedListener(wp<Camera3StreamBufferFreedListener> listener) = 0;
 };
 
 } // namespace camera3
diff --git a/services/mediaanalytics/MetricsSummarizer.cpp b/services/mediaanalytics/MetricsSummarizer.cpp
index 6d5787e..3477f1f 100644
--- a/services/mediaanalytics/MetricsSummarizer.cpp
+++ b/services/mediaanalytics/MetricsSummarizer.cpp
@@ -153,11 +153,11 @@
                 ALOGE("unable to save MediaMetrics record");
             }
             sortProps(item);
-            item->setInt32("aggregated",1);
+            item->setInt32("count",1);
             mSummaries->push_back(item);
     } else {
             ALOGV("increment existing record");
-            (*it)->addInt32("aggregated",1);
+            (*it)->addInt32("count",1);
             mergeRecord(*(*it), *item);
     }
 }
diff --git a/services/mediacodec/Android.mk b/services/mediacodec/Android.mk
index 8eb4aa0..6997b5a 100644
--- a/services/mediacodec/Android.mk
+++ b/services/mediacodec/Android.mk
@@ -4,46 +4,52 @@
 include $(CLEAR_VARS)
 LOCAL_SRC_FILES := MediaCodecService.cpp
 LOCAL_SHARED_LIBRARIES := \
-    libmedia \
+    libmedia_omx \
     libbinder \
     libgui \
     libutils \
     liblog \
     libstagefright_omx
 LOCAL_C_INCLUDES := \
-    $(TOP)/frameworks/av/media/libstagefright \
-    $(TOP)/frameworks/native/include/media/openmax
+    frameworks/av/include \
+    frameworks/av/media/libstagefright \
+    frameworks/av/media/libstagefright/include \
+    frameworks/native/include \
+    frameworks/native/include/media/openmax
 LOCAL_MODULE:= libmediacodecservice
+LOCAL_VENDOR_MODULE := true
 LOCAL_32_BIT_ONLY := true
 include $(BUILD_SHARED_LIBRARY)
 
-
 # service executable
 include $(CLEAR_VARS)
 LOCAL_REQUIRED_MODULES_arm := mediacodec.policy
 LOCAL_SRC_FILES := main_codecservice.cpp
 LOCAL_SHARED_LIBRARIES := \
-    libmedia \
+    libmedia_omx \
     libmediacodecservice \
     libbinder \
     libutils \
     libgui \
     liblog \
     libbase \
-    libavservices_minijail \
+    libavservices_minijail_vendor \
     libcutils \
     libhwbinder \
     libhidltransport \
     libstagefright_omx \
     android.hardware.media.omx@1.0 \
     android.hidl.memory@1.0
+
 LOCAL_C_INCLUDES := \
-    $(TOP)/frameworks/av/media/libstagefright \
-    $(TOP)/frameworks/av/media/libstagefright/include \
-    $(TOP)/frameworks/native/include/media/openmax
+    frameworks/av/include \
+    frameworks/av/media/libstagefright \
+    frameworks/av/media/libstagefright/include \
+    frameworks/native/include \
+    frameworks/native/include/media/openmax
 LOCAL_MODULE := android.hardware.media.omx@1.0-service
 LOCAL_MODULE_RELATIVE_PATH := hw
-LOCAL_PROPRIETARY_MODULE := true
+LOCAL_VENDOR_MODULE := true
 LOCAL_32_BIT_ONLY := true
 LOCAL_INIT_RC := android.hardware.media.omx@1.0-service.rc
 include $(BUILD_EXECUTABLE)
diff --git a/services/mediacodec/seccomp_policy/mediacodec-arm.policy b/services/mediacodec/seccomp_policy/mediacodec-arm.policy
index 52658d1..cbd7fb9 100644
--- a/services/mediacodec/seccomp_policy/mediacodec-arm.policy
+++ b/services/mediacodec/seccomp_policy/mediacodec-arm.policy
@@ -12,6 +12,7 @@
 dup: 1
 ppoll: 1
 mmap2: 1
+getrandom: 1
 
 # mremap: Ensure |flags| are (MREMAP_MAYMOVE | MREMAP_FIXED) TODO: Once minijail
 # parser support for '<' is in this needs to be modified to also prevent
diff --git a/services/mediadrm/Android.mk b/services/mediadrm/Android.mk
index fa3a02b..6b30db6 100644
--- a/services/mediadrm/Android.mk
+++ b/services/mediadrm/Android.mk
@@ -25,19 +25,13 @@
     libbinder \
     liblog \
     libmediadrm \
-    libutils
-ifneq ($(DISABLE_TREBLE_DRM), true)
-LOCAL_SHARED_LIBRARIES += \
+    libutils \
     libhidlbase \
     libhidlmemory \
-    android.hidl.base@1.0 \
+    libhidltransport \
     android.hardware.drm@1.0
-endif
 
 LOCAL_CFLAGS += -Wall -Wextra -Werror
-ifeq ($(DISABLE_TREBLE_DRM), true)
-LOCAL_CFLAGS += -DDISABLE_TREBLE_DRM=1
-endif
 
 LOCAL_MODULE:= mediadrmserver
 
diff --git a/services/mediadrm/MediaDrmService.cpp b/services/mediadrm/MediaDrmService.cpp
index b9ec347..a368c11 100644
--- a/services/mediadrm/MediaDrmService.cpp
+++ b/services/mediadrm/MediaDrmService.cpp
@@ -24,13 +24,8 @@
 #include <binder/IServiceManager.h>
 #include <utils/Log.h>
 
-#ifdef DISABLE_TREBLE_DRM
-#include <media/Crypto.h>
-#include <media/Drm.h>
-#else
 #include <media/CryptoHal.h>
 #include <media/DrmHal.h>
-#endif
 
 namespace android {
 
@@ -40,19 +35,11 @@
 }
 
 sp<ICrypto> MediaDrmService::makeCrypto() {
-#ifdef DISABLE_TREBLE_DRM
-    return new Crypto;
-#else
     return new CryptoHal;
-#endif
 }
 
 sp<IDrm> MediaDrmService::makeDrm() {
-#ifdef DISABLE_TREBLE_DRM
-    return new Drm;
-#else
     return new DrmHal;
-#endif
 }
 
 } // namespace android
diff --git a/services/medialog/MediaLogService.cpp b/services/medialog/MediaLogService.cpp
index aaf1018..a5512e1 100644
--- a/services/medialog/MediaLogService.cpp
+++ b/services/medialog/MediaLogService.cpp
@@ -26,7 +26,7 @@
 
 namespace android {
 
-// static const char kDeadlockedString[] = "MediaLogService may be deadlocked\n";
+ static const char kDeadlockedString[] = "MediaLogService may be deadlocked\n";
 MediaLogService::MediaLogService() :
     BnMediaLogService(),
     mMergerShared((NBLog::Shared*) malloc(NBLog::Timeline::sharedSize(kMergeBufferSize))),
@@ -99,35 +99,38 @@
         return NO_ERROR;
     }
 
-#if 0
-    Vector<NBLog::NamedReader> namedReaders;
-    {
-        bool locked = dumpTryLock(mLock);
+    if (args.size() > 0) {
+        const String8 arg0(args[0]);
+        if (!strcmp(arg0.string(), "-r")) {
+            // needed because mNamedReaders is protected by mLock
+            bool locked = dumpTryLock(mLock);
 
-        // failed to lock - MediaLogService is probably deadlocked
-        if (!locked) {
-            String8 result(kDeadlockedString);
-            if (fd >= 0) {
-                write(fd, result.string(), result.size());
-            } else {
-                ALOGW("%s:", result.string());
+            // failed to lock - MediaLogService is probably deadlocked
+            if (!locked) {
+                String8 result(kDeadlockedString);
+                if (fd >= 0) {
+                    write(fd, result.string(), result.size());
+                } else {
+                    ALOGW("%s:", result.string());
+                }
+                // TODO should we instead proceed to mMergeReader.dump? does it need lock?
+                return NO_ERROR;
             }
-            return NO_ERROR;
-        }
-            // namedReaders = mNamedReaders;
-            // for (size_t i = 0; i < namedReaders.size(); i++) {
-            //     const NBLog::NamedReader& namedReader = namedReaders[i];
-            //     if (fd >= 0) {
-            //         dprintf(fd, "\n%s:\n", namedReader.name());
-            //     } else {
-            //         ALOGI("%s:", namedReader.name());
-            //     }
-            //     namedReader.reader()->dump(fd, 0 /*indent*/);
-            // }
 
-        mLock.unlock();
+            for (const auto& namedReader : mNamedReaders) {
+                if (fd >= 0) {
+                    dprintf(fd, "\n%s:\n", namedReader.name());
+                } else {
+                    ALOGI("%s:", namedReader.name());
+                }
+                // TODO This code is for testing, remove it when done
+                // namedReader.reader()->dump(fd, 0 /*indent*/);
+            }
+
+            mLock.unlock();
+        }
     }
-#endif
+
     // FIXME request merge to make sure log is up to date
     mMergeReader.dump(fd);
     return NO_ERROR;
diff --git a/services/medialog/MediaLogService.h b/services/medialog/MediaLogService.h
index c6b99f1..39d9cc0 100644
--- a/services/medialog/MediaLogService.h
+++ b/services/medialog/MediaLogService.h
@@ -49,12 +49,15 @@
     // Internal dump
     static const int kDumpLockRetries = 50;
     static const int kDumpLockSleepUs = 20000;
-    static const size_t kMergeBufferSize = 16 * 1024; // TODO determine good value for this
+    // Size of merge buffer, in bytes
+    static const size_t kMergeBufferSize = 64 * 1024; // TODO determine good value for this
     static bool dumpTryLock(Mutex& mutex);
 
     Mutex               mLock;
 
-    Vector<NBLog::NamedReader> mNamedReaders;
+    Vector<NBLog::NamedReader> mNamedReaders;   // protected by mLock
+
+    // FIXME Need comments on all of these, especially about locking
     NBLog::Shared *mMergerShared;
     NBLog::Merger mMerger;
     NBLog::MergeReader mMergeReader;
diff --git a/services/mediaresourcemanager/Android.mk b/services/mediaresourcemanager/Android.mk
index c9cd8cc..5823036 100644
--- a/services/mediaresourcemanager/Android.mk
+++ b/services/mediaresourcemanager/Android.mk
@@ -11,7 +11,7 @@
 LOCAL_32_BIT_ONLY := true
 
 LOCAL_C_INCLUDES += \
-    $(TOPDIR)frameworks/av/include
+    frameworks/av/include
 
 LOCAL_CFLAGS += -Werror -Wall
 
diff --git a/services/minijail/Android.mk b/services/minijail/Android.mk
index 3e63f97..b6fcacc 100644
--- a/services/minijail/Android.mk
+++ b/services/minijail/Android.mk
@@ -8,6 +8,14 @@
 LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
 include $(BUILD_SHARED_LIBRARY)
 
+# Small library for media.extractor and media.codec sandboxing.
+include $(CLEAR_VARS)
+LOCAL_MODULE := libavservices_minijail_vendor
+LOCAL_VENDOR_MODULE := true
+LOCAL_SRC_FILES := minijail.cpp
+LOCAL_SHARED_LIBRARIES := libbase libminijail_vendor
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
+include $(BUILD_SHARED_LIBRARY)
 
 # Unit tests.
 include $(CLEAR_VARS)
diff --git a/services/oboeservice/AAudioClientTracker.cpp b/services/oboeservice/AAudioClientTracker.cpp
new file mode 100644
index 0000000..75392bd
--- /dev/null
+++ b/services/oboeservice/AAudioClientTracker.cpp
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#define LOG_TAG "AAudioService"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include <assert.h>
+#include <binder/IPCThreadState.h>
+#include <map>
+#include <mutex>
+#include <utils/Singleton.h>
+
+#include "utility/AAudioUtilities.h"
+#include "AAudioEndpointManager.h"
+#include "AAudioServiceEndpoint.h"
+#include "AAudioClientTracker.h"
+
+using namespace android;
+using namespace aaudio;
+
+ANDROID_SINGLETON_STATIC_INSTANCE(AAudioClientTracker);
+
+AAudioClientTracker::AAudioClientTracker()
+        : Singleton<AAudioClientTracker>() {
+}
+
+
+std::string AAudioClientTracker::dump() const {
+    std::stringstream result;
+    const bool isLocked = AAudio_tryUntilTrue(
+            [this]()->bool { return mLock.try_lock(); } /* f */,
+            50 /* times */,
+            20 /* sleepMs */);
+    if (!isLocked) {
+        result << "AAudioClientTracker may be deadlocked\n";
+    }
+
+    result << "AAudioClientTracker:\n";
+    for (const auto&  it : mNotificationClients) {
+        result << it.second->dump();
+    }
+
+    if (isLocked) {
+        mLock.unlock();
+    }
+    return result.str();
+}
+
+// Create a tracker for the client.
+aaudio_result_t AAudioClientTracker::registerClient(pid_t pid,
+                                         const sp<IAAudioClient>& client) {
+    ALOGV("AAudioClientTracker::registerClient(), calling pid = %d, getpid() = %d\n",
+          pid, getpid());
+
+    std::lock_guard<std::mutex> lock(mLock);
+    if (mNotificationClients.count(pid) == 0) {
+        sp<NotificationClient> notificationClient = new NotificationClient(pid);
+        mNotificationClients[pid] = notificationClient;
+
+        sp<IBinder> binder = IInterface::asBinder(client);
+        status_t status = binder->linkToDeath(notificationClient);
+        ALOGW_IF(status != NO_ERROR,
+                 "AAudioClientTracker::registerClient() linkToDeath = %d\n", status);
+        return AAudioConvert_androidToAAudioResult(status);
+    } else {
+        ALOGW("AAudioClientTracker::registerClient(%d) already registered!", pid);
+        return AAUDIO_OK; // TODO should this be considered an error
+    }
+}
+
+void AAudioClientTracker::unregisterClient(pid_t pid) {
+    ALOGV("AAudioClientTracker::unregisterClient(), calling pid = %d, getpid() = %d\n",
+          pid, getpid());
+    std::lock_guard<std::mutex> lock(mLock);
+    mNotificationClients.erase(pid);
+}
+
+int32_t AAudioClientTracker::getStreamCount(pid_t pid) {
+    std::lock_guard<std::mutex> lock(mLock);
+    auto it = mNotificationClients.find(pid);
+    if (it != mNotificationClients.end()) {
+        return it->second->getStreamCount();
+    } else {
+        return 0; // no existing client
+    }
+}
+
+aaudio_result_t
+AAudioClientTracker::registerClientStream(pid_t pid, sp<AAudioServiceStreamBase> serviceStream) {
+    aaudio_result_t result = AAUDIO_OK;
+    ALOGV("AAudioClientTracker::registerClientStream(%d, %p)\n", pid, serviceStream.get());
+    std::lock_guard<std::mutex> lock(mLock);
+    sp<NotificationClient> notificationClient = mNotificationClients[pid];
+    if (notificationClient == 0) {
+        // This will get called the first time the audio server registers an internal stream.
+        ALOGV("AAudioClientTracker::registerClientStream(%d,) unrecognized pid\n", pid);
+        notificationClient = new NotificationClient(pid);
+        mNotificationClients[pid] = notificationClient;
+    }
+    notificationClient->registerClientStream(serviceStream);
+    return result;
+}
+
+// Find the tracker for this process and remove it.
+aaudio_result_t
+AAudioClientTracker::unregisterClientStream(pid_t pid,
+                                            sp<AAudioServiceStreamBase> serviceStream) {
+    ALOGV("AAudioClientTracker::unregisterClientStream(%d, %p)\n", pid, serviceStream.get());
+    std::lock_guard<std::mutex> lock(mLock);
+    auto it = mNotificationClients.find(pid);
+    if (it != mNotificationClients.end()) {
+        ALOGV("AAudioClientTracker::unregisterClientStream(%d, %p) found NotificationClient\n",
+              pid, serviceStream.get());
+        it->second->unregisterClientStream(serviceStream);
+    } else {
+        ALOGE("AAudioClientTracker::unregisterClientStream(%d, %p) missing NotificationClient\n",
+              pid, serviceStream.get());
+    }
+    return AAUDIO_OK;
+}
+
+AAudioClientTracker::NotificationClient::NotificationClient(pid_t pid)
+        : mProcessId(pid) {
+    //ALOGD("AAudioClientTracker::NotificationClient(%d) created %p\n", pid, this);
+}
+
+AAudioClientTracker::NotificationClient::~NotificationClient() {
+    //ALOGD("AAudioClientTracker::~NotificationClient() destroyed %p\n", this);
+}
+
+int32_t AAudioClientTracker::NotificationClient::getStreamCount() {
+    std::lock_guard<std::mutex> lock(mLock);
+    return mStreams.size();
+}
+
+aaudio_result_t AAudioClientTracker::NotificationClient::registerClientStream(
+        sp<AAudioServiceStreamBase> serviceStream) {
+    std::lock_guard<std::mutex> lock(mLock);
+    mStreams.insert(serviceStream);
+    return AAUDIO_OK;
+}
+
+aaudio_result_t AAudioClientTracker::NotificationClient::unregisterClientStream(
+        sp<AAudioServiceStreamBase> serviceStream) {
+    std::lock_guard<std::mutex> lock(mLock);
+    mStreams.erase(serviceStream);
+    return AAUDIO_OK;
+}
+
+// Close any open streams for the client.
+void AAudioClientTracker::NotificationClient::binderDied(const wp<IBinder>& who __unused) {
+    AAudioService *aaudioService = AAudioClientTracker::getInstance().getAAudioService();
+    if (aaudioService != nullptr) {
+        // Copy the current list of streams to another vector because closing them below
+        // will cause unregisterClientStream() calls back to this object.
+        std::set<sp<AAudioServiceStreamBase>>  streamsToClose;
+
+        {
+            std::lock_guard<std::mutex> lock(mLock);
+            for (auto serviceStream : mStreams) {
+                streamsToClose.insert(serviceStream);
+            }
+        }
+
+        for (auto serviceStream : streamsToClose) {
+            aaudio_handle_t handle = serviceStream->getHandle();
+            ALOGW("AAudioClientTracker::binderDied() close abandoned stream 0x%08X\n", handle);
+            aaudioService->closeStream(handle);
+        }
+        // mStreams should be empty now
+    }
+    sp<NotificationClient> keep(this);
+    AAudioClientTracker::getInstance().unregisterClient(mProcessId);
+}
+
+
+std::string AAudioClientTracker::NotificationClient::dump() const {
+    std::stringstream result;
+    const bool isLocked = AAudio_tryUntilTrue(
+            [this]()->bool { return mLock.try_lock(); } /* f */,
+            50 /* times */,
+            20 /* sleepMs */);
+    if (!isLocked) {
+        result << "AAudioClientTracker::NotificationClient may be deadlocked\n";
+    }
+
+    result << "  client: pid = " << mProcessId << " has " << mStreams.size() << " streams\n";
+    for (auto serviceStream : mStreams) {
+        result << "     stream: 0x" << std::hex << serviceStream->getHandle() << std::dec << "\n";
+    }
+
+    if (isLocked) {
+        mLock.unlock();
+    }
+    return result.str();
+}
diff --git a/services/oboeservice/AAudioClientTracker.h b/services/oboeservice/AAudioClientTracker.h
new file mode 100644
index 0000000..accf1a7
--- /dev/null
+++ b/services/oboeservice/AAudioClientTracker.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_AAUDIO_AAUDIO_CLIENT_TRACKER_H
+#define ANDROID_AAUDIO_AAUDIO_CLIENT_TRACKER_H
+
+#include <map>
+#include <mutex>
+#include <set>
+
+#include <utils/Singleton.h>
+
+#include <aaudio/AAudio.h>
+#include "binding/IAAudioClient.h"
+#include "AAudioService.h"
+
+namespace aaudio {
+
+class AAudioClientTracker : public android::Singleton<AAudioClientTracker>{
+public:
+    AAudioClientTracker();
+    ~AAudioClientTracker() = default;
+
+    /**
+     * Returns information about the state of the this class.
+     *
+     * Will attempt to get the object lock, but will proceed
+     * even if it cannot.
+     *
+     * Each line of information ends with a newline.
+     *
+     * @return a string with useful information
+     */
+    std::string dump() const;
+
+    aaudio_result_t registerClient(pid_t pid, const android::sp<android::IAAudioClient>& client);
+
+    void unregisterClient(pid_t pid);
+
+    int32_t getStreamCount(pid_t pid);
+
+    aaudio_result_t registerClientStream(pid_t pid,
+                                         android::sp<AAudioServiceStreamBase> serviceStream);
+
+    aaudio_result_t unregisterClientStream(pid_t pid,
+                                           android::sp<AAudioServiceStreamBase> serviceStream);
+
+    android::AAudioService *getAAudioService() const {
+        return mAAudioService;
+    }
+
+    void setAAudioService(android::AAudioService *aaudioService) {
+        mAAudioService = aaudioService;
+    }
+
+private:
+
+    /**
+     * One per process.
+     */
+    class NotificationClient : public IBinder::DeathRecipient {
+    public:
+        NotificationClient(pid_t pid);
+        virtual ~NotificationClient();
+
+        int32_t getStreamCount();
+
+        std::string dump() const;
+
+        aaudio_result_t registerClientStream(android::sp<AAudioServiceStreamBase> serviceStream);
+
+        aaudio_result_t unregisterClientStream(android::sp<AAudioServiceStreamBase> serviceStream);
+
+        // IBinder::DeathRecipient
+        virtual     void    binderDied(const android::wp<IBinder>& who);
+
+    protected:
+        mutable std::mutex                              mLock;
+        const pid_t                                     mProcessId;
+        std::set<android::sp<AAudioServiceStreamBase>>  mStreams;
+    };
+
+    mutable std::mutex                               mLock;
+    std::map<pid_t, android::sp<NotificationClient>> mNotificationClients;
+    android::AAudioService                          *mAAudioService = nullptr;
+};
+
+} /* namespace aaudio */
+
+#endif //ANDROID_AAUDIO_AAUDIO_CLIENT_TRACKER_H
diff --git a/services/oboeservice/AAudioEndpointManager.cpp b/services/oboeservice/AAudioEndpointManager.cpp
index 3dc1feb..ec2f5b9 100644
--- a/services/oboeservice/AAudioEndpointManager.cpp
+++ b/services/oboeservice/AAudioEndpointManager.cpp
@@ -14,13 +14,16 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "AAudioService"
+#define LOG_TAG "AAudioEndpointManager"
 //#define LOG_NDEBUG 0
 #include <utils/Log.h>
 
 #include <assert.h>
+#include <functional>
 #include <map>
 #include <mutex>
+#include <sstream>
+#include <utility/AAudioUtilities.h>
 
 #include "AAudioEndpointManager.h"
 
@@ -35,51 +38,114 @@
         , mOutputs() {
 }
 
-AAudioServiceEndpoint *AAudioEndpointManager::openEndpoint(AAudioService &audioService, int32_t deviceId,
-                                                           aaudio_direction_t direction) {
+std::string AAudioEndpointManager::dump() const {
+    std::stringstream result;
+    const bool isLocked = AAudio_tryUntilTrue(
+            [this]()->bool { return mLock.try_lock(); } /* f */,
+            50 /* times */,
+            20 /* sleepMs */);
+    if (!isLocked) {
+        result << "EndpointManager may be deadlocked\n";
+    }
+
+    result << "AAudioEndpointManager:" << "\n";
+    size_t inputs = mInputs.size();
+    result << "Input Endpoints: " << inputs << "\n";
+    for (const auto &input : mInputs) {
+        result << "  Input: " << input->dump() << "\n";
+    }
+
+    size_t outputs = mOutputs.size();
+    result << "Output Endpoints: " << outputs << "\n";
+    for (const auto &output : mOutputs) {
+        result << "  Output: " << output->dump() << "\n";
+    }
+
+    if (isLocked) {
+        mLock.unlock();
+    }
+    return result.str();
+}
+
+AAudioServiceEndpoint *AAudioEndpointManager::openEndpoint(AAudioService &audioService,
+        const AAudioStreamConfiguration& configuration, aaudio_direction_t direction) {
     AAudioServiceEndpoint *endpoint = nullptr;
+    AAudioServiceEndpointCapture *capture = nullptr;
+    AAudioServiceEndpointPlay *player = nullptr;
     std::lock_guard<std::mutex> lock(mLock);
 
     // Try to find an existing endpoint.
+
+
+
     switch (direction) {
         case AAUDIO_DIRECTION_INPUT:
-            endpoint = mInputs[deviceId];
+            for (AAudioServiceEndpoint *ep : mInputs) {
+                if (ep->matches(configuration)) {
+                    endpoint = ep;
+                    break;
+                }
+            }
             break;
         case AAUDIO_DIRECTION_OUTPUT:
-            endpoint = mOutputs[deviceId];
+            for (AAudioServiceEndpoint *ep : mOutputs) {
+                if (ep->matches(configuration)) {
+                    endpoint = ep;
+                    break;
+                }
+            }
             break;
         default:
             assert(false); // There are only two possible directions.
             break;
     }
     ALOGD("AAudioEndpointManager::openEndpoint(), found %p for device = %d, dir = %d",
-          endpoint, deviceId, (int)direction);
+          endpoint, configuration.getDeviceId(), (int)direction);
 
     // If we can't find an existing one then open a new one.
     if (endpoint == nullptr) {
-        if (direction == AAUDIO_DIRECTION_INPUT) {
-            AAudioServiceEndpointCapture *capture = new AAudioServiceEndpointCapture(audioService);
-            if (capture->open(deviceId) != AAUDIO_OK) {
-                ALOGE("AAudioEndpointManager::openEndpoint(), open failed");
-                delete capture;
-            } else {
-                mInputs[deviceId] = capture;
+        // we must call openStream with audioserver identity
+        int64_t token = IPCThreadState::self()->clearCallingIdentity();
+        switch(direction) {
+            case AAUDIO_DIRECTION_INPUT:
+                capture = new AAudioServiceEndpointCapture(audioService);
                 endpoint = capture;
-            }
-        } else if (direction == AAUDIO_DIRECTION_OUTPUT) {
-            AAudioServiceEndpointPlay *player = new AAudioServiceEndpointPlay(audioService);
-            if (player->open(deviceId) != AAUDIO_OK) {
-                ALOGE("AAudioEndpointManager::openEndpoint(), open failed");
-                delete player;
-            } else {
-                mOutputs[deviceId] = player;
+                break;
+            case AAUDIO_DIRECTION_OUTPUT:
+                player = new AAudioServiceEndpointPlay(audioService);
                 endpoint = player;
-            }
+                break;
+            default:
+                break;
         }
 
+        if (endpoint != nullptr) {
+            aaudio_result_t result = endpoint->open(configuration);
+            if (result != AAUDIO_OK) {
+                ALOGE("AAudioEndpointManager::findEndpoint(), open failed");
+                delete endpoint;
+                endpoint = nullptr;
+            } else {
+                switch(direction) {
+                    case AAUDIO_DIRECTION_INPUT:
+                        mInputs.push_back(capture);
+                        break;
+                    case AAUDIO_DIRECTION_OUTPUT:
+                        mOutputs.push_back(player);
+                        break;
+                    default:
+                        break;
+                }
+            }
+        }
+        ALOGD("AAudioEndpointManager::openEndpoint(), created %p for device = %d, dir = %d",
+              endpoint, configuration.getDeviceId(), (int)direction);
+        IPCThreadState::self()->restoreCallingIdentity(token);
     }
 
     if (endpoint != nullptr) {
+        ALOGD("AAudioEndpointManager::openEndpoint(), sampleRate = %d, framesPerBurst = %d",
+              endpoint->getSampleRate(), endpoint->getFramesPerBurst());
         // Increment the reference count under this lock.
         endpoint->setReferenceCount(endpoint->getReferenceCount() + 1);
     }
@@ -95,20 +161,32 @@
     // Decrement the reference count under this lock.
     int32_t newRefCount = serviceEndpoint->getReferenceCount() - 1;
     serviceEndpoint->setReferenceCount(newRefCount);
+    ALOGD("AAudioEndpointManager::closeEndpoint(%p) newRefCount = %d",
+          serviceEndpoint, newRefCount);
+
+    // If no longer in use then close and delete it.
     if (newRefCount <= 0) {
         aaudio_direction_t direction = serviceEndpoint->getDirection();
-        int32_t deviceId = serviceEndpoint->getDeviceId();
+        // Track endpoints based on requested deviceId because UNSPECIFIED
+        // can change to a specific device after opening.
+        int32_t deviceId = serviceEndpoint->getRequestedDeviceId();
 
         switch (direction) {
             case AAUDIO_DIRECTION_INPUT:
-                mInputs.erase(deviceId);
+                mInputs.erase(
+                  std::remove(mInputs.begin(), mInputs.end(), serviceEndpoint), mInputs.end());
                 break;
             case AAUDIO_DIRECTION_OUTPUT:
-                mOutputs.erase(deviceId);
+                mOutputs.erase(
+                  std::remove(mOutputs.begin(), mOutputs.end(), serviceEndpoint), mOutputs.end());
+                break;
+            default:
                 break;
         }
 
         serviceEndpoint->close();
+        ALOGD("AAudioEndpointManager::closeEndpoint() delete %p for device %d, dir = %d",
+              serviceEndpoint, deviceId, (int)direction);
         delete serviceEndpoint;
     }
 }
diff --git a/services/oboeservice/AAudioEndpointManager.h b/services/oboeservice/AAudioEndpointManager.h
index db1103d..2511b2f 100644
--- a/services/oboeservice/AAudioEndpointManager.h
+++ b/services/oboeservice/AAudioEndpointManager.h
@@ -34,25 +34,37 @@
     ~AAudioEndpointManager() = default;
 
     /**
+     * Returns information about the state of the this class.
+     *
+     * Will attempt to get the object lock, but will proceed
+     * even if it cannot.
+     *
+     * Each line of information ends with a newline.
+     *
+     * @return a string with useful information
+     */
+    std::string dump() const;
+
+    /**
      * Find a service endpoint for the given deviceId and direction.
-     * If an endpoint does not already exist then it will try to create one.
+     * If an endpoint does not already exist then try to create one.
      *
      * @param deviceId
      * @param direction
      * @return endpoint or nullptr
      */
     AAudioServiceEndpoint *openEndpoint(android::AAudioService &audioService,
-                                        int32_t deviceId,
+                                        const AAudioStreamConfiguration& configuration,
                                         aaudio_direction_t direction);
 
     void closeEndpoint(AAudioServiceEndpoint *serviceEndpoint);
 
 private:
 
-    std::mutex    mLock;
+    mutable std::mutex mLock;
 
-    std::map<int32_t, AAudioServiceEndpointCapture *> mInputs;
-    std::map<int32_t, AAudioServiceEndpointPlay *> mOutputs;
+    std::vector<AAudioServiceEndpointCapture *> mInputs;
+    std::vector<AAudioServiceEndpointPlay *> mOutputs;
 
 };
 
diff --git a/services/oboeservice/AAudioMixer.cpp b/services/oboeservice/AAudioMixer.cpp
index 43203d4..952aa82 100644
--- a/services/oboeservice/AAudioMixer.cpp
+++ b/services/oboeservice/AAudioMixer.cpp
@@ -18,9 +18,17 @@
 //#define LOG_NDEBUG 0
 #include <utils/Log.h>
 
+#define ATRACE_TAG ATRACE_TAG_AUDIO
+
 #include <cstring>
+#include <utils/Trace.h>
+
 #include "AAudioMixer.h"
 
+#ifndef AAUDIO_MIXER_ATRACE_ENABLED
+#define AAUDIO_MIXER_ATRACE_ENABLED    1
+#endif
+
 using android::WrappingBuffer;
 using android::FifoBuffer;
 using android::fifo_frames_t;
@@ -41,13 +49,28 @@
     memset(mOutputBuffer, 0, mBufferSizeInBytes);
 }
 
-bool AAudioMixer::mix(FifoBuffer *fifo, float volume) {
+bool AAudioMixer::mix(int trackIndex, FifoBuffer *fifo, float volume) {
     WrappingBuffer wrappingBuffer;
     float *destination = mOutputBuffer;
     fifo_frames_t framesLeft = mFramesPerBurst;
 
+#if AAUDIO_MIXER_ATRACE_ENABLED
+    ATRACE_BEGIN("aaMix");
+#endif /* AAUDIO_MIXER_ATRACE_ENABLED */
+
     // Gather the data from the client. May be in two parts.
-    fifo->getFullDataAvailable(&wrappingBuffer);
+    fifo_frames_t fullFrames = fifo->getFullDataAvailable(&wrappingBuffer);
+#if AAUDIO_MIXER_ATRACE_ENABLED
+    if (ATRACE_ENABLED()) {
+        char rdyText[] = "aaMixRdy#";
+        char letter = 'A' + (trackIndex % 26);
+        rdyText[sizeof(rdyText) - 2] = letter;
+        ATRACE_INT(rdyText, fullFrames);
+    }
+#else /* MIXER_ATRACE_ENABLED */
+    (void) trackIndex;
+    (void) fullFrames;
+#endif /* AAUDIO_MIXER_ATRACE_ENABLED */
 
     // Mix data in one or two parts.
     int partIndex = 0;
@@ -65,11 +88,15 @@
         }
         partIndex++;
     }
-    fifo->getFifoControllerBase()->advanceReadIndex(mFramesPerBurst - framesLeft);
-    if (framesLeft > 0) {
-        //ALOGW("AAudioMixer::mix() UNDERFLOW by %d / %d frames ----- UNDERFLOW !!!!!!!!!!",
-        //      framesLeft, mFramesPerBurst);
-    }
+    // Always advance by one burst even if we do not have the data.
+    // Otherwise the stream timing will drift whenever there is an underflow.
+    // This actual underflow can then be detected by the client for XRun counting.
+    fifo->getFifoControllerBase()->advanceReadIndex(mFramesPerBurst);
+
+#if AAUDIO_MIXER_ATRACE_ENABLED
+    ATRACE_END();
+#endif /* AAUDIO_MIXER_ATRACE_ENABLED */
+
     return (framesLeft > 0); // did not get all the frames we needed, ie. "underflow"
 }
 
diff --git a/services/oboeservice/AAudioMixer.h b/services/oboeservice/AAudioMixer.h
index 9155fec..a8090bc 100644
--- a/services/oboeservice/AAudioMixer.h
+++ b/services/oboeservice/AAudioMixer.h
@@ -37,7 +37,7 @@
      * @param volume
      * @return true if underflowed
      */
-    bool mix(android::FifoBuffer *fifo, float volume);
+    bool mix(int trackIndex, android::FifoBuffer *fifo, float volume);
 
     void mixPart(float *destination, float *source, int32_t numFrames, float volume);
 
diff --git a/services/oboeservice/AAudioService.cpp b/services/oboeservice/AAudioService.cpp
index c9b9065..3992719 100644
--- a/services/oboeservice/AAudioService.cpp
+++ b/services/oboeservice/AAudioService.cpp
@@ -18,6 +18,7 @@
 //#define LOG_NDEBUG 0
 #include <utils/Log.h>
 
+#include <sstream>
 //#include <time.h>
 //#include <pthread.h>
 
@@ -26,16 +27,21 @@
 #include <utils/String16.h>
 
 #include "binding/AAudioServiceMessage.h"
+#include "AAudioClientTracker.h"
+#include "AAudioEndpointManager.h"
 #include "AAudioService.h"
 #include "AAudioServiceStreamMMAP.h"
 #include "AAudioServiceStreamShared.h"
 #include "AAudioServiceStreamMMAP.h"
 #include "binding/IAAudioService.h"
+#include "ServiceUtilities.h"
 #include "utility/HandleTracker.h"
 
 using namespace android;
 using namespace aaudio;
 
+#define MAX_STREAMS_PER_PROCESS   8
+
 typedef enum
 {
     AAUDIO_HANDLE_TYPE_STREAM
@@ -44,32 +50,76 @@
 
 android::AAudioService::AAudioService()
     : BnAAudioService() {
+    mAudioClient.clientUid = getuid();   // TODO consider using geteuid()
+    mAudioClient.clientPid = getpid();
+    mAudioClient.packageName = String16("");
+    AAudioClientTracker::getInstance().setAAudioService(this);
 }
 
 AAudioService::~AAudioService() {
 }
 
+status_t AAudioService::dump(int fd, const Vector<String16>& args) {
+    std::string result;
+
+    if (!dumpAllowed()) {
+        std::stringstream ss;
+        ss << "Permission denial: can't dump AAudioService from pid="
+                << IPCThreadState::self()->getCallingPid() << ", uid="
+                << IPCThreadState::self()->getCallingUid() << "\n";
+        result = ss.str();
+        ALOGW("%s", result.c_str());
+    } else {
+        result = mHandleTracker.dump()
+                 + AAudioClientTracker::getInstance().dump()
+                 + AAudioEndpointManager::getInstance().dump();
+    }
+    (void)write(fd, result.c_str(), result.size());
+    return NO_ERROR;
+}
+
+void AAudioService::registerClient(const sp<IAAudioClient>& client) {
+    pid_t pid = IPCThreadState::self()->getCallingPid();
+    AAudioClientTracker::getInstance().registerClient(pid, client);
+}
+
 aaudio_handle_t AAudioService::openStream(const aaudio::AAudioStreamRequest &request,
                                           aaudio::AAudioStreamConfiguration &configurationOutput) {
     aaudio_result_t result = AAUDIO_OK;
-    AAudioServiceStreamBase *serviceStream = nullptr;
+    sp<AAudioServiceStreamBase> serviceStream;
     const AAudioStreamConfiguration &configurationInput = request.getConstantConfiguration();
     bool sharingModeMatchRequired = request.isSharingModeMatchRequired();
     aaudio_sharing_mode_t sharingMode = configurationInput.getSharingMode();
 
+    // Enforce limit on client processes.
+    pid_t pid = request.getProcessId();
+    if (pid != mAudioClient.clientPid) {
+        int32_t count = AAudioClientTracker::getInstance().getStreamCount(pid);
+        if (count >= MAX_STREAMS_PER_PROCESS) {
+            ALOGE("AAudioService::openStream(): exceeded max streams per process %d >= %d",
+                  count,  MAX_STREAMS_PER_PROCESS);
+            return AAUDIO_ERROR_UNAVAILABLE;
+        }
+    }
+
     if (sharingMode != AAUDIO_SHARING_MODE_EXCLUSIVE && sharingMode != AAUDIO_SHARING_MODE_SHARED) {
         ALOGE("AAudioService::openStream(): unrecognized sharing mode = %d", sharingMode);
         return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
     }
 
     if (sharingMode == AAUDIO_SHARING_MODE_EXCLUSIVE) {
-        serviceStream = new AAudioServiceStreamMMAP();
+        // only trust audioserver for in service indication
+        bool inService = false;
+        if (mAudioClient.clientPid == IPCThreadState::self()->getCallingPid() &&
+                mAudioClient.clientUid == IPCThreadState::self()->getCallingUid()) {
+            inService = request.isInService();
+        }
+        serviceStream = new AAudioServiceStreamMMAP(mAudioClient, inService);
         result = serviceStream->open(request, configurationOutput);
         if (result != AAUDIO_OK) {
             // fall back to using a shared stream
-            ALOGD("AAudioService::openStream(), EXCLUSIVE mode failed");
-            delete serviceStream;
-            serviceStream = nullptr;
+            ALOGW("AAudioService::openStream(), could not open in EXCLUSIVE mode");
+            serviceStream.clear();
         } else {
             configurationOutput.setSharingMode(AAUDIO_SHARING_MODE_EXCLUSIVE);
         }
@@ -84,28 +134,43 @@
     }
 
     if (result != AAUDIO_OK) {
-        delete serviceStream;
-        ALOGE("AAudioService::openStream(): failed, return %d", result);
+        serviceStream.clear();
+        ALOGE("AAudioService::openStream(): failed, return %d = %s",
+              result, AAudio_convertResultToText(result));
         return result;
     } else {
-        aaudio_handle_t handle = mHandleTracker.put(AAUDIO_HANDLE_TYPE_STREAM, serviceStream);
-        ALOGV("AAudioService::openStream(): handle = 0x%08X", handle);
+        aaudio_handle_t handle = mHandleTracker.put(AAUDIO_HANDLE_TYPE_STREAM, serviceStream.get());
         if (handle < 0) {
             ALOGE("AAudioService::openStream(): handle table full");
-            delete serviceStream;
+            serviceStream->close();
+            serviceStream.clear();
+        } else {
+            ALOGD("AAudioService::openStream(): handle = 0x%08X", handle);
+            serviceStream->setHandle(handle);
+            pid_t pid = request.getProcessId();
+            AAudioClientTracker::getInstance().registerClientStream(pid, serviceStream);
         }
         return handle;
     }
 }
 
 aaudio_result_t AAudioService::closeStream(aaudio_handle_t streamHandle) {
-    AAudioServiceStreamBase *serviceStream = (AAudioServiceStreamBase *)
+    // Check permission and ownership first.
+    sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
+    if (serviceStream == nullptr) {
+        ALOGE("AAudioService::startStream(), illegal stream handle = 0x%0x", streamHandle);
+        return AAUDIO_ERROR_INVALID_HANDLE;
+    }
+
+    ALOGD("AAudioService.closeStream(0x%08X)", streamHandle);
+    // Remove handle from tracker so that we cannot look up the raw address any more.
+    serviceStream = (AAudioServiceStreamBase *)
             mHandleTracker.remove(AAUDIO_HANDLE_TYPE_STREAM,
                                   streamHandle);
-    ALOGV("AAudioService.closeStream(0x%08X)", streamHandle);
     if (serviceStream != nullptr) {
         serviceStream->close();
-        delete serviceStream;
+        pid_t pid = serviceStream->getOwnerProcessId();
+        AAudioClientTracker::getInstance().unregisterClientStream(pid, serviceStream);
         return AAUDIO_OK;
     }
     return AAUDIO_ERROR_INVALID_HANDLE;
@@ -113,8 +178,23 @@
 
 AAudioServiceStreamBase *AAudioService::convertHandleToServiceStream(
         aaudio_handle_t streamHandle) const {
-    return (AAudioServiceStreamBase *) mHandleTracker.get(AAUDIO_HANDLE_TYPE_STREAM,
-                              (aaudio_handle_t)streamHandle);
+    AAudioServiceStreamBase *serviceStream = (AAudioServiceStreamBase *)
+            mHandleTracker.get(AAUDIO_HANDLE_TYPE_STREAM, (aaudio_handle_t)streamHandle);
+    if (serviceStream != nullptr) {
+        // Only allow owner or the aaudio service to access the stream.
+        const uid_t callingUserId = IPCThreadState::self()->getCallingUid();
+        const uid_t ownerUserId = serviceStream->getOwnerUserId();
+        bool callerOwnsIt = callingUserId == ownerUserId;
+        bool serverCalling = callingUserId == mAudioClient.clientUid;
+        bool serverOwnsIt = ownerUserId == mAudioClient.clientUid;
+        bool allowed = callerOwnsIt || serverCalling || serverOwnsIt;
+        if (!allowed) {
+            ALOGE("AAudioService: calling uid %d cannot access stream 0x%08X owned by %d",
+                  callingUserId, streamHandle, ownerUserId);
+            serviceStream = nullptr;
+        }
+    }
+    return serviceStream;
 }
 
 aaudio_result_t AAudioService::getStreamDescription(
@@ -136,6 +216,7 @@
         ALOGE("AAudioService::startStream(), illegal stream handle = 0x%0x", streamHandle);
         return AAUDIO_ERROR_INVALID_HANDLE;
     }
+
     aaudio_result_t result = serviceStream->start();
     return result;
 }
@@ -170,9 +251,8 @@
 }
 
 aaudio_result_t AAudioService::registerAudioThread(aaudio_handle_t streamHandle,
-                                                         pid_t clientProcessId,
-                                                         pid_t clientThreadId,
-                                                         int64_t periodNanoseconds) {
+                                                   pid_t clientThreadId,
+                                                   int64_t periodNanoseconds) {
     AAudioServiceStreamBase *serviceStream = convertHandleToServiceStream(streamHandle);
     if (serviceStream == nullptr) {
         ALOGE("AAudioService::registerAudioThread(), illegal stream handle = 0x%0x", streamHandle);
@@ -182,12 +262,14 @@
         ALOGE("AAudioService::registerAudioThread(), thread already registered");
         return AAUDIO_ERROR_INVALID_STATE;
     }
+
+    const pid_t ownerPid = IPCThreadState::self()->getCallingPid(); // TODO review
     serviceStream->setRegisteredThread(clientThreadId);
-    int err = android::requestPriority(clientProcessId, clientThreadId,
+    int err = android::requestPriority(ownerPid, clientThreadId,
                                        DEFAULT_AUDIO_PRIORITY, true /* isForApp */);
     if (err != 0){
-        ALOGE("AAudioService::registerAudioThread() failed, errno = %d, priority = %d",
-              errno, DEFAULT_AUDIO_PRIORITY);
+        ALOGE("AAudioService::registerAudioThread(%d) failed, errno = %d, priority = %d",
+              clientThreadId, errno, DEFAULT_AUDIO_PRIORITY);
         return AAUDIO_ERROR_INTERNAL;
     } else {
         return AAUDIO_OK;
@@ -195,7 +277,6 @@
 }
 
 aaudio_result_t AAudioService::unregisterAudioThread(aaudio_handle_t streamHandle,
-                                                     pid_t clientProcessId,
                                                      pid_t clientThreadId) {
     AAudioServiceStreamBase *serviceStream = convertHandleToServiceStream(streamHandle);
     if (serviceStream == nullptr) {
@@ -210,3 +291,26 @@
     serviceStream->setRegisteredThread(0);
     return AAUDIO_OK;
 }
+
+aaudio_result_t AAudioService::startClient(aaudio_handle_t streamHandle,
+                                  const android::AudioClient& client,
+                                  audio_port_handle_t *clientHandle) {
+    AAudioServiceStreamBase *serviceStream = convertHandleToServiceStream(streamHandle);
+    if (serviceStream == nullptr) {
+        ALOGE("AAudioService::startClient(), illegal stream handle = 0x%0x",
+              streamHandle);
+        return AAUDIO_ERROR_INVALID_HANDLE;
+    }
+    return serviceStream->startClient(client, clientHandle);
+}
+
+aaudio_result_t AAudioService::stopClient(aaudio_handle_t streamHandle,
+                                          audio_port_handle_t clientHandle) {
+    AAudioServiceStreamBase *serviceStream = convertHandleToServiceStream(streamHandle);
+    if (serviceStream == nullptr) {
+        ALOGE("AAudioService::stopClient(), illegal stream handle = 0x%0x",
+              streamHandle);
+        return AAUDIO_ERROR_INVALID_HANDLE;
+    }
+    return serviceStream->stopClient(clientHandle);
+}
diff --git a/services/oboeservice/AAudioService.h b/services/oboeservice/AAudioService.h
index f5a7d2f..8421efc 100644
--- a/services/oboeservice/AAudioService.h
+++ b/services/oboeservice/AAudioService.h
@@ -21,6 +21,7 @@
 #include <pthread.h>
 
 #include <binder/BinderService.h>
+#include <media/AudioClient.h>
 
 #include <aaudio/AAudio.h>
 #include "utility/HandleTracker.h"
@@ -44,8 +45,12 @@
 
     static const char* getServiceName() { return AAUDIO_SERVICE_NAME; }
 
+    virtual status_t        dump(int fd, const Vector<String16>& args) override;
+
+    virtual void            registerClient(const sp<IAAudioClient>& client);
+
     virtual aaudio_handle_t openStream(const aaudio::AAudioStreamRequest &request,
-                                     aaudio::AAudioStreamConfiguration &configuration);
+                                     aaudio::AAudioStreamConfiguration &configurationOutput);
 
     virtual aaudio_result_t closeStream(aaudio_handle_t streamHandle);
 
@@ -62,11 +67,18 @@
     virtual aaudio_result_t flushStream(aaudio_handle_t streamHandle);
 
     virtual aaudio_result_t registerAudioThread(aaudio_handle_t streamHandle,
-                                              pid_t pid, pid_t tid,
-                                              int64_t periodNanoseconds) ;
+                                                pid_t tid,
+                                                int64_t periodNanoseconds) ;
 
     virtual aaudio_result_t unregisterAudioThread(aaudio_handle_t streamHandle,
-                                                  pid_t pid, pid_t tid);
+                                                  pid_t tid);
+
+    virtual aaudio_result_t startClient(aaudio_handle_t streamHandle,
+                                      const android::AudioClient& client,
+                                      audio_port_handle_t *clientHandle);
+
+    virtual aaudio_result_t stopClient(aaudio_handle_t streamHandle,
+                                       audio_port_handle_t clientHandle);
 
 private:
 
@@ -74,6 +86,8 @@
 
     HandleTracker mHandleTracker;
 
+    android::AudioClient mAudioClient;
+
     enum constants {
         DEFAULT_AUDIO_PRIORITY = 2
     };
diff --git a/services/oboeservice/AAudioServiceEndpoint.cpp b/services/oboeservice/AAudioServiceEndpoint.cpp
index d8ae284..0f863fe 100644
--- a/services/oboeservice/AAudioServiceEndpoint.cpp
+++ b/services/oboeservice/AAudioServiceEndpoint.cpp
@@ -14,20 +14,21 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "AAudioService"
+#define LOG_TAG "AAudioServiceEndpoint"
 //#define LOG_NDEBUG 0
 #include <utils/Log.h>
 
+#include <algorithm>
 #include <assert.h>
 #include <map>
 #include <mutex>
+#include <sstream>
+#include <vector>
+
 #include <utils/Singleton.h>
 
 #include "AAudioEndpointManager.h"
 #include "AAudioServiceEndpoint.h"
-#include <algorithm>
-#include <mutex>
-#include <vector>
 
 #include "core/AudioStreamBuilder.h"
 #include "AAudioServiceEndpoint.h"
@@ -44,15 +45,48 @@
 // This is the maximum size in frames. The effective size can be tuned smaller at runtime.
 #define DEFAULT_BUFFER_CAPACITY   (48 * 8)
 
+std::string AAudioServiceEndpoint::dump() const {
+    std::stringstream result;
+
+    const bool isLocked = AAudio_tryUntilTrue(
+            [this]()->bool { return mLockStreams.try_lock(); } /* f */,
+            50 /* times */,
+            20 /* sleepMs */);
+    if (!isLocked) {
+        result << "EndpointManager may be deadlocked\n";
+    }
+
+    AudioStreamInternal     *stream = mStreamInternal;
+    if (stream == nullptr) {
+        result << "null stream!" << "\n";
+    } else {
+        result << "mmap stream: rate = " << stream->getSampleRate() << "\n";
+    }
+
+    result << "    Registered Streams:" << "\n";
+    for (sp<AAudioServiceStreamShared> sharedStream : mRegisteredStreams) {
+        result << sharedStream->dump();
+    }
+
+    if (isLocked) {
+        mLockStreams.unlock();
+    }
+    return result.str();
+}
+
 // Set up an EXCLUSIVE MMAP stream that will be shared.
-aaudio_result_t AAudioServiceEndpoint::open(int32_t deviceId) {
+aaudio_result_t AAudioServiceEndpoint::open(const AAudioStreamConfiguration& configuration) {
+    mRequestedDeviceId = configuration.getDeviceId();
     mStreamInternal = getStreamInternal();
 
     AudioStreamBuilder builder;
     builder.setSharingMode(AAUDIO_SHARING_MODE_EXCLUSIVE);
     // Don't fall back to SHARED because that would cause recursion.
     builder.setSharingModeMatchRequired(true);
-    builder.setDeviceId(deviceId);
+    builder.setDeviceId(mRequestedDeviceId);
+    builder.setFormat(configuration.getFormat());
+    builder.setSampleRate(configuration.getSampleRate());
+    builder.setSamplesPerFrame(configuration.getSamplesPerFrame());
     builder.setDirection(getDirection());
     builder.setBufferCapacity(DEFAULT_BUFFER_CAPACITY);
 
@@ -60,45 +94,39 @@
 }
 
 aaudio_result_t AAudioServiceEndpoint::close() {
-    return getStreamInternal()->close();
+     return getStreamInternal()->close();
 }
 
 // TODO, maybe use an interface to reduce exposure
-aaudio_result_t AAudioServiceEndpoint::registerStream(AAudioServiceStreamShared *sharedStream) {
+aaudio_result_t AAudioServiceEndpoint::registerStream(sp<AAudioServiceStreamShared>sharedStream) {
     std::lock_guard<std::mutex> lock(mLockStreams);
     mRegisteredStreams.push_back(sharedStream);
     return AAUDIO_OK;
 }
 
-aaudio_result_t AAudioServiceEndpoint::unregisterStream(AAudioServiceStreamShared *sharedStream) {
+aaudio_result_t AAudioServiceEndpoint::unregisterStream(sp<AAudioServiceStreamShared>sharedStream) {
     std::lock_guard<std::mutex> lock(mLockStreams);
     mRegisteredStreams.erase(std::remove(mRegisteredStreams.begin(), mRegisteredStreams.end(), sharedStream),
               mRegisteredStreams.end());
     return AAUDIO_OK;
 }
 
-aaudio_result_t AAudioServiceEndpoint::startStream(AAudioServiceStreamShared *sharedStream) {
-    // TODO use real-time technique to avoid mutex, eg. atomic command FIFO
-    std::lock_guard<std::mutex> lock(mLockStreams);
-    mRunningStreams.push_back(sharedStream);
-    if (mRunningStreams.size() == 1) {
+aaudio_result_t AAudioServiceEndpoint::startStream(sp<AAudioServiceStreamShared> sharedStream) {
+    aaudio_result_t result = AAUDIO_OK;
+    if (++mRunningStreams == 1) {
+        // TODO use real-time technique to avoid mutex, eg. atomic command FIFO
+        std::lock_guard<std::mutex> lock(mLockStreams);
+        result = getStreamInternal()->requestStart();
         startSharingThread_l();
     }
-    return AAUDIO_OK;
+    return result;
 }
 
-aaudio_result_t AAudioServiceEndpoint::stopStream(AAudioServiceStreamShared *sharedStream) {
-    int numRunningStreams = 0;
-    {
-        std::lock_guard<std::mutex> lock(mLockStreams);
-        mRunningStreams.erase(
-                std::remove(mRunningStreams.begin(), mRunningStreams.end(), sharedStream),
-                mRunningStreams.end());
-        numRunningStreams = mRunningStreams.size();
-    }
-    if (numRunningStreams == 0) {
-        // Don't call this under a lock because the callbackLoop also uses the lock.
+aaudio_result_t AAudioServiceEndpoint::stopStream(sp<AAudioServiceStreamShared> sharedStream) {
+    // Don't lock here because the disconnectRegisteredStreams also uses the lock.
+    if (--mRunningStreams == 0) { // atomic
         stopSharingThread();
+        getStreamInternal()->requestStop();
     }
     return AAUDIO_OK;
 }
@@ -129,12 +157,27 @@
 
 void AAudioServiceEndpoint::disconnectRegisteredStreams() {
     std::lock_guard<std::mutex> lock(mLockStreams);
-    for(AAudioServiceStreamShared *sharedStream : mRunningStreams) {
-        sharedStream->onStop();
-    }
-    mRunningStreams.clear();
-    for(AAudioServiceStreamShared *sharedStream : mRegisteredStreams) {
-        sharedStream->onDisconnect();
+    for(auto sharedStream : mRegisteredStreams) {
+        sharedStream->stop();
+        sharedStream->disconnect();
     }
     mRegisteredStreams.clear();
 }
+
+bool AAudioServiceEndpoint::matches(const AAudioStreamConfiguration& configuration) {
+    if (configuration.getDeviceId() != AAUDIO_UNSPECIFIED &&
+            configuration.getDeviceId() != mStreamInternal->getDeviceId()) {
+        return false;
+    }
+    if (configuration.getSampleRate() != AAUDIO_UNSPECIFIED &&
+            configuration.getSampleRate() != mStreamInternal->getSampleRate()) {
+        return false;
+    }
+    if (configuration.getSamplesPerFrame() != AAUDIO_UNSPECIFIED &&
+            configuration.getSamplesPerFrame() != mStreamInternal->getSamplesPerFrame()) {
+        return false;
+    }
+
+    return true;
+}
+
diff --git a/services/oboeservice/AAudioServiceEndpoint.h b/services/oboeservice/AAudioServiceEndpoint.h
index 50bf049..e40a670 100644
--- a/services/oboeservice/AAudioServiceEndpoint.h
+++ b/services/oboeservice/AAudioServiceEndpoint.h
@@ -36,18 +36,21 @@
 public:
     virtual ~AAudioServiceEndpoint() = default;
 
-    virtual aaudio_result_t open(int32_t deviceId);
+    std::string dump() const;
+
+    virtual aaudio_result_t open(const AAudioStreamConfiguration& configuration);
 
     int32_t getSampleRate() const { return mStreamInternal->getSampleRate(); }
     int32_t getSamplesPerFrame() const { return mStreamInternal->getSamplesPerFrame();  }
     int32_t getFramesPerBurst() const { return mStreamInternal->getFramesPerBurst();  }
 
-    aaudio_result_t registerStream(AAudioServiceStreamShared *sharedStream);
-    aaudio_result_t unregisterStream(AAudioServiceStreamShared *sharedStream);
-    aaudio_result_t startStream(AAudioServiceStreamShared *sharedStream);
-    aaudio_result_t stopStream(AAudioServiceStreamShared *sharedStream);
+    aaudio_result_t registerStream(android::sp<AAudioServiceStreamShared> sharedStream);
+    aaudio_result_t unregisterStream(android::sp<AAudioServiceStreamShared> sharedStream);
+    aaudio_result_t startStream(android::sp<AAudioServiceStreamShared> sharedStream);
+    aaudio_result_t stopStream(android::sp<AAudioServiceStreamShared> sharedStream);
     aaudio_result_t close();
 
+    int32_t getRequestedDeviceId() const { return mRequestedDeviceId; }
     int32_t getDeviceId() const { return mStreamInternal->getDeviceId(); }
 
     aaudio_direction_t getDirection() const { return mStreamInternal->getDirection(); }
@@ -66,14 +69,17 @@
         mReferenceCount = count;
     }
 
+    bool matches(const AAudioStreamConfiguration& configuration);
+
     virtual AudioStreamInternal *getStreamInternal() = 0;
 
-    std::atomic<bool>        mCallbackEnabled;
+    std::atomic<bool>        mCallbackEnabled{false};
 
-    std::mutex               mLockStreams;
+    mutable std::mutex       mLockStreams;
 
-    std::vector<AAudioServiceStreamShared *> mRegisteredStreams;
-    std::vector<AAudioServiceStreamShared *> mRunningStreams;
+    std::vector<android::sp<AAudioServiceStreamShared>> mRegisteredStreams;
+
+    std::atomic<int>         mRunningStreams{0};
 
 private:
     aaudio_result_t startSharingThread_l();
@@ -81,6 +87,7 @@
 
     AudioStreamInternal     *mStreamInternal = nullptr;
     int32_t                  mReferenceCount = 0;
+    int32_t                  mRequestedDeviceId = 0;
 };
 
 } /* namespace aaudio */
diff --git a/services/oboeservice/AAudioServiceEndpointCapture.cpp b/services/oboeservice/AAudioServiceEndpointCapture.cpp
index 29d6cb9..6a37330 100644
--- a/services/oboeservice/AAudioServiceEndpointCapture.cpp
+++ b/services/oboeservice/AAudioServiceEndpointCapture.cpp
@@ -42,8 +42,8 @@
     delete mDistributionBuffer;
 }
 
-aaudio_result_t AAudioServiceEndpointCapture::open(int32_t deviceId) {
-    aaudio_result_t result = AAudioServiceEndpoint::open(deviceId);
+aaudio_result_t AAudioServiceEndpointCapture::open(const AAudioStreamConfiguration& configuration) {
+    aaudio_result_t result = AAudioServiceEndpoint::open(configuration);
     if (result == AAUDIO_OK) {
         delete mDistributionBuffer;
         int distributionBufferSizeBytes = getStreamInternal()->getFramesPerBurst()
@@ -57,9 +57,7 @@
 void *AAudioServiceEndpointCapture::callbackLoop() {
     ALOGD("AAudioServiceEndpointCapture(): callbackLoop() entering");
     int32_t underflowCount = 0;
-
-    aaudio_result_t result = getStreamInternal()->requestStart();
-
+    aaudio_result_t result = AAUDIO_OK;
     int64_t timeoutNanos = getStreamInternal()->calculateReasonableTimeout();
 
     // result might be a frame count
@@ -78,21 +76,21 @@
         // Distribute data to each active stream.
         { // use lock guard
             std::lock_guard <std::mutex> lock(mLockStreams);
-            for (AAudioServiceStreamShared *sharedStream : mRunningStreams) {
-                FifoBuffer *fifo = sharedStream->getDataFifoBuffer();
-                if (fifo->getFifoControllerBase()->getEmptyFramesAvailable() <
-                    getFramesPerBurst()) {
-                    underflowCount++;
-                } else {
-                    fifo->write(mDistributionBuffer, getFramesPerBurst());
+            for (sp<AAudioServiceStreamShared> sharedStream : mRegisteredStreams) {
+                if (sharedStream->isRunning()) {
+                    FifoBuffer *fifo = sharedStream->getDataFifoBuffer();
+                    if (fifo->getFifoControllerBase()->getEmptyFramesAvailable() <
+                        getFramesPerBurst()) {
+                        underflowCount++;
+                    } else {
+                        fifo->write(mDistributionBuffer, getFramesPerBurst());
+                    }
+                    sharedStream->markTransferTime(AudioClock::getNanoseconds());
                 }
-                sharedStream->markTransferTime(AudioClock::getNanoseconds());
             }
         }
     }
 
-    result = getStreamInternal()->requestStop();
-
     ALOGD("AAudioServiceEndpointCapture(): callbackLoop() exiting, %d underflows", underflowCount);
     return NULL; // TODO review
 }
diff --git a/services/oboeservice/AAudioServiceEndpointCapture.h b/services/oboeservice/AAudioServiceEndpointCapture.h
index 35857d1..8a3d72f 100644
--- a/services/oboeservice/AAudioServiceEndpointCapture.h
+++ b/services/oboeservice/AAudioServiceEndpointCapture.h
@@ -27,7 +27,7 @@
     explicit AAudioServiceEndpointCapture(android::AAudioService &audioService);
     virtual ~AAudioServiceEndpointCapture();
 
-    aaudio_result_t open(int32_t deviceId) override;
+    aaudio_result_t open(const AAudioStreamConfiguration& configuration) override;
 
     AudioStreamInternal *getStreamInternal() override {
         return &mStreamInternalCapture;
diff --git a/services/oboeservice/AAudioServiceEndpointPlay.cpp b/services/oboeservice/AAudioServiceEndpointPlay.cpp
index cc09cc3..b83b918 100644
--- a/services/oboeservice/AAudioServiceEndpointPlay.cpp
+++ b/services/oboeservice/AAudioServiceEndpointPlay.cpp
@@ -46,8 +46,8 @@
 AAudioServiceEndpointPlay::~AAudioServiceEndpointPlay() {
 }
 
-aaudio_result_t AAudioServiceEndpointPlay::open(int32_t deviceId) {
-    aaudio_result_t result = AAudioServiceEndpoint::open(deviceId);
+aaudio_result_t AAudioServiceEndpointPlay::open(const AAudioStreamConfiguration& configuration) {
+    aaudio_result_t result = AAudioServiceEndpoint::open(configuration);
     if (result == AAUDIO_OK) {
         mMixer.allocate(getStreamInternal()->getSamplesPerFrame(),
                         getStreamInternal()->getFramesPerBurst());
@@ -57,7 +57,6 @@
             mLatencyTuningEnabled = true;
             burstsPerBuffer = BURSTS_PER_BUFFER_DEFAULT;
         }
-        ALOGD("AAudioServiceEndpoint(): burstsPerBuffer = %d", burstsPerBuffer);
         int32_t desiredBufferSize = burstsPerBuffer * getStreamInternal()->getFramesPerBurst();
         getStreamInternal()->setBufferSize(desiredBufferSize);
     }
@@ -66,11 +65,8 @@
 
 // Mix data from each application stream and write result to the shared MMAP stream.
 void *AAudioServiceEndpointPlay::callbackLoop() {
-    ALOGD("AAudioServiceEndpointPlay(): callbackLoop() entering");
     int32_t underflowCount = 0;
-
-    aaudio_result_t result = getStreamInternal()->requestStart();
-
+    aaudio_result_t result = AAUDIO_OK;
     int64_t timeoutNanos = getStreamInternal()->calculateReasonableTimeout();
 
     // result might be a frame count
@@ -78,14 +74,18 @@
         // Mix data from each active stream.
         mMixer.clear();
         { // use lock guard
+            int index = 0;
             std::lock_guard <std::mutex> lock(mLockStreams);
-            for (AAudioServiceStreamShared *sharedStream : mRunningStreams) {
-                FifoBuffer *fifo = sharedStream->getDataFifoBuffer();
-                float volume = 0.5; // TODO get from system
-                bool underflowed = mMixer.mix(fifo, volume);
-                underflowCount += underflowed ? 1 : 0;
-                // TODO log underflows in each stream
-                sharedStream->markTransferTime(AudioClock::getNanoseconds());
+            for (sp<AAudioServiceStreamShared> sharedStream : mRegisteredStreams) {
+                if (sharedStream->isRunning()) {
+                    FifoBuffer *fifo = sharedStream->getDataFifoBuffer();
+                    float volume = 1.0; // to match legacy volume
+                    bool underflowed = mMixer.mix(index, fifo, volume);
+                    underflowCount += underflowed ? 1 : 0;
+                    // TODO log underflows in each stream
+                    sharedStream->markTransferTime(AudioClock::getNanoseconds());
+                }
+                index++;
             }
         }
 
@@ -102,8 +102,8 @@
         }
     }
 
-    result = getStreamInternal()->requestStop();
+    ALOGW_IF((underflowCount > 0),
+             "AAudioServiceEndpointPlay(): callbackLoop() had %d underflows", underflowCount);
 
-    ALOGD("AAudioServiceEndpointPlay(): callbackLoop() exiting, %d underflows", underflowCount);
     return NULL; // TODO review
 }
diff --git a/services/oboeservice/AAudioServiceEndpointPlay.h b/services/oboeservice/AAudioServiceEndpointPlay.h
index b977960..c22f510 100644
--- a/services/oboeservice/AAudioServiceEndpointPlay.h
+++ b/services/oboeservice/AAudioServiceEndpointPlay.h
@@ -32,12 +32,15 @@
 
 namespace aaudio {
 
+/**
+ * Contains a mixer and a stream for writing the result of the mix.
+ */
 class AAudioServiceEndpointPlay : public AAudioServiceEndpoint {
 public:
     explicit AAudioServiceEndpointPlay(android::AAudioService &audioService);
     virtual ~AAudioServiceEndpointPlay();
 
-    aaudio_result_t open(int32_t deviceId) override;
+    aaudio_result_t open(const AAudioStreamConfiguration& configuration) override;
 
     AudioStreamInternal *getStreamInternal() override {
         return &mStreamInternalPlay;
diff --git a/services/oboeservice/AAudioServiceStreamBase.cpp b/services/oboeservice/AAudioServiceStreamBase.cpp
index 8f0abc2..5f7d179 100644
--- a/services/oboeservice/AAudioServiceStreamBase.cpp
+++ b/services/oboeservice/AAudioServiceStreamBase.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "AAudioService"
+#define LOG_TAG "AAudioServiceStreamBase"
 //#define LOG_NDEBUG 0
 #include <utils/Log.h>
 
@@ -38,14 +38,42 @@
 AAudioServiceStreamBase::AAudioServiceStreamBase()
         : mUpMessageQueue(nullptr)
         , mAAudioThread() {
+    mMmapClient.clientUid = -1;
+    mMmapClient.clientPid = -1;
+    mMmapClient.packageName = String16("");
 }
 
 AAudioServiceStreamBase::~AAudioServiceStreamBase() {
-    close();
+    ALOGD("AAudioServiceStreamBase::~AAudioServiceStreamBase() destroying %p", this);
+    // If the stream is deleted when OPEN or in use then audio resources will leak.
+    // This would indicate an internal error. So we want to find this ASAP.
+    LOG_ALWAYS_FATAL_IF(!(mState == AAUDIO_STREAM_STATE_CLOSED
+                        || mState == AAUDIO_STREAM_STATE_UNINITIALIZED
+                        || mState == AAUDIO_STREAM_STATE_DISCONNECTED),
+                        "service stream still open, state = %d", mState);
+}
+
+std::string AAudioServiceStreamBase::dump() const {
+    std::stringstream result;
+
+    result << "      -------- handle = 0x" << std::hex << mHandle << std::dec << "\n";
+    result << "      state          = " << AAudio_convertStreamStateToText(mState) << "\n";
+    result << "      format         = " << mAudioFormat << "\n";
+    result << "      framesPerBurst = " << mFramesPerBurst << "\n";
+    result << "      channelCount   = " << mSamplesPerFrame << "\n";
+    result << "      capacityFrames = " << mCapacityInFrames << "\n";
+    result << "      owner uid      = " << mMmapClient.clientUid << "\n";
+
+    return result.str();
 }
 
 aaudio_result_t AAudioServiceStreamBase::open(const aaudio::AAudioStreamRequest &request,
                      aaudio::AAudioStreamConfiguration &configurationOutput) {
+
+    mMmapClient.clientUid = request.getUserId();
+    mMmapClient.clientPid = request.getProcessId();
+    mMmapClient.packageName.setTo(String16("")); // FIXME what should we do here?
+
     std::lock_guard<std::mutex> lock(mLockUpMessageQueue);
     if (mUpMessageQueue != nullptr) {
         return AAUDIO_ERROR_INVALID_STATE;
@@ -56,14 +84,20 @@
 }
 
 aaudio_result_t AAudioServiceStreamBase::close() {
-    std::lock_guard<std::mutex> lock(mLockUpMessageQueue);
-    delete mUpMessageQueue;
-    mUpMessageQueue = nullptr;
-
+    if (mState != AAUDIO_STREAM_STATE_CLOSED) {
+        stopTimestampThread();
+        std::lock_guard<std::mutex> lock(mLockUpMessageQueue);
+        delete mUpMessageQueue;
+        mUpMessageQueue = nullptr;
+        mState = AAUDIO_STREAM_STATE_CLOSED;
+    }
     return AAUDIO_OK;
 }
 
 aaudio_result_t AAudioServiceStreamBase::start() {
+    if (isRunning()) {
+        return AAUDIO_OK;
+    }
     sendServiceEvent(AAUDIO_SERVICE_EVENT_STARTED);
     mState = AAUDIO_STREAM_STATE_STARTED;
     mThreadEnabled.store(true);
@@ -71,12 +105,15 @@
 }
 
 aaudio_result_t AAudioServiceStreamBase::pause() {
-
+    aaudio_result_t result = AAUDIO_OK;
+    if (!isRunning()) {
+        return result;
+    }
     sendCurrentTimestamp();
     mThreadEnabled.store(false);
-    aaudio_result_t result = mAAudioThread.stop();
+    result = mAAudioThread.stop();
     if (result != AAUDIO_OK) {
-        processError();
+        disconnect();
         return result;
     }
     sendServiceEvent(AAUDIO_SERVICE_EVENT_PAUSED);
@@ -85,12 +122,15 @@
 }
 
 aaudio_result_t AAudioServiceStreamBase::stop() {
+    aaudio_result_t result = AAUDIO_OK;
+    if (!isRunning()) {
+        return result;
+    }
     // TODO wait for data to be played out
-    sendCurrentTimestamp();
-    mThreadEnabled.store(false);
-    aaudio_result_t result = mAAudioThread.stop();
+    sendCurrentTimestamp(); // warning - this calls a virtual function
+    result = stopTimestampThread();
     if (result != AAUDIO_OK) {
-        processError();
+        disconnect();
         return result;
     }
     sendServiceEvent(AAUDIO_SERVICE_EVENT_STOPPED);
@@ -98,6 +138,15 @@
     return result;
 }
 
+aaudio_result_t AAudioServiceStreamBase::stopTimestampThread() {
+    aaudio_result_t result = AAUDIO_OK;
+    // clear flag that tells thread to loop
+    if (mThreadEnabled.exchange(false)) {
+        result = mAAudioThread.stop();
+    }
+    return result;
+}
+
 aaudio_result_t AAudioServiceStreamBase::flush() {
     sendServiceEvent(AAUDIO_SERVICE_EVENT_FLUSHED);
     mState = AAUDIO_STREAM_STATE_FLUSHED;
@@ -120,14 +169,18 @@
             nextTime = timestampScheduler.nextAbsoluteTime();
         } else  {
             // Sleep until it is time to send the next timestamp.
+            // TODO Wait for a signal with a timeout so that we can stop more quickly.
             AudioClock::sleepUntilNanoTime(nextTime);
         }
     }
     ALOGD("AAudioServiceStreamBase::run() exiting ----------------");
 }
 
-void AAudioServiceStreamBase::processError() {
-    sendServiceEvent(AAUDIO_SERVICE_EVENT_DISCONNECTED);
+void AAudioServiceStreamBase::disconnect() {
+    if (mState != AAUDIO_STREAM_STATE_DISCONNECTED) {
+        sendServiceEvent(AAUDIO_SERVICE_EVENT_DISCONNECTED);
+        mState = AAUDIO_STREAM_STATE_DISCONNECTED;
+    }
 }
 
 aaudio_result_t AAudioServiceStreamBase::sendServiceEvent(aaudio_service_event_t event,
@@ -166,6 +219,8 @@
     //          (long long) command.timestamp.timestamp);
         command.what = AAudioServiceMessage::code::TIMESTAMP;
         result = writeUpMessageQueue(&command);
+    } else if (result == AAUDIO_ERROR_UNAVAILABLE) {
+        result = AAUDIO_OK; // just not available yet, try again later
     }
     return result;
 }
@@ -179,4 +234,4 @@
     mUpMessageQueue->fillParcelable(parcelable,
                                     parcelable.mUpMessageQueueParcelable);
     return getDownDataDescription(parcelable);
-}
\ No newline at end of file
+}
diff --git a/services/oboeservice/AAudioServiceStreamBase.h b/services/oboeservice/AAudioServiceStreamBase.h
index ee52c39..cebefec 100644
--- a/services/oboeservice/AAudioServiceStreamBase.h
+++ b/services/oboeservice/AAudioServiceStreamBase.h
@@ -20,11 +20,14 @@
 #include <assert.h>
 #include <mutex>
 
+#include <utils/RefBase.h>
+
 #include "fifo/FifoBuffer.h"
 #include "binding/IAAudioService.h"
 #include "binding/AudioEndpointParcelable.h"
 #include "binding/AAudioServiceMessage.h"
 #include "utility/AAudioUtilities.h"
+#include <media/AudioClient.h>
 
 #include "SharedRingBuffer.h"
 #include "AAudioThread.h"
@@ -39,7 +42,8 @@
  * Base class for a stream in the AAudio service.
  */
 class AAudioServiceStreamBase
-    : public Runnable  {
+    : public virtual android::RefBase
+    , public Runnable  {
 
 public:
     AAudioServiceStreamBase();
@@ -49,6 +53,8 @@
         ILLEGAL_THREAD_ID = 0
     };
 
+    std::string dump() const;
+
     // -------------------------------------------------------------------
     /**
      * Open the device.
@@ -73,11 +79,26 @@
      */
     virtual aaudio_result_t stop();
 
+    aaudio_result_t stopTimestampThread();
+
     /**
      *  Discard any data held by the underlying HAL or Service.
      */
     virtual aaudio_result_t flush();
 
+    virtual aaudio_result_t startClient(const android::AudioClient& client __unused,
+                                        audio_port_handle_t *clientHandle __unused) {
+        return AAUDIO_ERROR_UNAVAILABLE;
+    }
+
+    virtual aaudio_result_t stopClient(audio_port_handle_t clientHandle __unused) {
+        return AAUDIO_ERROR_UNAVAILABLE;
+    }
+
+    bool isRunning() const {
+        return mState == AAUDIO_STREAM_STATE_STARTED;
+    }
+
     // -------------------------------------------------------------------
 
     /**
@@ -111,33 +132,67 @@
 
     void run() override; // to implement Runnable
 
-    void processError();
+    void disconnect();
+
+    uid_t getOwnerUserId() const {
+        return mMmapClient.clientUid;
+    }
+
+    pid_t getOwnerProcessId() const {
+        return mMmapClient.clientPid;
+    }
+
+    aaudio_handle_t getHandle() const {
+        return mHandle;
+    }
+    void setHandle(aaudio_handle_t handle) {
+        mHandle = handle;
+    }
+
+    aaudio_stream_state_t getState() const {
+        return mState;
+    }
 
 protected:
+
+    void setState(aaudio_stream_state_t state) {
+        mState = state;
+    }
+
     aaudio_result_t writeUpMessageQueue(AAudioServiceMessage *command);
 
     aaudio_result_t sendCurrentTimestamp();
 
+    /**
+     * @param positionFrames
+     * @param timeNanos
+     * @return AAUDIO_OK or AAUDIO_ERROR_UNAVAILABLE or other negative error
+     */
     virtual aaudio_result_t getFreeRunningPosition(int64_t *positionFrames, int64_t *timeNanos) = 0;
 
     virtual aaudio_result_t getDownDataDescription(AudioEndpointParcelable &parcelable) = 0;
 
-    aaudio_stream_state_t               mState = AAUDIO_STREAM_STATE_UNINITIALIZED;
+    aaudio_stream_state_t   mState = AAUDIO_STREAM_STATE_UNINITIALIZED;
 
-    pid_t              mRegisteredClientThread = ILLEGAL_THREAD_ID;
+    pid_t                   mRegisteredClientThread = ILLEGAL_THREAD_ID;
 
-    SharedRingBuffer*  mUpMessageQueue;
-    std::mutex         mLockUpMessageQueue;
+    SharedRingBuffer*       mUpMessageQueue;
+    std::mutex              mLockUpMessageQueue;
 
-    AAudioThread        mAAudioThread;
+    AAudioThread            mAAudioThread;
     // This is used by one thread to tell another thread to exit. So it must be atomic.
-    std::atomic<bool>   mThreadEnabled;
+    std::atomic<bool>       mThreadEnabled;
 
-    aaudio_format_t    mAudioFormat = AAUDIO_FORMAT_UNSPECIFIED;
-    int32_t            mFramesPerBurst = 0;
-    int32_t            mSamplesPerFrame = AAUDIO_UNSPECIFIED;
-    int32_t            mSampleRate = AAUDIO_UNSPECIFIED;
-    int32_t            mCapacityInFrames = AAUDIO_UNSPECIFIED;
+    aaudio_format_t         mAudioFormat = AAUDIO_FORMAT_UNSPECIFIED;
+    int32_t                 mFramesPerBurst = 0;
+    int32_t                 mSamplesPerFrame = AAUDIO_UNSPECIFIED;
+    int32_t                 mSampleRate = AAUDIO_UNSPECIFIED;
+    int32_t                 mCapacityInFrames = AAUDIO_UNSPECIFIED;
+    android::AudioClient    mMmapClient;
+    audio_port_handle_t     mClientHandle = AUDIO_PORT_HANDLE_NONE;
+
+private:
+    aaudio_handle_t         mHandle = -1;
 };
 
 } /* namespace aaudio */
diff --git a/services/oboeservice/AAudioServiceStreamExclusive.h b/services/oboeservice/AAudioServiceStreamExclusive.h
deleted file mode 100644
index db382a3..0000000
--- a/services/oboeservice/AAudioServiceStreamExclusive.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef AAUDIO_AAUDIO_SERVICE_STREAM_EXCLUSIVE_H
-#define AAUDIO_AAUDIO_SERVICE_STREAM_EXCLUSIVE_H
-
-#include "AAudioServiceStreamMMAP.h"
-
-namespace aaudio {
-
-/**
- * Exclusive mode stream in the AAudio service.
- *
- * This is currently a stub.
- * We may move code from AAudioServiceStreamMMAP into this class.
- * If not, then it will be removed.
- */
-class AAudioServiceStreamExclusive : public AAudioServiceStreamMMAP {
-
-public:
-    AAudioServiceStreamExclusive() {};
-    virtual ~AAudioServiceStreamExclusive() = default;
-};
-
-} /* namespace aaudio */
-
-#endif //AAUDIO_AAUDIO_SERVICE_STREAM_EXCLUSIVE_H
diff --git a/services/oboeservice/AAudioServiceStreamMMAP.cpp b/services/oboeservice/AAudioServiceStreamMMAP.cpp
index 97b9937..08dd680 100644
--- a/services/oboeservice/AAudioServiceStreamMMAP.cpp
+++ b/services/oboeservice/AAudioServiceStreamMMAP.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "AAudioService"
+#define LOG_TAG "AAudioServiceStreamMMAP"
 //#define LOG_NDEBUG 0
 #include <utils/Log.h>
 
@@ -31,6 +31,7 @@
 #include "SharedMemoryProxy.h"
 #include "utility/AAudioUtilities.h"
 
+using android::base::unique_fd;
 using namespace android;
 using namespace aaudio;
 
@@ -38,30 +39,30 @@
 #define AAUDIO_SAMPLE_RATE_DEFAULT    48000
 
 /**
- * Stream that uses an MMAP buffer.
+ * Service Stream that uses an MMAP buffer.
  */
 
-AAudioServiceStreamMMAP::AAudioServiceStreamMMAP()
+AAudioServiceStreamMMAP::AAudioServiceStreamMMAP(const android::AudioClient& serviceClient,
+                                                 bool inService)
         : AAudioServiceStreamBase()
         , mMmapStreamCallback(new MyMmapStreamCallback(*this))
         , mPreviousFrameCounter(0)
-        , mMmapStream(nullptr) {
-}
-
-AAudioServiceStreamMMAP::~AAudioServiceStreamMMAP() {
-    close();
+        , mMmapStream(nullptr)
+        , mServiceClient(serviceClient)
+        , mInService(inService) {
 }
 
 aaudio_result_t AAudioServiceStreamMMAP::close() {
-    mMmapStream.clear(); // TODO review. Is that all we have to do?
-    // Apparently the above close is asynchronous. An attempt to open a new device
-    // right after a close can fail. Also some callbacks may still be in flight!
-    // FIXME Make closing synchronous.
-    AudioClock::sleepForNanos(100 * AAUDIO_NANOS_PER_MILLISECOND);
-
-    if (mAudioDataFileDescriptor != -1) {
-        ::close(mAudioDataFileDescriptor);
-        mAudioDataFileDescriptor = -1;
+    if (mState == AAUDIO_STREAM_STATE_CLOSED) {
+        return AAUDIO_OK;
+    }
+    stop();
+    if (mMmapStream != 0) {
+        mMmapStream.clear(); // TODO review. Is that all we have to do?
+        // Apparently the above close is asynchronous. An attempt to open a new device
+        // right after a close can fail. Also some callbacks may still be in flight!
+        // FIXME Make closing synchronous.
+        AudioClock::sleepForNanos(100 * AAUDIO_NANOS_PER_MILLISECOND);
     }
 
     return AAudioServiceStreamBase::close();
@@ -87,13 +88,10 @@
 
     const AAudioStreamConfiguration &configurationInput = request.getConstantConfiguration();
     audio_port_handle_t deviceId = configurationInput.getDeviceId();
-
-    mMmapClient.clientUid = request.getUserId();
-    mMmapClient.clientPid = request.getProcessId();
     aaudio_direction_t direction = request.getDirection();
 
     // Fill in config
-    aaudio_format_t aaudioFormat = configurationInput.getAudioFormat();
+    aaudio_format_t aaudioFormat = configurationInput.getFormat();
     if (aaudioFormat == AAUDIO_UNSPECIFIED || aaudioFormat == AAUDIO_FORMAT_PCM_FLOAT) {
         aaudioFormat = AAUDIO_FORMAT_PCM_I16;
     }
@@ -120,8 +118,6 @@
         return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
     }
 
-    mMmapClient.packageName.setTo(String16("aaudio_service")); // FIXME what should we do here?
-
     MmapStreamInterface::stream_direction_t streamDirection = (direction == AAUDIO_DIRECTION_OUTPUT)
         ? MmapStreamInterface::DIRECTION_OUTPUT : MmapStreamInterface::DIRECTION_INPUT;
 
@@ -132,27 +128,51 @@
                                                           mMmapClient,
                                                           &deviceId,
                                                           mMmapStreamCallback,
-                                                          mMmapStream);
+                                                          mMmapStream,
+                                                          &mPortHandle);
     if (status != OK) {
         ALOGE("openMmapStream returned status %d", status);
         return AAUDIO_ERROR_UNAVAILABLE;
     }
 
+    if (deviceId == AAUDIO_UNSPECIFIED) {
+        ALOGW("AAudioServiceStreamMMAP::open() - openMmapStream() failed to set deviceId");
+    }
+
     // Create MMAP/NOIRQ buffer.
     int32_t minSizeFrames = configurationInput.getBufferCapacity();
-    if (minSizeFrames == 0) { // zero will get rejected
+    if (minSizeFrames <= 0) { // zero will get rejected
         minSizeFrames = AAUDIO_BUFFER_CAPACITY_MIN;
     }
     status = mMmapStream->createMmapBuffer(minSizeFrames, &mMmapBufferinfo);
     if (status != OK) {
-        ALOGE("%s: createMmapBuffer() returned status %d, return AAUDIO_ERROR_UNAVAILABLE",
-              __FILE__, status);
+        ALOGE("AAudioServiceStreamMMAP::open() - createMmapBuffer() returned status %d",
+              status);
         return AAUDIO_ERROR_UNAVAILABLE;
     } else {
-        ALOGD("createMmapBuffer status %d shared_address = %p buffer_size %d burst_size %d",
-              status, mMmapBufferinfo.shared_memory_address,
-              mMmapBufferinfo.buffer_size_frames,
-              mMmapBufferinfo.burst_size_frames);
+        ALOGD("createMmapBuffer status = %d, buffer_size = %d, burst_size %d"
+                ", Sharable FD: %s",
+              status,
+              abs(mMmapBufferinfo.buffer_size_frames),
+              mMmapBufferinfo.burst_size_frames,
+              mMmapBufferinfo.buffer_size_frames < 0 ? "Yes" : "No");
+    }
+
+    mCapacityInFrames = mMmapBufferinfo.buffer_size_frames;
+    // FIXME: the audio HAL indicates if the shared memory fd can be shared outside of audioserver
+    // by returning a negative buffer size
+    if (mCapacityInFrames < 0) {
+        // Exclusive mode is possible from any client
+        mCapacityInFrames = -mCapacityInFrames;
+    } else {
+        // exclusive mode is only possible if the final fd destination is inside audioserver
+        if ((mMmapClient.clientUid != mServiceClient.clientUid) &&
+                configurationInput.getSharingMode() == AAUDIO_SHARING_MODE_EXCLUSIVE) {
+            // Fallback is handled by caller but indicate what is possible in case
+            // this is used in the future
+            configurationOutput.setSharingMode(AAUDIO_SHARING_MODE_SHARED);
+            return AAUDIO_ERROR_UNAVAILABLE;
+        }
     }
 
     // Get information about the stream and pass it back to the caller.
@@ -160,9 +180,14 @@
                            ? audio_channel_count_from_out_mask(config.channel_mask)
                            : audio_channel_count_from_in_mask(config.channel_mask);
 
-    mAudioDataFileDescriptor = mMmapBufferinfo.shared_memory_fd;
+    // AAudio creates a copy of this FD and retains ownership of the copy.
+    // Assume that AudioFlinger will close the original shared_memory_fd.
+    mAudioDataFileDescriptor.reset(dup(mMmapBufferinfo.shared_memory_fd));
+    if (mAudioDataFileDescriptor.get() == -1) {
+        ALOGE("AAudioServiceStreamMMAP::open() - could not dup shared_memory_fd");
+        return AAUDIO_ERROR_INTERNAL; // TODO review
+    }
     mFramesPerBurst = mMmapBufferinfo.burst_size_frames;
-    mCapacityInFrames = mMmapBufferinfo.buffer_size_frames;
     mAudioFormat = AAudioConvert_androidToAAudioDataFormat(config.format);
     mSampleRate = config.sample_rate;
 
@@ -181,12 +206,16 @@
     ALOGD("AAudioServiceStreamMMAP::open() original burst = %d, minMicros = %d, final burst = %d\n",
           mMmapBufferinfo.burst_size_frames, burstMinMicros, mFramesPerBurst);
 
+    ALOGD("AAudioServiceStreamMMAP::open() actual rate = %d, channels = %d, deviceId = %d\n",
+          mSampleRate, mSamplesPerFrame, deviceId);
+
     // Fill in AAudioStreamConfiguration
     configurationOutput.setSampleRate(mSampleRate);
     configurationOutput.setSamplesPerFrame(mSamplesPerFrame);
-    configurationOutput.setAudioFormat(mAudioFormat);
+    configurationOutput.setFormat(mAudioFormat);
     configurationOutput.setDeviceId(deviceId);
 
+    setState(AAUDIO_STREAM_STATE_OPEN);
     return AAUDIO_OK;
 }
 
@@ -194,15 +223,21 @@
  * Start the flow of data.
  */
 aaudio_result_t AAudioServiceStreamMMAP::start() {
+    if (isRunning()) {
+        return AAUDIO_OK;
+    }
     if (mMmapStream == nullptr) return AAUDIO_ERROR_NULL;
     aaudio_result_t result;
-    status_t status = mMmapStream->start(mMmapClient, &mPortHandle);
+    status_t status = mMmapStream->start(mServiceClient, &mPortHandle);
     if (status != OK) {
         ALOGE("AAudioServiceStreamMMAP::start() mMmapStream->start() returned %d", status);
-        processError();
+        disconnect();
         result = AAudioConvert_androidToAAudioResult(status);
     } else {
         result = AAudioServiceStreamBase::start();
+        if (!mInService && result == AAUDIO_OK) {
+            startClient(mMmapClient, &mClientHandle);
+        }
     }
     return result;
 }
@@ -211,18 +246,28 @@
  * Stop the flow of data such that start() can resume with loss of data.
  */
 aaudio_result_t AAudioServiceStreamMMAP::pause() {
+    if (!isRunning()) {
+        return AAUDIO_OK;
+    }
     if (mMmapStream == nullptr) return AAUDIO_ERROR_NULL;
-
     aaudio_result_t result1 = AAudioServiceStreamBase::pause();
+    if (!mInService) {
+        stopClient(mClientHandle);
+    }
     status_t status = mMmapStream->stop(mPortHandle);
     mFramesRead.reset32();
     return (result1 != AAUDIO_OK) ? result1 : AAudioConvert_androidToAAudioResult(status);
 }
 
 aaudio_result_t AAudioServiceStreamMMAP::stop() {
+    if (!isRunning()) {
+        return AAUDIO_OK;
+    }
     if (mMmapStream == nullptr) return AAUDIO_ERROR_NULL;
-
     aaudio_result_t result1 = AAudioServiceStreamBase::stop();
+    if (!mInService) {
+        stopClient(mClientHandle);
+    }
     aaudio_result_t status = mMmapStream->stop(mPortHandle);
     mFramesRead.reset32();
     return (result1 != AAUDIO_OK) ? result1 :  AAudioConvert_androidToAAudioResult(status);
@@ -234,34 +279,43 @@
 aaudio_result_t AAudioServiceStreamMMAP::flush() {
     if (mMmapStream == nullptr) return AAUDIO_ERROR_NULL;
     // TODO how do we flush an MMAP/NOIRQ buffer? sync pointers?
-    sendServiceEvent(AAUDIO_SERVICE_EVENT_FLUSHED);
-    mState = AAUDIO_STREAM_STATE_FLUSHED;
     return AAudioServiceStreamBase::flush();;
 }
 
+aaudio_result_t AAudioServiceStreamMMAP::startClient(const android::AudioClient& client,
+                                                     audio_port_handle_t *clientHandle) {
+    return AAudioConvert_androidToAAudioResult(mMmapStream->start(client, clientHandle));
+}
+
+aaudio_result_t AAudioServiceStreamMMAP::stopClient(audio_port_handle_t clientHandle) {
+    return AAudioConvert_androidToAAudioResult(mMmapStream->stop(clientHandle));
+}
 
 aaudio_result_t AAudioServiceStreamMMAP::getFreeRunningPosition(int64_t *positionFrames,
                                                                 int64_t *timeNanos) {
     struct audio_mmap_position position;
     if (mMmapStream == nullptr) {
-        processError();
+        disconnect();
         return AAUDIO_ERROR_NULL;
     }
     status_t status = mMmapStream->getMmapPosition(&position);
-    if (status != OK) {
-        ALOGE("sendCurrentTimestamp(): getMmapPosition() returned %d", status);
-        processError();
-        return AAudioConvert_androidToAAudioResult(status);
+    aaudio_result_t result = AAudioConvert_androidToAAudioResult(status);
+    if (result == AAUDIO_ERROR_UNAVAILABLE) {
+        ALOGW("sendCurrentTimestamp(): getMmapPosition() has no position data yet");
+    } else if (result != AAUDIO_OK) {
+        ALOGE("sendCurrentTimestamp(): getMmapPosition() returned status %d", status);
+        disconnect();
     } else {
         mFramesRead.update32(position.position_frames);
         *positionFrames = mFramesRead.get();
         *timeNanos = position.time_nanoseconds;
     }
-    return AAUDIO_OK;
+    return result;
 }
 
 void AAudioServiceStreamMMAP::onTearDown() {
-    ALOGE("AAudioServiceStreamMMAP::onTearDown() called - TODO");
+    ALOGD("AAudioServiceStreamMMAP::onTearDown() called");
+    disconnect();
 };
 
 void AAudioServiceStreamMMAP::onVolumeChanged(audio_channel_mask_t channels,
@@ -274,11 +328,11 @@
 
 void AAudioServiceStreamMMAP::onRoutingChanged(audio_port_handle_t deviceId) {
     ALOGD("AAudioServiceStreamMMAP::onRoutingChanged() called with %d, old = %d",
-          deviceId, mPortHandle);
-    if (mPortHandle > 0 && mPortHandle != deviceId) {
-        sendServiceEvent(AAUDIO_SERVICE_EVENT_DISCONNECTED);
+          deviceId, mDeviceId);
+    if (mDeviceId != AUDIO_PORT_HANDLE_NONE  && mDeviceId != deviceId) {
+        disconnect();
     }
-    mPortHandle = deviceId;
+    mDeviceId = deviceId;
 };
 
 /**
@@ -295,4 +349,4 @@
     parcelable.mDownDataQueueParcelable.setFramesPerBurst(mFramesPerBurst);
     parcelable.mDownDataQueueParcelable.setCapacityInFrames(mCapacityInFrames);
     return AAUDIO_OK;
-}
\ No newline at end of file
+}
diff --git a/services/oboeservice/AAudioServiceStreamMMAP.h b/services/oboeservice/AAudioServiceStreamMMAP.h
index fe75a10..b69dc46 100644
--- a/services/oboeservice/AAudioServiceStreamMMAP.h
+++ b/services/oboeservice/AAudioServiceStreamMMAP.h
@@ -19,6 +19,7 @@
 
 #include <atomic>
 
+#include <android-base/unique_fd.h>
 #include <media/audiohal/StreamHalInterface.h>
 #include <media/MmapStreamCallback.h>
 #include <media/MmapStreamInterface.h>
@@ -33,6 +34,7 @@
 #include "TimestampScheduler.h"
 #include "utility/MonotonicCounter.h"
 
+
 namespace aaudio {
 
     /**
@@ -43,9 +45,8 @@
     , public android::MmapStreamCallback {
 
 public:
-    AAudioServiceStreamMMAP();
-    virtual ~AAudioServiceStreamMMAP();
-
+    AAudioServiceStreamMMAP(const android::AudioClient& serviceClient, bool inService);
+    virtual ~AAudioServiceStreamMMAP() = default;
 
     aaudio_result_t open(const aaudio::AAudioStreamRequest &request,
                                  aaudio::AAudioStreamConfiguration &configurationOutput) override;
@@ -78,6 +79,11 @@
 
     aaudio_result_t close() override;
 
+    virtual aaudio_result_t startClient(const android::AudioClient& client,
+                                        audio_port_handle_t *clientHandle);
+
+    virtual aaudio_result_t stopClient(audio_port_handle_t clientHandle);
+
     /**
      * Send a MMAP/NOIRQ buffer timestamp to the client.
      */
@@ -127,13 +133,15 @@
     MonotonicCounter                    mFramesWritten;
     MonotonicCounter                    mFramesRead;
     int32_t                             mPreviousFrameCounter = 0;   // from HAL
-    int                                 mAudioDataFileDescriptor = -1;
 
     // Interface to the AudioFlinger MMAP support.
     android::sp<android::MmapStreamInterface> mMmapStream;
     struct audio_mmap_buffer_info             mMmapBufferinfo;
-    android::MmapStreamInterface::Client      mMmapClient;
-    audio_port_handle_t                       mPortHandle = -1; // TODO review best default
+    audio_port_handle_t                       mPortHandle = AUDIO_PORT_HANDLE_NONE;
+    audio_port_handle_t                       mDeviceId = AUDIO_PORT_HANDLE_NONE;
+    android::AudioClient                      mServiceClient;
+    bool                                      mInService = false;
+    android::base::unique_fd                  mAudioDataFileDescriptor;
 };
 
 } // namespace aaudio
diff --git a/services/oboeservice/AAudioServiceStreamShared.cpp b/services/oboeservice/AAudioServiceStreamShared.cpp
index 494b18e..5654113 100644
--- a/services/oboeservice/AAudioServiceStreamShared.cpp
+++ b/services/oboeservice/AAudioServiceStreamShared.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "AAudioService"
+#define LOG_TAG "AAudioServiceStreamShared"
 //#define LOG_NDEBUG 0
 #include <utils/Log.h>
 
@@ -34,93 +34,155 @@
 using namespace android;
 using namespace aaudio;
 
-#define MIN_BURSTS_PER_BUFFER   2
-#define MAX_BURSTS_PER_BUFFER   32
+#define MIN_BURSTS_PER_BUFFER       2
+#define DEFAULT_BURSTS_PER_BUFFER   16
+// This is an arbitrary range. TODO review.
+#define MAX_FRAMES_PER_BUFFER       (32 * 1024)
 
 AAudioServiceStreamShared::AAudioServiceStreamShared(AAudioService &audioService)
     : mAudioService(audioService)
     {
 }
 
-AAudioServiceStreamShared::~AAudioServiceStreamShared() {
-    close();
+int32_t AAudioServiceStreamShared::calculateBufferCapacity(int32_t requestedCapacityFrames,
+                                                           int32_t framesPerBurst) {
+
+    if (requestedCapacityFrames > MAX_FRAMES_PER_BUFFER) {
+        ALOGE("AAudioServiceStreamShared::calculateBufferCapacity() requested capacity %d > max %d",
+              requestedCapacityFrames, MAX_FRAMES_PER_BUFFER);
+        return AAUDIO_ERROR_OUT_OF_RANGE;
+    }
+
+    // Determine how many bursts will fit in the buffer.
+    int32_t numBursts;
+    if (requestedCapacityFrames == AAUDIO_UNSPECIFIED) {
+        // Use fewer bursts if default is too many.
+        if ((DEFAULT_BURSTS_PER_BUFFER * framesPerBurst) > MAX_FRAMES_PER_BUFFER) {
+            numBursts = MAX_FRAMES_PER_BUFFER / framesPerBurst;
+        } else {
+            numBursts = DEFAULT_BURSTS_PER_BUFFER;
+        }
+    } else {
+        // round up to nearest burst boundary
+        numBursts = (requestedCapacityFrames + framesPerBurst - 1) / framesPerBurst;
+    }
+
+    // Clip to bare minimum.
+    if (numBursts < MIN_BURSTS_PER_BUFFER) {
+        numBursts = MIN_BURSTS_PER_BUFFER;
+    }
+    // Check for numeric overflow.
+    if (numBursts > 0x8000 || framesPerBurst > 0x8000) {
+        ALOGE("AAudioServiceStreamShared::calculateBufferCapacity() overflow, capacity = %d * %d",
+              numBursts, framesPerBurst);
+        return AAUDIO_ERROR_OUT_OF_RANGE;
+    }
+    int32_t capacityInFrames = numBursts * framesPerBurst;
+
+    // Final sanity check.
+    if (capacityInFrames > MAX_FRAMES_PER_BUFFER) {
+        ALOGE("AAudioServiceStreamShared::calculateBufferCapacity() calc capacity %d > max %d",
+              capacityInFrames, MAX_FRAMES_PER_BUFFER);
+        return AAUDIO_ERROR_OUT_OF_RANGE;
+    }
+    ALOGD("AAudioServiceStreamShared::calculateBufferCapacity() requested %d frames, actual = %d",
+          requestedCapacityFrames, capacityInFrames);
+    return capacityInFrames;
 }
 
 aaudio_result_t AAudioServiceStreamShared::open(const aaudio::AAudioStreamRequest &request,
                      aaudio::AAudioStreamConfiguration &configurationOutput)  {
 
+    sp<AAudioServiceStreamShared> keep(this);
+
     aaudio_result_t result = AAudioServiceStreamBase::open(request, configurationOutput);
     if (result != AAUDIO_OK) {
-        ALOGE("AAudioServiceStreamBase open returned %d", result);
+        ALOGE("AAudioServiceStreamBase open() returned %d", result);
         return result;
     }
 
     const AAudioStreamConfiguration &configurationInput = request.getConstantConfiguration();
-    int32_t deviceId = configurationInput.getDeviceId();
     aaudio_direction_t direction = request.getDirection();
 
     AAudioEndpointManager &mEndpointManager = AAudioEndpointManager::getInstance();
-    mServiceEndpoint = mEndpointManager.openEndpoint(mAudioService, deviceId, direction);
+    mServiceEndpoint = mEndpointManager.openEndpoint(mAudioService, configurationOutput, direction);
     if (mServiceEndpoint == nullptr) {
-        ALOGE("AAudioServiceStreamShared::open(), mServiceEndPoint = %p", mServiceEndpoint);
+        ALOGE("AAudioServiceStreamShared::open() mServiceEndPoint = %p", mServiceEndpoint);
         return AAUDIO_ERROR_UNAVAILABLE;
     }
 
     // Is the request compatible with the shared endpoint?
-    mAudioFormat = configurationInput.getAudioFormat();
+    mAudioFormat = configurationInput.getFormat();
     if (mAudioFormat == AAUDIO_FORMAT_UNSPECIFIED) {
         mAudioFormat = AAUDIO_FORMAT_PCM_FLOAT;
     } else if (mAudioFormat != AAUDIO_FORMAT_PCM_FLOAT) {
-        ALOGE("AAudioServiceStreamShared::open(), mAudioFormat = %d, need FLOAT", mAudioFormat);
-        return AAUDIO_ERROR_INVALID_FORMAT;
+        ALOGE("AAudioServiceStreamShared::open() mAudioFormat = %d, need FLOAT", mAudioFormat);
+        result = AAUDIO_ERROR_INVALID_FORMAT;
+        goto error;
     }
 
     mSampleRate = configurationInput.getSampleRate();
     if (mSampleRate == AAUDIO_UNSPECIFIED) {
         mSampleRate = mServiceEndpoint->getSampleRate();
     } else if (mSampleRate != mServiceEndpoint->getSampleRate()) {
-        ALOGE("AAudioServiceStreamShared::open(), mAudioFormat = %d, need %d",
+        ALOGE("AAudioServiceStreamShared::open() mSampleRate = %d, need %d",
               mSampleRate, mServiceEndpoint->getSampleRate());
-        return AAUDIO_ERROR_INVALID_RATE;
+        result = AAUDIO_ERROR_INVALID_RATE;
+        goto error;
     }
 
     mSamplesPerFrame = configurationInput.getSamplesPerFrame();
     if (mSamplesPerFrame == AAUDIO_UNSPECIFIED) {
         mSamplesPerFrame = mServiceEndpoint->getSamplesPerFrame();
     } else if (mSamplesPerFrame != mServiceEndpoint->getSamplesPerFrame()) {
-        ALOGE("AAudioServiceStreamShared::open(), mSamplesPerFrame = %d, need %d",
+        ALOGE("AAudioServiceStreamShared::open() mSamplesPerFrame = %d, need %d",
               mSamplesPerFrame, mServiceEndpoint->getSamplesPerFrame());
-        return AAUDIO_ERROR_OUT_OF_RANGE;
+        result = AAUDIO_ERROR_OUT_OF_RANGE;
+        goto error;
     }
 
-    // Determine this stream's shared memory buffer capacity.
     mFramesPerBurst = mServiceEndpoint->getFramesPerBurst();
-    int32_t minCapacityFrames = configurationInput.getBufferCapacity();
-    int32_t numBursts = MAX_BURSTS_PER_BUFFER;
-    if (minCapacityFrames != AAUDIO_UNSPECIFIED) {
-        numBursts = (minCapacityFrames + mFramesPerBurst - 1) / mFramesPerBurst;
-        if (numBursts < MIN_BURSTS_PER_BUFFER) {
-            numBursts = MIN_BURSTS_PER_BUFFER;
-        } else if (numBursts > MAX_BURSTS_PER_BUFFER) {
-            numBursts = MAX_BURSTS_PER_BUFFER;
-        }
+    ALOGD("AAudioServiceStreamShared::open() mSampleRate = %d, mFramesPerBurst = %d",
+          mSampleRate, mFramesPerBurst);
+
+    mCapacityInFrames = calculateBufferCapacity(configurationInput.getBufferCapacity(),
+                                     mFramesPerBurst);
+    if (mCapacityInFrames < 0) {
+        result = mCapacityInFrames; // negative error code
+        mCapacityInFrames = 0;
+        goto error;
     }
-    mCapacityInFrames = numBursts * mFramesPerBurst;
-    ALOGD("AAudioServiceStreamShared::open(), mCapacityInFrames = %d", mCapacityInFrames);
 
     // Create audio data shared memory buffer for client.
     mAudioDataQueue = new SharedRingBuffer();
-    mAudioDataQueue->allocate(calculateBytesPerFrame(), mCapacityInFrames);
+    result = mAudioDataQueue->allocate(calculateBytesPerFrame(), mCapacityInFrames);
+    if (result != AAUDIO_OK) {
+        ALOGE("AAudioServiceStreamShared::open() could not allocate FIFO with %d frames",
+              mCapacityInFrames);
+        result = AAUDIO_ERROR_NO_MEMORY;
+        goto error;
+    }
+
+    ALOGD("AAudioServiceStreamShared::open() actual rate = %d, channels = %d, deviceId = %d",
+          mSampleRate, mSamplesPerFrame, mServiceEndpoint->getDeviceId());
 
     // Fill in configuration for client.
     configurationOutput.setSampleRate(mSampleRate);
     configurationOutput.setSamplesPerFrame(mSamplesPerFrame);
-    configurationOutput.setAudioFormat(mAudioFormat);
-    configurationOutput.setDeviceId(deviceId);
+    configurationOutput.setFormat(mAudioFormat);
+    configurationOutput.setDeviceId(mServiceEndpoint->getDeviceId());
 
-    mServiceEndpoint->registerStream(this);
+    result = mServiceEndpoint->registerStream(keep);
+    if (result != AAUDIO_OK) {
+        goto error;
+    }
 
+    setState(AAUDIO_STREAM_STATE_OPEN);
     return AAUDIO_OK;
+
+error:
+    close();
+    return result;
 }
 
 /**
@@ -129,6 +191,9 @@
  * An AAUDIO_SERVICE_EVENT_STARTED will be sent to the client when complete.
  */
 aaudio_result_t AAudioServiceStreamShared::start()  {
+    if (isRunning()) {
+        return AAUDIO_OK;
+    }
     AAudioServiceEndpoint *endpoint = mServiceEndpoint;
     if (endpoint == nullptr) {
         return AAUDIO_ERROR_INVALID_STATE;
@@ -137,11 +202,14 @@
     aaudio_result_t result = endpoint->startStream(this);
     if (result != AAUDIO_OK) {
         ALOGE("AAudioServiceStreamShared::start() mServiceEndpoint returned %d", result);
-        processError();
+        disconnect();
     } else {
-        result = AAudioServiceStreamBase::start();
+        result = endpoint->getStreamInternal()->startClient(mMmapClient, &mClientHandle);
+        if (result == AAUDIO_OK) {
+            result = AAudioServiceStreamBase::start();
+        }
     }
-    return AAUDIO_OK;
+    return result;
 }
 
 /**
@@ -150,29 +218,35 @@
  * An AAUDIO_SERVICE_EVENT_PAUSED will be sent to the client when complete.
 */
 aaudio_result_t AAudioServiceStreamShared::pause()  {
+    if (!isRunning()) {
+        return AAUDIO_OK;
+    }
     AAudioServiceEndpoint *endpoint = mServiceEndpoint;
     if (endpoint == nullptr) {
         return AAUDIO_ERROR_INVALID_STATE;
     }
-    // Add this stream to the mixer.
+    endpoint->getStreamInternal()->stopClient(mClientHandle);
     aaudio_result_t result = endpoint->stopStream(this);
     if (result != AAUDIO_OK) {
         ALOGE("AAudioServiceStreamShared::pause() mServiceEndpoint returned %d", result);
-        processError();
+        disconnect(); // TODO should we return or pause Base first?
     }
     return AAudioServiceStreamBase::pause();
 }
 
 aaudio_result_t AAudioServiceStreamShared::stop()  {
+    if (!isRunning()) {
+        return AAUDIO_OK;
+    }
     AAudioServiceEndpoint *endpoint = mServiceEndpoint;
     if (endpoint == nullptr) {
         return AAUDIO_ERROR_INVALID_STATE;
     }
-    // Add this stream to the mixer.
+    endpoint->getStreamInternal()->stopClient(mClientHandle);
     aaudio_result_t result = endpoint->stopStream(this);
     if (result != AAUDIO_OK) {
         ALOGE("AAudioServiceStreamShared::stop() mServiceEndpoint returned %d", result);
-        processError();
+        disconnect();
     }
     return AAudioServiceStreamBase::stop();
 }
@@ -183,22 +257,37 @@
  * An AAUDIO_SERVICE_EVENT_FLUSHED will be sent to the client when complete.
  */
 aaudio_result_t AAudioServiceStreamShared::flush()  {
-    // TODO make sure we are paused
-    // TODO actually flush the data
-    return AAudioServiceStreamBase::flush() ;
+    AAudioServiceEndpoint *endpoint = mServiceEndpoint;
+    if (endpoint == nullptr) {
+        return AAUDIO_ERROR_INVALID_STATE;
+    }
+    if (mState != AAUDIO_STREAM_STATE_PAUSED) {
+         ALOGE("AAudioServiceStreamShared::flush() stream not paused, state = %s",
+            AAudio_convertStreamStateToText(mState));
+        return AAUDIO_ERROR_INVALID_STATE;
+    }
+    // Data will get flushed when the client receives the FLUSHED event.
+    return AAudioServiceStreamBase::flush();
 }
 
 aaudio_result_t AAudioServiceStreamShared::close()  {
-    pause();
-    // TODO wait for pause() to synchronize
-    AAudioServiceEndpoint *endpoint = mServiceEndpoint;
-    if (endpoint != nullptr) {
-        endpoint->unregisterStream(this);
-
-        AAudioEndpointManager &mEndpointManager = AAudioEndpointManager::getInstance();
-        mEndpointManager.closeEndpoint(endpoint);
-        mServiceEndpoint = nullptr;
+    if (mState == AAUDIO_STREAM_STATE_CLOSED) {
+        return AAUDIO_OK;
     }
+
+    stop();
+
+    AAudioServiceEndpoint *endpoint = mServiceEndpoint;
+    if (endpoint == nullptr) {
+        return AAUDIO_ERROR_INVALID_STATE;
+    }
+
+    endpoint->unregisterStream(this);
+
+    AAudioEndpointManager &mEndpointManager = AAudioEndpointManager::getInstance();
+    mEndpointManager.closeEndpoint(endpoint);
+    mServiceEndpoint = nullptr;
+
     if (mAudioDataQueue != nullptr) {
         delete mAudioDataQueue;
         mAudioDataQueue = nullptr;
@@ -218,14 +307,6 @@
     return AAUDIO_OK;
 }
 
-void AAudioServiceStreamShared::onStop() {
-}
-
-void AAudioServiceStreamShared::onDisconnect() {
-    mServiceEndpoint->close();
-    mServiceEndpoint = nullptr;
-}
-
 void AAudioServiceStreamShared::markTransferTime(int64_t nanoseconds) {
     mMarkedPosition = mAudioDataQueue->getFifoBuffer()->getReadCounter();
     mMarkedTime = nanoseconds;
diff --git a/services/oboeservice/AAudioServiceStreamShared.h b/services/oboeservice/AAudioServiceStreamShared.h
index dfdbbb3..6b67337 100644
--- a/services/oboeservice/AAudioServiceStreamShared.h
+++ b/services/oboeservice/AAudioServiceStreamShared.h
@@ -44,7 +44,7 @@
 
 public:
     AAudioServiceStreamShared(android::AAudioService &aAudioService);
-    virtual ~AAudioServiceStreamShared();
+    virtual ~AAudioServiceStreamShared() = default;
 
     aaudio_result_t open(const aaudio::AAudioStreamRequest &request,
                          aaudio::AAudioStreamConfiguration &configurationOutput) override;
@@ -87,16 +87,20 @@
      */
     void markTransferTime(int64_t nanoseconds);
 
-    void onStop();
-
-    void onDisconnect();
-
 protected:
 
     aaudio_result_t getDownDataDescription(AudioEndpointParcelable &parcelable) override;
 
     aaudio_result_t getFreeRunningPosition(int64_t *positionFrames, int64_t *timeNanos) override;
 
+    /**
+     * @param requestedCapacityFrames
+     * @param framesPerBurst
+     * @return capacity or negative error
+     */
+    static int32_t calculateBufferCapacity(int32_t requestedCapacityFrames,
+                                            int32_t framesPerBurst);
+
 private:
     android::AAudioService  &mAudioService;
     AAudioServiceEndpoint   *mServiceEndpoint = nullptr;
diff --git a/services/oboeservice/Android.mk b/services/oboeservice/Android.mk
index b447725..a896a7a 100644
--- a/services/oboeservice/Android.mk
+++ b/services/oboeservice/Android.mk
@@ -25,6 +25,7 @@
     $(LIBAAUDIO_SRC_DIR)/utility/HandleTracker.cpp \
     SharedMemoryProxy.cpp \
     SharedRingBuffer.cpp \
+    AAudioClientTracker.cpp \
     AAudioEndpointManager.cpp \
     AAudioMixer.cpp \
     AAudioService.cpp \
@@ -46,9 +47,11 @@
 LOCAL_SHARED_LIBRARIES :=  \
     libaaudio \
     libaudioflinger \
+    libaudioclient \
     libbinder \
     libcutils \
     libmediautils \
+    libserviceutility \
     libutils \
     liblog
 
diff --git a/services/oboeservice/SharedRingBuffer.cpp b/services/oboeservice/SharedRingBuffer.cpp
index 6b3fb4c..83b25b3 100644
--- a/services/oboeservice/SharedRingBuffer.cpp
+++ b/services/oboeservice/SharedRingBuffer.cpp
@@ -35,11 +35,6 @@
         munmap(mSharedMemory, mSharedMemorySizeInBytes);
         mSharedMemory = nullptr;
     }
-    if (mFileDescriptor != -1) {
-        ALOGV("SharedRingBuffer: LEAK? close(mFileDescriptor = %d)\n", mFileDescriptor);
-        close(mFileDescriptor);
-        mFileDescriptor = -1;
-    }
 }
 
 aaudio_result_t SharedRingBuffer::allocate(fifo_frames_t   bytesPerFrame,
@@ -49,17 +44,17 @@
     // Create shared memory large enough to hold the data and the read and write counters.
     mDataMemorySizeInBytes = bytesPerFrame * capacityInFrames;
     mSharedMemorySizeInBytes = mDataMemorySizeInBytes + (2 * (sizeof(fifo_counter_t)));
-    mFileDescriptor = ashmem_create_region("AAudioSharedRingBuffer", mSharedMemorySizeInBytes);
-    ALOGV("SharedRingBuffer::allocate() LEAK? mFileDescriptor = %d\n", mFileDescriptor);
-    if (mFileDescriptor < 0) {
+    mFileDescriptor.reset(ashmem_create_region("AAudioSharedRingBuffer", mSharedMemorySizeInBytes));
+    if (mFileDescriptor.get() == -1) {
         ALOGE("SharedRingBuffer::allocate() ashmem_create_region() failed %d", errno);
         return AAUDIO_ERROR_INTERNAL;
     }
+    ALOGV("SharedRingBuffer::allocate() mFileDescriptor = %d\n", mFileDescriptor.get());
 
-    int err = ashmem_set_prot_region(mFileDescriptor, PROT_READ|PROT_WRITE); // TODO error handling?
+    int err = ashmem_set_prot_region(mFileDescriptor.get(), PROT_READ|PROT_WRITE); // TODO error handling?
     if (err < 0) {
         ALOGE("SharedRingBuffer::allocate() ashmem_set_prot_region() failed %d", errno);
-        close(mFileDescriptor);
+        mFileDescriptor.reset();
         return AAUDIO_ERROR_INTERNAL; // TODO convert errno to a better AAUDIO_ERROR;
     }
 
@@ -67,10 +62,10 @@
     mSharedMemory = (uint8_t *) mmap(0, mSharedMemorySizeInBytes,
                          PROT_READ|PROT_WRITE,
                          MAP_SHARED,
-                         mFileDescriptor, 0);
+                         mFileDescriptor.get(), 0);
     if (mSharedMemory == MAP_FAILED) {
         ALOGE("SharedRingBuffer::allocate() mmap() failed %d", errno);
-        close(mFileDescriptor);
+        mFileDescriptor.reset();
         return AAUDIO_ERROR_INTERNAL; // TODO convert errno to a better AAUDIO_ERROR;
     }
 
diff --git a/services/oboeservice/SharedRingBuffer.h b/services/oboeservice/SharedRingBuffer.h
index a2c3766..79169bc 100644
--- a/services/oboeservice/SharedRingBuffer.h
+++ b/services/oboeservice/SharedRingBuffer.h
@@ -17,6 +17,7 @@
 #ifndef AAUDIO_SHARED_RINGBUFFER_H
 #define AAUDIO_SHARED_RINGBUFFER_H
 
+#include <android-base/unique_fd.h>
 #include <stdint.h>
 #include <cutils/ashmem.h>
 #include <sys/mman.h>
@@ -51,12 +52,12 @@
     }
 
 private:
-    int                    mFileDescriptor = -1;
-    android::FifoBuffer   *mFifoBuffer = nullptr;
-    uint8_t               *mSharedMemory = nullptr;
-    int32_t                mSharedMemorySizeInBytes = 0;
-    int32_t                mDataMemorySizeInBytes = 0;
-    android::fifo_frames_t mCapacityInFrames = 0;
+    android::base::unique_fd  mFileDescriptor;
+    android::FifoBuffer      *mFifoBuffer = nullptr;
+    uint8_t                  *mSharedMemory = nullptr;
+    int32_t                   mSharedMemorySizeInBytes = 0;
+    int32_t                   mDataMemorySizeInBytes = 0;
+    android::fifo_frames_t    mCapacityInFrames = 0;
 };
 
 } /* namespace aaudio */
diff --git a/services/soundtrigger/Android.mk b/services/soundtrigger/Android.mk
index e21aae3..10ee141 100644
--- a/services/soundtrigger/Android.mk
+++ b/services/soundtrigger/Android.mk
@@ -58,7 +58,7 @@
 
 
 LOCAL_C_INCLUDES += \
-    $(TOPDIR)frameworks/av/services/audioflinger
+    frameworks/av/services/audioflinger
 
 LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
 
diff --git a/soundtrigger/Android.bp b/soundtrigger/Android.bp
new file mode 100644
index 0000000..6178153
--- /dev/null
+++ b/soundtrigger/Android.bp
@@ -0,0 +1,36 @@
+// Copyright 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.
+
+cc_library_shared {
+    name: "libsoundtrigger",
+
+    srcs: [
+        "SoundTrigger.cpp",
+        "ISoundTrigger.cpp",
+        "ISoundTriggerClient.cpp",
+        "ISoundTriggerHwService.cpp",
+    ],
+
+    shared_libs: [
+        "libcutils",
+        "libutils",
+        "liblog",
+        "libbinder",
+    ],
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+    ],
+}
diff --git a/soundtrigger/Android.mk b/soundtrigger/Android.mk
deleted file mode 100644
index e29adbf..0000000
--- a/soundtrigger/Android.mk
+++ /dev/null
@@ -1,39 +0,0 @@
-# Copyright 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-	SoundTrigger.cpp \
-	ISoundTrigger.cpp \
-	ISoundTriggerClient.cpp \
-	ISoundTriggerHwService.cpp
-
-LOCAL_SHARED_LIBRARIES := \
-	libcutils \
-	libutils \
-	liblog \
-	libbinder \
-
-#LOCAL_C_INCLUDES += \
-	system/media/camera/include \
-	system/media/private/camera/include
-
-LOCAL_MODULE:= libsoundtrigger
-
-LOCAL_CFLAGS := -Werror -Wall
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/soundtrigger/SoundTrigger.cpp b/soundtrigger/SoundTrigger.cpp
index e959b83..289b7b1 100644
--- a/soundtrigger/SoundTrigger.cpp
+++ b/soundtrigger/SoundTrigger.cpp
@@ -124,9 +124,9 @@
 }
 
 // SoundTrigger
-SoundTrigger::SoundTrigger(sound_trigger_module_handle_t module,
+SoundTrigger::SoundTrigger(sound_trigger_module_handle_t /*module*/,
                                  const sp<SoundTriggerCallback>& callback)
-    : mModule(module), mCallback(callback)
+    : mCallback(callback)
 {
 }