Merge "Check NAL size before looking inside"
diff --git a/media/libmedia/Android.bp b/media/libmedia/Android.bp
index 3ac519b..34b15a8 100644
--- a/media/libmedia/Android.bp
+++ b/media/libmedia/Android.bp
@@ -259,7 +259,6 @@
         "IMediaExtractor.cpp",
         "IMediaExtractorService.cpp",
         "IMediaSource.cpp",
-        "IStreamSource.cpp",
         "MediaCodecBuffer.cpp",
         "MediaUtils.cpp",
         "Metadata.cpp",
@@ -313,77 +312,3 @@
         },
     },
 }
-
-cc_library {
-    name: "libmedia_player2",
-
-    srcs: [
-        "JAudioTrack.cpp",
-        "MediaPlayer2Manager.cpp",
-        "mediaplayer2.cpp",
-    ],
-
-    shared_libs: [
-        "libandroid_runtime",
-        "libaudioclient",
-        "libbinder",
-        "libcutils",
-        "libgui",
-        "liblog",
-        "libmedia_omx",
-        "libmedia_player2_util",
-        "libmediaextractor",
-        "libstagefright_foundation",
-        "libui",
-        "libutils",
-
-        "libcrypto",
-        "libmediadrm",
-        "libmediametrics",
-        "libmediandk",
-        "libmediautils",
-        "libmemunreachable",
-        "libnativewindow",
-        "libpowermanager",
-        "libstagefright_httplive",
-        "libstagefright_player2",
-    ],
-
-    export_shared_lib_headers: [
-        "libaudioclient",
-        "libbinder",
-        "libmedia_omx",
-    ],
-
-    header_libs: [
-        "media_plugin_headers",
-    ],
-
-    static_libs: [
-        "libmedia_helper",
-        "libstagefright_nuplayer2",
-        "libstagefright_rtsp",
-        "libstagefright_timedtext",
-    ],
-
-    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/libmediaplayer2/Android.bp b/media/libmediaplayer2/Android.bp
new file mode 100644
index 0000000..17fa01c
--- /dev/null
+++ b/media/libmediaplayer2/Android.bp
@@ -0,0 +1,79 @@
+cc_library_headers {
+    name: "libmediaplayer2_headers",
+    vendor_available: true,
+    export_include_dirs: ["include"],
+}
+
+cc_library {
+    name: "libmediaplayer2",
+
+    srcs: [
+        "JAudioTrack.cpp",
+        "MediaPlayer2Manager.cpp",
+        "mediaplayer2.cpp",
+    ],
+
+    shared_libs: [
+        "libandroid_runtime",
+        "libaudioclient",
+        "libbinder",
+        "libcutils",
+        "libgui",
+        "liblog",
+        "libmedia_omx",
+        "libmedia_player2_util",
+        "libmediaextractor",
+        "libstagefright_foundation",
+        "libui",
+        "libutils",
+
+        "libcrypto",
+        "libmediadrm",
+        "libmediametrics",
+        "libmediandk",
+        "libmediautils",
+        "libmemunreachable",
+        "libnativewindow",
+        "libpowermanager",
+        "libstagefright_httplive",
+        "libstagefright_player2",
+    ],
+
+    export_shared_lib_headers: [
+        "libaudioclient",
+        "libbinder",
+        "libmedia_omx",
+    ],
+
+    header_libs: [
+        "media_plugin_headers",
+    ],
+
+    static_libs: [
+        "libmedia_helper",
+        "libstagefright_nuplayer2",
+        "libstagefright_rtsp",
+        "libstagefright_timedtext",
+    ],
+
+    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/JAudioTrack.cpp b/media/libmediaplayer2/JAudioTrack.cpp
similarity index 99%
rename from media/libmedia/JAudioTrack.cpp
rename to media/libmediaplayer2/JAudioTrack.cpp
index 99da0f7..6d9605a 100644
--- a/media/libmedia/JAudioTrack.cpp
+++ b/media/libmediaplayer2/JAudioTrack.cpp
@@ -18,7 +18,7 @@
 
 #include "media/JAudioAttributes.h"
 #include "media/JAudioFormat.h"
-#include "media/JAudioTrack.h"
+#include "mediaplayer2/JAudioTrack.h"
 
 #include <android_media_AudioErrors.h>
 #include <android_runtime/AndroidRuntime.h>
diff --git a/media/libmedia/MediaPlayer2Manager.cpp b/media/libmediaplayer2/MediaPlayer2Manager.cpp
similarity index 99%
rename from media/libmedia/MediaPlayer2Manager.cpp
rename to media/libmediaplayer2/MediaPlayer2Manager.cpp
index 4c0a7ac..c642d89 100644
--- a/media/libmedia/MediaPlayer2Manager.cpp
+++ b/media/libmediaplayer2/MediaPlayer2Manager.cpp
@@ -47,8 +47,6 @@
 #include <media/AudioPolicyHelper.h>
 #include <media/DataSourceDesc.h>
 #include <media/MediaHTTPService.h>
-#include <media/MediaPlayer2EngineClient.h>
-#include <media/MediaPlayer2Interface.h>
 #include <media/Metadata.h>
 #include <media/AudioTrack.h>
 #include <media/MemoryLeakTrackUtil.h>
@@ -63,6 +61,9 @@
 #include <media/stagefright/SurfaceUtils.h>
 #include <mediautils/BatteryNotifier.h>
 
+#include <mediaplayer2/MediaPlayer2EngineClient.h>
+#include <mediaplayer2/MediaPlayer2Interface.h>
+
 #include <memunreachable/memunreachable.h>
 #include <system/audio.h>
 #include <system/window.h>
diff --git a/media/libmedia/MediaPlayer2Manager.h b/media/libmediaplayer2/MediaPlayer2Manager.h
similarity index 99%
rename from media/libmedia/MediaPlayer2Manager.h
rename to media/libmediaplayer2/MediaPlayer2Manager.h
index 95b875b..fde1381 100644
--- a/media/libmedia/MediaPlayer2Manager.h
+++ b/media/libmediaplayer2/MediaPlayer2Manager.h
@@ -26,10 +26,10 @@
 #include <utils/String8.h>
 #include <utils/Vector.h>
 
-#include <media/MediaPlayer2Engine.h>
-#include <media/MediaPlayer2Interface.h>
 #include <media/Metadata.h>
 #include <media/stagefright/foundation/ABase.h>
+#include <mediaplayer2/MediaPlayer2Engine.h>
+#include <mediaplayer2/MediaPlayer2Interface.h>
 
 #include <system/audio.h>
 
diff --git a/media/libmedia/include/media/JAudioTrack.h b/media/libmediaplayer2/include/mediaplayer2/JAudioTrack.h
similarity index 100%
rename from media/libmedia/include/media/JAudioTrack.h
rename to media/libmediaplayer2/include/mediaplayer2/JAudioTrack.h
diff --git a/media/libmedia/include/media/MediaPlayer2Engine.h b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Engine.h
similarity index 100%
rename from media/libmedia/include/media/MediaPlayer2Engine.h
rename to media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Engine.h
diff --git a/media/libmedia/include/media/MediaPlayer2EngineClient.h b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2EngineClient.h
similarity index 100%
rename from media/libmedia/include/media/MediaPlayer2EngineClient.h
rename to media/libmediaplayer2/include/mediaplayer2/MediaPlayer2EngineClient.h
diff --git a/media/libmedia/include/media/MediaPlayer2Interface.h b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Interface.h
similarity index 99%
rename from media/libmedia/include/media/MediaPlayer2Interface.h
rename to media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Interface.h
index be300bb..bee5175 100644
--- a/media/libmedia/include/media/MediaPlayer2Interface.h
+++ b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Interface.h
@@ -31,8 +31,8 @@
 #include <media/AVSyncSettings.h>
 #include <media/BufferingSettings.h>
 #include <media/Metadata.h>
-#include <media/mediaplayer2.h>
 #include <media/stagefright/foundation/AHandler.h>
+#include <mediaplayer2/mediaplayer2.h>
 
 // Fwd decl to make sure everyone agrees that the scope of struct sockaddr_in is
 // global, and not in android::
diff --git a/media/libmedia/include/media/mediaplayer2.h b/media/libmediaplayer2/include/mediaplayer2/mediaplayer2.h
similarity index 98%
rename from media/libmedia/include/media/mediaplayer2.h
rename to media/libmediaplayer2/include/mediaplayer2/mediaplayer2.h
index c8b124c..35186ed 100644
--- a/media/libmedia/include/media/mediaplayer2.h
+++ b/media/libmediaplayer2/include/mediaplayer2/mediaplayer2.h
@@ -23,8 +23,8 @@
 
 #include <media/AudioResamplerPublic.h>
 #include <media/BufferingSettings.h>
-#include <media/MediaPlayer2EngineClient.h>
-#include <media/MediaPlayer2Engine.h>
+#include <mediaplayer2/MediaPlayer2EngineClient.h>
+#include <mediaplayer2/MediaPlayer2Engine.h>
 
 #include <utils/Condition.h>
 #include <utils/KeyedVector.h>
diff --git a/media/libmedia/mediaplayer2.cpp b/media/libmediaplayer2/mediaplayer2.cpp
similarity index 99%
rename from media/libmedia/mediaplayer2.cpp
rename to media/libmediaplayer2/mediaplayer2.cpp
index 1eb3795..b858783 100644
--- a/media/libmedia/mediaplayer2.cpp
+++ b/media/libmediaplayer2/mediaplayer2.cpp
@@ -29,7 +29,6 @@
 #include <binder/IServiceManager.h>
 #include <binder/IPCThreadState.h>
 
-#include <media/mediaplayer2.h>
 #include <media/AudioResamplerPublic.h>
 #include <media/AudioSystem.h>
 #include <media/AVSyncSettings.h>
@@ -37,6 +36,7 @@
 #include <media/DataSourceDesc.h>
 #include <media/MediaAnalyticsItem.h>
 #include <media/NdkWrapper.h>
+#include <mediaplayer2/mediaplayer2.h>
 
 #include <binder/MemoryBase.h>
 
diff --git a/media/libmedia/nuplayer2/Android.bp b/media/libmediaplayer2/nuplayer2/Android.bp
similarity index 97%
rename from media/libmedia/nuplayer2/Android.bp
rename to media/libmediaplayer2/nuplayer2/Android.bp
index 1f4455f..c40b361 100644
--- a/media/libmedia/nuplayer2/Android.bp
+++ b/media/libmediaplayer2/nuplayer2/Android.bp
@@ -16,6 +16,7 @@
     ],
 
     header_libs: [
+        "libmediaplayer2_headers",
         "media_plugin_headers",
     ],
 
diff --git a/media/libmedia/nuplayer2/GenericSource2.cpp b/media/libmediaplayer2/nuplayer2/GenericSource2.cpp
similarity index 100%
rename from media/libmedia/nuplayer2/GenericSource2.cpp
rename to media/libmediaplayer2/nuplayer2/GenericSource2.cpp
diff --git a/media/libmedia/nuplayer2/GenericSource2.h b/media/libmediaplayer2/nuplayer2/GenericSource2.h
similarity index 99%
rename from media/libmedia/nuplayer2/GenericSource2.h
rename to media/libmediaplayer2/nuplayer2/GenericSource2.h
index 2016304..bc13eb7 100644
--- a/media/libmedia/nuplayer2/GenericSource2.h
+++ b/media/libmediaplayer2/nuplayer2/GenericSource2.h
@@ -23,8 +23,8 @@
 
 #include "ATSParser.h"
 
-#include <media/mediaplayer2.h>
 #include <media/stagefright/MediaBuffer.h>
+#include <mediaplayer2/mediaplayer2.h>
 
 namespace android {
 
diff --git a/media/libmedia/nuplayer2/HTTPLiveSource2.cpp b/media/libmediaplayer2/nuplayer2/HTTPLiveSource2.cpp
similarity index 100%
rename from media/libmedia/nuplayer2/HTTPLiveSource2.cpp
rename to media/libmediaplayer2/nuplayer2/HTTPLiveSource2.cpp
diff --git a/media/libmedia/nuplayer2/HTTPLiveSource2.h b/media/libmediaplayer2/nuplayer2/HTTPLiveSource2.h
similarity index 100%
rename from media/libmedia/nuplayer2/HTTPLiveSource2.h
rename to media/libmediaplayer2/nuplayer2/HTTPLiveSource2.h
diff --git a/media/libmedia/nuplayer2/JWakeLock.cpp b/media/libmediaplayer2/nuplayer2/JWakeLock.cpp
similarity index 100%
rename from media/libmedia/nuplayer2/JWakeLock.cpp
rename to media/libmediaplayer2/nuplayer2/JWakeLock.cpp
diff --git a/media/libmedia/nuplayer2/JWakeLock.h b/media/libmediaplayer2/nuplayer2/JWakeLock.h
similarity index 100%
rename from media/libmedia/nuplayer2/JWakeLock.h
rename to media/libmediaplayer2/nuplayer2/JWakeLock.h
diff --git a/media/libmedia/nuplayer2/MODULE_LICENSE_APACHE2 b/media/libmediaplayer2/nuplayer2/MODULE_LICENSE_APACHE2
similarity index 100%
rename from media/libmedia/nuplayer2/MODULE_LICENSE_APACHE2
rename to media/libmediaplayer2/nuplayer2/MODULE_LICENSE_APACHE2
diff --git a/media/libmedia/nuplayer2/NOTICE b/media/libmediaplayer2/nuplayer2/NOTICE
similarity index 100%
rename from media/libmedia/nuplayer2/NOTICE
rename to media/libmediaplayer2/nuplayer2/NOTICE
diff --git a/media/libmedia/nuplayer2/NuPlayer2.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp
similarity index 100%
rename from media/libmedia/nuplayer2/NuPlayer2.cpp
rename to media/libmediaplayer2/nuplayer2/NuPlayer2.cpp
diff --git a/media/libmedia/nuplayer2/NuPlayer2.h b/media/libmediaplayer2/nuplayer2/NuPlayer2.h
similarity index 99%
rename from media/libmedia/nuplayer2/NuPlayer2.h
rename to media/libmediaplayer2/nuplayer2/NuPlayer2.h
index 1d74b55..594525c 100644
--- a/media/libmedia/nuplayer2/NuPlayer2.h
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2.h
@@ -19,9 +19,10 @@
 #define NU_PLAYER2_H_
 
 #include <media/AudioResamplerPublic.h>
-#include <media/MediaPlayer2Interface.h>
 #include <media/stagefright/foundation/AHandler.h>
 
+#include <mediaplayer2/MediaPlayer2Interface.h>
+
 namespace android {
 
 struct ABuffer;
diff --git a/media/libmedia/nuplayer2/NuPlayer2CCDecoder.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2CCDecoder.cpp
similarity index 100%
rename from media/libmedia/nuplayer2/NuPlayer2CCDecoder.cpp
rename to media/libmediaplayer2/nuplayer2/NuPlayer2CCDecoder.cpp
diff --git a/media/libmedia/nuplayer2/NuPlayer2CCDecoder.h b/media/libmediaplayer2/nuplayer2/NuPlayer2CCDecoder.h
similarity index 100%
rename from media/libmedia/nuplayer2/NuPlayer2CCDecoder.h
rename to media/libmediaplayer2/nuplayer2/NuPlayer2CCDecoder.h
diff --git a/media/libmedia/nuplayer2/NuPlayer2Decoder.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2Decoder.cpp
similarity index 100%
rename from media/libmedia/nuplayer2/NuPlayer2Decoder.cpp
rename to media/libmediaplayer2/nuplayer2/NuPlayer2Decoder.cpp
diff --git a/media/libmedia/nuplayer2/NuPlayer2Decoder.h b/media/libmediaplayer2/nuplayer2/NuPlayer2Decoder.h
similarity index 100%
rename from media/libmedia/nuplayer2/NuPlayer2Decoder.h
rename to media/libmediaplayer2/nuplayer2/NuPlayer2Decoder.h
diff --git a/media/libmedia/nuplayer2/NuPlayer2DecoderBase.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2DecoderBase.cpp
similarity index 100%
rename from media/libmedia/nuplayer2/NuPlayer2DecoderBase.cpp
rename to media/libmediaplayer2/nuplayer2/NuPlayer2DecoderBase.cpp
diff --git a/media/libmedia/nuplayer2/NuPlayer2DecoderBase.h b/media/libmediaplayer2/nuplayer2/NuPlayer2DecoderBase.h
similarity index 100%
rename from media/libmedia/nuplayer2/NuPlayer2DecoderBase.h
rename to media/libmediaplayer2/nuplayer2/NuPlayer2DecoderBase.h
diff --git a/media/libmedia/nuplayer2/NuPlayer2DecoderPassThrough.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2DecoderPassThrough.cpp
similarity index 100%
rename from media/libmedia/nuplayer2/NuPlayer2DecoderPassThrough.cpp
rename to media/libmediaplayer2/nuplayer2/NuPlayer2DecoderPassThrough.cpp
diff --git a/media/libmedia/nuplayer2/NuPlayer2DecoderPassThrough.h b/media/libmediaplayer2/nuplayer2/NuPlayer2DecoderPassThrough.h
similarity index 100%
rename from media/libmedia/nuplayer2/NuPlayer2DecoderPassThrough.h
rename to media/libmediaplayer2/nuplayer2/NuPlayer2DecoderPassThrough.h
diff --git a/media/libmedia/nuplayer2/NuPlayer2Driver.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.cpp
similarity index 100%
rename from media/libmedia/nuplayer2/NuPlayer2Driver.cpp
rename to media/libmediaplayer2/nuplayer2/NuPlayer2Driver.cpp
diff --git a/media/libmedia/nuplayer2/NuPlayer2Driver.h b/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.h
similarity index 98%
rename from media/libmedia/nuplayer2/NuPlayer2Driver.h
rename to media/libmediaplayer2/nuplayer2/NuPlayer2Driver.h
index 55fc9ef..7156813 100644
--- a/media/libmedia/nuplayer2/NuPlayer2Driver.h
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.h
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include <media/MediaPlayer2Interface.h>
+#include <mediaplayer2/MediaPlayer2Interface.h>
 
 #include <media/MediaAnalyticsItem.h>
 #include <media/stagefright/foundation/ABase.h>
diff --git a/media/libmedia/nuplayer2/NuPlayer2Drm.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2Drm.cpp
similarity index 100%
rename from media/libmedia/nuplayer2/NuPlayer2Drm.cpp
rename to media/libmediaplayer2/nuplayer2/NuPlayer2Drm.cpp
diff --git a/media/libmedia/nuplayer2/NuPlayer2Drm.h b/media/libmediaplayer2/nuplayer2/NuPlayer2Drm.h
similarity index 100%
rename from media/libmedia/nuplayer2/NuPlayer2Drm.h
rename to media/libmediaplayer2/nuplayer2/NuPlayer2Drm.h
diff --git a/media/libmedia/nuplayer2/NuPlayer2Renderer.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2Renderer.cpp
similarity index 100%
rename from media/libmedia/nuplayer2/NuPlayer2Renderer.cpp
rename to media/libmediaplayer2/nuplayer2/NuPlayer2Renderer.cpp
diff --git a/media/libmedia/nuplayer2/NuPlayer2Renderer.h b/media/libmediaplayer2/nuplayer2/NuPlayer2Renderer.h
similarity index 100%
rename from media/libmedia/nuplayer2/NuPlayer2Renderer.h
rename to media/libmediaplayer2/nuplayer2/NuPlayer2Renderer.h
diff --git a/media/libmedia/nuplayer2/NuPlayer2Source.h b/media/libmediaplayer2/nuplayer2/NuPlayer2Source.h
similarity index 98%
rename from media/libmedia/nuplayer2/NuPlayer2Source.h
rename to media/libmediaplayer2/nuplayer2/NuPlayer2Source.h
index 41ded9d..ef57bc0 100644
--- a/media/libmedia/nuplayer2/NuPlayer2Source.h
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2Source.h
@@ -20,9 +20,9 @@
 
 #include "NuPlayer2.h"
 
-#include <media/mediaplayer2.h>
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/MetaData.h>
+#include <mediaplayer2/mediaplayer2.h>
 #include <utils/Vector.h>
 
 namespace android {
diff --git a/media/libmedia/nuplayer2/RTSPSource2.cpp b/media/libmediaplayer2/nuplayer2/RTSPSource2.cpp
similarity index 100%
rename from media/libmedia/nuplayer2/RTSPSource2.cpp
rename to media/libmediaplayer2/nuplayer2/RTSPSource2.cpp
diff --git a/media/libmedia/nuplayer2/RTSPSource2.h b/media/libmediaplayer2/nuplayer2/RTSPSource2.h
similarity index 100%
rename from media/libmedia/nuplayer2/RTSPSource2.h
rename to media/libmediaplayer2/nuplayer2/RTSPSource2.h
diff --git a/media/libstagefright/Android.bp b/media/libstagefright/Android.bp
index 5240f7b..2ec30dd 100644
--- a/media/libstagefright/Android.bp
+++ b/media/libstagefright/Android.bp
@@ -106,6 +106,10 @@
         "VideoFrameScheduler.cpp",
     ],
 
+    header_libs: [
+        "libstagefright_codec2_internal",
+    ],
+
     shared_libs: [
         "libaudioutils",
         "libbinder",
diff --git a/media/libstagefright/CCodecBufferChannel.cpp b/media/libstagefright/CCodecBufferChannel.cpp
index ca4ddc8..27060e1 100644
--- a/media/libstagefright/CCodecBufferChannel.cpp
+++ b/media/libstagefright/CCodecBufferChannel.cpp
@@ -23,6 +23,7 @@
 
 #include <C2AllocatorGralloc.h>
 #include <C2PlatformSupport.h>
+#include <C2BlockInternal.h>
 
 #include <android/hardware/cas/native/1.0/IDescrambler.h>
 #include <binder/MemoryDealer.h>
@@ -819,7 +820,7 @@
         std::shared_ptr<C2Allocator> allocator = mAllocator.lock();
         if (!allocator) {
             c2_status_t err = GetCodec2PlatformAllocatorStore()->fetchAllocator(
-                    C2AllocatorStore::PLATFORM_START + 1,  // GRALLOC
+                    C2PlatformAllocatorStore::GRALLOC,
                     &allocator);
             if (err != OK) {
                 return UNKNOWN_ERROR;
@@ -835,7 +836,8 @@
         if (err != OK) {
             return UNKNOWN_ERROR;
         }
-        std::shared_ptr<C2GraphicBlock> block(new GraphicBlock(alloc));
+
+        std::shared_ptr<C2GraphicBlock> block = _C2BlockFactory::CreateGraphicBlock(alloc);
 
         std::unique_ptr<C2Work> work(new C2Work);
         work->input.flags = (C2FrameData::flags_t)0;
diff --git a/media/libstagefright/codec2/include/C2.h b/media/libstagefright/codec2/include/C2.h
index ab81cdc..00e3924 100644
--- a/media/libstagefright/codec2/include/C2.h
+++ b/media/libstagefright/codec2/include/C2.h
@@ -534,6 +534,18 @@
     });
 }
 
+/**
+ *  \ingroup utils_internal
+ */
+template<typename T, typename U, typename V>
+inline constexpr typename c2_types<T, V>::wide_type c2_clamp(const T a, const U b, const V c) {
+    typedef typename c2_types<T, U, V>::wide_type wide_type;
+    return ({
+        wide_type a_(a), b_(b), c_(c);
+        static_cast<typename c2_types<T, V>::wide_type>(b_ < a_ ? a_ : b_ > c_ ? c_ : b_);
+    });
+}
+
 /// @}
 
 #ifdef __ANDROID__
diff --git a/media/libstagefright/codec2/include/C2Buffer.h b/media/libstagefright/codec2/include/C2Buffer.h
index 45ad17f..034075f 100644
--- a/media/libstagefright/codec2/include/C2Buffer.h
+++ b/media/libstagefright/codec2/include/C2Buffer.h
@@ -134,7 +134,7 @@
 private:
     class Impl;
     std::shared_ptr<Impl> mImpl;
-    C2Fence(const std::shared_ptr<Impl> &impl);
+    C2Fence(std::shared_ptr<Impl> impl);
     friend struct _C2FenceFactory;
 };
 
@@ -324,15 +324,20 @@
 
     C2_ALLOW_OVERFLOW
     inline constexpr C2Segment intersect(const C2Segment &other) const {
-        if (!isValid()) {
-            return *this;
-        } else if (!other.isValid()) {
-            return other;
-        } else {
-            return C2Segment(c2_max(offset, other.offset),
-                             c2_min(end(), other.end()) - c2_max(offset, other.offset));
-        }
+        return C2Segment(c2_max(offset, other.offset),
+                         c2_min(end(), other.end()) - c2_max(offset, other.offset));
     }
+
+    /** clamps end to offset if it overflows */
+    inline constexpr C2Segment normalize() const {
+        return C2Segment(offset, c2_max(offset, end()) - offset);
+    }
+
+    /** clamps end to max if it overflows */
+    inline constexpr C2Segment saturate() const {
+        return C2Segment(offset, c2_min(size, ~offset));
+    }
+
 };
 
 /**
@@ -370,7 +375,7 @@
 };
 
 /**
- * Aspect for objects that have a linear range.
+ * Aspect for objects that have a linear range inside a linear capacity.
  *
  * This class is copiable.
  */
@@ -386,33 +391,52 @@
         return C2Segment(mOffset, mSize);
     }
 
-protected:
-    // capacity range [0, capacity]
-    inline constexpr explicit _C2LinearRangeAspect(const _C2LinearCapacityAspect *parent)
-        : _C2LinearCapacityAspect(parent),
-          mOffset(0),
-          mSize(capacity()) { }
+private:
+    // subrange of capacity [0, capacity] & [size, size + offset]
+    inline constexpr _C2LinearRangeAspect(uint32_t capacity_, size_t offset, size_t size)
+        : _C2LinearCapacityAspect(capacity_),
+          mOffset(c2_min(offset, capacity())),
+          mSize(c2_min(size, capacity() - mOffset)) {
+    }
 
+protected:
     // copy constructor (no error check)
     inline constexpr _C2LinearRangeAspect(const _C2LinearRangeAspect &other)
         : _C2LinearCapacityAspect(other.capacity()),
           mOffset(other.offset()),
-          mSize(other.size()) { }
+          mSize(other.size()) {
+    }
 
-    // subrange of capacity [0, capacity] & [size, size + offset]
+    // parent capacity range [0, capacity]
+    inline constexpr explicit _C2LinearRangeAspect(const _C2LinearCapacityAspect *parent)
+        : _C2LinearCapacityAspect(parent),
+          mOffset(0),
+          mSize(capacity()) {
+    }
+
+    // subrange of parent capacity [0, capacity] & [size, size + offset]
     inline constexpr _C2LinearRangeAspect(const _C2LinearCapacityAspect *parent, size_t offset, size_t size)
         : _C2LinearCapacityAspect(parent),
           mOffset(c2_min(offset, capacity())),
-          mSize(c2_min(size, capacity() - mOffset)) { }
+          mSize(c2_min(size, capacity() - mOffset)) {
+    }
 
-    // subsection of the two [offset, offset + size] ranges
+    // subsection of the parent's and [offset, offset + size] ranges
     inline constexpr _C2LinearRangeAspect(const _C2LinearRangeAspect *parent, size_t offset, size_t size)
-        : _C2LinearCapacityAspect(parent == nullptr ? 0 : parent->capacity()),
+        : _C2LinearCapacityAspect(parent),
           mOffset(c2_min(c2_max(offset, parent == nullptr ? 0 : parent->offset()), capacity())),
-          mSize(c2_min(c2_min(size, parent == nullptr ? 0 : parent->size()), capacity() - mOffset)) { }
+          mSize(std::min(c2_min(size, parent == nullptr ? 0 : parent->size()), capacity() - mOffset)) {
+    }
 
-private:
-    friend class _C2EditableLinearRange;
+public:
+    inline constexpr _C2LinearRangeAspect childRange(size_t offset, size_t size) const {
+        return _C2LinearRangeAspect(
+            mSize,
+            c2_min(c2_max(offset, mOffset), capacity()) - mOffset,
+            c2_min(c2_min(size, mSize), capacity() - c2_min(c2_max(offset, mOffset), capacity())));
+    }
+
+    friend class _C2EditableLinearRangeAspect;
     // invariants 0 <= mOffset <= mOffset + mSize <= capacity()
     uint32_t mOffset;
     uint32_t mSize;
@@ -420,7 +444,7 @@
 };
 
 /**
- * Utility class for safe range calculations.
+ * Utility class for safe range calculations using size_t-s.
  */
 class C2LinearRange : public _C2LinearRangeAspect {
 public:
@@ -436,7 +460,7 @@
 };
 
 /**
- * Utility class for simple capacity and range construction.
+ * Utility class for simple and safe capacity and range construction.
  */
 class C2LinearCapacity : public _C2LinearCapacityAspect {
 public:
@@ -453,21 +477,10 @@
  *
  * This class is copiable.
  */
-class _C2EditableLinearRange : public _C2LinearRangeAspect {
-protected:
-    inline explicit _C2EditableLinearRange(const _C2LinearCapacityAspect *parent)
-        : _C2LinearRangeAspect(parent) { }
+class _C2EditableLinearRangeAspect : public _C2LinearRangeAspect {
+    using _C2LinearRangeAspect::_C2LinearRangeAspect;
 
-    inline _C2EditableLinearRange(const _C2LinearRangeAspect &other)
-        : _C2LinearRangeAspect(other) { }
-
-    inline _C2EditableLinearRange(const _C2LinearCapacityAspect *parent, size_t offset, size_t size)
-        : _C2LinearRangeAspect(parent, offset, size) { }
-
-    // subsection of the two [offset, offset + size] ranges
-    inline _C2EditableLinearRange(const _C2LinearRangeAspect *parent, size_t offset, size_t size)
-        : _C2LinearRangeAspect(parent, offset, size) { }
-
+public:
 /// \name Editable linear range interface
 /// @{
 
@@ -1086,7 +1099,7 @@
  *
  * This class is copiable. \todo movable only?
  */
-class C2WriteView : public _C2EditableLinearRange {
+class C2WriteView : public _C2EditableLinearRangeAspect {
 public:
     /**
      * Start of the block.
@@ -1354,30 +1367,6 @@
 /// @{
 
 /**
- * Interface for objects that have a width and height (planar capacity).
- */
-class _C2PlanarCapacityAspect {
-/// \name Planar capacity interface
-/// @{
-public:
-    inline uint32_t width() const { return _mWidth; }
-    inline uint32_t height() const { return _mHeight; }
-
-protected:
-    inline _C2PlanarCapacityAspect(uint32_t width, uint32_t height)
-      : _mWidth(width), _mHeight(height) { }
-
-    inline _C2PlanarCapacityAspect(const _C2PlanarCapacityAspect *parent)
-        : _mWidth(parent == nullptr ? 0 : parent->width()),
-          _mHeight(parent == nullptr ? 0 : parent->height()) { }
-
-private:
-    const uint32_t _mWidth;
-    const uint32_t _mHeight;
-/// @}
-};
-
-/**
  * C2Rect: rectangle type with non-negative coordinates.
  *
  * \note This struct has public fields without getters/setters. All methods are inline.
@@ -1465,17 +1454,44 @@
 
     C2_ALLOW_OVERFLOW
     inline constexpr C2Rect intersect(const C2Rect &other) const {
-        if (!isValid()) {
-            return *this;
-        } else if (!other.isValid()) {
-            return other;
-        } else {
-            return C2Rect(c2_min(right(), other.right()) - c2_max(left, other.left),
-                          c2_min(bottom(), other.bottom()) - c2_max(top, other.top),
-                          c2_max(left, other.left),
-                          c2_max(top, other.top));
-        }
+        return C2Rect(c2_min(right(), other.right()) - c2_max(left, other.left),
+                      c2_min(bottom(), other.bottom()) - c2_max(top, other.top),
+                      c2_max(left, other.left),
+                      c2_max(top, other.top));
     }
+
+    /** clamps right and bottom to top, left if they overflow */
+    inline constexpr C2Rect normalize() const {
+        return C2Rect(c2_max(left, right()) - left, c2_max(top, bottom()) - top, left, top);
+    }
+};
+
+/**
+ * Interface for objects that have a width and height (planar capacity).
+ */
+class _C2PlanarCapacityAspect {
+/// \name Planar capacity interface
+/// @{
+public:
+    inline constexpr uint32_t width() const { return _mWidth; }
+    inline constexpr uint32_t height() const { return _mHeight; }
+
+    inline constexpr operator C2Rect() const {
+        return C2Rect(_mWidth, _mHeight);
+    }
+
+protected:
+    inline constexpr _C2PlanarCapacityAspect(uint32_t width, uint32_t height)
+      : _mWidth(width), _mHeight(height) { }
+
+    inline explicit constexpr _C2PlanarCapacityAspect(const _C2PlanarCapacityAspect *parent)
+        : _mWidth(parent == nullptr ? 0 : parent->width()),
+          _mHeight(parent == nullptr ? 0 : parent->height()) { }
+
+private:
+    uint32_t _mWidth;
+    uint32_t _mHeight;
+/// @}
 };
 
 /**
@@ -1497,6 +1513,7 @@
 
     int32_t colInc;       ///< column increment in bytes. may be negative
     int32_t rowInc;       ///< row increment in bytes. may be negative
+
     uint32_t colSampling; ///< subsampling compared to width (must be a power of 2)
     uint32_t rowSampling; ///< subsampling compared to height (must be a power of 2)
 
@@ -1529,7 +1546,7 @@
         BIG_END,    // BIG_ENDIAN is a reserved macro
     } endianness; ///< endianness of the samples
 
-    inline ssize_t minOffset(uint32_t width, uint32_t height) {
+    inline constexpr ssize_t minOffset(uint32_t width, uint32_t height) const {
         ssize_t offs = 0;
         if (width > 0 && colInc < 0) {
             offs += colInc * (ssize_t)(width - 1);
@@ -1540,7 +1557,7 @@
         return offs;
     }
 
-    inline ssize_t maxOffset(uint32_t width, uint32_t height, uint32_t allocatedDepth) {
+    inline constexpr ssize_t maxOffset(uint32_t width, uint32_t height) const {
         ssize_t offs = (allocatedDepth + 7) >> 3;
         if (width > 0 && colInc > 0) {
             offs += colInc * (ssize_t)(width - 1);
@@ -1550,20 +1567,20 @@
         }
         return offs;
     }
-};
+} C2_PACK;
 
 struct C2PlanarLayout {
 //public:
     enum type_t : uint32_t {
         TYPE_UNKNOWN = 0,
-        TYPE_YUV = 0x100,
-        TYPE_YUVA,
-        TYPE_RGB,
-        TYPE_RGBA,
+        TYPE_YUV = 0x100,   ///< YUV image with 3 planes
+        TYPE_YUVA,          ///< YUVA image with 4 planes
+        TYPE_RGB,           ///< RGB image with 3 planes
+        TYPE_RGBA,          ///< RBGA image with 4 planes
     };
 
-    type_t type;
-    uint32_t numPlanes;               // number of planes
+    type_t type;                    // image type
+    uint32_t numPlanes;             // number of planes
 
     enum plane_index_t : uint32_t {
         PLANE_Y = 0,
@@ -1584,13 +1601,68 @@
  *
  * This class is copiable.
  */
-class _C2PlanarSection : public _C2PlanarCapacityAspect {
+class _C2PlanarSectionAspect : public _C2PlanarCapacityAspect {
 /// \name Planar section interface
 /// @{
+private:
+    inline constexpr _C2PlanarSectionAspect(uint32_t width, uint32_t height, const C2Rect &crop)
+        : _C2PlanarCapacityAspect(width, height),
+          mCrop(std::min(width - std::min(crop.left, width), crop.width),
+                std::min(height - std::min(crop.top, height), crop.height),
+                std::min(crop.left, width),
+                std::min(crop.height, height)) {
+    }
+
 public:
     // crop can be an empty rect, does not have to line up with subsampling
     // NOTE: we do not support floating-point crop
-    inline const C2Rect crop() const { return mCrop; }
+    inline constexpr C2Rect crop() const { return mCrop; }
+
+    /**
+     * Returns a child planar section for |crop|, where the capacity represents this section.
+     */
+    inline constexpr _C2PlanarSectionAspect childSection(const C2Rect &crop) const {
+        return _C2PlanarSectionAspect(
+                mCrop.width, mCrop.height,
+                // crop and translate |crop| rect
+                C2Rect(c2_min(mCrop.right() - c2_clamp(mCrop.left, crop.left, mCrop.right()), crop.width),
+                       c2_min(mCrop.bottom() - c2_clamp(mCrop.top, crop.top, mCrop.bottom()), crop.height),
+                       c2_clamp(mCrop.left, crop.left, mCrop.right()) - mCrop.left,
+                       c2_clamp(mCrop.top, crop.top, mCrop.bottom()) - mCrop.top));
+    }
+
+protected:
+    inline constexpr _C2PlanarSectionAspect(const _C2PlanarCapacityAspect *parent)
+        : _C2PlanarCapacityAspect(parent), mCrop(width(), height()) {}
+
+    inline constexpr _C2PlanarSectionAspect(const _C2PlanarCapacityAspect *parent, const C2Rect &crop)
+        : _C2PlanarCapacityAspect(parent),
+          mCrop(parent == nullptr ? C2Rect(0, 0) : ((C2Rect)*parent).intersect(crop).normalize()) { }
+
+    inline constexpr _C2PlanarSectionAspect(const _C2PlanarSectionAspect *parent, const C2Rect &crop)
+        : _C2PlanarCapacityAspect(parent),
+          mCrop(parent == nullptr ? C2Rect(0, 0) : parent->crop().intersect(crop).normalize()) { }
+
+private:
+    friend class _C2EditablePlanarSectionAspect;
+    C2Rect mCrop;
+/// @}
+};
+
+/**
+ * Aspect for objects that have an editable planar section (crop rectangle).
+ *
+ * This class is copiable.
+ */
+class _C2EditablePlanarSectionAspect : public _C2PlanarSectionAspect {
+/// \name Planar section interface
+/// @{
+    using _C2PlanarSectionAspect::_C2PlanarSectionAspect;
+
+public:
+    // crop can be an empty rect, does not have to line up with subsampling
+    // NOTE: we do not support floating-point crop
+    inline constexpr C2Rect crop() const { return mCrop; }
 
     /**
      *  Sets crop to crop intersected with [(0,0) .. (width, height)]
@@ -1616,17 +1688,41 @@
         mCrop = crop;
         return true;
     }
-
-protected:
-    inline _C2PlanarSection(const _C2PlanarCapacityAspect *parent)
-        : _C2PlanarCapacityAspect(parent), mCrop(width(), height()) {}
-
-private:
-    C2Rect mCrop;
 /// @}
 };
 
 /**
+ * Utility class for safe range calculations using size_t-s.
+ */
+class C2PlanarSection : public _C2PlanarSectionAspect {
+public:
+    inline constexpr C2PlanarSection(const _C2PlanarCapacityAspect &parent, const C2Rect &crop)
+        : _C2PlanarSectionAspect(&parent, crop) { }
+
+    inline constexpr C2PlanarSection(const _C2PlanarSectionAspect &parent, const C2Rect &crop)
+        : _C2PlanarSectionAspect(&parent, crop) { }
+
+    inline constexpr C2PlanarSection intersect(const C2Rect &crop) const {
+        return C2PlanarSection(*this, crop);
+    }
+};
+
+/**
+ * Utility class for simple and safe planar capacity and section construction.
+ */
+class C2PlanarCapacity : public _C2PlanarCapacityAspect {
+public:
+    inline constexpr explicit C2PlanarCapacity(size_t width, size_t height)
+        : _C2PlanarCapacityAspect(c2_min(width, std::numeric_limits<uint32_t>::max()),
+                                  c2_min(height, std::numeric_limits<uint32_t>::max())) { }
+
+    inline constexpr C2PlanarSection section(const C2Rect &crop) const {
+        return C2PlanarSection(*this, crop);
+    }
+};
+
+
+/**
  * \ingroup graphic allocator
  * 2D allocation interface.
  */
@@ -1640,19 +1736,22 @@
      * descriptor referring to an acquire sync fence object. If it is already safe to access the
      * buffer contents, then -1.
      *
+     * Safe regions for the pointer addresses returned can be gotten via C2LayoutInfo.minOffse()/
+     * maxOffset().
+     *
      * \note Only one portion of the graphic allocation can be mapped at the same time. (This is
      * from gralloc1 limitation.)
      *
-     * \param rect            section to be mapped (this does not have to be aligned)
-     * \param usage           the desired usage. \todo this must be kSoftwareRead and/or
+     * \param rect          section to be mapped (this does not have to be aligned)
+     * \param usage         the desired usage. \todo this must be kSoftwareRead and/or
      *                      kSoftwareWrite.
-     * \param fenceFd         a pointer to a file descriptor if an async mapping is requested. If
+     * \param fenceFd       a pointer to a file descriptor if an async mapping is requested. If
      *                      not-null, and acquire fence FD will be stored here on success, or -1
      *                      on failure. If null, the mapping will be synchronous.
-     * \param layout          a pointer to where the mapped planes' descriptors will be
+     * \param layout        a pointer to where the mapped planes' descriptors will be
      *                      stored. On failure, nullptr will be stored here.
-     *
-     * \todo Do we need to support sync operation as we could just wait for the fence?
+     * \param addr          pointer to an array with at least C2PlanarLayout::MAX_NUM_PLANES
+     *                      elements. Only layout.numPlanes elements will be modified on success.
      *
      * \retval C2_OK        the operation was successful
      * \retval C2_REFUSED   no permission to map the section
@@ -1666,7 +1765,6 @@
      */
     virtual c2_status_t map(
             C2Rect rect, C2MemoryUsage usage, int *fenceFd,
-            // TODO: return <addr, size> buffers with plane sizes
             C2PlanarLayout *layout /* nonnull */, uint8_t **addr /* nonnull */) = 0;
 
     /**
@@ -1687,11 +1785,9 @@
     virtual c2_status_t unmap(C2Fence *fenceFd /* nullable */) = 0;
 
     /**
-     * Returns true if this is a valid allocation.
-     *
-     * \todo remove?
+     * Returns the allocator ID for this allocation. This is useful to put the handle into context.
      */
-    virtual bool isValid() const = 0;
+    virtual C2Allocator::id_t getAllocatorId() const = 0;
 
     /**
      * Returns a pointer to the allocation handle.
@@ -1710,15 +1806,36 @@
 
 class C2GraphicAllocation;
 
-class C2Block2D : public _C2PlanarSection {
+/**
+ * A 2D block.
+ *
+ * \note width()/height() is not meaningful for users of blocks; instead, crop().width() and
+ * crop().height() is the capacity of the usable portion. Use and crop() if accessing the block
+ * directly through its handle to represent the allotted region of the underlying allocation to this
+ * block.
+ */
+class C2Block2D : public _C2PlanarSectionAspect {
 public:
+    /**
+     * Returns the underlying handle for this allocation.
+     *
+     * \note that the block and its block pool has shared ownership of the handle
+     *       and if all references to the block are released, the underlying block
+     *       allocation may get reused even if a client keeps a clone of this handle.
+     */
     const C2Handle *handle() const;
 
-protected:
-    C2Block2D(const std::shared_ptr<C2GraphicAllocation> &alloc);
+    /**
+     * Returns the allocator's ID that created the underlying allocation for this block. This
+     * provides the context for understanding the handle.
+     */
+    C2Allocator::id_t getAllocatorId() const;
 
-private:
+protected:
     class Impl;
+    C2Block2D(std::shared_ptr<Impl> impl, const _C2PlanarSectionAspect &section);
+
+    friend struct _C2BlockFactory;
     std::shared_ptr<Impl> mImpl;
 };
 
@@ -1731,21 +1848,19 @@
  * to ensure subsampling is followed. This results in nearly identical interface between read and
  * write views, so C2GraphicView can encompass both of them.
  */
-class C2GraphicView : public _C2PlanarSection {
+class C2GraphicView : public _C2EditablePlanarSectionAspect {
 public:
     /**
-     * \return array of pointers to the start of the planes or nullptr on error.
-     * Regardless of crop rect, they always point to the top-left corner of
-     * each plane.  Access outside of the crop rect results in an undefined
-     * behavior.
+     * \return array of pointers (of layout().numPlanes elements) to the start of the planes or
+     * nullptr on error. Regardless of crop rect, they always point to the top-left corner of each
+     * plane. Access outside of the crop rect results in an undefined behavior.
      */
     const uint8_t *const *data() const;
 
     /**
-     * \return array of pointers to the start of the planes or nullptr on error.
-     * Regardless of crop rect, they always point to the top-left corner of
-     * each plane.  Access outside of the crop rect results in an undefined
-     * behavior.
+     * \return array of pointers (of layout().numPlanes elements) to the start of the planes or
+     * nullptr on error. Regardless of crop rect, they always point to the top-left corner of each
+     * plane. Access outside of the crop rect results in an undefined behavior.
      */
     uint8_t *const *data();
 
@@ -1770,14 +1885,12 @@
     c2_status_t error() const;
 
 protected:
-    C2GraphicView(
-            const _C2PlanarCapacityAspect *parent,
-            uint8_t *const *data,
-            const C2PlanarLayout& layout);
+    class Impl;
+    C2GraphicView(std::shared_ptr<Impl> impl, const _C2PlanarSectionAspect &section);
     explicit C2GraphicView(c2_status_t error);
 
 private:
-    class Impl;
+    friend struct _C2BlockFactory;
     std::shared_ptr<Impl> mImpl;
 };
 
@@ -1814,11 +1927,11 @@
     C2Fence fence() const { return mFence; }
 
 protected:
-    C2ConstGraphicBlock(const std::shared_ptr<C2GraphicAllocation> &alloc, C2Fence fence);
+    C2ConstGraphicBlock(
+            std::shared_ptr<Impl> impl, const _C2PlanarSectionAspect &section, C2Fence fence);
 
 private:
-    class Impl;
-    std::shared_ptr<Impl> mImpl;
+    friend struct _C2BlockFactory;
     C2Fence mFence;
 };
 
@@ -1848,11 +1961,9 @@
     C2ConstGraphicBlock share(const C2Rect &crop, C2Fence fence);
 
 protected:
-    explicit C2GraphicBlock(const std::shared_ptr<C2GraphicAllocation> &alloc);
+    C2GraphicBlock(std::shared_ptr<Impl> impl, const _C2PlanarSectionAspect &section);
 
-private:
-    class Impl;
-    std::shared_ptr<Impl> mImpl;
+    friend struct _C2BlockFactory;
 };
 
 /// @}
diff --git a/media/libstagefright/codec2/tests/vndk/C2BufferTest.cpp b/media/libstagefright/codec2/tests/vndk/C2BufferTest.cpp
index 2de43c8..f0e57e2 100644
--- a/media/libstagefright/codec2/tests/vndk/C2BufferTest.cpp
+++ b/media/libstagefright/codec2/tests/vndk/C2BufferTest.cpp
@@ -26,6 +26,209 @@
 
 namespace android {
 
+class C2BufferUtilsTest : public ::testing::Test {
+    static void StaticSegmentTest() {
+        // constructor
+        static_assert(C2Segment(123u, 456u).offset == 123, "");
+        static_assert(C2Segment(123u, 456u).size == 456, "");
+
+        // empty
+        static_assert(!C2Segment(123u, 456u).isEmpty(), "");
+        static_assert(C2Segment(123u, 0u).isEmpty(), "");
+
+        // valid
+        static_assert(C2Segment(123u, 456u).isValid(), "");
+        static_assert(C2Segment(123u, ~123u).isValid(), "");
+        static_assert(!C2Segment(123u, 1 + ~123u).isValid(), "");
+
+        // bool()
+        static_assert(C2Segment(123u, 456u), "");
+        static_assert((bool)C2Segment(123u, ~123u), "");
+        static_assert(!bool(C2Segment(123u, 1 + ~123u)), "");
+        static_assert(!bool(C2Segment(123u, 0)), "");
+
+        // !
+        static_assert(!!C2Segment(123u, 456u), "");
+        static_assert(!!C2Segment(123u, ~123u), "");
+        static_assert(!C2Segment(123u, 1 + ~123u), "");
+        static_assert(!C2Segment(123u, 0), "");
+
+        // contains
+        static_assert(C2Segment(123u, ~123u).contains(C2Segment(123u, 0)), "");
+        static_assert(!C2Segment(123u, 1 + ~123u).contains(C2Segment(123u, 0)), "");
+        static_assert(C2Segment(123u, ~123u).contains(C2Segment(123u, ~123u)), "");
+        static_assert(!C2Segment(123u, ~123u).contains(C2Segment(123u, 1 + ~123u)), "");
+        static_assert(!C2Segment(123u, 1 + ~123u).contains(C2Segment(123u, 1 + ~123u)), "");
+        static_assert(!C2Segment(123u, ~123u).contains(C2Segment(122u, 2u)), "");
+        static_assert(C2Segment(123u, ~123u).contains(C2Segment(123u, 2u)), "");
+        static_assert(C2Segment(123u, 3u).contains(C2Segment(124u, 2u)), "");
+        static_assert(!C2Segment(123u, 3u).contains(C2Segment(125u, 2u)), "");
+
+        // ==
+        static_assert(C2Segment(123u, 456u) == C2Segment(123u, 456u), "");
+        static_assert(!(C2Segment(123u, 456u) == C2Segment(123u, 457u)), "");
+        static_assert(!(C2Segment(123u, 456u) == C2Segment(123u, 455u)), "");
+        static_assert(!(C2Segment(123u, 456u) == C2Segment(122u, 456u)), "");
+        static_assert(!(C2Segment(123u, 456u) == C2Segment(124u, 456u)), "");
+        static_assert(!(C2Segment(123u, 0u) == C2Segment(124u, 0u)), "");
+        static_assert(C2Segment(123u, 0u) == C2Segment(123u, 0u), "");
+        static_assert(C2Segment(123u, 1 + ~123u) == C2Segment(124u, 1 + ~124u), "");
+
+        // !=
+        static_assert(!(C2Segment(123u, 456u) != C2Segment(123u, 456u)), "");
+        static_assert(C2Segment(123u, 456u) != C2Segment(123u, 457u), "");
+        static_assert(C2Segment(123u, 456u) != C2Segment(123u, 455u), "");
+        static_assert(C2Segment(123u, 456u) != C2Segment(122u, 456u), "");
+        static_assert(C2Segment(123u, 456u) != C2Segment(124u, 456u), "");
+        static_assert(C2Segment(123u, 0u) != C2Segment(124u, 0u), "");
+        static_assert(!(C2Segment(123u, 0u) != C2Segment(123u, 0u)), "");
+        static_assert(!(C2Segment(123u, 1 + ~123u) != C2Segment(124u, 1 + ~124u)), "");
+
+        // <=
+        static_assert(C2Segment(123u, 456u) <= C2Segment(123u, 456u), "");
+        static_assert(C2Segment(123u, 456u) <= C2Segment(123u, 457u), "");
+        static_assert(C2Segment(123u, 456u) <= C2Segment(122u, 457u), "");
+        static_assert(!(C2Segment(123u, 457u) <= C2Segment(123u, 456u)), "");
+        static_assert(!(C2Segment(122u, 457u) <= C2Segment(123u, 456u)), "");
+        static_assert(!(C2Segment(123u, 457u) <= C2Segment(124u, 457u)), "");
+        static_assert(!(C2Segment(122u, 457u) <= C2Segment(123u, 457u)), "");
+        static_assert(!(C2Segment(122u, 0u) <= C2Segment(123u, 0u)), "");
+        static_assert(C2Segment(123u, 0u) <= C2Segment(122u, 1u), "");
+        static_assert(C2Segment(122u, 0u) <= C2Segment(122u, 1u), "");
+        static_assert(!(C2Segment(122u, ~122u) <= C2Segment(122u, 1 + ~122u)), "");
+        static_assert(!(C2Segment(122u, 1 + ~122u) <= C2Segment(122u, ~122u)), "");
+        static_assert(!(C2Segment(122u, 1 + ~122u) <= C2Segment(122u, 1 + ~122u)), "");
+
+        // <
+        static_assert(!(C2Segment(123u, 456u) < C2Segment(123u, 456u)), "");
+        static_assert(C2Segment(123u, 456u) < C2Segment(123u, 457u), "");
+        static_assert(C2Segment(123u, 456u) < C2Segment(122u, 457u), "");
+        static_assert(!(C2Segment(123u, 457u) < C2Segment(123u, 456u)), "");
+        static_assert(!(C2Segment(122u, 457u) < C2Segment(123u, 456u)), "");
+        static_assert(!(C2Segment(123u, 457u) < C2Segment(124u, 457u)), "");
+        static_assert(!(C2Segment(122u, 457u) < C2Segment(123u, 457u)), "");
+        static_assert(!(C2Segment(122u, 0u) < C2Segment(123u, 0u)), "");
+        static_assert(C2Segment(123u, 0u) < C2Segment(122u, 1u), "");
+        static_assert(C2Segment(122u, 0u) < C2Segment(122u, 1u), "");
+        static_assert(!(C2Segment(122u, ~122u) < C2Segment(122u, 1 + ~122u)), "");
+        static_assert(!(C2Segment(122u, 1 + ~122u) < C2Segment(122u, ~122u)), "");
+        static_assert(!(C2Segment(122u, 1 + ~122u) < C2Segment(122u, 1 + ~122u)), "");
+
+        // <=
+        static_assert(C2Segment(123u, 456u) >= C2Segment(123u, 456u), "");
+        static_assert(C2Segment(123u, 457u) >= C2Segment(123u, 456u), "");
+        static_assert(C2Segment(122u, 457u) >= C2Segment(123u, 456u), "");
+        static_assert(!(C2Segment(123u, 456u) >= C2Segment(123u, 457u)), "");
+        static_assert(!(C2Segment(123u, 456u) >= C2Segment(122u, 457u)), "");
+        static_assert(!(C2Segment(124u, 457u) >= C2Segment(123u, 457u)), "");
+        static_assert(!(C2Segment(123u, 457u) >= C2Segment(122u, 457u)), "");
+        static_assert(!(C2Segment(123u, 0u) >= C2Segment(122u, 0u)), "");
+        static_assert(C2Segment(122u, 1u) >= C2Segment(123u, 0u), "");
+        static_assert(C2Segment(122u, 1u) >= C2Segment(122u, 0u), "");
+        static_assert(!(C2Segment(122u, 1 + ~122u) >= C2Segment(122u, ~122u)), "");
+        static_assert(!(C2Segment(122u, ~122u) >= C2Segment(122u, 1 + ~122u)), "");
+        static_assert(!(C2Segment(122u, 1 + ~122u) >= C2Segment(122u, 1 + ~122u)), "");
+
+        // <
+        static_assert(!(C2Segment(123u, 456u) > C2Segment(123u, 456u)), "");
+        static_assert(C2Segment(123u, 457u) > C2Segment(123u, 456u), "");
+        static_assert(C2Segment(122u, 457u) > C2Segment(123u, 456u), "");
+        static_assert(!(C2Segment(123u, 456u) > C2Segment(123u, 457u)), "");
+        static_assert(!(C2Segment(123u, 456u) > C2Segment(122u, 457u)), "");
+        static_assert(!(C2Segment(124u, 457u) > C2Segment(123u, 457u)), "");
+        static_assert(!(C2Segment(123u, 457u) > C2Segment(122u, 457u)), "");
+        static_assert(!(C2Segment(123u, 0u) > C2Segment(122u, 0u)), "");
+        static_assert(C2Segment(122u, 1u) > C2Segment(123u, 0u), "");
+        static_assert(C2Segment(122u, 1u) > C2Segment(122u, 0u), "");
+        static_assert(!(C2Segment(122u, 1 + ~122u) > C2Segment(122u, ~122u)), "");
+        static_assert(!(C2Segment(122u, ~122u) > C2Segment(122u, 1 + ~122u)), "");
+        static_assert(!(C2Segment(122u, 1 + ~122u) > C2Segment(122u, 1 + ~122u)), "");
+
+        // end
+        static_assert(C2Segment(123u, 456u).end() == 579u, "");
+        static_assert(C2Segment(123u, 0u).end() == 123u, "");
+        static_assert(C2Segment(123u, ~123u).end() == 0xffffffffu, "");
+        static_assert(C2Segment(123u, 1 + ~123u).end() == 0u, "");
+
+        // intersect
+        static_assert(C2Segment(123u, 456u).intersect(C2Segment(123u, 456u)) == C2Segment(123u, 456u), "");
+        static_assert(C2Segment(123u, 456u).intersect(C2Segment(123u, 460u)) == C2Segment(123u, 456u), "");
+        static_assert(C2Segment(123u, 456u).intersect(C2Segment(124u, 460u)) == C2Segment(124u, 455u), "");
+        static_assert(C2Segment(123u, 456u).intersect(C2Segment(579u, 460u)) == C2Segment(579u, 0u), "");
+        static_assert(C2Segment(123u, 456u).intersect(C2Segment(589u, 460u)) == C2Segment(589u, ~9u /* -10 */), "");
+        static_assert(C2Segment(123u, 456u).intersect(C2Segment(123u, 455u)) == C2Segment(123u, 455u), "");
+        static_assert(C2Segment(123u, 456u).intersect(C2Segment(122u, 456u)) == C2Segment(123u, 455u), "");
+        static_assert(C2Segment(123u, 456u).intersect(C2Segment(0u, 123u)) == C2Segment(123u, 0u), "");
+        static_assert(C2Segment(123u, 456u).intersect(C2Segment(0u, 0u)) == C2Segment(123u, ~122u /* -123 */), "");
+
+        // normalize (change invalid segments to empty segments)
+        static_assert(C2Segment(123u, 456u).normalize() == C2Segment(123u, 456u), "");
+        static_assert(C2Segment(123u, ~123u).normalize() == C2Segment(123u, ~123u), "");
+        static_assert(C2Segment(123u, 1 + ~123u).normalize() == C2Segment(123u, 0u), "");
+
+        // note: normalize cannot be used to make this work
+        static_assert(C2Segment(123u, 456u).intersect(C2Segment(150u, ~150u)).normalize() == C2Segment(150u, 429u), "");
+        static_assert(C2Segment(123u, 456u).intersect(C2Segment(150u, 1 + ~150u)).normalize() != C2Segment(150u, 429u), "");
+        static_assert(C2Segment(123u, 456u).intersect(C2Segment(150u, 1 + ~150u)).normalize() == C2Segment(150u, 0u), "");
+
+        // saturate (change invalid segments to full segments up to max)
+        static_assert(C2Segment(123u, 456u).saturate() == C2Segment(123u, 456u), "");
+        static_assert(C2Segment(123u, ~123u).saturate() == C2Segment(123u, ~123u), "");
+        static_assert(C2Segment(123u, 1 + ~123u).saturate() == C2Segment(123u, ~123u), "");
+
+        // note: saturate can be used to make this work but only partially
+        static_assert(C2Segment(123u, 456u).intersect(C2Segment(150u, 1 + ~150u).saturate()).normalize() == C2Segment(150u, 429u), "");
+        static_assert(C2Segment(123u, 456u).intersect(C2Segment(0u, 100u).saturate()).normalize() == C2Segment(123u, 0u), "");
+        static_assert(C2Segment(123u, 456u).intersect(C2Segment(1000u, 100u).saturate()).normalize() != C2Segment(579u, 0u), "");
+        static_assert(C2Segment(123u, 456u).intersect(C2Segment(1000u, 100u).saturate()).normalize() == C2Segment(1000u, 0u), "");
+
+    }
+
+    static void StaticLinearRangeAndCapacityTest() {
+        class TestCapacity : public _C2LinearCapacityAspect {
+            using _C2LinearCapacityAspect::_C2LinearCapacityAspect;
+            friend class C2BufferUtilsTest;
+        };
+
+        class TestRange : public _C2LinearRangeAspect {
+            using _C2LinearRangeAspect::_C2LinearRangeAspect;
+            friend class C2BufferUtilsTest;
+        };
+
+        // _C2LinearCapacityAspect
+        static_assert(TestCapacity(0u).capacity() == 0u, "");
+        constexpr TestCapacity cap(123u);
+        static_assert(TestCapacity(&cap).capacity() == 123u, "");
+        static_assert(TestCapacity(nullptr).capacity() == 0u, "");
+
+        // _C2LinearCapacityRange
+        static_assert(TestRange(&cap).capacity() == 123u, "");
+        static_assert(TestRange(&cap).offset() == 0u, "");
+        static_assert(TestRange(&cap).size() == 123u, "");
+        static_assert(TestRange(&cap).endOffset() == 123u, "");
+
+        constexpr TestRange range(&cap, 50u, 100u);
+
+        static_assert(range.capacity() == 123u, "");
+        static_assert(range.offset() == 50u, "");
+        static_assert(range.size() == 73u, "");
+        static_assert(range.endOffset() == 123u, "");
+
+        static_assert(TestRange(&cap, 20u, 30u).capacity() == 123u, "");
+        static_assert(TestRange(&cap, 20u, 30u).offset() == 20u, "");
+        static_assert(TestRange(&cap, 20u, 30u).size() == 30u, "");
+        static_assert(TestRange(&cap, 20u, 30u).endOffset() == 50u, "");
+
+        static_assert(TestRange(&cap, 200u, 30u).capacity() == 123u, "");
+        static_assert(TestRange(&cap, 200u, 30u).offset() == 123u, "");
+        static_assert(TestRange(&cap, 200u, 30u).size() == 0u, "");
+        static_assert(TestRange(&cap, 200u, 30u).endOffset() == 123u, "");
+
+    }
+
+};
+
+
 class C2BufferTest : public ::testing::Test {
 public:
     C2BufferTest()
@@ -180,6 +383,14 @@
         data[i] = i % 100u;
     }
 
+    writeView.setOffset(kCapacity / 3);
+    data = writeView.data();
+    ASSERT_NE(nullptr, data);
+    for (size_t i = 0; i < writeView.size(); ++i) {
+        ASSERT_EQ((i + kCapacity / 3) % 100u, data[i]) << " at i = " << i
+            << "; data = " << static_cast<void *>(data);
+    }
+
     C2Fence fence;
     C2ConstLinearBlock constBlock = block->share(
             kCapacity / 3, kCapacity / 3, fence);
diff --git a/media/libstagefright/codec2/vndk/C2AllocatorGralloc.cpp b/media/libstagefright/codec2/vndk/C2AllocatorGralloc.cpp
index 155583d..b287ca8 100644
--- a/media/libstagefright/codec2/vndk/C2AllocatorGralloc.cpp
+++ b/media/libstagefright/codec2/vndk/C2AllocatorGralloc.cpp
@@ -25,6 +25,7 @@
 
 #include <C2AllocatorGralloc.h>
 #include <C2Buffer.h>
+#include <C2PlatformSupport.h>
 
 namespace android {
 
@@ -185,7 +186,7 @@
             C2Rect rect, C2MemoryUsage usage, int *fenceFd,
             C2PlanarLayout *layout /* nonnull */, uint8_t **addr /* nonnull */) override;
     virtual c2_status_t unmap(C2Fence *fenceFd /* nullable */) override;
-    virtual bool isValid() const override { return true; }
+    virtual C2Allocator::id_t getAllocatorId() const override { return mAllocatorId; }
     virtual const C2Handle *handle() const override { return mLockedHandle ? : mHandle; }
     virtual bool equals(const std::shared_ptr<const C2GraphicAllocation> &other) const override;
 
@@ -195,7 +196,8 @@
               const BufferDescriptorInfo &info,
               const sp<IMapper> &mapper,
               hidl_handle &hidlHandle,
-              const C2HandleGralloc *const handle);
+              const C2HandleGralloc *const handle,
+              C2Allocator::id_t allocatorId);
     int dup() const;
     c2_status_t status() const;
 
@@ -207,20 +209,24 @@
     buffer_handle_t mBuffer;
     const C2HandleGralloc *mLockedHandle;
     bool mLocked;
+    C2Allocator::id_t mAllocatorId;
 };
 
 C2AllocationGralloc::C2AllocationGralloc(
           const BufferDescriptorInfo &info,
           const sp<IMapper> &mapper,
           hidl_handle &hidlHandle,
-          const C2HandleGralloc *const handle)
+          const C2HandleGralloc *const handle,
+          C2Allocator::id_t allocatorId)
     : C2GraphicAllocation(info.mapperInfo.width, info.mapperInfo.height),
       mInfo(info),
       mMapper(mapper),
       mHidlHandle(std::move(hidlHandle)),
       mHandle(handle),
       mBuffer(nullptr),
-      mLocked(false) {}
+      mLocked(false),
+      mAllocatorId(allocatorId) {
+}
 
 C2AllocationGralloc::~C2AllocationGralloc() {
     if (!mBuffer) {
@@ -422,11 +428,19 @@
 /* ===================================== GRALLOC ALLOCATOR ==================================== */
 class C2AllocatorGralloc::Impl {
 public:
-    Impl();
+    Impl(id_t id);
 
-    id_t getId() const;
+    id_t getId() const {
+        return mTraits->id;
+    }
 
-    C2String getName() const;
+    C2String getName() const {
+        return mTraits->name;
+    }
+
+    std::shared_ptr<const C2Allocator::Traits> getTraits() const {
+        return mTraits;
+    }
 
     c2_status_t newGraphicAllocation(
             uint32_t width, uint32_t height, uint32_t format, const C2MemoryUsage &usage,
@@ -439,13 +453,19 @@
     c2_status_t status() const { return mInit; }
 
 private:
+    std::shared_ptr<C2Allocator::Traits> mTraits;
     c2_status_t mInit;
     sp<IAllocator> mAllocator;
     sp<IMapper> mMapper;
 };
 
-C2AllocatorGralloc::Impl::Impl() : mInit(C2_OK) {
-    // TODO: share a global service
+C2AllocatorGralloc::Impl::Impl(id_t id) : mInit(C2_OK) {
+    // TODO: get this from allocator
+    C2MemoryUsage minUsage = { 0, 0 }, maxUsage = { ~(uint64_t)0, ~(uint64_t)0 };
+    Traits traits = { "android.allocator.gralloc", id, C2Allocator::GRAPHIC, minUsage, maxUsage };
+    mTraits = std::make_shared<C2Allocator::Traits>(traits);
+
+    // gralloc allocator is a singleton, so all objects share a global service
     mAllocator = IAllocator::getService();
     mMapper = IMapper::getService();
     if (mAllocator == nullptr || mMapper == nullptr) {
@@ -453,14 +473,6 @@
     }
 }
 
-C2Allocator::id_t C2AllocatorGralloc::Impl::getId() const {
-    return 1; /// \todo implement ID
-}
-
-C2String C2AllocatorGralloc::Impl::getName() const {
-    return "android.allocator.gralloc";
-}
-
 c2_status_t C2AllocatorGralloc::Impl::newGraphicAllocation(
         uint32_t width, uint32_t height, uint32_t format, const C2MemoryUsage &usage,
         std::shared_ptr<C2GraphicAllocation> *allocation) {
@@ -517,7 +529,8 @@
             C2HandleGralloc::WrapNativeHandle(
                     buffer.getNativeHandle(),
                     info.mapperInfo.width, info.mapperInfo.height,
-                    (uint32_t)info.mapperInfo.format, info.mapperInfo.usage, info.stride)));
+                    (uint32_t)info.mapperInfo.format, info.mapperInfo.usage, info.stride),
+            mTraits->id));
     return C2_OK;
 }
 
@@ -536,11 +549,11 @@
 
     hidl_handle hidlHandle = C2HandleGralloc::UnwrapNativeHandle(grallocHandle);
 
-    allocation->reset(new C2AllocationGralloc(info, mMapper, hidlHandle, grallocHandle));
+    allocation->reset(new C2AllocationGralloc(info, mMapper, hidlHandle, grallocHandle, mTraits->id));
     return C2_OK;
 }
 
-C2AllocatorGralloc::C2AllocatorGralloc(id_t) : mImpl(new Impl) {}
+C2AllocatorGralloc::C2AllocatorGralloc(id_t id) : mImpl(new Impl(id)) {}
 
 C2AllocatorGralloc::~C2AllocatorGralloc() { delete mImpl; }
 
@@ -552,6 +565,10 @@
     return mImpl->getName();
 }
 
+std::shared_ptr<const C2Allocator::Traits> C2AllocatorGralloc::getTraits() const {
+    return mImpl->getTraits();
+}
+
 c2_status_t C2AllocatorGralloc::newGraphicAllocation(
         uint32_t width, uint32_t height, uint32_t format, C2MemoryUsage usage,
         std::shared_ptr<C2GraphicAllocation> *allocation) {
diff --git a/media/libstagefright/codec2/vndk/C2Buffer.cpp b/media/libstagefright/codec2/vndk/C2Buffer.cpp
index ff92679..0de8cde 100644
--- a/media/libstagefright/codec2/vndk/C2Buffer.cpp
+++ b/media/libstagefright/codec2/vndk/C2Buffer.cpp
@@ -19,6 +19,7 @@
 #include <utils/Log.h>
 
 #include <map>
+#include <mutex>
 
 #include <C2BufferPriv.h>
 #include <C2BlockInternal.h>
@@ -61,33 +62,33 @@
     friend class ::android::C2LinearBlock;
 };
 
-class C2DefaultGraphicView : public C2GraphicView {
+class GraphicViewBuddy : public C2GraphicView {
     using C2GraphicView::C2GraphicView;
     friend class ::android::C2ConstGraphicBlock;
     friend class ::android::C2GraphicBlock;
 };
 
-class C2AcquirableConstGraphicView : public C2Acquirable<const C2GraphicView> {
+class AcquirableConstGraphicViewBuddy : public C2Acquirable<const C2GraphicView> {
     using C2Acquirable::C2Acquirable;
     friend class ::android::C2ConstGraphicBlock;
 };
 
-class C2AcquirableGraphicView : public C2Acquirable<C2GraphicView> {
+class AcquirableGraphicViewBuddy : public C2Acquirable<C2GraphicView> {
     using C2Acquirable::C2Acquirable;
     friend class ::android::C2GraphicBlock;
 };
 
-class C2DefaultConstGraphicBlock : public C2ConstGraphicBlock {
+class ConstGraphicBlockBuddy : public C2ConstGraphicBlock {
     using C2ConstGraphicBlock::C2ConstGraphicBlock;
     friend class ::android::C2GraphicBlock;
 };
 
-class C2DefaultGraphicBlock : public C2GraphicBlock {
+class GraphicBlockBuddy : public C2GraphicBlock {
     using C2GraphicBlock::C2GraphicBlock;
     friend class ::android::C2BasicGraphicBlockPool;
 };
 
-class C2DefaultBufferData : public C2BufferData {
+class BufferDataBuddy : public C2BufferData {
     using C2BufferData::C2BufferData;
     friend class ::android::C2Buffer;
 };
@@ -241,10 +242,11 @@
 C2WriteView::C2WriteView(std::shared_ptr<Impl> impl)
 // UGLY: _C2LinearRangeAspect requires a bona-fide object for capacity to prevent spoofing, so
 // this is what we have to do.
-    : _C2EditableLinearRange(std::make_unique<C2LinearCapacity>(impl->size()).get()), mImpl(impl) { }
+// TODO: use childRange
+    : _C2EditableLinearRangeAspect(std::make_unique<C2LinearCapacity>(impl->size()).get()), mImpl(impl) { }
 
 C2WriteView::C2WriteView(c2_status_t error)
-    : _C2EditableLinearRange(nullptr), mImpl(std::make_shared<Impl>(error)) {}
+    : _C2EditableLinearRangeAspect(nullptr), mImpl(std::make_shared<Impl>(error)) {}
 
 uint8_t *C2WriteView::base() { return mImpl->data(); }
 
@@ -309,14 +311,6 @@
     return ConstLinearBlockBuddy(mImpl, C2LinearRange(*this, offset_, size_), fence);
 }
 
-std::shared_ptr<C2LinearBlock> _C2BlockFactory::CreateLinearBlock(
-        const std::shared_ptr<C2LinearAllocation> &alloc,
-        const std::shared_ptr<_C2BlockPoolData> &data, size_t offset, size_t size) {
-    std::shared_ptr<C2Block1D::Impl> impl =
-        std::make_shared<C2Block1D::Impl>(alloc, data, offset, size);
-    return std::shared_ptr<C2LinearBlock>(new C2LinearBlock(impl, *impl));
-}
-
 C2BasicLinearBlockPool::C2BasicLinearBlockPool(
         const std::shared_ptr<C2Allocator> &allocator)
   : mAllocator(allocator) { }
@@ -338,215 +332,288 @@
     return C2_OK;
 }
 
+std::shared_ptr<C2LinearBlock> _C2BlockFactory::CreateLinearBlock(
+        const std::shared_ptr<C2LinearAllocation> &alloc,
+        const std::shared_ptr<_C2BlockPoolData> &data, size_t offset, size_t size) {
+    std::shared_ptr<C2Block1D::Impl> impl =
+        std::make_shared<C2Block1D::Impl>(alloc, data, offset, size);
+    return std::shared_ptr<C2LinearBlock>(new C2LinearBlock(impl, *impl));
+}
+
 /* ========================================== 2D BLOCK ========================================= */
 
-class C2Block2D::Impl {
+/**
+ * Implementation that is shared between all 2D blocks and views.
+ *
+ * For blocks' Impl's crop is always the allotted crop, even if it is a sub block.
+ *
+ * For views' Impl's crop is the mapped portion - which for now is always the
+ * allotted crop.
+ */
+class C2_HIDE _C2Block2DImpl : public _C2PlanarSectionAspect {
 public:
-    const C2Handle *handle() const {
-        return mAllocation->handle();
+    /**
+     * Impl's crop is always the or part of the allotted crop of the allocation.
+     */
+    _C2Block2DImpl(const std::shared_ptr<C2GraphicAllocation> &alloc,
+            const std::shared_ptr<_C2BlockPoolData> &poolData = nullptr,
+            const C2Rect &allottedCrop = C2Rect(~0u, ~0u))
+        : _C2PlanarSectionAspect(alloc.get(), allottedCrop),
+          mAllocation(alloc),
+          mPoolData(poolData) { }
+
+    /** returns const pool data  */
+    std::shared_ptr<const _C2BlockPoolData> poolData() const {
+        return mPoolData;
     }
 
-    Impl(const std::shared_ptr<C2GraphicAllocation> &alloc)
-        : mAllocation(alloc) {}
+    /** returns native handle */
+    const C2Handle *handle() const {
+        return mAllocation ? mAllocation->handle() : nullptr;
+    }
+
+    /** returns the allocator's ID */
+    C2Allocator::id_t getAllocatorId() const {
+        // BAD_ID can only happen if this Impl class is initialized for a view - never for a block.
+        return mAllocation ? mAllocation->getAllocatorId() : C2Allocator::BAD_ID;
+    }
+
+    std::shared_ptr<C2GraphicAllocation> getAllocation() const {
+        return mAllocation;
+    }
 
 private:
     std::shared_ptr<C2GraphicAllocation> mAllocation;
+    std::shared_ptr<_C2BlockPoolData> mPoolData;
 };
 
-C2Block2D::C2Block2D(const std::shared_ptr<C2GraphicAllocation> &alloc)
-    : _C2PlanarSection(alloc.get()), mImpl(new Impl(alloc)) {}
+class C2_HIDE _C2MappingBlock2DImpl : public _C2Block2DImpl {
+public:
+    using _C2Block2DImpl::_C2Block2DImpl;
+
+    /**
+     * This class contains the mapped data pointer, and the potential error.
+     */
+    struct Mapped {
+    private:
+        friend class _C2MappingBlock2DImpl;
+
+        Mapped(const _C2Block2DImpl *impl, bool writable, C2Fence *fence __unused)
+            : mImpl(impl), mWritable(writable) {
+            memset(mData, 0, sizeof(mData));
+            const C2Rect crop = mImpl->crop();
+            // gralloc requires mapping the whole region of interest as we cannot
+            // map multiple regions
+            mError = mImpl->getAllocation()->map(
+                    crop,
+                    { C2MemoryUsage::CPU_READ, writable ? C2MemoryUsage::CPU_WRITE : 0 },
+                    nullptr,
+                    &mLayout,
+                    mData);
+            if (mError != C2_OK) {
+                memset(&mLayout, 0, sizeof(mLayout));
+                memset(mData, 0, sizeof(mData));
+            } else {
+                // TODO: validate plane layout and
+                // adjust data pointers to the crop region's top left corner.
+                // fail if it is not on a subsampling boundary
+                for (size_t planeIx = 0; planeIx < mLayout.numPlanes; ++planeIx) {
+                    const uint32_t colSampling = mLayout.planes[planeIx].colSampling;
+                    const uint32_t rowSampling = mLayout.planes[planeIx].rowSampling;
+                    if (crop.left % colSampling || crop.right() % colSampling
+                            || crop.top % rowSampling || crop.bottom() % rowSampling) {
+                        // cannot calculate data pointer
+                        mImpl->getAllocation()->unmap(nullptr);
+                        memset(&mLayout, 0, sizeof(mLayout));
+                        memset(mData, 0, sizeof(mData));
+                        mError = C2_BAD_VALUE;
+                        return;
+                    }
+                    mData[planeIx] += (ssize_t)crop.left * mLayout.planes[planeIx].colInc
+                            + (ssize_t)crop.top * mLayout.planes[planeIx].rowInc;
+                }
+            }
+        }
+
+        explicit Mapped(c2_status_t error)
+            : mImpl(nullptr), mWritable(false), mError(error) {
+            // CHECK(error != C2_OK);
+            memset(&mLayout, 0, sizeof(mLayout));
+            memset(mData, 0, sizeof(mData));
+        }
+
+    public:
+        ~Mapped() {
+            if (mData[0] != nullptr) {
+                mImpl->getAllocation()->unmap(nullptr);
+            }
+        }
+
+        /** returns mapping status */
+        c2_status_t error() const { return mError; }
+
+        /** returns data pointer */
+        uint8_t *const *data() const { return mData; }
+
+        /** returns the plane layout */
+        C2PlanarLayout layout() const { return mLayout; }
+
+        /** returns whether the mapping is writable */
+        bool writable() const { return mWritable; }
+
+    private:
+        const _C2Block2DImpl *mImpl;
+        bool mWritable;
+        c2_status_t mError;
+        uint8_t *mData[C2PlanarLayout::MAX_NUM_PLANES];
+        C2PlanarLayout mLayout;
+    };
+
+    /**
+     * Maps the allotted region.
+     *
+     * If already mapped and it is currently in use, returns the existing mapping.
+     * If fence is provided, an acquire fence is stored there.
+     */
+    std::shared_ptr<Mapped> map(bool writable, C2Fence *fence) {
+        std::lock_guard<std::mutex> lock(mMappedLock);
+        std::shared_ptr<Mapped> existing = mMapped.lock();
+        if (!existing) {
+            existing = std::shared_ptr<Mapped>(new Mapped(this, writable, fence));
+            mMapped = existing;
+        } else {
+            // if we mapped the region read-only, we cannot remap it read-write
+            if (writable && !existing->writable()) {
+                existing = std::shared_ptr<Mapped>(new Mapped(C2_CANNOT_DO));
+            }
+            if (fence != nullptr) {
+                *fence = C2Fence();
+            }
+        }
+        return existing;
+    }
+
+private:
+    std::weak_ptr<Mapped> mMapped;
+    std::mutex mMappedLock;
+};
+
+class C2_HIDE _C2MappedBlock2DImpl : public _C2Block2DImpl {
+public:
+    _C2MappedBlock2DImpl(const _C2Block2DImpl &impl,
+                         std::shared_ptr<_C2MappingBlock2DImpl::Mapped> mapping)
+        : _C2Block2DImpl(impl), mMapping(mapping) {
+    }
+
+    std::shared_ptr<_C2MappingBlock2DImpl::Mapped> mapping() const { return mMapping; }
+
+private:
+    std::shared_ptr<_C2MappingBlock2DImpl::Mapped> mMapping;
+};
+
+/**
+ * Block implementation.
+ */
+class C2Block2D::Impl : public _C2MappingBlock2DImpl {
+    using _C2MappingBlock2DImpl::_C2MappingBlock2DImpl;
+};
 
 const C2Handle *C2Block2D::handle() const {
     return mImpl->handle();
 }
 
-class C2GraphicView::Impl {
-public:
-    Impl(uint8_t *const *data, const C2PlanarLayout &layout)
-        : mData(data), mLayout(layout), mError(C2_OK) {}
-    explicit Impl(c2_status_t error) : mData(nullptr), mError(error) {}
+C2Allocator::id_t C2Block2D::getAllocatorId() const {
+    return mImpl->getAllocatorId();
+}
 
-    uint8_t *const *data() const { return mData; }
-    const C2PlanarLayout &layout() const { return mLayout; }
-    c2_status_t error() const { return mError; }
+C2Block2D::C2Block2D(std::shared_ptr<Impl> impl, const _C2PlanarSectionAspect &section)
+    // always clamp subsection to parent (impl) crop for safety
+    : _C2PlanarSectionAspect(impl.get(), section.crop()), mImpl(impl) {
+}
 
-private:
-    uint8_t *const *mData;
-    C2PlanarLayout mLayout;
-    c2_status_t mError;
+/**
+ * Graphic view implementation.
+ *
+ * range of Impl is the mapped range of the underlying allocation. range of View is the current
+ * crop.
+ */
+class C2GraphicView::Impl : public _C2MappedBlock2DImpl {
+    using _C2MappedBlock2DImpl::_C2MappedBlock2DImpl;
 };
 
-C2GraphicView::C2GraphicView(
-        const _C2PlanarCapacityAspect *parent,
-        uint8_t *const *data,
-        const C2PlanarLayout& layout)
-    : _C2PlanarSection(parent), mImpl(new Impl(data, layout)) {}
-
-C2GraphicView::C2GraphicView(c2_status_t error)
-    : _C2PlanarSection(nullptr), mImpl(new Impl(error)) {}
+C2GraphicView::C2GraphicView(std::shared_ptr<Impl> impl, const _C2PlanarSectionAspect &section)
+    : _C2EditablePlanarSectionAspect(impl.get(), section.crop()), mImpl(impl) {
+}
 
 const uint8_t *const *C2GraphicView::data() const {
-    return mImpl->data();
+    return mImpl->mapping()->data();
 }
 
 uint8_t *const *C2GraphicView::data() {
-    return mImpl->data();
+    return mImpl->mapping()->data();
 }
 
 const C2PlanarLayout C2GraphicView::layout() const {
-    return mImpl->layout();
+    return mImpl->mapping()->layout();
 }
 
 const C2GraphicView C2GraphicView::subView(const C2Rect &rect) const {
-    C2GraphicView view(this, mImpl->data(), mImpl->layout());
-    view.setCrop_be(rect);
-    return view;
+    return C2GraphicView(mImpl, C2PlanarSection(*mImpl, rect));
 }
 
 C2GraphicView C2GraphicView::subView(const C2Rect &rect) {
-    C2GraphicView view(this, mImpl->data(), mImpl->layout());
-    view.setCrop_be(rect);
-    return view;
+    return C2GraphicView(mImpl, C2PlanarSection(*mImpl, rect));
 }
 
 c2_status_t C2GraphicView::error() const {
-    return mImpl->error();
+    return mImpl->mapping()->error();
 }
 
-class C2ConstGraphicBlock::Impl {
-public:
-    explicit Impl(const std::shared_ptr<C2GraphicAllocation> &alloc)
-        : mAllocation(alloc), mData{ nullptr } {}
-
-    ~Impl() {
-        if (mData[0] != nullptr) {
-            // TODO: fence
-            mAllocation->unmap(nullptr);
-        }
-    }
-
-    c2_status_t map(C2Rect rect) {
-        if (mData[0] != nullptr) {
-            // Already mapped.
-            return C2_OK;
-        }
-        c2_status_t err = mAllocation->map(
-                rect,
-                { C2MemoryUsage::CPU_READ, 0 },
-                nullptr,
-                &mLayout,
-                mData);
-        if (err != C2_OK) {
-            memset(mData, 0, sizeof(mData));
-        }
-        return err;
-    }
-
-    C2ConstGraphicBlock subBlock(const C2Rect &rect, C2Fence fence) const {
-        C2ConstGraphicBlock block(mAllocation, fence);
-        block.setCrop_be(rect);
-        return block;
-    }
-
-    uint8_t *const *data() const {
-        return mData[0] == nullptr ? nullptr : &mData[0];
-    }
-
-    const C2PlanarLayout &layout() const { return mLayout; }
-
-private:
-    std::shared_ptr<C2GraphicAllocation> mAllocation;
-    C2PlanarLayout mLayout;
-    uint8_t *mData[C2PlanarLayout::MAX_NUM_PLANES];
-};
-
+/**
+ * Const graphic block implementation.
+ */
 C2ConstGraphicBlock::C2ConstGraphicBlock(
-        const std::shared_ptr<C2GraphicAllocation> &alloc, C2Fence fence)
-    : C2Block2D(alloc), mImpl(new Impl(alloc)), mFence(fence) {}
+        std::shared_ptr<Impl> impl, const _C2PlanarSectionAspect &section, C2Fence fence)
+    : C2Block2D(impl, section), mFence(fence) { }
 
 C2Acquirable<const C2GraphicView> C2ConstGraphicBlock::map() const {
-    c2_status_t err = mImpl->map(crop());
-    if (err != C2_OK) {
-        C2DefaultGraphicView view(err);
-        return C2AcquirableConstGraphicView(err, mFence, view);
-    }
-    C2DefaultGraphicView view(this, mImpl->data(), mImpl->layout());
-    return C2AcquirableConstGraphicView(err, mFence, view);
+    C2Fence fence;
+    std::shared_ptr<_C2MappingBlock2DImpl::Mapped> mapping =
+        mImpl->map(false /* writable */, &fence);
+    std::shared_ptr<GraphicViewBuddy::Impl> gvi =
+        std::shared_ptr<GraphicViewBuddy::Impl>(new GraphicViewBuddy::Impl(*mImpl, mapping));
+    return AcquirableConstGraphicViewBuddy(
+            mapping->error(), fence, GraphicViewBuddy(gvi, C2PlanarSection(*mImpl, crop())));
 }
 
 C2ConstGraphicBlock C2ConstGraphicBlock::subBlock(const C2Rect &rect) const {
-    return mImpl->subBlock(rect, mFence);
+    return C2ConstGraphicBlock(mImpl, C2PlanarSection(*mImpl, crop().intersect(rect)), mFence);
 }
 
-class C2GraphicBlock::Impl {
-public:
-    explicit Impl(const std::shared_ptr<C2GraphicAllocation> &alloc)
-        : mAllocation(alloc), mData{ nullptr } {}
-
-    ~Impl() {
-        if (mData[0] != nullptr) {
-            // TODO: fence
-            mAllocation->unmap(nullptr);
-        }
-    }
-
-    c2_status_t map(C2Rect rect) {
-        if (mData[0] != nullptr) {
-            // Already mapped.
-            return C2_OK;
-        }
-        uint8_t *data[C2PlanarLayout::MAX_NUM_PLANES];
-        c2_status_t err = mAllocation->map(
-                rect,
-                { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE },
-                nullptr,
-                &mLayout,
-                data);
-        if (err == C2_OK) {
-            memcpy(mData, data, sizeof(mData));
-        } else {
-            memset(mData, 0, sizeof(mData));
-        }
-        return err;
-    }
-
-    C2ConstGraphicBlock share(const C2Rect &crop, C2Fence fence) const {
-        C2DefaultConstGraphicBlock block(mAllocation, fence);
-        block.setCrop_be(crop);
-        return block;
-    }
-
-    uint8_t *const *data() const {
-        return mData[0] == nullptr ? nullptr : mData;
-    }
-
-    const C2PlanarLayout &layout() const { return mLayout; }
-
-private:
-    std::shared_ptr<C2GraphicAllocation> mAllocation;
-    C2PlanarLayout mLayout;
-    uint8_t *mData[C2PlanarLayout::MAX_NUM_PLANES];
-};
-
-C2GraphicBlock::C2GraphicBlock(const std::shared_ptr<C2GraphicAllocation> &alloc)
-    : C2Block2D(alloc), mImpl(new Impl(alloc)) {}
+/**
+ * Graphic block implementation.
+ */
+C2GraphicBlock::C2GraphicBlock(
+    std::shared_ptr<Impl> impl, const _C2PlanarSectionAspect &section)
+    : C2Block2D(impl, section) { }
 
 C2Acquirable<C2GraphicView> C2GraphicBlock::map() {
-    c2_status_t err = mImpl->map(crop());
-    if (err != C2_OK) {
-        C2DefaultGraphicView view(err);
-        // TODO: fence
-        return C2AcquirableGraphicView(err, C2Fence(), view);
-    }
-    C2DefaultGraphicView view(this, mImpl->data(), mImpl->layout());
-    // TODO: fence
-    return C2AcquirableGraphicView(err, C2Fence(), view);
+    C2Fence fence;
+    std::shared_ptr<_C2MappingBlock2DImpl::Mapped> mapping =
+        mImpl->map(true /* writable */, &fence);
+    std::shared_ptr<GraphicViewBuddy::Impl> gvi =
+        std::shared_ptr<GraphicViewBuddy::Impl>(new GraphicViewBuddy::Impl(*mImpl, mapping));
+    return AcquirableGraphicViewBuddy(
+            mapping->error(), fence, GraphicViewBuddy(gvi, C2PlanarSection(*mImpl, crop())));
 }
 
 C2ConstGraphicBlock C2GraphicBlock::share(const C2Rect &crop, C2Fence fence) {
-    return mImpl->share(crop, fence);
+    return ConstGraphicBlockBuddy(mImpl, C2PlanarSection(*mImpl, crop), fence);
 }
 
+/**
+ * Basic block pool implementations.
+ */
 C2BasicGraphicBlockPool::C2BasicGraphicBlockPool(
         const std::shared_ptr<C2Allocator> &allocator)
   : mAllocator(allocator) {}
@@ -565,11 +632,19 @@
         return err;
     }
 
-    block->reset(new C2DefaultGraphicBlock(alloc));
+    *block = _C2BlockFactory::CreateGraphicBlock(alloc);
 
     return C2_OK;
 }
 
+std::shared_ptr<C2GraphicBlock> _C2BlockFactory::CreateGraphicBlock(
+        const std::shared_ptr<C2GraphicAllocation> &alloc,
+        const std::shared_ptr<_C2BlockPoolData> &data, const C2Rect &allottedCrop) {
+    std::shared_ptr<C2Block2D::Impl> impl =
+        std::make_shared<C2Block2D::Impl>(alloc, data, allottedCrop);
+    return std::shared_ptr<C2GraphicBlock>(new C2GraphicBlock(impl, *impl));
+}
+
 /* ========================================== BUFFER ========================================= */
 
 class C2BufferData::Impl {
@@ -679,7 +754,7 @@
 
 private:
     C2Buffer * const mThis;
-    C2DefaultBufferData mData;
+    BufferDataBuddy mData;
     std::map<C2Param::Type, std::shared_ptr<C2Info>> mInfos;
     std::list<std::pair<OnDestroyNotify, void *>> mNotify;
 };
diff --git a/media/libstagefright/codec2/vndk/include/C2AllocatorGralloc.h b/media/libstagefright/codec2/vndk/include/C2AllocatorGralloc.h
index 0e1a3ac..9dc7152 100644
--- a/media/libstagefright/codec2/vndk/include/C2AllocatorGralloc.h
+++ b/media/libstagefright/codec2/vndk/include/C2AllocatorGralloc.h
@@ -49,9 +49,7 @@
 
     virtual C2String getName() const override;
 
-    virtual std::shared_ptr<const Traits> getTraits() const override {
-        return nullptr; // \todo
-    }
+    virtual std::shared_ptr<const Traits> getTraits() const override;
 
     virtual c2_status_t newGraphicAllocation(
             uint32_t width, uint32_t height, uint32_t format, C2MemoryUsage usage,
@@ -61,7 +59,7 @@
             const C2Handle *handle,
             std::shared_ptr<C2GraphicAllocation> *allocation) override;
 
-    C2AllocatorGralloc(id_t id = 0);
+    C2AllocatorGralloc(id_t id);
 
     c2_status_t status() const;
 
diff --git a/media/libstagefright/codec2/vndk/internal/C2BlockInternal.h b/media/libstagefright/codec2/vndk/internal/C2BlockInternal.h
index c84d1fb..9c68369 100644
--- a/media/libstagefright/codec2/vndk/internal/C2BlockInternal.h
+++ b/media/libstagefright/codec2/vndk/internal/C2BlockInternal.h
@@ -24,15 +24,44 @@
 struct _C2BlockPoolData;
 
 /**
- * Interface for creating blocks by block pool/buffer passing implementations.
+ * Internal only interface for creating blocks by block pool/buffer passing implementations.
+ *
+ * \todo this must be hidden
  */
-struct C2_HIDE _C2BlockFactory {
+struct _C2BlockFactory {
+    /**
+     * Create a linear block from an allocation for an allotted range.
+     *
+     * @param alloc parent allocation
+     * @param data  blockpool data
+     * @param offset allotted range offset
+     * @param size  allotted size
+     *
+     * @return shared pointer to the linear block. nullptr if there was not enough memory to
+     *         create this block.
+     */
     static
     std::shared_ptr<C2LinearBlock> C2_HIDE CreateLinearBlock(
             const std::shared_ptr<C2LinearAllocation> &alloc,
             const std::shared_ptr<_C2BlockPoolData> &data = nullptr,
             size_t offset = 0,
             size_t size = ~(size_t)0);
+
+    /**
+     * Create a graphic block from an allocation for an allotted section.
+     *
+     * @param alloc parent allocation
+     * @param data  blockpool data
+     * @param crop  allotted crop region
+     *
+     * @return shared pointer to the graphic block. nullptr if there was not enough memory to
+     *         create this block.
+     */
+    static
+    std::shared_ptr<C2GraphicBlock> CreateGraphicBlock(
+            const std::shared_ptr<C2GraphicAllocation> &alloc,
+            const std::shared_ptr<_C2BlockPoolData> &data = nullptr,
+            const C2Rect &allottedCrop = C2Rect(~0u, ~0u));
 };
 
 }
diff --git a/media/ndk/NdkMediaDataSource.cpp b/media/ndk/NdkMediaDataSource.cpp
index 0cae6f4..f190f80 100644
--- a/media/ndk/NdkMediaDataSource.cpp
+++ b/media/ndk/NdkMediaDataSource.cpp
@@ -40,6 +40,7 @@
     void *userdata;
     AMediaDataSourceReadAt readAt;
     AMediaDataSourceGetSize getSize;
+    AMediaDataSourceClose close;
 };
 
 NdkDataSource::NdkDataSource(AMediaDataSource *dataSource)
@@ -77,6 +78,12 @@
     return String8("application/octet-stream");
 }
 
+void NdkDataSource::close() {
+    if (mDataSource->close != NULL && mDataSource->userdata != NULL) {
+        mDataSource->close(mDataSource->userdata);
+    }
+}
+
 extern "C" {
 
 EXPORT
@@ -85,6 +92,7 @@
     mSource->userdata = NULL;
     mSource->readAt = NULL;
     mSource->getSize = NULL;
+    mSource->close = NULL;
     return mSource;
 }
 
@@ -111,5 +119,10 @@
     mSource->getSize = getSize;
 }
 
+EXPORT
+void AMediaDataSource_setClose(AMediaDataSource *mSource, AMediaDataSourceClose close) {
+    mSource->close = close;
+}
+
 } // extern "C"
 
diff --git a/media/ndk/NdkMediaDataSourcePriv.h b/media/ndk/NdkMediaDataSourcePriv.h
index a1cb331..65ddd2a 100644
--- a/media/ndk/NdkMediaDataSourcePriv.h
+++ b/media/ndk/NdkMediaDataSourcePriv.h
@@ -47,6 +47,7 @@
     virtual status_t getSize(off64_t *);
     virtual String8 toString();
     virtual String8 getMIMEType() const;
+    virtual void close();
 
 private:
 
diff --git a/media/ndk/include/media/NdkMediaDataSource.h b/media/ndk/include/media/NdkMediaDataSource.h
index 752b684..9e2e351 100644
--- a/media/ndk/include/media/NdkMediaDataSource.h
+++ b/media/ndk/include/media/NdkMediaDataSource.h
@@ -74,6 +74,13 @@
 typedef ssize_t (*AMediaDataSourceGetSize)(void *userdata);
 
 /**
+ * Called to close the data source and release associated resources.
+ * The NDK media framework guarantees that after |close| is called
+ * no future callbacks will be invoked on the data source.
+ */
+typedef void (*AMediaDataSourceClose)(void *userdata);
+
+/**
  * Create new media data source. Returns NULL if memory allocation
  * for the new data source object fails.
  */
@@ -117,6 +124,17 @@
         AMediaDataSource*,
         AMediaDataSourceGetSize);
 
+/**
+ * Set a custom callback to receive signal from the NDK media framework
+ * when the data source is closed.
+ *
+ * Please refer to the definition of AMediaDataSourceClose for
+ * additional details.
+ */
+void AMediaDataSource_setClose(
+        AMediaDataSource*,
+        AMediaDataSourceClose);
+
 #endif  /*__ANDROID_API__ >= 28 */
 
 __END_DECLS
diff --git a/media/ndk/libmediandk.map.txt b/media/ndk/libmediandk.map.txt
index 37c557a..17c1a0d 100644
--- a/media/ndk/libmediandk.map.txt
+++ b/media/ndk/libmediandk.map.txt
@@ -125,6 +125,7 @@
     AMediaCrypto_requiresSecureDecoderComponent;
     AMediaDataSource_delete;      # introduced=28
     AMediaDataSource_new;         # introduced=28
+    AMediaDataSource_setClose;    # introduced=28
     AMediaDataSource_setGetSize;  # introduced=28
     AMediaDataSource_setReadAt;   # introduced=28
     AMediaDataSource_setUserdata; # introduced=28
diff --git a/packages/MediaComponents/res/layout/mr_controller_material_dialog_b.xml b/packages/MediaComponents/res/layout/mr_controller_material_dialog_b.xml
index 3751002..b304471 100644
--- a/packages/MediaComponents/res/layout/mr_controller_material_dialog_b.xml
+++ b/packages/MediaComponents/res/layout/mr_controller_material_dialog_b.xml
@@ -23,7 +23,7 @@
         android:layout_height="wrap_content"
         android:layout_gravity="center"
         android:orientation="vertical"
-        android:background="?attr/colorBackgroundFloating">
+        android:background="?android:attr/colorBackgroundFloating">
         <LinearLayout android:id="@+id/mr_title_bar"
             android:layout_width="fill_parent"
             android:layout_height="wrap_content"
@@ -44,7 +44,7 @@
                 android:layout_gravity="center_vertical"
                 android:contentDescription="@string/mr_controller_close_description"
                 android:src="?attr/mediaRouteCloseDrawable"
-                android:background="?attr/selectableItemBackgroundBorderless" />
+                android:background="?android:attr/selectableItemBackgroundBorderless" />
         </LinearLayout>
         <FrameLayout android:id="@+id/mr_custom_control"
             android:layout_width="fill_parent"
@@ -58,7 +58,7 @@
                 android:layout_height="wrap_content"
                 android:adjustViewBounds="true"
                 android:scaleType="fitXY"
-                android:background="?attr/colorPrimary"
+                android:background="?android:attr/colorPrimary"
                 android:layout_gravity="top"
                 android:contentDescription="@string/mr_controller_album_art"
                 android:visibility="gone" />
@@ -89,7 +89,7 @@
                             android:layout_alignParentRight="true"
                             android:layout_centerVertical="true"
                             android:contentDescription="@string/mr_controller_play"
-                            android:background="?attr/selectableItemBackgroundBorderless"
+                            android:background="?android:attr/selectableItemBackgroundBorderless"
                             android:visibility="gone" />
                         <LinearLayout android:id="@+id/mr_control_title_container"
                             android:orientation="vertical"
@@ -146,7 +146,7 @@
                             android:layout_width="48dp"
                             android:layout_height="48dp"
                             android:padding="12dp"
-                            android:background="?attr/selectableItemBackgroundBorderless"
+                            android:background="?android:attr/selectableItemBackgroundBorderless"
                             android:visibility="gone"/>
                     </LinearLayout>
                 </LinearLayout>
@@ -181,7 +181,7 @@
                 android:paddingTop="4dp">
                 <Button
                     android:id="@android:id/button3"
-                    style="?attr/buttonBarNeutralButtonStyle"
+                    style="?android:attr/buttonBarNeutralButtonStyle"
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"/>
                 <android.support.v4.widget.Space
@@ -197,7 +197,7 @@
                     android:layout_height="wrap_content"/>
                 <Button
                     android:id="@android:id/button1"
-                    style="?attr/buttonBarPositiveButtonStyle"
+                    style="?android:attr/buttonBarPositiveButtonStyle"
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"/>
             </android.support.v7.widget.ButtonBarLayout>
diff --git a/packages/MediaComponents/src/com/android/media/update/ApiHelper.java b/packages/MediaComponents/src/com/android/media/update/ApiHelper.java
index 06f463f..7018844 100644
--- a/packages/MediaComponents/src/com/android/media/update/ApiHelper.java
+++ b/packages/MediaComponents/src/com/android/media/update/ApiHelper.java
@@ -18,9 +18,12 @@
 
 import android.annotation.Nullable;
 import android.content.Context;
+import android.content.ContextWrapper;
 import android.content.res.Resources;
 import android.content.res.Resources.Theme;
 import android.content.res.XmlResourceParser;
+import android.support.v4.widget.Space;
+import android.support.v7.widget.ButtonBarLayout;
 import android.util.AttributeSet;
 import android.view.ContextThemeWrapper;
 import android.view.LayoutInflater;
@@ -28,6 +31,9 @@
 import android.view.ViewGroup;
 
 import com.android.support.mediarouter.app.MediaRouteButton;
+import com.android.support.mediarouter.app.MediaRouteExpandCollapseButton;
+import com.android.support.mediarouter.app.MediaRouteVolumeSlider;
+import com.android.support.mediarouter.app.OverlayListView;
 
 public class ApiHelper {
     private static ApiHelper sInstance;
@@ -68,6 +74,7 @@
     }
 
     public static LayoutInflater getLayoutInflater(Context context, Theme theme) {
+        // TODO (b/72975976): Avoid to use ContextThemeWrapper with app context and lib theme.
         LayoutInflater layoutInflater = LayoutInflater.from(context).cloneInContext(
                 new ContextThemeWrapper(context, theme));
         layoutInflater.setFactory2(new LayoutInflater.Factory2() {
@@ -76,6 +83,16 @@
                     View parent, String name, Context context, AttributeSet attrs) {
                 if (MediaRouteButton.class.getCanonicalName().equals(name)) {
                     return new MediaRouteButton(context, attrs);
+                } else if (MediaRouteVolumeSlider.class.getCanonicalName().equals(name)) {
+                    return new MediaRouteVolumeSlider(context, attrs);
+                } else if (MediaRouteExpandCollapseButton.class.getCanonicalName().equals(name)) {
+                    return new MediaRouteExpandCollapseButton(context, attrs);
+                } else if (OverlayListView.class.getCanonicalName().equals(name)) {
+                    return new OverlayListView(context, attrs);
+                } else if (ButtonBarLayout.class.getCanonicalName().equals(name)) {
+                    return new ButtonBarLayout(context, attrs);
+                } else if (Space.class.getCanonicalName().equals(name)) {
+                    return new Space(context, attrs);
                 }
                 return null;
             }
diff --git a/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteChooserDialog.java b/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteChooserDialog.java
index aeb4408..6e70eaf 100644
--- a/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteChooserDialog.java
+++ b/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteChooserDialog.java
@@ -98,9 +98,9 @@
     }
 
     public MediaRouteChooserDialog(Context context, int theme) {
+        // TODO (b/72975976): Avoid to use ContextThemeWrapper with app context and lib theme.
         super(new ContextThemeWrapper(context,
-                ApiHelper.getLibTheme(MediaRouterThemeHelper.getRouterThemeId(context))),
-                theme == 0 ? android.R.style.Animation : theme);
+                ApiHelper.getLibTheme(MediaRouterThemeHelper.getRouterThemeId(context))), theme);
         context = getContext();
 
         mRouter = MediaRouter.getInstance(context);
diff --git a/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteControllerDialog.java b/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteControllerDialog.java
index 123ab21..269a6e9 100644
--- a/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteControllerDialog.java
+++ b/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteControllerDialog.java
@@ -21,6 +21,7 @@
 import static android.support.v4.media.session.PlaybackStateCompat.ACTION_PLAY_PAUSE;
 import static android.support.v4.media.session.PlaybackStateCompat.ACTION_STOP;
 
+import android.app.AlertDialog;
 import android.app.PendingIntent;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -41,11 +42,10 @@
 import android.support.v4.media.session.PlaybackStateCompat;
 import android.support.v4.util.ObjectsCompat;
 import android.support.v4.view.accessibility.AccessibilityEventCompat;
-import android.support.v7.app.AlertDialog;
 import android.support.v7.graphics.Palette;
-
 import android.text.TextUtils;
 import android.util.Log;
+import android.view.ContextThemeWrapper;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -72,6 +72,7 @@
 import android.widget.SeekBar;
 import android.widget.TextView;
 
+import com.android.media.update.ApiHelper;
 import com.android.media.update.R;
 import com.android.support.mediarouter.media.MediaRouteSelector;
 import com.android.support.mediarouter.media.MediaRouter;
@@ -204,8 +205,9 @@
     }
 
     public MediaRouteControllerDialog(Context context, int theme) {
-        super(context = MediaRouterThemeHelper.createThemedDialogContext(context, theme, true),
-                MediaRouterThemeHelper.createThemedDialogStyle(context));
+        // TODO (b/72975976): Avoid to use ContextThemeWrapper with app context and lib theme.
+        super(new ContextThemeWrapper(context,
+                ApiHelper.getLibTheme(MediaRouterThemeHelper.getRouterThemeId(context))), theme);
         mContext = getContext();
 
         mControllerCallback = new MediaControllerCallback();
@@ -213,16 +215,14 @@
         mCallback = new MediaRouterCallback();
         mRoute = mRouter.getSelectedRoute();
         setMediaSession(mRouter.getMediaSessionToken());
-        mVolumeGroupListPaddingTop = mContext.getResources().getDimensionPixelSize(
+        mVolumeGroupListPaddingTop = ApiHelper.getLibResources().getDimensionPixelSize(
                 R.dimen.mr_controller_volume_group_list_padding_top);
         mAccessibilityManager =
                 (AccessibilityManager) mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
-        if (android.os.Build.VERSION.SDK_INT >= 21) {
-            mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
-                    R.interpolator.mr_linear_out_slow_in);
-            mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
-                    R.interpolator.mr_fast_out_slow_in);
-        }
+        mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(
+                mContext, android.R.interpolator.linear_out_slow_in);
+        mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(
+                mContext, android.R.interpolator.fast_out_slow_in);
         mAccelerateDecelerateInterpolator = new AccelerateDecelerateInterpolator();
     }
 
@@ -332,7 +332,10 @@
         super.onCreate(savedInstanceState);
 
         getWindow().setBackgroundDrawableResource(android.R.color.transparent);
-        setContentView(R.layout.mr_controller_material_dialog_b);
+
+        setContentView(ApiHelper.inflateLibLayout(mContext,
+                ApiHelper.getLibTheme(MediaRouterThemeHelper.getRouterThemeId(mContext)),
+                R.layout.mr_controller_material_dialog_b));
 
         // Remove the neutral button.
         findViewById(BUTTON_NEUTRAL_RES_ID).setVisibility(View.GONE);
@@ -355,12 +358,14 @@
         });
         int color = MediaRouterThemeHelper.getButtonTextColor(mContext);
         mDisconnectButton = findViewById(BUTTON_DISCONNECT_RES_ID);
-        mDisconnectButton.setText(R.string.mr_controller_disconnect);
+        mDisconnectButton.setText(
+                ApiHelper.getLibResources().getString(R.string.mr_controller_disconnect));
         mDisconnectButton.setTextColor(color);
         mDisconnectButton.setOnClickListener(listener);
 
         mStopCastingButton = findViewById(BUTTON_STOP_RES_ID);
-        mStopCastingButton.setText(R.string.mr_controller_stop_casting);
+        mStopCastingButton.setText(
+                ApiHelper.getLibResources().getString(R.string.mr_controller_stop_casting));
         mStopCastingButton.setTextColor(color);
         mStopCastingButton.setOnClickListener(listener);
 
@@ -435,11 +440,11 @@
             }
         });
         loadInterpolator();
-        mGroupListAnimationDurationMs = mContext.getResources().getInteger(
+        mGroupListAnimationDurationMs = ApiHelper.getLibResources().getInteger(
                 R.integer.mr_controller_volume_group_list_animation_duration_ms);
-        mGroupListFadeInDurationMs = mContext.getResources().getInteger(
+        mGroupListFadeInDurationMs = ApiHelper.getLibResources().getInteger(
                 R.integer.mr_controller_volume_group_list_fade_in_duration_ms);
-        mGroupListFadeOutDurationMs = mContext.getResources().getInteger(
+        mGroupListFadeOutDurationMs = ApiHelper.getLibResources().getInteger(
                 R.integer.mr_controller_volume_group_list_fade_out_duration_ms);
 
         mCustomControlView = onCreateMediaControlView(savedInstanceState);
@@ -461,7 +466,7 @@
         View decorView = getWindow().getDecorView();
         mDialogContentWidth = width - decorView.getPaddingLeft() - decorView.getPaddingRight();
 
-        Resources res = mContext.getResources();
+        Resources res = ApiHelper.getLibResources();
         mVolumeGroupListItemIconSize = res.getDimensionPixelSize(
                 R.dimen.mr_controller_volume_group_list_item_icon_size);
         mVolumeGroupListItemHeight = res.getDimensionPixelSize(
@@ -726,12 +731,8 @@
     }
 
     void loadInterpolator() {
-        if (android.os.Build.VERSION.SDK_INT >= 21) {
-            mInterpolator = mIsGroupExpanded ? mLinearOutSlowInInterpolator
-                    : mFastOutSlowInInterpolator;
-        } else {
-            mInterpolator = mAccelerateDecelerateInterpolator;
-        }
+        mInterpolator =
+                mIsGroupExpanded ? mLinearOutSlowInInterpolator : mFastOutSlowInInterpolator;
     }
 
     private void updateVolumeControlLayout() {
@@ -990,14 +991,17 @@
             if (mRoute.getPresentationDisplayId()
                     != MediaRouter.RouteInfo.PRESENTATION_DISPLAY_ID_NONE) {
                 // The user is currently casting screen.
-                mTitleView.setText(R.string.mr_controller_casting_screen);
+                mTitleView.setText(ApiHelper.getLibResources().getString(
+                        R.string.mr_controller_casting_screen));
                 showTitle = true;
             } else if (mState == null || mState.getState() == PlaybackStateCompat.STATE_NONE) {
                 // Show "No media selected" as we don't yet know the playback state.
-                mTitleView.setText(R.string.mr_controller_no_media_selected);
+                mTitleView.setText(ApiHelper.getLibResources().getString(
+                        R.string.mr_controller_no_media_selected));
                 showTitle = true;
             } else if (!hasTitle && !hasSubtitle) {
-                mTitleView.setText(R.string.mr_controller_no_info_available);
+                mTitleView.setText(ApiHelper.getLibResources().getString(
+                        R.string.mr_controller_no_info_available));
                 showTitle = true;
             } else {
                 if (hasTitle) {
@@ -1219,7 +1223,7 @@
                                 AccessibilityEventCompat.TYPE_ANNOUNCEMENT);
                         event.setPackageName(mContext.getPackageName());
                         event.setClassName(getClass().getName());
-                        event.getText().add(mContext.getString(actionDescResId));
+                        event.getText().add(ApiHelper.getLibResources().getString(actionDescResId));
                         mAccessibilityManager.sendAccessibilityEvent(event);
                     }
                 }
diff --git a/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteExpandCollapseButton.java b/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteExpandCollapseButton.java
index 392b39d..defeedb 100644
--- a/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteExpandCollapseButton.java
+++ b/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteExpandCollapseButton.java
@@ -26,12 +26,13 @@
 import android.view.View;
 import android.widget.ImageButton;
 
+import com.android.media.update.ApiHelper;
 import com.android.media.update.R;
 
 /**
  * Chevron/Caret button to expand/collapse group volume list with animation.
  */
-class MediaRouteExpandCollapseButton extends ImageButton {
+public class MediaRouteExpandCollapseButton extends ImageButton {
     final AnimationDrawable mExpandAnimationDrawable;
     final AnimationDrawable mCollapseAnimationDrawable;
     final String mExpandGroupDescription;
@@ -49,10 +50,10 @@
 
     public MediaRouteExpandCollapseButton(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
-        mExpandAnimationDrawable = (AnimationDrawable) ContextCompat.getDrawable(
-                context, R.drawable.mr_group_expand);
-        mCollapseAnimationDrawable = (AnimationDrawable) ContextCompat.getDrawable(
-                context, R.drawable.mr_group_collapse);
+        mExpandAnimationDrawable = (AnimationDrawable)
+                ApiHelper.getLibResources().getDrawable(R.drawable.mr_group_expand);
+        mCollapseAnimationDrawable = (AnimationDrawable)
+                ApiHelper.getLibResources().getDrawable(R.drawable.mr_group_collapse);
 
         ColorFilter filter = new PorterDuffColorFilter(
                 MediaRouterThemeHelper.getControllerColor(context, defStyleAttr),
@@ -60,8 +61,10 @@
         mExpandAnimationDrawable.setColorFilter(filter);
         mCollapseAnimationDrawable.setColorFilter(filter);
 
-        mExpandGroupDescription = context.getString(R.string.mr_controller_expand_group);
-        mCollapseGroupDescription = context.getString(R.string.mr_controller_collapse_group);
+        mExpandGroupDescription =
+                ApiHelper.getLibResources().getString(R.string.mr_controller_expand_group);
+        mCollapseGroupDescription =
+                ApiHelper.getLibResources().getString(R.string.mr_controller_collapse_group);
 
         setImageDrawable(mExpandAnimationDrawable.getFrame(0));
         setContentDescription(mExpandGroupDescription);
diff --git a/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteVolumeSlider.java b/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteVolumeSlider.java
index 7a34fb5..d05d20e 100644
--- a/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteVolumeSlider.java
+++ b/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteVolumeSlider.java
@@ -20,14 +20,14 @@
 import android.graphics.Color;
 import android.graphics.PorterDuff;
 import android.graphics.drawable.Drawable;
-import android.support.v7.widget.AppCompatSeekBar;
 import android.util.AttributeSet;
 import android.util.Log;
+import android.widget.SeekBar;
 
 /**
  * Volume slider with showing, hiding, and applying alpha supports to the thumb.
  */
-class MediaRouteVolumeSlider extends AppCompatSeekBar {
+public class MediaRouteVolumeSlider extends SeekBar {
     private static final String TAG = "MediaRouteVolumeSlider";
 
     private final float mDisabledAlpha;
@@ -41,7 +41,8 @@
     }
 
     public MediaRouteVolumeSlider(Context context, AttributeSet attrs) {
-        this(context, attrs, android.support.v7.appcompat.R.attr.seekBarStyle);
+        super(context, attrs);
+        mDisabledAlpha = MediaRouterThemeHelper.getDisabledAlpha(context);
     }
 
     public MediaRouteVolumeSlider(Context context, AttributeSet attrs, int defStyleAttr) {
@@ -56,8 +57,10 @@
 
         // The thumb drawable is a collection of drawables and its current drawables are changed per
         // state. Apply the color filter and alpha on every state change.
-        mThumb.setColorFilter(mColor, PorterDuff.Mode.SRC_IN);
-        mThumb.setAlpha(alpha);
+        if (mThumb != null) {
+            mThumb.setColorFilter(mColor, PorterDuff.Mode.SRC_IN);
+            mThumb.setAlpha(alpha);
+        }
 
         getProgressDrawable().setColorFilter(mColor, PorterDuff.Mode.SRC_IN);
         getProgressDrawable().setAlpha(alpha);
diff --git a/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouterThemeHelper.java b/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouterThemeHelper.java
index 7440130..63f042f 100644
--- a/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouterThemeHelper.java
+++ b/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouterThemeHelper.java
@@ -74,9 +74,8 @@
 
         // 2) If no theme is supplied, look it up from the context (dialogTheme/alertDialogTheme)
         if (theme == 0) {
-            theme = getThemeResource(context, !alertDialog
-                    ? android.support.v7.appcompat.R.attr.dialogTheme
-                    : android.support.v7.appcompat.R.attr.alertDialogTheme);
+            theme = getThemeResource(context,
+                    !alertDialog ? android.R.attr.dialogTheme : android.R.attr.alertDialogTheme);
         }
         //    Apply it
         context = new ContextThemeWrapper(context, theme);
@@ -93,7 +92,7 @@
         // 4) Apply the custom Media Router theme
         int theme = getThemeResource(context, R.attr.mediaRouteTheme);
         if (theme == 0) {
-            // 3) No custom MediaRouther theme was provided so apply the base theme instead
+            // 3) No custom MediaRouter theme was provided so apply the base theme instead
             theme = getRouterThemeId(context);
         }
 
@@ -113,8 +112,7 @@
     }
 
     static @ControllerColorType int getControllerColor(Context context, int style) {
-        int primaryColor = getThemeColor(context, style,
-                android.support.v7.appcompat.R.attr.colorPrimary);
+        int primaryColor = getThemeColor(context, style, android.R.attr.colorPrimary);
         if (primaryColor == 0) {
             primaryColor = getThemeColor(context, style, android.R.attr.colorPrimary);
             if (primaryColor == 0) {
@@ -129,23 +127,20 @@
     }
 
     static int getButtonTextColor(Context context) {
-        int primaryColor = getThemeColor(context, 0,
-                android.support.v7.appcompat.R.attr.colorPrimary);
+        int primaryColor = getThemeColor(context, 0, android.R.attr.colorPrimary);
         int backgroundColor = getThemeColor(context, 0, android.R.attr.colorBackground);
 
         if (ColorUtils.calculateContrast(primaryColor, backgroundColor) < MIN_CONTRAST) {
             // Default to colorAccent if the contrast ratio is low.
-            return getThemeColor(context, 0, android.support.v7.appcompat.R.attr.colorAccent);
+            return getThemeColor(context, 0, android.R.attr.colorAccent);
         }
         return primaryColor;
     }
 
     static void setMediaControlsBackgroundColor(
             Context context, View mainControls, View groupControls, boolean hasGroup) {
-        int primaryColor = getThemeColor(context, 0,
-                android.support.v7.appcompat.R.attr.colorPrimary);
-        int primaryDarkColor = getThemeColor(context, 0,
-                android.support.v7.appcompat.R.attr.colorPrimaryDark);
+        int primaryColor = getThemeColor(context, 0, android.R.attr.colorPrimary);
+        int primaryDarkColor = getThemeColor(context, 0, android.R.attr.colorPrimaryDark);
         if (hasGroup && getControllerColor(context, 0) == COLOR_DARK_ON_LIGHT_BACKGROUND) {
             // Instead of showing dark controls in a possibly dark (i.e. the primary dark), model
             // the white dialog and use the primary color for the group controls.
@@ -174,6 +169,7 @@
 
     private static boolean isLightTheme(Context context) {
         TypedValue value = new TypedValue();
+        // TODO(sungsoo): Switch to com.android.internal.R.attr.isLightTheme
         return context.getTheme().resolveAttribute(android.support.v7.appcompat.R.attr.isLightTheme,
                 value, true) && value.data != 0;
     }
diff --git a/packages/MediaComponents/src/com/android/support/mediarouter/app/OverlayListView.java b/packages/MediaComponents/src/com/android/support/mediarouter/app/OverlayListView.java
index 59019ff..b00dee2 100644
--- a/packages/MediaComponents/src/com/android/support/mediarouter/app/OverlayListView.java
+++ b/packages/MediaComponents/src/com/android/support/mediarouter/app/OverlayListView.java
@@ -32,7 +32,7 @@
  * A ListView which has an additional overlay layer. {@link BitmapDrawable}
  * can be added to the layer and can be animated.
  */
-final class OverlayListView extends ListView {
+public final class OverlayListView extends ListView {
     private final List<OverlayObject> mOverlayObjects = new ArrayList<>();
 
     public OverlayListView(Context context) {
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index 1ebaea9..8e112a1 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -122,8 +122,7 @@
 }
 
 binder::Status CameraDeviceClient::insertGbpLocked(const sp<IGraphicBufferProducer>& gbp,
-        SurfaceMap* outSurfaceMap,
-        Vector<int32_t>* outputStreamIds) {
+        SurfaceMap* outSurfaceMap, Vector<int32_t>* outputStreamIds, int32_t *currentStreamId) {
     int idx = mStreamMap.indexOfKey(IInterface::asBinder(gbp));
 
     // Trying to submit request with surface that wasn't created
@@ -146,6 +145,10 @@
             __FUNCTION__, mCameraIdStr.string(), streamSurfaceId.streamId(),
             streamSurfaceId.surfaceId());
 
+    if (currentStreamId != nullptr) {
+        *currentStreamId = streamSurfaceId.streamId();
+    }
+
     return binder::Status::ok();
 }
 
@@ -218,40 +221,6 @@
                     "Invalid camera request settings");
         }
 
-        CameraDeviceBase::PhysicalCameraSettingsList physicalSettingsList;
-        for (const auto& it : request.mPhysicalCameraSettings) {
-            String8 physicalId(it.id.c_str());
-            if ((physicalId != mDevice->getId()) && !checkPhysicalCameraId(physicalId)) {
-                ALOGE("%s: Camera %s: Physical camera id: %s is invalid.", __FUNCTION__,
-                        mCameraIdStr.string(), physicalId.string());
-                return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT,
-                        "Invalid physical camera id");
-            }
-
-            CameraMetadata metadata(it.settings);
-            if (metadata.isEmpty()) {
-                ALOGE("%s: Camera %s: Sent empty metadata packet. Rejecting request.",
-                        __FUNCTION__, mCameraIdStr.string());
-                return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT,
-                        "Request settings are empty");
-            }
-
-            if (!enforceRequestPermissions(metadata)) {
-                // Callee logs
-                return STATUS_ERROR(CameraService::ERROR_PERMISSION_DENIED,
-                        "Caller does not have permission to change restricted controls");
-            }
-
-            physicalSettingsList.push_back({it.id, metadata});
-        }
-
-        if (streaming && (physicalSettingsList.size() > 1)) {
-            ALOGE("%s: Camera %s: Individual physical camera settings are not supported in "
-                    "streaming requests. Rejecting request.", __FUNCTION__, mCameraIdStr.string());
-            return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT,
-                    "Streaming request contains individual physical requests");
-        }
-
         if (request.mSurfaceList.isEmpty() && request.mStreamIdxList.size() == 0) {
             ALOGE("%s: Camera %s: Requests must have at least one surface target. "
                     "Rejecting request.", __FUNCTION__, mCameraIdStr.string());
@@ -265,15 +234,26 @@
          */
         SurfaceMap surfaceMap;
         Vector<int32_t> outputStreamIds;
+        std::vector<std::string> requestedPhysicalIds;
         if (request.mSurfaceList.size() > 0) {
             for (sp<Surface> surface : request.mSurfaceList) {
                 if (surface == 0) continue;
 
+                int32_t streamId;
                 sp<IGraphicBufferProducer> gbp = surface->getIGraphicBufferProducer();
-                res = insertGbpLocked(gbp, &surfaceMap, &outputStreamIds);
+                res = insertGbpLocked(gbp, &surfaceMap, &outputStreamIds, &streamId);
                 if (!res.isOk()) {
                     return res;
                 }
+
+                ssize_t index = mConfiguredOutputs.indexOfKey(streamId);
+                if (index >= 0) {
+                    String8 requestedPhysicalId(
+                            mConfiguredOutputs.valueAt(index).getPhysicalCameraId());
+                    requestedPhysicalIds.push_back(requestedPhysicalId.string());
+                } else {
+                    ALOGW("%s: Output stream Id not found among configured outputs!", __FUNCTION__);
+                }
             }
         } else {
             for (size_t i = 0; i < request.mStreamIdxList.size(); i++) {
@@ -298,13 +278,55 @@
                             "Request targets Surface has invalid surface index");
                 }
 
-                res = insertGbpLocked(gbps[surfaceIdx], &surfaceMap, &outputStreamIds);
+                res = insertGbpLocked(gbps[surfaceIdx], &surfaceMap, &outputStreamIds, nullptr);
                 if (!res.isOk()) {
                     return res;
                 }
+
+                String8 requestedPhysicalId(
+                        mConfiguredOutputs.valueAt(index).getPhysicalCameraId());
+                requestedPhysicalIds.push_back(requestedPhysicalId.string());
             }
         }
 
+        CameraDeviceBase::PhysicalCameraSettingsList physicalSettingsList;
+        for (const auto& it : request.mPhysicalCameraSettings) {
+            String8 physicalId(it.id.c_str());
+            if (physicalId != mDevice->getId()) {
+                auto found = std::find(requestedPhysicalIds.begin(), requestedPhysicalIds.end(),
+                        it.id);
+                if (found == requestedPhysicalIds.end()) {
+                    ALOGE("%s: Camera %s: Physical camera id: %s not part of attached outputs.",
+                            __FUNCTION__, mCameraIdStr.string(), physicalId.string());
+                    return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT,
+                            "Invalid physical camera id");
+                }
+            }
+
+            CameraMetadata metadata(it.settings);
+            if (metadata.isEmpty()) {
+                ALOGE("%s: Camera %s: Sent empty metadata packet. Rejecting request.",
+                        __FUNCTION__, mCameraIdStr.string());
+                return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT,
+                        "Request settings are empty");
+            }
+
+            physicalSettingsList.push_back({it.id, metadata});
+        }
+
+        if (streaming && (physicalSettingsList.size() > 1)) {
+            ALOGE("%s: Camera %s: Individual physical camera settings are not supported in "
+                    "streaming requests. Rejecting request.", __FUNCTION__, mCameraIdStr.string());
+            return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT,
+                    "Streaming request contains individual physical requests");
+        }
+
+        if (!enforceRequestPermissions(physicalSettingsList.begin()->metadata)) {
+            // Callee logs
+            return STATUS_ERROR(CameraService::ERROR_PERMISSION_DENIED,
+                    "Caller does not have permission to change restricted controls");
+        }
+
         physicalSettingsList.begin()->metadata.update(ANDROID_REQUEST_OUTPUT_STREAMS,
                 &outputStreamIds[0], outputStreamIds.size());
 
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.h b/services/camera/libcameraservice/api2/CameraDeviceClient.h
index 14aeed0..435c99d 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.h
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.h
@@ -259,8 +259,8 @@
 
     // Utility method to insert the surface into SurfaceMap
     binder::Status insertGbpLocked(const sp<IGraphicBufferProducer>& gbp,
-            /*out*/SurfaceMap* surfaceMap,
-            /*out*/Vector<int32_t>* streamIds);
+            /*out*/SurfaceMap* surfaceMap, /*out*/Vector<int32_t>* streamIds,
+            /*out*/int32_t*  currentStreamId);
 
     // Check that the physicalCameraId passed in is spported by the camera
     // device.