[automerger skipped] Merge "RESTRICT AUTOMERGE Gate input buffers from input surface" into pi-dev
am: 3d4739e5bf -s ours
am skip reason: subject contains skip directive

Change-Id: I402c07f172d752472cdc6f5f5092458294a547c5
diff --git a/Android.bp b/Android.bp
index ca555fb..699ede1 100644
--- a/Android.bp
+++ b/Android.bp
@@ -3,7 +3,3 @@
         "hardware/google/interfaces",
     ],
 }
-
-subdirs = [
-    "media",
-]
diff --git a/codec2/Android.bp b/codec2/Android.bp
index ee46c24..9addc79 100644
--- a/codec2/Android.bp
+++ b/codec2/Android.bp
@@ -40,8 +40,3 @@
 
     ldflags: ["-Wl,-Bsymbolic"],
 }
-
-subdirs = [
-    "tests",
-    "vndk",
-]
diff --git a/codec2/Android.mk b/codec2/Android.mk
deleted file mode 100644
index 948b145..0000000
--- a/codec2/Android.mk
+++ /dev/null
@@ -1,44 +0,0 @@
-# =============================================================================
-# DOCUMENTATION GENERATION
-# =============================================================================
-C2_ROOT := $(call my-dir)
-
-C2_DOCS_ROOT := $(OUT_DIR)/target/common/docs/codec2
-
-C2_OUT_TEMP := $(PRODUCT_OUT)/gen/ETC/Codec2-docs_intermediates
-
-C2_DOXY := $(or $(shell command -v doxygen),\
-		$(shell command -v /Applications/Doxygen.app/Contents/Resources/doxygen))
-
-check-doxygen:
-ifndef C2_DOXY
-	$(error 'doxygen is not available')
-endif
-
-$(C2_OUT_TEMP)/doxy-api.config: $(C2_ROOT)/docs/doxygen.config
-	# only document include directory, no internal sections
-	sed 's/\(^INPUT *=.*\)/\1include\//; \
-	s/\(^INTERNAL_DOCS *= *\).*/\1NO/; \
-	s/\(^ENABLED_SECTIONS *=.*\)INTERNAL\(.*\).*/\1\2/; \
-	s:\(^OUTPUT_DIRECTORY *= \)out:\1'$(OUT_DIR)':;' \
-		$(C2_ROOT)/docs/doxygen.config > $@
-
-$(C2_OUT_TEMP)/doxy-internal.config: $(C2_ROOT)/docs/doxygen.config
-	sed 's:\(^OUTPUT_DIRECTORY *= \)out\(.*\)api:\1'$(OUT_DIR)'\2internal:;' \
-		$(C2_ROOT)/docs/doxygen.config > $@
-
-docs-api: $(C2_OUT_TEMP)/doxy-api.config check-doxygen
-	echo API docs are building in $(C2_DOCS_ROOT)/api
-	rm -rf $(C2_DOCS_ROOT)/api
-	mkdir -p $(C2_DOCS_ROOT)/api
-	$(C2_DOXY) $(C2_OUT_TEMP)/doxy-api.config
-
-docs-internal: $(C2_OUT_TEMP)/doxy-internal.config check-doxygen
-	echo Internal docs are building in $(C2_DOCS_ROOT)/internal
-	rm -rf $(C2_DOCS_ROOT)/internal
-	mkdir -p $(C2_DOCS_ROOT)/internal
-	$(C2_DOXY) $(C2_OUT_TEMP)/doxy-internal.config
-
-docs-all: docs-api docs-internal
-
-include $(call all-makefiles-under,$(call my-dir))
diff --git a/codec2/docs/doxyfilter.sh b/codec2/docs/doxyfilter.sh
deleted file mode 100755
index d813153..0000000
--- a/codec2/docs/doxyfilter.sh
+++ /dev/null
@@ -1,100 +0,0 @@
-#!/usr/bin/env python3
-import re, sys
-
-global in_comment, current, indent, hold
-in_comment, current, indent, hold = False, None, '', []
-
-class ChangeCStyleCommentsToDoxy:
-    def dump_hold():
-        global hold
-        for h in hold:
-            print(h, end='')
-        hold[:] = []
-
-    def doxy_hold():
-        global current, hold
-        if current == '//':
-            for h in hold:
-                print(re.sub(r'^( *//(?!/))', r'\1/', h), end='')
-        else:
-            first = True
-            for h in hold:
-                if first:
-                    h = re.sub(r'^( */[*](?![*]))', r'\1*', h)
-                    first = False
-                print(h, end='')
-        hold[:] = []
-
-    def process_comment(t, ind, line):
-        global current, indent, hold
-        if t != current or ind not in (indent, indent + ' '):
-            dump_hold()
-            current, indent = t, ind
-        hold.append(line)
-
-    def process_line(ind, line):
-        global current, indent
-        if ind in (indent, ''):
-            doxy_hold()
-        else:
-            dump_hold()
-        current, indent = None, None
-        print(line, end='')
-
-    def process(self, input, path):
-        for line in input:
-            ind = re.match(r'^( *)', line).group(1)
-            if in_comment:
-                # TODO: this is not quite right, but good enough
-                m = re.match(r'^ *[*]/', line)
-                if m:
-                    process_comment('/*', ind, line)
-                    in_comment = False
-                else:
-                    process_comment('/*', ind, line)
-                continue
-            m = re.match(r'^ *//', line)
-            if m:
-                # one-line comment
-                process_comment('//', ind, line)
-                continue
-            m = re.match(r'^ */[*]', line)
-            if m:
-                # multi-line comment
-                process_comment('/*', ind, line)
-                # TODO: this is not quite right, but good enough
-                in_comment = not re.match(r'^ *[*]/', line)
-                continue
-            process_line(ind, line)
-
-class AutoGroup:
-    def process(self, input, path):
-        if '/codec2/include/' in path:
-            group = 'API Codec2 API'
-        elif False:
-            return
-        elif '/codec2/vndk/' in path:
-            group = 'VNDK Platform provided glue'
-        elif '/codec2/tests/' in path:
-            group = 'Tests Unit tests'
-        else:
-            group = 'Random Misc. sandbox'
-
-        print('#undef __APPLE__')
-
-        for line in input:
-            if re.match(r'^namespace android {', line):
-                print(line, end='')
-                print()
-                print(r'/// \addtogroup {}'.format(group))
-                print(r'/// @{')
-                continue
-            elif re.match(r'^} +// +namespace', line):
-                print(r'/// @}')
-                print()
-            print(line, end='')
-
-P = AutoGroup()
-for path in sys.argv[1:]:
-    with open(path, 'rt') as input:
-        P.process(input, path)
diff --git a/codec2/docs/doxygen.config b/codec2/docs/doxygen.config
deleted file mode 100644
index 11a921f..0000000
--- a/codec2/docs/doxygen.config
+++ /dev/null
@@ -1,2446 +0,0 @@
-# Doxyfile 1.8.11
-
-# This file describes the settings to be used by the documentation system
-# doxygen (www.doxygen.org) for a project.
-#
-# All text after a double hash (##) is considered a comment and is placed in
-# front of the TAG it is preceding.
-#
-# All text after a single hash (#) is considered a comment and will be ignored.
-# The format is:
-# TAG = value [value, ...]
-# For lists, items can also be appended using:
-# TAG += value [value, ...]
-# Values that contain spaces should be placed between quotes (\" \").
-
-#---------------------------------------------------------------------------
-# Project related configuration options
-#---------------------------------------------------------------------------
-
-# This tag specifies the encoding used for all characters in the config file
-# that follow. The default is UTF-8 which is also the encoding used for all text
-# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
-# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
-# for the list of possible encodings.
-# The default value is: UTF-8.
-
-DOXYFILE_ENCODING      = UTF-8
-
-# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
-# double-quotes, unless you are using Doxywizard) that should identify the
-# project for which the documentation is generated. This name is used in the
-# title of most generated pages and in a few other places.
-# The default value is: My Project.
-
-PROJECT_NAME           = Codec2
-
-# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
-# could be handy for archiving the generated documentation or if some version
-# control system is used.
-
-PROJECT_NUMBER         = 
-
-# Using the PROJECT_BRIEF tag one can provide an optional one line description
-# for a project that appears at the top of each page and should give viewer a
-# quick idea about the purpose of the project. Keep the description short.
-
-PROJECT_BRIEF          = 
-
-# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
-# in the documentation. The maximum height of the logo should not exceed 55
-# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
-# the logo to the output directory.
-
-PROJECT_LOGO           = 
-
-# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
-# into which the generated documentation will be written. If a relative path is
-# entered, it will be relative to the location where doxygen was started. If
-# left blank the current directory will be used.
-
-OUTPUT_DIRECTORY       = out/target/common/docs/codec2/api
-
-# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
-# directories (in 2 levels) under the output directory of each output format and
-# will distribute the generated files over these directories. Enabling this
-# option can be useful when feeding doxygen a huge amount of source files, where
-# putting all generated files in the same directory would otherwise causes
-# performance problems for the file system.
-# The default value is: NO.
-
-CREATE_SUBDIRS         = NO
-
-# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
-# characters to appear in the names of generated files. If set to NO, non-ASCII
-# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
-# U+3044.
-# The default value is: NO.
-
-ALLOW_UNICODE_NAMES    = NO
-
-# The OUTPUT_LANGUAGE tag is used to specify the language in which all
-# documentation generated by doxygen is written. Doxygen will use this
-# information to generate all constant output in the proper language.
-# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
-# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
-# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
-# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
-# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
-# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
-# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
-# Ukrainian and Vietnamese.
-# The default value is: English.
-
-OUTPUT_LANGUAGE        = English
-
-# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
-# descriptions after the members that are listed in the file and class
-# documentation (similar to Javadoc). Set to NO to disable this.
-# The default value is: YES.
-
-BRIEF_MEMBER_DESC      = YES
-
-# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief
-# description of a member or function before the detailed description
-#
-# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
-# brief descriptions will be completely suppressed.
-# The default value is: YES.
-
-REPEAT_BRIEF           = YES
-
-# This tag implements a quasi-intelligent brief description abbreviator that is
-# used to form the text in various listings. Each string in this list, if found
-# as the leading text of the brief description, will be stripped from the text
-# and the result, after processing the whole list, is used as the annotated
-# text. Otherwise, the brief description is used as-is. If left blank, the
-# following values are used ($name is automatically replaced with the name of
-# the entity):The $name class, The $name widget, The $name file, is, provides,
-# specifies, contains, represents, a, an and the.
-
-ABBREVIATE_BRIEF       = "The $name class" \
-                         "The $name widget" \
-                         "The $name file" \
-                         is \
-                         provides \
-                         specifies \
-                         contains \
-                         represents \
-                         a \
-                         an \
-                         the
-
-# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
-# doxygen will generate a detailed section even if there is only a brief
-# description.
-# The default value is: NO.
-
-ALWAYS_DETAILED_SEC    = NO
-
-# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
-# inherited members of a class in the documentation of that class as if those
-# members were ordinary class members. Constructors, destructors and assignment
-# operators of the base classes will not be shown.
-# The default value is: NO.
-
-INLINE_INHERITED_MEMB  = YES
-
-# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path
-# before files name in the file list and in the header files. If set to NO the
-# shortest path that makes the file name unique will be used
-# The default value is: YES.
-
-FULL_PATH_NAMES        = YES
-
-# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
-# Stripping is only done if one of the specified strings matches the left-hand
-# part of the path. The tag can be used to show relative paths in the file list.
-# If left blank the directory from which doxygen is run is used as the path to
-# strip.
-#
-# Note that you can specify absolute paths here, but also relative paths, which
-# will be relative from the directory where doxygen is started.
-# This tag requires that the tag FULL_PATH_NAMES is set to YES.
-
-STRIP_FROM_PATH        = frameworks/av/media/libstagefright/codec2
-
-# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
-# path mentioned in the documentation of a class, which tells the reader which
-# header file to include in order to use a class. If left blank only the name of
-# the header file containing the class definition is used. Otherwise one should
-# specify the list of include paths that are normally passed to the compiler
-# using the -I flag.
-
-STRIP_FROM_INC_PATH    = 
-
-# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
-# less readable) file names. This can be useful is your file systems doesn't
-# support long names like on DOS, Mac, or CD-ROM.
-# The default value is: NO.
-
-SHORT_NAMES            = NO
-
-# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
-# first line (until the first dot) of a Javadoc-style comment as the brief
-# description. If set to NO, the Javadoc-style will behave just like regular Qt-
-# style comments (thus requiring an explicit @brief command for a brief
-# description.)
-# The default value is: NO.
-
-JAVADOC_AUTOBRIEF      = YES
-
-# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
-# line (until the first dot) of a Qt-style comment as the brief description. If
-# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
-# requiring an explicit \brief command for a brief description.)
-# The default value is: NO.
-
-QT_AUTOBRIEF           = YES
-
-# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
-# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
-# a brief description. This used to be the default behavior. The new default is
-# to treat a multi-line C++ comment block as a detailed description. Set this
-# tag to YES if you prefer the old behavior instead.
-#
-# Note that setting this tag to YES also means that rational rose comments are
-# not recognized any more.
-# The default value is: NO.
-
-MULTILINE_CPP_IS_BRIEF = NO
-
-# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
-# documentation from any documented member that it re-implements.
-# The default value is: YES.
-
-INHERIT_DOCS           = YES
-
-# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new
-# page for each member. If set to NO, the documentation of a member will be part
-# of the file/class/namespace that contains it.
-# The default value is: NO.
-
-SEPARATE_MEMBER_PAGES  = NO
-
-# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
-# uses this value to replace tabs by spaces in code fragments.
-# Minimum value: 1, maximum value: 16, default value: 4.
-
-TAB_SIZE               = 4
-
-# This tag can be used to specify a number of aliases that act as commands in
-# the documentation. An alias has the form:
-# name=value
-# For example adding
-# "sideeffect=@par Side Effects:\n"
-# will allow you to put the command \sideeffect (or @sideeffect) in the
-# documentation, which will result in a user-defined paragraph with heading
-# "Side Effects:". You can put \n's in the value part of an alias to insert
-# newlines.
-
-ALIASES                = 
-
-# This tag can be used to specify a number of word-keyword mappings (TCL only).
-# A mapping has the form "name=value". For example adding "class=itcl::class"
-# will allow you to use the command class in the itcl::class meaning.
-
-TCL_SUBST              = 
-
-# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
-# only. Doxygen will then generate output that is more tailored for C. For
-# instance, some of the names that are used will be different. The list of all
-# members will be omitted, etc.
-# The default value is: NO.
-
-OPTIMIZE_OUTPUT_FOR_C  = NO
-
-# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
-# Python sources only. Doxygen will then generate output that is more tailored
-# for that language. For instance, namespaces will be presented as packages,
-# qualified scopes will look different, etc.
-# The default value is: NO.
-
-OPTIMIZE_OUTPUT_JAVA   = NO
-
-# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
-# sources. Doxygen will then generate output that is tailored for Fortran.
-# The default value is: NO.
-
-OPTIMIZE_FOR_FORTRAN   = NO
-
-# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
-# sources. Doxygen will then generate output that is tailored for VHDL.
-# The default value is: NO.
-
-OPTIMIZE_OUTPUT_VHDL   = NO
-
-# Doxygen selects the parser to use depending on the extension of the files it
-# parses. With this tag you can assign which parser to use for a given
-# extension. Doxygen has a built-in mapping, but you can override or extend it
-# using this tag. The format is ext=language, where ext is a file extension, and
-# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
-# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
-# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
-# Fortran. In the later case the parser tries to guess whether the code is fixed
-# or free formatted code, this is the default for Fortran type files), VHDL. For
-# instance to make doxygen treat .inc files as Fortran files (default is PHP),
-# and .f files as C (default is Fortran), use: inc=Fortran f=C.
-#
-# Note: For files without extension you can use no_extension as a placeholder.
-#
-# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
-# the files are not read by doxygen.
-
-EXTENSION_MAPPING      = 
-
-# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
-# according to the Markdown format, which allows for more readable
-# documentation. See http://daringfireball.net/projects/markdown/ for details.
-# The output of markdown processing is further processed by doxygen, so you can
-# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
-# case of backward compatibilities issues.
-# The default value is: YES.
-
-MARKDOWN_SUPPORT       = YES
-
-# When enabled doxygen tries to link words that correspond to documented
-# classes, or namespaces to their corresponding documentation. Such a link can
-# be prevented in individual cases by putting a % sign in front of the word or
-# globally by setting AUTOLINK_SUPPORT to NO.
-# The default value is: YES.
-
-AUTOLINK_SUPPORT       = YES
-
-# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
-# to include (a tag file for) the STL sources as input, then you should set this
-# tag to YES in order to let doxygen match functions declarations and
-# definitions whose arguments contain STL classes (e.g. func(std::string);
-# versus func(std::string) {}). This also make the inheritance and collaboration
-# diagrams that involve STL classes more complete and accurate.
-# The default value is: NO.
-
-BUILTIN_STL_SUPPORT    = YES
-
-# If you use Microsoft's C++/CLI language, you should set this option to YES to
-# enable parsing support.
-# The default value is: NO.
-
-CPP_CLI_SUPPORT        = NO
-
-# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
-# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
-# will parse them like normal C++ but will assume all classes use public instead
-# of private inheritance when no explicit protection keyword is present.
-# The default value is: NO.
-
-SIP_SUPPORT            = NO
-
-# For Microsoft's IDL there are propget and propput attributes to indicate
-# getter and setter methods for a property. Setting this option to YES will make
-# doxygen to replace the get and set methods by a property in the documentation.
-# This will only work if the methods are indeed getting or setting a simple
-# type. If this is not the case, or you want to show the methods anyway, you
-# should set this option to NO.
-# The default value is: YES.
-
-IDL_PROPERTY_SUPPORT   = YES
-
-# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
-# tag is set to YES then doxygen will reuse the documentation of the first
-# member in the group (if any) for the other members of the group. By default
-# all members of a group must be documented explicitly.
-# The default value is: NO.
-
-DISTRIBUTE_GROUP_DOC   = NO
-
-# If one adds a struct or class to a group and this option is enabled, then also
-# any nested class or struct is added to the same group. By default this option
-# is disabled and one has to add nested compounds explicitly via \ingroup.
-# The default value is: NO.
-
-GROUP_NESTED_COMPOUNDS = NO
-
-# Set the SUBGROUPING tag to YES to allow class member groups of the same type
-# (for instance a group of public functions) to be put as a subgroup of that
-# type (e.g. under the Public Functions section). Set it to NO to prevent
-# subgrouping. Alternatively, this can be done per class using the
-# \nosubgrouping command.
-# The default value is: YES.
-
-SUBGROUPING            = YES
-
-# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
-# are shown inside the group in which they are included (e.g. using \ingroup)
-# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
-# and RTF).
-#
-# Note that this feature does not work in combination with
-# SEPARATE_MEMBER_PAGES.
-# The default value is: NO.
-
-INLINE_GROUPED_CLASSES = NO
-
-# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
-# with only public data fields or simple typedef fields will be shown inline in
-# the documentation of the scope in which they are defined (i.e. file,
-# namespace, or group documentation), provided this scope is documented. If set
-# to NO, structs, classes, and unions are shown on a separate page (for HTML and
-# Man pages) or section (for LaTeX and RTF).
-# The default value is: NO.
-
-INLINE_SIMPLE_STRUCTS  = NO
-
-# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
-# enum is documented as struct, union, or enum with the name of the typedef. So
-# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
-# with name TypeT. When disabled the typedef will appear as a member of a file,
-# namespace, or class. And the struct will be named TypeS. This can typically be
-# useful for C code in case the coding convention dictates that all compound
-# types are typedef'ed and only the typedef is referenced, never the tag name.
-# The default value is: NO.
-
-TYPEDEF_HIDES_STRUCT   = YES
-
-# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
-# cache is used to resolve symbols given their name and scope. Since this can be
-# an expensive process and often the same symbol appears multiple times in the
-# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
-# doxygen will become slower. If the cache is too large, memory is wasted. The
-# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
-# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
-# symbols. At the end of a run doxygen will report the cache usage and suggest
-# the optimal cache size from a speed point of view.
-# Minimum value: 0, maximum value: 9, default value: 0.
-
-LOOKUP_CACHE_SIZE      = 0
-
-#---------------------------------------------------------------------------
-# Build related configuration options
-#---------------------------------------------------------------------------
-
-# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
-# documentation are documented, even if no documentation was available. Private
-# class members and static file members will be hidden unless the
-# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
-# Note: This will also disable the warnings about undocumented members that are
-# normally produced when WARNINGS is set to YES.
-# The default value is: NO.
-
-EXTRACT_ALL            = YES
-
-# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
-# be included in the documentation.
-# The default value is: NO.
-
-EXTRACT_PRIVATE        = NO
-
-# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
-# scope will be included in the documentation.
-# The default value is: NO.
-
-EXTRACT_PACKAGE        = NO
-
-# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
-# included in the documentation.
-# The default value is: NO.
-
-EXTRACT_STATIC         = NO
-
-# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
-# locally in source files will be included in the documentation. If set to NO,
-# only classes defined in header files are included. Does not have any effect
-# for Java sources.
-# The default value is: YES.
-
-EXTRACT_LOCAL_CLASSES  = YES
-
-# This flag is only useful for Objective-C code. If set to YES, local methods,
-# which are defined in the implementation section but not in the interface are
-# included in the documentation. If set to NO, only methods in the interface are
-# included.
-# The default value is: NO.
-
-EXTRACT_LOCAL_METHODS  = NO
-
-# If this flag is set to YES, the members of anonymous namespaces will be
-# extracted and appear in the documentation as a namespace called
-# 'anonymous_namespace{file}', where file will be replaced with the base name of
-# the file that contains the anonymous namespace. By default anonymous namespace
-# are hidden.
-# The default value is: NO.
-
-EXTRACT_ANON_NSPACES   = NO
-
-# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
-# undocumented members inside documented classes or files. If set to NO these
-# members will be included in the various overviews, but no documentation
-# section is generated. This option has no effect if EXTRACT_ALL is enabled.
-# The default value is: NO.
-
-HIDE_UNDOC_MEMBERS     = NO
-
-# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
-# undocumented classes that are normally visible in the class hierarchy. If set
-# to NO, these classes will be included in the various overviews. This option
-# has no effect if EXTRACT_ALL is enabled.
-# The default value is: NO.
-
-HIDE_UNDOC_CLASSES     = NO
-
-# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
-# (class|struct|union) declarations. If set to NO, these declarations will be
-# included in the documentation.
-# The default value is: NO.
-
-HIDE_FRIEND_COMPOUNDS  = NO
-
-# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
-# documentation blocks found inside the body of a function. If set to NO, these
-# blocks will be appended to the function's detailed documentation block.
-# The default value is: NO.
-
-HIDE_IN_BODY_DOCS      = NO
-
-# The INTERNAL_DOCS tag determines if documentation that is typed after a
-# \internal command is included. If the tag is set to NO then the documentation
-# will be excluded. Set it to YES to include the internal documentation.
-# The default value is: NO.
-
-INTERNAL_DOCS          = YES
-
-# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
-# names in lower-case letters. If set to YES, upper-case letters are also
-# allowed. This is useful if you have classes or files whose names only differ
-# in case and if your file system supports case sensitive file names. Windows
-# and Mac users are advised to set this option to NO.
-# The default value is: system dependent.
-
-CASE_SENSE_NAMES       = NO
-
-# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
-# their full class and namespace scopes in the documentation. If set to YES, the
-# scope will be hidden.
-# The default value is: NO.
-
-HIDE_SCOPE_NAMES       = YES
-
-# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will
-# append additional text to a page's title, such as Class Reference. If set to
-# YES the compound reference will be hidden.
-# The default value is: NO.
-
-HIDE_COMPOUND_REFERENCE= NO
-
-# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
-# the files that are included by a file in the documentation of that file.
-# The default value is: YES.
-
-SHOW_INCLUDE_FILES     = YES
-
-# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
-# grouped member an include statement to the documentation, telling the reader
-# which file to include in order to use the member.
-# The default value is: NO.
-
-SHOW_GROUPED_MEMB_INC  = NO
-
-# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
-# files with double quotes in the documentation rather than with sharp brackets.
-# The default value is: NO.
-
-FORCE_LOCAL_INCLUDES   = NO
-
-# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
-# documentation for inline members.
-# The default value is: YES.
-
-INLINE_INFO            = YES
-
-# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
-# (detailed) documentation of file and class members alphabetically by member
-# name. If set to NO, the members will appear in declaration order.
-# The default value is: YES.
-
-SORT_MEMBER_DOCS       = YES
-
-# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
-# descriptions of file, namespace and class members alphabetically by member
-# name. If set to NO, the members will appear in declaration order. Note that
-# this will also influence the order of the classes in the class list.
-# The default value is: NO.
-
-SORT_BRIEF_DOCS        = NO
-
-# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
-# (brief and detailed) documentation of class members so that constructors and
-# destructors are listed first. If set to NO the constructors will appear in the
-# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
-# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
-# member documentation.
-# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
-# detailed member documentation.
-# The default value is: NO.
-
-SORT_MEMBERS_CTORS_1ST = NO
-
-# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
-# of group names into alphabetical order. If set to NO the group names will
-# appear in their defined order.
-# The default value is: NO.
-
-SORT_GROUP_NAMES       = NO
-
-# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
-# fully-qualified names, including namespaces. If set to NO, the class list will
-# be sorted only by class name, not including the namespace part.
-# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
-# Note: This option applies only to the class list, not to the alphabetical
-# list.
-# The default value is: NO.
-
-SORT_BY_SCOPE_NAME     = NO
-
-# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
-# type resolution of all parameters of a function it will reject a match between
-# the prototype and the implementation of a member function even if there is
-# only one candidate or it is obvious which candidate to choose by doing a
-# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
-# accept a match between prototype and implementation in such cases.
-# The default value is: NO.
-
-STRICT_PROTO_MATCHING  = NO
-
-# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo
-# list. This list is created by putting \todo commands in the documentation.
-# The default value is: YES.
-
-GENERATE_TODOLIST      = YES
-
-# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test
-# list. This list is created by putting \test commands in the documentation.
-# The default value is: YES.
-
-GENERATE_TESTLIST      = YES
-
-# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug
-# list. This list is created by putting \bug commands in the documentation.
-# The default value is: YES.
-
-GENERATE_BUGLIST       = YES
-
-# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)
-# the deprecated list. This list is created by putting \deprecated commands in
-# the documentation.
-# The default value is: YES.
-
-GENERATE_DEPRECATEDLIST= YES
-
-# The ENABLED_SECTIONS tag can be used to enable conditional documentation
-# sections, marked by \if <section_label> ... \endif and \cond <section_label>
-# ... \endcond blocks.
-
-ENABLED_SECTIONS       = INTERNAL
-
-# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
-# initial value of a variable or macro / define can have for it to appear in the
-# documentation. If the initializer consists of more lines than specified here
-# it will be hidden. Use a value of 0 to hide initializers completely. The
-# appearance of the value of individual variables and macros / defines can be
-# controlled using \showinitializer or \hideinitializer command in the
-# documentation regardless of this setting.
-# Minimum value: 0, maximum value: 10000, default value: 30.
-
-MAX_INITIALIZER_LINES  = 30
-
-# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
-# the bottom of the documentation of classes and structs. If set to YES, the
-# list will mention the files that were used to generate the documentation.
-# The default value is: YES.
-
-SHOW_USED_FILES        = YES
-
-# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
-# will remove the Files entry from the Quick Index and from the Folder Tree View
-# (if specified).
-# The default value is: YES.
-
-SHOW_FILES             = YES
-
-# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
-# page. This will remove the Namespaces entry from the Quick Index and from the
-# Folder Tree View (if specified).
-# The default value is: YES.
-
-SHOW_NAMESPACES        = YES
-
-# The FILE_VERSION_FILTER tag can be used to specify a program or script that
-# doxygen should invoke to get the current version for each file (typically from
-# the version control system). Doxygen will invoke the program by executing (via
-# popen()) the command command input-file, where command is the value of the
-# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
-# by doxygen. Whatever the program writes to standard output is used as the file
-# version. For an example see the documentation.
-
-FILE_VERSION_FILTER    = 
-
-# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
-# by doxygen. The layout file controls the global structure of the generated
-# output files in an output format independent way. To create the layout file
-# that represents doxygen's defaults, run doxygen with the -l option. You can
-# optionally specify a file name after the option, if omitted DoxygenLayout.xml
-# will be used as the name of the layout file.
-#
-# Note that if you run doxygen from a directory containing a file called
-# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
-# tag is left empty.
-
-LAYOUT_FILE            = 
-
-# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
-# the reference definitions. This must be a list of .bib files. The .bib
-# extension is automatically appended if omitted. This requires the bibtex tool
-# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
-# For LaTeX the style of the bibliography can be controlled using
-# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
-# search path. See also \cite for info how to create references.
-
-CITE_BIB_FILES         = 
-
-#---------------------------------------------------------------------------
-# Configuration options related to warning and progress messages
-#---------------------------------------------------------------------------
-
-# The QUIET tag can be used to turn on/off the messages that are generated to
-# standard output by doxygen. If QUIET is set to YES this implies that the
-# messages are off.
-# The default value is: NO.
-
-QUIET                  = NO
-
-# The WARNINGS tag can be used to turn on/off the warning messages that are
-# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
-# this implies that the warnings are on.
-#
-# Tip: Turn warnings on while writing the documentation.
-# The default value is: YES.
-
-WARNINGS               = YES
-
-# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate
-# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
-# will automatically be disabled.
-# The default value is: YES.
-
-WARN_IF_UNDOCUMENTED   = YES
-
-# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
-# potential errors in the documentation, such as not documenting some parameters
-# in a documented function, or documenting parameters that don't exist or using
-# markup commands wrongly.
-# The default value is: YES.
-
-WARN_IF_DOC_ERROR      = YES
-
-# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
-# are documented, but have no documentation for their parameters or return
-# value. If set to NO, doxygen will only warn about wrong or incomplete
-# parameter documentation, but not about the absence of documentation.
-# The default value is: NO.
-
-WARN_NO_PARAMDOC       = NO
-
-# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
-# a warning is encountered.
-# The default value is: NO.
-
-WARN_AS_ERROR          = NO
-
-# The WARN_FORMAT tag determines the format of the warning messages that doxygen
-# can produce. The string should contain the $file, $line, and $text tags, which
-# will be replaced by the file and line number from which the warning originated
-# and the warning text. Optionally the format may contain $version, which will
-# be replaced by the version of the file (if it could be obtained via
-# FILE_VERSION_FILTER)
-# The default value is: $file:$line: $text.
-
-WARN_FORMAT            = "$file:$line: $text"
-
-# The WARN_LOGFILE tag can be used to specify a file to which warning and error
-# messages should be written. If left blank the output is written to standard
-# error (stderr).
-
-WARN_LOGFILE           = 
-
-#---------------------------------------------------------------------------
-# Configuration options related to the input files
-#---------------------------------------------------------------------------
-
-# The INPUT tag is used to specify the files and/or directories that contain
-# documented source files. You may enter file names like myfile.cpp or
-# directories like /usr/src/myproject. Separate the files or directories with
-# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
-# Note: If this tag is empty the current directory is searched.
-
-INPUT                  = frameworks/av/media/libstagefright/codec2/
-
-# This tag can be used to specify the character encoding of the source files
-# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
-# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
-# documentation (see: http://www.gnu.org/software/libiconv) for the list of
-# possible encodings.
-# The default value is: UTF-8.
-
-INPUT_ENCODING         = UTF-8
-
-# If the value of the INPUT tag contains directories, you can use the
-# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
-# *.h) to filter out the source-files in the directories.
-#
-# Note that for custom extensions or not directly supported extensions you also
-# need to set EXTENSION_MAPPING for the extension otherwise the files are not
-# read by doxygen.
-#
-# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
-# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
-# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc,
-# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f, *.for, *.tcl,
-# *.vhd, *.vhdl, *.ucf, *.qsf, *.as and *.js.
-
-FILE_PATTERNS          = C2*.c \
-                         C2*.cpp \
-                         C2*.h
-
-# The RECURSIVE tag can be used to specify whether or not subdirectories should
-# be searched for input files as well.
-# The default value is: NO.
-
-RECURSIVE              = YES
-
-# The EXCLUDE tag can be used to specify files and/or directories that should be
-# excluded from the INPUT source files. This way you can easily exclude a
-# subdirectory from a directory tree whose root is specified with the INPUT tag.
-#
-# Note that relative paths are relative to the directory from which doxygen is
-# run.
-
-EXCLUDE                = 
-
-# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
-# directories that are symbolic links (a Unix file system feature) are excluded
-# from the input.
-# The default value is: NO.
-
-EXCLUDE_SYMLINKS       = NO
-
-# If the value of the INPUT tag contains directories, you can use the
-# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
-# certain files from those directories.
-#
-# Note that the wildcards are matched against the file with absolute path, so to
-# exclude all test directories for example use the pattern */test/*
-
-EXCLUDE_PATTERNS       = ._*
-
-# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
-# (namespaces, classes, functions, etc.) that should be excluded from the
-# output. The symbol name can be a fully qualified name, a word, or if the
-# wildcard * is used, a substring. Examples: ANamespace, AClass,
-# AClass::ANamespace, ANamespace::*Test
-#
-# Note that the wildcards are matched against the file with absolute path, so to
-# exclude all test directories use the pattern */test/*
-
-EXCLUDE_SYMBOLS        = 
-
-# The EXAMPLE_PATH tag can be used to specify one or more files or directories
-# that contain example code fragments that are included (see the \include
-# command).
-
-EXAMPLE_PATH           = 
-
-# If the value of the EXAMPLE_PATH tag contains directories, you can use the
-# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
-# *.h) to filter out the source-files in the directories. If left blank all
-# files are included.
-
-EXAMPLE_PATTERNS       = *
-
-# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
-# searched for input files to be used with the \include or \dontinclude commands
-# irrespective of the value of the RECURSIVE tag.
-# The default value is: NO.
-
-EXAMPLE_RECURSIVE      = NO
-
-# The IMAGE_PATH tag can be used to specify one or more files or directories
-# that contain images that are to be included in the documentation (see the
-# \image command).
-
-IMAGE_PATH             = 
-
-# The INPUT_FILTER tag can be used to specify a program that doxygen should
-# invoke to filter for each input file. Doxygen will invoke the filter program
-# by executing (via popen()) the command:
-#
-# <filter> <input-file>
-#
-# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
-# name of an input file. Doxygen will then use the output that the filter
-# program writes to standard output. If FILTER_PATTERNS is specified, this tag
-# will be ignored.
-#
-# Note that the filter must not add or remove lines; it is applied before the
-# code is scanned, but not when the output code is generated. If lines are added
-# or removed, the anchors will not be placed correctly.
-#
-# Note that for custom extensions or not directly supported extensions you also
-# need to set EXTENSION_MAPPING for the extension otherwise the files are not
-# properly processed by doxygen.
-
-INPUT_FILTER           = frameworks/av/media/libstagefright/codec2/docs/doxyfilter.sh
-
-# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
-# basis. Doxygen will compare the file name with each pattern and apply the
-# filter if there is a match. The filters are a list of the form: pattern=filter
-# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
-# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
-# patterns match the file name, INPUT_FILTER is applied.
-#
-# Note that for custom extensions or not directly supported extensions you also
-# need to set EXTENSION_MAPPING for the extension otherwise the files are not
-# properly processed by doxygen.
-
-FILTER_PATTERNS        = 
-
-# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
-# INPUT_FILTER) will also be used to filter the input files that are used for
-# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
-# The default value is: NO.
-
-FILTER_SOURCE_FILES    = YES
-
-# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
-# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
-# it is also possible to disable source filtering for a specific pattern using
-# *.ext= (so without naming a filter).
-# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
-
-FILTER_SOURCE_PATTERNS = 
-
-# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
-# is part of the input, its contents will be placed on the main page
-# (index.html). This can be useful if you have a project on for instance GitHub
-# and want to reuse the introduction page also for the doxygen output.
-
-USE_MDFILE_AS_MAINPAGE = 
-
-#---------------------------------------------------------------------------
-# Configuration options related to source browsing
-#---------------------------------------------------------------------------
-
-# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
-# generated. Documented entities will be cross-referenced with these sources.
-#
-# Note: To get rid of all source code in the generated output, make sure that
-# also VERBATIM_HEADERS is set to NO.
-# The default value is: NO.
-
-SOURCE_BROWSER         = YES
-
-# Setting the INLINE_SOURCES tag to YES will include the body of functions,
-# classes and enums directly into the documentation.
-# The default value is: NO.
-
-INLINE_SOURCES         = NO
-
-# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
-# special comment blocks from generated source code fragments. Normal C, C++ and
-# Fortran comments will always remain visible.
-# The default value is: YES.
-
-STRIP_CODE_COMMENTS    = YES
-
-# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
-# function all documented functions referencing it will be listed.
-# The default value is: NO.
-
-REFERENCED_BY_RELATION = YES
-
-# If the REFERENCES_RELATION tag is set to YES then for each documented function
-# all documented entities called/used by that function will be listed.
-# The default value is: NO.
-
-REFERENCES_RELATION    = YES
-
-# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
-# to YES then the hyperlinks from functions in REFERENCES_RELATION and
-# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
-# link to the documentation.
-# The default value is: YES.
-
-REFERENCES_LINK_SOURCE = YES
-
-# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
-# source code will show a tooltip with additional information such as prototype,
-# brief description and links to the definition and documentation. Since this
-# will make the HTML file larger and loading of large files a bit slower, you
-# can opt to disable this feature.
-# The default value is: YES.
-# This tag requires that the tag SOURCE_BROWSER is set to YES.
-
-SOURCE_TOOLTIPS        = YES
-
-# If the USE_HTAGS tag is set to YES then the references to source code will
-# point to the HTML generated by the htags(1) tool instead of doxygen built-in
-# source browser. The htags tool is part of GNU's global source tagging system
-# (see http://www.gnu.org/software/global/global.html). You will need version
-# 4.8.6 or higher.
-#
-# To use it do the following:
-# - Install the latest version of global
-# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
-# - Make sure the INPUT points to the root of the source tree
-# - Run doxygen as normal
-#
-# Doxygen will invoke htags (and that will in turn invoke gtags), so these
-# tools must be available from the command line (i.e. in the search path).
-#
-# The result: instead of the source browser generated by doxygen, the links to
-# source code will now point to the output of htags.
-# The default value is: NO.
-# This tag requires that the tag SOURCE_BROWSER is set to YES.
-
-USE_HTAGS              = NO
-
-# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
-# verbatim copy of the header file for each class for which an include is
-# specified. Set to NO to disable this.
-# See also: Section \class.
-# The default value is: YES.
-
-VERBATIM_HEADERS       = YES
-
-# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the
-# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the
-# cost of reduced performance. This can be particularly helpful with template
-# rich C++ code for which doxygen's built-in parser lacks the necessary type
-# information.
-# Note: The availability of this option depends on whether or not doxygen was
-# generated with the -Duse-libclang=ON option for CMake.
-# The default value is: NO.
-
-CLANG_ASSISTED_PARSING = YES
-
-# If clang assisted parsing is enabled you can provide the compiler with command
-# line options that you would normally use when invoking the compiler. Note that
-# the include paths will already be set by doxygen for the files and directories
-# specified with INPUT and INCLUDE_PATH.
-# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.
-
-CLANG_OPTIONS          = -std=c++11
-
-#---------------------------------------------------------------------------
-# Configuration options related to the alphabetical class index
-#---------------------------------------------------------------------------
-
-# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
-# compounds will be generated. Enable this if the project contains a lot of
-# classes, structs, unions or interfaces.
-# The default value is: YES.
-
-ALPHABETICAL_INDEX     = YES
-
-# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
-# which the alphabetical index list will be split.
-# Minimum value: 1, maximum value: 20, default value: 5.
-# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
-
-COLS_IN_ALPHA_INDEX    = 5
-
-# In case all classes in a project start with a common prefix, all classes will
-# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
-# can be used to specify a prefix (or a list of prefixes) that should be ignored
-# while generating the index headers.
-# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
-
-IGNORE_PREFIX          = 
-
-#---------------------------------------------------------------------------
-# Configuration options related to the HTML output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
-# The default value is: YES.
-
-GENERATE_HTML          = YES
-
-# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
-# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
-# it.
-# The default directory is: html.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_OUTPUT            = html
-
-# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
-# generated HTML page (for example: .htm, .php, .asp).
-# The default value is: .html.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_FILE_EXTENSION    = .html
-
-# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
-# each generated HTML page. If the tag is left blank doxygen will generate a
-# standard header.
-#
-# To get valid HTML the header file that includes any scripts and style sheets
-# that doxygen needs, which is dependent on the configuration options used (e.g.
-# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
-# default header using
-# doxygen -w html new_header.html new_footer.html new_stylesheet.css
-# YourConfigFile
-# and then modify the file new_header.html. See also section "Doxygen usage"
-# for information on how to generate the default header that doxygen normally
-# uses.
-# Note: The header is subject to change so you typically have to regenerate the
-# default header when upgrading to a newer version of doxygen. For a description
-# of the possible markers and block names see the documentation.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_HEADER            = 
-
-# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
-# generated HTML page. If the tag is left blank doxygen will generate a standard
-# footer. See HTML_HEADER for more information on how to generate a default
-# footer and what special commands can be used inside the footer. See also
-# section "Doxygen usage" for information on how to generate the default footer
-# that doxygen normally uses.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_FOOTER            = 
-
-# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
-# sheet that is used by each HTML page. It can be used to fine-tune the look of
-# the HTML output. If left blank doxygen will generate a default style sheet.
-# See also section "Doxygen usage" for information on how to generate the style
-# sheet that doxygen normally uses.
-# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
-# it is more robust and this tag (HTML_STYLESHEET) will in the future become
-# obsolete.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_STYLESHEET        = 
-
-# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
-# cascading style sheets that are included after the standard style sheets
-# created by doxygen. Using this option one can overrule certain style aspects.
-# This is preferred over using HTML_STYLESHEET since it does not replace the
-# standard style sheet and is therefore more robust against future updates.
-# Doxygen will copy the style sheet files to the output directory.
-# Note: The order of the extra style sheet files is of importance (e.g. the last
-# style sheet in the list overrules the setting of the previous ones in the
-# list). For an example see the documentation.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_EXTRA_STYLESHEET  = 
-
-# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
-# other source files which should be copied to the HTML output directory. Note
-# that these files will be copied to the base HTML output directory. Use the
-# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
-# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
-# files will be copied as-is; there are no commands or markers available.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_EXTRA_FILES       = 
-
-# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
-# will adjust the colors in the style sheet and background images according to
-# this color. Hue is specified as an angle on a colorwheel, see
-# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
-# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
-# purple, and 360 is red again.
-# Minimum value: 0, maximum value: 359, default value: 220.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_COLORSTYLE_HUE    = 220
-
-# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
-# in the HTML output. For a value of 0 the output will use grayscales only. A
-# value of 255 will produce the most vivid colors.
-# Minimum value: 0, maximum value: 255, default value: 100.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_COLORSTYLE_SAT    = 100
-
-# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
-# luminance component of the colors in the HTML output. Values below 100
-# gradually make the output lighter, whereas values above 100 make the output
-# darker. The value divided by 100 is the actual gamma applied, so 80 represents
-# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
-# change the gamma.
-# Minimum value: 40, maximum value: 240, default value: 80.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_COLORSTYLE_GAMMA  = 80
-
-# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
-# page will contain the date and time when the page was generated. Setting this
-# to YES can help to show when doxygen was last run and thus if the
-# documentation is up to date.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_TIMESTAMP         = NO
-
-# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
-# documentation will contain sections that can be hidden and shown after the
-# page has loaded.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_DYNAMIC_SECTIONS  = YES
-
-# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
-# shown in the various tree structured indices initially; the user can expand
-# and collapse entries dynamically later on. Doxygen will expand the tree to
-# such a level that at most the specified number of entries are visible (unless
-# a fully collapsed tree already exceeds this amount). So setting the number of
-# entries 1 will produce a full collapsed tree by default. 0 is a special value
-# representing an infinite number of entries and will result in a full expanded
-# tree by default.
-# Minimum value: 0, maximum value: 9999, default value: 100.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_INDEX_NUM_ENTRIES = 100
-
-# If the GENERATE_DOCSET tag is set to YES, additional index files will be
-# generated that can be used as input for Apple's Xcode 3 integrated development
-# environment (see: http://developer.apple.com/tools/xcode/), introduced with
-# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
-# Makefile in the HTML output directory. Running make will produce the docset in
-# that directory and running make install will install the docset in
-# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
-# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
-# for more information.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-GENERATE_DOCSET        = NO
-
-# This tag determines the name of the docset feed. A documentation feed provides
-# an umbrella under which multiple documentation sets from a single provider
-# (such as a company or product suite) can be grouped.
-# The default value is: Doxygen generated docs.
-# This tag requires that the tag GENERATE_DOCSET is set to YES.
-
-DOCSET_FEEDNAME        = "Doxygen generated docs"
-
-# This tag specifies a string that should uniquely identify the documentation
-# set bundle. This should be a reverse domain-name style string, e.g.
-# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
-# The default value is: org.doxygen.Project.
-# This tag requires that the tag GENERATE_DOCSET is set to YES.
-
-DOCSET_BUNDLE_ID       = org.doxygen.Project
-
-# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
-# the documentation publisher. This should be a reverse domain-name style
-# string, e.g. com.mycompany.MyDocSet.documentation.
-# The default value is: org.doxygen.Publisher.
-# This tag requires that the tag GENERATE_DOCSET is set to YES.
-
-DOCSET_PUBLISHER_ID    = org.doxygen.Publisher
-
-# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
-# The default value is: Publisher.
-# This tag requires that the tag GENERATE_DOCSET is set to YES.
-
-DOCSET_PUBLISHER_NAME  = Publisher
-
-# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
-# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
-# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
-# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
-# Windows.
-#
-# The HTML Help Workshop contains a compiler that can convert all HTML output
-# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
-# files are now used as the Windows 98 help format, and will replace the old
-# Windows help format (.hlp) on all Windows platforms in the future. Compressed
-# HTML files also contain an index, a table of contents, and you can search for
-# words in the documentation. The HTML workshop also contains a viewer for
-# compressed HTML files.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-GENERATE_HTMLHELP      = NO
-
-# The CHM_FILE tag can be used to specify the file name of the resulting .chm
-# file. You can add a path in front of the file if the result should not be
-# written to the html output directory.
-# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
-
-CHM_FILE               = 
-
-# The HHC_LOCATION tag can be used to specify the location (absolute path
-# including file name) of the HTML help compiler (hhc.exe). If non-empty,
-# doxygen will try to run the HTML help compiler on the generated index.hhp.
-# The file has to be specified with full path.
-# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
-
-HHC_LOCATION           = 
-
-# The GENERATE_CHI flag controls if a separate .chi index file is generated
-# (YES) or that it should be included in the master .chm file (NO).
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
-
-GENERATE_CHI           = NO
-
-# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)
-# and project file content.
-# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
-
-CHM_INDEX_ENCODING     = 
-
-# The BINARY_TOC flag controls whether a binary table of contents is generated
-# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it
-# enables the Previous and Next buttons.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
-
-BINARY_TOC             = NO
-
-# The TOC_EXPAND flag can be set to YES to add extra items for group members to
-# the table of contents of the HTML help documentation and to the tree view.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
-
-TOC_EXPAND             = NO
-
-# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
-# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
-# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
-# (.qch) of the generated HTML documentation.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-GENERATE_QHP           = NO
-
-# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
-# the file name of the resulting .qch file. The path specified is relative to
-# the HTML output folder.
-# This tag requires that the tag GENERATE_QHP is set to YES.
-
-QCH_FILE               = 
-
-# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
-# Project output. For more information please see Qt Help Project / Namespace
-# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
-# The default value is: org.doxygen.Project.
-# This tag requires that the tag GENERATE_QHP is set to YES.
-
-QHP_NAMESPACE          = org.doxygen.Project
-
-# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
-# Help Project output. For more information please see Qt Help Project / Virtual
-# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
-# folders).
-# The default value is: doc.
-# This tag requires that the tag GENERATE_QHP is set to YES.
-
-QHP_VIRTUAL_FOLDER     = doc
-
-# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
-# filter to add. For more information please see Qt Help Project / Custom
-# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
-# filters).
-# This tag requires that the tag GENERATE_QHP is set to YES.
-
-QHP_CUST_FILTER_NAME   = 
-
-# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
-# custom filter to add. For more information please see Qt Help Project / Custom
-# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
-# filters).
-# This tag requires that the tag GENERATE_QHP is set to YES.
-
-QHP_CUST_FILTER_ATTRS  = 
-
-# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
-# project's filter section matches. Qt Help Project / Filter Attributes (see:
-# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
-# This tag requires that the tag GENERATE_QHP is set to YES.
-
-QHP_SECT_FILTER_ATTRS  = 
-
-# The QHG_LOCATION tag can be used to specify the location of Qt's
-# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
-# generated .qhp file.
-# This tag requires that the tag GENERATE_QHP is set to YES.
-
-QHG_LOCATION           = 
-
-# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
-# generated, together with the HTML files, they form an Eclipse help plugin. To
-# install this plugin and make it available under the help contents menu in
-# Eclipse, the contents of the directory containing the HTML and XML files needs
-# to be copied into the plugins directory of eclipse. The name of the directory
-# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
-# After copying Eclipse needs to be restarted before the help appears.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-GENERATE_ECLIPSEHELP   = NO
-
-# A unique identifier for the Eclipse help plugin. When installing the plugin
-# the directory name containing the HTML and XML files should also have this
-# name. Each documentation set should have its own identifier.
-# The default value is: org.doxygen.Project.
-# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
-
-ECLIPSE_DOC_ID         = org.doxygen.Project
-
-# If you want full control over the layout of the generated HTML pages it might
-# be necessary to disable the index and replace it with your own. The
-# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
-# of each HTML page. A value of NO enables the index and the value YES disables
-# it. Since the tabs in the index contain the same information as the navigation
-# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-DISABLE_INDEX          = NO
-
-# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
-# structure should be generated to display hierarchical information. If the tag
-# value is set to YES, a side panel will be generated containing a tree-like
-# index structure (just like the one that is generated for HTML Help). For this
-# to work a browser that supports JavaScript, DHTML, CSS and frames is required
-# (i.e. any modern browser). Windows users are probably better off using the
-# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can
-# further fine-tune the look of the index. As an example, the default style
-# sheet generated by doxygen has an example that shows how to put an image at
-# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
-# the same information as the tab index, you could consider setting
-# DISABLE_INDEX to YES when enabling this option.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-GENERATE_TREEVIEW      = YES
-
-# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
-# doxygen will group on one line in the generated HTML documentation.
-#
-# Note that a value of 0 will completely suppress the enum values from appearing
-# in the overview section.
-# Minimum value: 0, maximum value: 20, default value: 4.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-ENUM_VALUES_PER_LINE   = 4
-
-# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
-# to set the initial width (in pixels) of the frame in which the tree is shown.
-# Minimum value: 0, maximum value: 1500, default value: 250.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-TREEVIEW_WIDTH         = 250
-
-# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to
-# external symbols imported via tag files in a separate window.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-EXT_LINKS_IN_WINDOW    = NO
-
-# Use this tag to change the font size of LaTeX formulas included as images in
-# the HTML documentation. When you change the font size after a successful
-# doxygen run you need to manually remove any form_*.png images from the HTML
-# output directory to force them to be regenerated.
-# Minimum value: 8, maximum value: 50, default value: 10.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-FORMULA_FONTSIZE       = 10
-
-# Use the FORMULA_TRANPARENT tag to determine whether or not the images
-# generated for formulas are transparent PNGs. Transparent PNGs are not
-# supported properly for IE 6.0, but are supported on all modern browsers.
-#
-# Note that when changing this option you need to delete any form_*.png files in
-# the HTML output directory before the changes have effect.
-# The default value is: YES.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-FORMULA_TRANSPARENT    = YES
-
-# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
-# http://www.mathjax.org) which uses client side Javascript for the rendering
-# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
-# installed or if you want to formulas look prettier in the HTML output. When
-# enabled you may also need to install MathJax separately and configure the path
-# to it using the MATHJAX_RELPATH option.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-USE_MATHJAX            = NO
-
-# When MathJax is enabled you can set the default output format to be used for
-# the MathJax output. See the MathJax site (see:
-# http://docs.mathjax.org/en/latest/output.html) for more details.
-# Possible values are: HTML-CSS (which is slower, but has the best
-# compatibility), NativeMML (i.e. MathML) and SVG.
-# The default value is: HTML-CSS.
-# This tag requires that the tag USE_MATHJAX is set to YES.
-
-MATHJAX_FORMAT         = HTML-CSS
-
-# When MathJax is enabled you need to specify the location relative to the HTML
-# output directory using the MATHJAX_RELPATH option. The destination directory
-# should contain the MathJax.js script. For instance, if the mathjax directory
-# is located at the same level as the HTML output directory, then
-# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
-# Content Delivery Network so you can quickly see the result without installing
-# MathJax. However, it is strongly recommended to install a local copy of
-# MathJax from http://www.mathjax.org before deployment.
-# The default value is: http://cdn.mathjax.org/mathjax/latest.
-# This tag requires that the tag USE_MATHJAX is set to YES.
-
-MATHJAX_RELPATH        = http://cdn.mathjax.org/mathjax/latest
-
-# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
-# extension names that should be enabled during MathJax rendering. For example
-# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
-# This tag requires that the tag USE_MATHJAX is set to YES.
-
-MATHJAX_EXTENSIONS     = 
-
-# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
-# of code that will be used on startup of the MathJax code. See the MathJax site
-# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
-# example see the documentation.
-# This tag requires that the tag USE_MATHJAX is set to YES.
-
-MATHJAX_CODEFILE       = 
-
-# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
-# the HTML output. The underlying search engine uses javascript and DHTML and
-# should work on any modern browser. Note that when using HTML help
-# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
-# there is already a search function so this one should typically be disabled.
-# For large projects the javascript based search engine can be slow, then
-# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
-# search using the keyboard; to jump to the search box use <access key> + S
-# (what the <access key> is depends on the OS and browser, but it is typically
-# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
-# key> to jump into the search results window, the results can be navigated
-# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
-# the search. The filter options can be selected when the cursor is inside the
-# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
-# to select a filter and <Enter> or <escape> to activate or cancel the filter
-# option.
-# The default value is: YES.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-SEARCHENGINE           = YES
-
-# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
-# implemented using a web server instead of a web client using Javascript. There
-# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
-# setting. When disabled, doxygen will generate a PHP script for searching and
-# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
-# and searching needs to be provided by external tools. See the section
-# "External Indexing and Searching" for details.
-# The default value is: NO.
-# This tag requires that the tag SEARCHENGINE is set to YES.
-
-SERVER_BASED_SEARCH    = NO
-
-# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
-# script for searching. Instead the search results are written to an XML file
-# which needs to be processed by an external indexer. Doxygen will invoke an
-# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
-# search results.
-#
-# Doxygen ships with an example indexer (doxyindexer) and search engine
-# (doxysearch.cgi) which are based on the open source search engine library
-# Xapian (see: http://xapian.org/).
-#
-# See the section "External Indexing and Searching" for details.
-# The default value is: NO.
-# This tag requires that the tag SEARCHENGINE is set to YES.
-
-EXTERNAL_SEARCH        = NO
-
-# The SEARCHENGINE_URL should point to a search engine hosted by a web server
-# which will return the search results when EXTERNAL_SEARCH is enabled.
-#
-# Doxygen ships with an example indexer (doxyindexer) and search engine
-# (doxysearch.cgi) which are based on the open source search engine library
-# Xapian (see: http://xapian.org/). See the section "External Indexing and
-# Searching" for details.
-# This tag requires that the tag SEARCHENGINE is set to YES.
-
-SEARCHENGINE_URL       = 
-
-# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
-# search data is written to a file for indexing by an external tool. With the
-# SEARCHDATA_FILE tag the name of this file can be specified.
-# The default file is: searchdata.xml.
-# This tag requires that the tag SEARCHENGINE is set to YES.
-
-SEARCHDATA_FILE        = searchdata.xml
-
-# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
-# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
-# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
-# projects and redirect the results back to the right project.
-# This tag requires that the tag SEARCHENGINE is set to YES.
-
-EXTERNAL_SEARCH_ID     = 
-
-# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
-# projects other than the one defined by this configuration file, but that are
-# all added to the same external search index. Each project needs to have a
-# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
-# to a relative location where the documentation can be found. The format is:
-# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
-# This tag requires that the tag SEARCHENGINE is set to YES.
-
-EXTRA_SEARCH_MAPPINGS  = 
-
-#---------------------------------------------------------------------------
-# Configuration options related to the LaTeX output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
-# The default value is: YES.
-
-GENERATE_LATEX         = NO
-
-# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
-# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
-# it.
-# The default directory is: latex.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_OUTPUT           = latex
-
-# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
-# invoked.
-#
-# Note that when enabling USE_PDFLATEX this option is only used for generating
-# bitmaps for formulas in the HTML output, but not in the Makefile that is
-# written to the output directory.
-# The default file is: latex.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_CMD_NAME         = latex
-
-# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
-# index for LaTeX.
-# The default file is: makeindex.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-MAKEINDEX_CMD_NAME     = makeindex
-
-# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
-# documents. This may be useful for small projects and may help to save some
-# trees in general.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-COMPACT_LATEX          = NO
-
-# The PAPER_TYPE tag can be used to set the paper type that is used by the
-# printer.
-# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
-# 14 inches) and executive (7.25 x 10.5 inches).
-# The default value is: a4.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-PAPER_TYPE             = a4
-
-# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
-# that should be included in the LaTeX output. The package can be specified just
-# by its name or with the correct syntax as to be used with the LaTeX
-# \usepackage command. To get the times font for instance you can specify :
-# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times}
-# To use the option intlimits with the amsmath package you can specify:
-# EXTRA_PACKAGES=[intlimits]{amsmath}
-# If left blank no extra packages will be included.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-EXTRA_PACKAGES         = 
-
-# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
-# generated LaTeX document. The header should contain everything until the first
-# chapter. If it is left blank doxygen will generate a standard header. See
-# section "Doxygen usage" for information on how to let doxygen write the
-# default header to a separate file.
-#
-# Note: Only use a user-defined header if you know what you are doing! The
-# following commands have a special meaning inside the header: $title,
-# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
-# $projectbrief, $projectlogo. Doxygen will replace $title with the empty
-# string, for the replacement values of the other commands the user is referred
-# to HTML_HEADER.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_HEADER           = 
-
-# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
-# generated LaTeX document. The footer should contain everything after the last
-# chapter. If it is left blank doxygen will generate a standard footer. See
-# LATEX_HEADER for more information on how to generate a default footer and what
-# special commands can be used inside the footer.
-#
-# Note: Only use a user-defined footer if you know what you are doing!
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_FOOTER           = 
-
-# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined
-# LaTeX style sheets that are included after the standard style sheets created
-# by doxygen. Using this option one can overrule certain style aspects. Doxygen
-# will copy the style sheet files to the output directory.
-# Note: The order of the extra style sheet files is of importance (e.g. the last
-# style sheet in the list overrules the setting of the previous ones in the
-# list).
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_EXTRA_STYLESHEET = 
-
-# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
-# other source files which should be copied to the LATEX_OUTPUT output
-# directory. Note that the files will be copied as-is; there are no commands or
-# markers available.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_EXTRA_FILES      = 
-
-# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
-# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
-# contain links (just like the HTML output) instead of page references. This
-# makes the output suitable for online browsing using a PDF viewer.
-# The default value is: YES.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-PDF_HYPERLINKS         = YES
-
-# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
-# the PDF file directly from the LaTeX files. Set this option to YES, to get a
-# higher quality PDF documentation.
-# The default value is: YES.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-USE_PDFLATEX           = YES
-
-# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
-# command to the generated LaTeX files. This will instruct LaTeX to keep running
-# if errors occur, instead of asking the user for help. This option is also used
-# when generating formulas in HTML.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_BATCHMODE        = NO
-
-# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
-# index chapters (such as File Index, Compound Index, etc.) in the output.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_HIDE_INDICES     = NO
-
-# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
-# code with syntax highlighting in the LaTeX output.
-#
-# Note that which sources are shown also depends on other settings such as
-# SOURCE_BROWSER.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_SOURCE_CODE      = NO
-
-# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
-# bibliography, e.g. plainnat, or ieeetr. See
-# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
-# The default value is: plain.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_BIB_STYLE        = plain
-
-# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated
-# page will contain the date and time when the page was generated. Setting this
-# to NO can help when comparing the output of multiple runs.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_TIMESTAMP        = NO
-
-#---------------------------------------------------------------------------
-# Configuration options related to the RTF output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The
-# RTF output is optimized for Word 97 and may not look too pretty with other RTF
-# readers/editors.
-# The default value is: NO.
-
-GENERATE_RTF           = NO
-
-# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
-# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
-# it.
-# The default directory is: rtf.
-# This tag requires that the tag GENERATE_RTF is set to YES.
-
-RTF_OUTPUT             = rtf
-
-# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF
-# documents. This may be useful for small projects and may help to save some
-# trees in general.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_RTF is set to YES.
-
-COMPACT_RTF            = NO
-
-# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
-# contain hyperlink fields. The RTF file will contain links (just like the HTML
-# output) instead of page references. This makes the output suitable for online
-# browsing using Word or some other Word compatible readers that support those
-# fields.
-#
-# Note: WordPad (write) and others do not support links.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_RTF is set to YES.
-
-RTF_HYPERLINKS         = NO
-
-# Load stylesheet definitions from file. Syntax is similar to doxygen's config
-# file, i.e. a series of assignments. You only have to provide replacements,
-# missing definitions are set to their default value.
-#
-# See also section "Doxygen usage" for information on how to generate the
-# default style sheet that doxygen normally uses.
-# This tag requires that the tag GENERATE_RTF is set to YES.
-
-RTF_STYLESHEET_FILE    = 
-
-# Set optional variables used in the generation of an RTF document. Syntax is
-# similar to doxygen's config file. A template extensions file can be generated
-# using doxygen -e rtf extensionFile.
-# This tag requires that the tag GENERATE_RTF is set to YES.
-
-RTF_EXTENSIONS_FILE    = 
-
-# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code
-# with syntax highlighting in the RTF output.
-#
-# Note that which sources are shown also depends on other settings such as
-# SOURCE_BROWSER.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_RTF is set to YES.
-
-RTF_SOURCE_CODE        = NO
-
-#---------------------------------------------------------------------------
-# Configuration options related to the man page output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for
-# classes and files.
-# The default value is: NO.
-
-GENERATE_MAN           = NO
-
-# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
-# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
-# it. A directory man3 will be created inside the directory specified by
-# MAN_OUTPUT.
-# The default directory is: man.
-# This tag requires that the tag GENERATE_MAN is set to YES.
-
-MAN_OUTPUT             = man
-
-# The MAN_EXTENSION tag determines the extension that is added to the generated
-# man pages. In case the manual section does not start with a number, the number
-# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
-# optional.
-# The default value is: .3.
-# This tag requires that the tag GENERATE_MAN is set to YES.
-
-MAN_EXTENSION          = .3
-
-# The MAN_SUBDIR tag determines the name of the directory created within
-# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
-# MAN_EXTENSION with the initial . removed.
-# This tag requires that the tag GENERATE_MAN is set to YES.
-
-MAN_SUBDIR             = 
-
-# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
-# will generate one additional man file for each entity documented in the real
-# man page(s). These additional files only source the real man page, but without
-# them the man command would be unable to find the correct page.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_MAN is set to YES.
-
-MAN_LINKS              = NO
-
-#---------------------------------------------------------------------------
-# Configuration options related to the XML output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that
-# captures the structure of the code including all documentation.
-# The default value is: NO.
-
-GENERATE_XML           = NO
-
-# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
-# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
-# it.
-# The default directory is: xml.
-# This tag requires that the tag GENERATE_XML is set to YES.
-
-XML_OUTPUT             = xml
-
-# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program
-# listings (including syntax highlighting and cross-referencing information) to
-# the XML output. Note that enabling this will significantly increase the size
-# of the XML output.
-# The default value is: YES.
-# This tag requires that the tag GENERATE_XML is set to YES.
-
-XML_PROGRAMLISTING     = YES
-
-#---------------------------------------------------------------------------
-# Configuration options related to the DOCBOOK output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files
-# that can be used to generate PDF.
-# The default value is: NO.
-
-GENERATE_DOCBOOK       = NO
-
-# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
-# front of it.
-# The default directory is: docbook.
-# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
-
-DOCBOOK_OUTPUT         = docbook
-
-# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the
-# program listings (including syntax highlighting and cross-referencing
-# information) to the DOCBOOK output. Note that enabling this will significantly
-# increase the size of the DOCBOOK output.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
-
-DOCBOOK_PROGRAMLISTING = NO
-
-#---------------------------------------------------------------------------
-# Configuration options for the AutoGen Definitions output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
-# AutoGen Definitions (see http://autogen.sf.net) file that captures the
-# structure of the code including all documentation. Note that this feature is
-# still experimental and incomplete at the moment.
-# The default value is: NO.
-
-GENERATE_AUTOGEN_DEF   = NO
-
-#---------------------------------------------------------------------------
-# Configuration options related to the Perl module output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module
-# file that captures the structure of the code including all documentation.
-#
-# Note that this feature is still experimental and incomplete at the moment.
-# The default value is: NO.
-
-GENERATE_PERLMOD       = NO
-
-# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary
-# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
-# output from the Perl module output.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_PERLMOD is set to YES.
-
-PERLMOD_LATEX          = NO
-
-# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely
-# formatted so it can be parsed by a human reader. This is useful if you want to
-# understand what is going on. On the other hand, if this tag is set to NO, the
-# size of the Perl module output will be much smaller and Perl will parse it
-# just the same.
-# The default value is: YES.
-# This tag requires that the tag GENERATE_PERLMOD is set to YES.
-
-PERLMOD_PRETTY         = YES
-
-# The names of the make variables in the generated doxyrules.make file are
-# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
-# so different doxyrules.make files included by the same Makefile don't
-# overwrite each other's variables.
-# This tag requires that the tag GENERATE_PERLMOD is set to YES.
-
-PERLMOD_MAKEVAR_PREFIX = 
-
-#---------------------------------------------------------------------------
-# Configuration options related to the preprocessor
-#---------------------------------------------------------------------------
-
-# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all
-# C-preprocessor directives found in the sources and include files.
-# The default value is: YES.
-
-ENABLE_PREPROCESSING   = YES
-
-# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
-# in the source code. If set to NO, only conditional compilation will be
-# performed. Macro expansion can be done in a controlled way by setting
-# EXPAND_ONLY_PREDEF to YES.
-# The default value is: NO.
-# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-
-MACRO_EXPANSION        = YES
-
-# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
-# the macro expansion is limited to the macros specified with the PREDEFINED and
-# EXPAND_AS_DEFINED tags.
-# The default value is: NO.
-# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-
-EXPAND_ONLY_PREDEF     = YES
-
-# If the SEARCH_INCLUDES tag is set to YES, the include files in the
-# INCLUDE_PATH will be searched if a #include is found.
-# The default value is: YES.
-# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-
-SEARCH_INCLUDES        = YES
-
-# The INCLUDE_PATH tag can be used to specify one or more directories that
-# contain include files that are not input files but should be processed by the
-# preprocessor.
-# This tag requires that the tag SEARCH_INCLUDES is set to YES.
-
-INCLUDE_PATH           = /Volumes/A/aosp/prebuilts/clang/darwin-x86/host/3.6/lib/clang/3.6/include \
-                         /Volumes/A/aosp/external/libcxx/include \
-                         /Volumes/A/aosp/bionic/libc/include \
-                         /Volumes/A/aosp/bionic/libc/kernel/uapi \
-                         /Volumes/A/aosp/bionic/libc/kernel/uapi/asm-arm64 \
-                         /Volumes/A/aosp/external/gtest
-
-# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
-# patterns (like *.h and *.hpp) to filter out the header-files in the
-# directories. If left blank, the patterns specified with FILE_PATTERNS will be
-# used.
-# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-
-INCLUDE_FILE_PATTERNS  = 
-
-# The PREDEFINED tag can be used to specify one or more macro names that are
-# defined before the preprocessor is started (similar to the -D option of e.g.
-# gcc). The argument of the tag is a list of macros of the form: name or
-# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
-# is assumed. To prevent a macro definition from being undefined via #undef or
-# recursively expanded use the := operator instead of the = operator.
-# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-
-PREDEFINED             = __APPLE__= \
-                         __ANDROID__=1 \
-                         ANDROID:=1 \
-			 __unused=
-
-# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
-# tag can be used to specify a list of macro names that should be expanded. The
-# macro definition that is found in the sources will be used. Use the PREDEFINED
-# tag if you want to use a different macro definition that overrules the
-# definition found in the source code.
-# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-
-EXPAND_AS_DEFINED      = DEFINE_FLEXIBLE_METHODS \
-                         DEFINE_CAST_OPERATORS
-
-# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
-# remove all references to function-like macros that are alone on a line, have
-# an all uppercase name, and do not end with a semicolon. Such function macros
-# are typically used for boiler-plate code, and will confuse the parser if not
-# removed.
-# The default value is: YES.
-# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-
-SKIP_FUNCTION_MACROS   = YES
-
-#---------------------------------------------------------------------------
-# Configuration options related to external references
-#---------------------------------------------------------------------------
-
-# The TAGFILES tag can be used to specify one or more tag files. For each tag
-# file the location of the external documentation should be added. The format of
-# a tag file without this location is as follows:
-# TAGFILES = file1 file2 ...
-# Adding location for the tag files is done as follows:
-# TAGFILES = file1=loc1 "file2 = loc2" ...
-# where loc1 and loc2 can be relative or absolute paths or URLs. See the
-# section "Linking to external documentation" for more information about the use
-# of tag files.
-# Note: Each tag file must have a unique name (where the name does NOT include
-# the path). If a tag file is not located in the directory in which doxygen is
-# run, you must also specify the path to the tagfile here.
-
-TAGFILES               = 
-
-# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
-# tag file that is based on the input files it reads. See section "Linking to
-# external documentation" for more information about the usage of tag files.
-
-GENERATE_TAGFILE       = 
-
-# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
-# the class index. If set to NO, only the inherited external classes will be
-# listed.
-# The default value is: NO.
-
-ALLEXTERNALS           = NO
-
-# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
-# in the modules index. If set to NO, only the current project's groups will be
-# listed.
-# The default value is: YES.
-
-EXTERNAL_GROUPS        = YES
-
-# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in
-# the related pages index. If set to NO, only the current project's pages will
-# be listed.
-# The default value is: YES.
-
-EXTERNAL_PAGES         = YES
-
-# The PERL_PATH should be the absolute path and name of the perl script
-# interpreter (i.e. the result of 'which perl').
-# The default file (with absolute path) is: /usr/bin/perl.
-
-PERL_PATH              = /usr/bin/perl
-
-#---------------------------------------------------------------------------
-# Configuration options related to the dot tool
-#---------------------------------------------------------------------------
-
-# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram
-# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
-# NO turns the diagrams off. Note that this option also works with HAVE_DOT
-# disabled, but it is recommended to install and use dot, since it yields more
-# powerful graphs.
-# The default value is: YES.
-
-CLASS_DIAGRAMS         = YES
-
-# You can define message sequence charts within doxygen comments using the \msc
-# command. Doxygen will then run the mscgen tool (see:
-# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
-# documentation. The MSCGEN_PATH tag allows you to specify the directory where
-# the mscgen tool resides. If left empty the tool is assumed to be found in the
-# default search path.
-
-MSCGEN_PATH            = 
-
-# You can include diagrams made with dia in doxygen documentation. Doxygen will
-# then run dia to produce the diagram and insert it in the documentation. The
-# DIA_PATH tag allows you to specify the directory where the dia binary resides.
-# If left empty dia is assumed to be found in the default search path.
-
-DIA_PATH               = 
-
-# If set to YES the inheritance and collaboration graphs will hide inheritance
-# and usage relations if the target is undocumented or is not a class.
-# The default value is: YES.
-
-HIDE_UNDOC_RELATIONS   = YES
-
-# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
-# available from the path. This tool is part of Graphviz (see:
-# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
-# Bell Labs. The other options in this section have no effect if this option is
-# set to NO
-# The default value is: NO.
-
-HAVE_DOT               = NO
-
-# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
-# to run in parallel. When set to 0 doxygen will base this on the number of
-# processors available in the system. You can set it explicitly to a value
-# larger than 0 to get control over the balance between CPU load and processing
-# speed.
-# Minimum value: 0, maximum value: 32, default value: 0.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_NUM_THREADS        = 0
-
-# When you want a differently looking font in the dot files that doxygen
-# generates you can specify the font name using DOT_FONTNAME. You need to make
-# sure dot is able to find the font, which can be done by putting it in a
-# standard location or by setting the DOTFONTPATH environment variable or by
-# setting DOT_FONTPATH to the directory containing the font.
-# The default value is: Helvetica.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_FONTNAME           = Helvetica
-
-# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
-# dot graphs.
-# Minimum value: 4, maximum value: 24, default value: 10.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_FONTSIZE           = 10
-
-# By default doxygen will tell dot to use the default font as specified with
-# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
-# the path where dot can find it using this tag.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_FONTPATH           = 
-
-# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
-# each documented class showing the direct and indirect inheritance relations.
-# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-CLASS_GRAPH            = YES
-
-# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
-# graph for each documented class showing the direct and indirect implementation
-# dependencies (inheritance, containment, and class references variables) of the
-# class with other documented classes.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-COLLABORATION_GRAPH    = YES
-
-# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
-# groups, showing the direct groups dependencies.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-GROUP_GRAPHS           = YES
-
-# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and
-# collaboration diagrams in a style similar to the OMG's Unified Modeling
-# Language.
-# The default value is: NO.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-UML_LOOK               = NO
-
-# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
-# class node. If there are many fields or methods and many nodes the graph may
-# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
-# number of items for each type to make the size more manageable. Set this to 0
-# for no limit. Note that the threshold may be exceeded by 50% before the limit
-# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
-# but if the number exceeds 15, the total amount of fields shown is limited to
-# 10.
-# Minimum value: 0, maximum value: 100, default value: 10.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-UML_LIMIT_NUM_FIELDS   = 10
-
-# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
-# collaboration graphs will show the relations between templates and their
-# instances.
-# The default value is: NO.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-TEMPLATE_RELATIONS     = NO
-
-# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
-# YES then doxygen will generate a graph for each documented file showing the
-# direct and indirect include dependencies of the file with other documented
-# files.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-INCLUDE_GRAPH          = YES
-
-# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
-# set to YES then doxygen will generate a graph for each documented file showing
-# the direct and indirect include dependencies of the file with other documented
-# files.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-INCLUDED_BY_GRAPH      = YES
-
-# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
-# dependency graph for every global function or class method.
-#
-# Note that enabling this option will significantly increase the time of a run.
-# So in most cases it will be better to enable call graphs for selected
-# functions only using the \callgraph command. Disabling a call graph can be
-# accomplished by means of the command \hidecallgraph.
-# The default value is: NO.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-CALL_GRAPH             = NO
-
-# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
-# dependency graph for every global function or class method.
-#
-# Note that enabling this option will significantly increase the time of a run.
-# So in most cases it will be better to enable caller graphs for selected
-# functions only using the \callergraph command. Disabling a caller graph can be
-# accomplished by means of the command \hidecallergraph.
-# The default value is: NO.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-CALLER_GRAPH           = NO
-
-# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
-# hierarchy of all classes instead of a textual one.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-GRAPHICAL_HIERARCHY    = YES
-
-# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
-# dependencies a directory has on other directories in a graphical way. The
-# dependency relations are determined by the #include relations between the
-# files in the directories.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DIRECTORY_GRAPH        = YES
-
-# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
-# generated by dot. For an explanation of the image formats see the section
-# output formats in the documentation of the dot tool (Graphviz (see:
-# http://www.graphviz.org/)).
-# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
-# to make the SVG files visible in IE 9+ (other browsers do not have this
-# requirement).
-# Possible values are: png, jpg, gif, svg, png:gd, png:gd:gd, png:cairo,
-# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and
-# png:gdiplus:gdiplus.
-# The default value is: png.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_IMAGE_FORMAT       = png
-
-# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
-# enable generation of interactive SVG images that allow zooming and panning.
-#
-# Note that this requires a modern browser other than Internet Explorer. Tested
-# and working are Firefox, Chrome, Safari, and Opera.
-# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
-# the SVG files visible. Older versions of IE do not have SVG support.
-# The default value is: NO.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-INTERACTIVE_SVG        = NO
-
-# The DOT_PATH tag can be used to specify the path where the dot tool can be
-# found. If left blank, it is assumed the dot tool can be found in the path.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_PATH               = 
-
-# The DOTFILE_DIRS tag can be used to specify one or more directories that
-# contain dot files that are included in the documentation (see the \dotfile
-# command).
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOTFILE_DIRS           = 
-
-# The MSCFILE_DIRS tag can be used to specify one or more directories that
-# contain msc files that are included in the documentation (see the \mscfile
-# command).
-
-MSCFILE_DIRS           = 
-
-# The DIAFILE_DIRS tag can be used to specify one or more directories that
-# contain dia files that are included in the documentation (see the \diafile
-# command).
-
-DIAFILE_DIRS           = 
-
-# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
-# path where java can find the plantuml.jar file. If left blank, it is assumed
-# PlantUML is not used or called during a preprocessing step. Doxygen will
-# generate a warning when it encounters a \startuml command in this case and
-# will not generate output for the diagram.
-
-PLANTUML_JAR_PATH      = 
-
-# When using plantuml, the specified paths are searched for files specified by
-# the !include statement in a plantuml block.
-
-PLANTUML_INCLUDE_PATH  = 
-
-# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
-# that will be shown in the graph. If the number of nodes in a graph becomes
-# larger than this value, doxygen will truncate the graph, which is visualized
-# by representing a node as a red box. Note that doxygen if the number of direct
-# children of the root node in a graph is already larger than
-# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
-# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
-# Minimum value: 0, maximum value: 10000, default value: 50.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_GRAPH_MAX_NODES    = 50
-
-# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
-# generated by dot. A depth value of 3 means that only nodes reachable from the
-# root by following a path via at most 3 edges will be shown. Nodes that lay
-# further from the root node will be omitted. Note that setting this option to 1
-# or 2 may greatly reduce the computation time needed for large code bases. Also
-# note that the size of a graph can be further restricted by
-# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
-# Minimum value: 0, maximum value: 1000, default value: 0.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-MAX_DOT_GRAPH_DEPTH    = 0
-
-# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
-# background. This is disabled by default, because dot on Windows does not seem
-# to support this out of the box.
-#
-# Warning: Depending on the platform used, enabling this option may lead to
-# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
-# read).
-# The default value is: NO.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_TRANSPARENT        = NO
-
-# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
-# files in one run (i.e. multiple -o and -T options on the command line). This
-# makes dot run faster, but since only newer versions of dot (>1.8.10) support
-# this, this feature is disabled by default.
-# The default value is: NO.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_MULTI_TARGETS      = NO
-
-# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
-# explaining the meaning of the various boxes and arrows in the dot generated
-# graphs.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-GENERATE_LEGEND        = YES
-
-# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot
-# files that are used to generate the various graphs.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_CLEANUP            = YES
diff --git a/codec2/faultinjection/Android.bp b/codec2/faultinjection/Android.bp
new file mode 100644
index 0000000..ef7871e
--- /dev/null
+++ b/codec2/faultinjection/Android.bp
@@ -0,0 +1,29 @@
+cc_library_shared {
+    name: "libc2_component_wrapper",
+    vendor_available: true,
+
+    srcs: [
+        "C2ComponentWrapper.cpp",
+        "SimpleMethodState.cpp",
+    ],
+
+    shared_libs: [
+        "libcutils",
+        "liblog",
+        "libstagefright_codec2",
+        "libstagefright_codec2_vndk",
+        "libstagefright_foundation",
+        "libutils",
+    ],
+
+    sanitize: {
+        misc_undefined: [
+            "unsigned-integer-overflow",
+            "signed-integer-overflow",
+        ],
+        cfi: true,
+    },
+
+    ldflags: ["-Wl,-Bsymbolic"],
+}
+
diff --git a/codec2/faultinjection/C2ComponentWrapper.cpp b/codec2/faultinjection/C2ComponentWrapper.cpp
new file mode 100644
index 0000000..c45f8bf
--- /dev/null
+++ b/codec2/faultinjection/C2ComponentWrapper.cpp
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "C2ComponentWrapper"
+
+#include <chrono>
+#include <functional>
+#include <thread>
+
+#include <C2ComponentWrapper.h>
+#include <C2Config.h>
+#include <C2PlatformSupport.h>
+
+namespace android {
+
+namespace {
+
+using namespace std::chrono_literals;
+
+c2_status_t WrapSimpleMethod(
+        std::function<c2_status_t(void)> op, const SimpleMethodState &state) {
+    c2_status_t result = C2_OK;
+    switch (state.getMode()) {
+        case SimpleMethodState::EXECUTE:
+            result = op();
+            break;
+        case SimpleMethodState::NO_OP:
+            break;
+        case SimpleMethodState::HANG:
+            while (true) {
+                std::this_thread::sleep_for(1s);
+            }
+            break;
+    }
+    (void)state.overrideResult(&result);
+    return result;
+}
+
+}  // namespace
+
+C2ComponentWrapper::Injecter::Injecter(C2ComponentWrapper *thiz) : mThiz(thiz) {}
+
+SimpleMethodState::Injecter C2ComponentWrapper::Injecter::start() {
+    return SimpleMethodState::Injecter(&mThiz->mStartState);
+}
+
+C2ComponentWrapper::Listener::Listener(
+        const std::shared_ptr<C2Component::Listener> &listener) : mListener(listener) {}
+
+void C2ComponentWrapper::Listener::onWorkDone_nb(std::weak_ptr<C2Component> component,
+        std::list<std::unique_ptr<C2Work>> workItems) {
+    mListener->onWorkDone_nb(component, std::move(workItems));
+}
+
+void C2ComponentWrapper::Listener::onTripped_nb(std::weak_ptr<C2Component> component,
+        std::vector<std::shared_ptr<C2SettingResult>> settingResult) {
+    mListener->onTripped_nb(component,settingResult);
+}
+
+void C2ComponentWrapper::Listener::onError_nb(
+        std::weak_ptr<C2Component> component, uint32_t errorCode) {
+    mListener->onError_nb(component, errorCode);
+}
+
+C2ComponentWrapper::C2ComponentWrapper(
+        const std::shared_ptr<C2Component> &comp) : mComp(comp) {}
+
+c2_status_t C2ComponentWrapper::setListener_vb(
+        const std::shared_ptr<C2Component::Listener> &listener, c2_blocking_t mayBlock) {
+    mListener = std::make_shared<Listener>(listener);
+    return mComp->setListener_vb(mListener, mayBlock);
+}
+
+c2_status_t C2ComponentWrapper::queue_nb(std::list<std::unique_ptr<C2Work>>* const items) {
+    return mComp->queue_nb(items);
+}
+
+c2_status_t C2ComponentWrapper::announce_nb(const std::vector<C2WorkOutline> &items) {
+    return mComp->announce_nb(items);
+}
+
+c2_status_t C2ComponentWrapper::flush_sm(
+        C2Component::flush_mode_t mode, std::list<std::unique_ptr<C2Work>>* const flushedWork) {
+    return mComp->flush_sm(mode, flushedWork);
+}
+
+c2_status_t C2ComponentWrapper::drain_nb(C2Component::drain_mode_t mode) {
+    return mComp->drain_nb(mode);
+}
+
+c2_status_t C2ComponentWrapper::start() {
+    return WrapSimpleMethod([this] { return mComp->start(); }, mStartState);
+}
+
+c2_status_t C2ComponentWrapper::stop() {
+    return mComp->stop();
+}
+
+c2_status_t C2ComponentWrapper::reset() {
+    return mComp->reset();
+}
+
+c2_status_t C2ComponentWrapper::release() {
+    return mComp->release();
+}
+
+std::shared_ptr<C2ComponentInterface> C2ComponentWrapper::intf(){
+    return mComp->intf();
+}
+
+C2ComponentWrapper::Injecter C2ComponentWrapper::inject() {
+    return Injecter(this);
+}
+
+}  // namespace android
diff --git a/codec2/faultinjection/C2ComponentWrapper.h b/codec2/faultinjection/C2ComponentWrapper.h
new file mode 100644
index 0000000..737350d
--- /dev/null
+++ b/codec2/faultinjection/C2ComponentWrapper.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef C2_COMPONENT_WRAPPER_H_
+#define C2_COMPONENT_WRAPPER_H_
+
+#include <C2Component.h>
+
+#include "SimpleMethodState.h"
+
+namespace android {
+
+/**
+ * Creates a Wrapper around the class C2Component and its methods. The wrapper is used to
+ * simulate errors in the android media components by fault injection technique.
+ * This is done to check how the framework handles the error situation.
+ */
+class C2ComponentWrapper
+        : public C2Component, public std::enable_shared_from_this<C2ComponentWrapper> {
+public:
+    class Injecter {
+    public:
+        explicit Injecter(C2ComponentWrapper *thiz);
+
+        SimpleMethodState::Injecter start();
+    private:
+        C2ComponentWrapper *const mThiz;
+    };
+
+    /**
+     * A wrapper around the listener class inside C2Component class.
+     */
+    class Listener : public C2Component::Listener {
+    public:
+        explicit Listener(const std::shared_ptr<C2Component::Listener> &listener);
+        virtual ~Listener() = default;
+
+        void onWorkDone_nb(std::weak_ptr<C2Component> component,
+                           std::list<std::unique_ptr<C2Work>> workItems) override;
+        void onTripped_nb(std::weak_ptr<C2Component> component,
+                          std::vector<std::shared_ptr<C2SettingResult>> settingResult) override;
+        void onError_nb(std::weak_ptr<C2Component> component, uint32_t errorCode) override;
+
+    private:
+        std::shared_ptr<C2Component::Listener> mListener;
+    };
+
+    explicit C2ComponentWrapper(const std::shared_ptr<C2Component> &comp);
+    virtual ~C2ComponentWrapper() = default;
+
+    virtual c2_status_t setListener_vb(
+            const std::shared_ptr<C2Component::Listener> &listener,
+            c2_blocking_t mayBlock) override;
+    virtual c2_status_t queue_nb(std::list<std::unique_ptr<C2Work>>* const items) override;
+    virtual c2_status_t announce_nb(const std::vector<C2WorkOutline> &items) override;
+    virtual c2_status_t flush_sm(
+            flush_mode_t mode, std::list<std::unique_ptr<C2Work>>* const flushedWork) override;
+    virtual c2_status_t drain_nb(drain_mode_t mode) override;
+    virtual c2_status_t start() override;
+    virtual c2_status_t stop() override;
+    virtual c2_status_t reset() override;
+    virtual c2_status_t release() override;
+    virtual std::shared_ptr<C2ComponentInterface> intf() override;
+
+    Injecter inject();
+
+private:
+    std::shared_ptr<Listener> mListener;
+    std::shared_ptr<C2Component> mComp;
+
+    SimpleMethodState mStartState;
+};
+
+}  // namespace android
+
+#endif // C2_COMPONENT_WRAPPER_H_
diff --git a/codec2/faultinjection/SimpleMethodState.cpp b/codec2/faultinjection/SimpleMethodState.cpp
new file mode 100644
index 0000000..179d64e
--- /dev/null
+++ b/codec2/faultinjection/SimpleMethodState.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "SimpleMethodState"
+#include <log/log.h>
+
+#include "SimpleMethodState.h"
+
+namespace android {
+
+SimpleMethodState::Injecter::Injecter(SimpleMethodState *thiz) : mThiz(thiz) {}
+
+void SimpleMethodState::Injecter::hang() {
+    mThiz->mMode = HANG;
+}
+
+void SimpleMethodState::Injecter::fail(c2_status_t err, bool execute) {
+    mThiz->mMode = execute ? EXECUTE : NO_OP;
+    mThiz->mOverride = true;
+    mThiz->mResultOverride = err;
+}
+
+SimpleMethodState::SimpleMethodState()
+    : mMode(EXECUTE), mOverride(false), mResultOverride(C2_OK) {}
+
+SimpleMethodState::Mode SimpleMethodState::getMode() const {
+    return mMode;
+}
+
+bool SimpleMethodState::overrideResult(c2_status_t *result) const {
+    if (!mOverride) {
+        return false;
+    }
+    *result = mResultOverride;
+    return true;
+}
+
+}  // namespace android
diff --git a/codec2/faultinjection/SimpleMethodState.h b/codec2/faultinjection/SimpleMethodState.h
new file mode 100644
index 0000000..dc0459d
--- /dev/null
+++ b/codec2/faultinjection/SimpleMethodState.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SIMPLE_METHOD_STATE_H_
+#define SIMPLE_METHOD_STATE_H_
+
+#include <C2.h>
+
+namespace android {
+
+/**
+ * State for a simple method which returns c2_status_t and takes no parameters.
+ */
+class SimpleMethodState {
+public:
+    enum Mode {
+        // Execute the normal operation
+        EXECUTE,
+        // Don't do anything
+        NO_OP,
+        // Hang; never return
+        HANG,
+    };
+
+    /**
+     * Injecter class that modifies the internal states of this class.
+     */
+    class Injecter {
+    public:
+        explicit Injecter(SimpleMethodState *thiz);
+
+        /**
+         * Hang the operation.
+         */
+        void hang();
+
+        /**
+         * Fail the operation with given params.
+         *
+         * \param err       error code to replace the actual return value
+         * \param execute   whether the wrapper should execute the operation
+         */
+        void fail(c2_status_t err, bool execute = false);
+
+    private:
+        SimpleMethodState *const mThiz;
+    };
+
+    SimpleMethodState();
+
+    /**
+     * Get execution mode.
+     */
+    Mode getMode() const;
+
+    /**
+     * Override result from running the operation if configured so.
+     */
+    bool overrideResult(c2_status_t *result) const;
+
+private:
+    Mode mMode;
+    bool mOverride;
+    c2_status_t mResultOverride;
+};
+
+}  // namespace android
+
+#endif // SIMPLE_METHOD_STATE_H_
diff --git a/codec2/hidl/1.0/mts/audio/MtsHidlC2V1_0TargetAudioDecTest.cpp b/codec2/hidl/1.0/mts/audio/MtsHidlC2V1_0TargetAudioDecTest.cpp
index f9ae8ba..1e87f38 100644
--- a/codec2/hidl/1.0/mts/audio/MtsHidlC2V1_0TargetAudioDecTest.cpp
+++ b/codec2/hidl/1.0/mts/audio/MtsHidlC2V1_0TargetAudioDecTest.cpp
@@ -19,6 +19,7 @@
 
 #include <android-base/logging.h>
 #include <gtest/gtest.h>
+#include <algorithm>
 #include <stdio.h>
 #include <fstream>
 
@@ -133,6 +134,8 @@
         }
         mEos = false;
         mFramesReceived = 0;
+        mTimestampUs = 0u;
+        mTimestampDevTest = false;
         if (mCompName == unknown_comp) mDisableTest = true;
         if (mDisableTest) std::cout << "[   WARN   ] Test Disabled \n";
     }
@@ -146,38 +149,39 @@
         Super::TearDown();
     }
 
+    struct outputMetaData {
+        uint64_t timestampUs;
+        uint32_t rangeLength;
+    };
     // callback function to process onWorkDone received by Listener
     void handleWorkDone(std::list<std::unique_ptr<C2Work>>& workItems) {
         for (std::unique_ptr<C2Work>& work : workItems) {
-            // handle configuration changes in work done
-            if (!work->worklets.empty() &&
-                (work->worklets.front()->output.configUpdate.size() != 0)) {
-                ALOGV("Config Update");
-                std::vector<std::unique_ptr<C2Param>> updates =
-                    std::move(work->worklets.front()->output.configUpdate);
-                std::vector<C2Param*> configParam;
-                std::vector<std::unique_ptr<C2SettingResult>> failures;
-                for (size_t i = 0; i < updates.size(); ++i) {
-                    C2Param* param = updates[i].get();
-                    if ((param->index() == C2StreamSampleRateInfo::output::PARAM_TYPE) ||
-                        (param->index() == C2StreamChannelCountInfo::output::PARAM_TYPE)) {
-                        configParam.push_back(param);
+            if (!work->worklets.empty()) {
+                // For decoder components current timestamp always exceeds
+                // previous timestamp
+                bool codecConfig = ((work->worklets.front()->output.flags &
+                                     C2FrameData::FLAG_CODEC_CONFIG) != 0);
+                if (!codecConfig &&
+                    !work->worklets.front()->output.buffers.empty()) {
+                    EXPECT_GE(work->worklets.front()->output.ordinal.timestamp.peeku(),
+                        mTimestampUs);
+                    mTimestampUs =
+                        work->worklets.front()->output.ordinal.timestamp.peeku();
+                    uint32_t rangeLength =
+                        work->worklets.front()->output.buffers[0]->data()
+                        .linearBlocks().front().map().get().capacity();
+                    //List of timestamp values and output size to calculate timestamp
+                    if (mTimestampDevTest) {
+                        outputMetaData meta = {mTimestampUs, rangeLength};
+                        oBufferMetaData.push_back(meta);
                     }
                 }
-                mComponent->config(configParam, C2_DONT_BLOCK, &failures);
-                ASSERT_EQ(failures.size(), 0u);
+                bool mCsd = false;
+                workDone(mComponent, work, mFlushedIndices, mQueueLock,
+                         mQueueCondition, mWorkQueue, mEos, mCsd,
+                         mFramesReceived);
+                (void)mCsd;
             }
-            mFramesReceived++;
-            mEos = (work->worklets.front()->output.flags &
-                    C2FrameData::FLAG_END_OF_STREAM) != 0;
-            ALOGV("WorkDone: frameID received %d",
-                (int)work->worklets.front()->output.ordinal.frameIndex.peeku());
-            work->input.buffers.clear();
-            work->worklets.clear();
-            typedef std::unique_lock<std::mutex> ULock;
-            ULock l(mQueueLock);
-            mWorkQueue.push_back(std::move(work));
-            mQueueCondition.notify_all();
         }
     }
 
@@ -200,8 +204,14 @@
 
     bool mEos;
     bool mDisableTest;
+    bool mTimestampDevTest;
     standardComp mCompName;
+    uint64_t mTimestampUs;
     uint32_t mFramesReceived;
+    std::list<uint64_t> mFlushedIndices;
+    std::list<uint64_t> mTimestampUslist;
+    ::android::List<outputMetaData> oBufferMetaData;
+
     C2BlockPool::local_id_t mBlockPoolId;
     std::shared_ptr<C2BlockPool> mLinearPool;
     std::shared_ptr<C2Allocator> mLinearAllocator;
@@ -254,7 +264,7 @@
 
     // Validates component name
     if (compName == Codec2AudioDecHidlTest::unknown_comp) {
-        ALOGD("Component InValid");
+        ALOGE("Component InValid");
         disableTest = true;
         return;
     }
@@ -295,37 +305,9 @@
         ASSERT_TRUE(false);
     } else {
         size_t offset = sizeof(C2Param);
-        ALOGD("--------------PARAMS-----------------");
         for (size_t i = 0; i < inParams.size(); ++i) {
             C2Param* param = inParams[i].get();
             bitStreamInfo[i] = *(int32_t*)((uint8_t*)param + offset);
-            ALOGD("Param value : %u", *(int32_t*)((uint8_t*)param + offset));
-            ALOGD("Param isVendor %d", param->isVendor());
-            ALOGD("Param forInput %d", param->forInput());
-            ALOGD("Param forOutput %d", param->forOutput());
-            switch (param->kind()) {
-                case C2Param::NONE:
-                    ALOGD("Param kind NONE");
-                    break;
-                case C2Param::STRUCT:
-                    ALOGD("Param kind STRUCT");
-                    break;
-                case C2Param::INFO:
-                    ALOGD("Param kind INFO");
-                    break;
-                case C2Param::SETTING:
-                    ALOGD("Param kind SETTING");
-                    break;
-                case C2Param::TUNING:
-                    ALOGD("Param kind TUNING");
-                    break;
-                default:
-                    ALOGD("Param kind Invalid");
-                    break;
-            }
-            ALOGD("Param size (if size is 0 parameter is invalid) %zu",
-                  param->size());
-            ALOGD("--------------------------------------");
         }
         switch (compName) {
             case Codec2AudioDecHidlTest::amrnb: {
@@ -404,20 +386,16 @@
     }
 }
 
-void decodeNFrames(const std::shared_ptr<android::Codec2Client::Component> &component,
-                   std::mutex &queueLock, std::condition_variable &queueCondition,
-                   std::list<std::unique_ptr<C2Work>> &workQueue,
-                   std::shared_ptr<C2Allocator> &linearAllocator,
-                   std::shared_ptr<C2BlockPool> &linearPool,
-                   C2BlockPool::local_id_t blockPoolId,
+void decodeNFrames(const std::shared_ptr<android::Codec2Client::Component>& component,
+                   std::mutex &queueLock, std::condition_variable& queueCondition,
+                   std::list<std::unique_ptr<C2Work>>& workQueue,
+                   std::list<uint64_t>& flushedIndices,
+                   std::shared_ptr<C2BlockPool>& linearPool,
                    std::ifstream& eleStream,
                    android::Vector<FrameInfo>* Info,
                    int offset, int range, bool signalEOS = true) {
     typedef std::unique_lock<std::mutex> ULock;
-    int frameID = 0;
-    linearPool =
-        std::make_shared<C2PooledBlockPool>(linearAllocator, blockPoolId++);
-    component->start();
+    int frameID = offset;
     int maxRetry = 0;
     while (1) {
         if (frameID == (int)Info->size() || frameID == (offset + range)) break;
@@ -440,42 +418,49 @@
         int64_t timestamp = (*Info)[frameID].timestamp;
         if ((*Info)[frameID].flags) flags = 1u << ((*Info)[frameID].flags - 1);
         if (signalEOS && ((frameID == (int)Info->size() - 1) ||
-                              (frameID == (offset + range - 1))))
-                flags |= C2FrameData::FLAG_END_OF_STREAM;
+                          (frameID == (offset + range - 1))))
+            flags |= C2FrameData::FLAG_END_OF_STREAM;
 
         work->input.flags = (C2FrameData::flags_t)flags;
         work->input.ordinal.timestamp = timestamp;
         work->input.ordinal.frameIndex = frameID;
+        {
+            ULock l(queueLock);
+            flushedIndices.emplace_back(frameID);
+        }
         int size = (*Info)[frameID].bytesCount;
         char* data = (char*)malloc(size);
+        ASSERT_NE(data, nullptr);
 
         eleStream.read(data, size);
         ASSERT_EQ(eleStream.gcount(), size);
 
-        std::shared_ptr<C2LinearBlock> block;
-        ASSERT_EQ(C2_OK,
-                  linearPool->fetchLinearBlock(
-                      size, {C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE},
-                      &block));
-        ASSERT_TRUE(block);
-
-        // Write View
-        C2WriteView view = block->map().get();
-        if (view.error() != C2_OK) {
-            fprintf(stderr, "C2LinearBlock::map() failed : %d", view.error());
-            break;
-        }
-        ASSERT_EQ((size_t)size, view.capacity());
-        ASSERT_EQ(0u, view.offset());
-        ASSERT_EQ((size_t)size, view.size());
-
-        memcpy(view.base(), data, size);
-
         work->input.buffers.clear();
-        work->input.buffers.emplace_back(new LinearBuffer(block));
+        if (size) {
+            std::shared_ptr<C2LinearBlock> block;
+            ASSERT_EQ(C2_OK,
+                    linearPool->fetchLinearBlock(
+                        size, {C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE},
+                        &block));
+            ASSERT_TRUE(block);
+
+            // Write View
+            C2WriteView view = block->map().get();
+            if (view.error() != C2_OK) {
+                fprintf(stderr, "C2LinearBlock::map() failed : %d", view.error());
+                break;
+            }
+            ASSERT_EQ((size_t)size, view.capacity());
+            ASSERT_EQ(0u, view.offset());
+            ASSERT_EQ((size_t)size, view.size());
+
+            memcpy(view.base(), data, size);
+
+            work->input.buffers.emplace_back(new LinearBuffer(block));
+            free(data);
+        }
         work->worklets.clear();
         work->worklets.emplace_back(new C2Worklet);
-        free(data);
 
         std::list<std::unique_ptr<C2Work>> items;
         items.push_back(std::move(work));
@@ -488,28 +473,6 @@
     }
 }
 
-void waitOnInputConsumption(std::mutex& queueLock,
-                            std::condition_variable& queueCondition,
-                            std::list<std::unique_ptr<C2Work>>& workQueue) {
-    typedef std::unique_lock<std::mutex> ULock;
-    uint32_t queueSize;
-    uint32_t maxRetry = 0;
-    {
-        ULock l(queueLock);
-        queueSize = workQueue.size();
-    }
-    while ((maxRetry < MAX_RETRY) && (queueSize < MAX_INPUT_BUFFERS)) {
-        ULock l(queueLock);
-        if (queueSize != workQueue.size()) {
-            queueSize = workQueue.size();
-            maxRetry = 0;
-        } else {
-            queueCondition.wait_for(l, TIME_OUT);
-            maxRetry++;
-        }
-    }
-}
-
 TEST_F(Codec2AudioDecHidlTest, validateCompName) {
     if (mDisableTest) return;
     ALOGV("Checks if the given component is a valid audio component");
@@ -520,16 +483,106 @@
 TEST_F(Codec2AudioDecHidlTest, configComp) {
     description("Tests component specific configuration");
     if (mDisableTest) return;
+    ASSERT_EQ(mComponent->start(), C2_OK);
     int32_t bitStreamInfo[2] = {0};
     ASSERT_NO_FATAL_FAILURE(
         getInputChannelInfo(mComponent, mCompName, bitStreamInfo));
     setupConfigParam(mComponent, bitStreamInfo);
+    ASSERT_EQ(mComponent->stop(), C2_OK);
 }
 
 TEST_F(Codec2AudioDecHidlTest, DecodeTest) {
     description("Decodes input file");
     if (mDisableTest) return;
 
+    ASSERT_EQ(mComponent->start(), C2_OK);
+    mTimestampDevTest = true;
+    char mURL[512], info[512];
+    std::ifstream eleStream, eleInfo;
+
+    strcpy(mURL, gEnv->getRes().c_str());
+    strcpy(info, gEnv->getRes().c_str());
+    GetURLForComponent(mCompName, mURL, info);
+
+    eleInfo.open(info);
+    ASSERT_EQ(eleInfo.is_open(), true);
+    android::Vector<FrameInfo> Info;
+    int bytesCount = 0;
+    uint32_t flags = 0;
+    uint32_t timestamp = 0;
+    while (1) {
+        if (!(eleInfo >> bytesCount)) break;
+        eleInfo >> flags;
+        eleInfo >> timestamp;
+        bool codecConfig =
+            ((1 << (flags - 1)) & C2FrameData::FLAG_CODEC_CONFIG) != 0;
+        if (mTimestampDevTest && !codecConfig)
+            mTimestampUslist.push_back(timestamp);
+        Info.push_back({bytesCount, flags, timestamp});
+    }
+    eleInfo.close();
+    int32_t bitStreamInfo[2] = {0};
+    if (mCompName == raw) {
+        bitStreamInfo[0] = 8000;
+        bitStreamInfo[1] = 1;
+    } else {
+        ASSERT_NO_FATAL_FAILURE(
+            getInputChannelInfo(mComponent, mCompName, bitStreamInfo));
+    }
+    setupConfigParam(mComponent, bitStreamInfo);
+    ALOGV("mURL : %s", mURL);
+    eleStream.open(mURL, std::ifstream::binary);
+    ASSERT_EQ(eleStream.is_open(), true);
+    ASSERT_NO_FATAL_FAILURE(decodeNFrames(
+        mComponent, mQueueLock, mQueueCondition, mWorkQueue, mFlushedIndices,
+        mLinearPool, eleStream, &Info, 0, (int)Info.size()));
+    // blocking call to ensures application to Wait till all the inputs are
+    // consumed
+    ASSERT_NO_FATAL_FAILURE(
+        waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue));
+    eleStream.close();
+    if (mFramesReceived != Info.size()) {
+        ALOGE("Input buffer count and Output buffer count mismatch");
+        ALOGE("framesReceived : %d inputFrames : %zu", mFramesReceived,
+              Info.size());
+        ASSERT_TRUE(false);
+    }
+    ASSERT_EQ(mEos, true);
+    if (mTimestampDevTest) {
+        uint64_t expTs;
+        uint32_t samplesReceived = 0;
+        // Update SampleRate and ChannelCount
+        ASSERT_NO_FATAL_FAILURE(
+            getInputChannelInfo(mComponent, mCompName, bitStreamInfo));
+        int nSampleRate = bitStreamInfo[0];
+        int nChannels = bitStreamInfo[1];
+        std::list<uint64_t>::iterator itIn = mTimestampUslist.begin();
+        android::List<outputMetaData>::iterator itOut = oBufferMetaData.begin();
+        EXPECT_EQ(*itIn, itOut->timestampUs);
+        expTs = *itIn;
+        while (itOut != oBufferMetaData.end()) {
+            EXPECT_EQ(expTs, itOut->timestampUs);
+            if (expTs != itOut->timestampUs) break;
+            // buffer samples = ((total bytes) / (ac * (bits per sample / 8))
+            samplesReceived += ((itOut->rangeLength) / (nChannels * 2));
+            expTs = samplesReceived * 1000000ll / nSampleRate;
+            itOut++;
+        }
+        itIn = mTimestampUslist.end();
+        --itIn;
+        EXPECT_GT(expTs, *itIn);
+        oBufferMetaData.clear();
+        mTimestampUslist.clear();
+    }
+    ASSERT_EQ(mComponent->stop(), C2_OK);
+}
+
+// thumbnail test
+TEST_F(Codec2AudioDecHidlTest, ThumbnailTest) {
+    description("Test Request for thumbnail");
+    if (mDisableTest) return;
+
+    ASSERT_EQ(mComponent->start(), C2_OK);
     char mURL[512], info[512];
     std::ifstream eleStream, eleInfo;
 
@@ -560,16 +613,242 @@
     }
     setupConfigParam(mComponent, bitStreamInfo);
     ALOGV("mURL : %s", mURL);
+
+    // request EOS for thumbnail
+    // signal EOS flag with last frame
+    size_t i = -1;
+    do {
+        i++;
+        flags = 0;
+        if (Info[i].flags) flags = 1u << (Info[i].flags - 1);
+
+    } while (!(flags & SYNC_FRAME));
     eleStream.open(mURL, std::ifstream::binary);
     ASSERT_EQ(eleStream.is_open(), true);
     ASSERT_NO_FATAL_FAILURE(decodeNFrames(
-        mComponent, mQueueLock, mQueueCondition, mWorkQueue, mLinearAllocator,
-        mLinearPool, mBlockPoolId, eleStream, &Info, 0, (int)Info.size()));
+        mComponent, mQueueLock, mQueueCondition, mWorkQueue, mFlushedIndices,
+        mLinearPool, eleStream, &Info, 0, i + 1));
+    ASSERT_NO_FATAL_FAILURE(
+        waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue));
+    eleStream.close();
+    EXPECT_GE(mFramesReceived, 1U);
+    ASSERT_EQ(mEos, true);
+    ASSERT_EQ(mComponent->stop(), C2_OK);
+}
+
+TEST_F(Codec2AudioDecHidlTest, EOSTest) {
+    description("Test empty input buffer with EOS flag");
+    if (mDisableTest) return;
+    typedef std::unique_lock<std::mutex> ULock;
+    ASSERT_EQ(mComponent->start(), C2_OK);
+    std::unique_ptr<C2Work> work;
+    // Prepare C2Work
+    {
+        ULock l(mQueueLock);
+        if (!mWorkQueue.empty()) {
+            work.swap(mWorkQueue.front());
+            mWorkQueue.pop_front();
+        } else {
+            ASSERT_TRUE(false) << "mWorkQueue Empty at the start of test";
+        }
+    }
+    ASSERT_NE(work, nullptr);
+
+    work->input.flags = (C2FrameData::flags_t)C2FrameData::FLAG_END_OF_STREAM;
+    work->input.ordinal.timestamp = 0;
+    work->input.ordinal.frameIndex = 0;
+    work->input.buffers.clear();
+    work->worklets.clear();
+    work->worklets.emplace_back(new C2Worklet);
+
+    std::list<std::unique_ptr<C2Work>> items;
+    items.push_back(std::move(work));
+    ASSERT_EQ(mComponent->queue(&items), C2_OK);
+
+    {
+        ULock l(mQueueLock);
+        if (mWorkQueue.size() != MAX_INPUT_BUFFERS) {
+            mQueueCondition.wait_for(l, TIME_OUT);
+        }
+    }
+    ASSERT_EQ(mEos, true);
+    ASSERT_EQ(mWorkQueue.size(), (size_t)MAX_INPUT_BUFFERS);
+    ASSERT_EQ(mComponent->stop(), C2_OK);
+}
+
+TEST_F(Codec2AudioDecHidlTest, FlushTest) {
+    description("Tests Flush calls");
+    if (mDisableTest) return;
+    typedef std::unique_lock<std::mutex> ULock;
+    ASSERT_EQ(mComponent->start(), C2_OK);
+    char mURL[512], info[512];
+    std::ifstream eleStream, eleInfo;
+
+    strcpy(mURL, gEnv->getRes().c_str());
+    strcpy(info, gEnv->getRes().c_str());
+    GetURLForComponent(mCompName, mURL, info);
+
+    eleInfo.open(info);
+    ASSERT_EQ(eleInfo.is_open(), true);
+    android::Vector<FrameInfo> Info;
+    int bytesCount = 0;
+    uint32_t flags = 0;
+    uint32_t timestamp = 0;
+    mFlushedIndices.clear();
+    while (1) {
+        if (!(eleInfo >> bytesCount)) break;
+        eleInfo >> flags;
+        eleInfo >> timestamp;
+        Info.push_back({bytesCount, flags, timestamp});
+    }
+    eleInfo.close();
+    int32_t bitStreamInfo[2] = {0};
+    if (mCompName == raw) {
+        bitStreamInfo[0] = 8000;
+        bitStreamInfo[1] = 1;
+    } else {
+        ASSERT_NO_FATAL_FAILURE(
+            getInputChannelInfo(mComponent, mCompName, bitStreamInfo));
+    }
+    setupConfigParam(mComponent, bitStreamInfo);
+    ALOGV("mURL : %s", mURL);
+    eleStream.open(mURL, std::ifstream::binary);
+    ASSERT_EQ(eleStream.is_open(), true);
+    // Decode 128 frames and flush. here 128 is chosen to ensure there is a key
+    // frame after this so that the below section can be covered for all
+    // components
+    uint32_t numFramesFlushed = 128;
+    ASSERT_NO_FATAL_FAILURE(decodeNFrames(
+        mComponent, mQueueLock, mQueueCondition, mWorkQueue, mFlushedIndices,
+        mLinearPool, eleStream, &Info, 0, numFramesFlushed, false));
+    // flush
+    std::list<std::unique_ptr<C2Work>> flushedWork;
+    c2_status_t err =
+        mComponent->flush(C2Component::FLUSH_COMPONENT, &flushedWork);
+    ASSERT_EQ(err, C2_OK);
+    ASSERT_NO_FATAL_FAILURE(
+        waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue,
+            (size_t)MAX_INPUT_BUFFERS - flushedWork.size()));
+    uint64_t frameIndex;
+    {
+        //Update mFlushedIndices based on the index received from flush()
+        ULock l(mQueueLock);
+        for (std::unique_ptr<C2Work>& work : flushedWork) {
+            ASSERT_NE(work, nullptr);
+            frameIndex = work->input.ordinal.frameIndex.peeku();
+            std::list<uint64_t>::iterator frameIndexIt =
+                std::find(mFlushedIndices.begin(), mFlushedIndices.end(),
+                          frameIndex);
+            if (!mFlushedIndices.empty() &&
+                (frameIndexIt != mFlushedIndices.end())) {
+                mFlushedIndices.erase(frameIndexIt);
+                work->input.buffers.clear();
+                work->worklets.clear();
+                mWorkQueue.push_back(std::move(work));
+            }
+        }
+    }
+    // Seek to next key frame and start decoding till the end
+    mFlushedIndices.clear();
+    int index = numFramesFlushed;
+    bool keyFrame = false;
+    flags = 0;
+    while (index < (int)Info.size()) {
+        if (Info[index].flags) flags = 1u << (Info[index].flags - 1);
+        if ((flags & SYNC_FRAME) == SYNC_FRAME) {
+            keyFrame = true;
+            break;
+        }
+        flags = 0;
+        eleStream.ignore(Info[index].bytesCount);
+        index++;
+    }
+    if (keyFrame) {
+        ASSERT_NO_FATAL_FAILURE(
+            decodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
+                          mFlushedIndices, mLinearPool, eleStream, &Info, index,
+                          (int)Info.size() - index));
+    }
+    eleStream.close();
+    err =
+        mComponent->flush(C2Component::FLUSH_COMPONENT, &flushedWork);
+    ASSERT_EQ(err, C2_OK);
+    ASSERT_NO_FATAL_FAILURE(
+        waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue,
+            (size_t)MAX_INPUT_BUFFERS - flushedWork.size()));
+    {
+        //Update mFlushedIndices based on the index received from flush()
+        ULock l(mQueueLock);
+        for (std::unique_ptr<C2Work>& work : flushedWork) {
+            ASSERT_NE(work, nullptr);
+            frameIndex = work->input.ordinal.frameIndex.peeku();
+            std::list<uint64_t>::iterator frameIndexIt =
+                std::find(mFlushedIndices.begin(), mFlushedIndices.end(),
+                          frameIndex);
+            if (!mFlushedIndices.empty() &&
+                (frameIndexIt != mFlushedIndices.end())) {
+                mFlushedIndices.erase(frameIndexIt);
+                work->input.buffers.clear();
+                work->worklets.clear();
+                mWorkQueue.push_back(std::move(work));
+            }
+        }
+    }
+    ASSERT_EQ(mFlushedIndices.empty(), true);
+    ASSERT_EQ(mComponent->stop(), C2_OK);
+}
+
+TEST_F(Codec2AudioDecHidlTest, DecodeTestEmptyBuffersInserted) {
+    description("Decode with multiple empty input frames");
+    if (mDisableTest) return;
+
+    ASSERT_EQ(mComponent->start(), C2_OK);
+
+    char mURL[512], info[512];
+    std::ifstream eleStream, eleInfo;
+
+    strcpy(mURL, gEnv->getRes().c_str());
+    strcpy(info, gEnv->getRes().c_str());
+    GetURLForComponent(mCompName, mURL, info);
+
+    eleInfo.open(info);
+    ASSERT_EQ(eleInfo.is_open(), true) << mURL << " - file not found";
+    android::Vector<FrameInfo> Info;
+    int bytesCount = 0;
+    uint32_t frameId = 0;
+    uint32_t flags = 0;
+    uint32_t timestamp = 0;
+    bool codecConfig = false;
+    // This test introduces empty CSD after every 20th frame
+    // and empty input frames at an interval of 5 frames.
+    while (1) {
+        if (!(frameId % 5)) {
+            if (!(frameId % 20)) flags = 32;
+            else flags = 0;
+            bytesCount = 0;
+        } else {
+            if (!(eleInfo >> bytesCount)) break;
+            eleInfo >> flags;
+            eleInfo >> timestamp;
+            codecConfig = flags ?
+                ((1 << (flags - 1)) & C2FrameData::FLAG_CODEC_CONFIG) != 0 : 0;
+        }
+        Info.push_back({bytesCount, flags, timestamp});
+        frameId++;
+    }
+    eleInfo.close();
+
+    ALOGV("mURL : %s", mURL);
+    eleStream.open(mURL, std::ifstream::binary);
+    ASSERT_EQ(eleStream.is_open(), true);
+    ASSERT_NO_FATAL_FAILURE(decodeNFrames(
+        mComponent, mQueueLock, mQueueCondition, mWorkQueue, mFlushedIndices,
+        mLinearPool, eleStream, &Info, 0, (int)Info.size()));
 
     // blocking call to ensures application to Wait till all the inputs are
     // consumed
     if (!mEos) {
-        ALOGD("Waiting for input consumption");
+        ALOGV("Waiting for input consumption");
         ASSERT_NO_FATAL_FAILURE(
             waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue));
     }
@@ -577,18 +856,16 @@
     eleStream.close();
     if (mFramesReceived != Info.size()) {
         ALOGE("Input buffer count and Output buffer count mismatch");
-        ALOGE("framesReceived : %d inputFrames : %zu", mFramesReceived,
+        ALOGV("framesReceived : %d inputFrames : %zu", mFramesReceived,
               Info.size());
         ASSERT_TRUE(false);
     }
+
+    ASSERT_EQ(mComponent->stop(), C2_OK);
 }
 
 }  // anonymous namespace
 
-// TODO : Thumbnail Test
-// TODO : Test EOS
-// TODO : Flush Test
-// TODO : Timestamps deviation
 int main(int argc, char** argv) {
     gEnv = new ComponentTestEnvironment();
     ::testing::AddGlobalTestEnvironment(gEnv);
diff --git a/codec2/hidl/1.0/mts/audio/MtsHidlC2V1_0TargetAudioEncTest.cpp b/codec2/hidl/1.0/mts/audio/MtsHidlC2V1_0TargetAudioEncTest.cpp
index af71e38..5d66ee5 100644
--- a/codec2/hidl/1.0/mts/audio/MtsHidlC2V1_0TargetAudioEncTest.cpp
+++ b/codec2/hidl/1.0/mts/audio/MtsHidlC2V1_0TargetAudioEncTest.cpp
@@ -21,6 +21,7 @@
 #include <gtest/gtest.h>
 #include <stdio.h>
 #include <fstream>
+#include <algorithm>
 
 #include <codec2/hidl/client.h>
 #include <C2AllocatorIon.h>
@@ -95,6 +96,7 @@
         const StringToName kStringToName[] = {
             {"aac", aac},
             {"flac", flac},
+            {"opus", opus},
             {"amrnb", amrnb},
             {"amrwb", amrwb},
         };
@@ -134,37 +136,17 @@
     // callback function to process onWorkDone received by Listener
     void handleWorkDone(std::list<std::unique_ptr<C2Work>>& workItems) {
         for (std::unique_ptr<C2Work>& work : workItems) {
-            // handle configuration changes in work done
-            if (!work->worklets.empty() &&
-                (work->worklets.front()->output.configUpdate.size() != 0)) {
-                ALOGV("Config Update");
-                std::vector<std::unique_ptr<C2Param>> updates =
-                    std::move(work->worklets.front()->output.configUpdate);
-                std::vector<C2Param*> configParam;
-                std::vector<std::unique_ptr<C2SettingResult>> failures;
-                for (size_t i = 0; i < updates.size(); ++i) {
-                    C2Param* param = updates[i].get();
-                    if (param->index() == C2StreamCsdInfo::output::PARAM_TYPE) {
-                        mCsd = true;
-                    }
-                }
+            if (!work->worklets.empty()) {
+                workDone(mComponent, work, mFlushedIndices, mQueueLock,
+                         mQueueCondition, mWorkQueue, mEos, mCsd,
+                         mFramesReceived);
             }
-            mFramesReceived++;
-            mEos = (work->worklets.front()->output.flags &
-                    C2FrameData::FLAG_END_OF_STREAM) != 0;
-            ALOGV("WorkDone: frameID received %d",
-                (int)work->worklets.front()->output.ordinal.frameIndex.peeku());
-            work->input.buffers.clear();
-            work->worklets.clear();
-            typedef std::unique_lock<std::mutex> ULock;
-            ULock l(mQueueLock);
-            mWorkQueue.push_back(std::move(work));
-            mQueueCondition.notify_all();
         }
     }
     enum standardComp {
         aac,
         flac,
+        opus,
         amrnb,
         amrwb,
         unknown_comp,
@@ -175,6 +157,8 @@
     bool mDisableTest;
     standardComp mCompName;
     uint32_t mFramesReceived;
+    std::list<uint64_t> mFlushedIndices;
+
     C2BlockPool::local_id_t mBlockPoolId;
     std::shared_ptr<C2BlockPool> mLinearPool;
     std::shared_ptr<C2Allocator> mLinearAllocator;
@@ -264,6 +248,8 @@
          "bbb_raw_1ch_16khz_s16le.raw"},
         {Codec2AudioEncHidlTest::standardComp::flac,
          "bbb_raw_2ch_48khz_s16le.raw"},
+        {Codec2AudioEncHidlTest::standardComp::opus,
+         "bbb_raw_2ch_48khz_s16le.raw"},
     };
 
     for (size_t i = 0; i < sizeof(kCompToURL) / sizeof(kCompToURL[0]); ++i) {
@@ -274,19 +260,16 @@
     }
 }
 
-void encodeNFrames(const std::shared_ptr<android::Codec2Client::Component> &component,
-                   std::mutex &queueLock, std::condition_variable &queueCondition,
-                   std::list<std::unique_ptr<C2Work>> &workQueue,
-                   std::shared_ptr<C2Allocator> &linearAllocator,
-                   std::shared_ptr<C2BlockPool> &linearPool,
-                   C2BlockPool::local_id_t blockPoolId,
+void encodeNFrames(const std::shared_ptr<android::Codec2Client::Component>& component,
+                   std::mutex &queueLock, std::condition_variable& queueCondition,
+                   std::list<std::unique_ptr<C2Work>>& workQueue,
+                   std::list<uint64_t>& flushedIndices,
+                   std::shared_ptr<C2BlockPool>& linearPool,
                    std::ifstream& eleStream, uint32_t nFrames,
                    int32_t samplesPerFrame, int32_t nChannels,
-                   int32_t nSampleRate,bool signalEOS = true) {
+                   int32_t nSampleRate, bool flushed = false,
+                   bool signalEOS = true) {
     typedef std::unique_lock<std::mutex> ULock;
-    linearPool =
-        std::make_shared<C2PooledBlockPool>(linearAllocator, blockPoolId++);
-    component->start();
 
     uint32_t frameID = 0;
     uint32_t maxRetry = 0;
@@ -314,11 +297,19 @@
         }
         if (signalEOS && (nFrames == 1))
             flags |= C2FrameData::FLAG_END_OF_STREAM;
-
+        if (flushed) {
+            flags |= SYNC_FRAME;
+            flushed = false;
+        }
         work->input.flags = (C2FrameData::flags_t)flags;
         work->input.ordinal.timestamp = timestamp;
         work->input.ordinal.frameIndex = frameID;
+        {
+            ULock l(queueLock);
+            flushedIndices.emplace_back(frameID);
+        }
         char* data = (char*)malloc(bytesCount);
+        ASSERT_NE(data, nullptr);
         eleStream.read(data, bytesCount);
         ASSERT_EQ(eleStream.gcount(), bytesCount);
         std::shared_ptr<C2LinearBlock> block;
@@ -357,28 +348,6 @@
     }
 }
 
-void waitOnInputConsumption(std::mutex& queueLock,
-                            std::condition_variable& queueCondition,
-                            std::list<std::unique_ptr<C2Work>>& workQueue) {
-    typedef std::unique_lock<std::mutex> ULock;
-    uint32_t queueSize;
-    uint32_t maxRetry = 0;
-    {
-        ULock l(queueLock);
-        queueSize = workQueue.size();
-    }
-    while ((maxRetry < MAX_RETRY) && (queueSize < MAX_INPUT_BUFFERS)) {
-        ULock l(queueLock);
-        if (queueSize != workQueue.size()) {
-            queueSize = workQueue.size();
-            maxRetry = 0;
-        } else {
-            queueCondition.wait_for(l, TIME_OUT);
-            maxRetry++;
-        }
-    }
-}
-
 TEST_F(Codec2AudioEncHidlTest, validateCompName) {
     if (mDisableTest) return;
     ALOGV("Checks if the given component is a valid audio component");
@@ -389,6 +358,7 @@
 TEST_F(Codec2AudioEncHidlTest, EncodeTest) {
     ALOGV("EncodeTest");
     if (mDisableTest) return;
+    ASSERT_EQ(mComponent->start(), C2_OK);
     char mURL[512];
     strcpy(mURL, gEnv->getRes().c_str());
     GetURLForComponent(mCompName, mURL);
@@ -408,6 +378,11 @@
             nSampleRate = 48000;
             samplesPerFrame = 1152;
             break;
+        case opus:
+            nChannels = 2;
+            nSampleRate = 48000;
+            samplesPerFrame = 960;
+            break;
         case amrnb:
             nChannels = 1;
             nSampleRate = 8000;
@@ -423,42 +398,192 @@
     }
     setupConfigParam(mComponent, nChannels, nSampleRate);
     std::ifstream eleStream;
+    uint32_t numFrames = 128;
     eleStream.open(mURL, std::ifstream::binary);
     ASSERT_EQ(eleStream.is_open(), true);
     ALOGV("mURL : %s", mURL);
     ASSERT_NO_FATAL_FAILURE(
         encodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
-                      mLinearAllocator, mLinearPool, mBlockPoolId, eleStream,
-                      128, samplesPerFrame, nChannels, nSampleRate));
-
+                      mFlushedIndices, mLinearPool, eleStream, numFrames,
+                      samplesPerFrame, nChannels, nSampleRate));
     // blocking call to ensures application to Wait till all the inputs are
     // consumed
-    if (!mEos) {
-        ALOGD("Waiting for input consumption");
-        ASSERT_NO_FATAL_FAILURE(
-            waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue));
-    }
-
+    ASSERT_NO_FATAL_FAILURE(
+        waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue));
     eleStream.close();
-    if (mFramesReceived != 128) {
+    if (mFramesReceived != numFrames) {
         ALOGE("Input buffer count and Output buffer count mismatch");
-        ALOGE("framesReceived : %d inputFrames : 128", mFramesReceived);
+        ALOGE("framesReceived : %d inputFrames : %u", mFramesReceived, numFrames);
         ASSERT_TRUE(false);
     }
-    if ((mCompName == flac || mCompName == aac)) {
+    if ((mCompName == flac || mCompName == opus || mCompName == aac)) {
         if (!mCsd) {
             ALOGE("CSD buffer missing");
             ASSERT_TRUE(false);
         }
     }
+    ASSERT_EQ(mEos, true);
+    ASSERT_EQ(mComponent->stop(), C2_OK);
+}
+
+TEST_F(Codec2AudioEncHidlTest, EOSTest) {
+    description("Test empty input buffer with EOS flag");
+    if (mDisableTest) return;
+    ASSERT_EQ(mComponent->start(), C2_OK);
+
+    typedef std::unique_lock<std::mutex> ULock;
+    std::unique_ptr<C2Work> work;
+    {
+        ULock l(mQueueLock);
+        if (!mWorkQueue.empty()) {
+            work.swap(mWorkQueue.front());
+            mWorkQueue.pop_front();
+        } else {
+            ALOGE("mWorkQueue Empty is not expected at the start of the test");
+            ASSERT_TRUE(false);
+        }
+    }
+    ASSERT_NE(work, nullptr);
+    work->input.flags = (C2FrameData::flags_t)C2FrameData::FLAG_END_OF_STREAM;
+    work->input.ordinal.timestamp = 0;
+    work->input.ordinal.frameIndex = 0;
+    work->input.buffers.clear();
+    work->worklets.clear();
+    work->worklets.emplace_back(new C2Worklet);
+
+    std::list<std::unique_ptr<C2Work>> items;
+    items.push_back(std::move(work));
+    ASSERT_EQ(mComponent->queue(&items), C2_OK);
+    uint32_t queueSize;
+    {
+        ULock l(mQueueLock);
+        queueSize = mWorkQueue.size();
+        if (queueSize < MAX_INPUT_BUFFERS) {
+            mQueueCondition.wait_for(l, TIME_OUT);
+        }
+    }
+    ASSERT_EQ(mEos, true);
+    ASSERT_EQ(mComponent->stop(), C2_OK);
+}
+
+TEST_F(Codec2AudioEncHidlTest, FlushTest) {
+    description("Test Request for flush");
+    if (mDisableTest) return;
+    ASSERT_EQ(mComponent->start(), C2_OK);
+
+    typedef std::unique_lock<std::mutex> ULock;
+    char mURL[512];
+    strcpy(mURL, gEnv->getRes().c_str());
+    GetURLForComponent(mCompName, mURL);
+
+    // Setting default configuration
+    mFlushedIndices.clear();
+    int32_t nChannels = 2;
+    int32_t nSampleRate = 44100;
+    int32_t samplesPerFrame = 1024;
+    switch (mCompName) {
+        case aac:
+            nChannels = 2;
+            nSampleRate = 48000;
+            samplesPerFrame = 1024;
+            break;
+        case flac:
+            nChannels = 2;
+            nSampleRate = 48000;
+            samplesPerFrame = 1152;
+            break;
+        case opus:
+            nChannels = 2;
+            nSampleRate = 48000;
+            samplesPerFrame = 960;
+            break;
+        case amrnb:
+            nChannels = 1;
+            nSampleRate = 8000;
+            samplesPerFrame = 160;
+            break;
+        case amrwb:
+            nChannels = 1;
+            nSampleRate = 16000;
+            samplesPerFrame = 160;
+            break;
+        default:
+            ASSERT_TRUE(false);
+    }
+    setupConfigParam(mComponent, nChannels, nSampleRate);
+    std::ifstream eleStream;
+    uint32_t numFramesFlushed = 30;
+    uint32_t numFrames = 128;
+    eleStream.open(mURL, std::ifstream::binary);
+    ASSERT_EQ(eleStream.is_open(), true);
+    ALOGV("mURL : %s", mURL);
+    ASSERT_NO_FATAL_FAILURE(
+        encodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
+                      mFlushedIndices, mLinearPool, eleStream, numFramesFlushed,
+                      samplesPerFrame, nChannels, nSampleRate));
+    std::list<std::unique_ptr<C2Work>> flushedWork;
+    c2_status_t err =
+        mComponent->flush(C2Component::FLUSH_COMPONENT, &flushedWork);
+    ASSERT_EQ(err, C2_OK);
+    ASSERT_NO_FATAL_FAILURE(
+        waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue,
+            (size_t)MAX_INPUT_BUFFERS - flushedWork.size()));
+    uint64_t frameIndex;
+    {
+        //Update mFlushedIndices based on the index received from flush()
+        ULock l(mQueueLock);
+        for (std::unique_ptr<C2Work>& work : flushedWork) {
+            ASSERT_NE(work, nullptr);
+            frameIndex = work->input.ordinal.frameIndex.peeku();
+            std::list<uint64_t>::iterator frameIndexIt =
+                std::find(mFlushedIndices.begin(), mFlushedIndices.end(),
+                          frameIndex);
+            if (!mFlushedIndices.empty() &&
+                (frameIndexIt != mFlushedIndices.end())) {
+                mFlushedIndices.erase(frameIndexIt);
+                work->input.buffers.clear();
+                work->worklets.clear();
+                mWorkQueue.push_back(std::move(work));
+            }
+        }
+    }
+    mFlushedIndices.clear();
+    ASSERT_NO_FATAL_FAILURE(
+        encodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
+                      mFlushedIndices, mLinearPool, eleStream,
+                      numFrames - numFramesFlushed, samplesPerFrame,
+                      nChannels, nSampleRate, true));
+    eleStream.close();
+    err =
+        mComponent->flush(C2Component::FLUSH_COMPONENT, &flushedWork);
+    ASSERT_EQ(err, C2_OK);
+    ASSERT_NO_FATAL_FAILURE(
+        waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue,
+            (size_t)MAX_INPUT_BUFFERS - flushedWork.size()));
+    {
+        //Update mFlushedIndices based on the index received from flush()
+        ULock l(mQueueLock);
+        for (std::unique_ptr<C2Work>& work : flushedWork) {
+            ASSERT_NE(work, nullptr);
+            frameIndex = work->input.ordinal.frameIndex.peeku();
+            std::list<uint64_t>::iterator frameIndexIt =
+                std::find(mFlushedIndices.begin(), mFlushedIndices.end(),
+                          frameIndex);
+            if (!mFlushedIndices.empty() &&
+                (frameIndexIt != mFlushedIndices.end())) {
+                mFlushedIndices.erase(frameIndexIt);
+                work->input.buffers.clear();
+                work->worklets.clear();
+                mWorkQueue.push_back(std::move(work));
+            }
+        }
+    }
+    ASSERT_EQ(mFlushedIndices.empty(), true);
+    ASSERT_EQ(mComponent->stop(), C2_OK);
 }
 
 }  // anonymous namespace
 
-// TODO : Thumbnail Test
-// TODO : Test EOS
-// TODO : Flush Test
-// TODO : Timestamps deviation
 int main(int argc, char** argv) {
     gEnv = new ComponentTestEnvironment();
     ::testing::AddGlobalTestEnvironment(gEnv);
diff --git a/codec2/hidl/1.0/mts/audio/media_c2_audio_hidl_test_common.h b/codec2/hidl/1.0/mts/audio/media_c2_audio_hidl_test_common.h
index 63370b3..4d773ce 100644
--- a/codec2/hidl/1.0/mts/audio/media_c2_audio_hidl_test_common.h
+++ b/codec2/hidl/1.0/mts/audio/media_c2_audio_hidl_test_common.h
@@ -17,8 +17,5 @@
 #ifndef MEDIA_C2_AUDIO_HIDL_TEST_COMMON_H
 #define MEDIA_C2_AUDIO_HIDL_TEST_COMMON_H
 
-#define MAX_RETRY 20
-#define TIME_OUT 400ms
-#define MAX_INPUT_BUFFERS 8
 
 #endif  // MEDIA_C2_AUDIO_HIDL_TEST_COMMON_H
diff --git a/codec2/hidl/1.0/mts/common/media_c2_hidl_test_common.cpp b/codec2/hidl/1.0/mts/common/media_c2_hidl_test_common.cpp
index 1b2772f..64a458c 100644
--- a/codec2/hidl/1.0/mts/common/media_c2_hidl_test_common.cpp
+++ b/codec2/hidl/1.0/mts/common/media_c2_hidl_test_common.cpp
@@ -14,39 +14,115 @@
  * limitations under the License.
  */
 
+// #define LOG_NDEBUG 0
 #define LOG_TAG "media_c2_hidl_test_common"
 #include <stdio.h>
 
 #include "media_c2_hidl_test_common.h"
-using ::hardware::google::media::c2::V1_0::FieldSupportedValues;
 
-void dumpFSV(const FieldSupportedValues& sv) {
-    ALOGD("Dumping FSV data");
-    using namespace std;
-    if (sv.type == FieldSupportedValues::Type::EMPTY) {
-        ALOGD("FSV Value is Empty");
-    }
-    if (sv.type == FieldSupportedValues::Type::RANGE) {
-        ALOGD("Dumping FSV range");
-        cout << ".range(" << sv.range.min;
-        if (sv.range.step != 0) {
-            cout << ":" << sv.range.step;
+// Test the codecs for NullBuffer, Empty Input Buffer with(out) flags set
+void testInputBuffer(
+    const std::shared_ptr<android::Codec2Client::Component>& component,
+    std::mutex& queueLock, std::list<std::unique_ptr<C2Work>>& workQueue,
+    uint32_t flags, bool isNullBuffer) {
+    std::unique_ptr<C2Work> work;
+    {
+        typedef std::unique_lock<std::mutex> ULock;
+        ULock l(queueLock);
+        if (!workQueue.empty()) {
+            work.swap(workQueue.front());
+            workQueue.pop_front();
+        } else {
+            ASSERT_TRUE(false) << "workQueue Empty at the start of test";
         }
-        if (sv.range.num != 1 || sv.range.denom != 1) {
-            cout << ":" << sv.range.num << "/" << sv.range.denom;
-        }
-        cout << " " << sv.range.max << ")";
     }
-    if (sv.values.size()) {
-        ALOGD("Dumping FSV value");
-        cout << (sv.type == FieldSupportedValues::Type::FLAGS ? ".flags("
-                                                              : ".list(");
-        const char* sep = "";
-        for (const auto& p : sv.values) {
-            cout << sep << p;
-            sep = ",";
-        }
-        cout << ")";
+    ASSERT_NE(work, nullptr);
+
+    work->input.flags = (C2FrameData::flags_t)flags;
+    work->input.ordinal.timestamp = 0;
+    work->input.ordinal.frameIndex = 0;
+    work->input.buffers.clear();
+    if (isNullBuffer) {
+        work->input.buffers.emplace_back(nullptr);
     }
-    cout << endl;
+    work->worklets.clear();
+    work->worklets.emplace_back(new C2Worklet);
+
+    std::list<std::unique_ptr<C2Work>> items;
+    items.push_back(std::move(work));
+    ASSERT_EQ(component->queue(&items), C2_OK);
 }
+
+// Wait for all the inputs to be consumed by the plugin.
+void waitOnInputConsumption(std::mutex& queueLock,
+                            std::condition_variable& queueCondition,
+                            std::list<std::unique_ptr<C2Work>>& workQueue,
+                            size_t bufferCount) {
+    typedef std::unique_lock<std::mutex> ULock;
+    uint32_t queueSize;
+    uint32_t maxRetry = 0;
+    {
+        ULock l(queueLock);
+        queueSize = workQueue.size();
+    }
+    while ((maxRetry < MAX_RETRY) && (queueSize < bufferCount)) {
+        ULock l(queueLock);
+        if (queueSize != workQueue.size()) {
+            queueSize = workQueue.size();
+            maxRetry = 0;
+        } else {
+            queueCondition.wait_for(l, TIME_OUT);
+            maxRetry++;
+        }
+    }
+}
+
+// process onWorkDone received by Listener
+void workDone(
+    const std::shared_ptr<android::Codec2Client::Component>& component,
+    std::unique_ptr<C2Work>& work, std::list<uint64_t>& flushedIndices,
+    std::mutex& queueLock, std::condition_variable& queueCondition,
+    std::list<std::unique_ptr<C2Work>>& workQueue, bool& eos, bool& csd,
+    uint32_t& framesReceived) {
+    // handle configuration changes in work done
+    if (work->worklets.front()->output.configUpdate.size() != 0) {
+        ALOGV("Config Update");
+        std::vector<std::unique_ptr<C2Param>> updates =
+            std::move(work->worklets.front()->output.configUpdate);
+        std::vector<C2Param*> configParam;
+        std::vector<std::unique_ptr<C2SettingResult>> failures;
+        for (size_t i = 0; i < updates.size(); ++i) {
+            C2Param* param = updates[i].get();
+            if (param->index() == C2StreamCsdInfo::output::PARAM_TYPE) {
+                csd = true;
+            } else if ((param->index() ==
+                        C2StreamSampleRateInfo::output::PARAM_TYPE) ||
+                       (param->index() ==
+                        C2StreamChannelCountInfo::output::PARAM_TYPE) ||
+                       (param->index() ==
+                        C2VideoSizeStreamInfo::output::PARAM_TYPE)) {
+                configParam.push_back(param);
+            }
+        }
+        component->config(configParam, C2_DONT_BLOCK, &failures);
+        ASSERT_EQ(failures.size(), 0u);
+    }
+    framesReceived++;
+    eos = (work->worklets.front()->output.flags &
+           C2FrameData::FLAG_END_OF_STREAM) != 0;
+    auto frameIndexIt = std::find(flushedIndices.begin(), flushedIndices.end(),
+                                  work->input.ordinal.frameIndex.peeku());
+    ALOGV("WorkDone: frameID received %d",
+          (int)work->worklets.front()->output.ordinal.frameIndex.peeku());
+    work->input.buffers.clear();
+    work->worklets.clear();
+    {
+        typedef std::unique_lock<std::mutex> ULock;
+        ULock l(queueLock);
+        workQueue.push_back(std::move(work));
+        if (!flushedIndices.empty()) {
+            flushedIndices.erase(frameIndexIt);
+        }
+        queueCondition.notify_all();
+    }
+}
\ No newline at end of file
diff --git a/codec2/hidl/1.0/mts/common/media_c2_hidl_test_common.h b/codec2/hidl/1.0/mts/common/media_c2_hidl_test_common.h
index 0e7db26..04e02c9 100644
--- a/codec2/hidl/1.0/mts/common/media_c2_hidl_test_common.h
+++ b/codec2/hidl/1.0/mts/common/media_c2_hidl_test_common.h
@@ -22,6 +22,7 @@
 #include <hardware/google/media/c2/1.0/types.h>
 
 #include <C2Component.h>
+#include <C2Config.h>
 #include <getopt.h>
 #include <hidl/HidlSupport.h>
 #include <media/stagefright/foundation/ALooper.h>
@@ -38,6 +39,10 @@
 
 #include <VtsHalHidlTargetTestEnvBase.h>
 
+#define MAX_RETRY 20
+#define TIME_OUT 400ms
+#define MAX_INPUT_BUFFERS 8
+
 /*
  * Handle Callback functions onWorkDone(), onTripped(),
  * onError(), onDeath(), onFramesRendered()
@@ -176,5 +181,21 @@
 /*
  * common functions declarations
  */
-void dumpFSV(const FieldSupportedValues& sv);
+void testInputBuffer(
+    const std::shared_ptr<android::Codec2Client::Component>& component,
+    std::mutex& queueLock, std::list<std::unique_ptr<C2Work>>& workQueue,
+    uint32_t flags, bool isNullBuffer);
+
+void waitOnInputConsumption(std::mutex& queueLock,
+                            std::condition_variable& queueCondition,
+                            std::list<std::unique_ptr<C2Work>>& workQueue,
+                            size_t bufferCount = MAX_INPUT_BUFFERS);
+
+void workDone(
+    const std::shared_ptr<android::Codec2Client::Component>& component,
+    std::unique_ptr<C2Work>& work, std::list<uint64_t>& flushedIndices,
+    std::mutex& queueLock, std::condition_variable& queueCondition,
+    std::list<std::unique_ptr<C2Work>>& workQueue, bool& eos, bool& csd,
+    uint32_t& framesReceived);
+
 #endif  // MEDIA_C2_HIDL_TEST_COMMON_H
diff --git a/codec2/hidl/1.0/mts/component/MtsHidlC2V1_0TargetComponentTest.cpp b/codec2/hidl/1.0/mts/component/MtsHidlC2V1_0TargetComponentTest.cpp
index 03b1716..ec803d7 100644
--- a/codec2/hidl/1.0/mts/component/MtsHidlC2V1_0TargetComponentTest.cpp
+++ b/codec2/hidl/1.0/mts/component/MtsHidlC2V1_0TargetComponentTest.cpp
@@ -31,21 +31,28 @@
 namespace {
 
 // google.codec2 Component test setup
-class Codec2ComponentHalTest : public ::testing::VtsHalHidlTargetTestBase {
+class Codec2ComponentHidlTest : public ::testing::VtsHalHidlTargetTestBase {
    private:
     typedef ::testing::VtsHalHidlTargetTestBase Super;
 
    public:
     virtual void SetUp() override {
         Super::SetUp();
+        mEos = false;
         mClient = android::Codec2Client::CreateFromService(
             gEnv->getInstance().c_str());
         ASSERT_NE(mClient, nullptr);
-        mListener.reset(new CodecListener());
+        mListener.reset(new CodecListener(
+            [this](std::list<std::unique_ptr<C2Work>>& workItems) {
+                handleWorkDone(workItems);
+            }));
         ASSERT_NE(mListener, nullptr);
         mClient->createComponent(gEnv->getComponent().c_str(), mListener,
                                  &mComponent);
         ASSERT_NE(mComponent, nullptr);
+        for (int i = 0; i < MAX_INPUT_BUFFERS; ++i) {
+            mWorkQueue.emplace_back(new C2Work);
+        }
     }
 
     virtual void TearDown() override {
@@ -59,6 +66,23 @@
         }
         Super::TearDown();
     }
+    // callback function to process onWorkDone received by Listener
+    void handleWorkDone(std::list<std::unique_ptr<C2Work>>& workItems) {
+        for (std::unique_ptr<C2Work>& work : workItems) {
+            if (!work->worklets.empty()) {
+                bool mCsd = false;
+                uint32_t mFramesReceived = 0;
+                std::list<uint64_t> mFlushedIndices;
+                workDone(mComponent, work, mFlushedIndices, mQueueLock, mQueueCondition,
+                         mWorkQueue, mEos, mCsd, mFramesReceived);
+            }
+        }
+    }
+
+    bool mEos;
+    std::mutex mQueueLock;
+    std::condition_variable mQueueCondition;
+    std::list<std::unique_ptr<C2Work>> mWorkQueue;
 
     std::shared_ptr<android::Codec2Client> mClient;
     std::shared_ptr<android::Codec2Client::Listener> mListener;
@@ -71,7 +95,7 @@
 };
 
 // Test Empty Flush
-TEST_F(Codec2ComponentHalTest, EmptyFlush) {
+TEST_F(Codec2ComponentHidlTest, EmptyFlush) {
     ALOGV("Empty Flush Test");
     c2_status_t err = mComponent->start();
     ASSERT_EQ(err, C2_OK);
@@ -87,7 +111,7 @@
 }
 
 // Test Queue Empty Work
-TEST_F(Codec2ComponentHalTest, QueueEmptyWork) {
+TEST_F(Codec2ComponentHidlTest, QueueEmptyWork) {
     ALOGV("Queue Empty Work Test");
     c2_status_t err = mComponent->start();
     ASSERT_EQ(err, C2_OK);
@@ -102,45 +126,39 @@
 }
 
 // Test Component Configuration
-TEST_F(Codec2ComponentHalTest, Config) {
+TEST_F(Codec2ComponentHidlTest, Config) {
     ALOGV("Configuration Test");
 
     C2String name = mComponent->getName();
     EXPECT_NE(name.empty(), true) << "Invalid Component Name";
 
+    c2_status_t err = C2_OK;
+    std::vector<std::unique_ptr<C2Param>> queried;
+    std::vector<std::unique_ptr<C2SettingResult>> failures;
+
     // Query supported params by the component
     std::vector<std::shared_ptr<C2ParamDescriptor>> params;
-    c2_status_t err = mComponent->querySupportedParams(&params);
+    err = mComponent->querySupportedParams(&params);
     ASSERT_EQ(err, C2_OK);
     ALOGV("Number of total params - %zu", params.size());
 
-    // Query Component Domain Type
-    std::vector<std::unique_ptr<C2Param>> queried;
-    err = mComponent->query({}, {C2PortMediaTypeSetting::input::PARAM_TYPE},
-                            C2_DONT_BLOCK, &queried);
-    EXPECT_NE(queried.size(), 0u);
-    std::string inputDomain =
-        ((C2StreamMediaTypeSetting::input*)queried[0].get())->m.value;
-    EXPECT_NE(inputDomain.empty(), true) << "Invalid Component Domain";
-
-    // Configure Component Domain
-    std::vector<std::unique_ptr<C2SettingResult>> failures;
-    C2PortMediaTypeSetting::input* portMediaType =
-        C2PortMediaTypeSetting::input::From(queried[0].get());
-    err = mComponent->config({portMediaType}, C2_DONT_BLOCK, &failures);
-    ASSERT_EQ(err, C2_OK);
-    ASSERT_EQ(failures.size(), 0u);
-
-    // TODO: Query/Config on other common Params
+    // Query and config all the supported params
+    for (std::shared_ptr<C2ParamDescriptor> p : params) {
+        ALOGD("Querying index %d", (int)p->index());
+        err = mComponent->query({}, {p->index()}, C2_DONT_BLOCK, &queried);
+        EXPECT_NE(queried.size(), 0u);
+        EXPECT_EQ(err, C2_OK);
+        err = mComponent->config({queried[0].get()}, C2_DONT_BLOCK, &failures);
+        ASSERT_EQ(err, C2_OK);
+        ASSERT_EQ(failures.size(), 0u);
+    }
 }
 
 // Test Multiple Start Stop Reset Test
-TEST_F(Codec2ComponentHalTest, MultipleStartStopReset) {
+TEST_F(Codec2ComponentHidlTest, MultipleStartStopReset) {
     ALOGV("Multiple Start Stop and Reset Test");
     c2_status_t err = C2_OK;
 
-#define MAX_RETRY 16
-
     for (size_t i = 0; i < MAX_RETRY; i++) {
         err = mComponent->start();
         ASSERT_EQ(err, C2_OK);
@@ -168,9 +186,67 @@
     ASSERT_NE(err, C2_OK);
 }
 
+// Test Component Release API
+TEST_F(Codec2ComponentHidlTest, MultipleRelease) {
+    ALOGV("Multiple Release Test");
+    c2_status_t err = mComponent->start();
+    ASSERT_EQ(err, C2_OK);
+
+    // Query Component Domain Type
+    std::vector<std::unique_ptr<C2Param>> queried;
+    err = mComponent->query({}, {C2PortMediaTypeSetting::input::PARAM_TYPE},
+                            C2_DONT_BLOCK, &queried);
+    EXPECT_NE(queried.size(), 0u);
+
+    // Configure Component Domain
+    std::vector<std::unique_ptr<C2SettingResult>> failures;
+    C2PortMediaTypeSetting::input* portMediaType =
+        C2PortMediaTypeSetting::input::From(queried[0].get());
+    err = mComponent->config({portMediaType}, C2_DONT_BLOCK, &failures);
+    ASSERT_EQ(err, C2_OK);
+    ASSERT_EQ(failures.size(), 0u);
+
+    for (size_t i = 0; i < MAX_RETRY; i++) {
+        err = mComponent->release();
+        ASSERT_EQ(err, C2_OK);
+    }
+}
+
+class Codec2ComponentInputTests : public Codec2ComponentHidlTest,
+        public ::testing::WithParamInterface<std::pair<uint32_t, bool> > {
+};
+
+TEST_P(Codec2ComponentInputTests, InputBufferTest) {
+    description("Tests for different inputs");
+
+    uint32_t flags = GetParam().first;
+    bool isNullBuffer = GetParam().second;
+    if (isNullBuffer) ALOGD("Testing for null input buffer with flag : %u", flags);
+    else ALOGD("Testing for empty input buffer with flag : %u", flags);
+    mEos = false;
+    ASSERT_EQ(mComponent->start(), C2_OK);
+    ASSERT_NO_FATAL_FAILURE(testInputBuffer(
+        mComponent, mQueueLock, mWorkQueue, flags, isNullBuffer));
+
+    ALOGD("Waiting for input consumption");
+    ASSERT_NO_FATAL_FAILURE(
+        waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue));
+
+    if (flags == C2FrameData::FLAG_END_OF_STREAM) ASSERT_EQ(mEos, true);
+    ASSERT_EQ(mComponent->stop(), C2_OK);
+    ASSERT_EQ(mComponent->reset(), C2_OK);
+}
+
+INSTANTIATE_TEST_CASE_P(NonStdInputs, Codec2ComponentInputTests, ::testing::Values(
+    std::make_pair(0, true),
+    std::make_pair(C2FrameData::FLAG_END_OF_STREAM, true),
+    std::make_pair(0, false),
+    std::make_pair(C2FrameData::FLAG_CODEC_CONFIG, false),
+    std::make_pair(C2FrameData::FLAG_END_OF_STREAM, false)));
+
 }  // anonymous namespace
 
-// TODO: Add test for Invalid work, Invalid Config handling
+// TODO: Add test for Invalid work,
 // TODO: Add test for Invalid states
 int main(int argc, char** argv) {
     gEnv = new ComponentTestEnvironment();
diff --git a/codec2/hidl/1.0/mts/res/bbb_av1_176_144.av1 b/codec2/hidl/1.0/mts/res/bbb_av1_176_144.av1
new file mode 100644
index 0000000..1d67af9
--- /dev/null
+++ b/codec2/hidl/1.0/mts/res/bbb_av1_176_144.av1
Binary files differ
diff --git a/codec2/hidl/1.0/mts/res/bbb_av1_176_144.info b/codec2/hidl/1.0/mts/res/bbb_av1_176_144.info
new file mode 100644
index 0000000..cc51168
--- /dev/null
+++ b/codec2/hidl/1.0/mts/res/bbb_av1_176_144.info
@@ -0,0 +1,300 @@
+6027 1 0
+6879 0 33000
+5 0 66000
+532 0 100000
+5 0 133000
+2458 0 166000
+5 0 200000
+475 0 233000
+5 0 266000
+1262 0 300000
+5 0 333000
+554 0 366000
+27 0 400000
+6971 0 433000
+5 0 466000
+601 0 500000
+5 0 533000
+3276 0 566000
+5 0 600000
+658 0 633000
+5 0 666000
+1680 0 700000
+5 0 733000
+610 0 766000
+24 0 800000
+6728 0 833000
+5 0 866000
+764 0 900000
+5 0 933000
+2656 0 966000
+5 0 1000000
+462 0 1033000
+5 0 1066000
+1459 0 1100000
+5 0 1133000
+608 0 1166000
+24 0 1200000
+7038 0 1233000
+5 0 1266000
+721 0 1300000
+5 0 1333000
+3102 0 1366000
+5 0 1400000
+752 0 1433000
+5 0 1466000
+1815 0 1500000
+5 0 1533000
+755 0 1566000
+25 0 1600000
+7657 0 1633000
+5 0 1666000
+852 0 1700000
+5 0 1733000
+3537 0 1766000
+5 0 1800000
+673 0 1833000
+5 0 1866000
+1774 0 1900000
+5 0 1933000
+554 0 1966000
+24 0 2000000
+8028 0 2033000
+5 0 2066000
+715 0 2100000
+5 0 2133000
+3395 0 2166000
+5 0 2200000
+736 0 2233000
+5 0 2266000
+1759 0 2300000
+5 0 2333000
+605 0 2366000
+23 0 2400000
+7651 0 2433000
+5 0 2466000
+619 0 2500000
+5 0 2533000
+2788 0 2566000
+5 0 2600000
+556 0 2633000
+5 0 2666000
+1335 0 2700000
+5 0 2733000
+521 0 2766000
+24 0 2800000
+2274 0 2833000
+676 0 2866000
+25 0 2900000
+6224 0 2933000
+5798 0 2966000
+5 0 3000000
+448 0 3033000
+5 0 3066000
+1950 0 3100000
+5 0 3133000
+386 0 3166000
+5 0 3200000
+1218 0 3233000
+5 0 3266000
+1316 0 3300000
+5 0 3333000
+580 0 3366000
+26 0 3400000
+6673 0 3433000
+5 0 3466000
+473 0 3500000
+5 0 3533000
+2467 0 3566000
+5 0 3600000
+429 0 3633000
+5 0 3666000
+1420 0 3700000
+5 0 3733000
+583 0 3766000
+29 0 3800000
+8492 0 3833000
+5 0 3866000
+720 0 3900000
+5 0 3933000
+3635 0 3966000
+5 0 4000000
+621 0 4033000
+5 0 4066000
+1969 0 4100000
+5 0 4133000
+49 0 4166000
+25 0 4200000
+7416 0 4233000
+5 0 4266000
+947 0 4300000
+5 0 4333000
+3713 0 4366000
+5 0 4400000
+714 0 4433000
+5 0 4466000
+2003 0 4500000
+5 0 4533000
+750 0 4566000
+25 0 4600000
+8470 0 4633000
+5 0 4666000
+737 0 4700000
+5 0 4733000
+4094 0 4766000
+5 0 4800000
+1019 0 4833000
+5 0 4866000
+2160 0 4900000
+5 0 4933000
+828 0 4966000
+24 0 5000000
+9282 0 5033000
+5 0 5066000
+655 0 5100000
+5 0 5133000
+3491 0 5166000
+5 0 5200000
+651 0 5233000
+5 0 5266000
+1906 0 5300000
+5 0 5333000
+662 0 5366000
+24 0 5400000
+9724 0 5433000
+5 0 5466000
+617 0 5500000
+5 0 5533000
+3145 0 5566000
+5 0 5600000
+578 0 5633000
+5 0 5666000
+1592 0 5700000
+5 0 5733000
+569 0 5766000
+25 0 5800000
+10015 0 5833000
+5 0 5866000
+609 0 5900000
+5 0 5933000
+3618 0 5966000
+5 0 6000000
+734 0 6033000
+5 0 6066000
+1748 0 6100000
+5 0 6133000
+550 0 6166000
+24 0 6200000
+8806 0 6233000
+5 0 6266000
+498 0 6300000
+5 0 6333000
+2913 0 6366000
+5 0 6400000
+597 0 6433000
+5 0 6466000
+1235 0 6500000
+5 0 6533000
+362 0 6566000
+24 0 6600000
+6592 0 6633000
+5 0 6666000
+468 0 6700000
+5 0 6733000
+1920 0 6766000
+5 0 6800000
+419 0 6833000
+5 0 6866000
+843 0 6900000
+5 0 6933000
+237 0 6966000
+24 0 7000000
+2687 0 7033000
+5 0 7066000
+399 0 7100000
+5 0 7133000
+200 0 7166000
+143 0 7200000
+25 0 7233000
+12603 0 7266000
+1139 0 7300000
+5 0 7333000
+56 0 7366000
+5 0 7400000
+273 0 7433000
+5 0 7466000
+48 0 7500000
+5 0 7533000
+102 0 7566000
+5 0 7600000
+39 0 7633000
+24 0 7666000
+3635 0 7700000
+5 0 7733000
+46 0 7766000
+5 0 7800000
+647 0 7833000
+5 0 7866000
+61 0 7900000
+5 0 7933000
+824 0 7966000
+5 0 8000000
+691 0 8033000
+27 0 8066000
+4573 0 8100000
+5 0 8133000
+473 0 8166000
+5 0 8200000
+1637 0 8233000
+5 0 8266000
+451 0 8300000
+5 0 8333000
+969 0 8366000
+5 0 8400000
+234 0 8433000
+24 0 8466000
+3361 0 8500000
+5 0 8533000
+168 0 8566000
+5 0 8600000
+662 0 8633000
+5 0 8666000
+129 0 8700000
+5 0 8733000
+443 0 8766000
+5 0 8800000
+183 0 8833000
+23 0 8866000
+2769 0 8900000
+5 0 8933000
+182 0 8966000
+5 0 9000000
+890 0 9033000
+5 0 9066000
+171 0 9100000
+5 0 9133000
+599 0 9166000
+5 0 9200000
+236 0 9233000
+23 0 9266000
+2316 0 9300000
+5 0 9333000
+333 0 9366000
+5 0 9400000
+759 0 9433000
+5 0 9466000
+210 0 9500000
+5 0 9533000
+324 0 9566000
+5 0 9600000
+98 0 9633000
+23 0 9666000
+1107 0 9700000
+5 0 9733000
+42 0 9766000
+5 0 9800000
+145 0 9833000
+5 0 9866000
+109 0 9900000
+89 0 9933000
+24 0 9966000
\ No newline at end of file
diff --git a/codec2/hidl/1.0/mts/res/bbb_av1_640_360.av1 b/codec2/hidl/1.0/mts/res/bbb_av1_640_360.av1
new file mode 100644
index 0000000..529bace
--- /dev/null
+++ b/codec2/hidl/1.0/mts/res/bbb_av1_640_360.av1
Binary files differ
diff --git a/codec2/hidl/1.0/mts/res/bbb_av1_640_360.info b/codec2/hidl/1.0/mts/res/bbb_av1_640_360.info
new file mode 100644
index 0000000..fca7833
--- /dev/null
+++ b/codec2/hidl/1.0/mts/res/bbb_av1_640_360.info
@@ -0,0 +1,167 @@
+12571 1 0
+9881 0 33000
+5 0 66000
+544 0 100000
+5 0 133000
+2642 0 166000
+5 0 200000
+531 0 233000
+5 0 266000
+1359 0 300000
+5 0 333000
+551 0 366000
+28 0 400000
+10791 0 433000
+5 0 466000
+655 0 500000
+5 0 533000
+3769 0 566000
+5 0 600000
+711 0 633000
+5 0 666000
+2004 0 700000
+5 0 733000
+657 0 766000
+26 0 800000
+8969 0 833000
+5 0 866000
+630 0 900000
+5 0 933000
+2787 0 966000
+5 0 1000000
+404 0 1033000
+5 0 1066000
+1518 0 1100000
+5 0 1133000
+493 0 1166000
+26 0 1200000
+9900 0 1233000
+5 0 1266000
+620 0 1300000
+5 0 1333000
+3072 0 1366000
+5 0 1400000
+668 0 1433000
+5 0 1466000
+1821 0 1500000
+5 0 1533000
+682 0 1566000
+26 0 1600000
+9560 0 1633000
+5 0 1666000
+667 0 1700000
+5 0 1733000
+3249 0 1766000
+5 0 1800000
+589 0 1833000
+5 0 1866000
+1816 0 1900000
+5 0 1933000
+548 0 1966000
+26 0 2000000
+9916 0 2033000
+5 0 2066000
+628 0 2100000
+5 0 2133000
+3034 0 2166000
+5 0 2200000
+590 0 2233000
+5 0 2266000
+1581 0 2300000
+5 0 2333000
+524 0 2366000
+26 0 2400000
+8182 0 2433000
+5 0 2466000
+552 0 2500000
+5 0 2533000
+2412 0 2566000
+5 0 2600000
+489 0 2633000
+5 0 2666000
+1227 0 2700000
+5 0 2733000
+432 0 2766000
+26 0 2800000
+2017 0 2833000
+516 0 2866000
+26 0 2900000
+16619 0 2933000
+6710 0 2966000
+5 0 3000000
+425 0 3033000
+5 0 3066000
+1964 0 3100000
+5 0 3133000
+386 0 3166000
+5 0 3200000
+1129 0 3233000
+5 0 3266000
+1156 0 3300000
+5 0 3333000
+486 0 3366000
+28 0 3400000
+10304 0 3433000
+5 0 3466000
+412 0 3500000
+5 0 3533000
+2608 0 3566000
+5 0 3600000
+397 0 3633000
+5 0 3666000
+1514 0 3700000
+5 0 3733000
+533 0 3766000
+26 0 3800000
+11698 0 3833000
+5 0 3866000
+542 0 3900000
+5 0 3933000
+3334 0 3966000
+5 0 4000000
+547 0 4033000
+5 0 4066000
+1809 0 4100000
+5 0 4133000
+55 0 4166000
+26 0 4200000
+9496 0 4233000
+5 0 4266000
+658 0 4300000
+5 0 4333000
+3232 0 4366000
+5 0 4400000
+600 0 4433000
+5 0 4466000
+1766 0 4500000
+5 0 4533000
+550 0 4566000
+25 0 4600000
+9951 0 4633000
+5 0 4666000
+624 0 4700000
+5 0 4733000
+3617 0 4766000
+5 0 4800000
+644 0 4833000
+5 0 4866000
+1841 0 4900000
+5 0 4933000
+649 0 4966000
+25 0 5000000
+9901 0 5033000
+5 0 5066000
+515 0 5100000
+5 0 5133000
+2814 0 5166000
+5 0 5200000
+511 0 5233000
+5 0 5266000
+1521 0 5300000
+5 0 5333000
+509 0 5366000
+26 0 5400000
+10579 0 5433000
+5 0 5466000
+575 0 5500000
+5 0 5533000
\ No newline at end of file
diff --git a/codec2/hidl/1.0/mts/video/MtsHidlC2V1_0TargetVideoDecTest.cpp b/codec2/hidl/1.0/mts/video/MtsHidlC2V1_0TargetVideoDecTest.cpp
index 1a3820d..9a42d72 100644
--- a/codec2/hidl/1.0/mts/video/MtsHidlC2V1_0TargetVideoDecTest.cpp
+++ b/codec2/hidl/1.0/mts/video/MtsHidlC2V1_0TargetVideoDecTest.cpp
@@ -101,7 +101,7 @@
 
         const StringToName kStringToName[] = {
             {"h263", h263}, {"avc", avc}, {"mpeg2", mpeg2}, {"mpeg4", mpeg4},
-            {"hevc", hevc}, {"vp8", vp8}, {"vp9", vp9},
+            {"hevc", hevc}, {"vp8", vp8}, {"vp9", vp9}, {"av1", av1},
         };
 
         const size_t kNumStringToName =
@@ -142,79 +142,48 @@
     // callback function to process onWorkDone received by Listener
     void handleWorkDone(std::list<std::unique_ptr<C2Work>>& workItems) {
         for (std::unique_ptr<C2Work>& work : workItems) {
-            // handle configuration changes in work done
-            if (!work->worklets.empty() &&
-                (work->worklets.front()->output.configUpdate.size() != 0)) {
-                ALOGV("Config Update");
-                std::vector<std::unique_ptr<C2Param>> updates =
-                    std::move(work->worklets.front()->output.configUpdate);
-                std::vector<C2Param*> configParam;
-                std::vector<std::unique_ptr<C2SettingResult>> failures;
-                for (size_t i = 0; i < updates.size(); ++i) {
-                    C2Param* param = updates[i].get();
-                    if (param->index() ==
-                        C2VideoSizeStreamInfo::output::PARAM_TYPE) {
-                        ALOGV("Received C2VideoSizeStreamInfo");
-                        configParam.push_back(param);
-                    }
-                }
-                mComponent->config(configParam, C2_DONT_BLOCK, &failures);
-                ASSERT_EQ(failures.size(), 0u);
-            }
+            if (!work->worklets.empty()) {
+                // For decoder components current timestamp always exceeds
+                // previous timestamp
+                typedef std::unique_lock<std::mutex> ULock;
+                bool codecConfig = ((work->worklets.front()->output.flags &
+                                     C2FrameData::FLAG_CODEC_CONFIG) != 0);
+                if (!codecConfig &&
+                    !work->worklets.front()->output.buffers.empty()) {
+                    EXPECT_GE(
+                        (work->worklets.front()->output.ordinal.timestamp.peeku()),
+                        mTimestampUs);
+                    mTimestampUs =
+                        work->worklets.front()->output.ordinal.timestamp.peeku();
 
-            mFramesReceived++;
-            mEos = (work->worklets.front()->output.flags &
-                    C2FrameData::FLAG_END_OF_STREAM) != 0;
-            auto frameIndexIt =
-                std::find(mFlushedIndices.begin(), mFlushedIndices.end(),
-                          work->input.ordinal.frameIndex.peeku());
-
-            // For decoder components current timestamp always exceeds
-            // previous timestamp
-            typedef std::unique_lock<std::mutex> ULock;
-            bool codecConfig = ((work->worklets.front()->output.flags &
-                                 C2FrameData::FLAG_CODEC_CONFIG) != 0);
-            if (!codecConfig &&
-                !work->worklets.front()->output.buffers.empty()) {
-                EXPECT_GE(
-                    (work->worklets.front()->output.ordinal.timestamp.peeku()),
-                    mTimestampUs);
-                mTimestampUs =
-                    work->worklets.front()->output.ordinal.timestamp.peeku();
-
-                ULock l(mQueueLock);
-                if (mTimestampDevTest) {
-                    bool tsHit = false;
-                    std::list<uint64_t>::iterator it = mTimestampUslist.begin();
-                    while (it != mTimestampUslist.end()) {
-                        if (*it == mTimestampUs) {
-                            mTimestampUslist.erase(it);
-                            tsHit = true;
-                            break;
+                    ULock l(mQueueLock);
+                    if (mTimestampDevTest) {
+                        bool tsHit = false;
+                        std::list<uint64_t>::iterator it = mTimestampUslist.begin();
+                        while (it != mTimestampUslist.end()) {
+                            if (*it == mTimestampUs) {
+                                mTimestampUslist.erase(it);
+                                tsHit = true;
+                                break;
+                            }
+                            it++;
                         }
-                        it++;
-                    }
-                    if (tsHit == false) {
-                        if (mTimestampUslist.empty() == false) {
-                            EXPECT_EQ(tsHit, true)
-                                << "TimeStamp not recognized";
-                        } else {
-                            std::cout << "[   INFO   ] Received non-zero "
-                                         "output / TimeStamp not recognized \n";
+                        if (tsHit == false) {
+                            if (mTimestampUslist.empty() == false) {
+                                EXPECT_EQ(tsHit, true)
+                                    << "TimeStamp not recognized";
+                            } else {
+                                std::cout << "[   INFO   ] Received non-zero "
+                                             "output / TimeStamp not recognized \n";
+                            }
                         }
                     }
                 }
-            }
-
-            work->input.buffers.clear();
-            work->worklets.clear();
-            {
-                ULock l(mQueueLock);
-                mWorkQueue.push_back(std::move(work));
-                if (!mFlushedIndices.empty()) {
-                    mFlushedIndices.erase(frameIndexIt);
-                }
-                mQueueCondition.notify_all();
+                bool mCsd;
+                workDone(mComponent, work, mFlushedIndices, mQueueLock,
+                         mQueueCondition, mWorkQueue, mEos, mCsd,
+                         mFramesReceived);
+                (void)mCsd;
             }
         }
     }
@@ -227,6 +196,7 @@
         hevc,
         vp8,
         vp9,
+        av1,
         unknown_comp,
     };
 
@@ -341,6 +311,11 @@
           "bbb_vp9_640x360_1600kbps_30fps.vp9"},
          {"bbb_vp9_176x144_285kbps_60fps.info",
           "bbb_vp9_640x360_1600kbps_30fps.info"}},
+        {Codec2VideoDecHidlTest::standardComp::av1,
+         {"bbb_av1_640_360.av1",
+          "bbb_av1_176_144.av1"},
+         {"bbb_av1_640_360.info",
+          "bbb_av1_176_144.info"}},
     };
 
     for (size_t i = 0; i < sizeof(kCompToURL) / sizeof(kCompToURL[0]); ++i) {
@@ -352,11 +327,11 @@
     }
 }
 
-void decodeNFrames(const std::shared_ptr<android::Codec2Client::Component> &component,
-                   std::mutex &queueLock, std::condition_variable &queueCondition,
-                   std::list<std::unique_ptr<C2Work>> &workQueue,
-                   std::list<uint64_t> &flushedIndices,
-                   std::shared_ptr<C2BlockPool> &linearPool,
+void decodeNFrames(const std::shared_ptr<android::Codec2Client::Component>& component,
+                   std::mutex &queueLock, std::condition_variable& queueCondition,
+                   std::list<std::unique_ptr<C2Work>>& workQueue,
+                   std::list<uint64_t>& flushedIndices,
+                   std::shared_ptr<C2BlockPool>& linearPool,
                    std::ifstream& eleStream,
                    android::Vector<FrameInfo>* Info,
                    int offset, int range, bool signalEOS = true) {
@@ -397,35 +372,37 @@
 
         int size = (*Info)[frameID].bytesCount;
         char* data = (char*)malloc(size);
+        ASSERT_NE(data, nullptr);
 
         eleStream.read(data, size);
         ASSERT_EQ(eleStream.gcount(), size);
 
-        std::shared_ptr<C2LinearBlock> block;
-        ASSERT_EQ(C2_OK,
-                  linearPool->fetchLinearBlock(
-                      size, {C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE},
-                      &block));
-        ASSERT_TRUE(block);
-
-        // Write View
-        C2WriteView view = block->map().get();
-        if (view.error() != C2_OK) {
-            fprintf(stderr, "C2LinearBlock::map() failed : %d", view.error());
-            break;
-        }
-        ASSERT_EQ((size_t)size, view.capacity());
-        ASSERT_EQ(0u, view.offset());
-        ASSERT_EQ((size_t)size, view.size());
-
-        memcpy(view.base(), data, size);
-
         work->input.buffers.clear();
-        work->input.buffers.emplace_back(new LinearBuffer(block));
+        if (size) {
+            std::shared_ptr<C2LinearBlock> block;
+            ASSERT_EQ(C2_OK,
+                    linearPool->fetchLinearBlock(
+                        size, {C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE},
+                        &block));
+            ASSERT_TRUE(block);
+
+            // Write View
+            C2WriteView view = block->map().get();
+            if (view.error() != C2_OK) {
+                fprintf(stderr, "C2LinearBlock::map() failed : %d", view.error());
+                break;
+            }
+            ASSERT_EQ((size_t)size, view.capacity());
+            ASSERT_EQ(0u, view.offset());
+            ASSERT_EQ((size_t)size, view.size());
+
+            memcpy(view.base(), data, size);
+
+            work->input.buffers.emplace_back(new LinearBuffer(block));
+            free(data);
+        }
         work->worklets.clear();
         work->worklets.emplace_back(new C2Worklet);
-        free(data);
-
         std::list<std::unique_ptr<C2Work>> items;
         items.push_back(std::move(work));
 
@@ -437,29 +414,6 @@
     }
 }
 
-void waitOnInputConsumption(std::mutex& queueLock,
-                            std::condition_variable& queueCondition,
-                            std::list<std::unique_ptr<C2Work>>& workQueue,
-                            size_t bufferCount = MAX_INPUT_BUFFERS) {
-    typedef std::unique_lock<std::mutex> ULock;
-    uint32_t queueSize;
-    uint32_t maxRetry = 0;
-    {
-        ULock l(queueLock);
-        queueSize = workQueue.size();
-    }
-    while ((maxRetry < MAX_RETRY) && (queueSize < bufferCount)) {
-        ULock l(queueLock);
-        if (queueSize != workQueue.size()) {
-            queueSize = workQueue.size();
-            maxRetry = 0;
-        } else {
-            queueCondition.wait_for(l, TIME_OUT);
-            maxRetry++;
-        }
-    }
-}
-
 TEST_F(Codec2VideoDecHidlTest, validateCompName) {
     if (mDisableTest) return;
     ALOGV("Checks if the given component is a valid video component");
@@ -489,8 +443,8 @@
         if (!(eleInfo >> bytesCount)) break;
         eleInfo >> flags;
         eleInfo >> timestamp;
-        bool codecConfig =
-            ((1 << (flags - 1)) & C2FrameData::FLAG_CODEC_CONFIG) != 0;
+        bool codecConfig = flags ?
+            ((1 << (flags - 1)) & C2FrameData::FLAG_CODEC_CONFIG) != 0 : 0;
         if (mTimestampDevTest && !codecConfig)
             mTimestampUslist.push_back(timestamp);
         Info.push_back({bytesCount, flags, timestamp});
@@ -560,8 +514,9 @@
             eleInfo >> timestamp;
             timestamp += timestampOffset;
             Info.push_back({bytesCount, flags, timestamp});
-            bool codecConfig =
-                ((1 << (flags - 1)) & C2FrameData::FLAG_CODEC_CONFIG) != 0;
+            bool codecConfig = flags ?
+                ((1 << (flags - 1)) & C2FrameData::FLAG_CODEC_CONFIG) != 0 : 0;
+
             {
                 ULock l(mQueueLock);
                 if (mTimestampDevTest && !codecConfig)
@@ -677,8 +632,8 @@
         EXPECT_GE(mFramesReceived, 1U);
         ASSERT_EQ(mEos, true);
         ASSERT_EQ(mComponent->stop(), C2_OK);
-        ASSERT_EQ(mComponent->release(), C2_OK);
     }
+    ASSERT_EQ(mComponent->release(), C2_OK);
 }
 
 TEST_F(Codec2VideoDecHidlTest, EOSTest) {
@@ -711,7 +666,6 @@
     ASSERT_EQ(mComponent->queue(&items), C2_OK);
 
     {
-        typedef std::unique_lock<std::mutex> ULock;
         ULock l(mQueueLock);
         if (mWorkQueue.size() != MAX_INPUT_BUFFERS) {
             mQueueCondition.wait_for(l, TIME_OUT);
@@ -722,46 +676,6 @@
     ASSERT_EQ(mComponent->stop(), C2_OK);
 }
 
-TEST_F(Codec2VideoDecHidlTest, EmptyBufferTest) {
-    description("Tests empty input buffer");
-    if (mDisableTest) return;
-    typedef std::unique_lock<std::mutex> ULock;
-    ASSERT_EQ(mComponent->start(), C2_OK);
-    std::unique_ptr<C2Work> work;
-    // Prepare C2Work
-    {
-        ULock l(mQueueLock);
-        if (!mWorkQueue.empty()) {
-            work.swap(mWorkQueue.front());
-            mWorkQueue.pop_front();
-        } else {
-            ASSERT_TRUE(false) << "mWorkQueue Empty at the start of test";
-        }
-    }
-    ASSERT_NE(work, nullptr);
-
-    work->input.flags = (C2FrameData::flags_t)0;
-    work->input.ordinal.timestamp = 0;
-    work->input.ordinal.frameIndex = 0;
-    work->input.buffers.clear();
-    work->worklets.clear();
-    work->worklets.emplace_back(new C2Worklet);
-
-    std::list<std::unique_ptr<C2Work>> items;
-    items.push_back(std::move(work));
-    ASSERT_EQ(mComponent->queue(&items), C2_OK);
-
-    {
-        typedef std::unique_lock<std::mutex> ULock;
-        ULock l(mQueueLock);
-        if (mWorkQueue.size() != MAX_INPUT_BUFFERS) {
-            mQueueCondition.wait_for(l, TIME_OUT);
-        }
-    }
-    ASSERT_EQ(mWorkQueue.size(), (size_t)MAX_INPUT_BUFFERS);
-    ASSERT_EQ(mComponent->stop(), C2_OK);
-}
-
 TEST_F(Codec2VideoDecHidlTest, FlushTest) {
     description("Tests Flush calls");
     if (mDisableTest) return;
@@ -873,6 +787,69 @@
     ASSERT_EQ(mComponent->stop(), C2_OK);
 }
 
+TEST_F(Codec2VideoDecHidlTest, DecodeTestEmptyBuffersInserted) {
+    description("Decode with multiple empty input frames");
+    if (mDisableTest) return;
+
+    char mURL[512], info[512];
+    std::ifstream eleStream, eleInfo;
+
+    strcpy(mURL, gEnv->getRes().c_str());
+    strcpy(info, gEnv->getRes().c_str());
+    GetURLForComponent(mCompName, mURL, info);
+
+    eleInfo.open(info);
+    ASSERT_EQ(eleInfo.is_open(), true) << mURL << " - file not found";
+    android::Vector<FrameInfo> Info;
+    int bytesCount = 0;
+    uint32_t frameId = 0;
+    uint32_t flags = 0;
+    uint32_t timestamp = 0;
+    bool codecConfig = false;
+    // This test introduces empty CSD after every 20th frame
+    // and empty input frames at an interval of 5 frames.
+    while (1) {
+        if (!(frameId % 5)) {
+            if (!(frameId % 20)) flags = 32;
+            else flags = 0;
+            bytesCount = 0;
+        } else {
+            if (!(eleInfo >> bytesCount)) break;
+            eleInfo >> flags;
+            eleInfo >> timestamp;
+            codecConfig = flags ?
+                ((1 << (flags - 1)) & C2FrameData::FLAG_CODEC_CONFIG) != 0 : 0;
+        }
+        Info.push_back({bytesCount, flags, timestamp});
+        frameId++;
+    }
+    eleInfo.close();
+
+    ASSERT_EQ(mComponent->start(), C2_OK);
+    ALOGV("mURL : %s", mURL);
+    eleStream.open(mURL, std::ifstream::binary);
+    ASSERT_EQ(eleStream.is_open(), true);
+    ASSERT_NO_FATAL_FAILURE(decodeNFrames(
+        mComponent, mQueueLock, mQueueCondition, mWorkQueue, mFlushedIndices,
+        mLinearPool, eleStream, &Info, 0, (int)Info.size()));
+
+    // blocking call to ensures application to Wait till all the inputs are
+    // consumed
+    if (!mEos) {
+        ALOGV("Waiting for input consumption");
+        ASSERT_NO_FATAL_FAILURE(
+            waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue));
+    }
+
+    eleStream.close();
+    if (mFramesReceived != Info.size()) {
+        ALOGE("Input buffer count and Output buffer count mismatch");
+        ALOGV("framesReceived : %d inputFrames : %zu", mFramesReceived,
+              Info.size());
+        ASSERT_TRUE(false);
+    }
+}
+
 }  // anonymous namespace
 
 // TODO : Video specific configuration Test
diff --git a/codec2/hidl/1.0/mts/video/MtsHidlC2V1_0TargetVideoEncTest.cpp b/codec2/hidl/1.0/mts/video/MtsHidlC2V1_0TargetVideoEncTest.cpp
index 87b7902..8585c87 100644
--- a/codec2/hidl/1.0/mts/video/MtsHidlC2V1_0TargetVideoEncTest.cpp
+++ b/codec2/hidl/1.0/mts/video/MtsHidlC2V1_0TargetVideoEncTest.cpp
@@ -139,40 +139,11 @@
     // callback function to process onWorkDone received by Listener
     void handleWorkDone(std::list<std::unique_ptr<C2Work>>& workItems) {
         for (std::unique_ptr<C2Work>& work : workItems) {
-            // handle configuration changes in work done
-            if (!work->worklets.empty() &&
-                (work->worklets.front()->output.configUpdate.size() != 0)) {
-                ALOGV("Config Update");
-                std::vector<std::unique_ptr<C2Param>> updates =
-                    std::move(work->worklets.front()->output.configUpdate);
-                std::vector<C2Param*> configParam;
-                std::vector<std::unique_ptr<C2SettingResult>> failures;
-                for (size_t i = 0; i < updates.size(); ++i) {
-                    C2Param* param = updates[i].get();
-                    if (param->index() == C2StreamCsdInfo::output::PARAM_TYPE) {
-                        mCsd = true;
-                    }
-                }
-            }
-            mFramesReceived++;
-            if (work->result != C2_OK) mFailedWorkReceived++;
-            mEos = (work->worklets.front()->output.flags &
-                    C2FrameData::FLAG_END_OF_STREAM) != 0;
-            auto frameIndexIt =
-                std::find(mFlushedIndices.begin(), mFlushedIndices.end(),
-                          work->input.ordinal.frameIndex.peeku());
-            ALOGV("WorkDone: frameID received %d",
-                (int)work->worklets.front()->output.ordinal.frameIndex.peeku());
-            work->input.buffers.clear();
-            work->worklets.clear();
-            {
-                typedef std::unique_lock<std::mutex> ULock;
-                ULock l(mQueueLock);
-                mWorkQueue.push_back(std::move(work));
-                if (!mFlushedIndices.empty()) {
-                    mFlushedIndices.erase(frameIndexIt);
-                }
-                mQueueCondition.notify_all();
+            if (!work->worklets.empty()) {
+                if (work->result != C2_OK) mFailedWorkReceived++;
+                workDone(mComponent, work, mFlushedIndices, mQueueLock,
+                         mQueueCondition, mWorkQueue, mEos, mCsd,
+                         mFramesReceived);
             }
         }
     }
@@ -272,11 +243,11 @@
     strcat(URL, "bbb_352x288_420p_30fps_32frames.yuv");
 }
 
-void encodeNFrames(const std::shared_ptr<android::Codec2Client::Component> &component,
-                   std::mutex &queueLock, std::condition_variable &queueCondition,
-                   std::list<std::unique_ptr<C2Work>> &workQueue,
-                   std::list<uint64_t> &flushedIndices,
-                   std::shared_ptr<C2BlockPool> &graphicPool,
+void encodeNFrames(const std::shared_ptr<android::Codec2Client::Component>& component,
+                   std::mutex &queueLock, std::condition_variable& queueCondition,
+                   std::list<std::unique_ptr<C2Work>>& workQueue,
+                   std::list<uint64_t>& flushedIndices,
+                   std::shared_ptr<C2BlockPool>& graphicPool,
                    std::ifstream& eleStream, uint32_t frameID,
                    uint32_t nFrames, uint32_t nWidth, int32_t nHeight,
                    bool flushed = false,bool signalEOS = true) {
@@ -319,6 +290,7 @@
             flushedIndices.emplace_back(frameID);
         }
         char* data = (char*)malloc(bytesCount);
+        ASSERT_NE(data, nullptr);
         memset(data, 0, bytesCount);
         if (eleStream.is_open()) {
             eleStream.read(data, bytesCount);
@@ -365,30 +337,6 @@
     }
 }
 
-void waitOnInputConsumption(std::mutex &queueLock,
-                            std::condition_variable &queueCondition,
-                            std::list<std::unique_ptr<C2Work>> &workQueue,
-                            size_t bufferCount = MAX_INPUT_BUFFERS) {
-    typedef std::unique_lock<std::mutex> ULock;
-    uint32_t queueSize;
-    int maxRetry = 0;
-    {
-        ULock l(queueLock);
-        queueSize = workQueue.size();
-    }
-    while ((maxRetry < MAX_RETRY) && (queueSize < bufferCount)) {
-        ULock l(queueLock);
-        if (queueSize != workQueue.size()) {
-            queueSize = workQueue.size();
-            maxRetry = 0;
-        } else {
-            queueCondition.wait_for(l, TIME_OUT);
-            maxRetry++;
-        }
-    }
-}
-
-
 TEST_F(Codec2VideoEncHidlTest, validateCompName) {
     if (mDisableTest) return;
     ALOGV("Checks if the given component is a valid video component");
@@ -488,46 +436,6 @@
     ASSERT_EQ(mComponent->stop(), C2_OK);
 }
 
-TEST_F(Codec2VideoEncHidlTest, EmptyBufferTest) {
-    description("Tests empty input buffer");
-    if (mDisableTest) return;
-    ASSERT_EQ(mComponent->start(), C2_OK);
-
-    typedef std::unique_lock<std::mutex> ULock;
-    std::unique_ptr<C2Work> work;
-    {
-        ULock l(mQueueLock);
-        if (!mWorkQueue.empty()) {
-            work.swap(mWorkQueue.front());
-            mWorkQueue.pop_front();
-        } else {
-            ALOGE("mWorkQueue Empty is not expected at the start of the test");
-            ASSERT_TRUE(false);
-        }
-    }
-    ASSERT_NE(work, nullptr);
-    work->input.flags = (C2FrameData::flags_t)0;
-    work->input.ordinal.timestamp = 0;
-    work->input.ordinal.frameIndex = 0;
-    work->input.buffers.clear();
-    work->worklets.clear();
-    work->worklets.emplace_back(new C2Worklet);
-
-    std::list<std::unique_ptr<C2Work>> items;
-    items.push_back(std::move(work));
-    ASSERT_EQ(mComponent->queue(&items), C2_OK);
-    uint32_t queueSize;
-    {
-        ULock l(mQueueLock);
-        queueSize = mWorkQueue.size();
-        if (queueSize < MAX_INPUT_BUFFERS) {
-            mQueueCondition.wait_for(l, TIME_OUT);
-        }
-    }
-    ASSERT_EQ(mWorkQueue.size(), (uint32_t)MAX_INPUT_BUFFERS);
-    ASSERT_EQ(mComponent->stop(), C2_OK);
-}
-
 TEST_F(Codec2VideoEncHidlTest, FlushTest) {
     description("Test Request for flush");
     if (mDisableTest) return;
diff --git a/codec2/hidl/1.0/mts/video/media_c2_video_hidl_test_common.h b/codec2/hidl/1.0/mts/video/media_c2_video_hidl_test_common.h
index 1215b13..dd45557 100644
--- a/codec2/hidl/1.0/mts/video/media_c2_video_hidl_test_common.h
+++ b/codec2/hidl/1.0/mts/video/media_c2_video_hidl_test_common.h
@@ -17,9 +17,6 @@
 #ifndef MEDIA_C2_VIDEO_HIDL_TEST_COMMON_H
 #define MEDIA_C2_VIDEO_HIDL_TEST_COMMON_H
 
-#define MAX_RETRY 20
-#define TIME_OUT 400ms
-#define MAX_INPUT_BUFFERS 8
 #define ENCODER_TIMESTAMP_INCREMENT 40000
 #define ENC_NUM_FRAMES 32
 #define ENC_DEFAULT_FRAME_WIDTH 352
diff --git a/codec2/hidl/1.0/utils/Android.bp b/codec2/hidl/1.0/utils/Android.bp
index 1641e51..ed404ad 100644
--- a/codec2/hidl/1.0/utils/Android.bp
+++ b/codec2/hidl/1.0/utils/Android.bp
@@ -16,6 +16,7 @@
     ],
 
     header_libs: [
+        "libgui_headers",
         "libsystem_headers",
         "libstagefright_codec2_internal", // private
     ],
@@ -26,6 +27,7 @@
         "android.hardware.media.bufferpool@1.0",
         "android.hardware.media.omx@1.0",
         "android.hardware.media@1.0",
+        "android.hidl.token@1.0-utils",
         "hardware.google.media.c2@1.0",
         "libbase",
         "libcutils",
@@ -46,6 +48,7 @@
     ],
 
     export_shared_lib_headers: [
+        "android.hidl.token@1.0-utils",
         "hardware.google.media.c2@1.0",
         "libhidlbase",
         "libstagefright_bufferpool@1.0",
diff --git a/codec2/hidl/1.0/utils/ComponentStore.cpp b/codec2/hidl/1.0/utils/ComponentStore.cpp
index 4941ede..9a46b77 100644
--- a/codec2/hidl/1.0/utils/ComponentStore.cpp
+++ b/codec2/hidl/1.0/utils/ComponentStore.cpp
@@ -24,7 +24,7 @@
 #include <codec2/hidl/1.0/ConfigurableC2Intf.h>
 #include <codec2/hidl/1.0/types.h>
 
-#include <media/stagefright/bqhelper/WGraphicBufferProducer.h>
+#include <gui/bufferqueue/1.0/WGraphicBufferProducer.h>
 #include <media/stagefright/bqhelper/GraphicBufferSource.h>
 
 #include <C2PlatformSupport.h>
diff --git a/codec2/hidl/1.0/utils/types.cpp b/codec2/hidl/1.0/utils/types.cpp
index 56db4d5..10a7cef 100644
--- a/codec2/hidl/1.0/utils/types.cpp
+++ b/codec2/hidl/1.0/utils/types.cpp
@@ -20,8 +20,7 @@
 
 #include <codec2/hidl/1.0/types.h>
 
-#include <media/stagefright/bqhelper/WGraphicBufferProducer.h>
-
+#include <gui/bufferqueue/1.0/WGraphicBufferProducer.h>
 #include <C2AllocatorIon.h>
 #include <C2AllocatorGralloc.h>
 #include <C2BlockInternal.h>
@@ -1657,7 +1656,8 @@
 }
 
 sp<HGraphicBufferProducer> getHgbp(const sp<IGraphicBufferProducer>& igbp) {
-    sp<HGraphicBufferProducer> hgbp = igbp->getHalInterface();
+    sp<HGraphicBufferProducer> hgbp =
+            igbp->getHalInterface<HGraphicBufferProducer>();
     return hgbp ? hgbp :
             new TWGraphicBufferProducer<HGraphicBufferProducer>(igbp);
 }
diff --git a/codec2/hidl/client/client.cpp b/codec2/hidl/client/client.cpp
index ff67681..8b4b48b 100644
--- a/codec2/hidl/client/client.cpp
+++ b/codec2/hidl/client/client.cpp
@@ -30,8 +30,8 @@
 #include <bufferpool/ClientManager.h>
 #include <cutils/native_handle.h>
 #include <gui/bufferqueue/1.0/H2BGraphicBufferProducer.h>
+#include <gui/bufferqueue/1.0/WGraphicBufferProducer.h>
 #include <hidl/HidlSupport.h>
-#include <media/stagefright/bqhelper/WGraphicBufferProducer.h>
 #undef LOG
 
 #include <android/hardware/media/bufferpool/1.0/IClientManager.h>
@@ -553,6 +553,7 @@
                 for (size_t i = 0; i < t.size(); ++i) {
                     c2_status_t status = objcpy(
                             &mTraitsList[i], &mAliasesBuffer[i], t[i]);
+                    mTraitsList[i].owner = mInstanceName;
                     if (status != C2_OK) {
                         ALOGE("listComponents -- corrupted output.");
                         return;
@@ -1130,7 +1131,8 @@
         C2BlockPool::local_id_t blockPoolId,
         const sp<IGraphicBufferProducer>& surface,
         uint32_t generation) {
-    sp<HGraphicBufferProducer> igbp = surface->getHalInterface();
+    sp<HGraphicBufferProducer> igbp =
+            surface->getHalInterface<HGraphicBufferProducer>();
     if (!igbp) {
         igbp = new TWGraphicBufferProducer<HGraphicBufferProducer>(surface);
     }
diff --git a/codec2/hidl/services/Android.bp b/codec2/hidl/services/Android.bp
index 6b73383..00d25ca 100644
--- a/codec2/hidl/services/Android.bp
+++ b/codec2/hidl/services/Android.bp
@@ -38,8 +38,9 @@
 }
 
 cc_library_shared {
-    name: "libmedia_codecserviceregistrant",
-    soc_specific: true,
+    name: "libcodec2_serviceregistrant",
+    // need vendor version for update packaging, system version may have more dependencies
+    vendor_available: true,
     srcs: [
         "C2SoftwareCodecServiceRegistrant.cpp",
     ],
@@ -49,46 +50,45 @@
     ],
 
     shared_libs: [
-        "android.hardware.media.omx@1.0",
         "hardware.google.media.c2@1.0",
         "liblog",
         "libcodec2_hidl_utils@1.0",
         "libstagefright_codec2_vndk",
-        "libstagefright_omx",
-        "libstagefright_xmlparser",
         "libutils",
     ],
 
     // Codecs
-    required: [
-        "libstagefright_soft_c2avcdec.vendor",
-        "libstagefright_soft_c2avcenc.vendor",
-        "libstagefright_soft_c2aacdec.vendor",
-        "libstagefright_soft_c2aacenc.vendor",
-        "libstagefright_soft_c2amrnbdec.vendor",
-        "libstagefright_soft_c2amrnbenc.vendor",
-        "libstagefright_soft_c2amrwbdec.vendor",
-        "libstagefright_soft_c2amrwbenc.vendor",
-        "libstagefright_soft_c2hevcdec.vendor",
-        "libstagefright_soft_c2g711alawdec.vendor",
-        "libstagefright_soft_c2g711mlawdec.vendor",
-        "libstagefright_soft_c2mpeg2dec.vendor",
-        "libstagefright_soft_c2h263dec.vendor",
-        "libstagefright_soft_c2h263enc.vendor",
-        "libstagefright_soft_c2mpeg4dec.vendor",
-        "libstagefright_soft_c2mpeg4enc.vendor",
-        "libstagefright_soft_c2mp3dec.vendor",
-        "libstagefright_soft_c2vorbisdec.vendor",
-        "libstagefright_soft_c2opusdec.vendor",
-        "libstagefright_soft_c2vp8dec.vendor",
-        "libstagefright_soft_c2vp9dec.vendor",
-        "libstagefright_soft_c2vp8enc.vendor",
-        "libstagefright_soft_c2vp9enc.vendor",
-        "libstagefright_soft_c2rawdec.vendor",
-        "libstagefright_soft_c2flacdec.vendor",
-        "libstagefright_soft_c2flacenc.vendor",
-        "libstagefright_soft_c2gsmdec.vendor",
+    runtime_libs: [
+        "libstagefright_soft_c2avcdec",
+        "libstagefright_soft_c2avcenc",
+        "libstagefright_soft_c2aacdec",
+        "libstagefright_soft_c2aacenc",
+        "libstagefright_soft_c2amrnbdec",
+        "libstagefright_soft_c2amrnbenc",
+        "libstagefright_soft_c2amrwbdec",
+        "libstagefright_soft_c2amrwbenc",
+        "libstagefright_soft_c2hevcdec",
+        "libstagefright_soft_c2g711alawdec",
+        "libstagefright_soft_c2g711mlawdec",
+        "libstagefright_soft_c2mpeg2dec",
+        "libstagefright_soft_c2h263dec",
+        "libstagefright_soft_c2h263enc",
+        "libstagefright_soft_c2mpeg4dec",
+        "libstagefright_soft_c2mpeg4enc",
+        "libstagefright_soft_c2mp3dec",
+        "libstagefright_soft_c2vorbisdec",
+        "libstagefright_soft_c2opusdec",
+        "libstagefright_soft_c2vp8dec",
+        "libstagefright_soft_c2vp9dec",
+        "libstagefright_soft_c2vp8enc",
+        "libstagefright_soft_c2vp9enc",
+        "libstagefright_soft_c2rawdec",
+        "libstagefright_soft_c2flacdec",
+        "libstagefright_soft_c2flacenc",
+        "libstagefright_soft_c2gsmdec",
+        "libstagefright_soft_c2xaacdec",
     ],
+
     compile_multilib: "32",
 }
 
diff --git a/codec2/hidl/services/Android.mk b/codec2/hidl/services/Android.mk
deleted file mode 100644
index d9b28e7..0000000
--- a/codec2/hidl/services/Android.mk
+++ /dev/null
@@ -1,24 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-# vendor service seccomp policy
-ifeq ($(TARGET_ARCH),$(filter $(TARGET_ARCH), x86 x86_64 arm arm64))
-include $(CLEAR_VARS)
-LOCAL_MODULE := codec2.vendor.base.policy
-LOCAL_VENDOR_MODULE := true
-LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR)/etc/seccomp_policy
-LOCAL_REQUIRED_MODULES := crash_dump.policy
-ifdef TARGET_2ND_ARCH
-    ifneq ($(TARGET_TRANSLATE_2ND_ARCH),true)
-        LOCAL_SRC_FILES := seccomp_policy/codec2.vendor.base-$(TARGET_2ND_ARCH).policy
-    else
-        LOCAL_SRC_FILES := seccomp_policy/codec2.vendor.base-$(TARGET_ARCH).policy
-    endif
-else
-    LOCAL_SRC_FILES := seccomp_policy/codec2.vendor.base-$(TARGET_ARCH).policy
-endif
-include $(BUILD_PREBUILT)
-endif
-
-include $(call all-makefiles-under, $(LOCAL_PATH))
-
diff --git a/codec2/hidl/services/C2SoftwareCodecServiceRegistrant.cpp b/codec2/hidl/services/C2SoftwareCodecServiceRegistrant.cpp
index eddfbcb..04efa44 100644
--- a/codec2/hidl/services/C2SoftwareCodecServiceRegistrant.cpp
+++ b/codec2/hidl/services/C2SoftwareCodecServiceRegistrant.cpp
@@ -20,7 +20,6 @@
 #include <C2PlatformSupport.h>
 #include <codec2/hidl/1.0/ComponentStore.h>
 #include <media/CodecServiceRegistrant.h>
-#include <media/stagefright/omx/1.0/Omx.h>
 #include <log/log.h>
 
 extern "C" void RegisterCodecServices() {
@@ -38,15 +37,5 @@
             ALOGI("Codec2's IComponentStore software service created.");
         }
     }
-
-    // Default codec services
-    using namespace ::android::hardware::media::omx::V1_0;
-    android::sp<IOmx> omx = new implementation::Omx();
-    if (omx == nullptr) {
-        ALOGE("Cannot create IOmx HAL service.");
-    } else if (omx->registerAsService() != android::OK) {
-        ALOGE("Cannot register IOmx HAL service.");
-    }
-
 }
 
diff --git a/codec2/hidl/services/seccomp_policy/codec2.software.base-arm.policy b/codec2/hidl/services/seccomp_policy/codec2.software.base-arm.policy
deleted file mode 100644
index d5871d1..0000000
--- a/codec2/hidl/services/seccomp_policy/codec2.software.base-arm.policy
+++ /dev/null
@@ -1,73 +0,0 @@
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# Organized by frequency of systemcall - in descending order for
-# best performance.
-futex: 1
-ioctl: 1
-write: 1
-prctl: 1
-clock_gettime: 1
-getpriority: 1
-read: 1
-close: 1
-writev: 1
-dup: 1
-ppoll: 1
-mmap2: 1
-getrandom: 1
-
-# mremap: Ensure |flags| are (MREMAP_MAYMOVE | MREMAP_FIXED) TODO: Once minijail
-# parser support for '<' is in this needs to be modified to also prevent
-# |old_address| and |new_address| from touching the exception vector page, which
-# on ARM is statically loaded at 0xffff 0000. See
-# http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0211h/Babfeega.html
-# for more details.
-mremap: arg3 == 3
-munmap: 1
-mprotect: 1
-madvise: 1
-openat: 1
-sigaltstack: 1
-clone: 1
-setpriority: 1
-getuid32: 1
-fstat64: 1
-fstatfs64: 1
-pread64: 1
-faccessat: 1
-readlinkat: 1
-exit: 1
-rt_sigprocmask: 1
-set_tid_address: 1
-restart_syscall: 1
-exit_group: 1
-rt_sigreturn: 1
-pipe2: 1
-gettimeofday: 1
-sched_yield: 1
-nanosleep: 1
-lseek: 1
-_llseek: 1
-sched_get_priority_max: 1
-sched_get_priority_min: 1
-statfs64: 1
-sched_setscheduler: 1
-fstatat64: 1
-ugetrlimit: 1
-getdents64: 1
-getrandom: 1
-
-@include /system/etc/seccomp_policy/crash_dump.arm.policy
-
diff --git a/codec2/hidl/services/seccomp_policy/codec2.software.base-x86.policy b/codec2/hidl/services/seccomp_policy/codec2.software.base-x86.policy
deleted file mode 100644
index 20c7625..0000000
--- a/codec2/hidl/services/seccomp_policy/codec2.software.base-x86.policy
+++ /dev/null
@@ -1,57 +0,0 @@
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-read: 1
-mprotect: 1
-prctl: 1
-openat: 1
-getuid32: 1
-writev: 1
-ioctl: 1
-close: 1
-mmap2: 1
-fstat64: 1
-madvise: 1
-fstatat64: 1
-futex: 1
-munmap: 1
-faccessat: 1
-_llseek: 1
-lseek: 1
-clone: 1
-sigaltstack: 1
-setpriority: 1
-restart_syscall: 1
-exit: 1
-exit_group: 1
-rt_sigreturn: 1
-ugetrlimit: 1
-readlinkat: 1
-_llseek: 1
-fstatfs64: 1
-pread64: 1
-mremap: 1
-dup: 1
-set_tid_address: 1
-write: 1
-nanosleep: 1
-
-# Required by AddressSanitizer
-gettid: 1
-sched_yield: 1
-getpid: 1
-gettid: 1
-
-@include /system/etc/seccomp_policy/crash_dump.x86.policy
-
diff --git a/codec2/hidl/services/seccomp_policy/codec2.vendor.base-arm.policy b/codec2/hidl/services/seccomp_policy/codec2.vendor.base-arm.policy
deleted file mode 100644
index d5871d1..0000000
--- a/codec2/hidl/services/seccomp_policy/codec2.vendor.base-arm.policy
+++ /dev/null
@@ -1,73 +0,0 @@
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# Organized by frequency of systemcall - in descending order for
-# best performance.
-futex: 1
-ioctl: 1
-write: 1
-prctl: 1
-clock_gettime: 1
-getpriority: 1
-read: 1
-close: 1
-writev: 1
-dup: 1
-ppoll: 1
-mmap2: 1
-getrandom: 1
-
-# mremap: Ensure |flags| are (MREMAP_MAYMOVE | MREMAP_FIXED) TODO: Once minijail
-# parser support for '<' is in this needs to be modified to also prevent
-# |old_address| and |new_address| from touching the exception vector page, which
-# on ARM is statically loaded at 0xffff 0000. See
-# http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0211h/Babfeega.html
-# for more details.
-mremap: arg3 == 3
-munmap: 1
-mprotect: 1
-madvise: 1
-openat: 1
-sigaltstack: 1
-clone: 1
-setpriority: 1
-getuid32: 1
-fstat64: 1
-fstatfs64: 1
-pread64: 1
-faccessat: 1
-readlinkat: 1
-exit: 1
-rt_sigprocmask: 1
-set_tid_address: 1
-restart_syscall: 1
-exit_group: 1
-rt_sigreturn: 1
-pipe2: 1
-gettimeofday: 1
-sched_yield: 1
-nanosleep: 1
-lseek: 1
-_llseek: 1
-sched_get_priority_max: 1
-sched_get_priority_min: 1
-statfs64: 1
-sched_setscheduler: 1
-fstatat64: 1
-ugetrlimit: 1
-getdents64: 1
-getrandom: 1
-
-@include /system/etc/seccomp_policy/crash_dump.arm.policy
-
diff --git a/codec2/hidl/services/seccomp_policy/codec2.vendor.base-x86.policy b/codec2/hidl/services/seccomp_policy/codec2.vendor.base-x86.policy
deleted file mode 100644
index 20c7625..0000000
--- a/codec2/hidl/services/seccomp_policy/codec2.vendor.base-x86.policy
+++ /dev/null
@@ -1,57 +0,0 @@
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-read: 1
-mprotect: 1
-prctl: 1
-openat: 1
-getuid32: 1
-writev: 1
-ioctl: 1
-close: 1
-mmap2: 1
-fstat64: 1
-madvise: 1
-fstatat64: 1
-futex: 1
-munmap: 1
-faccessat: 1
-_llseek: 1
-lseek: 1
-clone: 1
-sigaltstack: 1
-setpriority: 1
-restart_syscall: 1
-exit: 1
-exit_group: 1
-rt_sigreturn: 1
-ugetrlimit: 1
-readlinkat: 1
-_llseek: 1
-fstatfs64: 1
-pread64: 1
-mremap: 1
-dup: 1
-set_tid_address: 1
-write: 1
-nanosleep: 1
-
-# Required by AddressSanitizer
-gettid: 1
-sched_yield: 1
-getpid: 1
-gettid: 1
-
-@include /system/etc/seccomp_policy/crash_dump.x86.policy
-
diff --git a/codec2/include/C2.h b/codec2/include/C2.h
index 8a55f8d..ef3466d 100644
--- a/codec2/include/C2.h
+++ b/codec2/include/C2.h
@@ -289,7 +289,7 @@
      * Convert to a smaller counter type. This is always safe.
      */
     template<typename U, typename E=typename std::enable_if<(sizeof(U) < sizeof(T))>::type>
-    inline operator c2_cntr_t<U>() {
+    inline constexpr operator c2_cntr_t<U>() {
         return c2_cntr_t<U>(mValue);
     }
 
diff --git a/codec2/include/C2Component.h b/codec2/include/C2Component.h
index 8810725..7624851 100644
--- a/codec2/include/C2Component.h
+++ b/codec2/include/C2Component.h
@@ -409,6 +409,7 @@
         kind_t kind; ///< component kind
         rank_t rank; ///< component rank
         C2String mediaType; ///< media type supported by the component
+        C2String owner; ///< name of the component store owning this component
 
         /**
          * name alias(es) for backward compatibility.
diff --git a/codec2/include/C2Config.h b/codec2/include/C2Config.h
index 838ae49..be5f128 100644
--- a/codec2/include/C2Config.h
+++ b/codec2/include/C2Config.h
@@ -180,6 +180,7 @@
 
     kParamIndexPictureTypeMask,
     kParamIndexPictureType,
+    kParamIndexHdr10PlusMetadata,
 
     /* ------------------------------------ video components ------------------------------------ */
 
@@ -238,6 +239,8 @@
     kParamIndexMinFrameRate, // input-surface, float
     kParamIndexTimestampGapAdjustment, // input-surface, struct
 
+    kParamIndexSurfaceAllocator, // u32
+
     // deprecated indices due to renaming
     kParamIndexAacStreamFormat = kParamIndexAacPackaging,
     kParamIndexCsd = kParamIndexInitData,
@@ -904,6 +907,18 @@
 constexpr char C2_PARAMKEY_PRIVATE_ALLOCATORS[] = "algo.buffers.allocator-ids";
 
 /**
+ * Allocator to use for outputting to surface.
+ *
+ * Components can optionally request allocator type for outputting to surface.
+ *
+ * If none specified, client will use the default BufferQueue-backed allocator ID for outputting to
+ * surface.
+ */
+typedef C2PortParam<C2Tuning, C2Uint32Value, kParamIndexSurfaceAllocator>
+        C2PortSurfaceAllocatorTuning;
+constexpr char C2_PARAMKEY_OUTPUT_SURFACE_ALLOCATOR[] = "output.buffers.surface-allocator-id";
+
+/**
  * Block pools to use.
  *
  * These are allocated by the client for the component using the allocator IDs specified by the
@@ -1546,6 +1561,14 @@
         C2StreamHdrStaticInfo;
 constexpr char C2_PARAMKEY_HDR_STATIC_INFO[] = "raw.hdr-static-info";
 
+/**
+ * HDR10+ Metadata Info.
+ */
+typedef C2StreamParam<C2Info, C2BlobValue, kParamIndexHdr10PlusMetadata>
+        C2StreamHdr10PlusInfo;
+constexpr char C2_PARAMKEY_INPUT_HDR10_PLUS_INFO[] = "input.hdr10-plus-info";
+constexpr char C2_PARAMKEY_OUTPUT_HDR10_PLUS_INFO[] = "output.hdr10-plus-info";
+
 /* ------------------------------------ block-based coding ----------------------------------- */
 
 /**
diff --git a/codec2/include/C2Enum.h b/codec2/include/C2Enum.h
index a7bbcdc..b0fad8f 100644
--- a/codec2/include/C2Enum.h
+++ b/codec2/include/C2Enum.h
@@ -63,7 +63,7 @@
 
     static std::vector<C2String> sanitizeEnumValueNames(
             const std::vector<C2StringLiteral> names,
-            C2StringLiteral _prefix = NULL);
+            C2StringLiteral _prefix = nullptr);
 
     friend class C2UtilTest_EnumUtilsTest_Test;
 
@@ -75,7 +75,7 @@
     static C2_HIDE C2FieldDescriptor::NamedValuesType sanitizeEnumValues(
             std::vector<T> values,
             std::vector<C2StringLiteral> names,
-            C2StringLiteral prefix = NULL) {
+            C2StringLiteral prefix = nullptr) {
         C2FieldDescriptor::NamedValuesType namedValues;
         std::vector<C2String> sanitizedNames = sanitizeEnumValueNames(names, prefix);
         for (size_t i = 0; i < values.size() && i < sanitizedNames.size(); ++i) {
@@ -147,7 +147,7 @@
  */
 #define C2ENUM(name, type, ...) \
 enum name : type { __VA_ARGS__ }; \
-DEFINE_C2_ENUM_VALUE_AUTO_HELPER(name, type, NULL, __VA_ARGS__)
+DEFINE_C2_ENUM_VALUE_AUTO_HELPER(name, type, nullptr, __VA_ARGS__)
 
 /**
  * Defines an enum type with the default named value mapper but custom prefix. The default
diff --git a/codec2/include/C2Param.h b/codec2/include/C2Param.h
index 40be3b3..efc5c89 100644
--- a/codec2/include/C2Param.h
+++ b/codec2/include/C2Param.h
@@ -988,7 +988,10 @@
     /** specialization for easy enums */
     template<typename E>
     inline static NamedValuesType namedValuesFor(const C2EasyEnum<E> &) {
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wnull-dereference"
         return namedValuesFor(*(E*)nullptr);
+#pragma GCC diagnostic pop
     }
 
 private:
@@ -1104,7 +1107,10 @@
 template<typename B>
 struct C2FieldDescriptor::_NamedValuesGetter<B, true> {
     inline static C2FieldDescriptor::NamedValuesType getNamedValues() {
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wnull-dereference"
         return C2FieldDescriptor::namedValuesFor(*(B*)nullptr);
+#pragma GCC diagnostic pop
     }
 };
 
@@ -1599,11 +1605,13 @@
     /// \internal
     /// \todo: create separate values vs. flags initializer as for flags we want
     /// to list both allowed and required flags
-    template<typename T, typename E=decltype(C2FieldDescriptor::namedValuesFor(*(T*)0))>
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wnull-dereference"
+    template<typename T, typename E=decltype(C2FieldDescriptor::namedValuesFor(*(T*)nullptr))>
     C2FieldSupportedValues(bool flags, const T*)
         : type(flags ? FLAGS : VALUES),
           range{(T)0, (T)0, (T)0, (T)0, (T)0} {
-              C2FieldDescriptor::NamedValuesType named = C2FieldDescriptor::namedValuesFor(*(T*)0);
+              C2FieldDescriptor::NamedValuesType named = C2FieldDescriptor::namedValuesFor(*(T*)nullptr);
         if (flags) {
             values.emplace_back(0); // min-mask defaults to 0
         }
@@ -1612,6 +1620,7 @@
         }
     }
 };
+#pragma GCC diagnostic pop
 
 /**
  * Supported values for a specific field.
diff --git a/codec2/include/media/stagefright/codec2/1.0/InputSurface.h b/codec2/include/media/stagefright/codec2/1.0/InputSurface.h
index b011a06..226dcc1 100644
--- a/codec2/include/media/stagefright/codec2/1.0/InputSurface.h
+++ b/codec2/include/media/stagefright/codec2/1.0/InputSurface.h
@@ -20,7 +20,7 @@
 #include <memory>
 
 #include <C2Component.h>
-#include <media/stagefright/bqhelper/WGraphicBufferProducer.h>
+#include <gui/bufferqueue/1.0/WGraphicBufferProducer.h>
 #include <media/stagefright/codec2/1.0/InputSurfaceConnection.h>
 
 namespace android {
diff --git a/codec2/include/media/stagefright/codec2/1.0/InputSurfaceConnection.h b/codec2/include/media/stagefright/codec2/1.0/InputSurfaceConnection.h
index b24a416..06e52cf 100644
--- a/codec2/include/media/stagefright/codec2/1.0/InputSurfaceConnection.h
+++ b/codec2/include/media/stagefright/codec2/1.0/InputSurfaceConnection.h
@@ -20,8 +20,8 @@
 #include <memory>
 
 #include <C2Component.h>
+#include <gui/bufferqueue/1.0/WGraphicBufferProducer.h>
 #include <media/stagefright/bqhelper/GraphicBufferSource.h>
-#include <media/stagefright/bqhelper/WGraphicBufferProducer.h>
 #include <media/stagefright/codec2/1.0/InputSurfaceConnection.h>
 
 namespace android {
diff --git a/codec2/tests/Android.bp b/codec2/tests/Android.bp
index 9f167bf..f54c039 100644
--- a/codec2/tests/Android.bp
+++ b/codec2/tests/Android.bp
@@ -20,7 +20,6 @@
     cflags: [
         "-Werror",
         "-Wall",
-        "-std=c++14",
     ],
 }
 
@@ -48,7 +47,6 @@
     cflags: [
         "-Werror",
         "-Wall",
-        "-std=c++14",
     ],
 }
 
@@ -74,6 +72,5 @@
     cflags: [
         "-Werror",
         "-Wall",
-        "-std=c++14",
     ],
 }
diff --git a/codec2/tests/C2SampleComponent_test.cpp b/codec2/tests/C2SampleComponent_test.cpp
index ea445e8..cd354ad 100644
--- a/codec2/tests/C2SampleComponent_test.cpp
+++ b/codec2/tests/C2SampleComponent_test.cpp
@@ -361,11 +361,11 @@
             for (const C2FieldDescriptor::NamedValueType &p : f.namedValues()) {
                 cout << sep << p.first << "=";
                 switch (f.type()) {
-                case C2Value::INT32: cout << get(p.second, (int32_t *)0); break;
-                case C2Value::INT64: cout << get(p.second, (int64_t *)0); break;
-                case C2Value::UINT32: cout << get(p.second, (uint32_t *)0); break;
-                case C2Value::UINT64: cout << get(p.second, (uint64_t *)0); break;
-                case C2Value::FLOAT: cout << get(p.second, (float *)0); break;
+                case C2FieldDescriptor::INT32: cout << get(p.second, (int32_t *)0); break;
+                case C2FieldDescriptor::INT64: cout << get(p.second, (int64_t *)0); break;
+                case C2FieldDescriptor::UINT32: cout << get(p.second, (uint32_t *)0); break;
+                case C2FieldDescriptor::UINT64: cout << get(p.second, (uint64_t *)0); break;
+                case C2FieldDescriptor::FLOAT: cout << get(p.second, (float *)0); break;
                 default: cout << "???"; break;
                 }
                 sep = ",";
diff --git a/codec2/vndk/Android.bp b/codec2/vndk/Android.bp
index cc1db02..845d113 100644
--- a/codec2/vndk/Android.bp
+++ b/codec2/vndk/Android.bp
@@ -36,6 +36,7 @@
     export_shared_lib_headers: [
         "libbase",
         "android.hardware.media.bufferpool@1.0",
+        "android.hidl.token@1.0-utils",
     ],
 
     local_include_dirs: [
@@ -47,11 +48,16 @@
         "hardware/google/av/codec2/include",
     ],
 
+    header_libs: [
+        "libgui_headers",
+    ],
+
     shared_libs: [
         "android.hardware.graphics.allocator@2.0",
         "android.hardware.graphics.bufferqueue@1.0",
         "android.hardware.graphics.mapper@2.0",
         "android.hardware.media.bufferpool@1.0",
+        "android.hidl.token@1.0-utils",
         "libbase",
         "libbinder",
         "libcutils",
@@ -71,7 +77,6 @@
     cflags: [
         "-Werror",
         "-Wall",
-        "-std=c++14",
     ],
 }
 
@@ -101,6 +106,3 @@
     // TODO: separate internal headers so they can be exposed here
 }
 
-subdirs = [
-    "bufferpool",
-]
diff --git a/codec2/vndk/C2AllocatorGralloc.cpp b/codec2/vndk/C2AllocatorGralloc.cpp
index 360dec8..d3fbbd0 100644
--- a/codec2/vndk/C2AllocatorGralloc.cpp
+++ b/codec2/vndk/C2AllocatorGralloc.cpp
@@ -303,6 +303,7 @@
     const C2HandleGralloc *mLockedHandle;
     bool mLocked;
     C2Allocator::id_t mAllocatorId;
+    std::mutex mMappedLock;
 };
 
 C2AllocationGralloc::C2AllocationGralloc(
@@ -352,6 +353,7 @@
     // TODO
     (void) fence;
 
+    std::lock_guard<std::mutex> lock(mMappedLock);
     if (mBuffer && mLocked) {
         ALOGD("already mapped");
         return C2_DUPLICATE;
@@ -558,6 +560,8 @@
     // TODO: check addr and size, use fence
     (void)addr;
     (void)rect;
+
+    std::lock_guard<std::mutex> lock(mMappedLock);
     c2_status_t err = C2_OK;
     mMapper->unlock(
             const_cast<native_handle_t *>(mBuffer),
diff --git a/codec2/vndk/bufferpool/Accessor.cpp b/codec2/vndk/bufferpool/Accessor.cpp
deleted file mode 100644
index b1dfc08..0000000
--- a/codec2/vndk/bufferpool/Accessor.cpp
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#define LOG_TAG "BufferPoolConnection"
-
-#include "Accessor.h"
-#include "AccessorImpl.h"
-#include "Connection.h"
-
-namespace android {
-namespace hardware {
-namespace media {
-namespace bufferpool {
-namespace V1_0 {
-namespace implementation {
-
-void ConnectionDeathRecipient::add(
-        int64_t connectionId,
-        const sp<Accessor> &accessor) {
-    std::lock_guard<std::mutex> lock(mLock);
-    if (mAccessors.find(connectionId) == mAccessors.end()) {
-        mAccessors.insert(std::make_pair(connectionId, accessor));
-    }
-}
-
-void ConnectionDeathRecipient::remove(int64_t connectionId) {
-    std::lock_guard<std::mutex> lock(mLock);
-    mAccessors.erase(connectionId);
-    auto it = mConnectionToCookie.find(connectionId);
-    if (it != mConnectionToCookie.end()) {
-        uint64_t cookie = it->second;
-        mConnectionToCookie.erase(it);
-        auto cit = mCookieToConnections.find(cookie);
-        if (cit != mCookieToConnections.end()) {
-            cit->second.erase(connectionId);
-            if (cit->second.size() == 0) {
-                mCookieToConnections.erase(cit);
-            }
-        }
-    }
-}
-
-void ConnectionDeathRecipient::addCookieToConnection(
-        uint64_t cookie,
-        int64_t connectionId) {
-    std::lock_guard<std::mutex> lock(mLock);
-    if (mAccessors.find(connectionId) == mAccessors.end()) {
-        return;
-    }
-    mConnectionToCookie.insert(std::make_pair(connectionId, cookie));
-    auto it = mCookieToConnections.find(cookie);
-    if (it != mCookieToConnections.end()) {
-        it->second.insert(connectionId);
-    } else {
-        mCookieToConnections.insert(std::make_pair(
-                cookie, std::set<int64_t>{connectionId}));
-    }
-}
-
-void ConnectionDeathRecipient::serviceDied(
-        uint64_t cookie,
-        const wp<::android::hidl::base::V1_0::IBase>& /* who */
-        ) {
-    std::map<int64_t, const wp<Accessor>> connectionsToClose;
-    {
-        std::lock_guard<std::mutex> lock(mLock);
-
-        auto it = mCookieToConnections.find(cookie);
-        if (it != mCookieToConnections.end()) {
-            for (auto conIt = it->second.begin(); conIt != it->second.end(); ++conIt) {
-                auto accessorIt = mAccessors.find(*conIt);
-                if (accessorIt != mAccessors.end()) {
-                    connectionsToClose.insert(std::make_pair(*conIt, accessorIt->second));
-                    mAccessors.erase(accessorIt);
-                }
-                mConnectionToCookie.erase(*conIt);
-            }
-            mCookieToConnections.erase(it);
-        }
-    }
-
-    if (connectionsToClose.size() > 0) {
-        sp<Accessor> accessor;
-        for (auto it = connectionsToClose.begin(); it != connectionsToClose.end(); ++it) {
-            accessor = it->second.promote();
-
-            if (accessor) {
-                accessor->close(it->first);
-                ALOGD("connection %lld closed on death", (long long)it->first);
-            }
-        }
-    }
-}
-
-namespace {
-static sp<ConnectionDeathRecipient> sConnectionDeathRecipient =
-        new ConnectionDeathRecipient();
-}
-
-sp<ConnectionDeathRecipient> Accessor::getConnectionDeathRecipient() {
-    return sConnectionDeathRecipient;
-}
-
-// Methods from ::android::hardware::media::bufferpool::V1_0::IAccessor follow.
-Return<void> Accessor::connect(connect_cb _hidl_cb) {
-    sp<Connection> connection;
-    ConnectionId connectionId;
-    const QueueDescriptor* fmqDesc;
-
-    ResultStatus status = connect(&connection, &connectionId, &fmqDesc, false);
-    if (status == ResultStatus::OK) {
-        _hidl_cb(status, connection, connectionId, *fmqDesc);
-    } else {
-        _hidl_cb(status, nullptr, -1LL,
-                 android::hardware::MQDescriptorSync<BufferStatusMessage>(
-                         std::vector<android::hardware::GrantorDescriptor>(),
-                         nullptr /* nhandle */, 0 /* size */));
-    }
-    return Void();
-}
-
-Accessor::Accessor(const std::shared_ptr<BufferPoolAllocator> &allocator)
-    : mImpl(new Impl(allocator)) {}
-
-Accessor::~Accessor() {
-}
-
-bool Accessor::isValid() {
-    return (bool)mImpl;
-}
-
-ResultStatus Accessor::allocate(
-        ConnectionId connectionId,
-        const std::vector<uint8_t> &params,
-        BufferId *bufferId, const native_handle_t** handle) {
-    if (mImpl) {
-        return mImpl->allocate(connectionId, params, bufferId, handle);
-    }
-    return ResultStatus::CRITICAL_ERROR;
-}
-
-ResultStatus Accessor::fetch(
-        ConnectionId connectionId, TransactionId transactionId,
-        BufferId bufferId, const native_handle_t** handle) {
-    if (mImpl) {
-        return mImpl->fetch(connectionId, transactionId, bufferId, handle);
-    }
-    return ResultStatus::CRITICAL_ERROR;
-}
-
-ResultStatus Accessor::connect(
-        sp<Connection> *connection, ConnectionId *pConnectionId,
-        const QueueDescriptor** fmqDescPtr, bool local) {
-    if (mImpl) {
-        ResultStatus status = mImpl->connect(this, connection, pConnectionId, fmqDescPtr);
-        if (!local && status == ResultStatus::OK) {
-            sp<Accessor> accessor(this);
-            sConnectionDeathRecipient->add(*pConnectionId, accessor);
-        }
-        return status;
-    }
-    return ResultStatus::CRITICAL_ERROR;
-}
-
-ResultStatus Accessor::close(ConnectionId connectionId) {
-    if (mImpl) {
-        ResultStatus status = mImpl->close(connectionId);
-        sConnectionDeathRecipient->remove(connectionId);
-        return status;
-    }
-    return ResultStatus::CRITICAL_ERROR;
-}
-
-void Accessor::cleanUp(bool clearCache) {
-    if (mImpl) {
-        mImpl->cleanUp(clearCache);
-    }
-}
-
-//IAccessor* HIDL_FETCH_IAccessor(const char* /* name */) {
-//    return new Accessor();
-//}
-
-}  // namespace implementation
-}  // namespace V1_0
-}  // namespace bufferpool
-}  // namespace media
-}  // namespace hardware
-}  // namespace android
diff --git a/codec2/vndk/bufferpool/Accessor.h b/codec2/vndk/bufferpool/Accessor.h
deleted file mode 100644
index 2f86f7b..0000000
--- a/codec2/vndk/bufferpool/Accessor.h
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V1_0_ACCESSOR_H
-#define ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V1_0_ACCESSOR_H
-
-#include <android/hardware/media/bufferpool/1.0/IAccessor.h>
-#include <bufferpool/BufferPoolTypes.h>
-#include <hidl/MQDescriptor.h>
-#include <hidl/Status.h>
-#include "BufferStatus.h"
-
-#include <set>
-
-namespace android {
-namespace hardware {
-namespace media {
-namespace bufferpool {
-namespace V1_0 {
-namespace implementation {
-
-using ::android::hardware::hidl_array;
-using ::android::hardware::hidl_memory;
-using ::android::hardware::hidl_string;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::sp;
-
-struct Accessor;
-struct Connection;
-
-/**
- * Receives death notifications from remote connections.
- * On death notifications, the connections are closed and used resources
- * are released.
- */
-struct ConnectionDeathRecipient : public hardware::hidl_death_recipient {
-    /**
-     * Registers a newly connected connection from remote processes.
-     */
-    void add(int64_t connectionId, const sp<Accessor> &accessor);
-
-    /**
-     * Removes a connection.
-     */
-    void remove(int64_t connectionId);
-
-    void addCookieToConnection(uint64_t cookie, int64_t connectionId);
-
-    virtual void serviceDied(
-            uint64_t /* cookie */,
-            const wp<::android::hidl::base::V1_0::IBase>& /* who */
-            ) override;
-
-private:
-    std::mutex mLock;
-    std::map<uint64_t, std::set<int64_t>>  mCookieToConnections;
-    std::map<int64_t, uint64_t> mConnectionToCookie;
-    std::map<int64_t, const wp<Accessor>> mAccessors;
-};
-
-/**
- * A buffer pool accessor which enables a buffer pool to communicate with buffer
- * pool clients. 1:1 correspondense holds between a buffer pool and an accessor.
- */
-struct Accessor : public IAccessor {
-    // Methods from ::android::hardware::media::bufferpool::V1_0::IAccessor follow.
-    Return<void> connect(connect_cb _hidl_cb) override;
-
-    /**
-     * Creates a buffer pool accessor which uses the specified allocator.
-     *
-     * @param allocator buffer allocator.
-     */
-    explicit Accessor(const std::shared_ptr<BufferPoolAllocator> &allocator);
-
-    /** Destructs a buffer pool accessor. */
-    ~Accessor();
-
-    /** Returns whether the accessor is valid. */
-    bool isValid();
-
-    /** Allocates a buffer from a buffer pool.
-     *
-     * @param connectionId  the connection id of the client.
-     * @param params        the allocation parameters.
-     * @param bufferId      the id of the allocated buffer.
-     * @param handle        the native handle of the allocated buffer.
-     *
-     * @return OK when a buffer is successfully allocated.
-     *         NO_MEMORY when there is no memory.
-     *         CRITICAL_ERROR otherwise.
-     */
-    ResultStatus allocate(
-            ConnectionId connectionId,
-            const std::vector<uint8_t>& params,
-            BufferId *bufferId,
-            const native_handle_t** handle);
-
-    /**
-     * Fetches a buffer for the specified transaction.
-     *
-     * @param connectionId  the id of receiving connection(client).
-     * @param transactionId the id of the transfer transaction.
-     * @param bufferId      the id of the buffer to be fetched.
-     * @param handle        the native handle of the fetched buffer.
-     *
-     * @return OK when a buffer is successfully fetched.
-     *         NO_MEMORY when there is no memory.
-     *         CRITICAL_ERROR otherwise.
-     */
-    ResultStatus fetch(
-            ConnectionId connectionId,
-            TransactionId transactionId,
-            BufferId bufferId,
-            const native_handle_t** handle);
-
-    /**
-     * Makes a connection to the buffer pool. The buffer pool client uses the
-     * created connection in order to communicate with the buffer pool. An
-     * FMQ for buffer status message is also created for the client.
-     *
-     * @param connection    created connection
-     * @param pConnectionId the id of the created connection
-     * @param fmqDescPtr    FMQ descriptor for shared buffer status message
-     *                      queue between a buffer pool and the client.
-     * @param local         true when a connection request comes from local process,
-     *                      false otherwise.
-     *
-     * @return OK when a connection is successfully made.
-     *         NO_MEMORY when there is no memory.
-     *         CRITICAL_ERROR otherwise.
-     */
-    ResultStatus connect(
-            sp<Connection> *connection, ConnectionId *pConnectionId,
-            const QueueDescriptor** fmqDescPtr, bool local);
-
-    /**
-     * Closes the specified connection to the client.
-     *
-     * @param connectionId  the id of the connection.
-     *
-     * @return OK when the connection is closed.
-     *         CRITICAL_ERROR otherwise.
-     */
-    ResultStatus close(ConnectionId connectionId);
-
-    /**
-     * Processes pending buffer status messages and perfoms periodic cache
-     * cleaning.
-     *
-     * @param clearCache    if clearCache is true, it frees all buffers waiting
-     *                      to be recycled.
-     */
-    void cleanUp(bool clearCache);
-
-    /**
-     * Gets a hidl_death_recipient for remote connection death.
-     */
-    static sp<ConnectionDeathRecipient> getConnectionDeathRecipient();
-
-private:
-    class Impl;
-    std::unique_ptr<Impl> mImpl;
-};
-
-}  // namespace implementation
-}  // namespace V1_0
-}  // namespace bufferpool
-}  // namespace media
-}  // namespace hardware
-}  // namespace android
-
-#endif  // ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V1_0_ACCESSOR_H
diff --git a/codec2/vndk/bufferpool/AccessorImpl.cpp b/codec2/vndk/bufferpool/AccessorImpl.cpp
deleted file mode 100644
index 06d49c1..0000000
--- a/codec2/vndk/bufferpool/AccessorImpl.cpp
+++ /dev/null
@@ -1,543 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "BufferPoolAccessor"
-//#define LOG_NDEBUG 0
-
-#include <sys/types.h>
-#include <time.h>
-#include <unistd.h>
-#include <utils/Log.h>
-#include "AccessorImpl.h"
-#include "Connection.h"
-
-namespace android {
-namespace hardware {
-namespace media {
-namespace bufferpool {
-namespace V1_0 {
-namespace implementation {
-
-namespace {
-    static constexpr int64_t kCleanUpDurationUs = 500000; // TODO tune 0.5 sec
-    static constexpr int64_t kLogDurationUs = 5000000; // 5 secs
-
-    static constexpr size_t kMinAllocBytesForEviction = 1024*1024*15;
-    static constexpr size_t kMinBufferCountForEviction = 40;
-}
-
-// Buffer structure in bufferpool process
-struct InternalBuffer {
-    BufferId mId;
-    size_t mOwnerCount;
-    size_t mTransactionCount;
-    const std::shared_ptr<BufferPoolAllocation> mAllocation;
-    const size_t mAllocSize;
-    const std::vector<uint8_t> mConfig;
-
-    InternalBuffer(
-            BufferId id,
-            const std::shared_ptr<BufferPoolAllocation> &alloc,
-            const size_t allocSize,
-            const std::vector<uint8_t> &allocConfig)
-            : mId(id), mOwnerCount(0), mTransactionCount(0),
-            mAllocation(alloc), mAllocSize(allocSize), mConfig(allocConfig) {}
-
-    const native_handle_t *handle() {
-        return mAllocation->handle();
-    }
-};
-
-struct TransactionStatus {
-    TransactionId mId;
-    BufferId mBufferId;
-    ConnectionId mSender;
-    ConnectionId mReceiver;
-    BufferStatus mStatus;
-    int64_t mTimestampUs;
-    bool mSenderValidated;
-
-    TransactionStatus(const BufferStatusMessage &message, int64_t timestampUs) {
-        mId = message.transactionId;
-        mBufferId = message.bufferId;
-        mStatus = message.newStatus;
-        mTimestampUs = timestampUs;
-        if (mStatus == BufferStatus::TRANSFER_TO) {
-            mSender = message.connectionId;
-            mReceiver = message.targetConnectionId;
-            mSenderValidated = true;
-        } else {
-            mSender = -1LL;
-            mReceiver = message.connectionId;
-            mSenderValidated = false;
-        }
-    }
-};
-
-// Helper template methods for handling map of set.
-template<class T, class U>
-bool insert(std::map<T, std::set<U>> *mapOfSet, T key, U value) {
-    auto iter = mapOfSet->find(key);
-    if (iter == mapOfSet->end()) {
-        std::set<U> valueSet{value};
-        mapOfSet->insert(std::make_pair(key, valueSet));
-        return true;
-    } else if (iter->second.find(value)  == iter->second.end()) {
-        iter->second.insert(value);
-        return true;
-    }
-    return false;
-}
-
-template<class T, class U>
-bool erase(std::map<T, std::set<U>> *mapOfSet, T key, U value) {
-    bool ret = false;
-    auto iter = mapOfSet->find(key);
-    if (iter != mapOfSet->end()) {
-        if (iter->second.erase(value) > 0) {
-            ret = true;
-        }
-        if (iter->second.size() == 0) {
-            mapOfSet->erase(iter);
-        }
-    }
-    return ret;
-}
-
-template<class T, class U>
-bool contains(std::map<T, std::set<U>> *mapOfSet, T key, U value) {
-    auto iter = mapOfSet->find(key);
-    if (iter != mapOfSet->end()) {
-        auto setIter = iter->second.find(value);
-        return setIter != iter->second.end();
-    }
-    return false;
-}
-
-int32_t Accessor::Impl::sPid = getpid();
-uint32_t Accessor::Impl::sSeqId = time(NULL);
-
-Accessor::Impl::Impl(
-        const std::shared_ptr<BufferPoolAllocator> &allocator)
-        : mAllocator(allocator) {}
-
-Accessor::Impl::~Impl() {
-}
-
-ResultStatus Accessor::Impl::connect(
-        const sp<Accessor> &accessor, sp<Connection> *connection,
-        ConnectionId *pConnectionId, const QueueDescriptor** fmqDescPtr) {
-    sp<Connection> newConnection = new Connection();
-    ResultStatus status = ResultStatus::CRITICAL_ERROR;
-    {
-        std::lock_guard<std::mutex> lock(mBufferPool.mMutex);
-        if (newConnection) {
-            ConnectionId id = (int64_t)sPid << 32 | sSeqId;
-            status = mBufferPool.mObserver.open(id, fmqDescPtr);
-            if (status == ResultStatus::OK) {
-                newConnection->initialize(accessor, id);
-                *connection = newConnection;
-                *pConnectionId = id;
-                ++sSeqId;
-            }
-        }
-        mBufferPool.processStatusMessages();
-        mBufferPool.cleanUp();
-    }
-    return status;
-}
-
-ResultStatus Accessor::Impl::close(ConnectionId connectionId) {
-    std::lock_guard<std::mutex> lock(mBufferPool.mMutex);
-    mBufferPool.processStatusMessages();
-    mBufferPool.handleClose(connectionId);
-    mBufferPool.mObserver.close(connectionId);
-    // Since close# will be called after all works are finished, it is OK to
-    // evict unused buffers.
-    mBufferPool.cleanUp(true);
-    return ResultStatus::OK;
-}
-
-ResultStatus Accessor::Impl::allocate(
-        ConnectionId connectionId, const std::vector<uint8_t>& params,
-        BufferId *bufferId, const native_handle_t** handle) {
-    std::unique_lock<std::mutex> lock(mBufferPool.mMutex);
-    mBufferPool.processStatusMessages();
-    ResultStatus status = ResultStatus::OK;
-    if (!mBufferPool.getFreeBuffer(mAllocator, params, bufferId, handle)) {
-        lock.unlock();
-        std::shared_ptr<BufferPoolAllocation> alloc;
-        size_t allocSize;
-        status = mAllocator->allocate(params, &alloc, &allocSize);
-        lock.lock();
-        if (status == ResultStatus::OK) {
-            status = mBufferPool.addNewBuffer(alloc, allocSize, params, bufferId, handle);
-        }
-        ALOGV("create a buffer %d : %u %p",
-              status == ResultStatus::OK, *bufferId, *handle);
-    }
-    if (status == ResultStatus::OK) {
-        // TODO: handle ownBuffer failure
-        mBufferPool.handleOwnBuffer(connectionId, *bufferId);
-    }
-    mBufferPool.cleanUp();
-    return status;
-}
-
-ResultStatus Accessor::Impl::fetch(
-        ConnectionId connectionId, TransactionId transactionId,
-        BufferId bufferId, const native_handle_t** handle) {
-    std::lock_guard<std::mutex> lock(mBufferPool.mMutex);
-    mBufferPool.processStatusMessages();
-    auto found = mBufferPool.mTransactions.find(transactionId);
-    if (found != mBufferPool.mTransactions.end() &&
-            contains(&mBufferPool.mPendingTransactions,
-                     connectionId, transactionId)) {
-        if (found->second->mSenderValidated &&
-                found->second->mStatus == BufferStatus::TRANSFER_FROM &&
-                found->second->mBufferId == bufferId) {
-            found->second->mStatus = BufferStatus::TRANSFER_FETCH;
-            auto bufferIt = mBufferPool.mBuffers.find(bufferId);
-            if (bufferIt != mBufferPool.mBuffers.end()) {
-                mBufferPool.mStats.onBufferFetched();
-                *handle = bufferIt->second->handle();
-                return ResultStatus::OK;
-            }
-        }
-    }
-    mBufferPool.cleanUp();
-    return ResultStatus::CRITICAL_ERROR;
-}
-
-void Accessor::Impl::cleanUp(bool clearCache) {
-    // transaction timeout, buffer cacheing TTL handling
-    std::lock_guard<std::mutex> lock(mBufferPool.mMutex);
-    mBufferPool.processStatusMessages();
-    mBufferPool.cleanUp(clearCache);
-}
-
-Accessor::Impl::Impl::BufferPool::BufferPool()
-    : mTimestampUs(getTimestampNow()),
-      mLastCleanUpUs(mTimestampUs),
-      mLastLogUs(mTimestampUs),
-      mSeq(0) {}
-
-
-// Statistics helper
-template<typename T, typename S>
-int percentage(T base, S total) {
-    return int(total ? 0.5 + 100. * static_cast<S>(base) / total : 0);
-}
-
-Accessor::Impl::Impl::BufferPool::~BufferPool() {
-    std::lock_guard<std::mutex> lock(mMutex);
-    ALOGD("Destruction - bufferpool %p "
-          "cached: %zu/%zuM, %zu/%d%% in use; "
-          "allocs: %zu, %d%% recycled; "
-          "transfers: %zu, %d%% unfetced",
-          this, mStats.mBuffersCached, mStats.mSizeCached >> 20,
-          mStats.mBuffersInUse, percentage(mStats.mBuffersInUse, mStats.mBuffersCached),
-          mStats.mTotalAllocations, percentage(mStats.mTotalRecycles, mStats.mTotalAllocations),
-          mStats.mTotalTransfers,
-          percentage(mStats.mTotalTransfers - mStats.mTotalFetches, mStats.mTotalTransfers));
-}
-
-bool Accessor::Impl::BufferPool::handleOwnBuffer(
-        ConnectionId connectionId, BufferId bufferId) {
-
-    bool added = insert(&mUsingBuffers, connectionId, bufferId);
-    if (added) {
-        auto iter = mBuffers.find(bufferId);
-        iter->second->mOwnerCount++;
-    }
-    insert(&mUsingConnections, bufferId, connectionId);
-    return added;
-}
-
-bool Accessor::Impl::BufferPool::handleReleaseBuffer(
-        ConnectionId connectionId, BufferId bufferId) {
-    bool deleted = erase(&mUsingBuffers, connectionId, bufferId);
-    if (deleted) {
-        auto iter = mBuffers.find(bufferId);
-        iter->second->mOwnerCount--;
-        if (iter->second->mOwnerCount == 0 &&
-                iter->second->mTransactionCount == 0) {
-            mStats.onBufferUnused(iter->second->mAllocSize);
-            mFreeBuffers.insert(bufferId);
-        }
-    }
-    erase(&mUsingConnections, bufferId, connectionId);
-    ALOGV("release buffer %u : %d", bufferId, deleted);
-    return deleted;
-}
-
-bool Accessor::Impl::BufferPool::handleTransferTo(const BufferStatusMessage &message) {
-    auto completed = mCompletedTransactions.find(
-            message.transactionId);
-    if (completed != mCompletedTransactions.end()) {
-        // already completed
-        mCompletedTransactions.erase(completed);
-        return true;
-    }
-    // the buffer should exist and be owned.
-    auto bufferIter = mBuffers.find(message.bufferId);
-    if (bufferIter == mBuffers.end() ||
-            !contains(&mUsingBuffers, message.connectionId, message.bufferId)) {
-        return false;
-    }
-    auto found = mTransactions.find(message.transactionId);
-    if (found != mTransactions.end()) {
-        // transfer_from was received earlier.
-        found->second->mSender = message.connectionId;
-        found->second->mSenderValidated = true;
-        return true;
-    }
-    // TODO: verify there is target connection Id
-    mStats.onBufferSent();
-    mTransactions.insert(std::make_pair(
-            message.transactionId,
-            std::make_unique<TransactionStatus>(message, mTimestampUs)));
-    insert(&mPendingTransactions, message.targetConnectionId,
-           message.transactionId);
-    bufferIter->second->mTransactionCount++;
-    return true;
-}
-
-bool Accessor::Impl::BufferPool::handleTransferFrom(const BufferStatusMessage &message) {
-    auto found = mTransactions.find(message.transactionId);
-    if (found == mTransactions.end()) {
-        // TODO: is it feasible to check ownership here?
-        mStats.onBufferSent();
-        mTransactions.insert(std::make_pair(
-                message.transactionId,
-                std::make_unique<TransactionStatus>(message, mTimestampUs)));
-        insert(&mPendingTransactions, message.connectionId,
-               message.transactionId);
-        auto bufferIter = mBuffers.find(message.bufferId);
-        bufferIter->second->mTransactionCount++;
-    } else {
-        if (message.connectionId == found->second->mReceiver) {
-            found->second->mStatus = BufferStatus::TRANSFER_FROM;
-        }
-    }
-    return true;
-}
-
-bool Accessor::Impl::BufferPool::handleTransferResult(const BufferStatusMessage &message) {
-    auto found = mTransactions.find(message.transactionId);
-    if (found != mTransactions.end()) {
-        bool deleted = erase(&mPendingTransactions, message.connectionId,
-                             message.transactionId);
-        if (deleted) {
-            if (!found->second->mSenderValidated) {
-                mCompletedTransactions.insert(message.transactionId);
-            }
-            auto bufferIter = mBuffers.find(message.bufferId);
-            if (message.newStatus == BufferStatus::TRANSFER_OK) {
-                handleOwnBuffer(message.connectionId, message.bufferId);
-            }
-            bufferIter->second->mTransactionCount--;
-            if (bufferIter->second->mOwnerCount == 0
-                && bufferIter->second->mTransactionCount == 0) {
-                mStats.onBufferUnused(bufferIter->second->mAllocSize);
-                mFreeBuffers.insert(message.bufferId);
-            }
-            mTransactions.erase(found);
-        }
-        ALOGV("transfer finished %llu %u - %d", (unsigned long long)message.transactionId,
-              message.bufferId, deleted);
-        return deleted;
-    }
-    ALOGV("transfer not found %llu %u", (unsigned long long)message.transactionId,
-          message.bufferId);
-    return false;
-}
-
-void Accessor::Impl::BufferPool::processStatusMessages() {
-    std::vector<BufferStatusMessage> messages;
-    mObserver.getBufferStatusChanges(messages);
-    mTimestampUs = getTimestampNow();
-    for (BufferStatusMessage& message: messages) {
-        bool ret = false;
-        switch (message.newStatus) {
-            case BufferStatus::NOT_USED:
-                ret = handleReleaseBuffer(
-                        message.connectionId, message.bufferId);
-                break;
-            case BufferStatus::USED:
-                // not happening
-                break;
-            case BufferStatus::TRANSFER_TO:
-                ret = handleTransferTo(message);
-                break;
-            case BufferStatus::TRANSFER_FROM:
-                ret = handleTransferFrom(message);
-                break;
-            case BufferStatus::TRANSFER_TIMEOUT:
-                // TODO
-                break;
-            case BufferStatus::TRANSFER_LOST:
-                // TODO
-                break;
-            case BufferStatus::TRANSFER_FETCH:
-                // not happening
-                break;
-            case BufferStatus::TRANSFER_OK:
-            case BufferStatus::TRANSFER_ERROR:
-                ret = handleTransferResult(message);
-                break;
-        }
-        if (ret == false) {
-            ALOGW("buffer status message processing failure - message : %d connection : %lld",
-                  message.newStatus, (long long)message.connectionId);
-        }
-    }
-    messages.clear();
-}
-
-bool Accessor::Impl::BufferPool::handleClose(ConnectionId connectionId) {
-    // Cleaning buffers
-    auto buffers = mUsingBuffers.find(connectionId);
-    if (buffers != mUsingBuffers.end()) {
-        for (const BufferId& bufferId : buffers->second) {
-            bool deleted = erase(&mUsingConnections, bufferId, connectionId);
-            if (deleted) {
-                auto bufferIter = mBuffers.find(bufferId);
-                bufferIter->second->mOwnerCount--;
-                if (bufferIter->second->mOwnerCount == 0 &&
-                        bufferIter->second->mTransactionCount == 0) {
-                    // TODO: handle freebuffer insert fail
-                    mStats.onBufferUnused(bufferIter->second->mAllocSize);
-                    mFreeBuffers.insert(bufferId);
-                }
-            }
-        }
-        mUsingBuffers.erase(buffers);
-    }
-
-    // Cleaning transactions
-    auto pending = mPendingTransactions.find(connectionId);
-    if (pending != mPendingTransactions.end()) {
-        for (const TransactionId& transactionId : pending->second) {
-            auto iter = mTransactions.find(transactionId);
-            if (iter != mTransactions.end()) {
-                if (!iter->second->mSenderValidated) {
-                    mCompletedTransactions.insert(transactionId);
-                }
-                BufferId bufferId = iter->second->mBufferId;
-                auto bufferIter = mBuffers.find(bufferId);
-                bufferIter->second->mTransactionCount--;
-                if (bufferIter->second->mOwnerCount == 0 &&
-                    bufferIter->second->mTransactionCount == 0) {
-                    // TODO: handle freebuffer insert fail
-                    mStats.onBufferUnused(bufferIter->second->mAllocSize);
-                    mFreeBuffers.insert(bufferId);
-                }
-                mTransactions.erase(iter);
-            }
-        }
-    }
-    return true;
-}
-
-bool Accessor::Impl::BufferPool::getFreeBuffer(
-        const std::shared_ptr<BufferPoolAllocator> &allocator,
-        const std::vector<uint8_t> &params, BufferId *pId,
-        const native_handle_t** handle) {
-    auto bufferIt = mFreeBuffers.begin();
-    for (;bufferIt != mFreeBuffers.end(); ++bufferIt) {
-        BufferId bufferId = *bufferIt;
-        if (allocator->compatible(params, mBuffers[bufferId]->mConfig)) {
-            break;
-        }
-    }
-    if (bufferIt != mFreeBuffers.end()) {
-        BufferId id = *bufferIt;
-        mFreeBuffers.erase(bufferIt);
-        mStats.onBufferRecycled(mBuffers[id]->mAllocSize);
-        *handle = mBuffers[id]->handle();
-        *pId = id;
-        ALOGV("recycle a buffer %u %p", id, *handle);
-        return true;
-    }
-    return false;
-}
-
-ResultStatus Accessor::Impl::BufferPool::addNewBuffer(
-        const std::shared_ptr<BufferPoolAllocation> &alloc,
-        const size_t allocSize,
-        const std::vector<uint8_t> &params,
-        BufferId *pId,
-        const native_handle_t** handle) {
-
-    BufferId bufferId = mSeq++;
-    if (mSeq == Connection::SYNC_BUFFERID) {
-        mSeq = 0;
-    }
-    std::unique_ptr<InternalBuffer> buffer =
-            std::make_unique<InternalBuffer>(
-                    bufferId, alloc, allocSize, params);
-    if (buffer) {
-        auto res = mBuffers.insert(std::make_pair(
-                bufferId, std::move(buffer)));
-        if (res.second) {
-            mStats.onBufferAllocated(allocSize);
-            *handle = alloc->handle();
-            *pId = bufferId;
-            return ResultStatus::OK;
-        }
-    }
-    return ResultStatus::NO_MEMORY;
-}
-
-void Accessor::Impl::BufferPool::cleanUp(bool clearCache) {
-    if (clearCache || mTimestampUs > mLastCleanUpUs + kCleanUpDurationUs) {
-        mLastCleanUpUs = mTimestampUs;
-        if (mTimestampUs > mLastLogUs + kLogDurationUs) {
-            mLastLogUs = mTimestampUs;
-            ALOGD("bufferpool %p : %zu(%zu size) total buffers - "
-                  "%zu(%zu size) used buffers - %zu/%zu (recycle/alloc) - "
-                  "%zu/%zu (fetch/transfer)",
-                  this, mStats.mBuffersCached, mStats.mSizeCached,
-                  mStats.mBuffersInUse, mStats.mSizeInUse,
-                  mStats.mTotalRecycles, mStats.mTotalAllocations,
-                  mStats.mTotalFetches, mStats.mTotalTransfers);
-        }
-        for (auto freeIt = mFreeBuffers.begin(); freeIt != mFreeBuffers.end();) {
-            if (!clearCache && mStats.mSizeCached < kMinAllocBytesForEviction
-                    && mBuffers.size() < kMinBufferCountForEviction) {
-                break;
-            }
-            auto it = mBuffers.find(*freeIt);
-            if (it != mBuffers.end() &&
-                    it->second->mOwnerCount == 0 && it->second->mTransactionCount == 0) {
-                mStats.onBufferEvicted(it->second->mAllocSize);
-                mBuffers.erase(it);
-                freeIt = mFreeBuffers.erase(freeIt);
-            } else {
-                ++freeIt;
-                ALOGW("bufferpool inconsistent!");
-            }
-        }
-    }
-}
-
-}  // namespace implementation
-}  // namespace V1_0
-}  // namespace bufferpool
-}  // namespace media
-}  // namespace hardware
-}  // namespace android
diff --git a/codec2/vndk/bufferpool/AccessorImpl.h b/codec2/vndk/bufferpool/AccessorImpl.h
deleted file mode 100644
index c04dbf3..0000000
--- a/codec2/vndk/bufferpool/AccessorImpl.h
+++ /dev/null
@@ -1,300 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V1_0_ACCESSORIMPL_H
-#define ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V1_0_ACCESSORIMPL_H
-
-#include <map>
-#include <set>
-#include "Accessor.h"
-
-namespace android {
-namespace hardware {
-namespace media {
-namespace bufferpool {
-namespace V1_0 {
-namespace implementation {
-
-struct InternalBuffer;
-struct TransactionStatus;
-
-/**
- * An implementation of a buffer pool accessor(or a buffer pool implementation.) */
-class Accessor::Impl {
-public:
-    Impl(const std::shared_ptr<BufferPoolAllocator> &allocator);
-
-    ~Impl();
-
-    ResultStatus connect(
-            const sp<Accessor> &accessor, sp<Connection> *connection,
-            ConnectionId *pConnectionId, const QueueDescriptor** fmqDescPtr);
-
-    ResultStatus close(ConnectionId connectionId);
-
-    ResultStatus allocate(ConnectionId connectionId,
-                          const std::vector<uint8_t>& params,
-                          BufferId *bufferId,
-                          const native_handle_t** handle);
-
-    ResultStatus fetch(ConnectionId connectionId,
-                       TransactionId transactionId,
-                       BufferId bufferId,
-                       const native_handle_t** handle);
-
-    void cleanUp(bool clearCache);
-
-private:
-    // ConnectionId = pid : (timestamp_created + seqId)
-    // in order to guarantee uniqueness for each connection
-    static uint32_t sSeqId;
-    static int32_t sPid;
-
-    const std::shared_ptr<BufferPoolAllocator> mAllocator;
-
-    /**
-     * Buffer pool implementation.
-     *
-     * Handles buffer status messages. Handles buffer allocation/recycling.
-     * Handles buffer transfer between buffer pool clients.
-     */
-    struct BufferPool {
-    private:
-        std::mutex mMutex;
-        int64_t mTimestampUs;
-        int64_t mLastCleanUpUs;
-        int64_t mLastLogUs;
-        BufferId mSeq;
-        BufferStatusObserver mObserver;
-
-        std::map<ConnectionId, std::set<BufferId>> mUsingBuffers;
-        std::map<BufferId, std::set<ConnectionId>> mUsingConnections;
-
-        std::map<ConnectionId, std::set<TransactionId>> mPendingTransactions;
-        // Transactions completed before TRANSFER_TO message arrival.
-        // Fetch does not occur for the transactions.
-        // Only transaction id is kept for the transactions in short duration.
-        std::set<TransactionId> mCompletedTransactions;
-        // Currently active(pending) transations' status & information.
-        std::map<TransactionId, std::unique_ptr<TransactionStatus>>
-                mTransactions;
-
-        std::map<BufferId, std::unique_ptr<InternalBuffer>> mBuffers;
-        std::set<BufferId> mFreeBuffers;
-
-        /// Buffer pool statistics which tracks allocation and transfer statistics.
-        struct Stats {
-            /// Total size of allocations which are used or available to use.
-            /// (bytes or pixels)
-            size_t mSizeCached;
-            /// # of cached buffers which are used or available to use.
-            size_t mBuffersCached;
-            /// Total size of allocations which are currently used. (bytes or pixels)
-            size_t mSizeInUse;
-            /// # of currently used buffers
-            size_t mBuffersInUse;
-
-            /// # of allocations called on bufferpool. (# of fetched from BlockPool)
-            size_t mTotalAllocations;
-            /// # of allocations that were served from the cache.
-            /// (# of allocator alloc prevented)
-            size_t mTotalRecycles;
-            /// # of buffer transfers initiated.
-            size_t mTotalTransfers;
-            /// # of transfers that had to be fetched.
-            size_t mTotalFetches;
-
-            Stats()
-                : mSizeCached(0), mBuffersCached(0), mSizeInUse(0), mBuffersInUse(0),
-                  mTotalAllocations(0), mTotalRecycles(0), mTotalTransfers(0), mTotalFetches(0) {}
-
-            /// A new buffer is allocated on an allocation request.
-            void onBufferAllocated(size_t allocSize) {
-                mSizeCached += allocSize;
-                mBuffersCached++;
-
-                mSizeInUse += allocSize;
-                mBuffersInUse++;
-
-                mTotalAllocations++;
-            }
-
-            /// A buffer is evicted and destroyed.
-            void onBufferEvicted(size_t allocSize) {
-                mSizeCached -= allocSize;
-                mBuffersCached--;
-            }
-
-            /// A buffer is recycled on an allocation request.
-            void onBufferRecycled(size_t allocSize) {
-                mSizeInUse += allocSize;
-                mBuffersInUse++;
-
-                mTotalAllocations++;
-                mTotalRecycles++;
-            }
-
-            /// A buffer is available to be recycled.
-            void onBufferUnused(size_t allocSize) {
-                mSizeInUse -= allocSize;
-                mBuffersInUse--;
-            }
-
-            /// A buffer transfer is initiated.
-            void onBufferSent() {
-                mTotalTransfers++;
-            }
-
-            /// A buffer fetch is invoked by a buffer transfer.
-            void onBufferFetched() {
-                mTotalFetches++;
-            }
-        } mStats;
-
-    public:
-        /** Creates a buffer pool. */
-        BufferPool();
-
-        /** Destroys a buffer pool. */
-        ~BufferPool();
-
-        /**
-         * Processes all pending buffer status messages, and returns the result.
-         * Each status message is handled by methods with 'handle' prefix.
-         */
-        void processStatusMessages();
-
-        /**
-         * Handles a buffer being owned by a connection.
-         *
-         * @param connectionId  the id of the buffer owning connection.
-         * @param bufferId      the id of the buffer.
-         *
-         * @return {@code true} when the buffer is owned,
-         *         {@code false} otherwise.
-         */
-        bool handleOwnBuffer(ConnectionId connectionId, BufferId bufferId);
-
-        /**
-         * Handles a buffer being released by a connection.
-         *
-         * @param connectionId  the id of the buffer owning connection.
-         * @param bufferId      the id of the buffer.
-         *
-         * @return {@code true} when the buffer ownership is released,
-         *         {@code false} otherwise.
-         */
-        bool handleReleaseBuffer(ConnectionId connectionId, BufferId bufferId);
-
-        /**
-         * Handles a transfer transaction start message from the sender.
-         *
-         * @param message   a buffer status message for the transaction.
-         *
-         * @result {@code true} when transfer_to message is acknowledged,
-         *         {@code false} otherwise.
-         */
-        bool handleTransferTo(const BufferStatusMessage &message);
-
-        /**
-         * Handles a transfer transaction being acked by the receiver.
-         *
-         * @param message   a buffer status message for the transaction.
-         *
-         * @result {@code true} when transfer_from message is acknowledged,
-         *         {@code false} otherwise.
-         */
-        bool handleTransferFrom(const BufferStatusMessage &message);
-
-        /**
-         * Handles a transfer transaction result message from the receiver.
-         *
-         * @param message   a buffer status message for the transaction.
-         *
-         * @result {@code true} when the exisitng transaction is finished,
-         *         {@code false} otherwise.
-         */
-        bool handleTransferResult(const BufferStatusMessage &message);
-
-        /**
-         * Handles a connection being closed, and returns the result. All the
-         * buffers and transactions owned by the connection will be cleaned up.
-         * The related FMQ will be cleaned up too.
-         *
-         * @param connectionId  the id of the connection.
-         *
-         * @result {@code true} when the connection existed,
-         *         {@code false} otherwise.
-         */
-        bool handleClose(ConnectionId connectionId);
-
-        /**
-         * Recycles a existing free buffer if it is possible.
-         *
-         * @param allocator the buffer allocator
-         * @param params    the allocation parameters.
-         * @param pId       the id of the recycled buffer.
-         * @param handle    the native handle of the recycled buffer.
-         *
-         * @return {@code true} when a buffer is recycled, {@code false}
-         *         otherwise.
-         */
-        bool getFreeBuffer(
-                const std::shared_ptr<BufferPoolAllocator> &allocator,
-                const std::vector<uint8_t> &params,
-                BufferId *pId, const native_handle_t **handle);
-
-        /**
-         * Adds a newly allocated buffer to bufferpool.
-         *
-         * @param alloc     the newly allocated buffer.
-         * @param allocSize the size of the newly allocated buffer.
-         * @param params    the allocation parameters.
-         * @param pId       the buffer id for the newly allocated buffer.
-         * @param handle    the native handle for the newly allocated buffer.
-         *
-         * @return OK when an allocation is successfully allocated.
-         *         NO_MEMORY when there is no memory.
-         *         CRITICAL_ERROR otherwise.
-         */
-        ResultStatus addNewBuffer(
-                const std::shared_ptr<BufferPoolAllocation> &alloc,
-                const size_t allocSize,
-                const std::vector<uint8_t> &params,
-                BufferId *pId,
-                const native_handle_t **handle);
-
-        /**
-         * Processes pending buffer status messages and performs periodic cache
-         * cleaning.
-         *
-         * @param clearCache    if clearCache is true, it frees all buffers
-         *                      waiting to be recycled.
-         */
-        void cleanUp(bool clearCache = false);
-
-        friend class Accessor::Impl;
-    } mBufferPool;
-};
-
-}  // namespace implementation
-}  // namespace V1_0
-}  // namespace ufferpool
-}  // namespace media
-}  // namespace hardware
-}  // namespace android
-
-#endif  // ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V1_0_ACCESSORIMPL_H
diff --git a/codec2/vndk/bufferpool/Android.bp b/codec2/vndk/bufferpool/Android.bp
deleted file mode 100644
index c7ea70f..0000000
--- a/codec2/vndk/bufferpool/Android.bp
+++ /dev/null
@@ -1,29 +0,0 @@
-cc_library {
-    name: "libstagefright_bufferpool@1.0",
-    vendor_available: true,
-    srcs: [
-        "Accessor.cpp",
-        "AccessorImpl.cpp",
-        "BufferPoolClient.cpp",
-        "BufferStatus.cpp",
-        "ClientManager.cpp",
-        "Connection.cpp",
-    ],
-    export_include_dirs: [
-        "include",
-    ],
-    shared_libs: [
-        "libcutils",
-        "libfmq",
-        "libhidlbase",
-        "libhwbinder",
-        "libhidltransport",
-        "liblog",
-        "libutils",
-        "android.hardware.media.bufferpool@1.0",
-    ],
-    export_shared_lib_headers: [
-        "libfmq",
-        "android.hardware.media.bufferpool@1.0",
-    ],
-}
diff --git a/codec2/vndk/bufferpool/BufferPoolClient.cpp b/codec2/vndk/bufferpool/BufferPoolClient.cpp
deleted file mode 100644
index 3626004..0000000
--- a/codec2/vndk/bufferpool/BufferPoolClient.cpp
+++ /dev/null
@@ -1,708 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "BufferPoolClient"
-//#define LOG_NDEBUG 0
-
-#include <thread>
-#include <utils/Log.h>
-#include "BufferPoolClient.h"
-#include "Connection.h"
-
-namespace android {
-namespace hardware {
-namespace media {
-namespace bufferpool {
-namespace V1_0 {
-namespace implementation {
-
-static constexpr int64_t kReceiveTimeoutUs = 1000000; // 100ms
-static constexpr int kPostMaxRetry = 3;
-static constexpr int kCacheTtlUs = 1000000; // TODO: tune
-
-class BufferPoolClient::Impl
-        : public std::enable_shared_from_this<BufferPoolClient::Impl> {
-public:
-    explicit Impl(const sp<Accessor> &accessor);
-
-    explicit Impl(const sp<IAccessor> &accessor);
-
-    bool isValid() {
-        return mValid;
-    }
-
-    bool isLocal() {
-        return mValid && mLocal;
-    }
-
-    ConnectionId getConnectionId() {
-        return mConnectionId;
-    }
-
-    sp<IAccessor> &getAccessor() {
-        return mAccessor;
-    }
-
-    bool isActive(int64_t *lastTransactionUs, bool clearCache);
-
-    ResultStatus allocate(const std::vector<uint8_t> &params,
-                          native_handle_t **handle,
-                          std::shared_ptr<BufferPoolData> *buffer);
-
-    ResultStatus receive(
-            TransactionId transactionId, BufferId bufferId,
-            int64_t timestampUs,
-            native_handle_t **handle, std::shared_ptr<BufferPoolData> *buffer);
-
-    void postBufferRelease(BufferId bufferId);
-
-    bool postSend(
-            BufferId bufferId, ConnectionId receiver,
-            TransactionId *transactionId, int64_t *timestampUs);
-private:
-
-    bool postReceive(
-            BufferId bufferId, TransactionId transactionId,
-            int64_t timestampUs);
-
-    bool postReceiveResult(
-            BufferId bufferId, TransactionId transactionId, bool result, bool *needsSync);
-
-    void trySyncFromRemote();
-
-    bool syncReleased();
-
-    void evictCaches(bool clearCache = false);
-
-    ResultStatus allocateBufferHandle(
-            const std::vector<uint8_t>& params, BufferId *bufferId,
-            native_handle_t **handle);
-
-    ResultStatus fetchBufferHandle(
-            TransactionId transactionId, BufferId bufferId,
-            native_handle_t **handle);
-
-    struct BlockPoolDataDtor;
-    struct ClientBuffer;
-
-    bool mLocal;
-    bool mValid;
-    sp<IAccessor> mAccessor;
-    sp<Connection> mLocalConnection;
-    sp<IConnection> mRemoteConnection;
-    uint32_t mSeqId;
-    ConnectionId mConnectionId;
-    int64_t mLastEvictCacheUs;
-
-    // CachedBuffers
-    struct BufferCache {
-        std::mutex mLock;
-        bool mCreating;
-        std::condition_variable mCreateCv;
-        std::map<BufferId, std::unique_ptr<ClientBuffer>> mBuffers;
-        int mActive;
-        int64_t mLastChangeUs;
-
-        BufferCache() : mCreating(false), mActive(0), mLastChangeUs(getTimestampNow()) {}
-
-        void incActive_l() {
-            ++mActive;
-            mLastChangeUs = getTimestampNow();
-        }
-
-        void decActive_l() {
-            --mActive;
-            mLastChangeUs = getTimestampNow();
-        }
-    } mCache;
-
-    // FMQ - release notifier
-    struct {
-        std::mutex mLock;
-        // TODO: use only one list?(using one list may dealy sending messages?)
-        std::list<BufferId> mReleasingIds;
-        std::list<BufferId> mReleasedIds;
-        std::unique_ptr<BufferStatusChannel> mStatusChannel;
-    } mReleasing;
-
-    // This lock is held during synchronization from remote side.
-    // In order to minimize remote calls and locking durtaion, this lock is held
-    // by best effort approach using try_lock().
-    std::mutex mRemoteSyncLock;
-};
-
-struct BufferPoolClient::Impl::BlockPoolDataDtor {
-    BlockPoolDataDtor(const std::shared_ptr<BufferPoolClient::Impl> &impl)
-            : mImpl(impl) {}
-
-    void operator()(BufferPoolData *buffer) {
-        BufferId id = buffer->mId;
-        delete buffer;
-
-        auto impl = mImpl.lock();
-        if (impl && impl->isValid()) {
-            impl->postBufferRelease(id);
-        }
-    }
-    const std::weak_ptr<BufferPoolClient::Impl> mImpl;
-};
-
-struct BufferPoolClient::Impl::ClientBuffer {
-private:
-    bool mInvalidated; // TODO: implement
-    int64_t mExpireUs;
-    bool mHasCache;
-    ConnectionId mConnectionId;
-    BufferId mId;
-    native_handle_t *mHandle;
-    std::weak_ptr<BufferPoolData> mCache;
-
-    void updateExpire() {
-        mExpireUs = getTimestampNow() + kCacheTtlUs;
-    }
-
-public:
-    ClientBuffer(
-            ConnectionId connectionId, BufferId id, native_handle_t *handle)
-            : mInvalidated(false), mHasCache(false),
-              mConnectionId(connectionId), mId(id), mHandle(handle) {
-        (void)mInvalidated;
-        mExpireUs = getTimestampNow() + kCacheTtlUs;
-    }
-
-    ~ClientBuffer() {
-        if (mHandle) {
-            native_handle_close(mHandle);
-            native_handle_delete(mHandle);
-        }
-    }
-
-    bool expire() const {
-        int64_t now = getTimestampNow();
-        return now >= mExpireUs;
-    }
-
-    bool hasCache() const {
-        return mHasCache;
-    }
-
-    std::shared_ptr<BufferPoolData> fetchCache(native_handle_t **pHandle) {
-        if (mHasCache) {
-            std::shared_ptr<BufferPoolData> cache = mCache.lock();
-            if (cache) {
-                *pHandle = mHandle;
-            }
-            return cache;
-        }
-        return nullptr;
-    }
-
-    std::shared_ptr<BufferPoolData> createCache(
-            const std::shared_ptr<BufferPoolClient::Impl> &impl,
-            native_handle_t **pHandle) {
-        if (!mHasCache) {
-            // Allocates a raw ptr in order to avoid sending #postBufferRelease
-            // from deleter, in case of native_handle_clone failure.
-            BufferPoolData *ptr = new BufferPoolData(mConnectionId, mId);
-            if (ptr) {
-                std::shared_ptr<BufferPoolData> cache(ptr, BlockPoolDataDtor(impl));
-                if (cache) {
-                    mCache = cache;
-                    mHasCache = true;
-                    *pHandle = mHandle;
-                    return cache;
-                }
-            }
-            if (ptr) {
-                delete ptr;
-            }
-        }
-        return nullptr;
-    }
-
-    bool onCacheRelease() {
-        if (mHasCache) {
-            // TODO: verify mCache is not valid;
-            updateExpire();
-            mHasCache = false;
-            return true;
-        }
-        return false;
-    }
-};
-
-BufferPoolClient::Impl::Impl(const sp<Accessor> &accessor)
-    : mLocal(true), mValid(false), mAccessor(accessor), mSeqId(0),
-      mLastEvictCacheUs(getTimestampNow()) {
-    const QueueDescriptor *fmqDesc;
-    ResultStatus status = accessor->connect(
-            &mLocalConnection, &mConnectionId, &fmqDesc, true);
-    if (status == ResultStatus::OK) {
-        mReleasing.mStatusChannel =
-                std::make_unique<BufferStatusChannel>(*fmqDesc);
-        mValid = mReleasing.mStatusChannel &&
-                mReleasing.mStatusChannel->isValid();
-    }
-}
-
-BufferPoolClient::Impl::Impl(const sp<IAccessor> &accessor)
-    : mLocal(false), mValid(false), mAccessor(accessor), mSeqId(0),
-      mLastEvictCacheUs(getTimestampNow()) {
-    bool valid = false;
-    sp<IConnection>& outConnection = mRemoteConnection;
-    ConnectionId& id = mConnectionId;
-    std::unique_ptr<BufferStatusChannel>& outChannel =
-            mReleasing.mStatusChannel;
-    Return<void> transResult = accessor->connect(
-            [&valid, &outConnection, &id, &outChannel]
-            (ResultStatus status, sp<IConnection> connection,
-             ConnectionId connectionId, const QueueDescriptor& desc) {
-                if (status == ResultStatus::OK) {
-                    outConnection = connection;
-                    id = connectionId;
-                    outChannel = std::make_unique<BufferStatusChannel>(desc);
-                    if (outChannel && outChannel->isValid()) {
-                        valid = true;
-                    }
-                }
-            });
-    mValid = transResult.isOk() && valid;
-}
-
-bool BufferPoolClient::Impl::isActive(int64_t *lastTransactionUs, bool clearCache) {
-    bool active = false;
-    {
-        std::lock_guard<std::mutex> lock(mCache.mLock);
-        syncReleased();
-        evictCaches(clearCache);
-        *lastTransactionUs = mCache.mLastChangeUs;
-        active = mCache.mActive > 0;
-    }
-    if (mValid && mLocal && mLocalConnection) {
-        mLocalConnection->cleanUp(clearCache);
-        return true;
-    }
-    return active;
-}
-
-ResultStatus BufferPoolClient::Impl::allocate(
-        const std::vector<uint8_t> &params,
-        native_handle_t **pHandle,
-        std::shared_ptr<BufferPoolData> *buffer) {
-    if (!mLocal || !mLocalConnection || !mValid) {
-        return ResultStatus::CRITICAL_ERROR;
-    }
-    BufferId bufferId;
-    native_handle_t *handle = NULL;
-    buffer->reset();
-    ResultStatus status = allocateBufferHandle(params, &bufferId, &handle);
-    if (status == ResultStatus::OK) {
-        if (handle) {
-            std::unique_lock<std::mutex> lock(mCache.mLock);
-            syncReleased();
-            evictCaches();
-            auto cacheIt = mCache.mBuffers.find(bufferId);
-            if (cacheIt != mCache.mBuffers.end()) {
-                // TODO: verify it is recycled. (not having active ref)
-                mCache.mBuffers.erase(cacheIt);
-            }
-            auto clientBuffer = std::make_unique<ClientBuffer>(
-                    mConnectionId, bufferId, handle);
-            if (clientBuffer) {
-                auto result = mCache.mBuffers.insert(std::make_pair(
-                        bufferId, std::move(clientBuffer)));
-                if (result.second) {
-                    *buffer = result.first->second->createCache(
-                            shared_from_this(), pHandle);
-                    if (*buffer) {
-                        mCache.incActive_l();
-                    }
-                }
-            }
-        }
-        if (!*buffer) {
-            ALOGV("client cache creation failure %d: %lld",
-                  handle != NULL, (long long)mConnectionId);
-            status = ResultStatus::NO_MEMORY;
-            postBufferRelease(bufferId);
-        }
-    }
-    return status;
-}
-
-ResultStatus BufferPoolClient::Impl::receive(
-        TransactionId transactionId, BufferId bufferId, int64_t timestampUs,
-        native_handle_t **pHandle,
-        std::shared_ptr<BufferPoolData> *buffer) {
-    if (!mValid) {
-        return ResultStatus::CRITICAL_ERROR;
-    }
-    if (timestampUs != 0) {
-        timestampUs += kReceiveTimeoutUs;
-    }
-    if (!postReceive(bufferId, transactionId, timestampUs)) {
-        return ResultStatus::CRITICAL_ERROR;
-    }
-    ResultStatus status = ResultStatus::CRITICAL_ERROR;
-    buffer->reset();
-    while(1) {
-        std::unique_lock<std::mutex> lock(mCache.mLock);
-        syncReleased();
-        evictCaches();
-        auto cacheIt = mCache.mBuffers.find(bufferId);
-        if (cacheIt != mCache.mBuffers.end()) {
-            if (cacheIt->second->hasCache()) {
-                *buffer = cacheIt->second->fetchCache(pHandle);
-                if (!*buffer) {
-                    // check transfer time_out
-                    lock.unlock();
-                    std::this_thread::yield();
-                    continue;
-                }
-                ALOGV("client receive from reference %lld", (long long)mConnectionId);
-                break;
-            } else {
-                *buffer = cacheIt->second->createCache(shared_from_this(), pHandle);
-                if (*buffer) {
-                    mCache.incActive_l();
-                }
-                ALOGV("client receive from cache %lld", (long long)mConnectionId);
-                break;
-            }
-        } else {
-            if (!mCache.mCreating) {
-                mCache.mCreating = true;
-                lock.unlock();
-                native_handle_t* handle = NULL;
-                status = fetchBufferHandle(transactionId, bufferId, &handle);
-                lock.lock();
-                if (status == ResultStatus::OK) {
-                    if (handle) {
-                        auto clientBuffer = std::make_unique<ClientBuffer>(
-                                mConnectionId, bufferId, handle);
-                        if (clientBuffer) {
-                            auto result = mCache.mBuffers.insert(
-                                    std::make_pair(bufferId, std::move(
-                                            clientBuffer)));
-                            if (result.second) {
-                                *buffer = result.first->second->createCache(
-                                        shared_from_this(), pHandle);
-                                if (*buffer) {
-                                    mCache.incActive_l();
-                                }
-                            }
-                        }
-                    }
-                    if (!*buffer) {
-                        status = ResultStatus::NO_MEMORY;
-                    }
-                }
-                mCache.mCreating = false;
-                lock.unlock();
-                mCache.mCreateCv.notify_all();
-                break;
-            }
-            mCache.mCreateCv.wait(lock);
-        }
-    }
-    bool needsSync = false;
-    bool posted = postReceiveResult(bufferId, transactionId,
-                                      *buffer ? true : false, &needsSync);
-    ALOGV("client receive %lld - %u : %s (%d)", (long long)mConnectionId, bufferId,
-          *buffer ? "ok" : "fail", posted);
-    if (mValid && mLocal && mLocalConnection) {
-        mLocalConnection->cleanUp(false);
-    }
-    if (needsSync && mRemoteConnection) {
-        trySyncFromRemote();
-    }
-    if (*buffer) {
-        if (!posted) {
-            buffer->reset();
-            return ResultStatus::CRITICAL_ERROR;
-        }
-        return ResultStatus::OK;
-    }
-    return status;
-}
-
-
-void BufferPoolClient::Impl::postBufferRelease(BufferId bufferId) {
-    std::lock_guard<std::mutex> lock(mReleasing.mLock);
-    mReleasing.mReleasingIds.push_back(bufferId);
-    mReleasing.mStatusChannel->postBufferRelease(
-            mConnectionId, mReleasing.mReleasingIds, mReleasing.mReleasedIds);
-}
-
-// TODO: revise ad-hoc posting data structure
-bool BufferPoolClient::Impl::postSend(
-        BufferId bufferId, ConnectionId receiver,
-        TransactionId *transactionId, int64_t *timestampUs) {
-    bool ret = false;
-    bool needsSync = false;
-    {
-        std::lock_guard<std::mutex> lock(mReleasing.mLock);
-        *timestampUs = getTimestampNow();
-        *transactionId = (mConnectionId << 32) | mSeqId++;
-        // TODO: retry, add timeout, target?
-        ret =  mReleasing.mStatusChannel->postBufferStatusMessage(
-                *transactionId, bufferId, BufferStatus::TRANSFER_TO, mConnectionId,
-                receiver, mReleasing.mReleasingIds, mReleasing.mReleasedIds);
-        needsSync = !mLocal && mReleasing.mStatusChannel->needsSync();
-    }
-    if (mValid && mLocal && mLocalConnection) {
-        mLocalConnection->cleanUp(false);
-    }
-    if (needsSync && mRemoteConnection) {
-        trySyncFromRemote();
-    }
-    return ret;
-}
-
-bool BufferPoolClient::Impl::postReceive(
-        BufferId bufferId, TransactionId transactionId, int64_t timestampUs) {
-    for (int i = 0; i < kPostMaxRetry; ++i) {
-        std::unique_lock<std::mutex> lock(mReleasing.mLock);
-        int64_t now = getTimestampNow();
-        if (timestampUs == 0 || now < timestampUs) {
-            bool result = mReleasing.mStatusChannel->postBufferStatusMessage(
-                    transactionId, bufferId, BufferStatus::TRANSFER_FROM,
-                    mConnectionId, -1, mReleasing.mReleasingIds,
-                    mReleasing.mReleasedIds);
-            if (result) {
-                return true;
-            }
-            lock.unlock();
-            std::this_thread::yield();
-        } else {
-            mReleasing.mStatusChannel->postBufferStatusMessage(
-                    transactionId, bufferId, BufferStatus::TRANSFER_TIMEOUT,
-                    mConnectionId, -1, mReleasing.mReleasingIds,
-                    mReleasing.mReleasedIds);
-            return false;
-        }
-    }
-    return false;
-}
-
-bool BufferPoolClient::Impl::postReceiveResult(
-        BufferId bufferId, TransactionId transactionId, bool result, bool *needsSync) {
-    std::lock_guard<std::mutex> lock(mReleasing.mLock);
-    // TODO: retry, add timeout
-    bool ret = mReleasing.mStatusChannel->postBufferStatusMessage(
-            transactionId, bufferId,
-            result ? BufferStatus::TRANSFER_OK : BufferStatus::TRANSFER_ERROR,
-            mConnectionId, -1, mReleasing.mReleasingIds,
-            mReleasing.mReleasedIds);
-    *needsSync = !mLocal && mReleasing.mStatusChannel->needsSync();
-    return ret;
-}
-
-void BufferPoolClient::Impl::trySyncFromRemote() {
-    if (mRemoteSyncLock.try_lock()) {
-        bool needsSync = false;
-        {
-            std::lock_guard<std::mutex> lock(mReleasing.mLock);
-            needsSync = mReleasing.mStatusChannel->needsSync();
-        }
-        if (needsSync) {
-            TransactionId transactionId = (mConnectionId << 32);
-            BufferId bufferId = Connection::SYNC_BUFFERID;
-            Return<void> transResult = mRemoteConnection->fetch(
-                    transactionId, bufferId,
-                    []
-                    (ResultStatus outStatus, Buffer outBuffer) {
-                        (void) outStatus;
-                        (void) outBuffer;
-                    });
-        }
-        mRemoteSyncLock.unlock();
-    }
-}
-
-// should have mCache.mLock
-bool BufferPoolClient::Impl::syncReleased() {
-    std::lock_guard<std::mutex> lock(mReleasing.mLock);
-    if (mReleasing.mReleasingIds.size() > 0) {
-        mReleasing.mStatusChannel->postBufferRelease(
-                mConnectionId, mReleasing.mReleasingIds,
-                mReleasing.mReleasedIds);
-    }
-    if (mReleasing.mReleasedIds.size() > 0) {
-        for (BufferId& id: mReleasing.mReleasedIds) {
-            ALOGV("client release buffer %lld - %u", (long long)mConnectionId, id);
-            auto found = mCache.mBuffers.find(id);
-            if (found != mCache.mBuffers.end()) {
-                if (found->second->onCacheRelease()) {
-                    mCache.decActive_l();
-                } else {
-                    // should not happen!
-                    ALOGW("client %lld cache release status inconsitent!",
-                          (long long)mConnectionId);
-                }
-            } else {
-                // should not happen!
-                ALOGW("client %lld cache status inconsitent!", (long long)mConnectionId);
-            }
-        }
-        mReleasing.mReleasedIds.clear();
-        return true;
-    }
-    return false;
-}
-
-// should have mCache.mLock
-void BufferPoolClient::Impl::evictCaches(bool clearCache) {
-    int64_t now = getTimestampNow();
-    if (now >= mLastEvictCacheUs + kCacheTtlUs || clearCache) {
-        size_t evicted = 0;
-        for (auto it = mCache.mBuffers.begin(); it != mCache.mBuffers.end();) {
-            if (!it->second->hasCache() && (it->second->expire() || clearCache)) {
-                it = mCache.mBuffers.erase(it);
-                ++evicted;
-            } else {
-                ++it;
-            }
-        }
-        ALOGV("cache count %lld : total %zu, active %d, evicted %zu",
-              (long long)mConnectionId, mCache.mBuffers.size(), mCache.mActive, evicted);
-        mLastEvictCacheUs = now;
-    }
-}
-
-ResultStatus BufferPoolClient::Impl::allocateBufferHandle(
-        const std::vector<uint8_t>& params, BufferId *bufferId,
-        native_handle_t** handle) {
-    if (mLocalConnection) {
-        const native_handle_t* allocHandle = NULL;
-        ResultStatus status = mLocalConnection->allocate(
-                params, bufferId, &allocHandle);
-        if (status == ResultStatus::OK) {
-            *handle = native_handle_clone(allocHandle);
-        }
-        ALOGV("client allocate result %lld %d : %u clone %p",
-              (long long)mConnectionId, status == ResultStatus::OK,
-              *handle ? *bufferId : 0 , *handle);
-        return status;
-    }
-    return ResultStatus::CRITICAL_ERROR;
-}
-
-ResultStatus BufferPoolClient::Impl::fetchBufferHandle(
-        TransactionId transactionId, BufferId bufferId,
-        native_handle_t **handle) {
-    sp<IConnection> connection;
-    if (mLocal) {
-        connection = mLocalConnection;
-    } else {
-        connection = mRemoteConnection;
-    }
-    ResultStatus status;
-    Return<void> transResult = connection->fetch(
-            transactionId, bufferId,
-            [&status, &handle]
-            (ResultStatus outStatus, Buffer outBuffer) {
-                status = outStatus;
-                if (status == ResultStatus::OK) {
-                    *handle = native_handle_clone(
-                            outBuffer.buffer.getNativeHandle());
-                }
-            });
-    return transResult.isOk() ? status : ResultStatus::CRITICAL_ERROR;
-}
-
-
-BufferPoolClient::BufferPoolClient(const sp<Accessor> &accessor) {
-    mImpl = std::make_shared<Impl>(accessor);
-}
-
-BufferPoolClient::BufferPoolClient(const sp<IAccessor> &accessor) {
-    mImpl = std::make_shared<Impl>(accessor);
-}
-
-BufferPoolClient::~BufferPoolClient() {
-    // TODO: how to handle orphaned buffers?
-}
-
-bool BufferPoolClient::isValid() {
-    return mImpl && mImpl->isValid();
-}
-
-bool BufferPoolClient::isLocal() {
-    return mImpl && mImpl->isLocal();
-}
-
-bool BufferPoolClient::isActive(int64_t *lastTransactionUs, bool clearCache) {
-    if (!isValid()) {
-        *lastTransactionUs = 0;
-        return false;
-    }
-    return mImpl->isActive(lastTransactionUs, clearCache);
-}
-
-ConnectionId BufferPoolClient::getConnectionId() {
-    if (isValid()) {
-        return mImpl->getConnectionId();
-    }
-    return -1;
-}
-
-ResultStatus BufferPoolClient::getAccessor(sp<IAccessor> *accessor) {
-    if (isValid()) {
-        *accessor = mImpl->getAccessor();
-        return ResultStatus::OK;
-    }
-    return ResultStatus::CRITICAL_ERROR;
-}
-
-ResultStatus BufferPoolClient::allocate(
-        const std::vector<uint8_t> &params,
-        native_handle_t **handle,
-        std::shared_ptr<BufferPoolData> *buffer) {
-    if (isValid()) {
-        return mImpl->allocate(params, handle, buffer);
-    }
-    return ResultStatus::CRITICAL_ERROR;
-}
-
-ResultStatus BufferPoolClient::receive(
-        TransactionId transactionId, BufferId bufferId, int64_t timestampUs,
-        native_handle_t **handle, std::shared_ptr<BufferPoolData> *buffer) {
-    if (isValid()) {
-        return mImpl->receive(transactionId, bufferId, timestampUs, handle, buffer);
-    }
-    return ResultStatus::CRITICAL_ERROR;
-}
-
-ResultStatus BufferPoolClient::postSend(
-        ConnectionId receiverId,
-        const std::shared_ptr<BufferPoolData> &buffer,
-        TransactionId *transactionId,
-        int64_t *timestampUs) {
-    if (isValid()) {
-        bool result = mImpl->postSend(
-                buffer->mId, receiverId, transactionId, timestampUs);
-        return result ? ResultStatus::OK : ResultStatus::CRITICAL_ERROR;
-    }
-    return ResultStatus::CRITICAL_ERROR;
-}
-
-}  // namespace implementation
-}  // namespace V1_0
-}  // namespace bufferpool
-}  // namespace media
-}  // namespace hardware
-}  // namespace android
diff --git a/codec2/vndk/bufferpool/BufferPoolClient.h b/codec2/vndk/bufferpool/BufferPoolClient.h
deleted file mode 100644
index 577efed..0000000
--- a/codec2/vndk/bufferpool/BufferPoolClient.h
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V1_0_BUFFERPOOLCLIENT_H
-#define ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V1_0_BUFFERPOOLCLIENT_H
-
-#include <memory>
-#include <android/hardware/media/bufferpool/1.0/IAccessor.h>
-#include <android/hardware/media/bufferpool/1.0/IConnection.h>
-#include <bufferpool/BufferPoolTypes.h>
-#include <cutils/native_handle.h>
-#include "Accessor.h"
-
-namespace android {
-namespace hardware {
-namespace media {
-namespace bufferpool {
-namespace V1_0 {
-namespace implementation {
-
-using ::android::hardware::media::bufferpool::V1_0::IAccessor;
-using ::android::hardware::media::bufferpool::V1_0::IConnection;
-using ::android::hardware::media::bufferpool::V1_0::ResultStatus;
-using ::android::sp;
-
-/**
- * A buffer pool client for a buffer pool. For a specific buffer pool, at most
- * one buffer pool client exists per process. This class will not be exposed
- * outside. A buffer pool client will be used via ClientManager.
- */
-class BufferPoolClient {
-public:
-    /**
-     * Creates a buffer pool client from a local buffer pool
-     * (via ClientManager#create).
-     */
-    explicit BufferPoolClient(const sp<Accessor> &accessor);
-
-    /**
-     * Creates a buffer pool client from a remote buffer pool
-     * (via ClientManager#registerSender).
-     * Note: A buffer pool client created with remote buffer pool cannot
-     * allocate a buffer.
-     */
-    explicit BufferPoolClient(const sp<IAccessor> &accessor);
-
-    /** Destructs a buffer pool client. */
-    ~BufferPoolClient();
-
-private:
-    bool isValid();
-
-    bool isLocal();
-
-    bool isActive(int64_t *lastTransactionUs, bool clearCache);
-
-    ConnectionId getConnectionId();
-
-    ResultStatus getAccessor(sp<IAccessor> *accessor);
-
-    ResultStatus allocate(const std::vector<uint8_t> &params,
-                          native_handle_t **handle,
-                          std::shared_ptr<BufferPoolData> *buffer);
-
-    ResultStatus receive(TransactionId transactionId,
-                         BufferId bufferId,
-                         int64_t timestampUs,
-                         native_handle_t **handle,
-                         std::shared_ptr<BufferPoolData> *buffer);
-
-    ResultStatus postSend(ConnectionId receiver,
-                          const std::shared_ptr<BufferPoolData> &buffer,
-                          TransactionId *transactionId,
-                          int64_t *timestampUs);
-
-    class Impl;
-    std::shared_ptr<Impl> mImpl;
-
-    friend struct ClientManager;
-};
-
-}  // namespace implementation
-}  // namespace V1_0
-}  // namespace bufferpool
-}  // namespace media
-}  // namespace hardware
-}  // namespace android
-
-#endif  // ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V1_0_BUFFERPOOLCLIENT_H
diff --git a/codec2/vndk/bufferpool/BufferStatus.cpp b/codec2/vndk/bufferpool/BufferStatus.cpp
deleted file mode 100644
index 596cfa5..0000000
--- a/codec2/vndk/bufferpool/BufferStatus.cpp
+++ /dev/null
@@ -1,191 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "BufferPoolStatus"
-//#define LOG_NDEBUG 0
-
-#include <time.h>
-#include "BufferStatus.h"
-
-namespace android {
-namespace hardware {
-namespace media {
-namespace bufferpool {
-namespace V1_0 {
-namespace implementation {
-
-int64_t getTimestampNow() {
-    int64_t stamp;
-    struct timespec ts;
-    // TODO: CLOCK_MONOTONIC_COARSE?
-    clock_gettime(CLOCK_MONOTONIC, &ts);
-    stamp = ts.tv_nsec / 1000;
-    stamp += (ts.tv_sec * 1000000LL);
-    return stamp;
-}
-
-static constexpr int kNumElementsInQueue = 1024*16;
-static constexpr int kMinElementsToSyncInQueue = 128;
-
-ResultStatus BufferStatusObserver::open(
-        ConnectionId id, const QueueDescriptor** fmqDescPtr) {
-    if (mBufferStatusQueues.find(id) != mBufferStatusQueues.end()) {
-        // TODO: id collision log?
-        return ResultStatus::CRITICAL_ERROR;
-    }
-    std::unique_ptr<BufferStatusQueue> queue =
-            std::make_unique<BufferStatusQueue>(kNumElementsInQueue);
-    if (!queue || queue->isValid() == false) {
-        *fmqDescPtr = NULL;
-        return ResultStatus::NO_MEMORY;
-    } else {
-        *fmqDescPtr = queue->getDesc();
-    }
-    auto result = mBufferStatusQueues.insert(
-            std::make_pair(id, std::move(queue)));
-    if (!result.second) {
-        *fmqDescPtr = NULL;
-        return ResultStatus::NO_MEMORY;
-    }
-    return ResultStatus::OK;
-}
-
-ResultStatus BufferStatusObserver::close(ConnectionId id) {
-    if (mBufferStatusQueues.find(id) == mBufferStatusQueues.end()) {
-        return ResultStatus::CRITICAL_ERROR;
-    }
-    mBufferStatusQueues.erase(id);
-    return ResultStatus::OK;
-}
-
-void BufferStatusObserver::getBufferStatusChanges(std::vector<BufferStatusMessage> &messages) {
-    for (auto it = mBufferStatusQueues.begin(); it != mBufferStatusQueues.end(); ++it) {
-        BufferStatusMessage message;
-        size_t avail = it->second->availableToRead();
-        while (avail > 0) {
-            if (!it->second->read(&message, 1)) {
-                // Since avaliable # of reads are already confirmed,
-                // this should not happen.
-                // TODO: error handling (spurious client?)
-                ALOGW("FMQ message cannot be read from %lld", (long long)it->first);
-                return;
-            }
-            message.connectionId = it->first;
-            messages.push_back(message);
-            --avail;
-        }
-    }
-}
-
-BufferStatusChannel::BufferStatusChannel(
-        const QueueDescriptor &fmqDesc) {
-    std::unique_ptr<BufferStatusQueue> queue =
-            std::make_unique<BufferStatusQueue>(fmqDesc);
-    if (!queue || queue->isValid() == false) {
-        mValid = false;
-        return;
-    }
-    mValid  = true;
-    mBufferStatusQueue = std::move(queue);
-}
-
-bool BufferStatusChannel::isValid() {
-    return mValid;
-}
-
-bool BufferStatusChannel::needsSync() {
-    if (mValid) {
-        size_t avail = mBufferStatusQueue->availableToWrite();
-        return avail + kMinElementsToSyncInQueue < kNumElementsInQueue;
-    }
-    return false;
-}
-
-void BufferStatusChannel::postBufferRelease(
-        ConnectionId connectionId,
-        std::list<BufferId> &pending, std::list<BufferId> &posted) {
-    if (mValid && pending.size() > 0) {
-        size_t avail = mBufferStatusQueue->availableToWrite();
-        avail = std::min(avail, pending.size());
-        BufferStatusMessage message;
-        for (size_t i = 0 ; i < avail; ++i) {
-            BufferId id = pending.front();
-            message.newStatus = BufferStatus::NOT_USED;
-            message.bufferId = id;
-            message.connectionId = connectionId;
-            if (!mBufferStatusQueue->write(&message, 1)) {
-                // Since avaliable # of writes are already confirmed,
-                // this should not happen.
-                // TODO: error handing?
-                ALOGW("FMQ message cannot be sent from %lld", (long long)connectionId);
-                return;
-            }
-            pending.pop_front();
-            posted.push_back(id);
-        }
-    }
-}
-
-bool BufferStatusChannel::postBufferStatusMessage(
-        TransactionId transactionId, BufferId bufferId,
-        BufferStatus status, ConnectionId connectionId, ConnectionId targetId,
-        std::list<BufferId> &pending, std::list<BufferId> &posted) {
-    if (mValid) {
-        size_t avail = mBufferStatusQueue->availableToWrite();
-        size_t numPending = pending.size();
-        if (avail >= numPending + 1) {
-            BufferStatusMessage release, message;
-            for (size_t i = 0; i < numPending; ++i) {
-                BufferId id = pending.front();
-                release.newStatus = BufferStatus::NOT_USED;
-                release.bufferId = id;
-                release.connectionId = connectionId;
-                if (!mBufferStatusQueue->write(&release, 1)) {
-                    // Since avaliable # of writes are already confirmed,
-                    // this should not happen.
-                    // TODO: error handling?
-                    ALOGW("FMQ message cannot be sent from %lld", (long long)connectionId);
-                    return false;
-                }
-                pending.pop_front();
-                posted.push_back(id);
-            }
-            message.transactionId = transactionId;
-            message.bufferId = bufferId;
-            message.newStatus = status;
-            message.connectionId = connectionId;
-            message.targetConnectionId = targetId;
-            // TODO : timesatamp
-            message.timestampUs = 0;
-            if (!mBufferStatusQueue->write(&message, 1)) {
-                // Since avaliable # of writes are already confirmed,
-                // this should not happen.
-                ALOGW("FMQ message cannot be sent from %lld", (long long)connectionId);
-                return false;
-            }
-            return true;
-        }
-    }
-    return false;
-}
-
-}  // namespace implementation
-}  // namespace V1_0
-}  // namespace bufferpool
-}  // namespace media
-}  // namespace hardware
-}  // namespace android
-
diff --git a/codec2/vndk/bufferpool/BufferStatus.h b/codec2/vndk/bufferpool/BufferStatus.h
deleted file mode 100644
index a18a921..0000000
--- a/codec2/vndk/bufferpool/BufferStatus.h
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V1_0_BUFFERSTATUS_H
-#define ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V1_0_BUFFERSTATUS_H
-
-#include <android/hardware/media/bufferpool/1.0/types.h>
-#include <bufferpool/BufferPoolTypes.h>
-#include <fmq/MessageQueue.h>
-#include <hidl/MQDescriptor.h>
-#include <hidl/Status.h>
-#include <memory>
-#include <mutex>
-#include <vector>
-#include <list>
-
-namespace android {
-namespace hardware {
-namespace media {
-namespace bufferpool {
-namespace V1_0 {
-namespace implementation {
-
-/** Returns monotonic timestamp in Us since fixed point in time. */
-int64_t getTimestampNow();
-
-/**
- * A collection of FMQ for a buffer pool. buffer ownership/status change
- * messages are sent via the FMQs from the clients.
- */
-class BufferStatusObserver {
-private:
-    std::map<ConnectionId, std::unique_ptr<BufferStatusQueue>>
-            mBufferStatusQueues;
-
-public:
-    /** Creates an FMQ for the specified connection(client).
-     *
-     * @param connectionId  connection Id of the specified client.
-     * @param fmqDescPtr    double ptr of created FMQ's descriptor.
-     *
-     * @return OK if FMQ is created successfully.
-     *         NO_MEMORY when there is no memory.
-     *         CRITICAL_ERROR otherwise.
-     */
-    ResultStatus open(ConnectionId id, const QueueDescriptor** fmqDescPtr);
-
-    /** Closes an FMQ for the specified connection(client).
-     *
-     * @param connectionId  connection Id of the specified client.
-     *
-     * @return OK if the specified connection is closed successfully.
-     *         CRITICAL_ERROR otherwise.
-     */
-    ResultStatus close(ConnectionId id);
-
-    /** Retrieves all pending FMQ buffer status messages from clients.
-     *
-     * @param messages  retrieved pending messages.
-     */
-    void getBufferStatusChanges(std::vector<BufferStatusMessage> &messages);
-};
-
-/**
- * An FMQ for a buffer pool client. Buffer ownership/status change messages
- * are sent via the fmq to the buffer pool.
- */
-class BufferStatusChannel {
-private:
-    bool mValid;
-    std::unique_ptr<BufferStatusQueue> mBufferStatusQueue;
-
-public:
-    /**
-     * Connects to an FMQ from a descriptor of the created FMQ.
-     *
-     * @param fmqDesc   Descriptor of the created FMQ.
-     */
-    BufferStatusChannel(const QueueDescriptor &fmqDesc);
-
-    /** Returns whether the FMQ is connected successfully. */
-    bool isValid();
-
-    /** Returns whether the FMQ needs to be synced from the buffer pool */
-    bool needsSync();
-
-    /**
-     * Posts a buffer release message to the buffer pool.
-     *
-     * @param connectionId  connection Id of the client.
-     * @param pending       currently pending buffer release messages.
-     * @param posted        posted buffer release messages.
-     */
-    void postBufferRelease(
-            ConnectionId connectionId,
-            std::list<BufferId> &pending, std::list<BufferId> &posted);
-
-    /**
-     * Posts a buffer status message regarding the specified buffer
-     * transfer transaction.
-     *
-     * @param transactionId Id of the specified transaction.
-     * @param bufferId      buffer Id of the specified transaction.
-     * @param status        new status of the buffer.
-     * @param connectionId  connection Id of the client.
-     * @param targetId      connection Id of the receiver(only when the sender
-     *                      posts a status message).
-     * @param pending       currently pending buffer release messages.
-     * @param posted        posted buffer release messages.
-     *
-     * @return {@code true} when the specified message is posted,
-     *         {@code false} otherwise.
-     */
-    bool postBufferStatusMessage(
-            TransactionId transactionId,
-            BufferId bufferId,
-            BufferStatus status,
-            ConnectionId connectionId,
-            ConnectionId targetId,
-            std::list<BufferId> &pending, std::list<BufferId> &posted);
-};
-
-}  // namespace implementation
-}  // namespace V1_0
-}  // namespace bufferpool
-}  // namespace media
-}  // namespace hardware
-}  // namespace android
-
-#endif  // ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V1_0_BUFFERSTATUS_H
diff --git a/codec2/vndk/bufferpool/ClientManager.cpp b/codec2/vndk/bufferpool/ClientManager.cpp
deleted file mode 100644
index ecea0a4..0000000
--- a/codec2/vndk/bufferpool/ClientManager.cpp
+++ /dev/null
@@ -1,504 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#define LOG_TAG "BufferPoolManager"
-//#define LOG_NDEBUG 0
-
-#include <bufferpool/ClientManager.h>
-#include <hidl/HidlTransportSupport.h>
-#include <sys/types.h>
-#include <time.h>
-#include <unistd.h>
-#include <utils/Log.h>
-#include "BufferPoolClient.h"
-
-namespace android {
-namespace hardware {
-namespace media {
-namespace bufferpool {
-namespace V1_0 {
-namespace implementation {
-
-static constexpr int64_t kRegisterTimeoutUs = 500000; // 0.5 sec
-static constexpr int64_t kCleanUpDurationUs = 1000000; // TODO: 1 sec tune
-static constexpr int64_t kClientTimeoutUs = 5000000; // TODO: 5 secs tune
-
-/**
- * The holder of the cookie of remote IClientManager.
- * The cookie is process locally unique for each IClientManager.
- * (The cookie is used to notify death of clients to bufferpool process.)
- */
-class ClientManagerCookieHolder {
-public:
-    /**
-     * Creates a cookie holder for remote IClientManager(s).
-     */
-    ClientManagerCookieHolder();
-
-    /**
-     * Gets a cookie for a remote IClientManager.
-     *
-     * @param manager   the specified remote IClientManager.
-     * @param added     true when the specified remote IClientManager is added
-     *                  newly, false otherwise.
-     *
-     * @return the process locally unique cookie for the specified IClientManager.
-     */
-    uint64_t getCookie(const sp<IClientManager> &manager, bool *added);
-
-private:
-    uint64_t mSeqId;
-    std::mutex mLock;
-    std::list<std::pair<const wp<IClientManager>, uint64_t>> mManagers;
-};
-
-ClientManagerCookieHolder::ClientManagerCookieHolder() : mSeqId(0){}
-
-uint64_t ClientManagerCookieHolder::getCookie(
-        const sp<IClientManager> &manager,
-        bool *added) {
-    std::lock_guard<std::mutex> lock(mLock);
-    for (auto it = mManagers.begin(); it != mManagers.end();) {
-        const sp<IClientManager> key = it->first.promote();
-        if (key) {
-            if (interfacesEqual(key, manager)) {
-                *added = false;
-                return it->second;
-            }
-            ++it;
-        } else {
-            it = mManagers.erase(it);
-        }
-    }
-    uint64_t id = mSeqId++;
-    *added = true;
-    mManagers.push_back(std::make_pair(manager, id));
-    return id;
-}
-
-class ClientManager::Impl {
-public:
-    Impl();
-
-    // BnRegisterSender
-    ResultStatus registerSender(const sp<IAccessor> &accessor,
-                                ConnectionId *pConnectionId);
-
-    // BpRegisterSender
-    ResultStatus registerSender(const sp<IClientManager> &receiver,
-                                ConnectionId senderId,
-                                ConnectionId *receiverId);
-
-    ResultStatus create(const std::shared_ptr<BufferPoolAllocator> &allocator,
-                        ConnectionId *pConnectionId);
-
-    ResultStatus close(ConnectionId connectionId);
-
-    ResultStatus allocate(ConnectionId connectionId,
-                          const std::vector<uint8_t> &params,
-                          native_handle_t **handle,
-                          std::shared_ptr<BufferPoolData> *buffer);
-
-    ResultStatus receive(ConnectionId connectionId,
-                         TransactionId transactionId,
-                         BufferId bufferId,
-                         int64_t timestampUs,
-                         native_handle_t **handle,
-                         std::shared_ptr<BufferPoolData> *buffer);
-
-    ResultStatus postSend(ConnectionId receiverId,
-                          const std::shared_ptr<BufferPoolData> &buffer,
-                          TransactionId *transactionId,
-                          int64_t *timestampUs);
-
-    ResultStatus getAccessor(ConnectionId connectionId,
-                             sp<IAccessor> *accessor);
-
-    void cleanUp(bool clearCache = false);
-
-private:
-    // In order to prevent deadlock between multiple locks,
-    // always lock ClientCache.lock before locking ActiveClients.lock.
-    struct ClientCache {
-        // This lock is held for brief duration.
-        // Blocking operation is not performed while holding the lock.
-        std::mutex mMutex;
-        std::list<std::pair<const wp<IAccessor>, const std::weak_ptr<BufferPoolClient>>>
-                mClients;
-        std::condition_variable mConnectCv;
-        bool mConnecting;
-        int64_t mLastCleanUpUs;
-
-        ClientCache() : mConnecting(false), mLastCleanUpUs(getTimestampNow()) {}
-    } mCache;
-
-    // Active clients which can be retrieved via ConnectionId
-    struct ActiveClients {
-        // This lock is held for brief duration.
-        // Blocking operation is not performed holding the lock.
-        std::mutex mMutex;
-        std::map<ConnectionId, const std::shared_ptr<BufferPoolClient>>
-                mClients;
-    } mActive;
-
-    ClientManagerCookieHolder mRemoteClientCookies;
-};
-
-ClientManager::Impl::Impl() {}
-
-ResultStatus ClientManager::Impl::registerSender(
-        const sp<IAccessor> &accessor, ConnectionId *pConnectionId) {
-    cleanUp();
-    int64_t timeoutUs = getTimestampNow() + kRegisterTimeoutUs;
-    do {
-        std::unique_lock<std::mutex> lock(mCache.mMutex);
-        for (auto it = mCache.mClients.begin(); it != mCache.mClients.end(); ++it) {
-            sp<IAccessor> sAccessor = it->first.promote();
-            if (sAccessor && interfacesEqual(sAccessor, accessor)) {
-                const std::shared_ptr<BufferPoolClient> client = it->second.lock();
-                if (client) {
-                    std::lock_guard<std::mutex> lock(mActive.mMutex);
-                    *pConnectionId = client->getConnectionId();
-                    if (mActive.mClients.find(*pConnectionId) != mActive.mClients.end()) {
-                        ALOGV("register existing connection %lld", (long long)*pConnectionId);
-                        return ResultStatus::ALREADY_EXISTS;
-                    }
-                }
-                mCache.mClients.erase(it);
-                break;
-            }
-        }
-        if (!mCache.mConnecting) {
-            mCache.mConnecting = true;
-            lock.unlock();
-            ResultStatus result = ResultStatus::OK;
-            const std::shared_ptr<BufferPoolClient> client =
-                    std::make_shared<BufferPoolClient>(accessor);
-            lock.lock();
-            if (!client) {
-                result = ResultStatus::NO_MEMORY;
-            } else if (!client->isValid()) {
-                result = ResultStatus::CRITICAL_ERROR;
-            }
-            if (result == ResultStatus::OK) {
-                // TODO: handle insert fail. (malloc fail)
-                const std::weak_ptr<BufferPoolClient> wclient = client;
-                mCache.mClients.push_back(std::make_pair(accessor, wclient));
-                ConnectionId conId = client->getConnectionId();
-                {
-                    std::lock_guard<std::mutex> lock(mActive.mMutex);
-                    mActive.mClients.insert(std::make_pair(conId, client));
-                }
-                *pConnectionId = conId;
-                ALOGV("register new connection %lld", (long long)*pConnectionId);
-            }
-            mCache.mConnecting = false;
-            lock.unlock();
-            mCache.mConnectCv.notify_all();
-            return result;
-        }
-        mCache.mConnectCv.wait_for(
-                lock, std::chrono::microseconds(kRegisterTimeoutUs));
-    } while (getTimestampNow() < timeoutUs);
-    // TODO: return timeout error
-    return ResultStatus::CRITICAL_ERROR;
-}
-
-ResultStatus ClientManager::Impl::registerSender(
-        const sp<IClientManager> &receiver,
-        ConnectionId senderId,
-        ConnectionId *receiverId) {
-    sp<IAccessor> accessor;
-    bool local = false;
-    {
-        std::lock_guard<std::mutex> lock(mActive.mMutex);
-        auto it = mActive.mClients.find(senderId);
-        if (it == mActive.mClients.end()) {
-            return ResultStatus::NOT_FOUND;
-        }
-        it->second->getAccessor(&accessor);
-        local = it->second->isLocal();
-    }
-    ResultStatus rs = ResultStatus::CRITICAL_ERROR;
-    if (accessor) {
-       Return<void> transResult = receiver->registerSender(
-                accessor,
-                [&rs, receiverId](
-                        ResultStatus status,
-                        int64_t connectionId) {
-                    rs = status;
-                    *receiverId = connectionId;
-                });
-        if (!transResult.isOk()) {
-            return ResultStatus::CRITICAL_ERROR;
-        } else if (local && rs == ResultStatus::OK) {
-            sp<ConnectionDeathRecipient> recipient = Accessor::getConnectionDeathRecipient();
-            if (recipient)  {
-                ALOGV("client death recipient registered %lld", (long long)*receiverId);
-                bool added;
-                uint64_t cookie = mRemoteClientCookies.getCookie(receiver, &added);
-                recipient->addCookieToConnection(cookie, *receiverId);
-                if (added) {
-                    Return<bool> transResult = receiver->linkToDeath(recipient, cookie);
-                }
-            }
-        }
-    }
-    return rs;
-}
-
-ResultStatus ClientManager::Impl::create(
-        const std::shared_ptr<BufferPoolAllocator> &allocator,
-        ConnectionId *pConnectionId) {
-    const sp<Accessor> accessor = new Accessor(allocator);
-    if (!accessor || !accessor->isValid()) {
-        return ResultStatus::CRITICAL_ERROR;
-    }
-    std::shared_ptr<BufferPoolClient> client =
-            std::make_shared<BufferPoolClient>(accessor);
-    if (!client || !client->isValid()) {
-        return ResultStatus::CRITICAL_ERROR;
-    }
-    // Since a new bufferpool is created, evict memories which are used by
-    // existing bufferpools and clients.
-    cleanUp(true);
-    {
-        // TODO: handle insert fail. (malloc fail)
-        std::lock_guard<std::mutex> lock(mCache.mMutex);
-        const std::weak_ptr<BufferPoolClient> wclient = client;
-        mCache.mClients.push_back(std::make_pair(accessor, wclient));
-        ConnectionId conId = client->getConnectionId();
-        {
-            std::lock_guard<std::mutex> lock(mActive.mMutex);
-            mActive.mClients.insert(std::make_pair(conId, client));
-        }
-        *pConnectionId = conId;
-        ALOGV("create new connection %lld", (long long)*pConnectionId);
-    }
-    return ResultStatus::OK;
-}
-
-ResultStatus ClientManager::Impl::close(ConnectionId connectionId) {
-    std::lock_guard<std::mutex> lock1(mCache.mMutex);
-    std::lock_guard<std::mutex> lock2(mActive.mMutex);
-    auto it = mActive.mClients.find(connectionId);
-    if (it != mActive.mClients.end()) {
-        sp<IAccessor> accessor;
-        it->second->getAccessor(&accessor);
-        mActive.mClients.erase(connectionId);
-        for (auto cit = mCache.mClients.begin(); cit != mCache.mClients.end();) {
-            // clean up dead client caches
-            sp<IAccessor> cAccessor = cit->first.promote();
-            if (!cAccessor || (accessor && interfacesEqual(cAccessor, accessor))) {
-                cit = mCache.mClients.erase(cit);
-            } else {
-                cit++;
-            }
-        }
-        return ResultStatus::OK;
-    }
-    return ResultStatus::NOT_FOUND;
-}
-
-ResultStatus ClientManager::Impl::allocate(
-        ConnectionId connectionId, const std::vector<uint8_t> &params,
-        native_handle_t **handle, std::shared_ptr<BufferPoolData> *buffer) {
-    std::shared_ptr<BufferPoolClient> client;
-    {
-        std::lock_guard<std::mutex> lock(mActive.mMutex);
-        auto it = mActive.mClients.find(connectionId);
-        if (it == mActive.mClients.end()) {
-            return ResultStatus::NOT_FOUND;
-        }
-        client = it->second;
-    }
-    return client->allocate(params, handle, buffer);
-}
-
-ResultStatus ClientManager::Impl::receive(
-        ConnectionId connectionId, TransactionId transactionId,
-        BufferId bufferId, int64_t timestampUs,
-        native_handle_t **handle, std::shared_ptr<BufferPoolData> *buffer) {
-    std::shared_ptr<BufferPoolClient> client;
-    {
-        std::lock_guard<std::mutex> lock(mActive.mMutex);
-        auto it = mActive.mClients.find(connectionId);
-        if (it == mActive.mClients.end()) {
-            return ResultStatus::NOT_FOUND;
-        }
-        client = it->second;
-    }
-    return client->receive(transactionId, bufferId, timestampUs, handle, buffer);
-}
-
-ResultStatus ClientManager::Impl::postSend(
-        ConnectionId receiverId, const std::shared_ptr<BufferPoolData> &buffer,
-        TransactionId *transactionId, int64_t *timestampUs) {
-    ConnectionId connectionId = buffer->mConnectionId;
-    std::shared_ptr<BufferPoolClient> client;
-    {
-        std::lock_guard<std::mutex> lock(mActive.mMutex);
-        auto it = mActive.mClients.find(connectionId);
-        if (it == mActive.mClients.end()) {
-            return ResultStatus::NOT_FOUND;
-        }
-        client = it->second;
-    }
-    return client->postSend(receiverId, buffer, transactionId, timestampUs);
-}
-
-ResultStatus ClientManager::Impl::getAccessor(
-        ConnectionId connectionId, sp<IAccessor> *accessor) {
-    std::shared_ptr<BufferPoolClient> client;
-    {
-        std::lock_guard<std::mutex> lock(mActive.mMutex);
-        auto it = mActive.mClients.find(connectionId);
-        if (it == mActive.mClients.end()) {
-            return ResultStatus::NOT_FOUND;
-        }
-        client = it->second;
-    }
-    return client->getAccessor(accessor);
-}
-
-void ClientManager::Impl::cleanUp(bool clearCache) {
-    int64_t now = getTimestampNow();
-    int64_t lastTransactionUs;
-    std::lock_guard<std::mutex> lock1(mCache.mMutex);
-    if (clearCache || mCache.mLastCleanUpUs + kCleanUpDurationUs < now) {
-        std::lock_guard<std::mutex> lock2(mActive.mMutex);
-        int cleaned = 0;
-        for (auto it = mActive.mClients.begin(); it != mActive.mClients.end();) {
-            if (!it->second->isActive(&lastTransactionUs, clearCache)) {
-                if (lastTransactionUs + kClientTimeoutUs < now) {
-                    sp<IAccessor> accessor;
-                    it->second->getAccessor(&accessor);
-                    it = mActive.mClients.erase(it);
-                    ++cleaned;
-                    continue;
-                }
-            }
-            ++it;
-        }
-        for (auto cit = mCache.mClients.begin(); cit != mCache.mClients.end();) {
-            // clean up dead client caches
-            sp<IAccessor> cAccessor = cit->first.promote();
-            if (!cAccessor) {
-                cit = mCache.mClients.erase(cit);
-            } else {
-                ++cit;
-            }
-        }
-        ALOGV("# of cleaned connections: %d", cleaned);
-        mCache.mLastCleanUpUs = now;
-    }
-}
-
-// Methods from ::android::hardware::media::bufferpool::V1_0::IClientManager follow.
-Return<void> ClientManager::registerSender(const sp<::android::hardware::media::bufferpool::V1_0::IAccessor>& bufferPool, registerSender_cb _hidl_cb) {
-    if (mImpl) {
-        ConnectionId connectionId = -1;
-        ResultStatus status = mImpl->registerSender(bufferPool, &connectionId);
-        _hidl_cb(status, connectionId);
-    } else {
-        _hidl_cb(ResultStatus::CRITICAL_ERROR, -1);
-    }
-    return Void();
-}
-
-// Methods for local use.
-sp<ClientManager> ClientManager::sInstance;
-std::mutex ClientManager::sInstanceLock;
-
-sp<ClientManager> ClientManager::getInstance() {
-    std::lock_guard<std::mutex> lock(sInstanceLock);
-    if (!sInstance) {
-        sInstance = new ClientManager();
-    }
-    return sInstance;
-}
-
-ClientManager::ClientManager() : mImpl(new Impl()) {}
-
-ClientManager::~ClientManager() {
-}
-
-ResultStatus ClientManager::create(
-        const std::shared_ptr<BufferPoolAllocator> &allocator,
-        ConnectionId *pConnectionId) {
-    if (mImpl) {
-        return mImpl->create(allocator, pConnectionId);
-    }
-    return ResultStatus::CRITICAL_ERROR;
-}
-
-ResultStatus ClientManager::registerSender(
-        const sp<IClientManager> &receiver,
-        ConnectionId senderId,
-        ConnectionId *receiverId) {
-    if (mImpl) {
-        return mImpl->registerSender(receiver, senderId, receiverId);
-    }
-    return ResultStatus::CRITICAL_ERROR;
-}
-
-ResultStatus ClientManager::close(ConnectionId connectionId) {
-    if (mImpl) {
-        return mImpl->close(connectionId);
-    }
-    return ResultStatus::CRITICAL_ERROR;
-}
-
-ResultStatus ClientManager::allocate(
-        ConnectionId connectionId, const std::vector<uint8_t> &params,
-        native_handle_t **handle, std::shared_ptr<BufferPoolData> *buffer) {
-    if (mImpl) {
-        return mImpl->allocate(connectionId, params, handle, buffer);
-    }
-    return ResultStatus::CRITICAL_ERROR;
-}
-
-ResultStatus ClientManager::receive(
-        ConnectionId connectionId, TransactionId transactionId,
-        BufferId bufferId, int64_t timestampUs,
-        native_handle_t **handle, std::shared_ptr<BufferPoolData> *buffer) {
-    if (mImpl) {
-        return mImpl->receive(connectionId, transactionId, bufferId,
-                              timestampUs, handle, buffer);
-    }
-    return ResultStatus::CRITICAL_ERROR;
-}
-
-ResultStatus ClientManager::postSend(
-        ConnectionId receiverId, const std::shared_ptr<BufferPoolData> &buffer,
-        TransactionId *transactionId, int64_t* timestampUs) {
-    if (mImpl && buffer) {
-        return mImpl->postSend(receiverId, buffer, transactionId, timestampUs);
-    }
-    return ResultStatus::CRITICAL_ERROR;
-}
-
-void ClientManager::cleanUp() {
-    if (mImpl) {
-        mImpl->cleanUp(true);
-    }
-}
-
-}  // namespace implementation
-}  // namespace V1_0
-}  // namespace bufferpool
-}  // namespace media
-}  // namespace hardware
-}  // namespace android
diff --git a/codec2/vndk/bufferpool/Connection.cpp b/codec2/vndk/bufferpool/Connection.cpp
deleted file mode 100644
index 54f5c21..0000000
--- a/codec2/vndk/bufferpool/Connection.cpp
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "Connection.h"
-
-namespace android {
-namespace hardware {
-namespace media {
-namespace bufferpool {
-namespace V1_0 {
-namespace implementation {
-
-// Methods from ::android::hardware::media::bufferpool::V1_0::IConnection follow.
-Return<void> Connection::fetch(uint64_t transactionId, uint32_t bufferId, fetch_cb _hidl_cb) {
-    ResultStatus status = ResultStatus::CRITICAL_ERROR;
-    if (mInitialized && mAccessor) {
-        if (bufferId != SYNC_BUFFERID) {
-            const native_handle_t *handle = NULL;
-            status = mAccessor->fetch(
-                    mConnectionId, transactionId, bufferId, &handle);
-            if (status == ResultStatus::OK) {
-                Buffer buffer = {};
-                buffer.id = bufferId;
-                buffer.buffer = handle;
-                _hidl_cb(status, buffer);
-                return Void();
-            }
-        } else {
-            mAccessor->cleanUp(false);
-        }
-    }
-
-    Buffer buffer = {};
-    buffer.id = 0;
-    buffer.buffer = nullptr;
-
-    _hidl_cb(status, buffer);
-    return Void();
-}
-
-Connection::Connection() : mInitialized(false), mConnectionId(-1LL) {}
-
-Connection::~Connection() {
-    if (mInitialized && mAccessor) {
-        mAccessor->close(mConnectionId);
-    }
-}
-
-void Connection::initialize(
-        const sp<Accessor>& accessor, ConnectionId connectionId) {
-    if (!mInitialized) {
-        mAccessor = accessor;
-        mConnectionId = connectionId;
-        mInitialized = true;
-    }
-}
-
-ResultStatus Connection::allocate(
-        const std::vector<uint8_t> &params, BufferId *bufferId,
-        const native_handle_t **handle) {
-    if (mInitialized && mAccessor) {
-        return mAccessor->allocate(mConnectionId, params, bufferId, handle);
-    }
-    return ResultStatus::CRITICAL_ERROR;
-}
-
-void Connection::cleanUp(bool clearCache) {
-    if (mInitialized && mAccessor) {
-        mAccessor->cleanUp(clearCache);
-    }
-}
-
-// Methods from ::android::hidl::base::V1_0::IBase follow.
-
-//IConnection* HIDL_FETCH_IConnection(const char* /* name */) {
-//    return new Connection();
-//}
-
-}  // namespace implementation
-}  // namespace V1_0
-}  // namespace bufferpool
-}  // namespace media
-}  // namespace hardware
-}  // namespace android
diff --git a/codec2/vndk/bufferpool/Connection.h b/codec2/vndk/bufferpool/Connection.h
deleted file mode 100644
index e19cb67..0000000
--- a/codec2/vndk/bufferpool/Connection.h
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V1_0_CONNECTION_H
-#define ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V1_0_CONNECTION_H
-
-#include <android/hardware/media/bufferpool/1.0/IConnection.h>
-#include <bufferpool/BufferPoolTypes.h>
-#include <hidl/MQDescriptor.h>
-#include <hidl/Status.h>
-#include "Accessor.h"
-
-namespace android {
-namespace hardware {
-namespace media {
-namespace bufferpool {
-namespace V1_0 {
-namespace implementation {
-
-using ::android::hardware::hidl_array;
-using ::android::hardware::hidl_memory;
-using ::android::hardware::hidl_string;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::media::bufferpool::V1_0::implementation::Accessor;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::sp;
-
-struct Connection : public IConnection {
-    // Methods from ::android::hardware::media::bufferpool::V1_0::IConnection follow.
-    Return<void> fetch(uint64_t transactionId, uint32_t bufferId, fetch_cb _hidl_cb) override;
-
-    /**
-     * Allocates a buffer using the specified parameters. Recycles a buffer if
-     * it is possible. The returned buffer can be transferred to other remote
-     * clients(Connection).
-     *
-     * @param params    allocation parameters.
-     * @param bufferId  Id of the allocated buffer.
-     * @param handle    native handle of the allocated buffer.
-     *
-     * @return OK if a buffer is successfully allocated.
-     *         NO_MEMORY when there is no memory.
-     *         CRITICAL_ERROR otherwise.
-     */
-    ResultStatus allocate(const std::vector<uint8_t> &params,
-                          BufferId *bufferId, const native_handle_t **handle);
-
-    /**
-     * Processes pending buffer status messages and performs periodic cache cleaning
-     * from bufferpool.
-     *
-     * @param clearCache    if clearCache is true, bufferpool frees all buffers
-     *                      waiting to be recycled.
-     */
-    void cleanUp(bool clearCache);
-
-    /** Destructs a connection. */
-    ~Connection();
-
-    /** Creates a connection. */
-    Connection();
-
-    /**
-     * Initializes with the specified buffer pool and the connection id.
-     * The connection id should be unique in the whole system.
-     *
-     * @param accessor      the specified buffer pool.
-     * @param connectionId  Id.
-     */
-    void initialize(const sp<Accessor> &accessor, ConnectionId connectionId);
-
-    enum : uint32_t {
-        SYNC_BUFFERID = UINT32_MAX,
-    };
-
-private:
-    bool mInitialized;
-    sp<Accessor> mAccessor;
-    ConnectionId mConnectionId;
-};
-
-}  // namespace implementation
-}  // namespace V1_0
-}  // namespace bufferpool
-}  // namespace media
-}  // namespace hardware
-}  // namespace android
-
-#endif  // ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V1_0_CONNECTION_H
diff --git a/codec2/vndk/bufferpool/include/bufferpool/BufferPoolTypes.h b/codec2/vndk/bufferpool/include/bufferpool/BufferPoolTypes.h
deleted file mode 100644
index 710f015..0000000
--- a/codec2/vndk/bufferpool/include/bufferpool/BufferPoolTypes.h
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V1_0_BUFFERPOOLTYPES_H
-#define ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V1_0_BUFFERPOOLTYPES_H
-
-#include <android/hardware/media/bufferpool/1.0/types.h>
-#include <cutils/native_handle.h>
-#include <fmq/MessageQueue.h>
-#include <hidl/MQDescriptor.h>
-#include <hidl/Status.h>
-
-namespace android {
-namespace hardware {
-namespace media {
-namespace bufferpool {
-
-struct BufferPoolData {
-    // For local use, to specify a bufferpool (client connection) for buffers.
-    // Return value from connect#IAccessor(android.hardware.media.bufferpool@1.0).
-    int64_t mConnectionId;
-    // BufferId
-    uint32_t mId;
-
-    BufferPoolData() : mConnectionId(0), mId(0) {}
-
-    BufferPoolData(
-            int64_t connectionId, uint32_t id)
-            : mConnectionId(connectionId), mId(id) {}
-
-    ~BufferPoolData() {}
-};
-
-namespace V1_0 {
-namespace implementation {
-
-using ::android::hardware::kSynchronizedReadWrite;
-
-typedef uint32_t BufferId;
-typedef uint64_t TransactionId;
-typedef int64_t ConnectionId;
-
-enum : ConnectionId {
-    INVALID_CONNECTIONID = 0,
-};
-
-typedef android::hardware::MessageQueue<BufferStatusMessage, kSynchronizedReadWrite> BufferStatusQueue;
-typedef BufferStatusQueue::Descriptor QueueDescriptor;
-
-/**
- * Allocation wrapper class for buffer pool.
- */
-struct BufferPoolAllocation {
-    const native_handle_t *mHandle;
-
-    const native_handle_t *handle() {
-        return mHandle;
-    }
-
-    BufferPoolAllocation(const native_handle_t *handle) : mHandle(handle) {}
-
-    ~BufferPoolAllocation() {};
-};
-
-/**
- * Allocator wrapper class for buffer pool.
- */
-class BufferPoolAllocator {
-public:
-
-    /**
-     * Allocate an allocation(buffer) for buffer pool.
-     *
-     * @param params    allocation parameters
-     * @param alloc     created allocation
-     * @param allocSize size of created allocation
-     *
-     * @return OK when an allocation is created successfully.
-     */
-    virtual ResultStatus allocate(
-            const std::vector<uint8_t> &params,
-            std::shared_ptr<BufferPoolAllocation> *alloc,
-            size_t *allocSize) = 0;
-
-    /**
-     * Returns whether allocation parameters of an old allocation are
-     * compatible with new allocation parameters.
-     */
-    virtual bool compatible(const std::vector<uint8_t> &newParams,
-                            const std::vector<uint8_t> &oldParams) = 0;
-
-protected:
-    BufferPoolAllocator() = default;
-
-    virtual ~BufferPoolAllocator() = default;
-};
-
-}  // namespace implementation
-}  // namespace V1_0
-}  // namespace bufferpool
-}  // namespace media
-}  // namespace hardware
-}  // namespace android
-
-#endif  // ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V1_0_BUFFERPOOLTYPES_H
diff --git a/codec2/vndk/bufferpool/include/bufferpool/ClientManager.h b/codec2/vndk/bufferpool/include/bufferpool/ClientManager.h
deleted file mode 100644
index be5779f..0000000
--- a/codec2/vndk/bufferpool/include/bufferpool/ClientManager.h
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V1_0_CLIENTMANAGER_H
-#define ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V1_0_CLIENTMANAGER_H
-
-#include <android/hardware/media/bufferpool/1.0/IClientManager.h>
-#include <hidl/MQDescriptor.h>
-#include <hidl/Status.h>
-#include <memory>
-#include "BufferPoolTypes.h"
-
-namespace android {
-namespace hardware {
-namespace media {
-namespace bufferpool {
-namespace V1_0 {
-namespace implementation {
-
-using ::android::hardware::hidl_array;
-using ::android::hardware::hidl_memory;
-using ::android::hardware::hidl_string;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::media::bufferpool::V1_0::IAccessor;
-using ::android::hardware::media::bufferpool::V1_0::ResultStatus;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::sp;
-
-struct ClientManager : public IClientManager {
-    // Methods from ::android::hardware::media::bufferpool::V1_0::IClientManager follow.
-    Return<void> registerSender(const sp<::android::hardware::media::bufferpool::V1_0::IAccessor>& bufferPool, registerSender_cb _hidl_cb) override;
-
-    /** Gets an instance. */
-    static sp<ClientManager> getInstance();
-
-    /**
-     * Creates a local connection with a newly created buffer pool.
-     *
-     * @param allocator     for new buffer allocation.
-     * @param pConnectionId Id of the created connection. This is
-     *                      system-wide unique.
-     *
-     * @return OK when a buffer pool and a local connection is successfully
-     *         created.
-     *         NO_MEMORY when there is no memory.
-     *         CRITICAL_ERROR otherwise.
-     */
-    ResultStatus create(const std::shared_ptr<BufferPoolAllocator> &allocator,
-                        ConnectionId *pConnectionId);
-
-    /**
-     * Register a created connection as sender for remote process.
-     *
-     * @param receiver      The remote receiving process.
-     * @param senderId      A local connection which will send buffers to.
-     * @param receiverId    Id of the created receiving connection on the receiver
-     *                      process.
-     *
-     * @return OK when the receiving connection is successfully created on the
-     *         receiver process.
-     *         NOT_FOUND when the sender connection was not found.
-     *         ALREADY_EXISTS the receiving connection is already made.
-     *         CRITICAL_ERROR otherwise.
-     */
-    ResultStatus registerSender(const sp<IClientManager> &receiver,
-                                ConnectionId senderId,
-                                ConnectionId *receiverId);
-
-    /**
-     * Closes the specified connection.
-     *
-     * @param connectionId  The id of the connection.
-     *
-     * @return OK when the connection is closed.
-     *         NOT_FOUND when the specified connection was not found.
-     *         CRITICAL_ERROR otherwise.
-     */
-    ResultStatus close(ConnectionId connectionId);
-
-    /**
-     * Allocates a buffer from the specified connection.
-     *
-     * @param connectionId  The id of the connection.
-     * @param params        The allocation parameters.
-     * @param handle        The native handle to the allocated buffer. handle
-     *                      should be cloned before use.
-     * @param buffer        The allocated buffer.
-     *
-     * @return OK when a buffer was allocated successfully.
-     *         NOT_FOUND when the specified connection was not found.
-     *         NO_MEMORY when there is no memory.
-     *         CRITICAL_ERROR otherwise.
-     */
-    ResultStatus allocate(ConnectionId connectionId,
-                          const std::vector<uint8_t> &params,
-                          native_handle_t **handle,
-                          std::shared_ptr<BufferPoolData> *buffer);
-
-    /**
-     * Receives a buffer for the transaction.
-     *
-     * @param connectionId  The id of the receiving connection.
-     * @param transactionId The id for the transaction.
-     * @param bufferId      The id for the buffer.
-     * @param timestampUs   The timestamp of the buffer is being sent.
-     * @param handle        The native handle to the allocated buffer. handle
-     *                      should be cloned before use.
-     * @param buffer        The received buffer.
-     *
-     * @return OK when a buffer was received successfully.
-     *         NOT_FOUND when the specified connection was not found.
-     *         NO_MEMORY when there is no memory.
-     *         CRITICAL_ERROR otherwise.
-     */
-    ResultStatus receive(ConnectionId connectionId,
-                         TransactionId transactionId,
-                         BufferId bufferId,
-                         int64_t timestampUs,
-                          native_handle_t **handle,
-                         std::shared_ptr<BufferPoolData> *buffer);
-
-    /**
-     * Posts a buffer transfer transaction to the buffer pool. Sends a buffer
-     * to other remote clients(connection) after this call has been succeeded.
-     *
-     * @param receiverId    The id of the receiving connection.
-     * @param buffer        to transfer
-     * @param transactionId Id of the transfer transaction.
-     * @param timestampUs   The timestamp of the buffer transaction is being
-     *                      posted.
-     *
-     * @return OK when a buffer transaction was posted successfully.
-     *         NOT_FOUND when the sending connection was not found.
-     *         CRITICAL_ERROR otherwise.
-     */
-    ResultStatus postSend(ConnectionId receiverId,
-                          const std::shared_ptr<BufferPoolData> &buffer,
-                          TransactionId *transactionId,
-                          int64_t *timestampUs);
-
-    /**
-     *  Time out inactive lingering connections and close.
-     */
-    void cleanUp();
-
-    /** Destructs the manager of buffer pool clients.  */
-    ~ClientManager();
-private:
-    static sp<ClientManager> sInstance;
-    static std::mutex sInstanceLock;
-
-    class Impl;
-    const std::unique_ptr<Impl> mImpl;
-
-    ClientManager();
-};
-
-}  // namespace implementation
-}  // namespace V1_0
-}  // namespace bufferpool
-}  // namespace media
-}  // namespace hardware
-}  // namespace android
-
-#endif  // ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V1_0_CLIENTMANAGER_H
diff --git a/codec2/vndk/bufferpool/vts/Android.bp b/codec2/vndk/bufferpool/vts/Android.bp
deleted file mode 100644
index 62286f3..0000000
--- a/codec2/vndk/bufferpool/vts/Android.bp
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-cc_test {
-    name: "VtsVndkHidlBufferpoolV1_0TargetSingleTest",
-    defaults: ["VtsHalTargetTestDefaults"],
-    srcs: [
-        "allocator.cpp",
-        "single.cpp",
-    ],
-    static_libs: [
-        "android.hardware.media.bufferpool@1.0",
-        "libion",
-        "libstagefright_bufferpool@1.0",
-    ],
-    shared_libs: [
-        "libfmq",
-        "libstagefright_codec2",
-        "libstagefright_codec2_vndk",
-    ],
-    compile_multilib: "both",
-}
-
-cc_test {
-    name: "VtsVndkHidlBufferpoolV1_0TargetMultiTest",
-    defaults: ["VtsHalTargetTestDefaults"],
-    srcs: [
-        "allocator.cpp",
-        "multi.cpp",
-    ],
-    static_libs: [
-        "android.hardware.media.bufferpool@1.0",
-        "libion",
-        "libstagefright_bufferpool@1.0",
-    ],
-    shared_libs: [
-        "libfmq",
-        "libstagefright_codec2",
-        "libstagefright_codec2_vndk",
-    ],
-    compile_multilib: "both",
-}
diff --git a/codec2/vndk/bufferpool/vts/OWNERS b/codec2/vndk/bufferpool/vts/OWNERS
deleted file mode 100644
index 4c3f7a1..0000000
--- a/codec2/vndk/bufferpool/vts/OWNERS
+++ /dev/null
@@ -1,7 +0,0 @@
-# Media team
-taklee@google.com
-lajos@google.com
-
-# VTS team
-yim@google.com
-zhuoyao@google.com
diff --git a/codec2/vndk/bufferpool/vts/allocator.cpp b/codec2/vndk/bufferpool/vts/allocator.cpp
deleted file mode 100644
index 04e3b4e..0000000
--- a/codec2/vndk/bufferpool/vts/allocator.cpp
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <C2Buffer.h>
-#include "allocator.h"
-
-union Params {
-  struct {
-    uint32_t capacity;
-    C2MemoryUsage usage;
-  } data;
-  uint8_t array[0];
-  Params() : data{0, {0, 0}} {}
-  Params(uint32_t size)
-      : data{size, {C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE}} {}
-};
-
-struct AllocationDtor {
-  AllocationDtor(const std::shared_ptr<C2LinearAllocation> &alloc)
-      : mAlloc(alloc) {}
-
-  void operator()(BufferPoolAllocation *poolAlloc) { delete poolAlloc; }
-
-  const std::shared_ptr<C2LinearAllocation> mAlloc;
-};
-
-ResultStatus VtsBufferPoolAllocator::allocate(
-    const std::vector<uint8_t> &params,
-    std::shared_ptr<BufferPoolAllocation> *alloc,
-    size_t *allocSize) {
-  Params ionParams;
-  memcpy(&ionParams, params.data(), std::min(sizeof(Params), params.size()));
-
-  std::shared_ptr<C2LinearAllocation> linearAlloc;
-  c2_status_t status = mAllocator->newLinearAllocation(
-      ionParams.data.capacity, ionParams.data.usage, &linearAlloc);
-  if (status == C2_OK && linearAlloc) {
-    BufferPoolAllocation *ptr = new BufferPoolAllocation(linearAlloc->handle());
-    if (ptr) {
-      *alloc = std::shared_ptr<BufferPoolAllocation>(
-          ptr, AllocationDtor(linearAlloc));
-      if (*alloc) {
-        *allocSize = ionParams.data.capacity;
-        return ResultStatus::OK;
-      }
-      delete ptr;
-      return ResultStatus::NO_MEMORY;
-    }
-  }
-  return ResultStatus::CRITICAL_ERROR;
-}
-
-bool VtsBufferPoolAllocator::compatible(const std::vector<uint8_t> &newParams,
-                                        const std::vector<uint8_t> &oldParams) {
-  size_t newSize = newParams.size();
-  size_t oldSize = oldParams.size();
-  if (newSize == oldSize) {
-    for (size_t i = 0; i < newSize; ++i) {
-      if (newParams[i] != oldParams[i]) {
-        return false;
-      }
-    }
-    return true;
-  }
-  return false;
-}
-
-void getVtsAllocatorParams(std::vector<uint8_t> *params) {
-  constexpr static int kAllocationSize = 1024 * 10;
-  Params ionParams(kAllocationSize);
-
-  params->assign(ionParams.array, ionParams.array + sizeof(ionParams));
-}
diff --git a/codec2/vndk/bufferpool/vts/allocator.h b/codec2/vndk/bufferpool/vts/allocator.h
deleted file mode 100644
index b88d074..0000000
--- a/codec2/vndk/bufferpool/vts/allocator.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef VTS_VNDK_HIDL_BUFFERPOOL_V1_0_ALLOCATOR_H
-#define VTS_VNDK_HIDL_BUFFERPOOL_V1_0_ALLOCATOR_H
-
-#include <bufferpool/BufferPoolTypes.h>
-
-using android::hardware::media::bufferpool::V1_0::ResultStatus;
-using android::hardware::media::bufferpool::V1_0::implementation::
-    BufferPoolAllocation;
-using android::hardware::media::bufferpool::V1_0::implementation::
-    BufferPoolAllocator;
-
-// buffer allocator for the tests
-class VtsBufferPoolAllocator : public BufferPoolAllocator {
- public:
-  VtsBufferPoolAllocator(const std::shared_ptr<C2Allocator> &allocator)
-      : mAllocator(allocator) {}
-
-  ~VtsBufferPoolAllocator() override {}
-
-  ResultStatus allocate(const std::vector<uint8_t> &params,
-                        std::shared_ptr<BufferPoolAllocation> *alloc,
-                        size_t *allocSize) override;
-
-  bool compatible(const std::vector<uint8_t> &newParams,
-                  const std::vector<uint8_t> &oldParams) override;
-
- private:
-  const std::shared_ptr<C2Allocator> mAllocator;
-};
-
-// retrieve buffer allocator paramters
-void getVtsAllocatorParams(std::vector<uint8_t> *params);
-
-#endif  // VTS_VNDK_HIDL_BUFFERPOOL_V1_0_ALLOCATOR_H
diff --git a/codec2/vndk/bufferpool/vts/multi.cpp b/codec2/vndk/bufferpool/vts/multi.cpp
deleted file mode 100644
index 71ca6f1..0000000
--- a/codec2/vndk/bufferpool/vts/multi.cpp
+++ /dev/null
@@ -1,228 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "buffferpool_unit_test"
-
-#include <gtest/gtest.h>
-
-#include <C2AllocatorIon.h>
-#include <C2Buffer.h>
-#include <C2PlatformSupport.h>
-#include <android-base/logging.h>
-#include <binder/ProcessState.h>
-#include <bufferpool/ClientManager.h>
-#include <hidl/HidlSupport.h>
-#include <hidl/HidlTransportSupport.h>
-#include <hidl/LegacySupport.h>
-#include <hidl/Status.h>
-#include <signal.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-#include <iostream>
-#include <memory>
-#include <vector>
-#include "allocator.h"
-
-using android::C2AllocatorIon;
-using android::C2PlatformAllocatorStore;
-using android::hardware::configureRpcThreadpool;
-using android::hardware::hidl_handle;
-using android::hardware::media::bufferpool::V1_0::IClientManager;
-using android::hardware::media::bufferpool::V1_0::ResultStatus;
-using android::hardware::media::bufferpool::V1_0::implementation::BufferId;
-using android::hardware::media::bufferpool::V1_0::implementation::ClientManager;
-using android::hardware::media::bufferpool::V1_0::implementation::ConnectionId;
-using android::hardware::media::bufferpool::V1_0::implementation::TransactionId;
-using android::hardware::media::bufferpool::BufferPoolData;
-
-namespace {
-
-// communication message types between processes.
-enum PipeCommand : int32_t {
-    INIT_OK = 0,
-    INIT_ERROR,
-    SEND,
-    RECEIVE_OK,
-    RECEIVE_ERROR,
-};
-
-// communication message between processes.
-union PipeMessage {
-    struct  {
-        int32_t command;
-        BufferId bufferId;
-        ConnectionId connectionId;
-        TransactionId transactionId;
-        int64_t  timestampUs;
-    } data;
-    char array[0];
-};
-
-// media.bufferpool test setup
-class BufferpoolMultiTest : public ::testing::Test {
- public:
-  virtual void SetUp() override {
-    ResultStatus status;
-    mReceiverPid = -1;
-    mConnectionValid = false;
-
-    ASSERT_TRUE(pipe(mCommandPipeFds) == 0);
-    ASSERT_TRUE(pipe(mResultPipeFds) == 0);
-
-    mReceiverPid = fork();
-    ASSERT_TRUE(mReceiverPid >= 0);
-
-    if (mReceiverPid == 0) {
-      doReceiver();
-      // In order to ignore gtest behaviour, wait for being killed from
-      // tearDown
-      pause();
-    }
-
-    mManager = ClientManager::getInstance();
-    ASSERT_NE(mManager, nullptr);
-
-    std::shared_ptr<C2Allocator> allocator =
-        std::make_shared<C2AllocatorIon>(C2PlatformAllocatorStore::ION);
-    ASSERT_TRUE((bool)allocator);
-
-    mAllocator = std::make_shared<VtsBufferPoolAllocator>(allocator);
-    ASSERT_TRUE((bool)mAllocator);
-
-    status = mManager->create(mAllocator, &mConnectionId);
-    ASSERT_TRUE(status == ResultStatus::OK);
-    mConnectionValid = true;
-  }
-
-  virtual void TearDown() override {
-    if (mReceiverPid > 0) {
-      kill(mReceiverPid, SIGKILL);
-      int wstatus;
-      wait(&wstatus);
-    }
-
-    if (mConnectionValid) {
-      mManager->close(mConnectionId);
-    }
-  }
-
- protected:
-  static void description(const std::string& description) {
-    RecordProperty("description", description);
-  }
-
-  android::sp<ClientManager> mManager;
-  std::shared_ptr<BufferPoolAllocator> mAllocator;
-  bool mConnectionValid;
-  ConnectionId mConnectionId;
-  pid_t mReceiverPid;
-  int mCommandPipeFds[2];
-  int mResultPipeFds[2];
-
-  bool sendMessage(int *pipes, const PipeMessage &message) {
-    int ret = write(pipes[1], message.array, sizeof(PipeMessage));
-    return ret == sizeof(PipeMessage);
-  }
-
-  bool receiveMessage(int *pipes, PipeMessage *message) {
-    int ret = read(pipes[0], message->array, sizeof(PipeMessage));
-    return ret == sizeof(PipeMessage);
-  }
-
-  void doReceiver() {
-    configureRpcThreadpool(1, false);
-    PipeMessage message;
-    mManager = ClientManager::getInstance();
-    if (!mManager) {
-      message.data.command = PipeCommand::INIT_ERROR;
-      sendMessage(mResultPipeFds, message);
-      return;
-    }
-    android::status_t status = mManager->registerAsService();
-    if (status != android::OK) {
-      message.data.command = PipeCommand::INIT_ERROR;
-      sendMessage(mResultPipeFds, message);
-      return;
-    }
-    message.data.command = PipeCommand::INIT_OK;
-    sendMessage(mResultPipeFds, message);
-
-    receiveMessage(mCommandPipeFds, &message);
-    {
-      native_handle_t *rhandle = nullptr;
-      std::shared_ptr<BufferPoolData> rbuffer;
-      ResultStatus status = mManager->receive(
-          message.data.connectionId, message.data.transactionId,
-          message.data.bufferId, message.data.timestampUs, &rhandle, &rbuffer);
-      mManager->close(message.data.connectionId);
-      if (status != ResultStatus::OK) {
-        message.data.command = PipeCommand::RECEIVE_ERROR;
-        sendMessage(mResultPipeFds, message);
-        return;
-      }
-    }
-    message.data.command = PipeCommand::RECEIVE_OK;
-    sendMessage(mResultPipeFds, message);
-  }
-};
-
-// Buffer transfer test between processes.
-TEST_F(BufferpoolMultiTest, TransferBuffer) {
-  ResultStatus status;
-  PipeMessage message;
-
-  ASSERT_TRUE(receiveMessage(mResultPipeFds, &message));
-
-  android::sp<IClientManager> receiver = IClientManager::getService();
-  ConnectionId receiverId;
-  ASSERT_TRUE((bool)receiver);
-
-  status = mManager->registerSender(receiver, mConnectionId, &receiverId);
-  ASSERT_TRUE(status == ResultStatus::OK);
-  {
-    native_handle_t *shandle = nullptr;
-    std::shared_ptr<BufferPoolData> sbuffer;
-    TransactionId transactionId;
-    int64_t postUs;
-    std::vector<uint8_t> vecParams;
-
-    getVtsAllocatorParams(&vecParams);
-    status = mManager->allocate(mConnectionId, vecParams, &shandle, &sbuffer);
-    ASSERT_TRUE(status == ResultStatus::OK);
-
-    status = mManager->postSend(receiverId, sbuffer, &transactionId, &postUs);
-    ASSERT_TRUE(status == ResultStatus::OK);
-
-    message.data.command = PipeCommand::SEND;
-    message.data.bufferId = sbuffer->mId;
-    message.data.connectionId = receiverId;
-    message.data.transactionId = transactionId;
-    message.data.timestampUs = postUs;
-    sendMessage(mCommandPipeFds, message);
-  }
-  EXPECT_TRUE(receiveMessage(mResultPipeFds, &message));
-}
-
-}  // anonymous namespace
-
-int main(int argc, char** argv) {
-  setenv("TREBLE_TESTING_OVERRIDE", "true", true);
-  ::testing::InitGoogleTest(&argc, argv);
-  int status = RUN_ALL_TESTS();
-  LOG(INFO) << "Test result = " << status;
-  return status;
-}
diff --git a/codec2/vndk/bufferpool/vts/single.cpp b/codec2/vndk/bufferpool/vts/single.cpp
deleted file mode 100644
index 474f6b6..0000000
--- a/codec2/vndk/bufferpool/vts/single.cpp
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "buffferpool_unit_test"
-
-#include <gtest/gtest.h>
-
-#include <C2AllocatorIon.h>
-#include <C2Buffer.h>
-#include <C2PlatformSupport.h>
-#include <android-base/logging.h>
-#include <binder/ProcessState.h>
-#include <bufferpool/ClientManager.h>
-#include <hidl/HidlSupport.h>
-#include <hidl/HidlTransportSupport.h>
-#include <hidl/LegacySupport.h>
-#include <hidl/Status.h>
-#include <unistd.h>
-#include <iostream>
-#include <memory>
-#include <vector>
-#include "allocator.h"
-
-using android::C2AllocatorIon;
-using android::C2PlatformAllocatorStore;
-using android::hardware::hidl_handle;
-using android::hardware::media::bufferpool::V1_0::ResultStatus;
-using android::hardware::media::bufferpool::V1_0::implementation::BufferId;
-using android::hardware::media::bufferpool::V1_0::implementation::ClientManager;
-using android::hardware::media::bufferpool::V1_0::implementation::ConnectionId;
-using android::hardware::media::bufferpool::V1_0::implementation::TransactionId;
-using android::hardware::media::bufferpool::BufferPoolData;
-
-namespace {
-
-// Number of iteration for buffer allocation test.
-constexpr static int kNumAllocationTest = 3;
-
-// Number of iteration for buffer recycling test.
-constexpr static int kNumRecycleTest = 3;
-
-// media.bufferpool test setup
-class BufferpoolSingleTest : public ::testing::Test {
- public:
-  virtual void SetUp() override {
-    ResultStatus status;
-    mConnectionValid = false;
-
-    mManager = ClientManager::getInstance();
-    ASSERT_NE(mManager, nullptr);
-
-    std::shared_ptr<C2Allocator> allocator =
-        std::make_shared<C2AllocatorIon>(C2PlatformAllocatorStore::ION);
-    ASSERT_TRUE((bool)allocator);
-
-    mAllocator = std::make_shared<VtsBufferPoolAllocator>(allocator);
-    ASSERT_TRUE((bool)mAllocator);
-
-    status = mManager->create(mAllocator, &mConnectionId);
-    ASSERT_TRUE(status == ResultStatus::OK);
-
-    mConnectionValid = true;
-
-    status = mManager->registerSender(mManager, mConnectionId, &mReceiverId);
-    ASSERT_TRUE(status == ResultStatus::ALREADY_EXISTS &&
-                mReceiverId == mConnectionId);
-  }
-
-  virtual void TearDown() override {
-    if (mConnectionValid) {
-      mManager->close(mConnectionId);
-    }
-  }
-
- protected:
-  static void description(const std::string& description) {
-    RecordProperty("description", description);
-  }
-
-  android::sp<ClientManager> mManager;
-  std::shared_ptr<BufferPoolAllocator> mAllocator;
-  bool mConnectionValid;
-  ConnectionId mConnectionId;
-  ConnectionId mReceiverId;
-
-};
-
-// Buffer allocation test.
-// Check whether each buffer allocation is done successfully with
-// unique buffer id.
-TEST_F(BufferpoolSingleTest, AllocateBuffer) {
-  ResultStatus status;
-  std::vector<uint8_t> vecParams;
-  getVtsAllocatorParams(&vecParams);
-
-  std::shared_ptr<BufferPoolData> buffer[kNumAllocationTest];
-  native_handle_t *allocHandle = nullptr;
-  for (int i = 0; i < kNumAllocationTest; ++i) {
-    status = mManager->allocate(mConnectionId, vecParams, &allocHandle, &buffer[i]);
-    ASSERT_TRUE(status == ResultStatus::OK);
-  }
-  for (int i = 0; i < kNumAllocationTest; ++i) {
-    for (int j = i + 1; j < kNumAllocationTest; ++j) {
-      ASSERT_TRUE(buffer[i]->mId != buffer[j]->mId);
-    }
-  }
-  EXPECT_TRUE(kNumAllocationTest > 1);
-}
-
-// Buffer recycle test.
-// Check whether de-allocated buffers are recycled.
-TEST_F(BufferpoolSingleTest, RecycleBuffer) {
-  ResultStatus status;
-  std::vector<uint8_t> vecParams;
-  getVtsAllocatorParams(&vecParams);
-
-  BufferId bid[kNumRecycleTest];
-  for (int i = 0; i < kNumRecycleTest; ++i) {
-    std::shared_ptr<BufferPoolData> buffer;
-    native_handle_t *allocHandle = nullptr;
-    status = mManager->allocate(mConnectionId, vecParams, &allocHandle, &buffer);
-    ASSERT_TRUE(status == ResultStatus::OK);
-    bid[i] = buffer->mId;
-  }
-  for (int i = 1; i < kNumRecycleTest; ++i) {
-    ASSERT_TRUE(bid[i - 1] == bid[i]);
-  }
-  EXPECT_TRUE(kNumRecycleTest > 1);
-}
-
-// Buffer transfer test.
-// Check whether buffer is transferred to another client successfully.
-TEST_F(BufferpoolSingleTest, TransferBuffer) {
-  ResultStatus status;
-  std::vector<uint8_t> vecParams;
-  getVtsAllocatorParams(&vecParams);
-  std::shared_ptr<BufferPoolData> sbuffer, rbuffer;
-  native_handle_t *allocHandle = nullptr;
-  native_handle_t *recvHandle = nullptr;
-
-  TransactionId transactionId;
-  int64_t postUs;
-
-  status = mManager->allocate(mConnectionId, vecParams, &allocHandle, &sbuffer);
-  ASSERT_TRUE(status == ResultStatus::OK);
-  status = mManager->postSend(mReceiverId, sbuffer, &transactionId, &postUs);
-  ASSERT_TRUE(status == ResultStatus::OK);
-  status = mManager->receive(mReceiverId, transactionId, sbuffer->mId, postUs,
-                             &recvHandle, &rbuffer);
-  EXPECT_TRUE(status == ResultStatus::OK);
-}
-
-}  // anonymous namespace
-
-int main(int argc, char** argv) {
-  ::testing::InitGoogleTest(&argc, argv);
-  int status = RUN_ALL_TESTS();
-  LOG(INFO) << "Test result = " << status;
-  return status;
-}
diff --git a/codec2/vndk/include/C2BqBufferPriv.h b/codec2/vndk/include/C2BqBufferPriv.h
index 9271a71..0141f62 100644
--- a/codec2/vndk/include/C2BqBufferPriv.h
+++ b/codec2/vndk/include/C2BqBufferPriv.h
@@ -20,7 +20,7 @@
 #include <functional>
 
 #include <C2Buffer.h>
-#include <media/stagefright/bqhelper/WGraphicBufferProducer.h>
+#include <gui/bufferqueue/1.0/WGraphicBufferProducer.h>
 
 class C2BufferQueueBlockPool : public C2BlockPool {
 public:
diff --git a/codec2/vndk/platform/C2BqBuffer.cpp b/codec2/vndk/platform/C2BqBuffer.cpp
index 7bf3d64..90eba49 100644
--- a/codec2/vndk/platform/C2BqBuffer.cpp
+++ b/codec2/vndk/platform/C2BqBuffer.cpp
@@ -18,7 +18,7 @@
 #define LOG_TAG "C2BqBuffer"
 #include <utils/Log.h>
 
-#include <gui/BufferQueueDefs.h>
+#include <ui/BufferQueueDefs.h>
 #include <list>
 #include <map>
 #include <mutex>
diff --git a/media/Android.bp b/media/Android.bp
deleted file mode 100644
index 573d3ce..0000000
--- a/media/Android.bp
+++ /dev/null
@@ -1,4 +0,0 @@
-subdirs = [
-    "codecs",
-    "sfplugin",
-]
diff --git a/media/codecs/Android.bp b/media/codecs/Android.bp
deleted file mode 100644
index e8176cf..0000000
--- a/media/codecs/Android.bp
+++ /dev/null
@@ -1,3 +0,0 @@
-subdirs = [
-    "*",
-]
diff --git a/media/codecs/aac/C2SoftAacDec.cpp b/media/codecs/aac/C2SoftAacDec.cpp
index 02be0ea..c7c8442 100644
--- a/media/codecs/aac/C2SoftAacDec.cpp
+++ b/media/codecs/aac/C2SoftAacDec.cpp
@@ -239,10 +239,10 @@
         const std::shared_ptr<IntfImpl> &intfImpl)
     : SimpleC2Component(std::make_shared<SimpleInterface<IntfImpl>>(name, id, intfImpl)),
       mIntf(intfImpl),
-      mAACDecoder(NULL),
-      mStreamInfo(NULL),
+      mAACDecoder(nullptr),
+      mStreamInfo(nullptr),
       mSignalledError(false),
-      mOutputDelayRingBuffer(NULL) {
+      mOutputDelayRingBuffer(nullptr) {
 }
 
 C2SoftAacDec::~C2SoftAacDec() {
@@ -279,11 +279,11 @@
 void C2SoftAacDec::onRelease() {
     if (mAACDecoder) {
         aacDecoder_Close(mAACDecoder);
-        mAACDecoder = NULL;
+        mAACDecoder = nullptr;
     }
     if (mOutputDelayRingBuffer) {
         delete[] mOutputDelayRingBuffer;
-        mOutputDelayRingBuffer = NULL;
+        mOutputDelayRingBuffer = nullptr;
     }
 }
 
@@ -291,9 +291,9 @@
     ALOGV("initDecoder()");
     status_t status = UNKNOWN_ERROR;
     mAACDecoder = aacDecoder_Open(TT_MP4_ADIF, /* num layers */ 1);
-    if (mAACDecoder != NULL) {
+    if (mAACDecoder != nullptr) {
         mStreamInfo = aacDecoder_GetStreamInfo(mAACDecoder);
-        if (mStreamInfo != NULL) {
+        if (mStreamInfo != nullptr) {
             status = OK;
         }
     }
@@ -305,7 +305,7 @@
     mOutputDelayRingBufferReadPos = 0;
     mOutputDelayRingBufferFilled = 0;
 
-    if (mAACDecoder == NULL) {
+    if (mAACDecoder == nullptr) {
         ALOGE("AAC decoder is null. TODO: Can not call aacDecoder_SetParam in the following code");
     }
 
@@ -401,7 +401,7 @@
             && (mOutputDelayRingBufferWritePos < mOutputDelayRingBufferReadPos
                     || mOutputDelayRingBufferWritePos >= mOutputDelayRingBufferReadPos + numSamples)) {
         // faster memcopy loop without checks, if the preconditions allow this
-        if (samples != 0) {
+        if (samples != nullptr) {
             for (int32_t i = 0; i < numSamples; i++) {
                 samples[i] = mOutputDelayRingBuffer[mOutputDelayRingBufferReadPos++];
             }
@@ -415,7 +415,7 @@
         ALOGV("slow C2SoftAacDec::outputDelayRingBufferGetSamples()");
 
         for (int32_t i = 0; i < numSamples; i++) {
-            if (samples != 0) {
+            if (samples != nullptr) {
                 samples[i] = mOutputDelayRingBuffer[mOutputDelayRingBufferReadPos];
             }
             mOutputDelayRingBufferReadPos++;
@@ -486,7 +486,6 @@
                         numSamples * sizeof(int16_t), usage, &block);
                 if (err != C2_OK) {
                     ALOGD("failed to fetch a linear block (%d)", err);
-                    mSignalledError = true;
                     return std::bind(fillEmptyWork, _1, C2_NO_MEMORY);
                 }
                 C2WriteView wView = block->map().get();
@@ -524,9 +523,12 @@
 void C2SoftAacDec::process(
         const std::unique_ptr<C2Work> &work,
         const std::shared_ptr<C2BlockPool> &pool) {
-    work->workletsProcessed = 0u;
+    // Initialize output work
     work->result = C2_OK;
+    work->workletsProcessed = 1u;
     work->worklets.front()->output.configUpdate.clear();
+    work->worklets.front()->output.flags = work->input.flags;
+
     if (mSignalledError) {
         return;
     }
@@ -567,13 +569,12 @@
         if (decoderErr != AAC_DEC_OK) {
             ALOGE("aacDecoder_ConfigRaw decoderErr = 0x%4.4x", decoderErr);
             mSignalledError = true;
-            // TODO: error
+            work->result = C2_CORRUPTED;
             return;
         }
         work->worklets.front()->output.flags = work->input.flags;
         work->worklets.front()->output.ordinal = work->input.ordinal;
         work->worklets.front()->output.buffers.clear();
-        work->workletsProcessed = 1u;
         return;
     }
 
@@ -629,7 +630,7 @@
 
             if (signalError) {
                 mSignalledError = true;
-                // TODO: notify(OMX_EventError, OMX_ErrorStreamCorrupt, ERROR_MALFORMED, NULL);
+                work->result = C2_CORRUPTED;
                 return;
             }
         } else {
@@ -687,7 +688,7 @@
             if (bytesValid[0] != 0) {
                 ALOGE("bytesValid[0] != 0 should never happen");
                 mSignalledError = true;
-                // TODO: notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
+                work->result = C2_CORRUPTED;
                 return;
             }
 
@@ -698,7 +699,7 @@
                 if (!outputDelayRingBufferPutSamples(tmpOutBuffer,
                         mStreamInfo->frameSize * mStreamInfo->numChannels)) {
                     mSignalledError = true;
-                    // TODO: notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL);
+                    work->result = C2_CORRUPTED;
                     return;
                 }
             } else {
@@ -709,7 +710,7 @@
                 if (!outputDelayRingBufferPutSamples(tmpOutBuffer,
                         mStreamInfo->frameSize * mStreamInfo->numChannels)) {
                     mSignalledError = true;
-                    // TODO: notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL);
+                    work->result = C2_CORRUPTED;
                     return;
                 }
 
@@ -766,8 +767,12 @@
                     C2FrameData &output = work->worklets.front()->output;
                     output.configUpdate.push_back(C2Param::Copy(sampleRateInfo));
                     output.configUpdate.push_back(C2Param::Copy(channelCountInfo));
+                } else {
+                    ALOGE("Config Update failed");
+                    mSignalledError = true;
+                    work->result = C2_CORRUPTED;
+                    return;
                 }
-                // TODO: error handling
             }
             ALOGV("size = %zu", size);
         } while (decoderErr == AAC_DEC_OK);
@@ -776,7 +781,7 @@
     int32_t outputDelay = mStreamInfo->outputDelay * mStreamInfo->numChannels;
 
     mBuffersInfo.push_back(std::move(inInfo));
-
+    work->workletsProcessed = 0u;
     if (!eos && mOutputDelayCompensated < outputDelay) {
         // discard outputDelay at the beginning
         int32_t toCompensate = outputDelay - mOutputDelayCompensated;
@@ -784,7 +789,7 @@
         if (discard > toCompensate) {
             discard = toCompensate;
         }
-        int32_t discarded = outputDelayRingBufferGetSamples(0, discard);
+        int32_t discarded = outputDelayRingBufferGetSamples(nullptr, discard);
         mOutputDelayCompensated += discarded;
         return;
     }
@@ -849,7 +854,7 @@
         if (avail > mStreamInfo->frameSize * mStreamInfo->numChannels) {
             avail = mStreamInfo->frameSize * mStreamInfo->numChannels;
         }
-        int32_t ns = outputDelayRingBufferGetSamples(0, avail);
+        int32_t ns = outputDelayRingBufferGetSamples(nullptr, avail);
         if (ns != avail) {
             ALOGW("not a complete frame of samples available");
             break;
diff --git a/media/codecs/aac/C2SoftAacEnc.cpp b/media/codecs/aac/C2SoftAacEnc.cpp
index 889016a..87730ae 100644
--- a/media/codecs/aac/C2SoftAacEnc.cpp
+++ b/media/codecs/aac/C2SoftAacEnc.cpp
@@ -144,17 +144,17 @@
         const std::shared_ptr<IntfImpl> &intfImpl)
     : SimpleC2Component(std::make_shared<SimpleInterface<IntfImpl>>(name, id, intfImpl)),
       mIntf(intfImpl),
-      mAACEncoder(NULL),
+      mAACEncoder(nullptr),
       mSBRMode(-1),
       mSBRRatio(0),
       mAACProfile(AOT_AAC_LC),
       mNumBytesPerInputFrame(0u),
       mOutBufferSize(0u),
       mSentCodecSpecificData(false),
-      mInputTimeSet(false),
       mInputSize(0),
-      mInputTimeUs(0),
-      mSignalledError(false) {
+      mInputTimeUs(-1ll),
+      mSignalledError(false),
+      mOutIndex(0u) {
 }
 
 C2SoftAacEnc::~C2SoftAacEnc() {
@@ -176,9 +176,8 @@
 
 c2_status_t C2SoftAacEnc::onStop() {
     mSentCodecSpecificData = false;
-    mInputTimeSet = false;
     mInputSize = 0u;
-    mInputTimeUs = 0;
+    mInputTimeUs = -1ll;
     mSignalledError = false;
     return C2_OK;
 }
@@ -194,9 +193,7 @@
 
 c2_status_t C2SoftAacEnc::onFlush_sm() {
     mSentCodecSpecificData = false;
-    mInputTimeSet = false;
     mInputSize = 0u;
-    mInputTimeUs = 0;
     return C2_OK;
 }
 
@@ -285,8 +282,10 @@
 void C2SoftAacEnc::process(
         const std::unique_ptr<C2Work> &work,
         const std::shared_ptr<C2BlockPool> &pool) {
+    // Initialize output work
     work->result = C2_OK;
-    work->workletsProcessed = 0u;
+    work->workletsProcessed = 1u;
+    work->worklets.front()->output.flags = work->input.flags;
 
     if (mSignalledError) {
         return;
@@ -300,10 +299,10 @@
         // The very first thing we want to output is the codec specific
         // data.
 
-        if (AACENC_OK != aacEncEncode(mAACEncoder, NULL, NULL, NULL, NULL)) {
+        if (AACENC_OK != aacEncEncode(mAACEncoder, nullptr, nullptr, nullptr, nullptr)) {
             ALOGE("Unable to initialize encoder for profile / sample-rate / bit-rate / channels");
-            // TODO: notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
             mSignalledError = true;
+            work->result = C2_CORRUPTED;
             return;
         }
 
@@ -316,14 +315,19 @@
         AACENC_InfoStruct encInfo;
         if (AACENC_OK != aacEncInfo(mAACEncoder, &encInfo)) {
             ALOGE("Failed to get AAC encoder info");
-            // TODO: notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
             mSignalledError = true;
+            work->result = C2_CORRUPTED;
             return;
         }
 
         std::unique_ptr<C2StreamCsdInfo::output> csd =
             C2StreamCsdInfo::output::AllocUnique(encInfo.confSize, 0u);
-        // TODO: check NO_MEMORY
+        if (!csd) {
+            ALOGE("CSD allocation failed");
+            mSignalledError = true;
+            work->result = C2_NO_MEMORY;
+            return;
+        }
         memcpy(csd->m.value, encInfo.confBuf, encInfo.confSize);
         ALOGV("put csd");
 #if defined(LOG_NDEBUG) && !LOG_NDEBUG
@@ -333,6 +337,7 @@
 
         mOutBufferSize = encInfo.maxOutBufBytes;
         mNumBytesPerInputFrame = encInfo.frameLength * channelCount * sizeof(int16_t);
+        mInputTimeUs = work->input.ordinal.timestamp;
 
         mSentCodecSpecificData = true;
     }
@@ -346,11 +351,6 @@
         data = view.data();
         capacity = view.capacity();
     }
-    if (!mInputTimeSet && capacity > 0) {
-        mInputTimeUs = work->input.ordinal.timestamp;
-        mInputTimeSet = true;
-    }
-    uint64_t timestamp = mInputTimeUs.peeku();
 
     size_t numFrames = (capacity + mInputSize + (eos ? mNumBytesPerInputFrame - 1 : 0))
             / mNumBytesPerInputFrame;
@@ -358,22 +358,11 @@
           capacity, mInputSize, numFrames, mNumBytesPerInputFrame);
 
     std::shared_ptr<C2LinearBlock> block;
+    std::shared_ptr<C2Buffer> buffer;
     std::unique_ptr<C2WriteView> wView;
     uint8_t *outPtr = temp;
     size_t outAvailable = 0u;
-
-    if (numFrames) {
-        C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
-        // TODO: error handling, proper usage, etc.
-        c2_status_t err = pool->fetchLinearBlock(mOutBufferSize * numFrames, usage, &block);
-        if (err != C2_OK) {
-            ALOGE("err = %d", err);
-        }
-
-        wView.reset(new C2WriteView(block->map().get()));
-        outPtr = wView->data();
-        outAvailable = wView->size();
-    }
+    uint64_t inputIndex = work->input.ordinal.frameIndex.peeku();
 
     AACENC_InArgs inargs;
     AACENC_OutArgs outargs;
@@ -405,15 +394,60 @@
     outBufDesc.bufSizes          = outBufferSize;
     outBufDesc.bufElSizes        = outBufferElSize;
 
-    // Encode the mInputFrame, which is treated as a modulo buffer
     AACENC_ERROR encoderErr = AACENC_OK;
-    size_t nOutputBytes = 0;
+
+    class FillWork {
+    public:
+        FillWork(uint32_t flags, C2WorkOrdinalStruct ordinal,
+                 const std::shared_ptr<C2Buffer> &buffer)
+            : mFlags(flags), mOrdinal(ordinal), mBuffer(buffer) {
+        }
+        ~FillWork() = default;
+
+        void operator()(const std::unique_ptr<C2Work> &work) {
+            work->worklets.front()->output.flags = (C2FrameData::flags_t)mFlags;
+            work->worklets.front()->output.buffers.clear();
+            work->worklets.front()->output.ordinal = mOrdinal;
+            work->workletsProcessed = 1u;
+            work->result = C2_OK;
+            if (mBuffer) {
+                work->worklets.front()->output.buffers.push_back(mBuffer);
+            }
+            ALOGV("timestamp = %lld, index = %lld, w/%s buffer",
+                  mOrdinal.timestamp.peekll(),
+                  mOrdinal.frameIndex.peekll(),
+                  mBuffer ? "" : "o");
+        }
+
+    private:
+        const uint32_t mFlags;
+        const C2WorkOrdinalStruct mOrdinal;
+        const std::shared_ptr<C2Buffer> mBuffer;
+    };
+
+    C2WorkOrdinalStruct outOrdinal = work->input.ordinal;
 
     while (encoderErr == AACENC_OK && inargs.numInSamples > 0) {
+        if (numFrames && !block) {
+            C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
+            // TODO: error handling, proper usage, etc.
+            c2_status_t err = pool->fetchLinearBlock(mOutBufferSize, usage, &block);
+            if (err != C2_OK) {
+                ALOGE("fetchLinearBlock failed : err = %d", err);
+                work->result = C2_NO_MEMORY;
+                return;
+            }
+
+            wView.reset(new C2WriteView(block->map().get()));
+            outPtr = wView->data();
+            outAvailable = wView->size();
+            --numFrames;
+        }
+
         memset(&outargs, 0, sizeof(outargs));
 
         outBuffer[0] = outPtr;
-        outBufferSize[0] = outAvailable - nOutputBytes;
+        outBufferSize[0] = outAvailable;
 
         encoderErr = aacEncEncode(mAACEncoder,
                                   &inBufDesc,
@@ -422,17 +456,32 @@
                                   &outargs);
 
         if (encoderErr == AACENC_OK) {
+            if (buffer) {
+                outOrdinal.frameIndex = mOutIndex++;
+                outOrdinal.timestamp = mInputTimeUs;
+                cloneAndSend(
+                        inputIndex,
+                        work,
+                        FillWork(C2FrameData::FLAG_INCOMPLETE, outOrdinal, buffer));
+                buffer.reset();
+            }
+
             if (outargs.numOutBytes > 0) {
                 mInputSize = 0;
                 int consumed = (capacity / sizeof(int16_t)) - inargs.numInSamples
                         + outargs.numInSamples;
                 mInputTimeUs = work->input.ordinal.timestamp
                         + (consumed * 1000000ll / channelCount / sampleRate);
+                buffer = createLinearBuffer(block, 0, outargs.numOutBytes);
+#if defined(LOG_NDEBUG) && !LOG_NDEBUG
+                hexdump(outPtr, std::min(outargs.numOutBytes, 256));
+#endif
+                outPtr = temp;
+                outAvailable = 0;
+                block.reset();
             } else {
                 mInputSize += outargs.numInSamples * sizeof(int16_t);
             }
-            outPtr += outargs.numOutBytes;
-            nOutputBytes += outargs.numOutBytes;
 
             if (outargs.numInSamples > 0) {
                 inBuffer[0] = (int16_t *)inBuffer[0] + outargs.numInSamples;
@@ -440,15 +489,31 @@
                 inargs.numInSamples -= outargs.numInSamples;
             }
         }
-        ALOGV("encoderErr = %d nOutputBytes = %zu; mInputSize = %zu inargs.numInSamples = %d",
-              encoderErr, nOutputBytes, mInputSize, inargs.numInSamples);
+        ALOGV("encoderErr = %d mInputSize = %zu inargs.numInSamples = %d, mInputTimeUs = %lld",
+              encoderErr, mInputSize, inargs.numInSamples, mInputTimeUs.peekll());
     }
 
     if (eos && inBufferSize[0] > 0) {
+        if (numFrames && !block) {
+            C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
+            // TODO: error handling, proper usage, etc.
+            c2_status_t err = pool->fetchLinearBlock(mOutBufferSize, usage, &block);
+            if (err != C2_OK) {
+                ALOGE("fetchLinearBlock failed : err = %d", err);
+                work->result = C2_NO_MEMORY;
+                return;
+            }
+
+            wView.reset(new C2WriteView(block->map().get()));
+            outPtr = wView->data();
+            outAvailable = wView->size();
+            --numFrames;
+        }
+
         memset(&outargs, 0, sizeof(outargs));
 
         outBuffer[0] = outPtr;
-        outBufferSize[0] = outAvailable - nOutputBytes;
+        outBufferSize[0] = outAvailable;
 
         // Flush
         inargs.numInSamples = -1;
@@ -458,34 +523,20 @@
                            &outBufDesc,
                            &inargs,
                            &outargs);
-
-        nOutputBytes += outargs.numOutBytes;
     }
 
-    work->worklets.front()->output.flags =
-        (C2FrameData::flags_t)(eos ? C2FrameData::FLAG_END_OF_STREAM : 0);
-    work->worklets.front()->output.buffers.clear();
-    work->worklets.front()->output.ordinal = work->input.ordinal;
-    work->worklets.front()->output.ordinal.timestamp = timestamp;
-    work->workletsProcessed = 1u;
-    if (nOutputBytes) {
-        work->worklets.front()->output.buffers.push_back(
-                createLinearBuffer(block, 0, nOutputBytes));
-    }
-
-#if 0
-    ALOGI("sending %d bytes of data (time = %lld us, flags = 0x%08lx)",
-          nOutputBytes, mInputTimeUs.peekll(), outHeader->nFlags);
-
-    hexdump(outHeader->pBuffer + outHeader->nOffset, outHeader->nFilledLen);
-#endif
+    outOrdinal.frameIndex = mOutIndex++;
+    outOrdinal.timestamp = mInputTimeUs;
+    FillWork((C2FrameData::flags_t)(eos ? C2FrameData::FLAG_END_OF_STREAM : 0),
+             outOrdinal, buffer)(work);
 }
 
 c2_status_t C2SoftAacEnc::drain(
         uint32_t drainMode,
         const std::shared_ptr<C2BlockPool> &pool) {
     switch (drainMode) {
-        case DRAIN_COMPONENT_NO_EOS:  // fall-through
+        case DRAIN_COMPONENT_NO_EOS:
+            [[fallthrough]];
         case NO_DRAIN:
             // no-op
             return C2_OK;
@@ -499,9 +550,7 @@
 
     (void)pool;
     mSentCodecSpecificData = false;
-    mInputTimeSet = false;
     mInputSize = 0u;
-    mInputTimeUs = 0;
 
     // TODO: we don't have any pending work at this time to drain.
     return C2_OK;
diff --git a/media/codecs/aac/C2SoftAacEnc.h b/media/codecs/aac/C2SoftAacEnc.h
index e6e7cf0..82fb438 100644
--- a/media/codecs/aac/C2SoftAacEnc.h
+++ b/media/codecs/aac/C2SoftAacEnc.h
@@ -17,6 +17,8 @@
 #ifndef ANDROID_C2_SOFT_AAC_ENC_H_
 #define ANDROID_C2_SOFT_AAC_ENC_H_
 
+#include <atomic>
+
 #include <SimpleC2Component.h>
 
 #include "aacenc_lib.h"
@@ -55,11 +57,11 @@
     UINT mOutBufferSize;
 
     bool mSentCodecSpecificData;
-    bool mInputTimeSet;
     size_t mInputSize;
     c2_cntr64_t mInputTimeUs;
 
     bool mSignalledError;
+    std::atomic_uint64_t mOutIndex;
 
     status_t initEncoder();
 
diff --git a/media/codecs/amr_nb_wb/C2SoftAmrDec.cpp b/media/codecs/amr_nb_wb/C2SoftAmrDec.cpp
index 400149a..c591e21 100644
--- a/media/codecs/amr_nb_wb/C2SoftAmrDec.cpp
+++ b/media/codecs/amr_nb_wb/C2SoftAmrDec.cpp
@@ -245,8 +245,11 @@
 void C2SoftAmrDec::process(
         const std::unique_ptr<C2Work> &work,
         const std::shared_ptr<C2BlockPool> &pool) {
+    // Initialize output work
     work->result = C2_OK;
-    work->workletsProcessed = 0u;
+    work->workletsProcessed = 1u;
+    work->worklets.front()->output.flags = work->input.flags;
+
     if (mSignalledError || mSignalledOutputEos) {
         work->result = C2_BAD_VALUE;
         return;
@@ -270,7 +273,6 @@
         work->worklets.front()->output.flags = work->input.flags;
         work->worklets.front()->output.buffers.clear();
         work->worklets.front()->output.ordinal = work->input.ordinal;
-        work->workletsProcessed = 1u;
         if (eos) {
             mSignalledOutputEos = true;
             ALOGV("signalled EOS");
@@ -368,7 +370,6 @@
     work->worklets.front()->output.buffers.clear();
     work->worklets.front()->output.buffers.push_back(createLinearBuffer(block));
     work->worklets.front()->output.ordinal = work->input.ordinal;
-    work->workletsProcessed = 1u;
     if (eos) {
         mSignalledOutputEos = true;
         ALOGV("signalled EOS");
diff --git a/media/codecs/amr_nb_wb/C2SoftAmrNbEnc.cpp b/media/codecs/amr_nb_wb/C2SoftAmrNbEnc.cpp
index b34c3a9..ca21480 100644
--- a/media/codecs/amr_nb_wb/C2SoftAmrNbEnc.cpp
+++ b/media/codecs/amr_nb_wb/C2SoftAmrNbEnc.cpp
@@ -188,8 +188,11 @@
 void C2SoftAmrNbEnc::process(
         const std::unique_ptr<C2Work> &work,
         const std::shared_ptr<C2BlockPool> &pool) {
+    // Initialize output work
     work->result = C2_OK;
-    work->workletsProcessed = 0u;
+    work->workletsProcessed = 1u;
+    work->worklets.front()->output.flags = work->input.flags;
+
     if (mSignalledError || mSignalledOutputEos) {
         work->result = C2_BAD_VALUE;
         return;
diff --git a/media/codecs/amr_nb_wb/C2SoftAmrWbEnc.cpp b/media/codecs/amr_nb_wb/C2SoftAmrWbEnc.cpp
index 1e5378c..be3892f 100644
--- a/media/codecs/amr_nb_wb/C2SoftAmrWbEnc.cpp
+++ b/media/codecs/amr_nb_wb/C2SoftAmrWbEnc.cpp
@@ -271,8 +271,11 @@
 void C2SoftAmrWbEnc::process(
         const std::unique_ptr<C2Work> &work,
         const std::shared_ptr<C2BlockPool> &pool) {
+    // Initialize output work
     work->result = C2_OK;
-    work->workletsProcessed = 0u;
+    work->workletsProcessed = 1u;
+    work->worklets.front()->output.flags = work->input.flags;
+
     if (mSignalledError || mSignalledOutputEos) {
         work->result = C2_BAD_VALUE;
         return;
diff --git a/media/codecs/avc/C2SoftAvcDec.cpp b/media/codecs/avc/C2SoftAvcDec.cpp
index 7f0b725..3e62744 100644
--- a/media/codecs/avc/C2SoftAvcDec.cpp
+++ b/media/codecs/avc/C2SoftAvcDec.cpp
@@ -328,7 +328,8 @@
       mOutBufferFlush(nullptr),
       mIvColorFormat(IV_YUV_420P),
       mWidth(320),
-      mHeight(240) {
+      mHeight(240),
+      mHeaderDecoded(false) {
     GENERATE_FILE_NAMES();
     CREATE_DUMP_FILE(mInFile);
 }
@@ -385,8 +386,10 @@
         }
     }
 
-    ivd_aligned_free(nullptr, mOutBufferFlush);
-    mOutBufferFlush = nullptr;
+    if (mOutBufferFlush) {
+        ivd_aligned_free(nullptr, mOutBufferFlush);
+        mOutBufferFlush = nullptr;
+    }
 
     return C2_OK;
 }
@@ -438,7 +441,7 @@
     return OK;
 }
 
-status_t C2SoftAvcDec::setParams(size_t stride) {
+status_t C2SoftAvcDec::setParams(size_t stride, IVD_VIDEO_DECODE_MODE_T dec_mode) {
     ivd_ctl_set_config_ip_t s_set_dyn_params_ip;
     ivd_ctl_set_config_op_t s_set_dyn_params_op;
 
@@ -448,7 +451,7 @@
     s_set_dyn_params_ip.u4_disp_wd = (UWORD32) stride;
     s_set_dyn_params_ip.e_frm_skip_mode = IVD_SKIP_NONE;
     s_set_dyn_params_ip.e_frm_out_mode = IVD_DISPLAY_FRAME_OUT;
-    s_set_dyn_params_ip.e_vid_dec_mode = IVD_DECODE_FRAME;
+    s_set_dyn_params_ip.e_vid_dec_mode = dec_mode;
     s_set_dyn_params_op.u4_size = sizeof(ivd_ctl_set_config_op_t);
     IV_API_CALL_STATUS_T status = ivdec_api_function(mDecHandle,
                                                      &s_set_dyn_params_ip,
@@ -491,7 +494,7 @@
     mSignalledError = false;
     resetPlugin();
     (void) setNumCores();
-    if (OK != setParams(mStride)) return UNKNOWN_ERROR;
+    if (OK != setParams(mStride, IVD_DECODE_FRAME)) return UNKNOWN_ERROR;
     (void) getVersion();
 
     return OK;
@@ -629,6 +632,7 @@
     mStride = 0;
     (void) setNumCores();
     mSignalledError = false;
+    mHeaderDecoded = false;
 
     return OK;
 }
@@ -682,14 +686,8 @@
         buffer->setInfo(mIntf->getColorAspects_l());
     }
 
-    auto fillWork = [buffer, index](const std::unique_ptr<C2Work> &work) {
-        uint32_t flags = 0;
-        if ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) &&
-                (c2_cntr64_t(index) == work->input.ordinal.frameIndex)) {
-            flags |= C2FrameData::FLAG_END_OF_STREAM;
-            ALOGV("signalling eos");
-        }
-        work->worklets.front()->output.flags = (C2FrameData::flags_t)flags;
+    auto fillWork = [buffer](const std::unique_ptr<C2Work> &work) {
+        work->worklets.front()->output.flags = (C2FrameData::flags_t)0;
         work->worklets.front()->output.buffers.clear();
         work->worklets.front()->output.buffers.push_back(buffer);
         work->worklets.front()->output.ordinal = work->input.ordinal;
@@ -709,7 +707,7 @@
     }
     if (mStride != ALIGN64(mWidth)) {
         mStride = ALIGN64(mWidth);
-        if (OK != setParams(mStride)) return C2_CORRUPTED;
+        if (OK != setParams(mStride, IVD_DECODE_FRAME)) return C2_CORRUPTED;
     }
     if (mOutBlock &&
             (mOutBlock->width() != mStride || mOutBlock->height() != mHeight)) {
@@ -739,8 +737,10 @@
 void C2SoftAvcDec::process(
         const std::unique_ptr<C2Work> &work,
         const std::shared_ptr<C2BlockPool> &pool) {
+    // Initialize output work
     work->result = C2_OK;
     work->workletsProcessed = 0u;
+    work->worklets.front()->output.flags = work->input.flags;
     if (mSignalledError || mSignalledOutputEos) {
         work->result = C2_BAD_VALUE;
         return;
@@ -769,6 +769,7 @@
     while (inPos < inSize) {
         if (C2_OK != ensureDecoderState(pool)) {
             mSignalledError = true;
+            work->workletsProcessed = 1u;
             work->result = C2_CORRUPTED;
             return;
         }
@@ -785,11 +786,18 @@
             if (!setDecodeArgs(&s_decode_ip, &s_decode_op, &rView, &wView,
                                inOffset + inPos, inSize - inPos, workIndex)) {
                 mSignalledError = true;
+                work->workletsProcessed = 1u;
                 work->result = C2_CORRUPTED;
                 return;
             }
+
+            if (false == mHeaderDecoded) {
+                /* Decode header and get dimensions */
+                setParams(mStride, IVD_DECODE_HEADER);
+            }
+
             WORD32 delay;
-            GETTIME(&mTimeStart, NULL);
+            GETTIME(&mTimeStart, nullptr);
             TIME_DIFF(mTimeEnd, mTimeStart, delay);
             (void) ivdec_api_function(mDecHandle, &s_decode_ip, &s_decode_op);
             WORD32 decodeTime;
@@ -800,22 +808,32 @@
         }
         if (IVD_MEM_ALLOC_FAILED == (s_decode_op.u4_error_code & 0xFF)) {
             ALOGE("allocation failure in decoder");
-            work->result = C2_CORRUPTED;
             mSignalledError = true;
+            work->workletsProcessed = 1u;
+            work->result = C2_CORRUPTED;
             return;
         } else if (IVD_STREAM_WIDTH_HEIGHT_NOT_SUPPORTED == (s_decode_op.u4_error_code & 0xFF)) {
             ALOGE("unsupported resolution : %dx%d", mWidth, mHeight);
-            work->result = C2_CORRUPTED;
             mSignalledError = true;
+            work->workletsProcessed = 1u;
+            work->result = C2_CORRUPTED;
             return;
         } else if (IVD_RES_CHANGED == (s_decode_op.u4_error_code & 0xFF)) {
             ALOGV("resolution changed");
             drainInternal(DRAIN_COMPONENT_NO_EOS, pool, work);
             resetDecoder();
             resetPlugin();
-            continue;
+            work->workletsProcessed = 0u;
+
+            /* Decode header and get new dimensions */
+            setParams(mStride, IVD_DECODE_HEADER);
+            (void) ivdec_api_function(mDecHandle, &s_decode_ip, &s_decode_op);
         }
         if (0 < s_decode_op.u4_pic_wd && 0 < s_decode_op.u4_pic_ht) {
+            if (mHeaderDecoded == false) {
+                mHeaderDecoded = true;
+                setParams(ALIGN64(s_decode_op.u4_pic_wd), IVD_DECODE_FRAME);
+            }
             if (s_decode_op.u4_pic_wd != mWidth || s_decode_op.u4_pic_ht != mHeight) {
                 mWidth = s_decode_op.u4_pic_wd;
                 mHeight = s_decode_op.u4_pic_ht;
@@ -823,8 +841,17 @@
 
                 C2VideoSizeStreamInfo::output size(0u, mWidth, mHeight);
                 std::vector<std::unique_ptr<C2SettingResult>> failures;
-                (void)mIntf->config({&size}, C2_MAY_BLOCK, &failures);
-                work->worklets.front()->output.configUpdate.push_back(C2Param::Copy(size));
+                c2_status_t err = mIntf->config({&size}, C2_MAY_BLOCK, &failures);
+                if (err == OK) {
+                    work->worklets.front()->output.configUpdate.push_back(
+                        C2Param::Copy(size));
+                } else {
+                    ALOGE("Cannot set width and height");
+                    mSignalledError = true;
+                    work->workletsProcessed = 1u;
+                    work->result = C2_CORRUPTED;
+                    return;
+                }
                 continue;
             }
         }
@@ -833,6 +860,10 @@
         if (s_decode_op.u4_output_present) {
             finishWork(s_decode_op.u4_ts, work);
         }
+        if (0 == s_decode_op.u4_num_bytes_consumed) {
+            ALOGD("Bytes consumed is zero. Ignoring remaining bytes");
+            break;
+        }
         inPos += s_decode_op.u4_num_bytes_consumed;
         if (hasPicture && (inSize - inPos)) {
             ALOGD("decoded frame in current access nal, ignoring further trailing bytes %d",
@@ -865,6 +896,7 @@
     while (true) {
         if (C2_OK != ensureDecoderState(pool)) {
             mSignalledError = true;
+            work->workletsProcessed = 1u;
             work->result = C2_CORRUPTED;
             return C2_CORRUPTED;
         }
@@ -877,21 +909,18 @@
         ivd_video_decode_op_t s_decode_op;
         if (!setDecodeArgs(&s_decode_ip, &s_decode_op, nullptr, &wView, 0, 0, 0)) {
             mSignalledError = true;
+            work->workletsProcessed = 1u;
             return C2_CORRUPTED;
         }
         (void) ivdec_api_function(mDecHandle, &s_decode_ip, &s_decode_op);
         if (s_decode_op.u4_output_present) {
             finishWork(s_decode_op.u4_ts, work);
         } else {
+            fillEmptyWork(work);
             break;
         }
     }
 
-    if (drainMode == DRAIN_COMPONENT_WITH_EOS &&
-            work && work->workletsProcessed == 0u) {
-        fillEmptyWork(work);
-    }
-
     return C2_OK;
 }
 
diff --git a/media/codecs/avc/C2SoftAvcDec.h b/media/codecs/avc/C2SoftAvcDec.h
index abf0fc6..2127a93 100644
--- a/media/codecs/avc/C2SoftAvcDec.h
+++ b/media/codecs/avc/C2SoftAvcDec.h
@@ -117,7 +117,7 @@
 private:
     status_t createDecoder();
     status_t setNumCores();
-    status_t setParams(size_t stride);
+    status_t setParams(size_t stride, IVD_VIDEO_DECODE_MODE_T dec_mode);
     void getVersion();
     status_t initDecoder();
     bool setDecodeArgs(ivd_video_decode_ip_t *ps_decode_ip,
@@ -162,7 +162,7 @@
     uint32_t mStride;
     bool mSignalledOutputEos;
     bool mSignalledError;
-
+    bool mHeaderDecoded;
     // Color aspects. These are ISO values and are meant to detect changes in aspects to avoid
     // converting them to C2 values for each frame
     struct VuiColorAspects {
diff --git a/media/codecs/avc/C2SoftAvcEnc.cpp b/media/codecs/avc/C2SoftAvcEnc.cpp
index cafda79..bfe745c 100644
--- a/media/codecs/avc/C2SoftAvcEnc.cpp
+++ b/media/codecs/avc/C2SoftAvcEnc.cpp
@@ -216,7 +216,7 @@
         };
 
         uint64_t mbs = uint64_t((size.v.width + 15) / 16) * ((size.v.height + 15) / 16);
-        float mbsPerSec = float(mbs) / frameRate.v.value;
+        float mbsPerSec = float(mbs) * frameRate.v.value;
 
         // Check if the supplied level meets the MB / bitrate requirements. If
         // not, update the level with the lowest level meeting the requirements.
@@ -270,7 +270,7 @@
 
     IV_PROFILE_T getProfile_l() const {
         switch (mProfileLevel->profile) {
-        case PROFILE_AVC_CONSTRAINED_BASELINE:  // fall-through
+        case PROFILE_AVC_CONSTRAINED_BASELINE:  [[fallthrough]];
         case PROFILE_AVC_BASELINE: return IV_PROFILE_BASE;
         case PROFILE_AVC_MAIN:     return IV_PROFILE_MAIN;
         default:
@@ -374,7 +374,7 @@
       mSawInputEOS(false),
       mSawOutputEOS(false),
       mSignalledError(false),
-      mCodecCtx(NULL),
+      mCodecCtx(nullptr),
       // TODO: output buffer size
       mOutBufferSize(524288) {
 
@@ -414,8 +414,8 @@
 }
 
 void  C2SoftAvcEnc::initEncParams() {
-    mCodecCtx = NULL;
-    mMemRecords = NULL;
+    mCodecCtx = nullptr;
+    mMemRecords = nullptr;
     mNumMemRecords = DEFAULT_MEM_REC_CNT;
     mHeaderGenerated = 0;
     mNumCores = GetCPUCoreCount();
@@ -436,8 +436,8 @@
     mEntropyMode = DEFAULT_ENTROPY_MODE;
     mBframes = DEFAULT_B_FRAMES;
 
-    gettimeofday(&mTimeStart, NULL);
-    gettimeofday(&mTimeEnd, NULL);
+    gettimeofday(&mTimeStart, nullptr);
+    gettimeofday(&mTimeEnd, nullptr);
 }
 
 c2_status_t C2SoftAvcEnc::setDimensions() {
@@ -872,7 +872,7 @@
 
         s_num_mem_rec_ip.e_cmd = IV_CMD_GET_NUM_MEM_REC;
 
-        status = ive_api_function(0, &s_num_mem_rec_ip, &s_num_mem_rec_op);
+        status = ive_api_function(nullptr, &s_num_mem_rec_ip, &s_num_mem_rec_op);
 
         if (status != IV_SUCCESS) {
             ALOGE("Get number of memory records failed = 0x%x\n",
@@ -889,7 +889,7 @@
         return C2_CORRUPTED;
     }
     mMemRecords = (iv_mem_rec_t *)malloc(mNumMemRecords * sizeof(iv_mem_rec_t));
-    if (NULL == mMemRecords) {
+    if (nullptr == mMemRecords) {
         ALOGE("Unable to allocate memory for hold memory records: Size %zu",
                 mNumMemRecords * sizeof(iv_mem_rec_t));
         mSignalledError = true;
@@ -901,7 +901,7 @@
         ps_mem_rec = mMemRecords;
         for (size_t i = 0; i < mNumMemRecords; i++) {
             ps_mem_rec->u4_size = sizeof(iv_mem_rec_t);
-            ps_mem_rec->pv_base = NULL;
+            ps_mem_rec->pv_base = nullptr;
             ps_mem_rec->u4_mem_size = 0;
             ps_mem_rec->u4_mem_alignment = 0;
             ps_mem_rec->e_mem_type = IV_NA_MEM_TYPE;
@@ -930,7 +930,7 @@
         s_fill_mem_rec_ip.u4_max_srch_rng_x = DEFAULT_MAX_SRCH_RANGE_X;
         s_fill_mem_rec_ip.u4_max_srch_rng_y = DEFAULT_MAX_SRCH_RANGE_Y;
 
-        status = ive_api_function(0, &s_fill_mem_rec_ip, &s_fill_mem_rec_op);
+        status = ive_api_function(nullptr, &s_fill_mem_rec_ip, &s_fill_mem_rec_op);
 
         if (status != IV_SUCCESS) {
             ALOGE("Fill memory records failed = 0x%x\n",
@@ -949,7 +949,7 @@
         for (size_t i = 0; i < mNumMemRecords; i++) {
             ps_mem_rec->pv_base = ive_aligned_malloc(
                     ps_mem_rec->u4_mem_alignment, ps_mem_rec->u4_mem_size);
-            if (ps_mem_rec->pv_base == NULL) {
+            if (ps_mem_rec->pv_base == nullptr) {
                 ALOGE("Allocation failure for mem record id %zu size %u\n", i,
                         ps_mem_rec->u4_mem_size);
                 return C2_CORRUPTED;
@@ -1085,14 +1085,18 @@
     /* Free memory records */
     ps_mem_rec = mMemRecords;
     for (size_t i = 0; i < s_retrieve_mem_op.u4_num_mem_rec_filled; i++) {
-        ive_aligned_free(ps_mem_rec->pv_base);
+        if (ps_mem_rec) ive_aligned_free(ps_mem_rec->pv_base);
+        else {
+            ALOGE("memory record is null.");
+            return C2_CORRUPTED;
+        }
         ps_mem_rec++;
     }
 
-    free(mMemRecords);
+    if (mMemRecords) free(mMemRecords);
 
     // clear other pointers into the space being free()d
-    mCodecCtx = NULL;
+    mCodecCtx = nullptr;
 
     mStarted = false;
 
@@ -1116,15 +1120,15 @@
     ps_encode_op->u4_size = sizeof(ive_video_encode_op_t);
 
     ps_encode_ip->e_cmd = IVE_CMD_VIDEO_ENCODE;
-    ps_encode_ip->pv_bufs = NULL;
-    ps_encode_ip->pv_mb_info = NULL;
-    ps_encode_ip->pv_pic_info = NULL;
+    ps_encode_ip->pv_bufs = nullptr;
+    ps_encode_ip->pv_mb_info = nullptr;
+    ps_encode_ip->pv_pic_info = nullptr;
     ps_encode_ip->u4_mb_info_type = 0;
     ps_encode_ip->u4_pic_info_type = 0;
     ps_encode_ip->u4_is_last = 0;
     ps_encode_ip->u4_timestamp_high = timestamp >> 32;
     ps_encode_ip->u4_timestamp_low = timestamp & 0xFFFFFFFF;
-    ps_encode_op->s_out_buf.pv_buf = NULL;
+    ps_encode_op->s_out_buf.pv_buf = nullptr;
 
     /* Initialize color formats */
     memset(ps_inp_raw_buf, 0, sizeof(iv_raw_buf_t));
@@ -1162,7 +1166,7 @@
 
     switch (layout.type) {
         case C2PlanarLayout::TYPE_RGB:
-            // fall-through
+            [[fallthrough]];
         case C2PlanarLayout::TYPE_RGBA: {
             ALOGV("yPlaneSize = %zu", yPlaneSize);
             MemoryBlock conversionBuffer = mConversionBuffers.fetch(yPlaneSize * 3 / 2);
@@ -1273,18 +1277,20 @@
 void C2SoftAvcEnc::process(
         const std::unique_ptr<C2Work> &work,
         const std::shared_ptr<C2BlockPool> &pool) {
+    // Initialize output work
     work->result = C2_OK;
-    work->workletsProcessed = 0u;
+    work->workletsProcessed = 1u;
+    work->worklets.front()->output.flags = work->input.flags;
 
     IV_STATUS_T status;
     WORD32 timeDelay, timeTaken;
     uint64_t timestamp = work->input.ordinal.timestamp.peekull();
 
     // Initialize encoder if not already initialized
-    if (mCodecCtx == NULL) {
+    if (mCodecCtx == nullptr) {
         if (C2_OK != initEncoder()) {
             ALOGE("Failed to initialize encoder");
-            work->workletsProcessed = 1u;
+            mSignalledError = true;
             work->result = C2_CORRUPTED;
             return;
         }
@@ -1302,12 +1308,11 @@
         constexpr uint32_t kHeaderLength = MIN_STREAM_SIZE;
         uint8_t header[kHeaderLength];
         error = setEncodeArgs(
-                &s_encode_ip, &s_encode_op, NULL, header, kHeaderLength, timestamp);
+                &s_encode_ip, &s_encode_op, nullptr, header, kHeaderLength, timestamp);
         if (error != C2_OK) {
             ALOGE("setEncodeArgs failed: %d", error);
             mSignalledError = true;
-            work->workletsProcessed = 1u;
-            work->result = error;
+            work->result = C2_CORRUPTED;
             return;
         }
         status = ive_api_function(mCodecCtx, &s_encode_ip, &s_encode_op);
@@ -1325,6 +1330,12 @@
 
         std::unique_ptr<C2StreamCsdInfo::output> csd =
             C2StreamCsdInfo::output::AllocUnique(s_encode_op.s_out_buf.u4_bytes, 0u);
+        if (!csd) {
+            ALOGE("CSD allocation failed");
+            mSignalledError = true;
+            work->result = C2_NO_MEMORY;
+            return;
+        }
         memcpy(csd->m.value, header, s_encode_op.s_out_buf.u4_bytes);
         work->worklets.front()->output.configUpdate.push_back(std::move(csd));
 
@@ -1398,14 +1409,12 @@
         c2_status_t err = pool->fetchLinearBlock(mOutBufferSize, usage, &block);
         if (err != C2_OK) {
             ALOGE("fetch linear block err = %d", err);
-            work->workletsProcessed = 1u;
             work->result = err;
             return;
         }
         C2WriteView wView = block->map().get();
         if (wView.error() != C2_OK) {
             ALOGE("write view map err = %d", wView.error());
-            work->workletsProcessed = 1u;
             work->result = wView.error();
             return;
         }
@@ -1413,9 +1422,8 @@
         error = setEncodeArgs(
                 &s_encode_ip, &s_encode_op, view.get(), wView.base(), wView.capacity(), timestamp);
         if (error != C2_OK) {
-            mSignalledError = true;
             ALOGE("setEncodeArgs failed : %d", error);
-            work->workletsProcessed = 1u;
+            mSignalledError = true;
             work->result = error;
             return;
         }
@@ -1424,7 +1432,7 @@
         //         mInFile, s_encode_ip.s_inp_buf.apv_bufs[0],
         //         (mHeight * mStride * 3 / 2));
 
-        GETTIME(&mTimeStart, NULL);
+        GETTIME(&mTimeStart, nullptr);
         /* Compute time elapsed between end of previous decode()
          * to start of current decode() */
         TIME_DIFF(mTimeEnd, mTimeStart, timeDelay);
@@ -1439,7 +1447,6 @@
             ALOGE("Encode Frame failed = 0x%x\n",
                     s_encode_op.u4_error_code);
             mSignalledError = true;
-            work->workletsProcessed = 1u;
             work->result = C2_CORRUPTED;
             return;
         }
@@ -1450,7 +1457,7 @@
         mBuffers[s_encode_ip.s_inp_buf.apv_bufs[0]] = inputBuffer;
     }
 
-    GETTIME(&mTimeEnd, NULL);
+    GETTIME(&mTimeEnd, nullptr);
     /* Compute time taken for decode() */
     TIME_DIFF(mTimeStart, mTimeEnd, timeTaken);
 
@@ -1459,7 +1466,7 @@
 
     void *freed = s_encode_op.s_inp_buf.apv_bufs[0];
     /* If encoder frees up an input buffer, mark it as free */
-    if (freed != NULL) {
+    if (freed != nullptr) {
         if (mBuffers.count(freed) == 0u) {
             ALOGD("buffer not tracked");
         } else {
@@ -1485,7 +1492,6 @@
         }
         work->worklets.front()->output.buffers.push_back(buffer);
     }
-    work->workletsProcessed = 1u;
 
     if (s_encode_op.u4_is_last) {
         // outputBufferHeader->nFlags |= OMX_BUFFERFLAG_EOS;
diff --git a/media/codecs/base/Android.bp b/media/codecs/base/Android.bp
index ad456e2..473cb4d 100644
--- a/media/codecs/base/Android.bp
+++ b/media/codecs/base/Android.bp
@@ -31,9 +31,6 @@
             "signed-integer-overflow",
         ],
         cfi: true,
-        diag: {
-            cfi: true,
-        },
     },
 
     ldflags: ["-Wl,-Bsymbolic"],
@@ -77,9 +74,6 @@
             "signed-integer-overflow",
         ],
         cfi: true,
-        diag: {
-            cfi: true,
-        },
     },
 }
 
@@ -93,9 +87,6 @@
             "signed-integer-overflow",
         ],
         cfi: true,
-        diag: {
-            cfi: true,
-        },
     },
 }
 
@@ -131,9 +122,6 @@
             "signed-integer-overflow",
         ],
         cfi: true,
-        diag: {
-            cfi: true,
-        },
     },
 
     ldflags: ["-Wl,-Bsymbolic"],
diff --git a/media/codecs/base/SimpleC2Component.cpp b/media/codecs/base/SimpleC2Component.cpp
index d6a62a7..50b4d20 100644
--- a/media/codecs/base/SimpleC2Component.cpp
+++ b/media/codecs/base/SimpleC2Component.cpp
@@ -102,7 +102,7 @@
         case kWhatInit: {
             int32_t err = thiz->onInit();
             Reply(msg, &err);
-            // fall-through
+            [[fallthrough]];
         }
         case kWhatStart: {
             mRunning = true;
@@ -361,14 +361,38 @@
     }
     if (work) {
         fillWork(work);
-        Mutexed<ExecState>::Locked state(mExecState);
-        std::shared_ptr<C2Component::Listener> listener = state->mListener;
-        state.unlock();
+        std::shared_ptr<C2Component::Listener> listener = mExecState.lock()->mListener;
         listener->onWorkDone_nb(shared_from_this(), vec(work));
         ALOGV("returning pending work");
     }
 }
 
+void SimpleC2Component::cloneAndSend(
+        uint64_t frameIndex,
+        const std::unique_ptr<C2Work> &currentWork,
+        std::function<void(const std::unique_ptr<C2Work> &)> fillWork) {
+    std::unique_ptr<C2Work> work(new C2Work);
+    if (currentWork->input.ordinal.frameIndex == frameIndex) {
+        work->input.flags = currentWork->input.flags;
+        work->input.ordinal = currentWork->input.ordinal;
+    } else {
+        Mutexed<PendingWork>::Locked pending(mPendingWork);
+        if (pending->count(frameIndex) == 0) {
+            ALOGW("unknown frame index: %" PRIu64, frameIndex);
+            return;
+        }
+        work->input.flags = pending->at(frameIndex)->input.flags;
+        work->input.ordinal = pending->at(frameIndex)->input.ordinal;
+    }
+    work->worklets.emplace_back(new C2Worklet);
+    if (work) {
+        fillWork(work);
+        std::shared_ptr<C2Component::Listener> listener = mExecState.lock()->mListener;
+        listener->onWorkDone_nb(shared_from_this(), vec(work));
+        ALOGV("cloned and sending work");
+    }
+}
+
 bool SimpleC2Component::processQueue() {
     std::unique_ptr<C2Work> work;
     uint64_t generation;
@@ -465,6 +489,13 @@
     }
 
     ALOGV("start processing frame #%" PRIu64, work->input.ordinal.frameIndex.peeku());
+    // If input buffer list is not empty, it means we have some input to process on.
+    // However, input could be a null buffer. In such case, clear the buffer list
+    // before making call to process().
+    if (!work->input.buffers.empty() && !work->input.buffers[0]) {
+        ALOGD("Encountered null input buffer. Clearing the input buffer");
+        work->input.buffers.clear();
+    }
     process(work, mOutputBlockPool);
     ALOGV("processed frame #%" PRIu64, work->input.ordinal.frameIndex.peeku());
     {
diff --git a/media/codecs/base/include/SimpleC2Component.h b/media/codecs/base/include/SimpleC2Component.h
index e745dc5..b3a98f4 100644
--- a/media/codecs/base/include/SimpleC2Component.h
+++ b/media/codecs/base/include/SimpleC2Component.h
@@ -121,6 +121,24 @@
      */
     void finish(uint64_t frameIndex, std::function<void(const std::unique_ptr<C2Work> &)> fillWork);
 
+    /**
+     * Clone pending or current work and send the work back to client.
+     *
+     * This method will retrieve and clone the pending or current work according
+     * to |frameIndex| and feed the work into |fillWork| function. |fillWork|
+     * must be "non-blocking". Once |fillWork| returns the filled work will be
+     * returned to the client.
+     *
+     * \param[in]   frameIndex    the index of the work
+     * \param[in]   currentWork   the current work under processing
+     * \param[in]   fillWork      the function to fill the retrieved work.
+     */
+    void cloneAndSend(
+            uint64_t frameIndex,
+            const std::unique_ptr<C2Work> &currentWork,
+            std::function<void(const std::unique_ptr<C2Work> &)> fillWork);
+
+
     std::shared_ptr<C2Buffer> createLinearBuffer(
             const std::shared_ptr<C2LinearBlock> &block);
 
diff --git a/media/codecs/cmds/Android.bp b/media/codecs/cmds/Android.bp
index c48ae07..6a4ca8c 100644
--- a/media/codecs/cmds/Android.bp
+++ b/media/codecs/cmds/Android.bp
@@ -15,7 +15,6 @@
         "libcutils",
         "libgui",
         "liblog",
-        "libmediaextractor",
         "libstagefright",
         "libstagefright_foundation",
         "libui",
@@ -25,7 +24,6 @@
     cflags: [
         "-Werror",
         "-Wall",
-        "-std=c++14",
     ],
 
     sanitize: {
@@ -34,8 +32,5 @@
             "unsigned-integer-overflow",
             "signed-integer-overflow",
         ],
-        diag: {
-            cfi: true,
-        },
     },
 }
diff --git a/media/codecs/cmds/codec2.cpp b/media/codecs/cmds/codec2.cpp
index 4d0fdd4..f2cf545 100644
--- a/media/codecs/cmds/codec2.cpp
+++ b/media/codecs/cmds/codec2.cpp
@@ -33,7 +33,6 @@
 #include <media/DataSource.h>
 #include <media/ICrypto.h>
 #include <media/IMediaHTTPService.h>
-#include <media/MediaExtractor.h>
 #include <media/MediaSource.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ALooper.h>
@@ -155,7 +154,7 @@
             HAL_PIXEL_FORMAT_YV12);
             //PIXEL_FORMAT_RGB_565);
 
-    CHECK(mControl != NULL);
+    CHECK(mControl != nullptr);
     CHECK(mControl->isValid());
 
     SurfaceComposerClient::Transaction{}
@@ -164,7 +163,7 @@
             .apply();
 
     mSurface = mControl->getSurface();
-    CHECK(mSurface != NULL);
+    CHECK(mSurface != nullptr);
     mSurface->connect(NATIVE_WINDOW_API_CPU, mProducerListener);
 }
 
@@ -305,7 +304,7 @@
         } else {
             status_t err = source->read(&buffer);
             if (err != OK) {
-                CHECK(buffer == NULL);
+                CHECK(buffer == nullptr);
 
                 if (err == INFO_FORMAT_CHANGED) {
                     continue;
@@ -367,7 +366,7 @@
 
         if (buffer) {
             buffer->release();
-            buffer = NULL;
+            buffer = nullptr;
         }
 
         ++numFrames;
@@ -419,9 +418,9 @@
         const char *filename = argv[k];
 
         sp<DataSource> dataSource =
-            DataSourceFactory::CreateFromURI(NULL /* httpService */, filename);
+            DataSourceFactory::CreateFromURI(nullptr /* httpService */, filename);
 
-        if (strncasecmp(filename, "sine:", 5) && dataSource == NULL) {
+        if (strncasecmp(filename, "sine:", 5) && dataSource == nullptr) {
             fprintf(stderr, "Unable to create data source.\n");
             return 1;
         }
@@ -431,14 +430,14 @@
 
         sp<IMediaExtractor> extractor = MediaExtractorFactory::Create(dataSource);
 
-        if (extractor == NULL) {
+        if (extractor == nullptr) {
             fprintf(stderr, "could not create extractor.\n");
             return -1;
         }
 
         sp<MetaData> meta = extractor->getMetaData();
 
-        if (meta != NULL) {
+        if (meta != nullptr) {
             const char *mime;
             if (!meta->findCString(kKeyMIMEType, &mime)) {
                 fprintf(stderr, "extractor did not provide MIME type.\n");
@@ -450,10 +449,9 @@
 
         size_t i;
         for (i = 0; i < numTracks; ++i) {
-            meta = extractor->getTrackMetaData(
-                    i, MediaExtractor::kIncludeExtensiveMetaData);
+            meta = extractor->getTrackMetaData(i, 0);
 
-            if (meta == NULL) {
+            if (meta == nullptr) {
                 break;
             }
             const char *mime;
@@ -464,10 +462,10 @@
                 break;
             }
 
-            meta = NULL;
+            meta = nullptr;
         }
 
-        if (meta == NULL) {
+        if (meta == nullptr) {
             fprintf(stderr, "No AVC track found.\n");
             return -1;
         }
diff --git a/media/codecs/flac/C2SoftFlacDec.cpp b/media/codecs/flac/C2SoftFlacDec.cpp
index 1358d66..f1e2f51 100644
--- a/media/codecs/flac/C2SoftFlacDec.cpp
+++ b/media/codecs/flac/C2SoftFlacDec.cpp
@@ -169,9 +169,12 @@
 void C2SoftFlacDec::process(
         const std::unique_ptr<C2Work> &work,
         const std::shared_ptr<C2BlockPool> &pool) {
+    // Initialize output work
     work->result = C2_OK;
-    work->workletsProcessed = 0u;
+    work->workletsProcessed = 1u;
     work->worklets.front()->output.configUpdate.clear();
+    work->worklets.front()->output.flags = work->input.flags;
+
     if (mSignalledError || mSignalledOutputEos) {
         work->result = C2_BAD_VALUE;
         return;
@@ -297,7 +300,6 @@
     work->worklets.front()->output.buffers.clear();
     work->worklets.front()->output.buffers.push_back(createLinearBuffer(block, 0, outSize));
     work->worklets.front()->output.ordinal = work->input.ordinal;
-    work->workletsProcessed = 1u;
     if (eos) {
         mSignalledOutputEos = true;
         ALOGV("signalled EOS");
diff --git a/media/codecs/flac/C2SoftFlacEnc.cpp b/media/codecs/flac/C2SoftFlacEnc.cpp
index 13c888e..e4192c7 100644
--- a/media/codecs/flac/C2SoftFlacEnc.cpp
+++ b/media/codecs/flac/C2SoftFlacEnc.cpp
@@ -176,8 +176,11 @@
 void C2SoftFlacEnc::process(
         const std::unique_ptr<C2Work> &work,
         const std::shared_ptr<C2BlockPool> &pool) {
+    // Initialize output work
     work->result = C2_OK;
     work->workletsProcessed = 1u;
+    work->worklets.front()->output.flags = work->input.flags;
+
     if (mSignalledError || mSignalledOutputEos) {
         work->result = C2_BAD_VALUE;
         return;
@@ -208,7 +211,12 @@
     if (!mWroteHeader) {
         std::unique_ptr<C2StreamCsdInfo::output> csd =
             C2StreamCsdInfo::output::AllocUnique(mHeaderOffset, 0u);
-        // TODO: check NO_MEMORY
+        if (!csd) {
+            ALOGE("CSD allocation failed");
+            mSignalledError = true;
+            work->result = C2_NO_MEMORY;
+            return;
+        }
         memcpy(csd->m.value, mHeader, mHeaderOffset);
         ALOGV("put csd, %d bytes", mHeaderOffset);
 
diff --git a/media/codecs/g711/C2SoftG711Dec.cpp b/media/codecs/g711/C2SoftG711Dec.cpp
index 2f84b46..1c71d45 100644
--- a/media/codecs/g711/C2SoftG711Dec.cpp
+++ b/media/codecs/g711/C2SoftG711Dec.cpp
@@ -140,8 +140,11 @@
 void C2SoftG711Dec::process(
         const std::unique_ptr<C2Work> &work,
         const std::shared_ptr<C2BlockPool> &pool) {
+    // Initialize output work
     work->result = C2_OK;
-    work->workletsProcessed = 0u;
+    work->workletsProcessed = 1u;
+    work->worklets.front()->output.flags = work->input.flags;
+
     if (mSignalledOutputEos) {
         work->result = C2_BAD_VALUE;
         return;
@@ -169,7 +172,6 @@
         work->worklets.front()->output.flags = work->input.flags;
         work->worklets.front()->output.buffers.clear();
         work->worklets.front()->output.ordinal = work->input.ordinal;
-        work->workletsProcessed = 1u;
         if (eos) {
             mSignalledOutputEos = true;
             ALOGV("signalled EOS");
@@ -205,7 +207,6 @@
     work->worklets.front()->output.buffers.clear();
     work->worklets.front()->output.buffers.push_back(createLinearBuffer(block));
     work->worklets.front()->output.ordinal = work->input.ordinal;
-    work->workletsProcessed = 1u;
 
     if (eos) {
         mSignalledOutputEos = true;
diff --git a/media/codecs/gsm/C2SoftGsmDec.cpp b/media/codecs/gsm/C2SoftGsmDec.cpp
index eedaa14..7101c79 100644
--- a/media/codecs/gsm/C2SoftGsmDec.cpp
+++ b/media/codecs/gsm/C2SoftGsmDec.cpp
@@ -174,8 +174,11 @@
 void C2SoftGsmDec::process(
         const std::unique_ptr<C2Work> &work,
         const std::shared_ptr<C2BlockPool> &pool) {
+    // Initialize output work
     work->result = C2_OK;
-    work->workletsProcessed = 0u;
+    work->workletsProcessed = 1u;
+    work->worklets.front()->output.flags = work->input.flags;
+
     if (mSignalledError || mSignalledEos) {
         work->result = C2_BAD_VALUE;
         return;
@@ -199,7 +202,6 @@
         work->worklets.front()->output.flags = work->input.flags;
         work->worklets.front()->output.buffers.clear();
         work->worklets.front()->output.ordinal = work->input.ordinal;
-        work->workletsProcessed = 1u;
         if (eos) {
             mSignalledEos = true;
             ALOGV("signalled EOS");
@@ -239,7 +241,6 @@
     work->worklets.front()->output.buffers.clear();
     work->worklets.front()->output.buffers.push_back(createLinearBuffer(block, 0, outSize));
     work->worklets.front()->output.ordinal = work->input.ordinal;
-    work->workletsProcessed = 1u;
     if (eos) {
         mSignalledEos = true;
         ALOGV("signalled EOS");
diff --git a/media/codecs/hevc/C2SoftHevcDec.cpp b/media/codecs/hevc/C2SoftHevcDec.cpp
index f71a7c5..99892ce 100644
--- a/media/codecs/hevc/C2SoftHevcDec.cpp
+++ b/media/codecs/hevc/C2SoftHevcDec.cpp
@@ -324,7 +324,8 @@
         mOutBufferFlush(nullptr),
         mIvColorformat(IV_YUV_420P),
         mWidth(320),
-        mHeight(240) {
+        mHeight(240),
+        mHeaderDecoded(false) {
 }
 
 C2SoftHevcDec::~C2SoftHevcDec() {
@@ -381,8 +382,10 @@
         }
     }
 
-    ivd_aligned_free(nullptr, mOutBufferFlush);
-    mOutBufferFlush = nullptr;
+    if (mOutBufferFlush) {
+        ivd_aligned_free(nullptr, mOutBufferFlush);
+        mOutBufferFlush = nullptr;
+    }
 
     return C2_OK;
 }
@@ -434,7 +437,7 @@
     return OK;
 }
 
-status_t C2SoftHevcDec::setParams(size_t stride) {
+status_t C2SoftHevcDec::setParams(size_t stride, IVD_VIDEO_DECODE_MODE_T dec_mode) {
     ivd_ctl_set_config_ip_t s_set_dyn_params_ip;
     ivd_ctl_set_config_op_t s_set_dyn_params_op;
 
@@ -444,7 +447,7 @@
     s_set_dyn_params_ip.u4_disp_wd = (UWORD32) stride;
     s_set_dyn_params_ip.e_frm_skip_mode = IVD_SKIP_NONE;
     s_set_dyn_params_ip.e_frm_out_mode = IVD_DISPLAY_FRAME_OUT;
-    s_set_dyn_params_ip.e_vid_dec_mode = IVD_DECODE_FRAME;
+    s_set_dyn_params_ip.e_vid_dec_mode = dec_mode;
     s_set_dyn_params_op.u4_size = sizeof(ivd_ctl_set_config_op_t);
     IV_API_CALL_STATUS_T status = ivdec_api_function(mDecHandle,
                                                      &s_set_dyn_params_ip,
@@ -489,7 +492,7 @@
     mSignalledError = false;
     resetPlugin();
     (void) setNumCores();
-    if (OK != setParams(mStride)) return UNKNOWN_ERROR;
+    if (OK != setParams(mStride, IVD_DECODE_FRAME)) return UNKNOWN_ERROR;
     (void) getVersion();
 
     return OK;
@@ -628,7 +631,7 @@
     mStride = 0;
     (void) setNumCores();
     mSignalledError = false;
-
+    mHeaderDecoded = false;
     return OK;
 }
 
@@ -681,14 +684,8 @@
         buffer->setInfo(mIntf->getColorAspects_l());
     }
 
-    auto fillWork = [buffer, index](const std::unique_ptr<C2Work> &work) {
-        uint32_t flags = 0;
-        if ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) &&
-                (c2_cntr64_t(index) == work->input.ordinal.frameIndex)) {
-            flags |= C2FrameData::FLAG_END_OF_STREAM;
-            ALOGV("signalling eos");
-        }
-        work->worklets.front()->output.flags = (C2FrameData::flags_t)flags;
+    auto fillWork = [buffer](const std::unique_ptr<C2Work> &work) {
+        work->worklets.front()->output.flags = (C2FrameData::flags_t)0;
         work->worklets.front()->output.buffers.clear();
         work->worklets.front()->output.buffers.push_back(buffer);
         work->worklets.front()->output.ordinal = work->input.ordinal;
@@ -708,7 +705,7 @@
     }
     if (mStride != ALIGN64(mWidth)) {
         mStride = ALIGN64(mWidth);
-        if (OK != setParams(mStride)) return C2_CORRUPTED;
+        if (OK != setParams(mStride, IVD_DECODE_FRAME)) return C2_CORRUPTED;
     }
     if (mOutBlock &&
             (mOutBlock->width() != mStride || mOutBlock->height() != mHeight)) {
@@ -738,9 +735,12 @@
 void C2SoftHevcDec::process(
         const std::unique_ptr<C2Work> &work,
         const std::shared_ptr<C2BlockPool> &pool) {
+    // Initialize output work
     work->result = C2_OK;
     work->workletsProcessed = 0u;
     work->worklets.front()->output.configUpdate.clear();
+    work->worklets.front()->output.flags = work->input.flags;
+
     if (mSignalledError || mSignalledOutputEos) {
         work->result = C2_BAD_VALUE;
         return;
@@ -769,6 +769,7 @@
     while (inPos < inSize) {
         if (C2_OK != ensureDecoderState(pool)) {
             mSignalledError = true;
+            work->workletsProcessed = 1u;
             work->result = C2_CORRUPTED;
             return;
         }
@@ -783,11 +784,17 @@
         if (!setDecodeArgs(&s_decode_ip, &s_decode_op, &rView, &wView,
                            inOffset + inPos, inSize - inPos, workIndex)) {
             mSignalledError = true;
+            work->workletsProcessed = 1u;
             work->result = C2_CORRUPTED;
             return;
         }
+
+        if (false == mHeaderDecoded) {
+            /* Decode header and get dimensions */
+            setParams(mStride, IVD_DECODE_HEADER);
+        }
         WORD32 delay;
-        GETTIME(&mTimeStart, NULL);
+        GETTIME(&mTimeStart, nullptr);
         TIME_DIFF(mTimeEnd, mTimeStart, delay);
         (void) ivdec_api_function(mDecHandle, &s_decode_ip, &s_decode_op);
         WORD32 decodeTime;
@@ -797,22 +804,32 @@
               s_decode_op.u4_num_bytes_consumed);
         if (IVD_MEM_ALLOC_FAILED == (s_decode_op.u4_error_code & 0xFF)) {
             ALOGE("allocation failure in decoder");
-            work->result = C2_CORRUPTED;
             mSignalledError = true;
+            work->workletsProcessed = 1u;
+            work->result = C2_CORRUPTED;
             return;
         } else if (IVD_STREAM_WIDTH_HEIGHT_NOT_SUPPORTED == (s_decode_op.u4_error_code & 0xFF)) {
             ALOGE("unsupported resolution : %dx%d", mWidth, mHeight);
-            work->result = C2_CORRUPTED;
             mSignalledError = true;
+            work->workletsProcessed = 1u;
+            work->result = C2_CORRUPTED;
             return;
         } else if (IVD_RES_CHANGED == (s_decode_op.u4_error_code & 0xFF)) {
             ALOGV("resolution changed");
             drainInternal(DRAIN_COMPONENT_NO_EOS, pool, work);
             resetDecoder();
             resetPlugin();
-            continue;
+            work->workletsProcessed = 0u;
+
+            /* Decode header and get new dimensions */
+            setParams(mStride, IVD_DECODE_HEADER);
+            (void) ivdec_api_function(mDecHandle, &s_decode_ip, &s_decode_op);
         }
         if (0 < s_decode_op.u4_pic_wd && 0 < s_decode_op.u4_pic_ht) {
+            if (mHeaderDecoded == false) {
+                mHeaderDecoded = true;
+                setParams(ALIGN64(s_decode_op.u4_pic_wd), IVD_DECODE_FRAME);
+            }
             if (s_decode_op.u4_pic_wd != mWidth ||  s_decode_op.u4_pic_ht != mHeight) {
                 mWidth = s_decode_op.u4_pic_wd;
                 mHeight = s_decode_op.u4_pic_ht;
@@ -828,9 +845,11 @@
                 } else {
                     ALOGE("Cannot set width and height");
                     mSignalledError = true;
+                    work->workletsProcessed = 1u;
                     work->result = C2_CORRUPTED;
                     return;
                 }
+                continue;
             }
         }
         (void) getVuiParams();
@@ -838,6 +857,10 @@
         if (s_decode_op.u4_output_present) {
             finishWork(s_decode_op.u4_ts, work);
         }
+        if (0 == s_decode_op.u4_num_bytes_consumed) {
+            ALOGD("Bytes consumed is zero. Ignoring remaining bytes");
+            break;
+        }
         inPos += s_decode_op.u4_num_bytes_consumed;
         if (hasPicture && (inSize - inPos)) {
             ALOGD("decoded frame in current access nal, ignoring further trailing bytes %d",
@@ -871,6 +894,7 @@
     while (true) {
         if (C2_OK != ensureDecoderState(pool)) {
             mSignalledError = true;
+            work->workletsProcessed = 1u;
             work->result = C2_CORRUPTED;
             return C2_CORRUPTED;
         }
@@ -883,21 +907,18 @@
         ivd_video_decode_op_t s_decode_op;
         if (!setDecodeArgs(&s_decode_ip, &s_decode_op, nullptr, &wView, 0, 0, 0)) {
             mSignalledError = true;
+            work->workletsProcessed = 1u;
             return C2_CORRUPTED;
         }
         (void) ivdec_api_function(mDecHandle, &s_decode_ip, &s_decode_op);
         if (s_decode_op.u4_output_present) {
             finishWork(s_decode_op.u4_ts, work);
         } else {
+            fillEmptyWork(work);
             break;
         }
     }
 
-    if (drainMode == DRAIN_COMPONENT_WITH_EOS &&
-            work && work->workletsProcessed == 0u) {
-        fillEmptyWork(work);
-    }
-
     return C2_OK;
 }
 
diff --git a/media/codecs/hevc/C2SoftHevcDec.h b/media/codecs/hevc/C2SoftHevcDec.h
index 2b3154d..75111fc 100644
--- a/media/codecs/hevc/C2SoftHevcDec.h
+++ b/media/codecs/hevc/C2SoftHevcDec.h
@@ -69,7 +69,7 @@
  private:
     status_t createDecoder();
     status_t setNumCores();
-    status_t setParams(size_t stride);
+    status_t setParams(size_t stride, IVD_VIDEO_DECODE_MODE_T dec_mode);
     status_t getVersion();
     status_t initDecoder();
     bool setDecodeArgs(ivd_video_decode_ip_t *ps_decode_ip,
@@ -120,6 +120,7 @@
     uint32_t mStride;
     bool mSignalledOutputEos;
     bool mSignalledError;
+    bool mHeaderDecoded;
 
     // Color aspects. These are ISO values and are meant to detect changes in aspects to avoid
     // converting them to C2 values for each frame
diff --git a/media/codecs/mp3/C2SoftMp3Dec.cpp b/media/codecs/mp3/C2SoftMp3Dec.cpp
index 48de625..c8b8397 100644
--- a/media/codecs/mp3/C2SoftMp3Dec.cpp
+++ b/media/codecs/mp3/C2SoftMp3Dec.cpp
@@ -336,9 +336,12 @@
 void C2SoftMP3::process(
         const std::unique_ptr<C2Work> &work,
         const std::shared_ptr<C2BlockPool> &pool) {
+    // Initialize output work
     work->result = C2_OK;
-    work->workletsProcessed = 0u;
+    work->workletsProcessed = 1u;
     work->worklets.front()->output.configUpdate.clear();
+    work->worklets.front()->output.flags = work->input.flags;
+
     if (mSignalledError || mSignalledOutputEos) {
         work->result = C2_BAD_VALUE;
         return;
@@ -361,7 +364,6 @@
         work->worklets.front()->output.flags = work->input.flags;
         work->worklets.front()->output.buffers.clear();
         work->worklets.front()->output.ordinal = work->input.ordinal;
-        work->workletsProcessed = 1u;
         return;
     }
     ALOGV("in buffer attr. size %zu timestamp %d frameindex %d", inSize,
@@ -494,7 +496,6 @@
     mProcessedSamples += ((outSize - outOffset) / (numChannels * sizeof(int16_t)));
     ALOGV("out buffer attr. offset %d size %d timestamp %u", outOffset, outSize - outOffset,
           (uint32_t)(mAnchorTimeStamp + outTimeStamp));
-
     decodedSizes.clear();
     work->worklets.front()->output.flags = work->input.flags;
     work->worklets.front()->output.buffers.clear();
@@ -502,7 +503,6 @@
             createLinearBuffer(block, outOffset, outSize - outOffset));
     work->worklets.front()->output.ordinal = work->input.ordinal;
     work->worklets.front()->output.ordinal.timestamp = mAnchorTimeStamp + outTimeStamp;
-    work->workletsProcessed = 1u;
     if (eos) {
         mSignalledOutputEos = true;
         ALOGV("signalled EOS");
diff --git a/media/codecs/mpeg2/C2SoftMpeg2Dec.cpp b/media/codecs/mpeg2/C2SoftMpeg2Dec.cpp
index 855598d..da32ec0 100644
--- a/media/codecs/mpeg2/C2SoftMpeg2Dec.cpp
+++ b/media/codecs/mpeg2/C2SoftMpeg2Dec.cpp
@@ -379,8 +379,10 @@
         }
     }
 
-    ivd_aligned_free(mOutBufferDrain);
-    mOutBufferDrain = nullptr;
+    if (mOutBufferDrain) {
+        ivd_aligned_free(mOutBufferDrain);
+        mOutBufferDrain = nullptr;
+    }
 
     return C2_OK;
 }
@@ -764,14 +766,8 @@
         buffer->setInfo(mIntf->getColorAspects_l());
     }
 
-    auto fillWork = [buffer, index](const std::unique_ptr<C2Work> &work) {
-        uint32_t flags = 0;
-        if ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) &&
-                (c2_cntr64_t(index) == work->input.ordinal.frameIndex)) {
-            flags |= C2FrameData::FLAG_END_OF_STREAM;
-            ALOGV("signalling eos");
-        }
-        work->worklets.front()->output.flags = (C2FrameData::flags_t)flags;
+    auto fillWork = [buffer](const std::unique_ptr<C2Work> &work) {
+        work->worklets.front()->output.flags = (C2FrameData::flags_t)0;
         work->worklets.front()->output.buffers.clear();
         work->worklets.front()->output.buffers.push_back(buffer);
         work->worklets.front()->output.ordinal = work->input.ordinal;
@@ -812,29 +808,6 @@
     return C2_OK;
 }
 
-void C2SoftMpeg2Dec::setTimeStampFrameIndexMap(uint64_t frameIndex, uint64_t timeStamp) {
-    mFrameIndices[timeStamp] = frameIndex;
-    return;
-}
-
-uint32_t C2SoftMpeg2Dec::getMinTimeStampFrameIndex() {
-    uint64_t frameIndex = 0;
-    uint64_t minTimeStamp = 0;
-    std::map<uint64_t , uint64_t >::iterator it = mFrameIndices.begin();
-
-    minTimeStamp = it->first;
-    while(it != mFrameIndices.end()) {
-        if(minTimeStamp > it->first) minTimeStamp = it->first;
-        it++;
-    }
-    if (mFrameIndices.count(minTimeStamp) == 0u) {
-        ALOGV("timestamp %d not tracked", (int)minTimeStamp);
-    } else {
-        frameIndex = mFrameIndices[minTimeStamp];
-        mFrameIndices.erase(minTimeStamp);
-    }
-    return frameIndex & 0xFFFFFFFF;
-}
 // TODO: can overall error checking be improved?
 // TODO: allow configuration of color format and usage for graphic buffers instead
 //       of hard coding them to HAL_PIXEL_FORMAT_YV12
@@ -844,9 +817,12 @@
 void C2SoftMpeg2Dec::process(
         const std::unique_ptr<C2Work> &work,
         const std::shared_ptr<C2BlockPool> &pool) {
+    // Initialize output work
     work->result = C2_OK;
     work->workletsProcessed = 0u;
     work->worklets.front()->output.configUpdate.clear();
+    work->worklets.front()->output.flags = work->input.flags;
+
     if (mSignalledError || mSignalledOutputEos) {
         work->result = C2_BAD_VALUE;
         return;
@@ -864,8 +840,6 @@
             work->result = C2_CORRUPTED;
             return;
         }
-        setTimeStampFrameIndexMap((uint64_t)work->input.ordinal.frameIndex.peeku(),
-            (uint64_t)work->input.ordinal.timestamp.peeku());
     }
     bool eos = ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0);
     bool hasPicture = false;
@@ -877,6 +851,7 @@
     while (inPos < inSize) {
         if (C2_OK != ensureDecoderState(pool)) {
             mSignalledError = true;
+            work->workletsProcessed = 1u;
             work->result = C2_CORRUPTED;
             return;
         }
@@ -892,13 +867,14 @@
         if (!setDecodeArgs(&s_decode_ip, &s_decode_op, &rView, &wView,
                            inOffset + inPos, inSize - inPos, workIndex)) {
             mSignalledError = true;
+            work->workletsProcessed = 1u;
             work->result = C2_CORRUPTED;
             return;
         }
         // If input dump is enabled, then write to file
         DUMP_TO_FILE(mInFile, s_decode_ip.pv_stream_buffer, s_decode_ip.u4_num_Bytes);
         WORD32 delay;
-        GETTIME(&mTimeStart, NULL);
+        GETTIME(&mTimeStart, nullptr);
         TIME_DIFF(mTimeEnd, mTimeStart, delay);
         (void) ivdec_api_function(mDecHandle, &s_decode_ip, &s_decode_op);
         WORD32 decodeTime;
@@ -910,6 +886,7 @@
             ALOGV("unsupported resolution : %dx%d", s_decode_op.u4_pic_wd, s_decode_op.u4_pic_ht);
             drainInternal(DRAIN_COMPONENT_NO_EOS, pool, work);
             resetPlugin();
+            work->workletsProcessed = 0u;
             mWidth = s_decode_op.u4_pic_wd;
             mHeight = s_decode_op.u4_pic_ht;
 
@@ -925,6 +902,7 @@
             } else {
                 ALOGE("Cannot set width and height");
                 mSignalledError = true;
+                work->workletsProcessed = 1u;
                 work->result = C2_CORRUPTED;
                 return;
             }
@@ -932,6 +910,7 @@
             if (OK != reInitDecoder()) {
                 ALOGE("Failed to reinitialize decoder");
                 mSignalledError = true;
+                work->workletsProcessed = 1u;
                 work->result = C2_CORRUPTED;
                 return;
             }
@@ -941,6 +920,7 @@
             drainInternal(DRAIN_COMPONENT_NO_EOS, pool, work);
             resetDecoder();
             resetPlugin();
+            work->workletsProcessed = 0u;
             continue;
         }
         if (0 < s_decode_op.u4_pic_wd && 0 < s_decode_op.u4_pic_ht) {
@@ -961,6 +941,7 @@
                 } else {
                     ALOGE("Cannot set width and height");
                     mSignalledError = true;
+                    work->workletsProcessed = 1u;
                     work->result = C2_CORRUPTED;
                     return;
                 }
@@ -970,8 +951,9 @@
         (void) getSeqInfo();
         hasPicture |= (1 == s_decode_op.u4_frame_decoded_flag);
         if (s_decode_op.u4_output_present) {
-            finishWork(getMinTimeStampFrameIndex(), work);
+            finishWork(s_decode_op.u4_ts, work);
         }
+
         inPos += s_decode_op.u4_num_bytes_consumed;
         if (hasPicture && (inSize - inPos) != 0) {
             ALOGD("decoded frame in current access nal, ignoring further trailing bytes %d",
@@ -1005,6 +987,7 @@
     while (true) {
         if (C2_OK != ensureDecoderState(pool)) {
             mSignalledError = true;
+            work->workletsProcessed = 1u;
             work->result = C2_CORRUPTED;
             return C2_CORRUPTED;
         }
@@ -1017,19 +1000,17 @@
         ivd_video_decode_op_t s_decode_op;
         if (!setDecodeArgs(&s_decode_ip, &s_decode_op, nullptr, &wView, 0, 0, 0)) {
             mSignalledError = true;
+            work->workletsProcessed = 1u;
             return C2_CORRUPTED;
         }
         (void) ivdec_api_function(mDecHandle, &s_decode_ip, &s_decode_op);
         if (s_decode_op.u4_output_present) {
-            finishWork(getMinTimeStampFrameIndex(), work);
+            finishWork(s_decode_op.u4_ts, work);
         } else {
+            fillEmptyWork(work);
             break;
         }
     }
-    if (drainMode == DRAIN_COMPONENT_WITH_EOS &&
-            work && work->workletsProcessed == 0u) {
-        fillEmptyWork(work);
-    }
 
     return C2_OK;
 }
diff --git a/media/codecs/mpeg2/C2SoftMpeg2Dec.h b/media/codecs/mpeg2/C2SoftMpeg2Dec.h
index 2ea3d85..9999872 100644
--- a/media/codecs/mpeg2/C2SoftMpeg2Dec.h
+++ b/media/codecs/mpeg2/C2SoftMpeg2Dec.h
@@ -136,8 +136,7 @@
     void resetPlugin();
     status_t deleteDecoder();
     status_t reInitDecoder();
-    uint32_t getMinTimeStampFrameIndex();
-    void setTimeStampFrameIndexMap(uint64_t frameIndex, uint64_t timeStamp);
+
     // TODO:This is not the right place for this enum. These should
     // be part of c2-vndk so that they can be accessed by all video plugins
     // until then, make them feel at home
@@ -181,8 +180,6 @@
         }
     } mBitstreamColorAspects;
 
-    std::map<uint64_t , uint64_t > mFrameIndices;
-
     // profile
     struct timeval mTimeStart;
     struct timeval mTimeEnd;
diff --git a/media/codecs/mpeg4_h263/C2SoftMpeg4Dec.cpp b/media/codecs/mpeg4_h263/C2SoftMpeg4Dec.cpp
index 793a515..901f5ed 100644
--- a/media/codecs/mpeg4_h263/C2SoftMpeg4Dec.cpp
+++ b/media/codecs/mpeg4_h263/C2SoftMpeg4Dec.cpp
@@ -324,6 +324,10 @@
     if (!mDecHandle) {
         mDecHandle = new tagvideoDecControls;
     }
+    if (!mDecHandle) {
+        ALOGE("mDecHandle is null");
+        return NO_MEMORY;
+    }
     memset(mDecHandle, 0, sizeof(tagvideoDecControls));
 
     /* TODO: bring these values to 352 and 288. It cannot be done as of now
@@ -446,8 +450,8 @@
             if (!PVInitVideoDecoder(
                     mDecHandle, vol_data, &vol_size, 1, mIntf->getMaxWidth(), mIntf->getMaxHeight(), H263_MODE)) {
                 ALOGE("Error in PVInitVideoDecoder H263_MODE while resChanged was set to true");
-                work->result = C2_CORRUPTED;
                 mSignalledError = true;
+                work->result = C2_CORRUPTED;
                 return true;
             }
         }
@@ -491,12 +495,14 @@
 void C2SoftMpeg4Dec::process(
         const std::unique_ptr<C2Work> &work,
         const std::shared_ptr<C2BlockPool> &pool) {
+    // Initialize output work
     work->result = C2_OK;
-    work->workletsProcessed = 0u;
+    work->workletsProcessed = 1u;
     work->worklets.front()->output.configUpdate.clear();
+    work->worklets.front()->output.flags = work->input.flags;
+
     if (mSignalledError || mSignalledOutputEos) {
         work->result = C2_BAD_VALUE;
-        work->workletsProcessed = 1u;
         return;
     }
 
@@ -548,18 +554,16 @@
                 mDecHandle, vol_data, &vol_size, 1,
                 mIntf->getMaxWidth(), mIntf->getMaxHeight(), mode)) {
             ALOGE("PVInitVideoDecoder failed. Unsupported content?");
-            work->result = C2_CORRUPTED;
-            work->workletsProcessed = 1u;
             mSignalledError = true;
+            work->result = C2_CORRUPTED;
             return;
         }
         mInitialized = true;
         MP4DecodingMode actualMode = PVGetDecBitstreamMode(mDecHandle);
         if (mode != actualMode) {
             ALOGE("Decoded mode not same as actual mode of the decoder");
-            work->result = C2_CORRUPTED;
-            work->workletsProcessed = 1u;
             mSignalledError = true;
+            work->result = C2_CORRUPTED;
             return;
         }
 
@@ -576,7 +580,6 @@
                 ALOGE("Config update size failed");
                 mSignalledError = true;
                 work->result = C2_CORRUPTED;
-                work->workletsProcessed = 1u;
                 return;
             }
         }
@@ -592,23 +595,20 @@
         if (C2_OK != err) {
             mSignalledError = true;
             work->result = err;
-            work->workletsProcessed = 1u;
             return;
         }
         C2GraphicView wView = mOutBlock->map().get();
         if (wView.error()) {
             ALOGE("graphic view map failed %d", wView.error());
             work->result = C2_CORRUPTED;
-            work->workletsProcessed = 1u;
             return;
         }
 
         uint32_t yFrameSize = sizeof(uint8) * mDecHandle->size;
         if (mOutputBufferSize < yFrameSize * 3 / 2){
             ALOGE("Too small output buffer: %zu bytes", mOutputBufferSize);
-            work->result = C2_NO_MEMORY;
-            work->workletsProcessed = 1u;
             mSignalledError = true;
+            work->result = C2_NO_MEMORY;
             return;
         }
 
@@ -628,9 +628,8 @@
                     &header_info, &useExtTimestamp,
                     mOutputBuffer[mNumSamplesOutput & 1]) != PV_TRUE) {
             ALOGE("failed to decode vop header.");
-            work->result = C2_CORRUPTED;
-            work->workletsProcessed = 1u;
             mSignalledError = true;
+            work->result = C2_CORRUPTED;
             return;
         }
 
@@ -638,9 +637,8 @@
         // decoder may detect size change after PVDecodeVopHeader.
         bool resChange = handleResChange(work);
         if (mIsMpeg4 && resChange) {
-            work->result = C2_CORRUPTED;
-            work->workletsProcessed = 1u;
             mSignalledError = true;
+            work->result = C2_CORRUPTED;
             return;
         } else if (resChange) {
             ALOGI("Setting width and height");
@@ -653,7 +651,6 @@
                 ALOGE("Config update size failed");
                 mSignalledError = true;
                 work->result = C2_CORRUPTED;
-                work->workletsProcessed = 1u;
                 return;
             }
             continue;
@@ -661,15 +658,13 @@
 
         if (PVDecodeVopBody(mDecHandle, &tmpInSize) != PV_TRUE) {
             ALOGE("failed to decode video frame.");
-            work->result = C2_CORRUPTED;
-            work->workletsProcessed = 1u;
             mSignalledError = true;
+            work->result = C2_CORRUPTED;
             return;
         }
         if (handleResChange(work)) {
-            work->result = C2_CORRUPTED;
-            work->workletsProcessed = 1u;
             mSignalledError = true;
+            work->result = C2_CORRUPTED;
             return;
         }
 
diff --git a/media/codecs/mpeg4_h263/C2SoftMpeg4Enc.cpp b/media/codecs/mpeg4_h263/C2SoftMpeg4Enc.cpp
index ddc1c7b..c8796f3 100644
--- a/media/codecs/mpeg4_h263/C2SoftMpeg4Enc.cpp
+++ b/media/codecs/mpeg4_h263/C2SoftMpeg4Enc.cpp
@@ -93,8 +93,8 @@
                     C2F(mSize, width).inRange(16, 176, 16),
                     C2F(mSize, height).inRange(16, 144, 16),
 #else
-                    C2F(mSize, width).inRange(176, 176, 16),
-                    C2F(mSize, height).inRange(144, 144, 16),
+                    C2F(mSize, width).oneOf({176, 352}),
+                    C2F(mSize, height).oneOf({144, 288}),
 #endif
                 })
                 .withSetter(SizeSetter)
@@ -253,9 +253,13 @@
     if (!mHandle) {
         mHandle = new tagvideoEncControls;
     }
+
     if (!mEncParams) {
         mEncParams = new tagvideoEncOptions;
     }
+
+    if (!(mEncParams && mHandle)) return C2_NO_MEMORY;
+
     mSignalledOutputEos = false;
     mSignalledError = false;
 
@@ -395,8 +399,10 @@
 void C2SoftMpeg4Enc::process(
         const std::unique_ptr<C2Work> &work,
         const std::shared_ptr<C2BlockPool> &pool) {
+    // Initialize output work
     work->result = C2_OK;
     work->workletsProcessed = 1u;
+    work->worklets.front()->output.flags = work->input.flags;
     if (mSignalledError || mSignalledOutputEos) {
         work->result = C2_BAD_VALUE;
         return;
@@ -432,8 +438,8 @@
         int32_t outputSize = mOutBufferSize;
         if (!PVGetVolHeader(mHandle, outPtr, &outputSize, 0)) {
             ALOGE("Failed to get VOL header");
-            work->result = C2_CORRUPTED;
             mSignalledError = true;
+            work->result = C2_CORRUPTED;
             return;
         } else {
             ALOGV("Bytes Generated in header %d\n", outputSize);
@@ -442,6 +448,12 @@
         ++mNumInputFrames;
         std::unique_ptr<C2StreamCsdInfo::output> csd =
             C2StreamCsdInfo::output::AllocUnique(outputSize, 0u);
+        if (!csd) {
+            ALOGE("CSD allocation failed");
+            mSignalledError = true;
+            work->result = C2_NO_MEMORY;
+            return;
+        }
         memcpy(csd->m.value, outPtr, outputSize);
         work->worklets.front()->output.configUpdate.push_back(std::move(csd));
     }
@@ -493,7 +505,7 @@
     size_t yPlaneSize = width * height;
     switch (layout.type) {
         case C2PlanarLayout::TYPE_RGB:
-        // fall-through
+            [[fallthrough]];
         case C2PlanarLayout::TYPE_RGBA: {
             MemoryBlock conversionBuffer = mConversionBuffers.fetch(yPlaneSize * 3 / 2);
             mConversionBuffersInUse.emplace(conversionBuffer.data(), conversionBuffer);
diff --git a/media/codecs/opus/C2SoftOpusDec.cpp b/media/codecs/opus/C2SoftOpusDec.cpp
index 996a87c..2439c3c 100644
--- a/media/codecs/opus/C2SoftOpusDec.cpp
+++ b/media/codecs/opus/C2SoftOpusDec.cpp
@@ -300,9 +300,12 @@
 void C2SoftOpusDec::process(
         const std::unique_ptr<C2Work> &work,
         const std::shared_ptr<C2BlockPool> &pool) {
+    // Initialize output work
     work->result = C2_OK;
-    work->workletsProcessed = 0u;
+    work->workletsProcessed = 1u;
     work->worklets.front()->output.configUpdate.clear();
+    work->worklets.front()->output.flags = work->input.flags;
+
     if (mSignalledError || mSignalledOutputEos) {
         work->result = C2_BAD_VALUE;
         return;
diff --git a/media/codecs/raw/C2SoftRawDec.cpp b/media/codecs/raw/C2SoftRawDec.cpp
index 27895c4..5c83481 100644
--- a/media/codecs/raw/C2SoftRawDec.cpp
+++ b/media/codecs/raw/C2SoftRawDec.cpp
@@ -83,6 +83,18 @@
                 DefineParam(mInputMaxBufSize, C2_PARAMKEY_INPUT_MAX_BUFFER_SIZE)
                 .withConstValue(new C2StreamMaxBufferSizeInfo::input(0u, 64 * 1024))
                 .build());
+
+        addParameter(
+                DefineParam(mPcmEncodingInfo, C2_PARAMKEY_PCM_ENCODING)
+                .withDefault(new C2StreamPcmEncodingInfo::output(0u, C2Config::PCM_16))
+                .withFields({C2F(mPcmEncodingInfo, value).oneOf({
+                     C2Config::PCM_16,
+                     C2Config::PCM_8,
+                     C2Config::PCM_FLOAT})
+                })
+                .withSetter((Setter<decltype(*mPcmEncodingInfo)>::StrictValueWithNoDeps))
+                .build());
+
     }
 
 private:
@@ -94,6 +106,7 @@
     std::shared_ptr<C2StreamChannelCountInfo::output> mChannelCount;
     std::shared_ptr<C2BitrateTuning::input> mBitrate;
     std::shared_ptr<C2StreamMaxBufferSizeInfo::input> mInputMaxBufSize;
+    std::shared_ptr<C2StreamPcmEncodingInfo::output> mPcmEncodingInfo;
 };
 
 C2SoftRawDec::C2SoftRawDec(
@@ -134,7 +147,8 @@
         const std::shared_ptr<C2BlockPool> &pool) {
     (void)pool;
     work->result = C2_OK;
-    work->workletsProcessed = 0u;
+    work->workletsProcessed = 1u;
+
     if (mSignalledEos) {
         work->result = C2_BAD_VALUE;
         return;
@@ -149,7 +163,6 @@
     if (!work->input.buffers.empty()) {
         work->worklets.front()->output.buffers.push_back(work->input.buffers[0]);
     }
-    work->workletsProcessed = 1u;
     if (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) {
         mSignalledEos = true;
         ALOGV("signalled EOS");
diff --git a/media/codecs/vorbis/C2SoftVorbisDec.cpp b/media/codecs/vorbis/C2SoftVorbisDec.cpp
index f67cf72..280ae36 100644
--- a/media/codecs/vorbis/C2SoftVorbisDec.cpp
+++ b/media/codecs/vorbis/C2SoftVorbisDec.cpp
@@ -231,9 +231,12 @@
 void C2SoftVorbisDec::process(
         const std::unique_ptr<C2Work> &work,
         const std::shared_ptr<C2BlockPool> &pool) {
+    // Initialize output work
     work->result = C2_OK;
-    work->workletsProcessed = 0u;
+    work->workletsProcessed = 1u;
     work->worklets.front()->output.configUpdate.clear();
+    work->worklets.front()->output.flags = work->input.flags;
+
     if (mSignalledError || mSignalledOutputEos) {
         work->result = C2_BAD_VALUE;
         return;
diff --git a/media/codecs/vpx/C2SoftVpxDec.cpp b/media/codecs/vpx/C2SoftVpxDec.cpp
index d6e49f7..8ecbf5d 100644
--- a/media/codecs/vpx/C2SoftVpxDec.cpp
+++ b/media/codecs/vpx/C2SoftVpxDec.cpp
@@ -97,6 +97,26 @@
                 .withSetter(ProfileLevelSetter, mSize)
                 .build());
 
+        mHdr10PlusInfoInput = C2StreamHdr10PlusInfo::input::AllocShared(0);
+        addParameter(
+                DefineParam(mHdr10PlusInfoInput, C2_PARAMKEY_INPUT_HDR10_PLUS_INFO)
+                .withDefault(mHdr10PlusInfoInput)
+                .withFields({
+                    C2F(mHdr10PlusInfoInput, m.value).any(),
+                })
+                .withSetter(Hdr10PlusInfoInputSetter)
+                .build());
+
+        mHdr10PlusInfoOutput = C2StreamHdr10PlusInfo::output::AllocShared(0);
+        addParameter(
+                DefineParam(mHdr10PlusInfoOutput, C2_PARAMKEY_OUTPUT_HDR10_PLUS_INFO)
+                .withDefault(mHdr10PlusInfoOutput)
+                .withFields({
+                    C2F(mHdr10PlusInfoOutput, m.value).any(),
+                })
+                .withSetter(Hdr10PlusInfoOutputSetter)
+                .build());
+
 #if 0
         // sample BT.2020 static info
         mHdrStaticInfo = std::make_shared<C2StreamHdrStaticInfo::output>();
@@ -217,6 +237,18 @@
         return C2R::Ok();
     }
 
+    static C2R Hdr10PlusInfoInputSetter(bool mayBlock, C2P<C2StreamHdr10PlusInfo::input> &me) {
+        (void)mayBlock;
+        (void)me;  // TODO: validate
+        return C2R::Ok();
+    }
+
+    static C2R Hdr10PlusInfoOutputSetter(bool mayBlock, C2P<C2StreamHdr10PlusInfo::output> &me) {
+        (void)mayBlock;
+        (void)me;  // TODO: validate
+        return C2R::Ok();
+    }
+
 private:
     std::shared_ptr<C2StreamProfileLevelInfo::input> mProfileLevel;
     std::shared_ptr<C2StreamPictureSizeInfo::output> mSize;
@@ -228,6 +260,8 @@
 #if 0
     std::shared_ptr<C2StreamHdrStaticInfo::output> mHdrStaticInfo;
 #endif
+    std::shared_ptr<C2StreamHdr10PlusInfo::input> mHdr10PlusInfoInput;
+    std::shared_ptr<C2StreamHdr10PlusInfo::output> mHdr10PlusInfoOutput;
 #endif
 };
 
@@ -320,6 +354,10 @@
     if (!mCodecCtx) {
         mCodecCtx = new vpx_codec_ctx_t;
     }
+    if (!mCodecCtx) {
+        ALOGE("mCodecCtx is null");
+        return NO_MEMORY;
+    }
 
     vpx_codec_dec_cfg_t cfg;
     memset(&cfg, 0, sizeof(vpx_codec_dec_cfg_t));
@@ -366,7 +404,8 @@
                            const std::shared_ptr<C2GraphicBlock> &block) {
     std::shared_ptr<C2Buffer> buffer = createGraphicBuffer(block,
                                                            C2Rect(mWidth, mHeight));
-    auto fillWork = [buffer, index](const std::unique_ptr<C2Work> &work) {
+    auto fillWork = [buffer, index, intf = this->mIntf](
+            const std::unique_ptr<C2Work> &work) {
         uint32_t flags = 0;
         if ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) &&
                 (c2_cntr64_t(index) == work->input.ordinal.frameIndex)) {
@@ -378,6 +417,28 @@
         work->worklets.front()->output.buffers.push_back(buffer);
         work->worklets.front()->output.ordinal = work->input.ordinal;
         work->workletsProcessed = 1u;
+
+        for (const std::unique_ptr<C2Param> &param: work->input.configUpdate) {
+            if (param) {
+                C2StreamHdr10PlusInfo::input *hdr10PlusInfo =
+                        C2StreamHdr10PlusInfo::input::From(param.get());
+
+                if (hdr10PlusInfo != nullptr) {
+                    std::vector<std::unique_ptr<C2SettingResult>> failures;
+                    std::unique_ptr<C2Param> outParam = C2Param::CopyAsStream(
+                            *param.get(), true /*output*/, param->stream());
+                    c2_status_t err = intf->config(
+                            { outParam.get() }, C2_MAY_BLOCK, &failures);
+                    if (err == C2_OK) {
+                        work->worklets.front()->output.configUpdate.push_back(
+                                C2Param::Copy(*outParam.get()));
+                    } else {
+                        ALOGE("finishWork: Config update size failed");
+                    }
+                    break;
+                }
+            }
+        }
     };
     if (work && c2_cntr64_t(index) == work->input.ordinal.frameIndex) {
         fillWork(work);
@@ -389,9 +450,12 @@
 void C2SoftVpxDec::process(
         const std::unique_ptr<C2Work> &work,
         const std::shared_ptr<C2BlockPool> &pool) {
+    // Initialize output work
     work->result = C2_OK;
     work->workletsProcessed = 0u;
     work->worklets.front()->output.configUpdate.clear();
+    work->worklets.front()->output.flags = work->input.flags;
+
     if (mSignalledError || mSignalledOutputEos) {
         work->result = C2_BAD_VALUE;
         return;
@@ -440,9 +504,9 @@
                 mCodecCtx, bitstream, inSize, &frameIndex, 0);
         if (err != VPX_CODEC_OK) {
             ALOGE("on2 decoder failed to decode frame. err: %d", err);
-            work->result = C2_CORRUPTED;
-            work->workletsProcessed = 1u;
             mSignalledError = true;
+            work->workletsProcessed = 1u;
+            work->result = C2_CORRUPTED;
             return;
         }
     }
@@ -510,8 +574,8 @@
         } else {
             ALOGE("Config update size failed");
             mSignalledError = true;
-            work->result = C2_CORRUPTED;
             work->workletsProcessed = 1u;
+            work->result = C2_CORRUPTED;
             return false;
         }
 
diff --git a/media/codecs/vpx/C2SoftVpxEnc.cpp b/media/codecs/vpx/C2SoftVpxEnc.cpp
index ead9c73..155a84f 100644
--- a/media/codecs/vpx/C2SoftVpxEnc.cpp
+++ b/media/codecs/vpx/C2SoftVpxEnc.cpp
@@ -348,7 +348,7 @@
               break;
           case kTemporalUpdateGoldenWithoutDependency:
               flags |= VP8_EFLAG_NO_REF_GF;
-              // Deliberately no break here.
+              [[fallthrough]];
           case kTemporalUpdateGolden:
               flags |= VP8_EFLAG_NO_REF_ARF;
               flags |= VP8_EFLAG_NO_UPD_ARF;
@@ -357,14 +357,14 @@
           case kTemporalUpdateAltrefWithoutDependency:
               flags |= VP8_EFLAG_NO_REF_ARF;
               flags |= VP8_EFLAG_NO_REF_GF;
-              // Deliberately no break here.
+              [[fallthrough]];
           case kTemporalUpdateAltref:
               flags |= VP8_EFLAG_NO_UPD_GF;
               flags |= VP8_EFLAG_NO_UPD_LAST;
               break;
           case kTemporalUpdateNoneNoRefAltref:
               flags |= VP8_EFLAG_NO_REF_ARF;
-              // Deliberately no break here.
+              [[fallthrough]];
           case kTemporalUpdateNone:
               flags |= VP8_EFLAG_NO_UPD_GF;
               flags |= VP8_EFLAG_NO_UPD_ARF;
@@ -412,8 +412,11 @@
 void C2SoftVpxEnc::process(
         const std::unique_ptr<C2Work> &work,
         const std::shared_ptr<C2BlockPool> &pool) {
+    // Initialize output work
     work->result = C2_OK;
     work->workletsProcessed = 1u;
+    work->worklets.front()->output.flags = work->input.flags;
+
     if (mSignalledError || mSignalledOutputEos) {
         work->result = C2_BAD_VALUE;
         return;
@@ -457,6 +460,7 @@
         ALOGE("unexpected Input buffer attributes %d(%d) x %d(%d)",
               inBuffer.width(), mSize->width, inBuffer.height(),
               mSize->height);
+        mSignalledError = true;
         work->result = C2_BAD_VALUE;
         return;
     }
@@ -563,6 +567,7 @@
             if (res != VPX_CODEC_OK) {
                 ALOGE("vpx encoder failed to update bitrate: %s",
                       vpx_codec_err_to_string(res));
+                mSignalledError = true;
                 work->result = C2_CORRUPTED;
                 return;
             }
@@ -589,6 +594,7 @@
                                                     VPX_DL_REALTIME);
     if (codec_return != VPX_CODEC_OK) {
         ALOGE("vpx encoder failed to encode frame");
+        mSignalledError = true;
         work->result = C2_CORRUPTED;
         return;
     }
diff --git a/media/codecs/xaac/C2SoftXaacDec.cpp b/media/codecs/xaac/C2SoftXaacDec.cpp
index ba856d1..1c0e70b 100644
--- a/media/codecs/xaac/C2SoftXaacDec.cpp
+++ b/media/codecs/xaac/C2SoftXaacDec.cpp
@@ -327,7 +327,10 @@
         return IA_FATAL_ERROR;
     }
 
-    mOutputDrainBuffer = new short[kOutputDrainBufferSize];
+    if (!mOutputDrainBuffer) {
+        mOutputDrainBuffer = new (std::nothrow) char[kOutputDrainBufferSize];
+        if (!mOutputDrainBuffer) return IA_FATAL_ERROR;
+    }
 
     err_code = initXAACDrc();
     RETURN_IF_FATAL(err_code,  "initXAACDrc");
@@ -357,7 +360,11 @@
     // TODO: error handling, proper usage, etc.
     c2_status_t err =
         pool->fetchLinearBlock(mOutputDrainBufferWritePos, usage, &block);
-    if (err != C2_OK) ALOGE("err = %d", err);
+    if (err != C2_OK) {
+        ALOGE("fetchLinearBlock failed : err = %d", err);
+        work->result = C2_NO_MEMORY;
+        return;
+    }
     C2WriteView wView = block->map().get();
     int16_t* outBuffer = reinterpret_cast<int16_t*>(wView.data());
     memcpy(outBuffer, mOutputDrainBuffer, mOutputDrainBufferWritePos);
@@ -387,9 +394,12 @@
 
 void C2SoftXaacDec::process(const std::unique_ptr<C2Work>& work,
                          const std::shared_ptr<C2BlockPool>& pool) {
-    work->workletsProcessed = 0u;
+    // Initialize output work
     work->result = C2_OK;
+    work->workletsProcessed = 1u;
     work->worklets.front()->output.configUpdate.clear();
+    work->worklets.front()->output.flags = work->input.flags;
+
     if (mSignalledError || mSignalledOutputEos) {
         work->result = C2_BAD_VALUE;
         return;
@@ -412,7 +422,6 @@
     bool eos = (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0;
     bool codecConfig =
         (work->input.flags & C2FrameData::FLAG_CODEC_CONFIG) != 0;
-
     if (codecConfig) {
         if (size == 0u) {
             ALOGE("empty codec config");
@@ -435,13 +444,13 @@
         work->worklets.front()->output.flags = work->input.flags;
         work->worklets.front()->output.ordinal = work->input.ordinal;
         work->worklets.front()->output.buffers.clear();
-        work->workletsProcessed = 1u;
         return;
     }
 
     mCurFrameIndex = work->input.ordinal.frameIndex.peeku();
     mCurTimestamp = work->input.ordinal.timestamp.peeku();
     mOutputDrainBufferWritePos = 0;
+    char* tempOutputDrainBuffer = mOutputDrainBuffer;
     while (size > 0u) {
         if ((kOutputDrainBufferSize * sizeof(int16_t) -
              mOutputDrainBufferWritePos) <
@@ -537,7 +546,7 @@
                     work->worklets.front()->output.configUpdate.push_back(
                         C2Param::Copy(channelCountInfo));
                 } else {
-                    ALOGE("Cannot set width and height");
+                    ALOGE("Config Update failed");
                     mSignalledError = true;
                     work->result = C2_CORRUPTED;
                     return;
@@ -588,7 +597,8 @@
 
             // fall through
         }
-        memcpy(mOutputDrainBuffer, mOutputBuffer, mNumOutBytes);
+        memcpy(tempOutputDrainBuffer, mOutputBuffer, mNumOutBytes);
+        tempOutputDrainBuffer += mNumOutBytes;
         mOutputDrainBufferWritePos += mNumOutBytes;
     }
 
@@ -623,7 +633,7 @@
     err_code = ixheaacd_dec_api(mXheaacCodecHandle,
                                 IA_API_CMD_INIT,
                                 IA_CMD_TYPE_FLUSH_MEM,
-                                NULL);
+                                nullptr);
     RETURN_IF_FATAL(err_code,  "IA_CMD_TYPE_FLUSH_MEM");
 
     err_code = ixheaacd_dec_api(mXheaacCodecHandle,
@@ -635,7 +645,7 @@
     err_code = ixheaacd_dec_api(mXheaacCodecHandle,
                                 IA_API_CMD_INIT,
                                 IA_CMD_TYPE_FLUSH_MEM,
-                                NULL);
+                                nullptr);
     RETURN_IF_FATAL(err_code,  "IA_CMD_TYPE_FLUSH_MEM");
 
     err_code = ixheaacd_dec_api(mXheaacCodecHandle,
@@ -695,7 +705,7 @@
     /* API size */
     uint32_t pui_api_size;
     /* Get the API size */
-    IA_ERRORCODE err_code = ixheaacd_dec_api(NULL,
+    IA_ERRORCODE err_code = ixheaacd_dec_api(nullptr,
                                              IA_API_CMD_GET_API_SIZE,
                                              0,
                                              &pui_api_size);
@@ -713,11 +723,11 @@
     err_code = ixheaacd_dec_api(mXheaacCodecHandle,
                                 IA_API_CMD_INIT,
                                 IA_CMD_TYPE_INIT_API_PRE_CONFIG_PARAMS,
-                                NULL);
+                                nullptr);
     RETURN_IF_FATAL(err_code,  "IA_CMD_TYPE_INIT_API_PRE_CONFIG_PARAMS");
 
     /* Get the API size */
-    err_code = ia_drc_dec_api(NULL, IA_API_CMD_GET_API_SIZE, 0, &pui_api_size);
+    err_code = ia_drc_dec_api(nullptr, IA_API_CMD_GET_API_SIZE, 0, &pui_api_size);
 
     RETURN_IF_FATAL(err_code, "IA_API_CMD_GET_API_SIZE");
 
@@ -731,7 +741,7 @@
 
     /* Set the config params to default values */
     err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_INIT,
-                              IA_CMD_TYPE_INIT_API_PRE_CONFIG_PARAMS, NULL);
+                              IA_CMD_TYPE_INIT_API_PRE_CONFIG_PARAMS, nullptr);
 
     RETURN_IF_FATAL(err_code, "IA_CMD_TYPE_INIT_API_PRE_CONFIG_PARAMS");
 
@@ -775,7 +785,7 @@
     err_code = ixheaacd_dec_api(mXheaacCodecHandle,
                                 IA_API_CMD_INIT,
                                 IA_CMD_TYPE_INIT_API_POST_CONFIG_PARAMS,
-                                NULL);
+                                nullptr);
     RETURN_IF_FATAL(err_code,  "IA_CMD_TYPE_INIT_API_POST_CONFIG_PARAMS");
 
     /* ******************************************************************/
@@ -906,12 +916,12 @@
         err_code = ixheaacd_dec_api(mXheaacCodecHandle,
                                     IA_API_CMD_INPUT_OVER,
                                     0,
-                                    NULL);
+                                    nullptr);
     }
 
     /* Irrespective of error returned in IA_API_CMD_INPUT_OVER, free allocated memory */
     for (void* buf : mMemoryVec) {
-        free(buf);
+        if (buf) free(buf);
     }
     mMemoryVec.clear();
     mXheaacCodecHandle = nullptr;
@@ -923,7 +933,7 @@
     ALOGV("deInitMPEGDDDrc");
 
     for (void* buf : mDrcMemoryVec) {
-        free(buf);
+        if (buf) free(buf);
     }
     mDrcMemoryVec.clear();
     return IA_NO_ERROR;
@@ -951,14 +961,14 @@
         err_code = ixheaacd_dec_api(mXheaacCodecHandle,
                                     IA_API_CMD_INIT,
                                     IA_CMD_TYPE_GA_HDR,
-                                    NULL);
+                                    nullptr);
         RETURN_IF_FATAL(err_code,  "IA_CMD_TYPE_GA_HDR");
     } else {
         /* Initialize the process */
         err_code = ixheaacd_dec_api(mXheaacCodecHandle,
                                     IA_API_CMD_INIT,
                                     IA_CMD_TYPE_INIT_PROCESS,
-                                    NULL);
+                                    nullptr);
         RETURN_IF_FATAL(err_code,  "IA_CMD_TYPE_INIT_PROCESS");
     }
 
@@ -1014,7 +1024,7 @@
         RETURN_IF_FATAL(err_code, "IA_API_CMD_GET_MEM_INFO_TYPE");
 
         pv_alloc_ptr = memalign(4, ui_size);
-        if (pv_alloc_ptr == NULL) {
+        if (pv_alloc_ptr == nullptr) {
             ALOGE(" Cannot create requested memory  %d", ui_size);
             return IA_FATAL_ERROR;
         }
@@ -1030,7 +1040,7 @@
     ui_size = 8192 * 2;
 
     mDrcInBuf = (int8_t*)memalign(4, ui_size);
-    if (mDrcInBuf == NULL) {
+    if (mDrcInBuf == nullptr) {
         ALOGE(" Cannot create requested memory  %d", ui_size);
         return IA_FATAL_ERROR;
     }
@@ -1040,7 +1050,7 @@
     RETURN_IF_FATAL(err_code, "IA_API_CMD_SET_MEM_PTR");
 
     mDrcOutBuf = (int8_t*)memalign(4, ui_size);
-    if (mDrcOutBuf == NULL) {
+    if (mDrcOutBuf == nullptr) {
         ALOGE(" Cannot create requested memory  %d", ui_size);
         return IA_FATAL_ERROR;
     }
@@ -1106,7 +1116,7 @@
     RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_PARAM_SBR_MODE");
 
     err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_INIT,
-                              IA_CMD_TYPE_INIT_API_POST_CONFIG_PARAMS, NULL);
+                              IA_CMD_TYPE_INIT_API_POST_CONFIG_PARAMS, nullptr);
 
     RETURN_IF_FATAL(err_code, "IA_CMD_TYPE_INIT_API_POST_CONFIG_PARAMS");
 
@@ -1145,7 +1155,7 @@
         RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_EXT_ELE_PTR");
 
         err_code =
-            ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_INIT, IA_CMD_TYPE_INIT_SET_BUFF_PTR, 0);
+            ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_INIT, IA_CMD_TYPE_INIT_SET_BUFF_PTR, nullptr);
         RETURN_IF_FATAL(err_code, "IA_CMD_TYPE_INIT_SET_BUFF_PTR");
 
         err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_GET_CONFIG_PARAM,
@@ -1173,7 +1183,7 @@
 
                 /* Execute process */
                 err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_INIT,
-                                          IA_CMD_TYPE_INIT_CPY_IL_BSF_BUFF, NULL);
+                                          IA_CMD_TYPE_INIT_CPY_IL_BSF_BUFF, nullptr);
                 RETURN_IF_FATAL(err_code, "IA_CMD_TYPE_INIT_CPY_IL_BSF_BUFF");
 
                 mDRCFlag = 1;
@@ -1197,7 +1207,7 @@
 
                 /* Execute process */
                 err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_INIT,
-                                          IA_CMD_TYPE_INIT_CPY_IC_BSF_BUFF, NULL);
+                                          IA_CMD_TYPE_INIT_CPY_IC_BSF_BUFF, nullptr);
 
                 RETURN_IF_FATAL(err_code, "IA_CMD_TYPE_INIT_CPY_IC_BSF_BUFF");
 
@@ -1238,11 +1248,11 @@
 
             /* Execute process */
             err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_INIT,
-                                      IA_CMD_TYPE_INIT_CPY_IN_BSF_BUFF, NULL);
+                                      IA_CMD_TYPE_INIT_CPY_IN_BSF_BUFF, nullptr);
             RETURN_IF_FATAL(err_code, "IA_CMD_TYPE_INIT_CPY_IN_BSF_BUFF");
 
             err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_INIT,
-                                      IA_CMD_TYPE_INIT_PROCESS, NULL);
+                                      IA_CMD_TYPE_INIT_PROCESS, nullptr);
             RETURN_IF_FATAL(err_code, "IA_CMD_TYPE_INIT_PROCESS");
 
             err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_GET_CONFIG_PARAM,
@@ -1276,7 +1286,7 @@
     err_code = ixheaacd_dec_api(mXheaacCodecHandle,
                                 IA_API_CMD_EXECUTE,
                                 IA_CMD_TYPE_DO_EXECUTE,
-                                NULL);
+                                nullptr);
     RETURN_IF_FATAL(err_code,  "IA_CMD_TYPE_DO_EXECUTE");
 
     /* Checking for end of processing */
@@ -1319,7 +1329,7 @@
 
             /* Execute process */
             err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_INIT,
-                                      IA_CMD_TYPE_INIT_CPY_BSF_BUFF, NULL);
+                                      IA_CMD_TYPE_INIT_CPY_BSF_BUFF, nullptr);
             RETURN_IF_FATAL(err_code, "IA_DRC_DEC_CONFIG_PARAM_BITS_FORMAT");
 
             mMpegDDRCPresent = 1;
@@ -1346,7 +1356,7 @@
         RETURN_IF_FATAL(err_code, "IA_API_CMD_SET_INPUT_BYTES");
 
         err_code =
-            ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_EXECUTE, IA_CMD_TYPE_DO_EXECUTE, NULL);
+            ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_EXECUTE, IA_CMD_TYPE_DO_EXECUTE, nullptr);
         RETURN_IF_FATAL(err_code, "IA_CMD_TYPE_DO_EXECUTE");
 
         memcpy(mOutputBuffer, mDrcOutBuf, *outBytes);
diff --git a/media/codecs/xaac/C2SoftXaacDec.h b/media/codecs/xaac/C2SoftXaacDec.h
index b99d2ea..5c8567f 100644
--- a/media/codecs/xaac/C2SoftXaacDec.h
+++ b/media/codecs/xaac/C2SoftXaacDec.h
@@ -97,7 +97,7 @@
     size_t mOutputBufferCount __unused;
     bool mSignalledOutputEos;
     bool mSignalledError;
-    short* mOutputDrainBuffer;
+    char* mOutputDrainBuffer;
     uint32_t mOutputDrainBufferWritePos;
 
     IA_ERRORCODE initDecoder();
diff --git a/media/eco/.clang-format b/media/eco/.clang-format
new file mode 100644
index 0000000..b043d46
--- /dev/null
+++ b/media/eco/.clang-format
@@ -0,0 +1,33 @@
+---
+BasedOnStyle: Google
+AllowShortFunctionsOnASingleLine: Inline
+AllowShortIfStatementsOnASingleLine: true
+AllowShortLoopsOnASingleLine: true
+BinPackArguments: true
+BinPackParameters: true
+CommentPragmas: NOLINT:.*
+ContinuationIndentWidth: 8
+DerivePointerAlignment: false
+IndentWidth: 4
+PointerAlignment: Left
+TabWidth: 4
+
+# Deviations from the above file:
+# "Don't indent the section label"
+AccessModifierOffset: -4
+# "Each line of text in your code should be at most 100 columns long."
+ColumnLimit: 100
+# "Constructor initializer lists can be all on one line or with subsequent
+# lines indented eight spaces.". clang-format does not support having the colon
+# on the same line as the constructor function name, so this is the best
+# approximation of that rule, which makes all entries in the list (except the
+# first one) have an eight space indentation.
+ConstructorInitializerIndentWidth: 6
+# There is nothing in go/droidcppstyle about case labels, but there seems to be
+# more code that does not indent the case labels in frameworks/base.
+IndentCaseLabels: false
+# There have been some bugs in which subsequent formatting operations introduce
+# weird comment jumps.
+ReflowComments: false
+# Android does support C++11 now.
+Standard: Cpp11
diff --git a/media/eco/Android.bp b/media/eco/Android.bp
new file mode 100644
index 0000000..d4fcb01
--- /dev/null
+++ b/media/eco/Android.bp
@@ -0,0 +1,55 @@
+cc_library_shared {
+name:
+    "libmedia_ecoservice",
+    vendor_available: true,
+
+    srcs: [
+        "aidl/android/media/eco/IECOService.aidl",
+        "aidl/android/media/eco/IECOSession.aidl",
+        "aidl/android/media/eco/IECOServiceStatsProvider.aidl",
+        "aidl/android/media/eco/IECOServiceInfoListener.aidl",
+        "ECOData.cpp",
+        "ECODebug.cpp",
+        "ECOService.cpp",
+        "ECOSession.cpp",
+        "ECOUtils.cpp",
+        ],
+
+    aidl: {
+        local_include_dirs: ["include","aidl"],
+        export_aidl_headers: true,
+    },
+
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+
+    local_include_dirs: [
+        "include",
+    ],
+
+    shared_libs: [
+        "libbinder",
+        "libcutils",
+        "liblog",
+        "libutils",
+    ],
+
+    export_include_dirs: [
+         "include"
+    ],
+
+    sanitize: {
+        misc_undefined: [
+            "unsigned-integer-overflow",
+            "signed-integer-overflow",
+        ],
+        cfi: false, // true,
+        diag: {
+            cfi: false, // true,
+        },
+    },
+
+    ldflags: ["-Wl,-Bsymbolic"],
+}
\ No newline at end of file
diff --git a/media/eco/ECOData.cpp b/media/eco/ECOData.cpp
new file mode 100644
index 0000000..189e609
--- /dev/null
+++ b/media/eco/ECOData.cpp
@@ -0,0 +1,421 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "ECOData"
+
+#include "eco/ECOData.h"
+
+#include <binder/Parcel.h>
+#include <inttypes.h>
+#include <utils/Errors.h>
+#include <utils/Log.h>
+
+#include <string>
+
+#include "eco/ECODataKey.h"
+#include "eco/ECOUtils.h"
+
+namespace android {
+namespace media {
+namespace eco {
+
+using namespace ::android;
+
+status_t ECOData::readFromParcel(const Parcel* parcel) {
+    if (parcel == nullptr) {
+        ALOGE("readFromParcel failed. Parcel pointer can not be null");
+        return BAD_VALUE;
+    }
+
+    // Reads the data type and time.
+    RETURN_STATUS_IF_ERROR(parcel->readInt32(&mDataType));
+    RETURN_STATUS_IF_ERROR(parcel->readInt64(&mDataTimeUs));
+
+    // Reads the number of items.
+    uint32_t numOfItems = 0;
+    RETURN_STATUS_IF_ERROR(parcel->readUint32(&numOfItems));
+
+    // Reads the key-value pairs one by one.
+    for (size_t i = 0; i < numOfItems; ++i) {
+        // Reads the name of the key.
+        const char* name = parcel->readCString();
+        if (name == NULL) {
+            ALOGE("Failed reading name for the key. Parsing aborted.");
+            return NAME_NOT_FOUND;
+        }
+
+        int32_t type;
+        RETURN_STATUS_IF_ERROR(parcel->readInt32(&type));
+        switch (static_cast<ValueType>(type)) {
+        case kTypeInt32: {
+            int32_t value32;
+            RETURN_STATUS_IF_ERROR(parcel->readInt32(&value32));
+            setInt32(std::string(name), value32);
+            break;
+        }
+        case kTypeInt64: {
+            int64_t value64;
+            RETURN_STATUS_IF_ERROR(parcel->readInt64(&value64));
+            setInt64(std::string(name), value64);
+            break;
+        }
+        case kTypeSize: {
+            int32_t valueSize;
+            RETURN_STATUS_IF_ERROR(parcel->readInt32(&valueSize));
+            setInt32(std::string(name), valueSize);
+            break;
+        }
+        case kTypeFloat: {
+            float valueFloat;
+            RETURN_STATUS_IF_ERROR(parcel->readFloat(&valueFloat));
+            setFloat(std::string(name), valueFloat);
+            break;
+        }
+        case kTypeDouble: {
+            double valueDouble;
+            RETURN_STATUS_IF_ERROR(parcel->readDouble(&valueDouble));
+            setDouble(std::string(name), valueDouble);
+            break;
+        }
+        case kTypeString: {
+            const char* valueStr = parcel->readCString();
+            if (valueStr == NULL) {
+                ALOGE("Failed reading name for the key. Parsing aborted.");
+                return NAME_NOT_FOUND;
+            }
+            setString(std::string(name), valueStr);
+            break;
+        }
+        case kTypeInt8: {
+            int8_t value8;
+            RETURN_STATUS_IF_ERROR(parcel->readByte(&value8));
+            setInt8(std::string(name), value8);
+            break;
+        }
+        default: {
+            return BAD_TYPE;
+        }
+        }
+    }
+
+    return NO_ERROR;
+}
+
+status_t ECOData::writeToParcel(Parcel* parcel) const {
+    if (parcel == nullptr) {
+        ALOGE("writeToParcel failed. Parcel pointer can not be null");
+        return BAD_VALUE;
+    }
+
+    // Writes out the data type and time.
+    RETURN_STATUS_IF_ERROR(parcel->writeInt32(mDataType));
+    RETURN_STATUS_IF_ERROR(parcel->writeInt64(mDataTimeUs));
+
+    // Writes out number of items.
+    RETURN_STATUS_IF_ERROR(parcel->writeUint32(int32_t(mKeyValueStore.size())));
+
+    // Writes out the key-value pairs one by one.
+    for (const auto& it : mKeyValueStore) {
+        // Writes out the key.
+        RETURN_STATUS_IF_ERROR(parcel->writeCString(it.first.c_str()));
+
+        // Writes out the data type.
+        const ECODataValueType& value = it.second;
+        RETURN_STATUS_IF_ERROR(parcel->writeInt32(static_cast<int32_t>(value.index())));
+        switch (static_cast<ValueType>(value.index())) {
+        case kTypeInt32:
+            RETURN_STATUS_IF_ERROR(parcel->writeInt32(std::get<int32_t>(it.second)));
+            break;
+
+        case kTypeInt64:
+            RETURN_STATUS_IF_ERROR(parcel->writeInt64(std::get<int64_t>(it.second)));
+            break;
+
+        case kTypeSize:
+            RETURN_STATUS_IF_ERROR(parcel->writeUint32(std::get<size_t>(it.second)));
+            break;
+
+        case kTypeFloat:
+            RETURN_STATUS_IF_ERROR(parcel->writeFloat(std::get<float>(it.second)));
+            break;
+
+        case kTypeDouble:
+            RETURN_STATUS_IF_ERROR(parcel->writeDouble(std::get<double>(it.second)));
+            break;
+
+        case kTypeString:
+            RETURN_STATUS_IF_ERROR(parcel->writeCString(std::get<std::string>(it.second).c_str()));
+            break;
+
+        case kTypeInt8:
+            RETURN_STATUS_IF_ERROR(parcel->writeByte(std::get<int8_t>(it.second)));
+            break;
+
+        default:
+            return BAD_TYPE;
+        }
+    }
+
+    return NO_ERROR;
+}
+
+int32_t ECOData::getDataType() const {
+    return mDataType;
+}
+
+int64_t ECOData::getDataTimeUs() const {
+    return mDataTimeUs;
+}
+
+// Inserts a new key into store if the key does not exist yet. Otherwise, this will override the
+// existing key's value.
+ECODataStatus ECOData::setString(const std::string& key, const std::string& value) {
+    if (key.empty() || value.empty()) {
+        return ECODataStatus::INVALID_ARGUMENT;
+    }
+
+    mKeyValueStore[key] = value;
+
+    // TODO(hkuang): Check the valueType is valid for the key.
+    return ECODataStatus::OK;
+}
+
+ECODataStatus ECOData::findString(const std::string& key, std::string* value) const {
+    if (key.empty()) {
+        return ECODataStatus::INVALID_ARGUMENT;
+    }
+
+    // Check if the key exists.
+    if (mKeyValueStore.find(key) == mKeyValueStore.end()) {
+        return ECODataStatus::KEY_NOT_EXIST;
+    }
+
+    // Safely access the value.
+    const std::string& entryValue = std::get<std::string>(mKeyValueStore.at(key));
+    value->assign(entryValue);
+
+    return ECODataStatus::OK;
+}
+
+// Inserts a new key into store if the key does not exist yet. Otherwise, this will override the
+// existing key's value.
+template <typename T>
+ECODataStatus ECOData::setValue(const std::string& key, T value) {
+    if (key.empty()) {
+        return ECODataStatus::INVALID_ARGUMENT;
+    }
+
+    mKeyValueStore[key] = value;
+    return ECODataStatus::OK;
+}
+
+template <typename T>
+ECODataStatus ECOData::findValue(const std::string& key, T* out) const {
+    if (key.empty() || out == nullptr) {
+        return ECODataStatus::INVALID_ARGUMENT;
+    }
+
+    if (mKeyValueStore.find(key) == mKeyValueStore.end()) {
+        return ECODataStatus::KEY_NOT_EXIST;
+    }
+
+    // Safely access the value.
+    *out = std::get<T>(mKeyValueStore.at(key));
+
+    return ECODataStatus::OK;
+}
+
+ECODataStatus ECOData::setInt32(const std::string& key, int32_t value) {
+    return setValue<int32_t>(key, value);
+}
+
+ECODataStatus ECOData::findInt32(const std::string& key, int32_t* out) const {
+    return findValue<int32_t>(key, out);
+}
+
+ECODataStatus ECOData::setInt64(const std::string& key, int64_t value) {
+    return setValue<int64_t>(key, value);
+}
+
+ECODataStatus ECOData::findInt64(const std::string& key, int64_t* out) const {
+    return findValue<int64_t>(key, out);
+}
+
+ECODataStatus ECOData::setDouble(const std::string& key, double value) {
+    return setValue<double>(key, value);
+}
+
+ECODataStatus ECOData::findDouble(const std::string& key, double* out) const {
+    return findValue<double>(key, out);
+}
+
+ECODataStatus ECOData::setSize(const std::string& key, size_t value) {
+    return setValue<size_t>(key, value);
+}
+
+ECODataStatus ECOData::findSize(const std::string& key, size_t* out) const {
+    return findValue<size_t>(key, out);
+}
+
+ECODataStatus ECOData::setFloat(const std::string& key, float value) {
+    return setValue<float>(key, value);
+}
+
+ECODataStatus ECOData::findFloat(const std::string& key, float* out) const {
+    return findValue<float>(key, out);
+}
+
+ECODataStatus ECOData::setInt8(const std::string& key, int8_t value) {
+    return setValue<int8_t>(key, value);
+}
+
+ECODataStatus ECOData::findInt8(const std::string& key, int8_t* out) const {
+    return findValue<int8_t>(key, out);
+}
+
+ECODataStatus ECOData::set(const std::string& key, const ECOData::ECODataValueType& value) {
+    if (key.empty()) {
+        return ECODataStatus::INVALID_ARGUMENT;
+    }
+    mKeyValueStore[key] = value;
+    return ECODataStatus::OK;
+}
+
+ECODataStatus ECOData::find(const std::string& key, ECOData::ECODataValueType* out) const {
+    if (key.empty() || out == nullptr) {
+        return ECODataStatus::INVALID_ARGUMENT;
+    }
+
+    if (mKeyValueStore.find(key) == mKeyValueStore.end()) {
+        return ECODataStatus::KEY_NOT_EXIST;
+    }
+
+    // Safely access the value.
+    *out = mKeyValueStore.at(key);
+
+    return ECODataStatus::OK;
+}
+
+std::string ECOData::getDataTypeString() const {
+    switch (mDataType) {
+    case DATA_TYPE_UNKNOWN:
+        return "DATA_TYPE_UNKNOWN";
+    case DATA_TYPE_STATS:
+        return "DATA_TYPE_STATS";
+    case DATA_TYPE_INFO:
+        return "DATA_TYPE_INFO";
+    case DATA_TYPE_STATS_PROVIDER_CONFIG:
+        return "DATA_TYPE_STATS_PROVIDER_CONFIG";
+    case DATA_TYPE_INFO_LISTENER_CONFIG:
+        return "DATA_TYPE_INFO_LISTENER_CONFIG";
+    }
+    return {};
+}
+
+// TODO(hkuang): Add test for this.
+bool ECODataKeyValueIterator::hasNext() {
+    if (mIterator == mKeyValueStore.end()) return false;
+
+    if (!mBeginReturned) {
+        // mIterator has been initialized to the beginning and
+        // hasn't been returned. Do not advance:
+        mBeginReturned = true;
+    } else {
+        std::advance(mIterator, 1);
+    }
+    return mIterator != mKeyValueStore.end();
+}
+
+// TODO(hkuang): Add test for this.
+ECOData::ECODataKeyValuePair ECODataKeyValueIterator::next() const {
+    return ECOData::ECODataKeyValuePair(mIterator->first, mIterator->second);
+}
+
+std::string ECOData::debugString() const {
+    std::string s = "ECOData(type = ";
+
+    std::string tmp;
+    switch (mDataType) {
+    case DATA_TYPE_UNKNOWN:
+        tmp = "Unknown";
+        break;
+    case DATA_TYPE_STATS:
+        tmp = "Stats";
+        break;
+    case DATA_TYPE_INFO:
+        tmp = "Info";
+        break;
+    case DATA_TYPE_STATS_PROVIDER_CONFIG:
+        tmp = "Stats provider config";
+        break;
+    case DATA_TYPE_INFO_LISTENER_CONFIG:
+        tmp = "Info listener config";
+        break;
+    default:
+        break;
+    }
+    s.append(tmp);
+    s.append(") = {\n  ");
+
+    // Writes out the key-value pairs one by one.
+    for (const auto& it : mKeyValueStore) {
+        const size_t SIZE = 100;
+        char keyValue[SIZE];
+        const ECODataValueType& value = it.second;
+        switch (static_cast<ValueType>(value.index())) {
+        case kTypeInt32:
+            snprintf(keyValue, SIZE, "int32_t %s = %d, ", it.first.c_str(),
+                     std::get<int32_t>(it.second));
+            break;
+        case kTypeInt64:
+            snprintf(keyValue, SIZE, "int64_t %s = %" PRId64 ", ", it.first.c_str(),
+                     std::get<int64_t>(it.second));
+            break;
+        case kTypeSize:
+            snprintf(keyValue, SIZE, "size_t %s = %zu, ", it.first.c_str(),
+                     std::get<size_t>(it.second));
+            break;
+        case kTypeFloat:
+            snprintf(keyValue, SIZE, "float %s = %f, ", it.first.c_str(),
+                     std::get<float>(it.second));
+            break;
+        case kTypeDouble:
+            snprintf(keyValue, SIZE, "double %s = %f, ", it.first.c_str(),
+                     std::get<double>(it.second));
+            break;
+        case kTypeString:
+            snprintf(keyValue, SIZE, "string %s = %s, ", it.first.c_str(),
+                     std::get<std::string>(it.second).c_str());
+            break;
+        case kTypeInt8:
+            snprintf(keyValue, SIZE, "int8_t %s = %d, ", it.first.c_str(),
+                     std::get<int8_t>(it.second));
+            break;
+        default:
+            break;
+        }
+        s.append(keyValue);
+    }
+
+    s.append("\n }");
+
+    return s;
+}
+
+}  // namespace eco
+}  // namespace media
+}  // namespace android
diff --git a/media/eco/ECODebug.cpp b/media/eco/ECODebug.cpp
new file mode 100644
index 0000000..5ed08ab
--- /dev/null
+++ b/media/eco/ECODebug.cpp
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "eco/ECODebug.h"
+
+namespace android {
+namespace media {
+namespace eco {
+
+uint32_t gECOLogLevel = 0;
+
+void updateLogLevel() {
+    gECOLogLevel = property_get_int32(kDebugLogsLevelProperty, 0);
+    ALOGI("ECOService log level is %d", gECOLogLevel);
+}
+
+}  // namespace eco
+}  // namespace media
+}  // namespace android
diff --git a/media/eco/ECOService.cpp b/media/eco/ECOService.cpp
new file mode 100644
index 0000000..6cc4be4
--- /dev/null
+++ b/media/eco/ECOService.cpp
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "ECOService"
+
+#include "eco/ECOService.h"
+
+#include <binder/BinderService.h>
+#include <cutils/atomic.h>
+#include <inttypes.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <sys/types.h>
+
+#include <algorithm>
+#include <climits>
+#include <cstring>
+#include <ctime>
+#include <string>
+
+#include "eco/ECODebug.h"
+
+namespace android {
+namespace media {
+namespace eco {
+
+ECOService::ECOService() : BnECOService() {
+    ALOGD("ECOService created");
+    updateLogLevel();
+}
+
+/*virtual*/ ::android::binder::Status ECOService::obtainSession(
+        int32_t width, int32_t height, bool isCameraRecording,
+        ::android::sp<::android::media::eco::IECOSession>* _aidl_return) {
+    ECOLOGI("ECOService::obtainSession w: %d, h: %d, isCameraRecording: %d", width, height,
+            isCameraRecording);
+
+    if (width <= 0) {
+        return STATUS_ERROR(ERROR_ILLEGAL_ARGUMENT, "Width can not be <= 0");
+    }
+
+    if (height <= 0) {
+        return STATUS_ERROR(ERROR_ILLEGAL_ARGUMENT, "Height can not be <= 0");
+    }
+
+    SessionConfig newCfg(width, height, isCameraRecording);
+
+    ECOLOGD("session count before is %zu", mSessionConfigToSessionMap.size());
+
+    Mutex::Autolock lock(mServiceLock);
+    bool foundSession = false;
+    // Instead of looking up the map directly, take the chance to scan the map and evict all the
+    // invalid sessions.
+    SanitizeSession([&](MapIterType iter) {
+        if (iter->first == newCfg) {
+            sp<ECOSession> session = iter->second.promote();
+            foundSession = true;
+            *_aidl_return = session;
+        }
+    });
+
+    if (foundSession) {
+        return binder::Status::ok();
+    }
+
+    // Create a new session and add it to the record.
+    sp<ECOSession> newSession = ECOSession::createECOSession(width, height, isCameraRecording);
+    if (newSession == nullptr) {
+        ECOLOGE("ECOService failed to create ECOSession w: %d, h: %d, isCameraRecording: %d", width,
+                height, isCameraRecording);
+        return STATUS_ERROR(ERROR_UNSUPPORTED, "Failed to create eco session");
+    }
+    *_aidl_return = newSession;
+    // Insert the new session into the map.
+    mSessionConfigToSessionMap[newCfg] = newSession;
+    ECOLOGD("session count after is %zu", mSessionConfigToSessionMap.size());
+
+    return binder::Status::ok();
+}
+
+/*virtual*/ ::android::binder::Status ECOService::getNumOfSessions(int32_t* _aidl_return) {
+    Mutex::Autolock lock(mServiceLock);
+    SanitizeSession(std::function<void(MapIterType it)>());  // empty callback
+    *_aidl_return = mSessionConfigToSessionMap.size();
+    return binder::Status::ok();
+}
+
+/*virtual*/ ::android::binder::Status ECOService::getSessions(
+        ::std::vector<::android::sp<::android::IBinder>>* _aidl_return) {
+    // Clear all the entries in the vector.
+    _aidl_return->clear();
+
+    Mutex::Autolock lock(mServiceLock);
+    SanitizeSession([&](MapIterType iter) {
+        sp<ECOSession> session = iter->second.promote();
+        _aidl_return->push_back(IInterface::asBinder(session));
+    });
+    return binder::Status::ok();
+}
+
+inline bool isEmptySession(const android::wp<ECOSession>& entry) {
+    sp<ECOSession> session = entry.promote();
+    return session == nullptr;
+}
+
+void ECOService::SanitizeSession(
+        const std::function<void(std::unordered_map<SessionConfig, wp<ECOSession>,
+                                                    SessionConfigHash>::iterator it)>& callback) {
+    for (auto it = mSessionConfigToSessionMap.begin(), end = mSessionConfigToSessionMap.end();
+         it != end;) {
+        if (isEmptySession(it->second)) {
+            it = mSessionConfigToSessionMap.erase(it);
+        } else {
+            if (callback != nullptr) {
+                callback(it);
+            };
+            it++;
+        }
+    }
+}
+
+/*virtual*/ void ECOService::binderDied(const wp<IBinder>& /*who*/) {}
+
+status_t ECOService::dump(int fd, const Vector<String16>& args) {
+    Mutex::Autolock lock(mServiceLock);
+    dprintf(fd, "\n== ECO Service info: ==\n\n");
+    dprintf(fd, "Number of ECOServices: %zu\n", mSessionConfigToSessionMap.size());
+    for (auto it = mSessionConfigToSessionMap.begin(), end = mSessionConfigToSessionMap.end();
+         it != end; it++) {
+        sp<ECOSession> session = it->second.promote();
+        if (session != nullptr) {
+            session->dump(fd, args);
+        }
+    }
+
+    return NO_ERROR;
+}
+
+}  // namespace eco
+}  // namespace media
+}  // namespace android
\ No newline at end of file
diff --git a/media/eco/ECOSession.cpp b/media/eco/ECOSession.cpp
new file mode 100644
index 0000000..752df4e
--- /dev/null
+++ b/media/eco/ECOSession.cpp
@@ -0,0 +1,575 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "ECOSession"
+//#define DEBUG_ECO_SESSION
+#include "eco/ECOSession.h"
+
+#include <binder/BinderService.h>
+#include <cutils/atomic.h>
+#include <inttypes.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <utils/Log.h>
+
+#include <algorithm>
+#include <climits>
+#include <cstring>
+#include <ctime>
+#include <string>
+
+#include "eco/ECODataKey.h"
+#include "eco/ECODebug.h"
+
+namespace android {
+namespace media {
+namespace eco {
+
+using android::binder::Status;
+using android::sp;
+
+#define RETURN_IF_ERROR(expr)         \
+    {                                 \
+        status_t _errorCode = (expr); \
+        if (_errorCode != true) {     \
+            return _errorCode;        \
+        }                             \
+    }
+
+// static
+sp<ECOSession> ECOSession::createECOSession(int32_t width, int32_t height, bool isCameraRecording) {
+    // Only support up to 720P.
+    // TODO: Support the same resolution as in EAF.
+    if (width <= 0 || height <= 0 || width > 5120 || height > 5120 ||
+        width > 1280 * 720 / height) {
+        ECOLOGE("Failed to create ECOSession with w: %d, h: %d, isCameraRecording: %d", width,
+                height, isCameraRecording);
+        return nullptr;
+    }
+    return new ECOSession(width, height, isCameraRecording);
+}
+
+ECOSession::ECOSession(int32_t width, int32_t height, bool isCameraRecording)
+      : BnECOSession(),
+        mStopThread(false),
+        mLastReportedQp(0),
+        mListener(nullptr),
+        mProvider(nullptr),
+        mWidth(width),
+        mHeight(height),
+        mIsCameraRecording(isCameraRecording) {
+    ECOLOGI("ECOSession created with w: %d, h: %d, isCameraRecording: %d", mWidth, mHeight,
+            mIsCameraRecording);
+    mThread = std::thread(startThread, this);
+
+    // Read the debug properies.
+    mLogStats = property_get_bool(kDebugLogStats, false);
+    mLogStatsEntries = mLogStats ? property_get_int32(kDebugLogStatsSize, 0) : 0;
+
+    mLogInfo = property_get_bool(kDebugLogStats, false);
+    mLogInfoEntries = mLogInfo ? property_get_int32(kDebugLogInfosSize, 0) : 0;
+
+    ECOLOGI("ECOSession debug settings: logStats: %s, entries: %d, logInfo: %s entries: %d",
+            mLogStats ? "true" : "false", mLogStatsEntries, mLogInfo ? "true" : "false",
+            mLogInfoEntries);
+}
+
+ECOSession::~ECOSession() {
+    mStopThread = true;
+
+    mWorkerWaitCV.notify_all();
+    if (mThread.joinable()) {
+        ECOLOGD("ECOSession: join the thread");
+        mThread.join();
+    }
+    ECOLOGI("ECOSession destroyed with w: %d, h: %d, isCameraRecording: %d", mWidth, mHeight,
+            mIsCameraRecording);
+}
+
+// static
+void ECOSession::startThread(ECOSession* session) {
+    session->run();
+}
+
+void ECOSession::run() {
+    ECOLOGD("ECOSession: starting main thread");
+
+    while (!mStopThread) {
+        std::unique_lock<std::mutex> runLock(mStatsQueueLock);
+
+        mWorkerWaitCV.wait(runLock, [this] {
+            return mStopThread == true || !mStatsQueue.empty() || mNewListenerAdded;
+        });
+
+        if (mStopThread) return;
+
+        std::scoped_lock<std::mutex> lock(mSessionLock);
+        if (mNewListenerAdded) {
+            // Check if there is any session info available.
+            ECOData sessionInfo = generateLatestSessionInfoEcoData();
+            if (!sessionInfo.isEmpty()) {
+                Status status = mListener->onNewInfo(sessionInfo);
+                if (!status.isOk()) {
+                    ECOLOGE("%s: Failed to publish info: %s due to binder error", __FUNCTION__,
+                            sessionInfo.debugString().c_str());
+                    // Remove the listener. The lock has been acquired outside this function.
+                    mListener = nullptr;
+                }
+            }
+            mNewListenerAdded = false;
+        }
+
+        if (!mStatsQueue.empty()) {
+            ECOData stats = mStatsQueue.front();
+            mStatsQueue.pop_front();
+            processStats(stats);  // TODO: Handle the error from processStats
+        }
+    }
+
+    ECOLOGD("ECOSession: exiting main thread");
+}
+
+bool ECOSession::processStats(const ECOData& stats) {
+    ECOLOGV("%s: receive stats: %s", __FUNCTION__, stats.debugString().c_str());
+
+    if (stats.getDataType() != ECOData::DATA_TYPE_STATS) {
+        ECOLOGE("Invalid stats. ECOData with type: %s", stats.getDataTypeString().c_str());
+        return false;
+    }
+
+    // Get the type of the stats.
+    std::string statsType;
+    if (stats.findString(KEY_STATS_TYPE, &statsType) != ECODataStatus::OK) {
+        ECOLOGE("Invalid stats ECOData without statsType");
+        return false;
+    }
+
+    if (statsType.compare(VALUE_STATS_TYPE_SESSION) == 0) {
+        processSessionStats(stats);
+    } else if (statsType.compare(VALUE_STATS_TYPE_FRAME) == 0) {
+        processFrameStats(stats);
+    } else {
+        ECOLOGE("processStats:: Failed to process stats as ECOData contains unknown stats type");
+        return false;
+    }
+
+    return true;
+}
+
+void ECOSession::processSessionStats(const ECOData& stats) {
+    ECOLOGV("processSessionStats");
+
+    ECOData info(ECOData::DATA_TYPE_INFO, systemTime(SYSTEM_TIME_BOOTTIME));
+    info.setString(KEY_INFO_TYPE, VALUE_INFO_TYPE_SESSION);
+
+    ECODataKeyValueIterator iter(stats);
+    while (iter.hasNext()) {
+        ECOData::ECODataKeyValuePair entry = iter.next();
+        const std::string& key = entry.first;
+        const ECOData::ECODataValueType value = entry.second;
+        ECOLOGV("Processing key: %s", key.c_str());
+        if (!key.compare(KEY_STATS_TYPE)) {
+            // Skip the key KEY_STATS_TYPE as that has been parsed already.
+            continue;
+        } else if (!key.compare(ENCODER_TYPE)) {
+            mCodecType = std::get<int32_t>(value);
+            ECOLOGV("codec type is %d", mCodecType);
+        } else if (!key.compare(ENCODER_PROFILE)) {
+            mCodecProfile = std::get<int32_t>(value);
+            ECOLOGV("codec profile is %d", mCodecProfile);
+        } else if (!key.compare(ENCODER_LEVEL)) {
+            mCodecLevel = std::get<int32_t>(value);
+            ECOLOGV("codec level is %d", mCodecLevel);
+        } else if (!key.compare(ENCODER_TARGET_BITRATE_BPS)) {
+            mTargetBitrateBps = std::get<int32_t>(value);
+            ECOLOGV("codec target bitrate is %d", mTargetBitrateBps);
+        } else if (!key.compare(ENCODER_KFI_FRAMES)) {
+            mKeyFrameIntervalFrames = std::get<int32_t>(value);
+            ECOLOGV("codec kfi is %d", mKeyFrameIntervalFrames);
+        } else if (!key.compare(ENCODER_FRAMERATE_FPS)) {
+            mFramerateFps = std::get<float>(value);
+            ECOLOGV("codec framerate is %f", mFramerateFps);
+        } else if (!key.compare(ENCODER_INPUT_WIDTH)) {
+            int32_t width = std::get<int32_t>(value);
+            if (width != mWidth) {
+                ECOLOGW("Codec width: %d, expected: %d", width, mWidth);
+            }
+            ECOLOGV("codec width is %d", width);
+        } else if (!key.compare(ENCODER_INPUT_HEIGHT)) {
+            int32_t height = std::get<int32_t>(value);
+            if (height != mHeight) {
+                ECOLOGW("Codec height: %d, expected: %d", height, mHeight);
+            }
+            ECOLOGV("codec height is %d", height);
+        } else {
+            ECOLOGW("Unknown session stats key %s from provider.", key.c_str());
+            continue;
+        }
+        info.set(key, value);
+    }
+
+    if (mListener != nullptr) {
+        Status status = mListener->onNewInfo(info);
+        if (!status.isOk()) {
+            ECOLOGE("%s: Failed to publish info: %s due to binder error", __FUNCTION__,
+                    info.debugString().c_str());
+            // Remove the listener. The lock has been acquired outside this function.
+            mListener = nullptr;
+        }
+    }
+}
+
+ECOData ECOSession::generateLatestSessionInfoEcoData() {
+    bool hasInfo = false;
+
+    ECOData info(ECOData::DATA_TYPE_INFO, systemTime(SYSTEM_TIME_BOOTTIME));
+
+    if (mOutputWidth != -1) {
+        info.setInt32(ENCODER_OUTPUT_WIDTH, mOutputWidth);
+        hasInfo = true;
+    }
+
+    if (mOutputHeight != -1) {
+        info.setInt32(ENCODER_OUTPUT_HEIGHT, mOutputHeight);
+        hasInfo = true;
+    }
+
+    if (mCodecType != -1) {
+        info.setInt32(ENCODER_TYPE, mCodecType);
+        hasInfo = true;
+    }
+
+    if (mCodecProfile != -1) {
+        info.setInt32(ENCODER_PROFILE, mCodecProfile);
+        hasInfo = true;
+    }
+
+    if (mCodecLevel != -1) {
+        info.setInt32(ENCODER_LEVEL, mCodecLevel);
+        hasInfo = true;
+    }
+
+    if (mTargetBitrateBps != -1) {
+        info.setInt32(ENCODER_TARGET_BITRATE_BPS, mTargetBitrateBps);
+        hasInfo = true;
+    }
+
+    if (mKeyFrameIntervalFrames != -1) {
+        info.setInt32(ENCODER_KFI_FRAMES, mKeyFrameIntervalFrames);
+        hasInfo = true;
+    }
+
+    if (mFramerateFps > 0) {
+        info.setFloat(ENCODER_FRAMERATE_FPS, mFramerateFps);
+        hasInfo = true;
+    }
+
+    if (hasInfo) {
+        info.setString(KEY_INFO_TYPE, VALUE_INFO_TYPE_SESSION);
+    }
+    return info;
+}
+
+void ECOSession::processFrameStats(const ECOData& stats) {
+    ECOLOGD("processFrameStats");
+
+    bool needToNotifyListener = false;
+    ECOData info(ECOData::DATA_TYPE_INFO, systemTime(SYSTEM_TIME_BOOTTIME));
+    info.setString(KEY_INFO_TYPE, VALUE_INFO_TYPE_FRAME);
+
+    ECODataKeyValueIterator iter(stats);
+    while (iter.hasNext()) {
+        ECOData::ECODataKeyValuePair entry = iter.next();
+        const std::string& key = entry.first;
+        const ECOData::ECODataValueType value = entry.second;
+        ECOLOGD("Processing %s key", key.c_str());
+
+        // Only process the keys that are supported by ECOService 1.0.
+        if (!key.compare(FRAME_NUM) || !key.compare(FRAME_PTS_US) || !key.compare(FRAME_TYPE) ||
+            !key.compare(FRAME_SIZE_BYTES)) {
+            info.set(key, value);
+        } else if (!key.compare(FRAME_AVG_QP)) {
+            // Check the qp to see if need to notify the listener.
+            const int32_t currAverageQp = std::get<int32_t>(value);
+
+            // Check if the delta between current QP and last reported QP is larger than the
+            // threshold specified by the listener.
+            const bool largeQPChangeDetected =
+                    abs(currAverageQp - mLastReportedQp) > mListenerQpCondition.mQpChangeThreshold;
+
+            // Check if the qp is going from below threshold to beyond threshold.
+            const bool exceedQpBlockinessThreshold =
+                    (mLastReportedQp <= mListenerQpCondition.mQpBlocknessThreshold &&
+                     currAverageQp > mListenerQpCondition.mQpBlocknessThreshold);
+
+            // Check if the qp is going from beyond threshold to below threshold.
+            const bool fallBelowQpBlockinessThreshold =
+                    (mLastReportedQp > mListenerQpCondition.mQpBlocknessThreshold &&
+                     currAverageQp <= mListenerQpCondition.mQpBlocknessThreshold);
+
+            // Notify the listener if any of the above three conditions met.
+            if (largeQPChangeDetected || exceedQpBlockinessThreshold ||
+                fallBelowQpBlockinessThreshold) {
+                mLastReportedQp = currAverageQp;
+                needToNotifyListener = true;
+            }
+
+            info.set(key, value);
+        } else {
+            ECOLOGW("Unknown frame stats key %s from provider.", key.c_str());
+        }
+    }
+
+    if (needToNotifyListener && mListener != nullptr) {
+        Status status = mListener->onNewInfo(info);
+        if (!status.isOk()) {
+            ECOLOGE("%s: Failed to publish info: %s due to binder error", __FUNCTION__,
+                    info.debugString().c_str());
+            // Remove the listener. The lock has been acquired outside this function.
+            mListener = nullptr;
+        }
+    }
+}
+
+Status ECOSession::getIsCameraRecording(bool* _aidl_return) {
+    std::scoped_lock<std::mutex> lock(mSessionLock);
+    *_aidl_return = mIsCameraRecording;
+    return binder::Status::ok();
+}
+
+Status ECOSession::addStatsProvider(
+        const sp<::android::media::eco::IECOServiceStatsProvider>& provider,
+        const ::android::media::eco::ECOData& config, bool* status) {
+    ::android::String16 name;
+    Status result = provider->getName(&name);
+    if (!result.isOk()) {
+        // This binder transaction failure may due to permission issue.
+        *status = false;
+        ALOGE("Failed to get provider name");
+        return STATUS_ERROR(ERROR_PERMISSION_DENIED, "Failed to get provider name");
+    }
+
+    ECOLOGV("Try to add stats provider name: %s uid: %d pid %d", ::android::String8(name).string(),
+            IPCThreadState::self()->getCallingUid(), IPCThreadState::self()->getCallingPid());
+
+    if (provider == nullptr) {
+        ECOLOGE("%s: provider must not be null", __FUNCTION__);
+        *status = false;
+        return STATUS_ERROR(ERROR_ILLEGAL_ARGUMENT, "Null provider given to addStatsProvider");
+    }
+
+    std::scoped_lock<std::mutex> lock(mSessionLock);
+
+    if (mProvider != nullptr) {
+        ::android::String16 name;
+        mProvider->getName(&name);
+        String8 errorMsg = String8::format(
+                "ECOService 1.0 only supports one stats provider, current provider: %s",
+                ::android::String8(name).string());
+        ECOLOGE("%s", errorMsg.string());
+        *status = false;
+        return STATUS_ERROR(ERROR_ALREADY_EXISTS, errorMsg.string());
+    }
+
+    // TODO: Handle the provider config.
+    if (config.getDataType() != ECOData::DATA_TYPE_STATS_PROVIDER_CONFIG) {
+        ECOLOGE("Provider config is invalid");
+        *status = false;
+        return STATUS_ERROR(ERROR_ILLEGAL_ARGUMENT, "Provider config is invalid");
+    }
+
+    mProvider = provider;
+    mProviderName = name;
+    *status = true;
+    return binder::Status::ok();
+}
+
+Status ECOSession::removeStatsProvider(
+        const sp<::android::media::eco::IECOServiceStatsProvider>& provider, bool* status) {
+    std::scoped_lock<std::mutex> lock(mSessionLock);
+    // Check if the provider is the same as current provider for the session.
+    if (provider.get() != mProvider.get()) {
+        *status = false;
+        return STATUS_ERROR(ERROR_ILLEGAL_ARGUMENT, "Provider does not match");
+    }
+
+    mProvider = nullptr;
+    *status = true;
+    return binder::Status::ok();
+}
+
+Status ECOSession::addInfoListener(
+        const sp<::android::media::eco::IECOServiceInfoListener>& listener,
+        const ::android::media::eco::ECOData& config, bool* status) {
+    ALOGV("%s: Add listener %p", __FUNCTION__, listener.get());
+    std::scoped_lock<std::mutex> lock(mSessionLock);
+
+    ::android::String16 name;
+    Status result = listener->getName(&name);
+    if (!result.isOk()) {
+        // This binder transaction failure may due to permission issue.
+        *status = false;
+        ALOGE("Failed to get listener name");
+        return STATUS_ERROR(ERROR_PERMISSION_DENIED, "Failed to get listener name");
+    }
+
+    if (mListener != nullptr) {
+        ECOLOGE("ECOService 1.0 only supports one listener");
+        *status = false;
+        return STATUS_ERROR(ERROR_ALREADY_EXISTS, "ECOService 1.0 only supports one listener");
+    }
+
+    if (listener == nullptr) {
+        ECOLOGE("%s: listener must not be null", __FUNCTION__);
+        *status = false;
+        return STATUS_ERROR(ERROR_ILLEGAL_ARGUMENT, "Null listener given to addInfoListener");
+    }
+
+    if (config.getDataType() != ECOData::DATA_TYPE_INFO_LISTENER_CONFIG) {
+        *status = false;
+        ECOLOGE("%s: listener config is invalid", __FUNCTION__);
+        return STATUS_ERROR(ERROR_ILLEGAL_ARGUMENT, "listener config is invalid");
+    }
+
+    if (config.isEmpty()) {
+        *status = false;
+        ECOLOGE("Listener must provide listening criterion");
+        return STATUS_ERROR(ERROR_ILLEGAL_ARGUMENT, "listener config is empty");
+    }
+
+    // For ECOService 1.0, listener must specify the two threshold in order to receive info.
+    if (config.findInt32(KEY_LISTENER_QP_BLOCKINESS_THRESHOLD,
+                         &mListenerQpCondition.mQpBlocknessThreshold) != ECODataStatus::OK ||
+        config.findInt32(KEY_LISTENER_QP_CHANGE_THRESHOLD,
+                         &mListenerQpCondition.mQpChangeThreshold) != ECODataStatus::OK ||
+        mListenerQpCondition.mQpBlocknessThreshold < ENCODER_MIN_QP ||
+        mListenerQpCondition.mQpBlocknessThreshold > ENCODER_MAX_QP) {
+        *status = false;
+        ECOLOGE("%s: listener config is invalid", __FUNCTION__);
+        return STATUS_ERROR(ERROR_ILLEGAL_ARGUMENT, "listener config is not valid");
+    }
+
+    ECOLOGD("Info listener name: %s uid: %d pid %d", ::android::String8(name).string(),
+            IPCThreadState::self()->getCallingUid(), IPCThreadState::self()->getCallingPid());
+
+    mListener = listener;
+    mListenerName = name;
+    mNewListenerAdded = true;
+    mWorkerWaitCV.notify_all();
+
+    *status = true;
+    return binder::Status::ok();
+}
+
+Status ECOSession::removeInfoListener(
+        const sp<::android::media::eco::IECOServiceInfoListener>& listener, bool* _aidl_return) {
+    std::scoped_lock<std::mutex> lock(mSessionLock);
+    // Check if the listener is the same as current listener for the session.
+    if (listener.get() != mListener.get()) {
+        *_aidl_return = false;
+        return STATUS_ERROR(ERROR_ILLEGAL_ARGUMENT, "Listener does not match");
+    }
+
+    mListener = nullptr;
+    mNewListenerAdded = false;
+    *_aidl_return = true;
+    return binder::Status::ok();
+}
+
+Status ECOSession::pushNewStats(const ::android::media::eco::ECOData& stats, bool*) {
+    ECOLOGV("ECOSession get new stats type: %s", stats.getDataTypeString().c_str());
+    std::unique_lock<std::mutex> lock(mStatsQueueLock);
+    mStatsQueue.push_back(stats);
+    mWorkerWaitCV.notify_all();
+    return binder::Status::ok();
+}
+
+Status ECOSession::getWidth(int32_t* _aidl_return) {
+    std::scoped_lock<std::mutex> lock(mSessionLock);
+    *_aidl_return = mWidth;
+    return binder::Status::ok();
+}
+
+Status ECOSession::getHeight(int32_t* _aidl_return) {
+    std::scoped_lock<std::mutex> lock(mSessionLock);
+    *_aidl_return = mHeight;
+    return binder::Status::ok();
+}
+
+Status ECOSession::getNumOfListeners(int32_t* _aidl_return) {
+    std::scoped_lock<std::mutex> lock(mSessionLock);
+    *_aidl_return = (mListener == nullptr ? 0 : 1);
+    return binder::Status::ok();
+}
+
+Status ECOSession::getNumOfProviders(int32_t* _aidl_return) {
+    std::scoped_lock<std::mutex> lock(mSessionLock);
+    *_aidl_return = (mProvider == nullptr ? 0 : 1);
+    return binder::Status::ok();
+}
+
+/*virtual*/ void ECOSession::binderDied(const wp<IBinder>& /*who*/) {
+    ECOLOGV("binderDied");
+}
+
+status_t ECOSession::dump(int fd, const Vector<String16>& /*args*/) {
+    std::scoped_lock<std::mutex> lock(mSessionLock);
+    dprintf(fd, "\n== Session Info: ==\n\n");
+    dprintf(fd,
+            "Width: %d Height: %d isCameraRecording: %d, target-bitrate: %d bps codetype: %d "
+            "profile: %d level: %d\n",
+            mWidth, mHeight, mIsCameraRecording, mTargetBitrateBps, mCodecType, mCodecProfile,
+            mCodecLevel);
+    if (mProvider != nullptr) {
+        dprintf(fd, "Provider: %s \n", ::android::String8(mProviderName).string());
+    }
+    if (mListener != nullptr) {
+        dprintf(fd, "Listener: %s \n", ::android::String8(mListenerName).string());
+    }
+    dprintf(fd, "\n===================\n\n");
+
+    return NO_ERROR;
+}
+
+void ECOSession::logStats(const ECOData& data) {
+    // Check if mLogStats is true;
+    if (!mLogStats || mLogStatsEntries == 0) return;
+
+    // Check if we need to remove the old entry.
+    if (mStatsDebugBuffer.size() >= mLogStatsEntries) {
+        mStatsDebugBuffer.pop_front();
+    }
+
+    mStatsDebugBuffer.push_back(data);
+}
+
+void ECOSession::logInfos(const ECOData& data) {
+    // Check if mLogInfo is true;
+    if (!mLogInfo || mLogInfoEntries == 0) return;
+
+    // Check if we need to remove the old entry.
+    if (mInfosDebugBuffer.size() >= mLogInfoEntries) {
+        mInfosDebugBuffer.pop_front();
+    }
+
+    mInfosDebugBuffer.push_back(data);
+}
+
+}  // namespace eco
+}  // namespace media
+}  // namespace android
diff --git a/media/eco/ECOUtils.cpp b/media/eco/ECOUtils.cpp
new file mode 100644
index 0000000..ab82252
--- /dev/null
+++ b/media/eco/ECOUtils.cpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "ECOUtils"
+
+#include "eco/ECOUtils.h"
+
+#include <utils/Timers.h>
+
+namespace android {
+namespace media {
+namespace eco {
+
+// Convert this SimpleEncoderConfig to ECOData with dataType.
+ECOData SimpleEncoderConfig::toEcoData(ECOData::ECODatatype dataType) {
+    ECOData data(dataType, systemTime(SYSTEM_TIME_BOOTTIME));
+    data.setString(KEY_STATS_TYPE, VALUE_STATS_TYPE_SESSION);
+    data.setInt32(ENCODER_TYPE, mCodecType);
+    data.setInt32(ENCODER_PROFILE, mProfile);
+    data.setInt32(ENCODER_LEVEL, mLevel);
+    data.setInt32(ENCODER_TARGET_BITRATE_BPS, mTargetBitrate);
+    data.setInt32(ENCODER_KFI_FRAMES, mKeyFrameIntervalFrames);
+    data.setFloat(ENCODER_FRAMERATE_FPS, mFrameRateFps);
+    return data;
+}
+
+// Convert this SimpleEncodedFrameData to ECOData with dataType.
+ECOData SimpleEncodedFrameData::toEcoData(ECOData::ECODatatype dataType) {
+    ECOData data(dataType, systemTime(SYSTEM_TIME_BOOTTIME));
+    data.setString(KEY_STATS_TYPE, VALUE_STATS_TYPE_FRAME);
+    data.setInt32(FRAME_NUM, mFrameNum);
+    data.setInt8(FRAME_TYPE, mFrameType);
+    data.setInt64(FRAME_PTS_US, mFramePtsUs);
+    data.setInt32(FRAME_AVG_QP, mAvgQp);
+    data.setInt32(FRAME_SIZE_BYTES, mFrameSizeBytes);
+    return data;
+}
+
+bool copyKeyValue(const ECOData& src, ECOData* dst) {
+    if (src.isEmpty() || dst == nullptr) return false;
+    dst->mKeyValueStore = src.mKeyValueStore;
+    return true;
+}
+
+}  // namespace eco
+}  // namespace media
+}  // namespace android
\ No newline at end of file
diff --git a/media/eco/OWNERS b/media/eco/OWNERS
new file mode 100644
index 0000000..2239c4f
--- /dev/null
+++ b/media/eco/OWNERS
@@ -0,0 +1,2 @@
+hkuang@google.com
+derekpang@google.com
\ No newline at end of file
diff --git a/media/eco/aidl/android/media/eco/ECOData.aidl b/media/eco/aidl/android/media/eco/ECOData.aidl
new file mode 100644
index 0000000..162cd89
--- /dev/null
+++ b/media/eco/aidl/android/media/eco/ECOData.aidl
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.eco;
+
+/** @hide */
+parcelable ECOData cpp_header "eco/ECOData.h";
\ No newline at end of file
diff --git a/media/eco/aidl/android/media/eco/IECOService.aidl b/media/eco/aidl/android/media/eco/IECOService.aidl
new file mode 100644
index 0000000..995abad
--- /dev/null
+++ b/media/eco/aidl/android/media/eco/IECOService.aidl
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.eco;
+
+import android.media.eco.ECOData;
+import android.media.eco.IECOServiceStatsProvider;
+import android.media.eco.IECOServiceInfoListener;
+import android.media.eco.IECOSession;
+
+/**
+ * Binder interface for ECO (Encoder Camera Optimization) service.
+ * @hide
+ */
+interface IECOService {
+    /**
+     * All ECO service Binder calls may return a ServiceSpecificException with the following error
+     * codes.
+     */
+    const int ERROR_PERMISSION_DENIED = 1;
+    const int ERROR_ALREADY_EXISTS = 2;
+    const int ERROR_ILLEGAL_ARGUMENT = 3;
+    const int ERROR_DISCONNECTED = 4;
+    const int ERROR_INVALID_OPERATION = 5;
+    const int ERROR_UNSUPPORTED = 6;
+
+    /**
+     * Obtains an IECOSession from the ECO service.
+     *
+     * <p>ECOService will first check if the requested session already existed. If not, it will
+     * create and return the new session. This should be called by IECOServiceStatsProvider or
+     * IECOServiceInfoListener to obtain an ECOSession interface upon start.</p>
+     *
+     * @param width Width of the requested video session (in pixel).
+     * @param height Height of the requested video session (in pixel).
+     * @param isCameraRecording A boolean indicates whether the session is for camera recording.
+     *
+     * @return IECOSession The session instance created by the ECOService.
+     */
+    IECOSession obtainSession(int width, int height, boolean isCameraRecording);
+
+    /**
+     * Return the total number of sessions inside ECO service.
+     */
+    int getNumOfSessions();
+
+    /**
+     * Return a list containing all ECOSessions.
+     */
+    List<IBinder> getSessions();
+}
diff --git a/media/eco/aidl/android/media/eco/IECOServiceInfoListener.aidl b/media/eco/aidl/android/media/eco/IECOServiceInfoListener.aidl
new file mode 100644
index 0000000..bf5bd88
--- /dev/null
+++ b/media/eco/aidl/android/media/eco/IECOServiceInfoListener.aidl
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.eco;
+
+import android.media.eco.ECOData;
+import android.os.IBinder;
+
+/**
+ * Binder interface for ECO service information listener.
+*
+* {@hide}
+*/
+interface IECOServiceInfoListener {
+    /**
+     * All listener Binder calls may return a ServiceSpecificException with the following error
+     * codes.
+     */
+    const int ERROR_PERMISSION_DENIED = 1;
+    const int ERROR_ILLEGAL_ARGUMENT = 2;
+    const int ERROR_INVALID_OPERATION = 3;
+    const int ERROR_UNSUPPORTED = 4;
+
+    /**
+     * Constants for the type of the listener.
+     */
+    const int INFO_LISTENER_TYPE_UNKNOWN = 1;
+    const int INFO_LISTENER_TYPE_VIDEO_ENCODER = 2;
+    const int INFO_LISTENER_TYPE_CAMERA = 3;
+
+    /**
+     * Return the type of the listener.
+     */
+    int getType();
+
+    /**
+     * Return the name of the listener.
+     */
+    String getName();
+
+    /**
+     * Return the IBinder instance of the ECOSession associated the provider.
+     */
+    IBinder getECOSession();
+
+    /**
+     * Handle the new info from ECOSession. This should only be called by ECOSession.
+     */
+    oneway void onNewInfo(in ECOData newInfo);
+}
\ No newline at end of file
diff --git a/media/eco/aidl/android/media/eco/IECOServiceStatsProvider.aidl b/media/eco/aidl/android/media/eco/IECOServiceStatsProvider.aidl
new file mode 100644
index 0000000..6e2f9c3
--- /dev/null
+++ b/media/eco/aidl/android/media/eco/IECOServiceStatsProvider.aidl
@@ -0,0 +1,56 @@
+/*
+* Copyright (C) 2019 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+package android.media.eco;
+
+import android.os.IBinder;
+
+/**
+* An interface for providers that provides various statistics to ECO service.
+* {@hide}
+*/
+interface IECOServiceStatsProvider {
+    /**
+     * All provider Binder calls may return a ServiceSpecificException with the following error
+     * codes.
+     */
+    const int ERROR_PERMISSION_DENIED = 1;
+    const int ERROR_ILLEGAL_ARGUMENT = 2;
+    const int ERROR_INVALID_OPERATION = 3;
+    const int ERROR_UNSUPPORTED = 4;
+
+    /**
+     * Constants for the type of the provider.
+     */
+    const int STATS_PROVIDER_TYPE_UNKNOWN = 1;
+    const int STATS_PROVIDER_TYPE_VIDEO_ENCODER = 2;
+    const int STATS_PROVIDER_TYPE_CAMERA = 3;
+
+    /**
+     * Return the type of the provider.
+     */
+    int getType();
+
+    /**
+     * Return the name of the provider.
+     */
+    String getName();
+
+    /**
+     * Return the IBinder instance of the ECOSession associated the listener.
+     */
+    IBinder getECOSession();
+}
diff --git a/media/eco/aidl/android/media/eco/IECOSession.aidl b/media/eco/aidl/android/media/eco/IECOSession.aidl
new file mode 100644
index 0000000..e4c1136
--- /dev/null
+++ b/media/eco/aidl/android/media/eco/IECOSession.aidl
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.eco;
+
+import android.media.eco.ECOData;
+import android.media.eco.IECOServiceStatsProvider;
+import android.media.eco.IECOServiceInfoListener;
+
+/**
+ * Binder interface for ECO Session.
+ * @hide
+ */
+interface IECOSession {
+    /**
+     * All ECO session Binder calls may return a ServiceSpecificException with the following error
+     * codes.
+     */
+    const int ERROR_PERMISSION_DENIED = 1;
+    const int ERROR_ALREADY_EXISTS = 2;
+    const int ERROR_ILLEGAL_ARGUMENT = 3;
+    const int ERROR_DISCONNECTED = 4;
+    const int ERROR_INVALID_OPERATION = 5;
+    const int ERROR_UNSUPPORTED = 6;
+
+    /**
+     * Adds an ECOServiceStasProvider.
+     *
+     * <p>This is called by ECOServiceStasProvider to add itself to the ECOSession.</p>
+     *
+     * @param provider Provider that implements IECOServiceStatsProvider interface.
+     * @param config  Config that specifies the types of the stats that the provider is going to
+     *                provide. The ECOData must be of type DATA_TYPE_STATS_PROVIDER_CONFIG. Note:
+     *                The provider must specify the following keys when adding itself:
+     *                KEY_PROVIDER_NAME in string and KEY_PROVIDER_TYPE as specified in
+     *                IECOServiceStatsProvider.
+     *
+     * @return true if the provider was successfully added, false otherwise.
+     */
+    boolean addStatsProvider(IECOServiceStatsProvider provider, in ECOData config);
+
+    /**
+     * Removes an ECOServiceStasProvider from ECOSession.
+     *
+     * @param provider Provider that implements IECOServiceStatsProvider interface.
+     *
+     * @return true if the provider was successfully removed, false otherwise.
+     */
+    boolean removeStatsProvider(IECOServiceStatsProvider provider);
+
+    /**
+     * Registers an ECOServiceInfoListener.
+     *
+     * <p>This is called by IECOServiceInfoListener to add itself to the ECOSession.</p>
+     *
+     * @param listener Listener that implements IECOServiceInfoListener interface.
+     * @param config  Config that specifies the condition for the data that the listener is
+     *                interested in.
+     *
+     * @return true if the listener was successfully added, false otherwise.
+     */
+    boolean addInfoListener(IECOServiceInfoListener listener, in ECOData config);
+
+    /**
+     * Removes an ECOServiceInfoListener from ECOSession.
+     *
+     * @param listener Listener that implements IECOServiceInfoListener interface.
+     *
+     * @return true if the listener was successfully removed, false otherwise.
+     */
+    boolean removeInfoListener(IECOServiceInfoListener listener);
+
+    /**
+     * Push new stats to the ECOSession. This should only be called by IECOServiceStatsProvider.
+     */
+    boolean pushNewStats(in ECOData newStats);
+
+    /**
+     * Return the width in pixels.
+     */
+    int getWidth();
+
+    /**
+     * Return the height in pixels.
+     */
+    int getHeight();
+
+    /**
+     * Return whether the session is for camera recording.
+     */
+    boolean getIsCameraRecording();
+
+    /**
+     * Query the number of listeners that a session has.
+     */
+    int getNumOfListeners();
+
+    /**
+     * Query the number of providers that a session has.
+     */
+    int getNumOfProviders();
+}
diff --git a/media/eco/include/eco/ECOData.h b/media/eco/include/eco/ECOData.h
new file mode 100644
index 0000000..cb42982
--- /dev/null
+++ b/media/eco/include/eco/ECOData.h
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_MEDIA_ECO_DATA_H_
+#define ANDROID_MEDIA_ECO_DATA_H_
+
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+
+#include <string>
+#include <unordered_map>
+#include <variant>
+
+namespace android {
+namespace media {
+namespace eco {
+
+enum class ECODataStatus {
+    OK,
+    FAIL_TO_INSERT,
+    INVALID_ECODATA_TYPE,
+    KEY_NOT_EXIST,
+    INVALID_VALUE_TYPE,
+    INVALID_ARGUMENT,
+};
+
+/**
+* ECOData is the container for all messages passed between different components in ECOService.
+* All messages in ECOServices are represented by a list of key-value pairs.
+* For example:
+*     "bit-rate" -> 22000000
+*     "Provider-Name" -> "QCOM-Video-Encoder".
+*     "avg-frame-qp" -> 40
+* ECOData follows the same design pattern of AMessage and Metadata in Media Framework. The key
+* must be non-empty string. Below are the supported data types:
+*
+*    //   Item types      set/find function suffixes
+*    //   ==========================================
+*    //     int32_t                Int32
+*    //     int64_t                Int64
+*    //     size_t                 Size
+*    //     float                  Float
+*    //     double                 Double
+*    //     String                 String
+*
+* ECOData does not support duplicate keys with different values. When inserting a key-value pair,
+* a new entry will be created if the key does not exist. Othewise, they key's value will be
+* overwritten with the new value.
+* 
+*  Sample usage:
+*
+*   // Create the ECOData
+*   std::unique_ptr<ECOData> data = std::make_unique<ECOData>(ECOData::DATA_TYPE_STATS, 1000);
+*
+*   // Set the encoder name.
+*   data->setString("stats-encoder-type", "google-avc");
+*
+*   // Set encoding bitrate.
+*   data->setInt32("stats-encoder-target-bitrate-bps", 22000000);
+*/
+class ECOData : public Parcelable {
+public:
+    using ECODataValueType =
+            std::variant<int32_t, int64_t, size_t, float, double, std::string, int8_t>;
+    using ECODataKeyValuePair = std::pair<std::string, ECODataValueType>;
+
+    ECOData() : mDataType(0), mDataTimeUs(-1) {}
+    ECOData(int32_t type) : mDataType(type), mDataTimeUs(-1) {}
+    ECOData(int32_t type, int64_t timeUs) : mDataType(type), mDataTimeUs(timeUs) {}
+
+    // Constants for mDataType.
+    typedef enum {
+        DATA_TYPE_UNKNOWN = 0,
+        /* Data sent from the ECOServiceStatsProvider to ECOService. */
+        DATA_TYPE_STATS = 1,
+        /* Data sent from the ECOService to ECOServiceInfoListener. */
+        DATA_TYPE_INFO = 2,
+        /* Configuration data sent by ECOServiceStatsProvider when connects with ECOService. */
+        DATA_TYPE_STATS_PROVIDER_CONFIG = 3,
+        /* Configuration data sent by ECOServiceInfoListener when connects with ECOService. */
+        DATA_TYPE_INFO_LISTENER_CONFIG = 4,
+    } ECODatatype;
+
+    // set/find functions that could be used for all the value types.
+    ECODataStatus set(const std::string& key, const ECODataValueType& value);
+    ECODataStatus find(const std::string& key, ECODataValueType* out) const;
+
+    // Convenient set/find functions for string value type.
+    ECODataStatus setString(const std::string& key, const std::string& value);
+    ECODataStatus findString(const std::string& key, std::string* out) const;
+
+    // Convenient set/find functions for int32_t value type.
+    ECODataStatus setInt32(const std::string& key, int32_t value);
+    ECODataStatus findInt32(const std::string& key, int32_t* out) const;
+
+    // Convenient set/find functions for int64_t value type.
+    ECODataStatus setInt64(const std::string& key, int64_t value);
+    ECODataStatus findInt64(const std::string& key, int64_t* out) const;
+
+    // Convenient set/find functions for float value type.
+    ECODataStatus setFloat(const std::string& key, float value);
+    ECODataStatus findFloat(const std::string& key, float* out) const;
+
+    // Convenient set/find functions for double value type.
+    ECODataStatus setDouble(const std::string& key, double value);
+    ECODataStatus findDouble(const std::string& key, double* out) const;
+
+    // Convenient set/find functions for size_t value type.
+    ECODataStatus setSize(const std::string& key, size_t value);
+    ECODataStatus findSize(const std::string& key, size_t* out) const;
+
+    // Convenient set/find functions for int8_t value type.
+    // TODO(hkuang): Add unit test.
+    ECODataStatus setInt8(const std::string& key, int8_t value);
+    ECODataStatus findInt8(const std::string& key, int8_t* out) const;
+
+    /**
+    * Serialization over Binder
+    */
+    status_t readFromParcel(const Parcel* parcel) override;
+    status_t writeToParcel(Parcel* parcel) const override;
+
+    /* Returns the type of the data. */
+    int32_t getDataType() const;
+
+    /* Returns the type of the data in string. */
+    std::string getDataTypeString() const;
+
+    /* Returns the timestamp associated with the data. */
+    int64_t getDataTimeUs() const;
+
+    /* Sets the type of the data. */
+    void setDataType(int32_t type);
+
+    /* Sets the timestamp associated with the data. */
+    void setDataTimeUs();
+
+    /* Gets the number of keys in the ECOData. */
+    size_t getNumOfEntries() const { return mKeyValueStore.size(); }
+
+    /* Whether the ECOData is empty. */
+    size_t isEmpty() const { return mKeyValueStore.size() == 0; }
+
+    friend class ECODataKeyValueIterator;
+
+    friend bool copyKeyValue(const ECOData& src, ECOData* dst);
+
+    // Dump the ECOData as a string.
+    std::string debugString() const;
+
+protected:
+    // ValueType. This must match the index in ECODataValueType.
+    enum ValueType {
+        kTypeInt32 = 0,
+        kTypeInt64 = 1,
+        kTypeSize = 2,
+        kTypeFloat = 3,
+        kTypeDouble = 4,
+        kTypeString = 5,
+        kTypeInt8 = 6,
+    };
+
+    /* The type of the data */
+    int32_t mDataType;
+
+    // The timestamp time associated with the data in microseconds. The timestamp should be in
+    // boottime time base. This is only used when the data type is stats or info. -1 means
+    // unavailable.
+    int64_t mDataTimeUs;
+
+    // Internal store for the key value pairs.
+    std::unordered_map<std::string, ECODataValueType> mKeyValueStore;
+
+    template <typename T>
+    ECODataStatus setValue(const std::string& key, T value);
+
+    template <typename T>
+    ECODataStatus findValue(const std::string& key, T* out) const;
+};
+
+// A simple ECOData iterator that will iterate over all the key value paris in ECOData.
+// To be used like:
+// while (it.hasNext()) {
+//   entry = it.next();
+// }
+class ECODataKeyValueIterator {
+public:
+    ECODataKeyValueIterator(const ECOData& data)
+          : mKeyValueStore(data.mKeyValueStore), mBeginReturned(false) {
+        mIterator = mKeyValueStore.begin();
+    }
+    ~ECODataKeyValueIterator() = default;
+    bool hasNext();
+    ECOData::ECODataKeyValuePair next() const;
+
+private:
+    const std::unordered_map<std::string, ECOData::ECODataValueType>& mKeyValueStore;
+    std::unordered_map<std::string, ECOData::ECODataValueType>::const_iterator mIterator;
+    bool mBeginReturned;
+};
+
+}  // namespace eco
+}  // namespace media
+}  // namespace android
+
+#endif  // ANDROID_MEDIA_ECO_DATA_H_
diff --git a/media/eco/include/eco/ECODataKey.h b/media/eco/include/eco/ECODataKey.h
new file mode 100644
index 0000000..7c59ae0
--- /dev/null
+++ b/media/eco/include/eco/ECODataKey.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef ANDROID_MEDIA_ECO_DATA_KEY_H_
+#define ANDROID_MEDIA_ECO_DATA_KEY_H_
+
+#include <android-base/unique_fd.h>
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+#include <stdint.h>
+#include <sys/mman.h>
+
+namespace android {
+namespace media {
+namespace eco {
+
+// ================================================================================================
+// Standard ECOData keys.
+// ================================================================================================
+constexpr char KEY_ECO_DATA_TYPE[] = "eco-data-type";
+constexpr char KEY_ECO_DATA_TIME_US[] = "eco-data-time-us";
+
+// ================================================================================================
+// Standard ECOServiceStatsProvider config keys. These keys are used in the ECOData as an config
+// when StatsProvider connects with ECOService.
+// ================================================================================================
+constexpr char KEY_PROVIDER_NAME[] = "provider-name";
+constexpr char KEY_PROVIDER_TYPE[] = "provider-type";
+
+// ================================================================================================
+// Standard ECOServiceInfoListener config keys. These keys are used in the ECOData as config
+// when ECOServiceInfoListener connects with ECOService to specify the informations that the
+// listener wants to listen to.
+// ================================================================================================
+constexpr char KEY_LISTENER_NAME[] = "listener-name";
+constexpr char KEY_LISTENER_TYPE[] = "listener-type";
+
+// Following two keys are used together for the listener to specify the condition when it wants to
+// receive notification. When a frame's avg-qp crosses KEY_LISTENER_QP_BLOCKINESS_THRESHOLD or
+// the detla of qp between current frame and previous frame also goes beyond
+// KEY_LISTENER_QP_CHANGE_THRESHOLD, ECOService will notify the listener.
+constexpr char KEY_LISTENER_QP_BLOCKINESS_THRESHOLD[] = "listener-qp-blockness-threshold";
+constexpr char KEY_LISTENER_QP_CHANGE_THRESHOLD[] = "listener-qp-change-threshold";
+
+// ================================================================================================
+// ECOService Stats keys. These key MUST BE specified when provider pushes the stats to ECOService
+// to indicate the stats is session stats or frame stats.
+// ================================================================================================
+constexpr char KEY_STATS_TYPE[] = "stats-type";
+constexpr char VALUE_STATS_TYPE_SESSION[] = "stats-type-session";  // value for KEY_STATS_TYPE.
+constexpr char VALUE_STATS_TYPE_FRAME[] = "stats-type-frame";      // value for KEY_STATS_TYPE.
+
+// ================================================================================================
+// Standard ECOService Info keys. These key will be in the info provided by ECOService to indicate
+// the info is session info or frame info.
+// ================================================================================================
+constexpr char KEY_INFO_TYPE[] = "info-type";
+constexpr char VALUE_INFO_TYPE_SESSION[] = "info-type-session";  // value for KEY_INFO_TYPE.
+constexpr char VALUE_INFO_TYPE_FRAME[] = "info-type-frame";      // value for KEY_INFO_TYPE.
+
+// ================================================================================================
+// General keys to be used by both stats and info in the ECOData.
+// ================================================================================================
+constexpr char ENCODER_NAME[] = "encoder-name";
+constexpr char ENCODER_TYPE[] = "encoder-type";
+constexpr char ENCODER_PROFILE[] = "encoder-profile";
+constexpr char ENCODER_LEVEL[] = "encoder-level";
+constexpr char ENCODER_INPUT_WIDTH[] = "encoder-input-width";
+constexpr char ENCODER_INPUT_HEIGHT[] = "encoder-input-height";
+constexpr char ENCODER_OUTPUT_WIDTH[] = "encoder-output-width";
+constexpr char ENCODER_OUTPUT_HEIGHT[] = "encoder-output-height";
+constexpr char ENCODER_TARGET_BITRATE_BPS[] = "encoder-target-bitrate-bps";
+constexpr char ENCODER_ACTUAL_BITRATE_BPS[] = "encoder-actual-bitrate-bps";
+constexpr char ENCODER_KFI_FRAMES[] = "encoder-kfi-frames";
+constexpr char ENCODER_FRAMERATE_FPS[] = "encoder-framerate-fps";
+
+constexpr char FRAME_NUM[] = "frame-num";
+constexpr char FRAME_PTS_US[] = "frame-pts-us";
+constexpr char FRAME_AVG_QP[] = "frame-avg-qp";
+constexpr char FRAME_TYPE[] = "frame-type";
+constexpr char FRAME_SIZE_BYTES[] = "frame-size-bytes";
+
+}  // namespace eco
+}  // namespace media
+}  // namespace android
+
+#endif  // ANDROID_MEDIA_ECO_DATA_KEY_H_
diff --git a/media/eco/include/eco/ECODebug.h b/media/eco/include/eco/ECODebug.h
new file mode 100644
index 0000000..b250f64
--- /dev/null
+++ b/media/eco/include/eco/ECODebug.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_MEDIA_ECO_DEBUG_H_
+#define ANDROID_MEDIA_ECO_DEBUG_H_
+
+#include <cutils/atomic.h>
+#include <cutils/properties.h>
+
+#include "ECOData.h"
+
+namespace android {
+namespace media {
+namespace eco {
+
+static const char* kDebugLogsLevelProperty = "media.ecoservice.log.level";
+static const char* kDebugLogStats = "media.ecoservice.log.stats";
+static const char* kDebugLogStatsSize = "media.ecoservice.log.stats.size";
+static const char* kDebugLogInfos = "media.ecoservice.log.info";
+static const char* kDebugLogInfosSize = "media.ecoservice.log.info.size";
+
+// A debug variable that should only be accessed by ECOService through updateLogLevel. It is rare
+// that this variable will have race condition. But if so, it is ok as this is just for debugging.
+extern uint32_t gECOLogLevel;
+
+enum ECOLogLevel : uint32_t {
+    ECO_MSGLEVEL_DEBUG = 0x01,    ///< debug logs
+    ECO_MSGLEVEL_VERBOSE = 0x02,  ///< very detailed logs
+    ECO_MSGLEVEL_ALL = 0x03,      ///< both debug logs and detailed logs
+};
+
+#define ECOLOGV(format, args...) ALOGD_IF((gECOLogLevel & ECO_MSGLEVEL_VERBOSE), format, ##args)
+#define ECOLOGD(format, args...) ALOGD_IF((gECOLogLevel & ECO_MSGLEVEL_DEBUG), format, ##args)
+#define ECOLOGI(format, args...) ALOGI(format, ##args)
+#define ECOLOGW(format, args...) ALOGW(format, ##args)
+#define ECOLOGE(format, args...) ALOGE(format, ##args)
+
+void updateLogLevel();
+
+// Convenience methods for constructing binder::Status objects for error returns
+#define STATUS_ERROR(errorCode, errorString)  \
+    binder::Status::fromServiceSpecificError( \
+            errorCode, String8::format("%s:%d: %s", __FUNCTION__, __LINE__, errorString))
+
+#define STATUS_ERROR_FMT(errorCode, errorString, ...) \
+    binder::Status::fromServiceSpecificError(         \
+            errorCode,                                \
+            String8::format("%s:%d: " errorString, __FUNCTION__, __LINE__, __VA_ARGS__))
+
+}  // namespace eco
+}  // namespace media
+}  // namespace android
+
+#endif  // ANDROID_MEDIA_ECO_DEBUG_H_
diff --git a/media/eco/include/eco/ECOService.h b/media/eco/include/eco/ECOService.h
new file mode 100644
index 0000000..f83edff
--- /dev/null
+++ b/media/eco/include/eco/ECOService.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_MEDIA_ECO_SERVICE_H_
+#define ANDROID_MEDIA_ECO_SERVICE_H_
+
+#include <android/media/eco/BnECOService.h>
+#include <binder/BinderService.h>
+
+#include <list>
+
+#include "eco/ECODebug.h"
+#include "eco/ECOSession.h"
+
+namespace android {
+namespace media {
+namespace eco {
+
+using android::sp;
+using android::binder::Status;
+using android::media::eco::ECOSession;
+
+/**
+ * ECO (Encoder Camera Optimization) service.
+ *
+ * ECOService creates and manages EcoSession to relay feedback information between one or multiple
+ * ECOServiceStatsProvider and ECOServiceInfoListener. The relationship can be many-to-many. In
+ * general, ECOServiceStatsProvider extracts information from an encoder for a given encoding
+ * session. EcoSession then relays the encoder information to any subscribed
+ * ECOServiceInfoListener.
+ *
+ * Internally, ECOService creates an ECOSession for each encoding session. Upon start, both
+ * ECOServiceStatsProvider and ECOServiceInfoListener should call obtainSession to get the
+ * ECOSession instance. After that, ECOServiceStatsProvider should push Stats to ECOSession and
+ * ECOServiceInfoListener should listen to the info from ECOSession. Upon finish, both
+ * ECOServiceStatsProvider and ECOServiceInfoListener should remove themselves from ECOSession.
+ * Then ECOService will safely destroy the ECOSession.
+ */
+class ECOService : public BinderService<ECOService>,
+                   public BnECOService,
+                   public virtual IBinder::DeathRecipient {
+    friend class BinderService<ECOService>;
+
+public:
+    ECOService();
+
+    virtual ~ECOService() = default;
+
+    virtual Status obtainSession(int32_t width, int32_t height, bool isCameraRecording,
+                                 sp<IECOSession>* _aidl_return);
+
+    virtual Status getNumOfSessions(int32_t* _aidl_return);
+
+    virtual Status getSessions(::std::vector<sp<IBinder>>* _aidl_return);
+
+    // Implementation of BinderService<T>
+    static char const* getServiceName() { return "media.ecoservice"; }
+
+    // IBinder::DeathRecipient implementation
+    virtual void binderDied(const wp<IBinder>& who);
+
+    virtual status_t dump(int fd, const Vector<String16>& args);
+
+private:
+    // Lock guarding ECO service state
+    Mutex mServiceLock;
+
+    struct SessionConfig {
+        int32_t mWidth;
+        int32_t mHeight;
+        bool mIsCameraRecording;
+
+        SessionConfig(int w, int h, bool isCameraRecording)
+              : mWidth(w), mHeight(h), mIsCameraRecording(isCameraRecording) {}
+
+        bool operator==(const SessionConfig& cfg) {
+            return mWidth == cfg.mWidth && mHeight == cfg.mHeight &&
+                   mIsCameraRecording == cfg.mIsCameraRecording;
+        }
+    };
+
+    friend bool operator==(const SessionConfig& p1, const SessionConfig& p2) {
+        return p1.mWidth == p2.mWidth && p1.mHeight == p2.mHeight &&
+               p1.mIsCameraRecording == p2.mIsCameraRecording;
+    }
+
+    // Hash function for mSessionConfigToSessionMap.
+    // TODO(hkuang): Add test for this hash function.
+    struct SessionConfigHash {
+        size_t operator()(const SessionConfig& cfg) const {
+            // Generate a hash by bit shifting and concatenation.
+            return cfg.mWidth | (cfg.mHeight << 16) | ((int32_t)cfg.mIsCameraRecording << 31);
+        }
+    };
+
+    // Map from SessionConfig to session.
+    std::unordered_map<SessionConfig, wp<ECOSession>, SessionConfigHash> mSessionConfigToSessionMap;
+
+    using MapIterType =
+            std::unordered_map<SessionConfig, wp<ECOSession>, SessionConfigHash>::iterator;
+
+    // A helpful function to traverse the mSessionConfigToSessionMap, remove the entry that
+    // does not exist any more and call |callback| when the entry is valid.
+    void SanitizeSession(const std::function<void(MapIterType it)>& callback);
+};
+
+}  // namespace eco
+}  // namespace media
+}  // namespace android
+
+#endif  // ANDROID_MEDIA_ECO_SERVICE_H_
diff --git a/media/eco/include/eco/ECOServiceConstants.h b/media/eco/include/eco/ECOServiceConstants.h
new file mode 100644
index 0000000..5d753d0
--- /dev/null
+++ b/media/eco/include/eco/ECOServiceConstants.h
@@ -0,0 +1,260 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef ANDROID_MEDIA_ECO_SERVICE_CONSTANTS_H_
+#define ANDROID_MEDIA_ECO_SERVICE_CONSTANTS_H_
+
+#include <stdint.h>
+#include <sys/mman.h>
+
+namespace android {
+namespace media {
+namespace eco {
+
+// Codec type.
+constexpr int32_t CodecTypeUnknown = 0x00;
+constexpr int32_t CodecTypeAVC = 0x01;
+constexpr int32_t CodecTypeHEVC = 0x02;
+
+// Encoded frame type.
+constexpr int32_t FrameTypeUnknown = 0x0;
+constexpr int32_t FrameTypeI = 0x01;
+constexpr int32_t FrameTypeP = 0x02;
+constexpr int32_t FrameTypeB = 0x04;
+
+// Below constants are borrowed from
+// frameworks/av/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
+
+// from MediaCodecInfo.java
+
+// Profile types:
+constexpr int32_t AVCProfileBaseline = 0x01;
+constexpr int32_t AVCProfileMain = 0x02;
+constexpr int32_t AVCProfileExtended = 0x04;
+constexpr int32_t AVCProfileHigh = 0x08;
+constexpr int32_t AVCProfileHigh10 = 0x10;
+constexpr int32_t AVCProfileHigh422 = 0x20;
+constexpr int32_t AVCProfileHigh444 = 0x40;
+constexpr int32_t AVCProfileConstrainedBaseline = 0x10000;
+constexpr int32_t AVCProfileConstrainedHigh = 0x80000;
+
+constexpr int32_t HEVCProfileMain = 0x01;
+constexpr int32_t HEVCProfileMain10 = 0x02;
+constexpr int32_t HEVCProfileMainStill = 0x04;
+constexpr int32_t HEVCProfileMain10HDR10 = 0x1000;
+constexpr int32_t HEVCProfileMain10HDR10Plus = 0x2000;
+
+// Level types:
+constexpr int32_t AVCLevel1 = 0x01;
+constexpr int32_t AVCLevel1b = 0x02;
+constexpr int32_t AVCLevel11 = 0x04;
+constexpr int32_t AVCLevel12 = 0x08;
+constexpr int32_t AVCLevel13 = 0x10;
+constexpr int32_t AVCLevel2 = 0x20;
+constexpr int32_t AVCLevel21 = 0x40;
+constexpr int32_t AVCLevel22 = 0x80;
+constexpr int32_t AVCLevel3 = 0x100;
+constexpr int32_t AVCLevel31 = 0x200;
+constexpr int32_t AVCLevel32 = 0x400;
+constexpr int32_t AVCLevel4 = 0x800;
+constexpr int32_t AVCLevel41 = 0x1000;
+constexpr int32_t AVCLevel42 = 0x2000;
+constexpr int32_t AVCLevel5 = 0x4000;
+constexpr int32_t AVCLevel51 = 0x8000;
+constexpr int32_t AVCLevel52 = 0x10000;
+constexpr int32_t AVCLevel6 = 0x20000;
+constexpr int32_t AVCLevel61 = 0x40000;
+constexpr int32_t AVCLevel62 = 0x80000;
+
+constexpr int32_t HEVCMainTierLevel1 = 0x1;
+constexpr int32_t HEVCHighTierLevel1 = 0x2;
+constexpr int32_t HEVCMainTierLevel2 = 0x4;
+constexpr int32_t HEVCHighTierLevel2 = 0x8;
+constexpr int32_t HEVCMainTierLevel21 = 0x10;
+constexpr int32_t HEVCHighTierLevel21 = 0x20;
+constexpr int32_t HEVCMainTierLevel3 = 0x40;
+constexpr int32_t HEVCHighTierLevel3 = 0x80;
+constexpr int32_t HEVCMainTierLevel31 = 0x100;
+constexpr int32_t HEVCHighTierLevel31 = 0x200;
+constexpr int32_t HEVCMainTierLevel4 = 0x400;
+constexpr int32_t HEVCHighTierLevel4 = 0x800;
+constexpr int32_t HEVCMainTierLevel41 = 0x1000;
+constexpr int32_t HEVCHighTierLevel41 = 0x2000;
+constexpr int32_t HEVCMainTierLevel5 = 0x4000;
+constexpr int32_t HEVCHighTierLevel5 = 0x8000;
+constexpr int32_t HEVCMainTierLevel51 = 0x10000;
+constexpr int32_t HEVCHighTierLevel51 = 0x20000;
+constexpr int32_t HEVCMainTierLevel52 = 0x40000;
+constexpr int32_t HEVCHighTierLevel52 = 0x80000;
+constexpr int32_t HEVCMainTierLevel6 = 0x100000;
+constexpr int32_t HEVCHighTierLevel6 = 0x200000;
+constexpr int32_t HEVCMainTierLevel61 = 0x400000;
+constexpr int32_t HEVCHighTierLevel61 = 0x800000;
+constexpr int32_t HEVCMainTierLevel62 = 0x1000000;
+constexpr int32_t HEVCHighTierLevel62 = 0x2000000;
+
+inline static const char* asString_AVCProfile(int32_t i, const char* def = "??") {
+    switch (i) {
+    case AVCProfileBaseline:
+        return "Baseline";
+    case AVCProfileMain:
+        return "Main";
+    case AVCProfileExtended:
+        return "Extended";
+    case AVCProfileHigh:
+        return "High";
+    case AVCProfileHigh10:
+        return "High10";
+    case AVCProfileHigh422:
+        return "High422";
+    case AVCProfileHigh444:
+        return "High444";
+    case AVCProfileConstrainedBaseline:
+        return "ConstrainedBaseline";
+    case AVCProfileConstrainedHigh:
+        return "ConstrainedHigh";
+    default:
+        return def;
+    }
+}
+
+inline static const char* asString_AVCLevel(int32_t i, const char* def = "??") {
+    switch (i) {
+    case AVCLevel1:
+        return "1";
+    case AVCLevel1b:
+        return "1b";
+    case AVCLevel11:
+        return "1.1";
+    case AVCLevel12:
+        return "1.2";
+    case AVCLevel13:
+        return "1.3";
+    case AVCLevel2:
+        return "2";
+    case AVCLevel21:
+        return "2.1";
+    case AVCLevel22:
+        return "2.2";
+    case AVCLevel3:
+        return "3";
+    case AVCLevel31:
+        return "3.1";
+    case AVCLevel32:
+        return "3.2";
+    case AVCLevel4:
+        return "4";
+    case AVCLevel41:
+        return "4.1";
+    case AVCLevel42:
+        return "4.2";
+    case AVCLevel5:
+        return "5";
+    case AVCLevel51:
+        return "5.1";
+    case AVCLevel52:
+        return "5.2";
+    case AVCLevel6:
+        return "6";
+    case AVCLevel61:
+        return "6.1";
+    case AVCLevel62:
+        return "6.2";
+    default:
+        return def;
+    }
+}
+
+inline static const char* asString_HEVCProfile(int32_t i, const char* def = "??") {
+    switch (i) {
+    case HEVCProfileMain:
+        return "Main";
+    case HEVCProfileMain10:
+        return "Main10";
+    case HEVCProfileMainStill:
+        return "MainStill";
+    case HEVCProfileMain10HDR10:
+        return "Main10HDR10";
+    case HEVCProfileMain10HDR10Plus:
+        return "Main10HDR10Plus";
+    default:
+        return def;
+    }
+}
+
+inline static const char* asString_HEVCTierLevel(int32_t i, const char* def = "??") {
+    switch (i) {
+    case HEVCMainTierLevel1:
+        return "Main 1";
+    case HEVCHighTierLevel1:
+        return "High 1";
+    case HEVCMainTierLevel2:
+        return "Main 2";
+    case HEVCHighTierLevel2:
+        return "High 2";
+    case HEVCMainTierLevel21:
+        return "Main 2.1";
+    case HEVCHighTierLevel21:
+        return "High 2.1";
+    case HEVCMainTierLevel3:
+        return "Main 3";
+    case HEVCHighTierLevel3:
+        return "High 3";
+    case HEVCMainTierLevel31:
+        return "Main 3.1";
+    case HEVCHighTierLevel31:
+        return "High 3.1";
+    case HEVCMainTierLevel4:
+        return "Main 4";
+    case HEVCHighTierLevel4:
+        return "High 4";
+    case HEVCMainTierLevel41:
+        return "Main 4.1";
+    case HEVCHighTierLevel41:
+        return "High 4.1";
+    case HEVCMainTierLevel5:
+        return "Main 5";
+    case HEVCHighTierLevel5:
+        return "High 5";
+    case HEVCMainTierLevel51:
+        return "Main 5.1";
+    case HEVCHighTierLevel51:
+        return "High 5.1";
+    case HEVCMainTierLevel52:
+        return "Main 5.2";
+    case HEVCHighTierLevel52:
+        return "High 5.2";
+    case HEVCMainTierLevel6:
+        return "Main 6";
+    case HEVCHighTierLevel6:
+        return "High 6";
+    case HEVCMainTierLevel61:
+        return "Main 6.1";
+    case HEVCHighTierLevel61:
+        return "High 6.1";
+    case HEVCMainTierLevel62:
+        return "Main 6.2";
+    case HEVCHighTierLevel62:
+        return "High 6.2";
+    default:
+        return def;
+    }
+}
+
+}  // namespace eco
+}  // namespace media
+}  // namespace android
+
+#endif  // ANDROID_MEDIA_ECO_SERVICE_CONSTANTS_H_
diff --git a/media/eco/include/eco/ECOServiceInfoListener.h b/media/eco/include/eco/ECOServiceInfoListener.h
new file mode 100644
index 0000000..8a08a69
--- /dev/null
+++ b/media/eco/include/eco/ECOServiceInfoListener.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_MEDIA_ECO_SERVICE_INFO_LISTENER_H_
+#define ANDROID_MEDIA_ECO_SERVICE_INFO_LISTENER_H_
+
+#include <android/media/eco/BnECOServiceInfoListener.h>
+#include <android/media/eco/IECOSession.h>
+#include <binder/BinderService.h>
+
+#include <condition_variable>
+#include <memory>
+#include <mutex>
+#include <thread>
+
+#include "ECOData.h"
+
+namespace android {
+namespace media {
+namespace eco {
+
+using ::android::binder::Status;
+
+/**
+ * ECOServiceInfoListener interface class.
+ */
+class ECOServiceInfoListener : public BinderService<IECOServiceInfoListener>,
+                               public BnECOServiceInfoListener,
+                               public virtual IBinder::DeathRecipient {
+    friend class BinderService<IECOServiceInfoListener>;
+
+public:
+    // Create a ECOServiceInfoListener with specifed width, height and isCameraRecording.
+    ECOServiceInfoListener(int32_t width, int32_t height, bool isCameraRecording);
+
+    virtual ~ECOServiceInfoListener() {}
+
+    virtual Status getType(int32_t* _aidl_return) = 0;
+    virtual Status getName(::android::String16* _aidl_return) = 0;
+    virtual Status getECOSession(::android::sp<::android::IBinder>* _aidl_return) = 0;
+    virtual Status onNewInfo(const ::android::media::eco::ECOData& newInfo) = 0;
+
+    // IBinder::DeathRecipient implementation.
+    virtual void binderDied(const wp<IBinder>& who);
+
+private:
+};
+
+}  // namespace eco
+}  // namespace media
+}  // namespace android
+
+#endif  // ANDROID_MEDIA_ECO_SERVICE_INFO_LISTENER_H_
diff --git a/media/eco/include/eco/ECOServiceStatsProvider.h b/media/eco/include/eco/ECOServiceStatsProvider.h
new file mode 100644
index 0000000..a6e1586
--- /dev/null
+++ b/media/eco/include/eco/ECOServiceStatsProvider.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_MEDIA_ECO_SERVICE_STATS_PROVIDER_H_
+#define ANDROID_MEDIA_ECO_SERVICE_STATS_PROVIDER_H_
+
+#include <android/media/eco/BnECOServiceStatsProvider.h>
+#include <android/media/eco/IECOSession.h>
+#include <binder/BinderService.h>
+
+#include <condition_variable>
+#include <memory>
+#include <mutex>
+#include <thread>
+
+#include "ECOData.h"
+
+namespace android {
+namespace media {
+namespace eco {
+
+using ::android::binder::Status;
+
+/**
+ * ECOServiceStatsProvider interface class.
+ */
+class ECOServiceStatsProvider : public BinderService<IECOServiceStatsProvider>,
+                                public BnECOServiceStatsProvider,
+                                public virtual IBinder::DeathRecipient {
+    friend class BinderService<IECOServiceStatsProvider>;
+
+public:
+    // Create a ECOServiceStatsProvider with specifed width, height and isCameraRecording.
+    ECOServiceStatsProvider(int32_t width, int32_t height, bool isCameraRecording);
+
+    virtual ~ECOServiceStatsProvider() {}
+
+    virtual Status getType(int32_t* _aidl_return) = 0;
+    virtual Status getName(::android::String16* _aidl_return) = 0;
+    virtual Status getECOSession(::android::sp<::android::IBinder>* _aidl_return) = 0;
+    virtual Status isCameraRecording(bool* _aidl_return) = 0;
+
+    // IBinder::DeathRecipient implementation
+    virtual void binderDied(const wp<IBinder>& who);
+
+private:
+};
+
+}  // namespace eco
+}  // namespace media
+}  // namespace android
+
+#endif  // ANDROID_MEDIA_ECO_SERVICE_STATS_PROVIDER_H_
diff --git a/media/eco/include/eco/ECOSession.h b/media/eco/include/eco/ECOSession.h
new file mode 100644
index 0000000..90f9d94
--- /dev/null
+++ b/media/eco/include/eco/ECOSession.h
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_MEDIA_ECO_SESSION_H_
+#define ANDROID_MEDIA_ECO_SESSION_H_
+
+#include <android/media/eco/BnECOSession.h>
+#include <android/media/eco/IECOServiceStatsProvider.h>
+#include <binder/BinderService.h>
+
+#include <condition_variable>
+#include <deque>
+#include <list>
+#include <memory>
+#include <mutex>
+#include <thread>
+
+#include "ECOData.h"
+#include "ECOServiceInfoListener.h"
+#include "ECOServiceStatsProvider.h"
+#include "ECOUtils.h"
+
+namespace android {
+namespace media {
+namespace eco {
+
+using ::android::binder::Status;
+
+/**
+ * ECO Session.
+ *
+ * ECOSession is created by ECOService to manage an encoding session. Both the providers and
+ * listeners should interact with ECO session after obtain it from ECOService. For ECOService 1.0,
+ * it only supports resolution of up to 720P and only for camera recording use case. Also, it only
+ * supports encoder as the provider and camera as listener.
+ */
+class ECOSession : public BinderService<ECOSession>,
+                   public BnECOSession,
+                   public virtual IBinder::DeathRecipient {
+    friend class BinderService<ECOSession>;
+
+public:
+    virtual ~ECOSession();
+
+    virtual Status addStatsProvider(const sp<IECOServiceStatsProvider>& provider,
+                                    const ECOData& statsConfig, /*out*/ bool* status);
+
+    virtual Status removeStatsProvider(const sp<IECOServiceStatsProvider>&, bool*);
+
+    virtual Status addInfoListener(const sp<IECOServiceInfoListener>&,
+                                   const ECOData& listenerConfig,
+                                   /*out*/ bool* status);
+
+    virtual Status removeInfoListener(const sp<IECOServiceInfoListener>&, bool*);
+
+    virtual Status pushNewStats(const ECOData&, bool*);
+
+    virtual Status getWidth(int32_t* _aidl_return);
+
+    virtual Status getHeight(int32_t* _aidl_return);
+
+    virtual Status getIsCameraRecording(bool*);
+
+    virtual Status getNumOfListeners(int32_t*);
+
+    virtual Status getNumOfProviders(int32_t*);
+
+    // IBinder::DeathRecipient implementation
+    virtual void binderDied(const wp<IBinder>& who);
+
+    // Grant permission to EcoSessionTest to run test.
+    friend class EcoSessionTest;
+
+    // Let ECOService create the session.
+    friend class ECOService;
+
+protected:
+    static android::sp<ECOSession> createECOSession(int32_t width, int32_t height,
+                                                    bool isCameraRecording);
+
+private:
+    // Only the  ECOService could create ECOSession.
+    ECOSession(int32_t width, int32_t height, bool isCameraRecording);
+
+    virtual status_t dump(int fd, const Vector<String16>& args);
+
+    // Start the main thread for processing the stats and pushing info to listener.
+    static void startThread(ECOSession* session);
+
+    void run();
+
+    bool processStats(const ECOData& stats);
+
+    // Lock guarding ECO session state
+    std::mutex mSessionLock;
+
+    // Process the session stats received from provider.
+    void processSessionStats(const ECOData& stats);
+
+    // Process the frame stats received from provider.
+    void processFrameStats(const ECOData& stats);
+
+    // Generate the latest session info if available.
+    ECOData generateLatestSessionInfoEcoData();
+
+    std::atomic<bool> mStopThread;
+
+    std::mutex mStatsQueueLock;
+    std::deque<ECOData> mStatsQueue;  // GUARDED_BY(mStatsQueueLock)
+    std::condition_variable mWorkerWaitCV;
+
+    bool mNewListenerAdded = false;
+
+    constexpr static int32_t ENCODER_MIN_QP = 0;
+    constexpr static int32_t ENCODER_MAX_QP = 51;
+
+    // Save the QP last reported to the listener. Init to be 0.
+    int32_t mLastReportedQp;
+
+    typedef struct QpRange {
+        int32_t mQpBlocknessThreshold = 50;
+        int32_t mQpChangeThreshold = 50;
+    } QpCondition;
+    QpCondition mListenerQpCondition;
+
+    android::sp<IECOServiceInfoListener> mListener;
+    String16 mListenerName;
+
+    android::sp<IECOServiceStatsProvider> mProvider;
+    String16 mProviderName;
+
+    // Main thread for processing the events from provider.
+    std::thread mThread;
+
+    // Width of the encoding session in number of pixels.
+    const int32_t mWidth;
+
+    // Height of the encoding session in number of pixels.
+    const int32_t mHeight;
+
+    // Whether the encoding is for camera recording.
+    const bool mIsCameraRecording;
+
+    // Ouput width of the encoding session in number of pixels, -1 means not available.
+    int32_t mOutputWidth = -1;
+
+    // Output height of the encoding session in number of pixels. -1 means not available.
+    int32_t mOutputHeight = -1;
+
+    // Encoder codec type of the encoding session. -1 means not available.
+    int32_t mCodecType = -1;
+
+    // Encoder codec profile. -1 means not available.
+    int32_t mCodecProfile = -1;
+
+    // Encoder codec level. -1 means not available.
+    int32_t mCodecLevel = -1;
+
+    // Target bitrate in bits per second. This should be provided by the provider. -1 means not
+    // available.
+    int32_t mTargetBitrateBps = -1;
+
+    // Actual bitrate in bits per second. This should be provided by the provider. -1 means not
+    // available.
+    int32_t mActualBitrateBps = -1;
+
+    // Key frame interval in number of frames. -1 means not available.
+    int32_t mKeyFrameIntervalFrames = -1;
+
+    // Frame rate in frames per second. -1 means not available.
+    float mFramerateFps;
+
+    // Debug related flags.
+    bool mLogStats;
+    uint32_t mLogStatsEntries;  // number of stats received from the provider.
+    std::list<ECOData> mStatsDebugBuffer;
+
+    // Pushes the ECOData to the debug buffer.
+    void logStats(const ECOData& data);
+
+    bool mLogInfo;
+    uint32_t mLogInfoEntries;  // number of infos sent to the listener.
+    std::list<ECOData> mInfosDebugBuffer;
+
+    // Pushes the ECOData to the debug buffer.
+    void logInfos(const ECOData& data);
+};
+
+}  // namespace eco
+}  // namespace media
+}  // namespace android
+
+#endif  // ANDROID_MEDIA_ECO_SESSION_H_
diff --git a/media/eco/include/eco/ECOUtils.h b/media/eco/include/eco/ECOUtils.h
new file mode 100644
index 0000000..e5bbfcc
--- /dev/null
+++ b/media/eco/include/eco/ECOUtils.h
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Helper classes and functions to be used by provider and listener.
+#ifndef ANDROID_MEDIA_ECO_UTILS_H_
+#define ANDROID_MEDIA_ECO_UTILS_H_
+
+#include <cutils/atomic.h>
+#include <utils/Errors.h>
+
+#include "ECOData.h"
+#include "ECODataKey.h"
+#include "ECOServiceConstants.h"
+
+namespace android {
+namespace media {
+namespace eco {
+
+#define RETURN_STATUS_IF_ERROR(expr)  \
+    {                                 \
+        status_t _errorCode = (expr); \
+        if (_errorCode != NO_ERROR) { \
+            return _errorCode;        \
+        }                             \
+    }
+
+// Helper structure to hold encoder config. This is used by EncoderProvider to provide stats to
+// ECOService or by ECOService to provide info to the listener. Providers could implement their
+// own more complex encoder config as long as ECOService supports parsing them.
+struct SimpleEncoderConfig {
+    // Encoder name as defined in device/google/[device]/media_codecs.xml.
+    std::string mEncoderName;
+
+    // Codec Type as defined in ECOServiceConstants.h. -1 means unavailable.
+    int32_t mCodecType;
+
+    // Codec profile as defined in ECOServiceConstants.h. -1 means unavailable.
+    int32_t mProfile;
+
+    // Codec level as defined in ECOServiceConstants.h. -1 means unavailable.
+    int32_t mLevel;
+
+    // Target bitrate in bits per second. -1 means unavailable.
+    int32_t mTargetBitrate;
+
+    // Key frame interval in frames. -1 means unavailable.
+    int32_t mKeyFrameIntervalFrames;
+
+    // Frame rate in frames per second. -1 means unavailable.
+    float mFrameRateFps;
+
+    SimpleEncoderConfig()
+          : mEncoderName(""),
+            mCodecType(-1),
+            mProfile(-1),
+            mLevel(-1),
+            mTargetBitrate(-1),
+            mKeyFrameIntervalFrames(-1),
+            mFrameRateFps(-1) {}
+
+    SimpleEncoderConfig(const std::string& name, int32_t codecType, int32_t profile, int32_t level,
+                        int32_t bitrate, int32_t kfi, float framerateFps)
+          : mEncoderName(name),
+            mCodecType(codecType),
+            mProfile(profile),
+            mLevel(level),
+            mTargetBitrate(bitrate),
+            mKeyFrameIntervalFrames(kfi),
+            mFrameRateFps(framerateFps) {}
+
+    // Convert this SimpleEncoderConfig to ECOData with dataType.
+    ECOData toEcoData(ECOData::ECODatatype dataType);
+};
+
+// Helper structure for
+struct SimpleEncodedFrameData {
+    // Frame sequence number starts from 0.
+    int32_t mFrameNum;
+
+    // Frame type as defined in ECOServiceConstants.h. -1 means unavailable.
+    int8_t mFrameType;
+
+    // Frame presentation timestamp in us. -1 means unavailable.
+    int64_t mFramePtsUs;
+
+    // Avg quantization parameter of the frame. -1 means unavailable.
+    int32_t mAvgQp;
+
+    // Frame size in bytes. -1 means unavailable.
+    int32_t mFrameSizeBytes;
+
+    SimpleEncodedFrameData()
+          : mFrameNum(-1),
+            mFrameType(FrameTypeUnknown),
+            mFramePtsUs(-1),
+            mAvgQp(-1),
+            mFrameSizeBytes(-1) {}
+
+    SimpleEncodedFrameData(int32_t frameNum, int8_t frameType, int64_t ptsUs, int32_t qp,
+                           int32_t sizeBytes)
+          : mFrameNum(frameNum),
+            mFrameType(frameType),
+            mFramePtsUs(ptsUs),
+            mAvgQp(qp),
+            mFrameSizeBytes(sizeBytes) {}
+
+    // Convert this SimpleEncoderConfig to ECOData with dataType.
+    ECOData toEcoData(ECOData::ECODatatype dataType);
+};
+
+bool copyKeyValue(const ECOData& src, ECOData* dst);
+
+}  // namespace eco
+}  // namespace media
+}  // namespace android
+
+#endif  // ANDROID_MEDIA_ECO_UTILS_H_
diff --git a/media/eco/tests/Android.bp b/media/eco/tests/Android.bp
new file mode 100644
index 0000000..6eb3015
--- /dev/null
+++ b/media/eco/tests/Android.bp
@@ -0,0 +1,57 @@
+cc_defaults{
+    name : "libmedia_ecoservice_tests_defaults",
+    cflags : [
+        "-Wall",
+        "-Werror",
+    ],
+}
+
+cc_test {
+    name: "EcoDataTest",
+    defaults: ["libmedia_ecoservice_tests_defaults"],
+    srcs: ["EcoDataTest.cpp"],
+    shared_libs: [
+        "libbinder",
+        "libcutils",
+        "libutils",
+        "liblog",
+        "libmedia_ecoservice",
+    ],
+}
+
+cc_test {
+    name: "EcoSessionTest",
+    defaults: ["libmedia_ecoservice_tests_defaults"],
+    srcs: [
+        "EcoSessionTest.cpp",
+        "FakeECOServiceStatsProvider.cpp",
+        "FakeECOServiceInfoListener.cpp",
+        ],
+
+    shared_libs: [
+        "libbinder",
+        "libcutils",
+        "libutils",
+        "liblog",
+        "libmedia_ecoservice",
+    ],
+}
+
+cc_test {
+    name: "EcoServiceTest",
+    vendor: true,
+    defaults: ["libmedia_ecoservice_tests_defaults"],
+    srcs: [
+        "EcoServiceTest.cpp",
+        "FakeECOServiceStatsProvider.cpp",
+        "FakeECOServiceInfoListener.cpp",
+        ],
+
+    shared_libs: [
+        "libbinder",
+        "libcutils",
+        "libutils",
+        "liblog",
+        "libmedia_ecoservice",
+    ],
+}
\ No newline at end of file
diff --git a/media/eco/tests/EcoDataTest.cpp b/media/eco/tests/EcoDataTest.cpp
new file mode 100644
index 0000000..f93b692
--- /dev/null
+++ b/media/eco/tests/EcoDataTest.cpp
@@ -0,0 +1,367 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Unit Test for EcoData.
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "ECODataTest"
+
+#include <android-base/unique_fd.h>
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+#include <cutils/ashmem.h>
+#include <gtest/gtest.h>
+#include <math.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <utils/Log.h>
+
+#include "eco/ECOData.h"
+#include "eco/ECODataKey.h"
+
+namespace android {
+namespace media {
+namespace eco {
+
+TEST(EcoDataTest, TestConstructor1) {
+    std::unique_ptr<ECOData> data = std::make_unique<ECOData>();
+    EXPECT_EQ(data->getDataType(), ECOData::DATA_TYPE_UNKNOWN);
+    EXPECT_EQ(data->getDataTimeUs(), -1);
+}
+
+TEST(EcoDataTest, TestConstructor2) {
+    std::unique_ptr<ECOData> data = std::make_unique<ECOData>(ECOData::DATA_TYPE_STATS);
+    EXPECT_EQ(data->getDataType(), ECOData::DATA_TYPE_STATS);
+    EXPECT_EQ(data->getDataTimeUs(), -1);
+}
+
+TEST(EcoDataTest, TestConstructor3) {
+    std::unique_ptr<ECOData> data = std::make_unique<ECOData>(ECOData::DATA_TYPE_STATS, 1000);
+    EXPECT_EQ(data->getDataType(), ECOData::DATA_TYPE_STATS);
+    EXPECT_EQ(data->getDataTimeUs(), 1000);
+}
+
+TEST(EcoDataTest, TestNormalSetAndFindString) {
+    std::unique_ptr<ECOData> data = std::make_unique<ECOData>(ECOData::DATA_TYPE_STATS, 1000);
+
+    data->setString(ENCODER_TYPE, "avc");
+    std::string testValue;
+    EXPECT_TRUE(data->findString(ENCODER_TYPE, &testValue) == ECODataStatus::OK);
+    EXPECT_EQ(testValue, "avc");
+
+    // Override existing key.
+    data->setString(ENCODER_TYPE, "hevc");
+    EXPECT_EQ(data->findString(ENCODER_TYPE, &testValue), ECODataStatus::OK);
+    EXPECT_EQ(testValue, "hevc");
+}
+
+TEST(EcoDataTest, TestSetAndFindMultipleString) {
+    std::unique_ptr<ECOData> data = std::make_unique<ECOData>(ECOData::DATA_TYPE_STATS, 1000);
+
+    std::unordered_map<std::string, std::string> inputEntries = {
+            {"name1", "avc"},  {"name2", "avc2"},   {"name3", "avc3"},   {"name4", "avc4"},
+            {"name5", "avc5"}, {"name6", "avc6"},   {"name7", "avc7"},   {"name8", "avc8"},
+            {"name9", "avc9"}, {"name10", "avc10"}, {"name11", "avc11"}, {"name12", "avc12"}};
+    for (auto it = inputEntries.begin(); it != inputEntries.end(); ++it) {
+        data->setString(it->first, it->second);
+    }
+
+    // Checks if the string exist in the ECOData.
+    for (auto it = inputEntries.begin(); it != inputEntries.end(); ++it) {
+        std::string testValue;
+        EXPECT_TRUE(data->findString(it->first, &testValue) == ECODataStatus::OK);
+        EXPECT_EQ(testValue, it->second);
+    }
+}
+
+TEST(EcoDataTest, TestSetAndFindInvalidString) {
+    std::unique_ptr<ECOData> data = std::make_unique<ECOData>(ECOData::DATA_TYPE_STATS, 1000);
+
+    // Test read to null ptr and expect failure
+    EXPECT_TRUE(data->findString("encoder-name", nullptr) != ECODataStatus::OK);
+
+    // Test find non-existing key and expect failure.
+    std::string testValue;
+    EXPECT_TRUE(data->findString("encoder-name", &testValue) != ECODataStatus::OK);
+
+    // Test set empty key and expect failure
+    EXPECT_TRUE(data->setString("", "avc") != ECODataStatus::OK);
+
+    // Test read empty key and expect failure
+    EXPECT_TRUE(data->findString("", &testValue) != ECODataStatus::OK);
+}
+
+TEST(EcoDataTest, TestNormalSetAndFindInt32) {
+    std::unique_ptr<ECOData> data = std::make_unique<ECOData>(ECOData::DATA_TYPE_STATS, 1000);
+
+    data->setInt32(ENCODER_TARGET_BITRATE_BPS, 2000000);
+    int32_t testValue;
+    EXPECT_TRUE(data->findInt32(ENCODER_TARGET_BITRATE_BPS, &testValue) == ECODataStatus::OK);
+    EXPECT_EQ(testValue, 2000000);
+
+    // Override existing key.
+    data->setInt32(ENCODER_TARGET_BITRATE_BPS, 2200000);
+    EXPECT_EQ(data->findInt32(ENCODER_TARGET_BITRATE_BPS, &testValue), ECODataStatus::OK);
+    EXPECT_EQ(testValue, 2200000);
+}
+
+TEST(EcoDataTest, TestSetAndFindMultipleInt32) {
+    std::unique_ptr<ECOData> data = std::make_unique<ECOData>(ECOData::DATA_TYPE_STATS, 1000);
+
+    std::unordered_map<std::string, int32_t> inputEntries = {
+            {"name1", 100}, {"name2", 200},    {"name3", 300},     {"name4", 400},
+            {"name5", 500}, {"name6", 600},    {"name7", 700},     {"name8", 800},
+            {"name9", 900}, {"name10", 10000}, {"name11", 110000}, {"name12", 120000}};
+    for (auto it = inputEntries.begin(); it != inputEntries.end(); ++it) {
+        data->setInt32(it->first, it->second);
+    }
+
+    // Checks if the string exist in the ECOData.
+    for (auto it = inputEntries.begin(); it != inputEntries.end(); ++it) {
+        int32_t testValue;
+        EXPECT_TRUE(data->findInt32(it->first, &testValue) == ECODataStatus::OK);
+        EXPECT_EQ(testValue, it->second);
+    }
+}
+
+TEST(EcoDataTest, TestSetAndFindInvalidInt32) {
+    std::unique_ptr<ECOData> data = std::make_unique<ECOData>(ECOData::DATA_TYPE_STATS, 1000);
+
+    // Test read to null ptr and expect failure
+    EXPECT_TRUE(data->findInt32("encoder-name", nullptr) != ECODataStatus::OK);
+
+    // Test find non-existing key and expect failure.
+    int32_t testValue;
+    EXPECT_TRUE(data->findInt32("encoder-name", &testValue) != ECODataStatus::OK);
+
+    // Test set empty key and expect failure
+    EXPECT_TRUE(data->setInt32("", 1000) != ECODataStatus::OK);
+
+    // Test read empty key and expect failure
+    EXPECT_TRUE(data->findInt32("", &testValue) != ECODataStatus::OK);
+}
+
+TEST(EcoDataTest, TestNormalSetAndFindInt64) {
+    std::unique_ptr<ECOData> data = std::make_unique<ECOData>(ECOData::DATA_TYPE_STATS, 1000);
+
+    data->setInt64(ENCODER_TARGET_BITRATE_BPS, 2000000);
+    int64_t testValue;
+    EXPECT_TRUE(data->findInt64(ENCODER_TARGET_BITRATE_BPS, &testValue) == ECODataStatus::OK);
+    EXPECT_EQ(testValue, 2000000);
+
+    // Override existing key.
+    data->setInt64(ENCODER_TARGET_BITRATE_BPS, 2200000);
+    EXPECT_EQ(data->findInt64(ENCODER_TARGET_BITRATE_BPS, &testValue), ECODataStatus::OK);
+    EXPECT_EQ(testValue, 2200000);
+}
+
+TEST(EcoDataTest, TestNormalSetAndFindMultipleInt64) {
+    std::unique_ptr<ECOData> data = std::make_unique<ECOData>(ECOData::DATA_TYPE_STATS, 1000);
+
+    std::unordered_map<std::string, int64_t> inputEntries = {
+            {"name1", 100}, {"name2", 200},    {"name3", 300},     {"name4", 400},
+            {"name5", 500}, {"name6", 600},    {"name7", 700},     {"name8", 800},
+            {"name9", 900}, {"name10", 10000}, {"name11", 110000}, {"name12", 120000}};
+    for (auto it = inputEntries.begin(); it != inputEntries.end(); ++it) {
+        data->setInt64(it->first, it->second);
+    }
+
+    // Checks if the string exist in the ECOData.
+    for (auto it = inputEntries.begin(); it != inputEntries.end(); ++it) {
+        int64_t testValue;
+        EXPECT_TRUE(data->findInt64(it->first, &testValue) == ECODataStatus::OK);
+        EXPECT_EQ(testValue, it->second);
+    }
+}
+
+TEST(EcoDataTest, TestSetAndFindInvalidInt64) {
+    std::unique_ptr<ECOData> data = std::make_unique<ECOData>(ECOData::DATA_TYPE_STATS, 1000);
+
+    // Test read to null ptr and expect failure
+    EXPECT_TRUE(data->findInt64("encoder-name", nullptr) != ECODataStatus::OK);
+
+    // Test find non-existing key and expect failure.
+    int64_t testValue;
+    EXPECT_TRUE(data->findInt64("encoder-name", &testValue) != ECODataStatus::OK);
+
+    // Test set empty key and expect failure
+    EXPECT_TRUE(data->setInt64("", 1000) != ECODataStatus::OK);
+
+    // Test read empty key and expect failure
+    EXPECT_TRUE(data->findInt64("", &testValue) != ECODataStatus::OK);
+}
+
+TEST(EcoDataTest, TestNormalSetAndFindFloat) {
+    std::unique_ptr<ECOData> data = std::make_unique<ECOData>(ECOData::DATA_TYPE_STATS, 1000);
+
+    data->setFloat(ENCODER_TARGET_BITRATE_BPS, 2000000.0);
+    float testValue;
+    EXPECT_TRUE(data->findFloat(ENCODER_TARGET_BITRATE_BPS, &testValue) == ECODataStatus::OK);
+    EXPECT_FLOAT_EQ(testValue, 2000000.0);
+
+    // Override existing key.
+    data->setFloat(ENCODER_TARGET_BITRATE_BPS, 2200000.0);
+    EXPECT_TRUE(data->findFloat(ENCODER_TARGET_BITRATE_BPS, &testValue) == ECODataStatus::OK);
+    EXPECT_FLOAT_EQ(testValue, 2200000.0);
+}
+
+TEST(EcoDataTest, TestNormalSetAndFindMultipleFloat) {
+    std::unique_ptr<ECOData> data = std::make_unique<ECOData>(ECOData::DATA_TYPE_STATS, 1000);
+
+    std::unordered_map<std::string, float> inputEntries = {
+            {"name1", 100.0}, {"name2", 200.0},    {"name3", 300.0},     {"name4", 400.0},
+            {"name5", 500.0}, {"name6", 600.0},    {"name7", 700.0},     {"name8", 800.0},
+            {"name9", 900.0}, {"name10", 10000.0}, {"name11", 110000.0}, {"name12", 120000.0}};
+    for (auto it = inputEntries.begin(); it != inputEntries.end(); ++it) {
+        data->setFloat(it->first, it->second);
+    }
+
+    // Checks if the string exist in the ECOData.
+    for (auto it = inputEntries.begin(); it != inputEntries.end(); ++it) {
+        float testValue;
+        EXPECT_TRUE(data->findFloat(it->first, &testValue) == ECODataStatus::OK);
+        EXPECT_FLOAT_EQ(testValue, it->second);
+    }
+}
+
+TEST(EcoDataTest, TestSetAndFindInvalidFloat) {
+    std::unique_ptr<ECOData> data = std::make_unique<ECOData>(ECOData::DATA_TYPE_STATS, 1000);
+
+    // Test read to null ptr and expect failure
+    EXPECT_TRUE(data->findFloat("encoder-name", nullptr) != ECODataStatus::OK);
+
+    // Test find non-existing key and expect failure.
+    float testValue;
+    EXPECT_TRUE(data->findFloat("encoder-name", &testValue) != ECODataStatus::OK);
+
+    // Test set empty key and expect failure
+    EXPECT_TRUE(data->setFloat("", 1000.0) != ECODataStatus::OK);
+
+    // Test read empty key and expect failure
+    EXPECT_TRUE(data->findFloat("", &testValue) != ECODataStatus::OK);
+}
+
+TEST(EcoDataTest, TestNormalSetAndFindMixedDataType) {
+    std::unique_ptr<ECOData> data = std::make_unique<ECOData>(ECOData::DATA_TYPE_STATS, 1000);
+
+    std::unordered_map<std::string, ECOData::ECODataValueType> inputEntries = {
+            {"name1", "google-encoder"}, {"name2", "avc"}, {"profile", 1}, {"level", 2},
+            {"framerate", 4.1},          {"kfi", 30}};
+    for (auto it = inputEntries.begin(); it != inputEntries.end(); ++it) {
+        data->set(it->first, it->second);
+    }
+
+    // Checks if the string exist in the ECOData.
+    for (auto it = inputEntries.begin(); it != inputEntries.end(); ++it) {
+        ECOData::ECODataValueType testValue;
+        EXPECT_TRUE(data->find(it->first, &testValue) == ECODataStatus::OK);
+        EXPECT_EQ(testValue, it->second);
+    }
+}
+
+TEST(EcoDataTest, TestSetAndFindInvalidDataType) {
+    std::unique_ptr<ECOData> data = std::make_unique<ECOData>(ECOData::DATA_TYPE_STATS, 1000);
+
+    // Test read to null ptr and expect failure
+    EXPECT_TRUE(data->find("encoder-name", nullptr) != ECODataStatus::OK);
+
+    // Test find non-existing key and expect failure.
+    ECOData::ECODataValueType testValue;
+    EXPECT_TRUE(data->find("encoder-name2", &testValue) != ECODataStatus::OK);
+
+    // Test set empty key and expect failure
+    EXPECT_TRUE(data->set("", 1000) != ECODataStatus::OK);
+
+    // Test read empty key and expect failure
+    EXPECT_TRUE(data->find("", &testValue) != ECODataStatus::OK);
+}
+
+TEST(EcoDataTest, TestNormalWriteReadParcel) {
+    constexpr int32_t kDataType = ECOData::DATA_TYPE_STATS;
+    constexpr int64_t kDataTimeUs = 1000;
+
+    std::unique_ptr<ECOData> sourceData = std::make_unique<ECOData>(kDataType, kDataTimeUs);
+
+    std::unordered_map<std::string, ECOData::ECODataValueType> inputEntries = {
+            {"name1", "google-encoder"}, {"name2", "avc"}, {"profile", 1}, {"level", 2},
+            {"framerate", 4.1},          {"kfi", 30}};
+    for (auto it = inputEntries.begin(); it != inputEntries.end(); ++it) {
+        sourceData->set(it->first, it->second);
+    }
+
+    std::unique_ptr<Parcel> parcel = std::make_unique<Parcel>();
+    EXPECT_TRUE(sourceData->writeToParcel(parcel.get()) == NO_ERROR);
+
+    // Rewind the data position of the parcel for this test. Otherwise, the following read will not
+    // start from the beginning.
+    parcel->setDataPosition(0);
+
+    // Reads the parcel back into a new ECOData
+    std::unique_ptr<ECOData> dstData = std::make_unique<ECOData>();
+    EXPECT_TRUE(dstData->readFromParcel(parcel.get()) == NO_ERROR);
+
+    // Checks the data type, time and number of entries.
+    EXPECT_EQ(sourceData->getNumOfEntries(), dstData->getNumOfEntries());
+    EXPECT_EQ(dstData->getDataType(), kDataType);
+    EXPECT_EQ(dstData->getDataTimeUs(), kDataTimeUs);
+
+    for (auto it = inputEntries.begin(); it != inputEntries.end(); ++it) {
+        ECOData::ECODataValueType testValue;
+        EXPECT_TRUE(dstData->find(it->first, &testValue) == ECODataStatus::OK);
+        EXPECT_EQ(testValue, it->second);
+    }
+}
+
+TEST(EcoDataTest, TestWriteInvalidParcel) {
+    constexpr int32_t kDataType = ECOData::DATA_TYPE_STATS;
+    constexpr int64_t kDataTimeUs = 1000;
+
+    std::unique_ptr<ECOData> sourceData = std::make_unique<ECOData>(kDataType, kDataTimeUs);
+
+    std::unique_ptr<Parcel> parcel = std::make_unique<Parcel>();
+    EXPECT_TRUE(sourceData->writeToParcel(nullptr) != NO_ERROR);
+}
+
+TEST(EcoDataTest, TestReadInvalidParcel) {
+    constexpr int32_t kDataType = ECOData::DATA_TYPE_STATS;
+    constexpr int64_t kDataTimeUs = 1000;
+
+    std::unique_ptr<ECOData> sourceData = std::make_unique<ECOData>(kDataType, kDataTimeUs);
+
+    std::unordered_map<std::string, ECOData::ECODataValueType> inputEntries = {
+            {"name1", "google-encoder"}, {"name2", "avc"}, {"profile", 1}, {"level", 2},
+            {"framerate", 4.1},          {"kfi", 30}};
+    for (auto it = inputEntries.begin(); it != inputEntries.end(); ++it) {
+        sourceData->set(it->first, it->second);
+    }
+
+    std::unique_ptr<Parcel> parcel = std::make_unique<Parcel>();
+    EXPECT_TRUE(sourceData->writeToParcel(parcel.get()) == NO_ERROR);
+
+    // Corrupt the parcel by write random data to the beginning.
+    parcel->setDataPosition(4);
+    parcel->writeCString("invalid-data");
+
+    parcel->setDataPosition(0);
+
+    // Reads the parcel back into a new ECOData
+    std::unique_ptr<ECOData> dstData = std::make_unique<ECOData>();
+    EXPECT_TRUE(dstData->readFromParcel(parcel.get()) != NO_ERROR);
+}
+
+}  // namespace eco
+}  // namespace media
+}  // namespace android
\ No newline at end of file
diff --git a/media/eco/tests/EcoServiceTest.cpp b/media/eco/tests/EcoServiceTest.cpp
new file mode 100644
index 0000000..dc589dd
--- /dev/null
+++ b/media/eco/tests/EcoServiceTest.cpp
@@ -0,0 +1,228 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Unit Test for ECOService.
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "ECOServiceTest"
+
+#include <android-base/unique_fd.h>
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+#include <cutils/ashmem.h>
+#include <gtest/gtest.h>
+#include <math.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <utils/Log.h>
+
+#include "FakeECOServiceInfoListener.h"
+#include "FakeECOServiceStatsProvider.h"
+#include "eco/ECOService.h"
+#include "eco/ECOUtils.h"
+
+namespace android {
+namespace media {
+namespace eco {
+
+using ::android::IBinder;
+using android::sp;
+using ::android::binder::Status;
+
+namespace {
+
+static constexpr uint32_t kTestWidth = 1280;
+static constexpr uint32_t kTestHeight = 720;
+static constexpr bool kIsCameraRecording = true;
+static constexpr float kFrameRate = 30.0f;
+
+}  // namespace
+
+// A helper class to help create ECOService and manage ECOService.
+class EcoServiceTest : public ::testing::Test {
+public:
+    EcoServiceTest() { ALOGD("EcoServiceTest created"); }
+
+    sp<IECOService> createService() {
+        android::sp<android::IServiceManager> sm = android::defaultServiceManager();
+        assert(sm != 0);
+        android::sp<android::IBinder> binder = sm->getService(String16("media.ecoservice"));
+
+        if (binder == 0) {
+            ALOGE("Failed to connect to ecoservice");
+            return nullptr;
+        } else {
+            ALOGD("Successfully connect to ecoservice");
+        }
+
+        mECOService = android::interface_cast<IECOService>(binder);
+        return mECOService;
+    }
+
+    ~EcoServiceTest() { ALOGD("EcoServiceTest destroyed"); }
+
+private:
+    sp<IECOService> mECOService = nullptr;
+};
+
+TEST_F(EcoServiceTest, NormalObtainSessionWithInvalidWidth) {
+    sp<IECOService> service = createService();
+    EXPECT_TRUE(service != nullptr);
+
+    // Provider obtains the session from the service.
+    sp<IECOSession> session = nullptr;
+
+    service->obtainSession(-1 /* width */, kTestHeight, kIsCameraRecording, &session);
+    EXPECT_FALSE(session);
+}
+
+TEST_F(EcoServiceTest, NormalObtainSessionWithInvalidHeight) {
+    sp<IECOService> service = createService();
+
+    // Provider obtains the session from the service.
+    sp<IECOSession> session = nullptr;
+
+    service->obtainSession(kTestWidth, -1 /* height */, kIsCameraRecording, &session);
+    EXPECT_FALSE(session);
+}
+
+TEST_F(EcoServiceTest, NormalObtainSessionWithCameraRecordingFalse) {
+    sp<IECOService> service = createService();
+
+    // Provider obtains the session from the service.
+    sp<IECOSession> session = nullptr;
+
+    service->obtainSession(kTestWidth, kTestHeight, false /* isCameraRecording */, &session);
+    EXPECT_TRUE(session);
+}
+
+TEST_F(EcoServiceTest, NormalObtainSingleSession) {
+    sp<IECOService> service = createService();
+    EXPECT_TRUE(service != nullptr);
+
+    // Provider obtains the session from the service.
+    sp<IECOSession> session = nullptr;
+
+    service->obtainSession(kTestWidth, kTestHeight, kIsCameraRecording, &session);
+    EXPECT_TRUE(session);
+}
+
+TEST_F(EcoServiceTest, NormalObtainSessionTwice) {
+    sp<IECOService> service = createService();
+    EXPECT_TRUE(service != nullptr);
+
+    // Provider obtains the session from the service.
+    sp<IECOSession> session1 = nullptr;
+
+    service->obtainSession(kTestWidth, kTestHeight, kIsCameraRecording, &session1);
+    EXPECT_TRUE(session1);
+
+    sp<IECOSession> session2 = nullptr;
+
+    service->obtainSession(kTestWidth, kTestHeight, kIsCameraRecording, &session2);
+    EXPECT_TRUE(session2);
+
+    // The two session instances should be the same.
+    EXPECT_TRUE(IInterface::asBinder(session1) == IInterface::asBinder(session2));
+}
+
+TEST_F(EcoServiceTest, ObtainTwoSessions) {
+    sp<IECOService> service = createService();
+    EXPECT_TRUE(service != nullptr);
+
+    // Provider obtains the session from the service.
+    sp<IECOSession> session1 = nullptr;
+
+    service->obtainSession(kTestWidth, kTestHeight, kIsCameraRecording, &session1);
+    EXPECT_TRUE(session1);
+
+    sp<IECOSession> session2 = nullptr;
+
+    service->obtainSession(kTestWidth - 1, kTestHeight - 1, kIsCameraRecording, &session2);
+    EXPECT_TRUE(session2);
+
+    // The two session instances must not be the same.
+    EXPECT_TRUE(IInterface::asBinder(session1) != IInterface::asBinder(session2));
+
+    // Check the session number.
+    int32_t count = 0;
+    service->getNumOfSessions(&count);
+    EXPECT_EQ(count, 2);
+
+    // Get the list of sessions from service.
+    std::vector<sp<IBinder>> sessionList;
+    service->getSessions(&sessionList);
+    bool foundFirstSession = false, foundSecondSession = false;
+
+    for (std::vector<sp<IBinder>>::iterator it = sessionList.begin(); it != sessionList.end();
+         ++it) {
+        if (IInterface::asBinder(session1) == it->get()) {
+            foundFirstSession = true;
+        }
+        if (IInterface::asBinder(session2) == it->get()) {
+            foundSecondSession = true;
+        }
+    }
+
+    // Expect found both sessions.
+    EXPECT_TRUE(foundFirstSession);
+    EXPECT_TRUE(foundSecondSession);
+}
+
+TEST_F(EcoServiceTest, TestNormalFlowWithOneListenerAndOneProvider) {
+    sp<IECOService> service = createService();
+    EXPECT_TRUE(service != nullptr);
+
+    // Provider obtains the session from the service.
+    sp<IECOSession> session = nullptr;
+
+    service->obtainSession(kTestWidth, kTestHeight, kIsCameraRecording, &session);
+    EXPECT_TRUE(session);
+
+    // Create provider and add it to the session.
+    sp<FakeECOServiceStatsProvider> fakeProvider = new FakeECOServiceStatsProvider(
+            kTestWidth, kTestHeight, kIsCameraRecording, kFrameRate);
+    fakeProvider->setECOSession(session);
+
+    ECOData providerConfig(ECOData::DATA_TYPE_STATS_PROVIDER_CONFIG,
+                           systemTime(SYSTEM_TIME_BOOTTIME));
+    providerConfig.setString(KEY_PROVIDER_NAME, "FakeECOServiceStatsProvider");
+    providerConfig.setInt32(KEY_PROVIDER_TYPE,
+                            ECOServiceStatsProvider::STATS_PROVIDER_TYPE_VIDEO_ENCODER);
+    bool res;
+    Status status = session->addStatsProvider(fakeProvider, providerConfig, &res);
+
+    // Create listener and add it to the session.
+    sp<FakeECOServiceInfoListener> fakeListener =
+            new FakeECOServiceInfoListener(kTestWidth, kTestHeight, kIsCameraRecording);
+    fakeListener->setECOSession(session);
+
+    // Create the listener config.
+    ECOData listenerConfig(ECOData::DATA_TYPE_INFO_LISTENER_CONFIG,
+                           systemTime(SYSTEM_TIME_BOOTTIME));
+    listenerConfig.setString(KEY_LISTENER_NAME, "FakeECOServiceInfoListener");
+    listenerConfig.setInt32(KEY_LISTENER_TYPE, ECOServiceInfoListener::INFO_LISTENER_TYPE_CAMERA);
+
+    // Specify the qp thresholds for receiving notification.
+    listenerConfig.setInt32(KEY_LISTENER_QP_BLOCKINESS_THRESHOLD, 40);
+    listenerConfig.setInt32(KEY_LISTENER_QP_CHANGE_THRESHOLD, 5);
+
+    status = session->addInfoListener(fakeListener, listenerConfig, &res);
+}
+
+}  // namespace eco
+}  // namespace media
+}  // namespace android
diff --git a/media/eco/tests/EcoSessionTest.cpp b/media/eco/tests/EcoSessionTest.cpp
new file mode 100644
index 0000000..33a449d
--- /dev/null
+++ b/media/eco/tests/EcoSessionTest.cpp
@@ -0,0 +1,608 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Unit Test for ECOSession.
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "ECOSessionTest"
+
+#include <android-base/unique_fd.h>
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+#include <cutils/ashmem.h>
+#include <gtest/gtest.h>
+#include <math.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <utils/Log.h>
+
+#include "FakeECOServiceInfoListener.h"
+#include "FakeECOServiceStatsProvider.h"
+#include "eco/ECOSession.h"
+#include "eco/ECOUtils.h"
+
+namespace android {
+namespace media {
+namespace eco {
+
+using android::sp;
+using ::android::binder::Status;
+
+static constexpr uint32_t kTestWidth = 1280;
+static constexpr uint32_t kTestHeight = 720;
+static constexpr bool kIsCameraRecording = true;
+static constexpr int32_t kTargetBitrateBps = 22000000;
+static constexpr int32_t kKeyFrameIntervalFrames = 30;
+static constexpr float kFrameRate = 30.0f;
+
+// A helpful class to help create ECOSession and manage ECOSession.
+class EcoSessionTest : public ::testing::Test {
+public:
+    EcoSessionTest() { ALOGD("EcoSessionTest created"); }
+
+    sp<ECOSession> createSession(int32_t width, int32_t height, bool isCameraRecording) {
+        mSession = ECOSession::createECOSession(width, height, isCameraRecording);
+        if (mSession == nullptr) return nullptr;
+        return mSession;
+    }
+
+private:
+    sp<ECOSession> mSession = nullptr;
+};
+
+TEST_F(EcoSessionTest, TestConstructorWithInvalidParameters) {
+    // Expects failure as ECOService1.0 will only support up to 720P and camera recording case.
+    EXPECT_TRUE(createSession(1920 /* width */, 1080 /* height */, true /* isCameraRecording */) ==
+                nullptr);
+
+    // Expects failure as ECOService1.0 will only support up to 720P and camera recording case.
+    EXPECT_TRUE(createSession(1920 /* width */, 1080 /* height */, false /* isCameraRecording */) ==
+                nullptr);
+
+    EXPECT_TRUE(createSession(1920 /* width */, -1 /* height */, true /* isCameraRecording */) ==
+                nullptr);
+
+    EXPECT_TRUE(createSession(-1 /* width */, 1080 /* height */, true /* isCameraRecording */) ==
+                nullptr);
+}
+
+TEST_F(EcoSessionTest, TestConstructorWithValidParameters) {
+    // Expects success with <= 720P and is for camera recording.
+    EXPECT_TRUE(createSession(1280 /* width */, 720 /* height */, true /* isCameraRecording */) !=
+                nullptr);
+
+    // Expects success with <= 720P and is for camera recording.
+    EXPECT_TRUE(createSession(640 /* width */, 480 /* height */, true /* isCameraRecording */) !=
+                nullptr);
+}
+
+TEST_F(EcoSessionTest, TestAddProviderWithoutSpecifyEcoDataType) {
+    sp<ECOSession> ecoSession = createSession(kTestWidth, kTestHeight, kIsCameraRecording);
+    EXPECT_TRUE(ecoSession);
+
+    sp<FakeECOServiceStatsProvider> fakeProvider = new FakeECOServiceStatsProvider(
+            kTestWidth, kTestHeight, kIsCameraRecording, kFrameRate, ecoSession);
+
+    ECOData providerConfig;
+    bool res;
+    Status status = ecoSession->addStatsProvider(fakeProvider, providerConfig, &res);
+    EXPECT_FALSE(status.isOk());
+}
+
+TEST_F(EcoSessionTest, TestAddProviderWithWrongEcoDataType) {
+    sp<ECOSession> ecoSession = createSession(kTestWidth, kTestHeight, kIsCameraRecording);
+    EXPECT_TRUE(ecoSession);
+
+    sp<FakeECOServiceStatsProvider> fakeProvider = new FakeECOServiceStatsProvider(
+            kTestWidth, kTestHeight, kIsCameraRecording, kFrameRate, ecoSession);
+
+    ECOData providerConfig(ECOData::DATA_TYPE_INFO_LISTENER_CONFIG,
+                           systemTime(SYSTEM_TIME_BOOTTIME));
+    bool res;
+    Status status = ecoSession->addStatsProvider(fakeProvider, providerConfig, &res);
+    EXPECT_FALSE(status.isOk());
+}
+
+TEST_F(EcoSessionTest, TestAddNormalProvider) {
+    sp<ECOSession> ecoSession = createSession(kTestWidth, kTestHeight, kIsCameraRecording);
+    EXPECT_TRUE(ecoSession);
+
+    sp<FakeECOServiceStatsProvider> fakeProvider = new FakeECOServiceStatsProvider(
+            kTestWidth, kTestHeight, kIsCameraRecording, kFrameRate, ecoSession);
+
+    ECOData providerConfig(ECOData::DATA_TYPE_STATS_PROVIDER_CONFIG,
+                           systemTime(SYSTEM_TIME_BOOTTIME));
+    bool res;
+    Status status = ecoSession->addStatsProvider(fakeProvider, providerConfig, &res);
+    EXPECT_TRUE(status.isOk());
+}
+
+// Add two providers and expect failure as ECOService1.0 only supports one provider and one
+// listener.
+TEST_F(EcoSessionTest, TestAddTwoProvider) {
+    sp<ECOSession> ecoSession = createSession(kTestWidth, kTestHeight, kIsCameraRecording);
+    EXPECT_TRUE(ecoSession);
+
+    sp<FakeECOServiceStatsProvider> fakeProvider1 = new FakeECOServiceStatsProvider(
+            kTestWidth, kTestHeight, kIsCameraRecording, kFrameRate, ecoSession);
+
+    ECOData providerConfig(ECOData::DATA_TYPE_STATS_PROVIDER_CONFIG,
+                           systemTime(SYSTEM_TIME_BOOTTIME));
+    bool res;
+    Status status = ecoSession->addStatsProvider(fakeProvider1, providerConfig, &res);
+    EXPECT_TRUE(status.isOk());
+
+    sp<FakeECOServiceStatsProvider> fakeProvider2 = new FakeECOServiceStatsProvider(
+            kTestWidth, kTestHeight, kIsCameraRecording, kFrameRate, ecoSession);
+    status = ecoSession->addStatsProvider(fakeProvider2, providerConfig, &res);
+    EXPECT_FALSE(status.isOk());
+}
+
+TEST_F(EcoSessionTest, TestAddListenerWithDifferentHeight) {
+    sp<ECOSession> ecoSession = createSession(kTestWidth, kTestHeight, kIsCameraRecording);
+    EXPECT_TRUE(ecoSession);
+
+    sp<FakeECOServiceInfoListener> fakeListener = new FakeECOServiceInfoListener(
+            kTestWidth - 1, kTestHeight, kIsCameraRecording, ecoSession);
+
+    ECOData ListenerConfig(ECOData::DATA_TYPE_INFO_LISTENER_CONFIG,
+                           systemTime(SYSTEM_TIME_BOOTTIME));
+    bool res;
+    Status status = ecoSession->addInfoListener(fakeListener, ListenerConfig, &res);
+    EXPECT_FALSE(status.isOk());
+}
+
+TEST_F(EcoSessionTest, TestAddListenerWithDifferentWidth) {
+    sp<ECOSession> ecoSession = createSession(kTestWidth, kTestHeight, kIsCameraRecording);
+    EXPECT_TRUE(ecoSession);
+
+    sp<FakeECOServiceInfoListener> fakeListener = new FakeECOServiceInfoListener(
+            kTestWidth, kTestHeight - 1, kIsCameraRecording, ecoSession);
+
+    ECOData ListenerConfig(ECOData::DATA_TYPE_INFO_LISTENER_CONFIG,
+                           systemTime(SYSTEM_TIME_BOOTTIME));
+    bool res;
+    Status status = ecoSession->addInfoListener(fakeListener, ListenerConfig, &res);
+    EXPECT_FALSE(status.isOk());
+}
+
+TEST_F(EcoSessionTest, TestAddListenerWithCameraRecordingFalse) {
+    sp<ECOSession> ecoSession = createSession(kTestWidth, kTestHeight, kIsCameraRecording);
+    EXPECT_TRUE(ecoSession);
+
+    sp<FakeECOServiceInfoListener> fakeListener = new FakeECOServiceInfoListener(
+            kTestWidth, kTestHeight, !kIsCameraRecording, ecoSession);
+
+    ECOData ListenerConfig(ECOData::DATA_TYPE_INFO_LISTENER_CONFIG,
+                           systemTime(SYSTEM_TIME_BOOTTIME));
+    bool res;
+    Status status = ecoSession->addInfoListener(fakeListener, ListenerConfig, &res);
+    EXPECT_FALSE(status.isOk());
+}
+
+// Test the ECOSession with FakeECOServiceStatsProvider and FakeECOServiceInfoListener. Push the
+// stats to ECOSession through FakeECOServiceStatsProvider and check the info received in
+// from FakeECOServiceInfoListener ECOSession.
+TEST_F(EcoSessionTest, TestSessionWithProviderAndListenerSimpleTest) {
+    // The time that listener needs to wait for the info from ECOService.
+    static constexpr int kServiceWaitTimeMs = 10;
+
+    // Create the session.
+    sp<ECOSession> ecoSession = createSession(kTestWidth, kTestHeight, kIsCameraRecording);
+
+    // Add provider.
+    sp<FakeECOServiceStatsProvider> fakeProvider = new FakeECOServiceStatsProvider(
+            kTestWidth, kTestHeight, kIsCameraRecording, kFrameRate, ecoSession);
+    ECOData providerConfig(ECOData::DATA_TYPE_STATS_PROVIDER_CONFIG,
+                           systemTime(SYSTEM_TIME_BOOTTIME));
+    providerConfig.setString(KEY_PROVIDER_NAME, "FakeECOServiceStatsProvider");
+    providerConfig.setInt32(KEY_PROVIDER_TYPE,
+                            ECOServiceStatsProvider::STATS_PROVIDER_TYPE_VIDEO_ENCODER);
+    bool res;
+    Status status = ecoSession->addStatsProvider(fakeProvider, providerConfig, &res);
+
+    // Create listener.
+    sp<FakeECOServiceInfoListener> fakeListener =
+            new FakeECOServiceInfoListener(kTestWidth, kTestHeight, kIsCameraRecording, ecoSession);
+
+    // Create the listener config.
+    ECOData listenerConfig(ECOData::DATA_TYPE_INFO_LISTENER_CONFIG,
+                           systemTime(SYSTEM_TIME_BOOTTIME));
+    listenerConfig.setString(KEY_LISTENER_NAME, "FakeECOServiceInfoListener");
+    listenerConfig.setInt32(KEY_LISTENER_TYPE, ECOServiceInfoListener::INFO_LISTENER_TYPE_CAMERA);
+
+    // Specify the qp thresholds for receiving notification.
+    listenerConfig.setInt32(KEY_LISTENER_QP_BLOCKINESS_THRESHOLD, 40);
+    listenerConfig.setInt32(KEY_LISTENER_QP_CHANGE_THRESHOLD, 5);
+
+    status = ecoSession->addInfoListener(fakeListener, listenerConfig, &res);
+
+    ECOData info;
+    bool getInfo = false;
+
+    // Set the getInfo flag to true and copy the info from fakeListener.
+    fakeListener->setInfoAvailableCallback(
+            [&info, &getInfo](const ::android::media::eco::ECOData& newInfo) {
+                getInfo = true;
+                info = newInfo;
+            });
+
+    // Inject the session stats into the ECOSession through fakeProvider.
+    SimpleEncoderConfig sessionEncoderConfig("google-avc", CodecTypeAVC, AVCProfileHigh, AVCLevel52,
+                                             kTargetBitrateBps, kKeyFrameIntervalFrames,
+                                             kFrameRate);
+    fakeProvider->injectSessionStats(sessionEncoderConfig.toEcoData(ECOData::DATA_TYPE_STATS));
+
+    // Wait as ECOService may take some time to process.
+    std::this_thread::sleep_for(std::chrono::milliseconds(kServiceWaitTimeMs));
+    // Check the Session info matches with the session stats sent by provider.
+    EXPECT_TRUE(getInfo);
+    EXPECT_TRUE(info.getDataType() == ECOData::DATA_TYPE_INFO);
+
+    std::string infoType;
+    EXPECT_TRUE(info.findString(KEY_INFO_TYPE, &infoType) == ECODataStatus::OK);
+    EXPECT_EQ(infoType, VALUE_INFO_TYPE_SESSION);
+
+    // Check the session info matches the session stats provided by FakeECOServiceStatsProvider.
+    int32_t codecType;
+    EXPECT_TRUE(info.findInt32(ENCODER_TYPE, &codecType) == ECODataStatus::OK);
+    EXPECT_EQ(codecType, CodecTypeAVC);
+
+    int32_t profile;
+    EXPECT_TRUE(info.findInt32(ENCODER_PROFILE, &profile) == ECODataStatus::OK);
+    EXPECT_EQ(profile, AVCProfileHigh);
+
+    int32_t level;
+    EXPECT_TRUE(info.findInt32(ENCODER_LEVEL, &level) == ECODataStatus::OK);
+    EXPECT_EQ(level, AVCLevel52);
+
+    int32_t bitrate;
+    EXPECT_TRUE(info.findInt32(ENCODER_TARGET_BITRATE_BPS, &bitrate) == ECODataStatus::OK);
+    EXPECT_EQ(bitrate, kTargetBitrateBps);
+
+    int32_t kfi;
+    EXPECT_TRUE(info.findInt32(ENCODER_KFI_FRAMES, &kfi) == ECODataStatus::OK);
+    EXPECT_EQ(kfi, kKeyFrameIntervalFrames);
+
+    // =======================================================================================
+    // Inject the frame stats with qp = 30. Expect receiving notification for the first frame.
+    SimpleEncodedFrameData frameStats(1 /* seq number */, FrameTypeI, 0 /* framePtsUs */,
+                                      30 /* avg-qp */, 56 /* frameSize */);
+
+    getInfo = false;
+    fakeProvider->injectFrameStats(frameStats.toEcoData(ECOData::DATA_TYPE_STATS));
+    std::this_thread::sleep_for(std::chrono::milliseconds(kServiceWaitTimeMs));
+    // Check the Session info matches with the session stats sent by provider.
+    EXPECT_TRUE(getInfo);
+
+    EXPECT_TRUE(info.findString(KEY_INFO_TYPE, &infoType) == ECODataStatus::OK);
+    EXPECT_EQ(infoType, VALUE_INFO_TYPE_FRAME);
+
+    int8_t frameType;
+    EXPECT_TRUE(info.findInt8(FRAME_TYPE, &frameType) == ECODataStatus::OK);
+    EXPECT_EQ(frameType, FrameTypeI);
+
+    int32_t frameNum;
+    EXPECT_TRUE(info.findInt32(FRAME_NUM, &frameNum) == ECODataStatus::OK);
+    EXPECT_EQ(frameNum, 1);
+
+    int64_t framePtsUs;
+    EXPECT_TRUE(info.findInt64(FRAME_PTS_US, &framePtsUs) == ECODataStatus::OK);
+    EXPECT_EQ(framePtsUs, 0);
+
+    int32_t frameQp;
+    EXPECT_TRUE(info.findInt32(FRAME_AVG_QP, &frameQp) == ECODataStatus::OK);
+    EXPECT_EQ(frameQp, 30);
+
+    int32_t frameSize;
+    EXPECT_TRUE(info.findInt32(FRAME_SIZE_BYTES, &frameSize) == ECODataStatus::OK);
+    EXPECT_EQ(frameSize, 56);
+
+    // =======================================================================================
+    // Inject the frame stats with qp = 35. Expect not receiving notification as 35 is below
+    // threshold.
+    frameStats = SimpleEncodedFrameData(2 /* seq number */, FrameTypeP, 333333 /* framePtsUs */,
+                                        35 /* avg-qp */, 56 /* frameSize */);
+    getInfo = false;
+    fakeProvider->injectFrameStats(frameStats.toEcoData(ECOData::DATA_TYPE_STATS));
+    // Wait as ECOService may take some time to process.
+    std::this_thread::sleep_for(std::chrono::milliseconds(kServiceWaitTimeMs));
+    EXPECT_FALSE(getInfo);
+
+    // =======================================================================================
+    // Inject the frame stats with qp = 41. Expect receiving notification as 41 goes beyond
+    // threshold 40.
+    frameStats = SimpleEncodedFrameData(3 /* seq number */, FrameTypeP, 666666 /* framePtsUs */,
+                                        41 /* avg-qp */, 56 /* frameSize */);
+    getInfo = false;
+    fakeProvider->injectFrameStats(frameStats.toEcoData(ECOData::DATA_TYPE_STATS));
+    // Wait as ECOService may take some time to process.
+    std::this_thread::sleep_for(std::chrono::milliseconds(kServiceWaitTimeMs));
+
+    // Check the frame info matches with the frame stats sent by provider.
+    EXPECT_TRUE(getInfo);
+    EXPECT_TRUE(info.findString(KEY_INFO_TYPE, &infoType) == ECODataStatus::OK);
+    EXPECT_EQ(infoType, VALUE_INFO_TYPE_FRAME);
+    EXPECT_TRUE(info.findInt8(FRAME_TYPE, &frameType) == ECODataStatus::OK);
+    EXPECT_EQ(frameType, FrameTypeP);
+    EXPECT_TRUE(info.findInt32(FRAME_NUM, &frameNum) == ECODataStatus::OK);
+    EXPECT_EQ(frameNum, 3);
+    EXPECT_TRUE(info.findInt64(FRAME_PTS_US, &framePtsUs) == ECODataStatus::OK);
+    EXPECT_EQ(framePtsUs, 666666);
+    EXPECT_TRUE(info.findInt32(FRAME_AVG_QP, &frameQp) == ECODataStatus::OK);
+    EXPECT_EQ(frameQp, 41);
+    EXPECT_TRUE(info.findInt32(FRAME_SIZE_BYTES, &frameSize) == ECODataStatus::OK);
+    EXPECT_EQ(frameSize, 56);
+
+    // =======================================================================================
+    // Inject the frame stats with qp = 42. Expect not receiving notification as 42 goes beyond
+    // threshold 40 but delta oes not go beyond the mQpChangeThreshold threshold.
+    frameStats = SimpleEncodedFrameData(4 /* seq number */, FrameTypeP, 999999 /* framePtsUs */,
+                                        42 /* avg-qp */, 56 /* frameSize */);
+    getInfo = false;
+    fakeProvider->injectFrameStats(frameStats.toEcoData(ECOData::DATA_TYPE_STATS));
+    // Wait as ECOService may take some time to process.
+    std::this_thread::sleep_for(std::chrono::milliseconds(kServiceWaitTimeMs));
+    EXPECT_FALSE(getInfo);
+
+    // =======================================================================================
+    // Inject the frame stats with qp = 10. Expect receiving notification as the detal from
+    // last reported QP is larger than threshold 4.
+    frameStats = SimpleEncodedFrameData(5 /* seq number */, FrameTypeB, 1333332 /* framePtsUs */,
+                                        49 /* avg-qp */, 56 /* frameSize */);
+    getInfo = false;
+    fakeProvider->injectFrameStats(frameStats.toEcoData(ECOData::DATA_TYPE_STATS));
+    // Wait as ECOService may take some time to process.
+    std::this_thread::sleep_for(std::chrono::milliseconds(kServiceWaitTimeMs));
+
+    // Check the frame info matches with the frame stats sent by provider.
+    EXPECT_TRUE(getInfo);
+    EXPECT_TRUE(info.findString(KEY_INFO_TYPE, &infoType) == ECODataStatus::OK);
+    EXPECT_EQ(infoType, VALUE_INFO_TYPE_FRAME);
+    EXPECT_TRUE(info.findInt8(FRAME_TYPE, &frameType) == ECODataStatus::OK);
+    EXPECT_EQ(frameType, FrameTypeB);
+    EXPECT_TRUE(info.findInt32(FRAME_NUM, &frameNum) == ECODataStatus::OK);
+    EXPECT_EQ(frameNum, 5);
+    EXPECT_TRUE(info.findInt64(FRAME_PTS_US, &framePtsUs) == ECODataStatus::OK);
+    EXPECT_EQ(framePtsUs, 1333332);
+    EXPECT_TRUE(info.findInt32(FRAME_AVG_QP, &frameQp) == ECODataStatus::OK);
+    EXPECT_EQ(frameQp, 49);
+    EXPECT_TRUE(info.findInt32(FRAME_SIZE_BYTES, &frameSize) == ECODataStatus::OK);
+    EXPECT_EQ(frameSize, 56);
+
+    // =======================================================================================
+    // Inject the frame stats with qp = 41. Expect receiving notification as the detal from
+    // last reported QP is larger than threshold 4.
+    frameStats = SimpleEncodedFrameData(6 /* seq number */, FrameTypeB, 1666665 /* framePtsUs */,
+                                        41 /* avg-qp */, 56 /* frameSize */);
+    getInfo = false;
+    fakeProvider->injectFrameStats(frameStats.toEcoData(ECOData::DATA_TYPE_STATS));
+    std::this_thread::sleep_for(std::chrono::milliseconds(kServiceWaitTimeMs));
+
+    // Check the frame info matches with the frame stats sent by provider.
+    EXPECT_TRUE(getInfo);
+    EXPECT_TRUE(info.findString(KEY_INFO_TYPE, &infoType) == ECODataStatus::OK);
+    EXPECT_EQ(infoType, VALUE_INFO_TYPE_FRAME);
+    EXPECT_TRUE(info.findInt8(FRAME_TYPE, &frameType) == ECODataStatus::OK);
+    EXPECT_EQ(frameType, FrameTypeB);
+    EXPECT_TRUE(info.findInt32(FRAME_NUM, &frameNum) == ECODataStatus::OK);
+    EXPECT_EQ(frameNum, 6);
+    EXPECT_TRUE(info.findInt64(FRAME_PTS_US, &framePtsUs) == ECODataStatus::OK);
+    EXPECT_EQ(framePtsUs, 1666665);
+    EXPECT_TRUE(info.findInt32(FRAME_AVG_QP, &frameQp) == ECODataStatus::OK);
+    EXPECT_EQ(frameQp, 41);
+    EXPECT_TRUE(info.findInt32(FRAME_SIZE_BYTES, &frameSize) == ECODataStatus::OK);
+    EXPECT_EQ(frameSize, 56);
+}
+
+TEST_F(EcoSessionTest, TestRemoveMatchProvider) {
+    sp<ECOSession> ecoSession = createSession(kTestWidth, kTestHeight, kIsCameraRecording);
+    EXPECT_TRUE(ecoSession);
+
+    sp<FakeECOServiceStatsProvider> fakeProvider1 = new FakeECOServiceStatsProvider(
+            kTestWidth, kTestHeight, kIsCameraRecording, kFrameRate, ecoSession);
+
+    ECOData providerConfig(ECOData::DATA_TYPE_STATS_PROVIDER_CONFIG,
+                           systemTime(SYSTEM_TIME_BOOTTIME));
+    bool res;
+    Status status = ecoSession->addStatsProvider(fakeProvider1, providerConfig, &res);
+    EXPECT_TRUE(res);
+    EXPECT_TRUE(status.isOk());
+
+    status = ecoSession->removeStatsProvider(fakeProvider1, &res);
+    EXPECT_TRUE(res);
+    EXPECT_TRUE(status.isOk());
+}
+
+TEST_F(EcoSessionTest, TestRemoveMisMatchProvider) {
+    sp<ECOSession> ecoSession = createSession(kTestWidth, kTestHeight, kIsCameraRecording);
+    EXPECT_TRUE(ecoSession);
+
+    sp<FakeECOServiceStatsProvider> fakeProvider1 = new FakeECOServiceStatsProvider(
+            kTestWidth, kTestHeight, kIsCameraRecording, kFrameRate, ecoSession);
+
+    ECOData providerConfig(ECOData::DATA_TYPE_STATS_PROVIDER_CONFIG,
+                           systemTime(SYSTEM_TIME_BOOTTIME));
+    bool res;
+    Status status = ecoSession->addStatsProvider(fakeProvider1, providerConfig, &res);
+    EXPECT_TRUE(res);
+    EXPECT_TRUE(status.isOk());
+
+    sp<FakeECOServiceStatsProvider> fakeProvider2 = new FakeECOServiceStatsProvider(
+            kTestWidth, kTestHeight, kIsCameraRecording, kFrameRate, ecoSession);
+
+    status = ecoSession->removeStatsProvider(fakeProvider2, &res);
+    EXPECT_FALSE(res);
+    EXPECT_FALSE(status.isOk());
+}
+
+TEST_F(EcoSessionTest, TestRemoveMatchListener) {
+    sp<ECOSession> ecoSession = createSession(kTestWidth, kTestHeight, kIsCameraRecording);
+    EXPECT_TRUE(ecoSession);
+
+    // Create listener.
+    sp<FakeECOServiceInfoListener> fakeListener =
+            new FakeECOServiceInfoListener(kTestWidth, kTestHeight, kIsCameraRecording, ecoSession);
+
+    // Create the listener config.
+    ECOData listenerConfig(ECOData::DATA_TYPE_INFO_LISTENER_CONFIG,
+                           systemTime(SYSTEM_TIME_BOOTTIME));
+    listenerConfig.setString(KEY_LISTENER_NAME, "FakeECOServiceInfoListener");
+    listenerConfig.setInt32(KEY_LISTENER_TYPE, ECOServiceInfoListener::INFO_LISTENER_TYPE_CAMERA);
+
+    // Specify the qp thresholds for receiving notification.
+    listenerConfig.setInt32(KEY_LISTENER_QP_BLOCKINESS_THRESHOLD, 40);
+    listenerConfig.setInt32(KEY_LISTENER_QP_CHANGE_THRESHOLD, 5);
+
+    bool res;
+    Status status = ecoSession->addInfoListener(fakeListener, listenerConfig, &res);
+
+    status = ecoSession->removeInfoListener(fakeListener, &res);
+    EXPECT_TRUE(res);
+    EXPECT_TRUE(status.isOk());
+}
+
+TEST_F(EcoSessionTest, TestRemoveMisMatchListener) {
+    sp<ECOSession> ecoSession = createSession(kTestWidth, kTestHeight, kIsCameraRecording);
+    EXPECT_TRUE(ecoSession);
+
+    // Create listener.
+    sp<FakeECOServiceInfoListener> fakeListener =
+            new FakeECOServiceInfoListener(kTestWidth, kTestHeight, kIsCameraRecording, ecoSession);
+
+    // Create the listener config.
+    ECOData listenerConfig(ECOData::DATA_TYPE_INFO_LISTENER_CONFIG,
+                           systemTime(SYSTEM_TIME_BOOTTIME));
+    listenerConfig.setString(KEY_LISTENER_NAME, "FakeECOServiceInfoListener");
+    listenerConfig.setInt32(KEY_LISTENER_TYPE, ECOServiceInfoListener::INFO_LISTENER_TYPE_CAMERA);
+
+    // Specify the qp thresholds for receiving notification.
+    listenerConfig.setInt32(KEY_LISTENER_QP_BLOCKINESS_THRESHOLD, 40);
+    listenerConfig.setInt32(KEY_LISTENER_QP_CHANGE_THRESHOLD, 5);
+
+    bool res;
+    Status status = ecoSession->addInfoListener(fakeListener, listenerConfig, &res);
+
+    // Create listener.
+    sp<FakeECOServiceInfoListener> fakeListener2 =
+            new FakeECOServiceInfoListener(kTestWidth, kTestHeight, kIsCameraRecording, ecoSession);
+
+    status = ecoSession->removeInfoListener(fakeListener2, &res);
+    EXPECT_FALSE(res);
+    EXPECT_FALSE(status.isOk());
+}
+
+// Test the listener connects to the ECOSession after provider sends the session info. Listener
+// should recieve the session info right after adding itself to the ECOSession.
+TEST_F(EcoSessionTest, TestAddListenerAferProviderStarts) {
+    // The time that listener needs to wait for the info from ECOService.
+    static constexpr int kServiceWaitTimeMs = 10;
+
+    // Create the session.
+    sp<ECOSession> ecoSession = createSession(kTestWidth, kTestHeight, kIsCameraRecording);
+
+    // Add provider.
+    sp<FakeECOServiceStatsProvider> fakeProvider = new FakeECOServiceStatsProvider(
+            kTestWidth, kTestHeight, kIsCameraRecording, kFrameRate, ecoSession);
+    ECOData providerConfig(ECOData::DATA_TYPE_STATS_PROVIDER_CONFIG,
+                           systemTime(SYSTEM_TIME_BOOTTIME));
+    providerConfig.setString(KEY_PROVIDER_NAME, "FakeECOServiceStatsProvider");
+    providerConfig.setInt32(KEY_PROVIDER_TYPE,
+                            ECOServiceStatsProvider::STATS_PROVIDER_TYPE_VIDEO_ENCODER);
+    bool res;
+    Status status = ecoSession->addStatsProvider(fakeProvider, providerConfig, &res);
+
+    // Inject the session stats into the ECOSession through fakeProvider.
+    SimpleEncoderConfig sessionEncoderConfig("google-avc", CodecTypeAVC, AVCProfileHigh, AVCLevel52,
+                                             kTargetBitrateBps, kKeyFrameIntervalFrames,
+                                             kFrameRate);
+    fakeProvider->injectSessionStats(sessionEncoderConfig.toEcoData(ECOData::DATA_TYPE_STATS));
+
+    // Wait as ECOService may take some time to process.
+    std::this_thread::sleep_for(std::chrono::milliseconds(kServiceWaitTimeMs));
+
+    // =======================================================================================
+    // Inject the frame stats with qp = 30. Expect receiving notification for the first frame.
+    SimpleEncodedFrameData frameStats(1 /* seq number */, FrameTypeI, 0 /* framePtsUs */,
+                                      30 /* avg-qp */, 56 /* frameSize */);
+
+    fakeProvider->injectFrameStats(frameStats.toEcoData(ECOData::DATA_TYPE_STATS));
+    std::this_thread::sleep_for(std::chrono::milliseconds(kServiceWaitTimeMs));
+
+    // =======================================================================================
+    // Create and add the listener to the ECOSession. Expect to receive the session infor right
+    // after addInfoListener.
+    sp<FakeECOServiceInfoListener> fakeListener =
+            new FakeECOServiceInfoListener(kTestWidth, kTestHeight, kIsCameraRecording, ecoSession);
+
+    // Create the listener config.
+    ECOData listenerConfig(ECOData::DATA_TYPE_INFO_LISTENER_CONFIG,
+                           systemTime(SYSTEM_TIME_BOOTTIME));
+    listenerConfig.setString(KEY_LISTENER_NAME, "FakeECOServiceInfoListener");
+    listenerConfig.setInt32(KEY_LISTENER_TYPE, ECOServiceInfoListener::INFO_LISTENER_TYPE_CAMERA);
+
+    // Specify the qp thresholds for receiving notification.
+    listenerConfig.setInt32(KEY_LISTENER_QP_BLOCKINESS_THRESHOLD, 40);
+    listenerConfig.setInt32(KEY_LISTENER_QP_CHANGE_THRESHOLD, 5);
+
+    ECOData info;
+    bool getInfo = false;
+
+    // Set the getInfo flag to true and copy the info from fakeListener.
+    fakeListener->setInfoAvailableCallback(
+            [&info, &getInfo](const ::android::media::eco::ECOData& newInfo) {
+                getInfo = true;
+                info = newInfo;
+            });
+
+    status = ecoSession->addInfoListener(fakeListener, listenerConfig, &res);
+
+    // Wait as ECOService may take some time to process.
+    std::this_thread::sleep_for(std::chrono::milliseconds(kServiceWaitTimeMs));
+
+    // Check the Session info matches with the session stats sent by provider.
+    EXPECT_TRUE(getInfo);
+    EXPECT_TRUE(info.getDataType() == ECOData::DATA_TYPE_INFO);
+
+    std::string infoType;
+    EXPECT_TRUE(info.findString(KEY_INFO_TYPE, &infoType) == ECODataStatus::OK);
+    EXPECT_EQ(infoType, VALUE_INFO_TYPE_SESSION);
+
+    // Check the session info matches the session stats provided by FakeECOServiceStatsProvider.
+    int32_t codecType;
+    EXPECT_TRUE(info.findInt32(ENCODER_TYPE, &codecType) == ECODataStatus::OK);
+    EXPECT_EQ(codecType, CodecTypeAVC);
+
+    int32_t profile;
+    EXPECT_TRUE(info.findInt32(ENCODER_PROFILE, &profile) == ECODataStatus::OK);
+    EXPECT_EQ(profile, AVCProfileHigh);
+
+    int32_t level;
+    EXPECT_TRUE(info.findInt32(ENCODER_LEVEL, &level) == ECODataStatus::OK);
+    EXPECT_EQ(level, AVCLevel52);
+
+    int32_t bitrate;
+    EXPECT_TRUE(info.findInt32(ENCODER_TARGET_BITRATE_BPS, &bitrate) == ECODataStatus::OK);
+    EXPECT_EQ(bitrate, kTargetBitrateBps);
+
+    int32_t kfi;
+    EXPECT_TRUE(info.findInt32(ENCODER_KFI_FRAMES, &kfi) == ECODataStatus::OK);
+    EXPECT_EQ(kfi, kKeyFrameIntervalFrames);
+}
+
+}  // namespace eco
+}  // namespace media
+}  // namespace android
diff --git a/media/eco/tests/FakeECOServiceInfoListener.cpp b/media/eco/tests/FakeECOServiceInfoListener.cpp
new file mode 100644
index 0000000..2a4a285
--- /dev/null
+++ b/media/eco/tests/FakeECOServiceInfoListener.cpp
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "FakeFakeECOServiceInfoListener"
+
+#include "FakeECOServiceInfoListener.h"
+
+#include <android-base/unique_fd.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+#include <cutils/ashmem.h>
+#include <gtest/gtest.h>
+#include <math.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <utils/Log.h>
+
+namespace android {
+namespace media {
+namespace eco {
+
+FakeECOServiceInfoListener::FakeECOServiceInfoListener(int32_t width, int32_t height,
+                                                       bool isCameraRecording,
+                                                       android::sp<IECOSession> session)
+      : mWidth(width),
+        mHeight(height),
+        mIsCameraRecording(isCameraRecording),
+        mECOSession(session) {
+    ALOGD("FakeECOServiceInfoListener construct with w: %d, h: %d, isCameraRecording: %d", mWidth,
+          mHeight, mIsCameraRecording);
+}
+
+FakeECOServiceInfoListener::FakeECOServiceInfoListener(int32_t width, int32_t height,
+                                                       bool isCameraRecording)
+      : mWidth(width), mHeight(height), mIsCameraRecording(isCameraRecording) {
+    ALOGD("FakeECOServiceInfoListener construct with w: %d, h: %d, isCameraRecording: %d", mWidth,
+          mHeight, mIsCameraRecording);
+}
+
+FakeECOServiceInfoListener::~FakeECOServiceInfoListener() {
+    ALOGD("FakeECOServiceInfoListener destructor");
+}
+
+Status FakeECOServiceInfoListener::getType(int32_t* /*_aidl_return*/) {
+    return binder::Status::ok();
+}
+
+Status FakeECOServiceInfoListener::getName(::android::String16* _aidl_return) {
+    *_aidl_return = String16("FakeECOServiceInfoListener");
+    return binder::Status::ok();
+}
+
+Status FakeECOServiceInfoListener::getECOSession(sp<::android::IBinder>* _aidl_return) {
+    *_aidl_return = IInterface::asBinder(mECOSession);
+    return binder::Status::ok();
+}
+
+Status FakeECOServiceInfoListener::onNewInfo(const ::android::media::eco::ECOData& newInfo) {
+    ALOGD("FakeECOServiceInfoListener get new info");
+    mInfoAvaiableCallback(newInfo);
+    return binder::Status::ok();
+}
+
+// IBinder::DeathRecipient implementation
+void FakeECOServiceInfoListener::binderDied(const wp<IBinder>& /*who*/) {}
+
+}  // namespace eco
+}  // namespace media
+}  // namespace android
diff --git a/media/eco/tests/FakeECOServiceInfoListener.h b/media/eco/tests/FakeECOServiceInfoListener.h
new file mode 100644
index 0000000..9974b63
--- /dev/null
+++ b/media/eco/tests/FakeECOServiceInfoListener.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// A fake ECOServiceInfoListener for testing ECOService and ECOSession.
+
+#include <android-base/unique_fd.h>
+#include <android/media/eco/BnECOServiceInfoListener.h>
+#include <android/media/eco/IECOSession.h>
+#include <binder/BinderService.h>
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+#include <cutils/ashmem.h>
+#include <gtest/gtest.h>
+#include <math.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <utils/Log.h>
+
+#include "eco/ECOData.h"
+#include "eco/ECODataKey.h"
+
+namespace android {
+namespace media {
+namespace eco {
+
+using ::android::sp;
+using ::android::binder::Status;
+
+/**
+ * A fake ECOServiceInfoListener.
+ *
+ * FakeECOServiceInfoListener is a fake ECOServiceInfoListener that used for testing.
+ */
+class FakeECOServiceInfoListener : public BnECOServiceInfoListener {
+public:
+    // Method called by the FakeECOServiceInfoListener when there is new info from ECOService.
+    // This is used by the test to verify the information is sent by the ECOService correctly.
+    using InfoAvailableCallback =
+            std::function<void(const ::android::media::eco::ECOData& newInfo)>;
+
+    FakeECOServiceInfoListener(int32_t width, int32_t height, bool isCameraRecording,
+                               sp<IECOSession> session);
+
+    FakeECOServiceInfoListener(int32_t width, int32_t height, bool isCameraRecording);
+
+    void setECOSession(android::sp<IECOSession> session) { mECOSession = session; }
+
+    virtual ~FakeECOServiceInfoListener();
+
+    virtual Status getType(int32_t* _aidl_return);
+    virtual Status getName(::android::String16* _aidl_return);
+    virtual Status getECOSession(::android::sp<::android::IBinder>* _aidl_return);
+    virtual Status onNewInfo(const ::android::media::eco::ECOData& newInfo);
+
+    // Helper callback to send the info to the test.
+    void setInfoAvailableCallback(InfoAvailableCallback callback) {
+        mInfoAvaiableCallback = callback;
+    }
+
+    // IBinder::DeathRecipient implementation
+    virtual void binderDied(const wp<IBinder>& who);
+
+private:
+    int32_t mWidth;
+    int32_t mHeight;
+    bool mIsCameraRecording;
+    android::sp<IECOSession> mECOSession;
+    InfoAvailableCallback mInfoAvaiableCallback;
+};
+
+}  // namespace eco
+}  // namespace media
+}  // namespace android
diff --git a/media/eco/tests/FakeECOServiceStatsProvider.cpp b/media/eco/tests/FakeECOServiceStatsProvider.cpp
new file mode 100644
index 0000000..883a830
--- /dev/null
+++ b/media/eco/tests/FakeECOServiceStatsProvider.cpp
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "FakeECOServiceStatsProvider"
+
+#include "FakeECOServiceStatsProvider.h"
+
+#include <android-base/unique_fd.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+#include <cutils/ashmem.h>
+#include <gtest/gtest.h>
+#include <math.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <utils/Log.h>
+
+namespace android {
+namespace media {
+namespace eco {
+
+FakeECOServiceStatsProvider::FakeECOServiceStatsProvider(int32_t width, int32_t height,
+                                                         bool isCameraRecording, float frameRate,
+                                                         android::sp<IECOSession> session)
+      : mWidth(width),
+        mHeight(height),
+        mIsCameraRecording(isCameraRecording),
+        mFrameRate(frameRate),
+        mFrameNumber(0),
+        mECOSession(session) {
+    ALOGD("FakeECOServiceStatsProvider construct with w: %d, h: %d, isCameraRecording: %d, "
+          "frameRate: %f",
+          mWidth, mHeight, mIsCameraRecording, mFrameRate);
+}
+
+FakeECOServiceStatsProvider::FakeECOServiceStatsProvider(int32_t width, int32_t height,
+                                                         bool isCameraRecording, float frameRate)
+      : mWidth(width),
+        mHeight(height),
+        mIsCameraRecording(isCameraRecording),
+        mFrameRate(frameRate),
+        mFrameNumber(0) {
+    ALOGD("FakeECOServiceStatsProvider construct with w: %d, h: %d, isCameraRecording: %d, "
+          "frameRate: %f",
+          mWidth, mHeight, mIsCameraRecording, mFrameRate);
+}
+
+FakeECOServiceStatsProvider::~FakeECOServiceStatsProvider() {
+    ALOGD("FakeECOServiceStatsProvider destructor");
+}
+
+Status FakeECOServiceStatsProvider::getType(int32_t* /*_aidl_return*/) {
+    return binder::Status::ok();
+}
+
+Status FakeECOServiceStatsProvider::getName(::android::String16* _aidl_return) {
+    *_aidl_return = String16("FakeECOServiceStatsProvider");
+    return binder::Status::ok();
+}
+
+Status FakeECOServiceStatsProvider::getECOSession(sp<::android::IBinder>* _aidl_return) {
+    *_aidl_return = IInterface::asBinder(mECOSession);
+    return binder::Status::ok();
+}
+
+bool FakeECOServiceStatsProvider::injectSessionStats(const ECOData& stats) {
+    if (mECOSession == nullptr) return false;
+    ALOGD("injectSessionStats");
+    bool res;
+    mECOSession->pushNewStats(stats, &res);
+    return res;
+}
+
+bool FakeECOServiceStatsProvider::injectFrameStats(const ECOData& stats) {
+    if (mECOSession == nullptr) return false;
+    ALOGD("injectPerFrameStats");
+    bool res;
+    mECOSession->pushNewStats(stats, &res);
+    return res;
+}
+
+// IBinder::DeathRecipient implementation
+void FakeECOServiceStatsProvider::binderDied(const wp<IBinder>& /*who*/) {}
+
+}  // namespace eco
+}  // namespace media
+}  // namespace android
diff --git a/media/eco/tests/FakeECOServiceStatsProvider.h b/media/eco/tests/FakeECOServiceStatsProvider.h
new file mode 100644
index 0000000..0f60d02
--- /dev/null
+++ b/media/eco/tests/FakeECOServiceStatsProvider.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// A fake ECOServiceStatsProvider for testing ECOService and ECOSession.
+
+#include <android-base/unique_fd.h>
+#include <android/media/eco/BnECOServiceStatsProvider.h>
+#include <binder/BinderService.h>
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+#include <cutils/ashmem.h>
+#include <gtest/gtest.h>
+#include <math.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <utils/Log.h>
+
+#include <condition_variable>
+#include <deque>
+#include <list>
+#include <memory>
+#include <mutex>
+#include <thread>
+
+#include "eco/ECOData.h"
+#include "eco/ECODataKey.h"
+#include "eco/ECOService.h"
+
+namespace android {
+namespace media {
+namespace eco {
+
+using ::android::sp;
+using ::android::binder::Status;
+
+/**
+ * A fake ECOServiceStatsProvider.
+ *
+ * FakeECOServiceStatsProvider is a fake ECOServiceStatsProvider that used for testing.
+ */
+
+class FakeECOServiceStatsProvider : public BnECOServiceStatsProvider {
+public:
+    FakeECOServiceStatsProvider(int32_t width, int32_t height, bool isCameraRecording,
+                                float frameRate, android::sp<IECOSession> session);
+
+    FakeECOServiceStatsProvider(int32_t width, int32_t height, bool isCameraRecording,
+                                float frameRate);
+
+    void setECOSession(android::sp<IECOSession> session) { mECOSession = session; }
+
+    // Helper function to inject session stats to the FakeECOServiceStatsProvider so provider
+    // could push to the service.
+    bool injectSessionStats(const ECOData& stats);
+
+    // Helper function to inject each frame's stats to the FakeECOServiceStatsProvider so provider
+    // could push to the service.
+    bool injectFrameStats(const ECOData& stats);
+
+    /* Starts the FakeECOServiceStatsProvider */
+    void start();
+
+    /* Stops FakeECOServiceStatsProvider */
+    void stop();
+
+    virtual ~FakeECOServiceStatsProvider();
+
+    virtual Status getType(int32_t* _aidl_return);
+    virtual Status getName(::android::String16* _aidl_return);
+    virtual Status getECOSession(::android::sp<::android::IBinder>* _aidl_return);
+
+    // IBinder::DeathRecipient implementation
+    virtual void binderDied(const wp<IBinder>& who);
+
+private:
+    int32_t mWidth;
+    int32_t mHeight;
+    bool mIsCameraRecording;
+    float mFrameRate;
+    uint32_t mFrameNumber;
+
+    android::sp<IECOSession> mECOSession;
+};
+
+}  // namespace eco
+}  // namespace media
+}  // namespace android
diff --git a/media/eco/tests/run_all_unit_tests.sh b/media/eco/tests/run_all_unit_tests.sh
new file mode 100644
index 0000000..7cbe27b
--- /dev/null
+++ b/media/eco/tests/run_all_unit_tests.sh
@@ -0,0 +1,13 @@
+#!/bin/bash
+if [ -z "$ANDROID_BUILD_TOP" ]; then
+    echo "Android build environment not set"
+    exit -1
+fi
+
+echo "waiting for device"
+adb root && adb wait-for-device remount && adb sync
+
+adb shell /data/nativetest/EcoDataTest/EcoDataTest
+adb shell /data/nativetest/EcoSessionTest/EcoSessionTest
+#ECOService test lives in vendor side.
+adb shell data/nativetest/vendor/EcoServiceTest/EcoServiceTest
diff --git a/media/sfplugin/Android.bp b/media/sfplugin/Android.bp
index 831fb35..5e2e3bd 100644
--- a/media/sfplugin/Android.bp
+++ b/media/sfplugin/Android.bp
@@ -54,8 +54,5 @@
             "unsigned-integer-overflow",
             "signed-integer-overflow",
         ],
-        diag: {
-            cfi: true,
-        },
     },
 }
diff --git a/media/sfplugin/C2OMXNode.cpp b/media/sfplugin/C2OMXNode.cpp
index 92b86b6..03d859a 100644
--- a/media/sfplugin/C2OMXNode.cpp
+++ b/media/sfplugin/C2OMXNode.cpp
@@ -49,10 +49,8 @@
 
 }  // namespace
 
-C2OMXNode::C2OMXNode(const std::shared_ptr<Codec2Client::Component> &comp,
-                     const std::shared_ptr<InputGater> &inputGater)
-    : mComp(comp), mInputGater(inputGater),
-      mFrameIndex(0), mWidth(0), mHeight(0),
+C2OMXNode::C2OMXNode(const std::shared_ptr<Codec2Client::Component> &comp)
+    : mComp(comp), mFrameIndex(0), mWidth(0), mHeight(0),
       mAdjustTimestampGapUs(0), mFirstInputFrame(true) {
     // TODO: read from intf()
     if (!strncmp(comp->getName().c_str(), "c2.android.", 11)) {
@@ -106,7 +104,7 @@
 
 status_t C2OMXNode::setParameter(OMX_INDEXTYPE index, const void *params, size_t size) {
     // handle max/fixed frame duration control
-    if (index == OMX_IndexParamMaxFrameDurationForBitrateControl
+    if (index == (OMX_INDEXTYPE)OMX_IndexParamMaxFrameDurationForBitrateControl
             && params != NULL
             && size == sizeof(OMX_PARAM_U32TYPE)) {
         // The incoming number is an int32_t contained in OMX_U32.
@@ -214,7 +212,6 @@
         sp<Fence> fence = new Fence(fenceFd);
         fence->waitForever(LOG_TAG);
     }
-
     std::shared_ptr<Codec2Client::Component> comp = mComp.lock();
     if (!comp) {
         return NO_INIT;
@@ -290,11 +287,6 @@
     std::list<std::unique_ptr<C2Work>> items;
     items.push_back(std::move(work));
 
-    std::shared_ptr<InputGater> inputGater = mInputGater.lock();
-    if (!inputGater || !inputGater->canQueue()) {
-        return OK;
-    }
-
     c2_status_t err = comp->queue(&items);
     if (err != C2_OK) {
         return UNKNOWN_ERROR;
diff --git a/media/sfplugin/C2OMXNode.h b/media/sfplugin/C2OMXNode.h
index a81a993..b5a815e 100644
--- a/media/sfplugin/C2OMXNode.h
+++ b/media/sfplugin/C2OMXNode.h
@@ -24,8 +24,6 @@
 #include <media/OMXBuffer.h>
 #include <codec2/hidl/client.h>
 
-#include "InputSurfaceWrapper.h"
-
 namespace android {
 
 /**
@@ -35,12 +33,7 @@
  * to work in any other usage than IGraphicBufferSource.
  */
 struct C2OMXNode : public BnOMXNode {
-
-    using InputGater = InputSurfaceWrapper::InputGater;
-
-    explicit C2OMXNode(
-            const std::shared_ptr<Codec2Client::Component> &comp,
-            const std::shared_ptr<InputGater> &inputGater);
+    explicit C2OMXNode(const std::shared_ptr<Codec2Client::Component> &comp);
     ~C2OMXNode() override = default;
 
     // IOMXNode
@@ -87,7 +80,6 @@
 
 private:
     std::weak_ptr<Codec2Client::Component> mComp;
-    std::weak_ptr<InputGater> mInputGater;
     sp<IOMXBufferSource> mBufferSource;
     std::shared_ptr<C2Allocator> mAllocator;
     std::atomic_uint64_t mFrameIndex;
diff --git a/media/sfplugin/CCodec.cpp b/media/sfplugin/CCodec.cpp
index e370edd..944a8a5 100644
--- a/media/sfplugin/CCodec.cpp
+++ b/media/sfplugin/CCodec.cpp
@@ -139,8 +139,7 @@
 
     ~C2InputSurfaceWrapper() override = default;
 
-    status_t connect(const std::shared_ptr<Codec2Client::Component> &comp,
-                     const std::shared_ptr<InputGater>& /*inputGater*/) override {
+    status_t connect(const std::shared_ptr<Codec2Client::Component> &comp) override {
         if (mConnection != nullptr) {
             return ALREADY_EXISTS;
         }
@@ -192,9 +191,8 @@
     }
     ~GraphicBufferSourceWrapper() override = default;
 
-    status_t connect(const std::shared_ptr<Codec2Client::Component> &comp,
-                     const std::shared_ptr<InputGater> &inputGater) override {
-        mNode = new C2OMXNode(comp, inputGater);
+    status_t connect(const std::shared_ptr<Codec2Client::Component> &comp) override {
+        mNode = new C2OMXNode(comp);
         mNode->setFrameSize(mWidth, mHeight);
 
         // NOTE: we do not use/pass through color aspects from GraphicBufferSource as we
@@ -375,7 +373,6 @@
     sp<C2OMXNode> mNode;
     uint32_t mWidth;
     uint32_t mHeight;
-    std::shared_ptr<C2OMXNode::InputGater> mInputGater;
     Config mConfig;
 };
 
@@ -536,6 +533,10 @@
         mCodec->onWorkQueued(eos);
     }
 
+    void onOutputBuffersChanged() override {
+        mCodec->mCallback->onOutputBuffersChanged();
+    }
+
 private:
     CCodec *mCodec;
 };
@@ -1328,6 +1329,10 @@
 
     std::list<std::unique_ptr<C2Work>> flushedWork;
     c2_status_t err = comp->flush(C2Component::FLUSH_COMPONENT, &flushedWork);
+    {
+        Mutexed<std::list<std::unique_ptr<C2Work>>>::Locked queue(mWorkDoneQueue);
+        flushedWork.splice(flushedWork.end(), *queue);
+    }
     if (err != C2_OK) {
         // TODO: convert err into status_t
         mCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL);
@@ -1373,9 +1378,7 @@
 }
 
 void CCodec::signalSetParameters(const sp<AMessage> &params) {
-    sp<AMessage> msg = new AMessage(kWhatSetParameters, this);
-    msg->setMessage("params", params);
-    msg->post();
+    setParameters(params);
 }
 
 void CCodec::setParameters(const sp<AMessage> &params) {
@@ -1504,8 +1507,7 @@
         }
         case kWhatStart: {
             // C2Component::start() should return within 500ms.
-            // WORKAROUND: start sometimes takes longer than expected.
-            setDeadline(now, 2500ms, "start");
+            setDeadline(now, 550ms, "start");
             mQueuedWorkCount = 0;
             start();
             break;
@@ -1541,13 +1543,6 @@
             setInputSurface(surface);
             break;
         }
-        case kWhatSetParameters: {
-            setDeadline(now, 50ms, "setParameters");
-            sp<AMessage> params;
-            CHECK(msg->findMessage("params", &params));
-            setParameters(params);
-            break;
-        }
         case kWhatWorkDone: {
             std::unique_ptr<C2Work> work;
             size_t numDiscardedInputBuffers;
@@ -1575,7 +1570,10 @@
                 (new AMessage(kWhatWorkDone, this))->post();
             }
 
-            subQueuedWorkCount(1);
+            if (work->worklets.empty()
+                    || !(work->worklets.front()->output.flags & C2FrameData::FLAG_INCOMPLETE)) {
+                subQueuedWorkCount(1);
+            }
             // handle configuration changes in work done
             Mutexed<Config>::Locked config(mConfig);
             bool changed = false;
@@ -1617,6 +1615,7 @@
                     C2StreamColorAspectsInfo::output::PARAM_TYPE,
                     C2StreamDataSpaceInfo::output::PARAM_TYPE,
                     C2StreamHdrStaticInfo::output::PARAM_TYPE,
+                    C2StreamHdr10PlusInfo::output::PARAM_TYPE,
                     C2StreamPixelAspectRatioInfo::output::PARAM_TYPE,
                     C2StreamSurfaceScalingInfo::output::PARAM_TYPE
                 };
@@ -1700,7 +1699,7 @@
         deadline->set(std::chrono::steady_clock::now() + 3s, "eos");
     }
     // TODO: query and use input/pipeline/output delay combined
-    if (count >= 8) {
+    if (count >= 4) {
         CCodecWatchdog::getInstance()->watch(this);
         Mutexed<NamedTimePoint>::Locked deadline(mQueueDeadline);
         deadline->set(std::chrono::steady_clock::now() + 3s, "queue");
diff --git a/media/sfplugin/CCodecBufferChannel.cpp b/media/sfplugin/CCodecBufferChannel.cpp
index d6d6d68..247eb9b 100644
--- a/media/sfplugin/CCodecBufferChannel.cpp
+++ b/media/sfplugin/CCodecBufferChannel.cpp
@@ -171,7 +171,7 @@
      * index and MediaCodecBuffer object. Returns false if registration
      * fails.
      */
-    virtual bool registerBuffer(
+    virtual status_t registerBuffer(
             const std::shared_ptr<C2Buffer> &buffer,
             size_t *index,
             sp<MediaCodecBuffer> *clientBuffer) = 0;
@@ -180,7 +180,7 @@
      * Register codec specific data as a buffer to be consistent with
      * MediaCodec behavior.
      */
-    virtual bool registerCsd(
+    virtual status_t registerCsd(
             const C2StreamCsdInfo::output * /* csd */,
             size_t * /* index */,
             sp<MediaCodecBuffer> * /* clientBuffer */) = 0;
@@ -274,7 +274,7 @@
 namespace {
 
 // TODO: get this info from component
-const static size_t kMinInputBufferArraySize = 8;
+const static size_t kMinInputBufferArraySize = 4;
 const static size_t kMaxPipelineCapacity = 18;
 const static size_t kChannelOutputDelay = 0;
 const static size_t kMinOutputBufferArraySize = kMaxPipelineCapacity +
@@ -571,25 +571,33 @@
      * \param match[in]     a function to test whether the buffer matches the
      *                      criteria or not.
      * \return OK           if successful,
-     *         NO_MEMORY    if there's no available slot meets the criteria.
+     *         WOULD_BLOCK  if slots are being used,
+     *         NO_MEMORY    if no slot matches the criteria, even though it's
+     *                      available
      */
     status_t grabBuffer(
             size_t *index,
             sp<Codec2Buffer> *buffer,
             std::function<bool(const sp<Codec2Buffer> &)> match =
                 [](const sp<Codec2Buffer> &) { return true; }) {
+        // allBuffersDontMatch remains true if all buffers are available but
+        // match() returns false for every buffer.
+        bool allBuffersDontMatch = true;
         for (size_t i = 0; i < mBuffers.size(); ++i) {
-            if (!mBuffers[i].ownedByClient && mBuffers[i].compBuffer.expired()
-                    && match(mBuffers[i].clientBuffer)) {
-                mBuffers[i].ownedByClient = true;
-                *buffer = mBuffers[i].clientBuffer;
-                (*buffer)->meta()->clear();
-                (*buffer)->setRange(0, (*buffer)->capacity());
-                *index = i;
-                return OK;
+            if (!mBuffers[i].ownedByClient && mBuffers[i].compBuffer.expired()) {
+                if (match(mBuffers[i].clientBuffer)) {
+                    mBuffers[i].ownedByClient = true;
+                    *buffer = mBuffers[i].clientBuffer;
+                    (*buffer)->meta()->clear();
+                    (*buffer)->setRange(0, (*buffer)->capacity());
+                    *index = i;
+                    return OK;
+                }
+            } else {
+                allBuffersDontMatch = false;
             }
         }
-        return NO_MEMORY;
+        return allBuffersDontMatch ? NO_MEMORY : WOULD_BLOCK;
     }
 
     /**
@@ -681,6 +689,14 @@
         }
     }
 
+    void realloc(std::function<sp<Codec2Buffer>()> alloc) {
+        size_t size = mBuffers.size();
+        mBuffers.clear();
+        for (size_t i = 0; i < size; ++i) {
+            mBuffers.push_back({ alloc(), std::weak_ptr<C2Buffer>(), false });
+        }
+    }
+
 private:
     std::string mImplName; ///< name for debugging
     const char *mName; ///< C-string version of name
@@ -1073,7 +1089,7 @@
         return nullptr;
     }
 
-    bool registerBuffer(
+    status_t registerBuffer(
             const std::shared_ptr<C2Buffer> &buffer,
             size_t *index,
             sp<MediaCodecBuffer> *clientBuffer) final {
@@ -1084,22 +1100,25 @@
                 [buffer](const sp<Codec2Buffer> &clientBuffer) {
                     return clientBuffer->canCopy(buffer);
                 });
-        if (err != OK) {
+        if (err == WOULD_BLOCK) {
+            ALOGV("[%s] buffers temporarily not available", mName);
+            return err;
+        } else if (err != OK) {
             ALOGD("[%s] grabBuffer failed: %d", mName, err);
-            return false;
+            return err;
         }
         c2Buffer->setFormat(mFormat);
         if (!c2Buffer->copy(buffer)) {
             ALOGD("[%s] copy buffer failed", mName);
-            return false;
+            return WOULD_BLOCK;
         }
         submit(c2Buffer);
         *clientBuffer = c2Buffer;
         ALOGV("[%s] grabbed buffer %zu", mName, *index);
-        return true;
+        return OK;
     }
 
-    bool registerCsd(
+    status_t registerCsd(
             const C2StreamCsdInfo::output *csd,
             size_t *index,
             sp<MediaCodecBuffer> *clientBuffer) final {
@@ -1112,13 +1131,13 @@
                             && clientBuffer->capacity() >= csd->flexCount();
                 });
         if (err != OK) {
-            return false;
+            return err;
         }
         memcpy(c2Buffer->base(), csd->m.value, csd->flexCount());
         c2Buffer->setRange(0, csd->flexCount());
         c2Buffer->setFormat(mFormat);
         *clientBuffer = c2Buffer;
-        return true;
+        return OK;
     }
 
     bool releaseBuffer(
@@ -1138,6 +1157,36 @@
         mImpl.getArray(array);
     }
 
+    void realloc(const std::shared_ptr<C2Buffer> &c2buffer) {
+        std::function<sp<Codec2Buffer>()> alloc;
+        switch (c2buffer->data().type()) {
+            case C2BufferData::LINEAR: {
+                uint32_t size = kLinearBufferSize;
+                const C2ConstLinearBlock &block = c2buffer->data().linearBlocks().front();
+                if (block.size() < kMaxLinearBufferSize / 2) {
+                    size = block.size() * 2;
+                } else {
+                    size = kMaxLinearBufferSize;
+                }
+                alloc = [format = mFormat, size] {
+                    return new LocalLinearBuffer(format, new ABuffer(size));
+                };
+                break;
+            }
+
+            // TODO: add support
+            case C2BufferData::GRAPHIC:         FALLTHROUGH_INTENDED;
+
+            case C2BufferData::INVALID:         FALLTHROUGH_INTENDED;
+            case C2BufferData::LINEAR_CHUNKS:   FALLTHROUGH_INTENDED;
+            case C2BufferData::GRAPHIC_CHUNKS:  FALLTHROUGH_INTENDED;
+            default:
+                ALOGD("Unsupported type: %d", (int)c2buffer->data().type());
+                return;
+        }
+        mImpl.realloc(alloc);
+    }
+
 private:
     BuffersArrayImpl mImpl;
 };
@@ -1148,7 +1197,7 @@
         : OutputBuffers(componentName, name),
           mImpl(mName) { }
 
-    bool registerBuffer(
+    status_t registerBuffer(
             const std::shared_ptr<C2Buffer> &buffer,
             size_t *index,
             sp<MediaCodecBuffer> *clientBuffer) override {
@@ -1157,10 +1206,10 @@
         *index = mImpl.assignSlot(newBuffer);
         *clientBuffer = newBuffer;
         ALOGV("[%s] registered buffer %zu", mName, *index);
-        return true;
+        return OK;
     }
 
-    bool registerCsd(
+    status_t registerCsd(
             const C2StreamCsdInfo::output *csd,
             size_t *index,
             sp<MediaCodecBuffer> *clientBuffer) final {
@@ -1168,7 +1217,7 @@
                 mFormat, ABuffer::CreateAsCopy(csd->m.value, csd->flexCount()));
         *index = mImpl.assignSlot(newBuffer);
         *clientBuffer = newBuffer;
-        return true;
+        return OK;
     }
 
     bool releaseBuffer(
@@ -1252,21 +1301,7 @@
 
     sp<Codec2Buffer> allocateArrayBuffer() override {
         // TODO: proper max output size
-        size_t capacity = kLinearBufferSize;
-        int32_t width = 0, height = 0;
-        bool video = mFormat->findInt32(KEY_MAX_WIDTH, &width)
-                  && mFormat->findInt32(KEY_MAX_HEIGHT, &height);
-        if (!video) {
-            video = mFormat->findInt32(KEY_WIDTH, &width)
-                 && mFormat->findInt32(KEY_HEIGHT, &height);
-        }
-        if (video) {
-            // Assuming data compression ratio better than 3:1.
-            capacity = std::min(std::max(capacity, (size_t)width * height / 2),
-                                kMaxLinearBufferSize);
-        }
-        ALOGD("[%s] Using linear capacity of %zu for array buffer", mName, capacity);
-        return new LocalLinearBuffer(mFormat, new ABuffer(capacity));
+        return new LocalLinearBuffer(mFormat, new ABuffer(kLinearBufferSize));
     }
 };
 
@@ -1380,90 +1415,57 @@
 // CCodecBufferChannel::PipelineCapacity
 
 CCodecBufferChannel::PipelineCapacity::PipelineCapacity()
-      : input(0), component(0), output(0),
+      : input(0), component(0),
         mName("<UNKNOWN COMPONENT>") {
 }
 
 void CCodecBufferChannel::PipelineCapacity::initialize(
         int newInput,
         int newComponent,
-        int newOutput,
         const char* newName,
         const char* callerTag) {
     input.store(newInput, std::memory_order_relaxed);
     component.store(newComponent, std::memory_order_relaxed);
-    output.store(newOutput, std::memory_order_relaxed);
     mName = newName;
     ALOGV("[%s] %s -- PipelineCapacity::initialize(): "
           "pipeline availability initialized ==> "
-          "input = %d, component = %d, output = %d",
+          "input = %d, component = %d",
             mName, callerTag ? callerTag : "*",
-            newInput, newComponent, newOutput);
+            newInput, newComponent);
 }
 
 bool CCodecBufferChannel::PipelineCapacity::allocate(const char* callerTag) {
     int prevInput = input.fetch_sub(1, std::memory_order_relaxed);
     int prevComponent = component.fetch_sub(1, std::memory_order_relaxed);
-    int prevOutput = output.fetch_sub(1, std::memory_order_relaxed);
-    if (prevInput > 0 && prevComponent > 0 && prevOutput > 0) {
+    if (prevInput > 0 && prevComponent > 0) {
         ALOGV("[%s] %s -- PipelineCapacity::allocate() returns true: "
               "pipeline availability -1 all ==> "
-              "input = %d, component = %d, output = %d",
+              "input = %d, component = %d",
                 mName, callerTag ? callerTag : "*",
                 prevInput - 1,
-                prevComponent - 1,
-                prevOutput - 1);
+                prevComponent - 1);
         return true;
     }
     input.fetch_add(1, std::memory_order_relaxed);
     component.fetch_add(1, std::memory_order_relaxed);
-    output.fetch_add(1, std::memory_order_relaxed);
     ALOGV("[%s] %s -- PipelineCapacity::allocate() returns false: "
           "pipeline availability unchanged ==> "
-          "input = %d, component = %d, output = %d",
+          "input = %d, component = %d",
             mName, callerTag ? callerTag : "*",
             prevInput,
-            prevComponent,
-            prevOutput);
-    return false;
-}
-
-bool CCodecBufferChannel::PipelineCapacity::allocateOutput(const char* callerTag) {
-    int prevComponent = component.fetch_sub(1, std::memory_order_relaxed);
-    int prevOutput = output.fetch_sub(1, std::memory_order_relaxed);
-    if (prevComponent > 0 && prevOutput > 1) { // One output reserved for csd.
-        ALOGV("[%s] %s -- PipelineCapacity::allocateOutput() returns true: "
-              "pipeline availability -1 output and -1 component ==> "
-              "input = %d, component = %d, output = %d",
-                mName, callerTag ? callerTag : "*",
-                input.load(std::memory_order_relaxed),
-                prevComponent - 1,
-                prevOutput - 1);
-        return true;
-    }
-    component.fetch_add(1, std::memory_order_relaxed);
-    output.fetch_add(1, std::memory_order_relaxed);
-    ALOGV("[%s] %s -- PipelineCapacity::allocateOutput() returns false: "
-          "pipeline availability unchanged ==> "
-          "input = %d, component = %d, output = %d",
-            mName, callerTag ? callerTag : "*",
-            input.load(std::memory_order_relaxed),
-            prevComponent,
-            prevOutput);
+            prevComponent);
     return false;
 }
 
 void CCodecBufferChannel::PipelineCapacity::free(const char* callerTag) {
     int prevInput = input.fetch_add(1, std::memory_order_relaxed);
     int prevComponent = component.fetch_add(1, std::memory_order_relaxed);
-    int prevOutput = output.fetch_add(1, std::memory_order_relaxed);
     ALOGV("[%s] %s -- PipelineCapacity::free(): "
           "pipeline availability +1 all ==> "
-          "input = %d, component = %d, output = %d",
+          "input = %d, component = %d",
             mName, callerTag ? callerTag : "*",
             prevInput + 1,
-            prevComponent + 1,
-            prevOutput + 1);
+            prevComponent + 1);
 }
 
 int CCodecBufferChannel::PipelineCapacity::freeInputSlots(
@@ -1473,13 +1475,12 @@
                                     std::memory_order_relaxed);
     ALOGV("[%s] %s -- PipelineCapacity::freeInputSlots(%zu): "
           "pipeline availability +%zu input ==> "
-          "input = %d, component = %d, output = %d",
+          "input = %d, component = %d",
             mName, callerTag ? callerTag : "*",
             numDiscardedInputBuffers,
             numDiscardedInputBuffers,
             prevInput + static_cast<int>(numDiscardedInputBuffers),
-            component.load(std::memory_order_relaxed),
-            output.load(std::memory_order_relaxed));
+            component.load(std::memory_order_relaxed));
     return prevInput + static_cast<int>(numDiscardedInputBuffers);
 }
 
@@ -1488,43 +1489,85 @@
     int prevComponent = component.fetch_add(1, std::memory_order_relaxed);
     ALOGV("[%s] %s -- PipelineCapacity::freeComponentSlot(): "
           "pipeline availability +1 component ==> "
-          "input = %d, component = %d, output = %d",
+          "input = %d, component = %d",
             mName, callerTag ? callerTag : "*",
             input.load(std::memory_order_relaxed),
-            prevComponent + 1,
-            output.load(std::memory_order_relaxed));
+            prevComponent + 1);
     return prevComponent + 1;
 }
 
-int CCodecBufferChannel::PipelineCapacity::freeOutputSlot(
-        const char* callerTag) {
-    int prevOutput = output.fetch_add(1, std::memory_order_relaxed);
-    ALOGV("[%s] %s -- PipelineCapacity::freeOutputSlot(): "
-          "pipeline availability +1 output ==> "
-          "input = %d, component = %d, output = %d",
-            mName, callerTag ? callerTag : "*",
-            input.load(std::memory_order_relaxed),
-            component.load(std::memory_order_relaxed),
-            prevOutput + 1);
-    return prevOutput + 1;
+// CCodecBufferChannel::ReorderStash
+
+CCodecBufferChannel::ReorderStash::ReorderStash() {
+    clear();
 }
 
-// InputGater
-struct CCodecBufferChannel::InputGater : public InputSurfaceWrapper::InputGater {
-    InputGater(const std::shared_ptr<CCodecBufferChannel>& owner)
-          : mOwner(owner) {}
-    virtual bool canQueue() override {
-        std::shared_ptr<CCodecBufferChannel> owner = mOwner.lock();
-        if (!owner) {
-            return false;
-        }
-        QueueGuard guard(owner->mSync);
-        return guard.isRunning() &&
-                owner->mAvailablePipelineCapacity.allocateOutput("InputGater");
+void CCodecBufferChannel::ReorderStash::clear() {
+    mPending.clear();
+    mStash.clear();
+    mDepth = 0;
+    mKey = C2Config::ORDINAL;
+}
+
+void CCodecBufferChannel::ReorderStash::setDepth(uint32_t depth) {
+    mPending.splice(mPending.end(), mStash);
+    mDepth = depth;
+}
+void CCodecBufferChannel::ReorderStash::setKey(C2Config::ordinal_key_t key) {
+    mPending.splice(mPending.end(), mStash);
+    mKey = key;
+}
+
+bool CCodecBufferChannel::ReorderStash::pop(Entry *entry) {
+    if (mPending.empty()) {
+        return false;
     }
-private:
-    std::weak_ptr<CCodecBufferChannel> mOwner;
-};
+    entry->buffer     = mPending.front().buffer;
+    entry->timestamp  = mPending.front().timestamp;
+    entry->flags      = mPending.front().flags;
+    entry->ordinal    = mPending.front().ordinal;
+    mPending.pop_front();
+    return true;
+}
+
+void CCodecBufferChannel::ReorderStash::emplace(
+        const std::shared_ptr<C2Buffer> &buffer,
+        int64_t timestamp,
+        int32_t flags,
+        const C2WorkOrdinalStruct &ordinal) {
+    for (auto it = mStash.begin(); it != mStash.end(); ++it) {
+        if (less(ordinal, it->ordinal)) {
+            mStash.emplace(it, buffer, timestamp, flags, ordinal);
+            return;
+        }
+    }
+    mStash.emplace_back(buffer, timestamp, flags, ordinal);
+    while (!mStash.empty() && mStash.size() > mDepth) {
+        mPending.push_back(mStash.front());
+        mStash.pop_front();
+    }
+}
+
+void CCodecBufferChannel::ReorderStash::defer(
+        const CCodecBufferChannel::ReorderStash::Entry &entry) {
+    mPending.push_front(entry);
+}
+
+bool CCodecBufferChannel::ReorderStash::hasPending() const {
+    return !mPending.empty();
+}
+
+bool CCodecBufferChannel::ReorderStash::less(
+        const C2WorkOrdinalStruct &o1, const C2WorkOrdinalStruct &o2) {
+    switch (mKey) {
+        case C2Config::ORDINAL:   return o1.frameIndex < o2.frameIndex;
+        case C2Config::TIMESTAMP: return o1.timestamp < o2.timestamp;
+        case C2Config::CUSTOM:    return o1.customOrdinal < o2.customOrdinal;
+        default:
+            ALOGD("Unrecognized key; default to timestamp");
+            return o1.frameIndex < o2.frameIndex;
+    }
+}
 
 // CCodecBufferChannel
 
@@ -1536,8 +1579,7 @@
       mFirstValidFrameIndex(0u),
       mMetaMode(MODE_NONE),
       mAvailablePipelineCapacity(),
-      mInputMetEos(false),
-      mPendingEosTimestamp(INT64_MIN) {
+      mInputMetEos(false) {
     Mutexed<std::unique_ptr<InputBuffers>>::Locked buffers(mInputBuffers);
     buffers->reset(new DummyInputBuffers(""));
 }
@@ -1559,8 +1601,7 @@
         const std::shared_ptr<InputSurfaceWrapper> &surface) {
     ALOGV("[%s] setInputSurface", mName);
     mInputSurface = surface;
-    mInputGater = std::make_shared<InputGater>(shared_from_this());
-    return mInputSurface->connect(mComponent, mInputGater);
+    return mInputSurface->connect(mComponent);
 }
 
 status_t CCodecBufferChannel::signalEndOfInputStream() {
@@ -1623,13 +1664,23 @@
     std::list<std::unique_ptr<C2Work>> items;
     items.push_back(std::move(work));
     c2_status_t err = mComponent->queue(&items);
+
+    if (err == C2_OK && eos && buffer->size() > 0u) {
+        mCCodecCallback->onWorkQueued(false);
+        work.reset(new C2Work);
+        work->input.ordinal.timestamp = timeUs;
+        work->input.ordinal.frameIndex = mFrameIndex++;
+        // WORKAROUND: keep client timestamp in customOrdinal
+        work->input.ordinal.customOrdinal = timeUs;
+        work->input.buffers.clear();
+        work->input.flags = C2FrameData::FLAG_END_OF_STREAM;
+
+        items.clear();
+        items.push_back(std::move(work));
+        err = mComponent->queue(&items);
+    }
     if (err == C2_OK) {
-        if (eos && buffer->size() > 0u) {
-            mCCodecCallback->onWorkQueued(false);
-            mPendingEosTimestamp = timeUs;
-        } else {
-            mCCodecCallback->onWorkQueued(eos);
-        }
+        mCCodecCallback->onWorkQueued(eos);
 
         Mutexed<std::unique_ptr<InputBuffers>>::Locked buffers(mInputBuffers);
         bool released = (*buffers)->releaseBuffer(buffer, nullptr, true);
@@ -1679,6 +1730,7 @@
     sp<EncryptedLinearBlockBuffer> encryptedBuffer((EncryptedLinearBlockBuffer *)buffer.get());
 
     ssize_t result = -1;
+    ssize_t codecDataOffset = 0;
     if (mCrypto != nullptr) {
         ICrypto::DestinationBuffer destination;
         if (secure) {
@@ -1719,9 +1771,16 @@
 
         CasStatus status = CasStatus::OK;
         hidl_string detailedError;
+        ScramblingControl sctrl = ScramblingControl::UNSCRAMBLED;
+
+        if (key != nullptr) {
+            sctrl = (ScramblingControl)key[0];
+            // Adjust for the PES offset
+            codecDataOffset = key[2] | (key[3] << 8);
+        }
 
         auto returnVoid = mDescrambler->descramble(
-                key != NULL ? (ScramblingControl)key[0] : ScramblingControl::UNSCRAMBLED,
+                sctrl,
                 hidlSubSamples,
                 srcBuffer,
                 0,
@@ -1741,6 +1800,11 @@
             return UNKNOWN_ERROR;
         }
 
+        if (result < codecDataOffset) {
+            ALOGD("invalid codec data offset: %zd, result %zd", codecDataOffset, result);
+            return BAD_VALUE;
+        }
+
         ALOGV("[%s] descramble succeeded, %zd bytes", mName, result);
 
         if (dstBuffer.type == BufferType::SHARED_MEMORY) {
@@ -1748,7 +1812,7 @@
         }
     }
 
-    buffer->setRange(0, result);
+    buffer->setRange(codecDataOffset, result - codecDataOffset);
     return queueInputBufferInternal(buffer);
 }
 
@@ -1762,30 +1826,9 @@
 }
 
 void CCodecBufferChannel::feedInputBufferIfAvailableInternal() {
-    while ((!mInputMetEos || mPendingEosTimestamp != INT64_MIN) &&
+    while (!mInputMetEos &&
+           !mReorderStash.lock()->hasPending() &&
            mAvailablePipelineCapacity.allocate("feedInputBufferIfAvailable")) {
-        int64_t pendingEosTimestamp = mPendingEosTimestamp.exchange(INT64_MIN);
-        if (pendingEosTimestamp != INT64_MIN) {
-            mAvailablePipelineCapacity.freeInputSlots(1, "feedInputBufferIfAvailable: queue eos");
-
-            std::unique_ptr<C2Work> work(new C2Work);
-            work->input.ordinal.timestamp = pendingEosTimestamp;
-            work->input.ordinal.frameIndex = mFrameIndex++;
-            // WORKAROUND: keep client timestamp in customOrdinal
-            work->input.ordinal.customOrdinal = pendingEosTimestamp;
-            work->input.buffers.clear();
-            work->input.flags = C2FrameData::FLAG_END_OF_STREAM;
-
-            std::list<std::unique_ptr<C2Work>> items;
-            items.push_back(std::move(work));
-            if (mComponent->queue(&items) == C2_OK) {
-                mCCodecCallback->onWorkQueued(true);
-            } else {
-                ALOGD("[%s] failed to queue EOS to the component", mName);
-                mCCodecCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL);
-            }
-            continue;
-        }
         sp<MediaCodecBuffer> inBuffer;
         size_t index;
         {
@@ -1803,16 +1846,27 @@
 
 status_t CCodecBufferChannel::renderOutputBuffer(
         const sp<MediaCodecBuffer> &buffer, int64_t timestampNs) {
-    mAvailablePipelineCapacity.freeOutputSlot("renderOutputBuffer");
-    feedInputBufferIfAvailable();
+    ALOGV("[%s] renderOutputBuffer: %p", mName, buffer.get());
     std::shared_ptr<C2Buffer> c2Buffer;
+    bool released = false;
     {
         Mutexed<std::unique_ptr<OutputBuffers>>::Locked buffers(mOutputBuffers);
         if (*buffers) {
-            (*buffers)->releaseBuffer(buffer, &c2Buffer);
+            released = (*buffers)->releaseBuffer(buffer, &c2Buffer);
         }
     }
+    // NOTE: some apps try to releaseOutputBuffer() with timestamp and/or render
+    //       set to true.
+    sendOutputBuffers();
+    // input buffer feeding may have been gated by pending output buffers
+    feedInputBufferIfAvailable();
     if (!c2Buffer) {
+        if (released) {
+            ALOGD("[%s] The app is calling releaseOutputBuffer() with "
+                  "timestamp or render=true with non-video buffers. Apps should "
+                  "call releaseOutputBuffer() with render=false for those.",
+                  mName);
+        }
         return INVALID_OPERATION;
     }
 
@@ -1868,6 +1922,11 @@
         std::static_pointer_cast<const C2StreamHdrStaticInfo::output>(
                 c2Buffer->getInfo(C2StreamHdrStaticInfo::output::PARAM_TYPE));
 
+    // HDR10 plus info
+    std::shared_ptr<const C2StreamHdr10PlusInfo::output> hdr10PlusInfo =
+        std::static_pointer_cast<const C2StreamHdr10PlusInfo::output>(
+                c2Buffer->getInfo(C2StreamHdr10PlusInfo::output::PARAM_TYPE));
+
     {
         Mutexed<OutputSurface>::Locked output(mOutputSurface);
         if (output->surface == nullptr) {
@@ -1895,33 +1954,41 @@
             videoScalingMode,
             transform,
             Fence::NO_FENCE, 0);
-    if (hdrStaticInfo) {
-        struct android_smpte2086_metadata smpte2086_meta = {
-            .displayPrimaryRed = {
-                hdrStaticInfo->mastering.red.x, hdrStaticInfo->mastering.red.y
-            },
-            .displayPrimaryGreen = {
-                hdrStaticInfo->mastering.green.x, hdrStaticInfo->mastering.green.y
-            },
-            .displayPrimaryBlue = {
-                hdrStaticInfo->mastering.blue.x, hdrStaticInfo->mastering.blue.y
-            },
-            .whitePoint = {
-                hdrStaticInfo->mastering.white.x, hdrStaticInfo->mastering.white.y
-            },
-            .maxLuminance = hdrStaticInfo->mastering.maxLuminance,
-            .minLuminance = hdrStaticInfo->mastering.minLuminance,
-        };
-
-        struct android_cta861_3_metadata cta861_meta = {
-            .maxContentLightLevel = hdrStaticInfo->maxCll,
-            .maxFrameAverageLightLevel = hdrStaticInfo->maxFall,
-        };
-
+    if (hdrStaticInfo || hdr10PlusInfo) {
         HdrMetadata hdr;
-        hdr.validTypes = HdrMetadata::SMPTE2086 | HdrMetadata::CTA861_3;
-        hdr.smpte2086 = smpte2086_meta;
-        hdr.cta8613 = cta861_meta;
+        if (hdrStaticInfo) {
+            struct android_smpte2086_metadata smpte2086_meta = {
+                .displayPrimaryRed = {
+                    hdrStaticInfo->mastering.red.x, hdrStaticInfo->mastering.red.y
+                },
+                .displayPrimaryGreen = {
+                    hdrStaticInfo->mastering.green.x, hdrStaticInfo->mastering.green.y
+                },
+                .displayPrimaryBlue = {
+                    hdrStaticInfo->mastering.blue.x, hdrStaticInfo->mastering.blue.y
+                },
+                .whitePoint = {
+                    hdrStaticInfo->mastering.white.x, hdrStaticInfo->mastering.white.y
+                },
+                .maxLuminance = hdrStaticInfo->mastering.maxLuminance,
+                .minLuminance = hdrStaticInfo->mastering.minLuminance,
+            };
+
+            struct android_cta861_3_metadata cta861_meta = {
+                .maxContentLightLevel = hdrStaticInfo->maxCll,
+                .maxFrameAverageLightLevel = hdrStaticInfo->maxFall,
+            };
+
+            hdr.validTypes = HdrMetadata::SMPTE2086 | HdrMetadata::CTA861_3;
+            hdr.smpte2086 = smpte2086_meta;
+            hdr.cta8613 = cta861_meta;
+        }
+        if (hdr10PlusInfo) {
+            hdr.validTypes |= HdrMetadata::HDR10PLUS;
+            hdr.hdr10plus.assign(
+                    hdr10PlusInfo->m.value,
+                    hdr10PlusInfo->m.value + hdr10PlusInfo->flexCount());
+        }
         qbi.setHdrMetadata(hdr);
     }
     // we don't have dirty regions
@@ -1957,11 +2024,12 @@
         if (*buffers && (*buffers)->releaseBuffer(buffer, nullptr)) {
             buffers.unlock();
             released = true;
-            mAvailablePipelineCapacity.freeOutputSlot("discardBuffer");
         }
     }
-    feedInputBufferIfAvailable();
-    if (!released) {
+    if (released) {
+        sendOutputBuffers();
+        feedInputBufferIfAvailable();
+    } else {
         ALOGD("[%s] MediaCodec discarded an unknown buffer", mName);
     }
     return OK;
@@ -1993,38 +2061,36 @@
         const sp<AMessage> &inputFormat, const sp<AMessage> &outputFormat) {
     C2StreamBufferTypeSetting::input iStreamFormat(0u);
     C2StreamBufferTypeSetting::output oStreamFormat(0u);
+    C2PortReorderBufferDepthTuning::output reorderDepth;
+    C2PortReorderKeySetting::output reorderKey;
     c2_status_t err = mComponent->query(
-            { &iStreamFormat, &oStreamFormat },
+            {
+                &iStreamFormat,
+                &oStreamFormat,
+                &reorderDepth,
+                &reorderKey,
+            },
             {},
             C2_DONT_BLOCK,
             nullptr);
-    if (err != C2_OK) {
+    if (err == C2_BAD_INDEX) {
+        if (!iStreamFormat || !oStreamFormat) {
+            return UNKNOWN_ERROR;
+        }
+    } else if (err != C2_OK) {
         return UNKNOWN_ERROR;
     }
 
-    // Query delays
-    C2PortRequestedDelayTuning::input inputDelay;
-    C2PortRequestedDelayTuning::output outputDelay;
-    C2RequestedPipelineDelayTuning pipelineDelay;
-#if 0
-    err = mComponent->query(
-            { &inputDelay, &pipelineDelay, &outputDelay },
-            {},
-            C2_DONT_BLOCK,
-            nullptr);
-    mAvailablePipelineCapacity.initialize(
-            inputDelay,
-            inputDelay + pipelineDelay,
-            inputDelay + pipelineDelay + outputDelay,
-            mName);
-#else
-    mAvailablePipelineCapacity.initialize(
-            kMinInputBufferArraySize,
-            kMaxPipelineCapacity,
-            kMinOutputBufferArraySize,
-            mName);
-#endif
-
+    {
+        Mutexed<ReorderStash>::Locked reorder(mReorderStash);
+        reorder->clear();
+        if (reorderDepth) {
+            reorder->setDepth(reorderDepth.value);
+        }
+        if (reorderKey) {
+            reorder->setKey(reorderKey.value);
+        }
+    }
     // TODO: get this from input format
     bool secure = mComponent->getName().find(".secure") != std::string::npos;
 
@@ -2173,7 +2239,7 @@
                                     C2_DONT_BLOCK,
                                     &params);
             if ((err != C2_OK && err != C2_BAD_INDEX) || params.size() != 1) {
-                ALOGD("[%s] Query input allocators returned %zu params => %s (%u)",
+                ALOGD("[%s] Query output allocators returned %zu params => %s (%u)",
                         mName, params.size(), asString(err), err);
             } else if (err == C2_OK && params.size() == 1) {
                 C2PortAllocatorsTuning::output *outputAllocators =
@@ -2191,11 +2257,39 @@
                 }
             }
 
-            // use bufferqueue if outputting to a surface
-            if (pools->outputAllocatorId == C2PlatformAllocatorStore::GRALLOC
-                    && outputSurface
-                    && ((poolMask >> C2PlatformAllocatorStore::BUFFERQUEUE) & 1)) {
-                pools->outputAllocatorId = C2PlatformAllocatorStore::BUFFERQUEUE;
+            // use bufferqueue if outputting to a surface.
+            // query C2PortSurfaceAllocatorTuning::output from component, or use default allocator
+            // if unsuccessful.
+            if (outputSurface) {
+                params.clear();
+                err = mComponent->query({ },
+                                        { C2PortSurfaceAllocatorTuning::output::PARAM_TYPE },
+                                        C2_DONT_BLOCK,
+                                        &params);
+                if ((err != C2_OK && err != C2_BAD_INDEX) || params.size() != 1) {
+                    ALOGD("[%s] Query output surface allocator returned %zu params => %s (%u)",
+                            mName, params.size(), asString(err), err);
+                } else if (err == C2_OK && params.size() == 1) {
+                    C2PortSurfaceAllocatorTuning::output *surfaceAllocator =
+                        C2PortSurfaceAllocatorTuning::output::From(params[0].get());
+                    if (surfaceAllocator) {
+                        std::shared_ptr<C2Allocator> allocator;
+                        // verify allocator IDs and resolve default allocator
+                        allocatorStore->fetchAllocator(surfaceAllocator->value, &allocator);
+                        if (allocator) {
+                            pools->outputAllocatorId = allocator->getId();
+                        } else {
+                            ALOGD("[%s] component requested invalid surface output allocator ID %u",
+                                    mName, surfaceAllocator->value);
+                            err = C2_BAD_VALUE;
+                        }
+                    }
+                }
+                if (pools->outputAllocatorId == C2PlatformAllocatorStore::GRALLOC
+                        && err != C2_OK
+                        && ((poolMask >> C2PlatformAllocatorStore::BUFFERQUEUE) & 1)) {
+                    pools->outputAllocatorId = C2PlatformAllocatorStore::BUFFERQUEUE;
+                }
             }
 
             if ((poolMask >> pools->outputAllocatorId) & 1) {
@@ -2248,7 +2342,8 @@
                     outputGeneration);
         }
 
-        if (oStreamFormat.value == C2BufferData::LINEAR) {
+        if (oStreamFormat.value == C2BufferData::LINEAR
+                && mComponentName.find("c2.qti.") == std::string::npos) {
             // WORKAROUND: if we're using early CSD workaround we convert to
             //             array mode, to appease apps assuming the output
             //             buffers to be of the same size.
@@ -2275,8 +2370,34 @@
         }
     }
 
+    // Set up pipeline control. This has to be done after mInputBuffers and
+    // mOutputBuffers are initialized to make sure that lingering callbacks
+    // about buffers from the previous generation do not interfere with the
+    // newly initialized pipeline capacity.
+
+    // Query delays
+    C2PortRequestedDelayTuning::input inputDelay;
+    C2PortRequestedDelayTuning::output outputDelay;
+    C2RequestedPipelineDelayTuning pipelineDelay;
+#if 0
+    err = mComponent->query(
+            { &inputDelay, &pipelineDelay, &outputDelay },
+            {},
+            C2_DONT_BLOCK,
+            nullptr);
+    mAvailablePipelineCapacity.initialize(
+            inputDelay,
+            inputDelay + pipelineDelay,
+            inputDelay + pipelineDelay + outputDelay,
+            mName);
+#else
+    mAvailablePipelineCapacity.initialize(
+            kMinInputBufferArraySize,
+            kMaxPipelineCapacity,
+            mName);
+#endif
+
     mInputMetEos = false;
-    mPendingEosTimestamp = INT64_MIN;
     mSync.start();
     return OK;
 }
@@ -2326,7 +2447,8 @@
                     ALOGD("[%s] buffer capacity too small for the config (%zu < %zu)",
                             mName, buffer->capacity(), config->size());
                 }
-            } else if (oStreamFormat.value == C2BufferData::LINEAR && i == 0) {
+            } else if (oStreamFormat.value == C2BufferData::LINEAR && i == 0
+                    && mComponentName.find("c2.qti.") == std::string::npos) {
                 // WORKAROUND: Some apps expect CSD available without queueing
                 //             any input. Queue an empty buffer to get the CSD.
                 buffer->setRange(0, 0);
@@ -2349,7 +2471,6 @@
     for (const sp<MediaCodecBuffer> &buffer : toBeQueued) {
         if (queueInputBufferInternal(buffer) != OK) {
             mAvailablePipelineCapacity.freeComponentSlot("requestInitialInputBuffers");
-            mAvailablePipelineCapacity.freeOutputSlot("requestInitialInputBuffers");
         }
     }
     return OK;
@@ -2357,11 +2478,10 @@
 
 void CCodecBufferChannel::stop() {
     mSync.stop();
-    mFirstValidFrameIndex = mFrameIndex.load();
+    mFirstValidFrameIndex = mFrameIndex.load(std::memory_order_relaxed);
     if (mInputSurface != nullptr) {
         mInputSurface.reset();
     }
-    mInputGater.reset();
 }
 
 void CCodecBufferChannel::flush(const std::list<std::unique_ptr<C2Work>> &flushedWork) {
@@ -2401,23 +2521,11 @@
         std::unique_ptr<C2Work> work, const sp<AMessage> &outputFormat,
         const C2StreamInitDataInfo::output *initData,
         size_t numDiscardedInputBuffers) {
-    if (work->result == C2_NOT_FOUND) {
-        // TODO: Define what flushed work's result is.
-        ALOGD("[%s] flushed work; ignored.", mName);
-        return;
-    }
-    if ((work->input.ordinal.frameIndex - mFirstValidFrameIndex.load()).peek() < 0) {
-        // Discard frames from previous generation.
-        ALOGD("[%s] Discard frames from previous generation.", mName);
-        return;
-    }
-
-    mAvailablePipelineCapacity.freeInputSlots(numDiscardedInputBuffers, "onWorkDone");
-    mAvailablePipelineCapacity.freeComponentSlot("onWorkDone");
     if (handleWork(std::move(work), outputFormat, initData)) {
-        mAvailablePipelineCapacity.freeOutputSlot("onWorkDone");
+        mAvailablePipelineCapacity.freeInputSlots(numDiscardedInputBuffers,
+                                                  "onWorkDone");
+        feedInputBufferIfAvailable();
     }
-    feedInputBufferIfAvailable();
 }
 
 void CCodecBufferChannel::onInputBufferDone(
@@ -2426,9 +2534,11 @@
     {
         Mutexed<std::unique_ptr<InputBuffers>>::Locked buffers(mInputBuffers);
         newInputSlotAvailable = (*buffers)->expireComponentBuffer(buffer);
+        if (newInputSlotAvailable) {
+            mAvailablePipelineCapacity.freeInputSlots(1, "onInputBufferDone");
+        }
     }
     if (newInputSlotAvailable) {
-        mAvailablePipelineCapacity.freeInputSlots(1, "onInputBufferDone");
         feedInputBufferIfAvailable();
     }
 }
@@ -2437,6 +2547,23 @@
         std::unique_ptr<C2Work> work,
         const sp<AMessage> &outputFormat,
         const C2StreamInitDataInfo::output *initData) {
+    if ((work->input.ordinal.frameIndex - mFirstValidFrameIndex.load()).peek() < 0) {
+        // Discard frames from previous generation.
+        ALOGD("[%s] Discard frames from previous generation.", mName);
+        return false;
+    }
+
+    if (work->worklets.size() != 1u
+            || !work->worklets.front()
+            || !(work->worklets.front()->output.flags & C2FrameData::FLAG_INCOMPLETE)) {
+        mAvailablePipelineCapacity.freeComponentSlot("handleWork");
+    }
+
+    if (work->result == C2_NOT_FOUND) {
+        ALOGD("[%s] flushed work; ignored.", mName);
+        return true;
+    }
+
     if (work->result != C2_OK) {
         ALOGD("[%s] work failed to complete: %d", mName, work->result);
         mCCodecCallback->onError(work->result, ACTION_CODE_FATAL);
@@ -2452,6 +2579,7 @@
     }
 
     const std::unique_ptr<C2Worklet> &worklet = work->worklets.front();
+
     std::shared_ptr<C2Buffer> buffer;
     // NOTE: MediaCodec usage supposedly have only one output stream.
     if (worklet->output.buffers.size() > 1u) {
@@ -2466,6 +2594,40 @@
         }
     }
 
+    while (!worklet->output.configUpdate.empty()) {
+        std::unique_ptr<C2Param> param;
+        worklet->output.configUpdate.back().swap(param);
+        worklet->output.configUpdate.pop_back();
+        switch (param->coreIndex().coreIndex()) {
+            case C2PortReorderBufferDepthTuning::CORE_INDEX: {
+                C2PortReorderBufferDepthTuning::output reorderDepth;
+                if (reorderDepth.updateFrom(*param)) {
+                    mReorderStash.lock()->setDepth(reorderDepth.value);
+                    ALOGV("[%s] onWorkDone: updated reorder depth to %u",
+                          mName, reorderDepth.value);
+                } else {
+                    ALOGD("[%s] onWorkDone: failed to read reorder depth", mName);
+                }
+                break;
+            }
+            case C2PortReorderKeySetting::CORE_INDEX: {
+                C2PortReorderKeySetting::output reorderKey;
+                if (reorderKey.updateFrom(*param)) {
+                    mReorderStash.lock()->setKey(reorderKey.value);
+                    ALOGV("[%s] onWorkDone: updated reorder key to %u",
+                          mName, reorderKey.value);
+                } else {
+                    ALOGD("[%s] onWorkDone: failed to read reorder key", mName);
+                }
+                break;
+            }
+            default:
+                ALOGV("[%s] onWorkDone: unrecognized config update (%08X)",
+                      mName, param->index());
+                break;
+        }
+    }
+
     if (outputFormat != nullptr) {
         Mutexed<std::unique_ptr<OutputBuffers>>::Locked buffers(mOutputBuffers);
         ALOGD("[%s] onWorkDone: output format changed to %s",
@@ -2490,7 +2652,6 @@
         ALOGV("[%s] onWorkDone: output EOS", mName);
     }
 
-    bool feedNeeded = true;
     sp<MediaCodecBuffer> outBuffer;
     size_t index;
 
@@ -2512,7 +2673,7 @@
 
     if (initData != nullptr) {
         Mutexed<std::unique_ptr<OutputBuffers>>::Locked buffers(mOutputBuffers);
-        if ((*buffers)->registerCsd(initData, &index, &outBuffer)) {
+        if ((*buffers)->registerCsd(initData, &index, &outBuffer) == OK) {
             outBuffer->meta()->setInt64("timeUs", timestamp.peek());
             outBuffer->meta()->setInt32("flags", MediaCodec::BUFFER_FLAG_CODECCONFIG);
             ALOGV("[%s] onWorkDone: csd index = %zu [%p]", mName, index, outBuffer.get());
@@ -2520,7 +2681,6 @@
             buffers.unlock();
             mCallback->onOutputBufferAvailable(index, outBuffer);
             buffers.lock();
-            feedNeeded = false;
         } else {
             ALOGD("[%s] onWorkDone: unable to register csd", mName);
             buffers.unlock();
@@ -2533,7 +2693,7 @@
     if (!buffer && !flags) {
         ALOGV("[%s] onWorkDone: Not reporting output buffer (%lld)",
               mName, work->input.ordinal.frameIndex.peekull());
-        return feedNeeded;
+        return true;
     }
 
     if (buffer) {
@@ -2552,23 +2712,53 @@
     }
 
     {
-        Mutexed<std::unique_ptr<OutputBuffers>>::Locked buffers(mOutputBuffers);
-        if (!(*buffers)->registerBuffer(buffer, &index, &outBuffer)) {
-            ALOGD("[%s] onWorkDone: unable to register output buffer", mName);
-            // TODO
-            // buffers.unlock();
-            // mCCodecCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL);
-            // buffers.lock();
-            return false;
+        Mutexed<ReorderStash>::Locked reorder(mReorderStash);
+        reorder->emplace(buffer, timestamp.peek(), flags, worklet->output.ordinal);
+        if (flags & MediaCodec::BUFFER_FLAG_EOS) {
+            // Flush reorder stash
+            reorder->setDepth(0);
         }
     }
+    sendOutputBuffers();
+    return true;
+}
 
-    outBuffer->meta()->setInt64("timeUs", timestamp.peek());
-    outBuffer->meta()->setInt32("flags", flags);
-    ALOGV("[%s] onWorkDone: out buffer index = %zu [%p] => %p + %zu",
-            mName, index, outBuffer.get(), outBuffer->data(), outBuffer->size());
-    mCallback->onOutputBufferAvailable(index, outBuffer);
-    return false;
+void CCodecBufferChannel::sendOutputBuffers() {
+    ReorderStash::Entry entry;
+    sp<MediaCodecBuffer> outBuffer;
+    size_t index;
+
+    while (true) {
+        {
+            Mutexed<ReorderStash>::Locked reorder(mReorderStash);
+            if (!reorder->hasPending()) {
+                break;
+            }
+            if (!reorder->pop(&entry)) {
+                break;
+            }
+        }
+        Mutexed<std::unique_ptr<OutputBuffers>>::Locked buffers(mOutputBuffers);
+        status_t err = (*buffers)->registerBuffer(entry.buffer, &index, &outBuffer);
+        if (err != OK) {
+            if (err != WOULD_BLOCK) {
+                OutputBuffersArray *array = (OutputBuffersArray *)buffers->get();
+                array->realloc(entry.buffer);
+                mCCodecCallback->onOutputBuffersChanged();
+            }
+            buffers.unlock();
+            ALOGV("[%s] sendOutputBuffers: unable to register output buffer", mName);
+            mReorderStash.lock()->defer(entry);
+            return;
+        }
+        buffers.unlock();
+
+        outBuffer->meta()->setInt64("timeUs", entry.timestamp);
+        outBuffer->meta()->setInt32("flags", entry.flags);
+        ALOGV("[%s] sendOutputBuffers: out buffer index = %zu [%p] => %p + %zu",
+                mName, index, outBuffer.get(), outBuffer->data(), outBuffer->size());
+        mCallback->onOutputBufferAvailable(index, outBuffer);
+    }
 }
 
 status_t CCodecBufferChannel::setSurface(const sp<Surface> &newSurface) {
diff --git a/media/sfplugin/CCodecBufferChannel.h b/media/sfplugin/CCodecBufferChannel.h
index 3ef58be..431baaa 100644
--- a/media/sfplugin/CCodecBufferChannel.h
+++ b/media/sfplugin/CCodecBufferChannel.h
@@ -43,6 +43,7 @@
     virtual void onError(status_t err, enum ActionCode actionCode) = 0;
     virtual void onOutputFramesRendered(int64_t mediaTimeUs, nsecs_t renderTimeNs) = 0;
     virtual void onWorkQueued(bool eos) = 0;
+    virtual void onOutputBuffersChanged() = 0;
 };
 
 /**
@@ -217,6 +218,7 @@
     bool handleWork(
             std::unique_ptr<C2Work> work, const sp<AMessage> &outputFormat,
             const C2StreamInitDataInfo::output *initData);
+    void sendOutputBuffers();
 
     QueueSync mSync;
     sp<MemoryDealer> mDealer;
@@ -271,56 +273,36 @@
     //    CCodecBufferChannel whose outputs have not been returned from the
     //    component (by calling onWorkDone()) does not exceed a certain limit.
     //    (Let us call this the "component" capacity.)
-    // 3. The number of work items that have been received by
-    //    CCodecBufferChannel whose outputs have not been released by the app
-    //    (either by calling discardBuffer() on an output buffer or calling
-    //    renderOutputBuffer()) does not exceed a certain limit. (Let us call
-    //    this the "output" capacity.)
     //
     // These three criteria guarantee that a new input buffer that arrives from
     // the invocation of onInputBufferAvailable() will not
     // 1. overload CCodecBufferChannel's input buffers;
     // 2. overload the component; or
-    // 3. overload CCodecBufferChannel's output buffers if the component
-    //    finishes all the pending work right away.
     //
     struct PipelineCapacity {
         // The number of available input capacity.
         std::atomic_int input;
         // The number of available component capacity.
         std::atomic_int component;
-        // The number of available output capacity.
-        std::atomic_int output;
 
         PipelineCapacity();
-        // Set the values of #component and #output.
-        void initialize(int newInput, int newComponent, int newOutput,
+        // Set the values of #input and #component.
+        void initialize(int newInput, int newComponent,
                         const char* newName = "<UNKNOWN COMPONENT>",
                         const char* callerTag = nullptr);
 
-        // Return true and decrease #input, #component and #output by one if
+        // Return true and decrease #input and #component by one if
         // they are all greater than zero; return false otherwise.
         //
         // callerTag is used for logging only.
         //
         // allocate() is called by CCodecBufferChannel to check whether it can
         // receive another input buffer. If the return value is true,
-        // onInputBufferAvailable() can (and will) be called afterwards.
+        // onInputBufferAvailable() and onOutputBufferAvailable() can be called
+        // afterwards.
         bool allocate(const char* callerTag = nullptr);
 
-        // Return true and decrease #component and #output by one if they are
-        // all greater than zero; return false otherwise.
-        //
-        // callerTag is used for logging only.
-        //
-        // allocateOutput() is called by CCodecBufferChannel::InputGater to
-        // check whether the component can accept a queue operation. This is
-        // used when the input comes from an input surface rather than from
-        // queueInputBuffer(). Calling allocateOutput() is similar to calling
-        // allocate() when the input capacity is infinite.
-        bool allocateOutput(const char* callerTag = nullptr);
-
-        // Increase #input, #component and #output by one.
+        // Increase #input and #component by one.
         //
         // callerTag is used for logging only.
         //
@@ -347,30 +329,57 @@
         // onWorkDone() is called.
         int freeComponentSlot(const char* callerTag = nullptr);
 
-        // Increase #output by one and return the updated value.
-        //
-        // callerTag is used for logging only.
-        //
-        // freeOutputSlot() is called by CCodecBufferChannel when
-        // discardBuffer() is called on an output buffer or when
-        // renderOutputBuffer() is called.
-        int freeOutputSlot(const char* callerTag = nullptr);
-
     private:
         // Component name. Used for logging.
         const char* mName;
     };
     PipelineCapacity mAvailablePipelineCapacity;
 
+    class ReorderStash {
+    public:
+        struct Entry {
+            inline Entry() : buffer(nullptr), timestamp(0), flags(0), ordinal({0, 0, 0}) {}
+            inline Entry(
+                    const std::shared_ptr<C2Buffer> &b,
+                    int64_t t,
+                    int32_t f,
+                    const C2WorkOrdinalStruct &o)
+                : buffer(b), timestamp(t), flags(f), ordinal(o) {}
+            std::shared_ptr<C2Buffer> buffer;
+            int64_t timestamp;
+            int32_t flags;
+            C2WorkOrdinalStruct ordinal;
+        };
+
+        ReorderStash();
+
+        void clear();
+        void setDepth(uint32_t depth);
+        void setKey(C2Config::ordinal_key_t key);
+        bool pop(Entry *entry);
+        void emplace(
+                const std::shared_ptr<C2Buffer> &buffer,
+                int64_t timestamp,
+                int32_t flags,
+                const C2WorkOrdinalStruct &ordinal);
+        void defer(const Entry &entry);
+        bool hasPending() const;
+
+    private:
+        std::list<Entry> mPending;
+        std::list<Entry> mStash;
+        uint32_t mDepth;
+        C2Config::ordinal_key_t mKey;
+
+        bool less(const C2WorkOrdinalStruct &o1, const C2WorkOrdinalStruct &o2);
+    };
+    Mutexed<ReorderStash> mReorderStash;
+
     std::atomic_bool mInputMetEos;
-    std::atomic_int64_t mPendingEosTimestamp;
 
     inline bool hasCryptoOrDescrambler() {
-        return mCrypto != NULL || mDescrambler != NULL;
+        return mCrypto != nullptr || mDescrambler != nullptr;
     }
-
-    struct InputGater;
-    std::shared_ptr<InputGater> mInputGater;
 };
 
 // Conversion of a c2_status_t value to a status_t value may depend on the
diff --git a/media/sfplugin/CCodecConfig.cpp b/media/sfplugin/CCodecConfig.cpp
index 8dbfd0e..ef02e74 100644
--- a/media/sfplugin/CCodecConfig.cpp
+++ b/media/sfplugin/CCodecConfig.cpp
@@ -570,6 +570,12 @@
     add(ConfigMapper("csd-0",           C2_PARAMKEY_INIT_DATA,       "value")
         .limitTo(D::OUTPUT & D::READ));
 
+    add(ConfigMapper(KEY_HDR10_PLUS_INFO, C2_PARAMKEY_INPUT_HDR10_PLUS_INFO, "value")
+        .limitTo(D::VIDEO & D::PARAM & D::INPUT));
+
+    add(ConfigMapper(KEY_HDR10_PLUS_INFO, C2_PARAMKEY_OUTPUT_HDR10_PLUS_INFO, "value")
+        .limitTo(D::VIDEO & D::OUTPUT));
+
     add(ConfigMapper(C2_PARAMKEY_TEMPORAL_LAYERING, C2_PARAMKEY_TEMPORAL_LAYERING, "")
         .limitTo(D::ENCODER & D::VIDEO & D::OUTPUT));
 
@@ -624,7 +630,23 @@
         .limitTo(D::AUDIO & D::CODED));
 
     add(ConfigMapper(KEY_PCM_ENCODING,  C2_PARAMKEY_PCM_ENCODING,       "value")
-        .limitTo(D::AUDIO));
+        .limitTo(D::AUDIO)
+        .withMappers([](C2Value v) -> C2Value {
+            int32_t value;
+            C2Config::pcm_encoding_t to;
+            if (v.get(&value) && C2Mapper::map(value, &to)) {
+                return to;
+            }
+            return C2Value();
+        }, [](C2Value v) -> C2Value {
+            C2Config::pcm_encoding_t value;
+            int32_t to;
+            using C2ValueType=typename _c2_reduce_enum_to_underlying_type<decltype(value)>::type;
+            if (v.get((C2ValueType*)&value) && C2Mapper::map(value, &to)) {
+                return to;
+            }
+            return C2Value();
+        }));
 
     add(ConfigMapper(KEY_IS_ADTS, C2_PARAMKEY_AAC_PACKAGING, "value")
         .limitTo(D::AUDIO & D::CODED)
diff --git a/media/sfplugin/Codec2Buffer.cpp b/media/sfplugin/Codec2Buffer.cpp
index df87a67..597e8f3 100644
--- a/media/sfplugin/Codec2Buffer.cpp
+++ b/media/sfplugin/Codec2Buffer.cpp
@@ -109,9 +109,11 @@
 
 // DummyContainerBuffer
 
+static uint8_t sDummyByte[1] = { 0 };
+
 DummyContainerBuffer::DummyContainerBuffer(
         const sp<AMessage> &format, const std::shared_ptr<C2Buffer> &buffer)
-    : Codec2Buffer(format, new ABuffer(nullptr, 1)),
+    : Codec2Buffer(format, new ABuffer(sDummyByte, 1)),
       mBufferRef(buffer) {
     setRange(0, buffer ? 1 : 0);
 }
@@ -296,7 +298,7 @@
                             break;
                         }
                     }
-                    // fall through if we could not wrap
+                    [[fallthrough]];
 
                     case COLOR_FormatYUV420Planar:
                     case COLOR_FormatYUV420PackedPlanar:
@@ -562,7 +564,7 @@
         const std::shared_ptr<C2Allocator> &alloc)
     : Codec2Buffer(format, new ABuffer(sizeof(VideoNativeMetadata))),
       mAlloc(alloc) {
-    ((VideoNativeMetadata *)base())->pBuffer = 0;
+    ((VideoNativeMetadata *)base())->pBuffer = nullptr;
 }
 
 std::shared_ptr<C2Buffer> GraphicMetadataBuffer::asC2Buffer() {
diff --git a/media/sfplugin/Codec2InfoBuilder.cpp b/media/sfplugin/Codec2InfoBuilder.cpp
index d883d46..4a6d672 100644
--- a/media/sfplugin/Codec2InfoBuilder.cpp
+++ b/media/sfplugin/Codec2InfoBuilder.cpp
@@ -74,11 +74,11 @@
 constexpr OMX_U32 kMaxIndicesToCheck = 32;
 
 status_t queryOmxCapabilities(
-        const char* name, const char* mime, bool isEncoder,
+        const char* name, const char* mediaType, bool isEncoder,
         MediaCodecInfo::CapabilitiesWriter* caps) {
 
-    const char *role = GetComponentRole(isEncoder, mime);
-    if (role == NULL) {
+    const char *role = GetComponentRole(isEncoder, mediaType);
+    if (role == nullptr) {
         return BAD_VALUE;
     }
 
@@ -129,8 +129,8 @@
         return err;
     }
 
-    bool isVideo = hasPrefix(mime, "video/") == 0;
-    bool isImage = hasPrefix(mime, "image/") == 0;
+    bool isVideo = hasPrefix(mediaType, "video/") == 0;
+    bool isImage = hasPrefix(mediaType, "image/") == 0;
 
     if (isVideo || isImage) {
         OMX_VIDEO_PARAM_PROFILELEVELTYPE param;
@@ -150,7 +150,7 @@
             // AVC components may not list the constrained profiles explicitly, but
             // decoders that support a profile also support its constrained version.
             // Encoders must explicitly support constrained profiles.
-            if (!isEncoder && strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC) == 0) {
+            if (!isEncoder && strcasecmp(mediaType, MEDIA_MIMETYPE_VIDEO_AVC) == 0) {
                 if (param.eProfile == OMX_VIDEO_AVCProfileHigh) {
                     caps->addProfileLevel(OMX_VIDEO_AVCProfileConstrainedHigh, param.eLevel);
                 } else if (param.eProfile == OMX_VIDEO_AVCProfileBaseline) {
@@ -194,7 +194,7 @@
                         asString(portFormat.eColorFormat), portFormat.eColorFormat);
             }
         }
-    } else if (strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC) == 0) {
+    } else if (strcasecmp(mediaType, MEDIA_MIMETYPE_AUDIO_AAC) == 0) {
         // More audio codecs if they have profiles.
         OMX_AUDIO_PARAM_ANDROID_PROFILETYPE param;
         InitOMXParams(&param);
@@ -225,18 +225,18 @@
     }
 
     if (isVideo && !isEncoder) {
-        native_handle_t *sidebandHandle = NULL;
+        native_handle_t *sidebandHandle = nullptr;
         if (omxNode->configureVideoTunnelMode(
                 kPortIndexOutput, OMX_TRUE, 0, &sidebandHandle) == OK) {
             // tunneled playback includes adaptive playback
-            caps->addFlags(MediaCodecInfo::Capabilities::kFlagSupportsAdaptivePlayback
-                    | MediaCodecInfo::Capabilities::kFlagSupportsTunneledPlayback);
+            caps->addDetail(MediaCodecInfo::Capabilities::FEATURE_ADAPTIVE_PLAYBACK, 1);
+            caps->addDetail(MediaCodecInfo::Capabilities::FEATURE_TUNNELED_PLAYBACK, 1);
         } else if (omxNode->setPortMode(
                 kPortIndexOutput, IOMX::kPortModeDynamicANWBuffer) == OK ||
                 omxNode->prepareForAdaptivePlayback(
                 kPortIndexOutput, OMX_TRUE,
                 1280 /* width */, 720 /* height */) == OK) {
-            caps->addFlags(MediaCodecInfo::Capabilities::kFlagSupportsAdaptivePlayback);
+            caps->addDetail(MediaCodecInfo::Capabilities::FEATURE_ADAPTIVE_PLAYBACK, 1);
         }
     }
 
@@ -248,7 +248,7 @@
         if (omxNode->getConfig(
                 (OMX_INDEXTYPE)OMX_IndexConfigAndroidIntraRefresh,
                 &params, sizeof(params)) == OK) {
-            caps->addFlags(MediaCodecInfo::Capabilities::kFlagSupportsIntraRefresh);
+            caps->addDetail(MediaCodecInfo::Capabilities::FEATURE_INTRA_REFRESH, 1);
         }
     }
 
@@ -271,12 +271,25 @@
                 writer->addMediaCodecInfo();
         info->setName(name.c_str());
         info->setOwner("default");
-        info->setEncoder(encoder);
+        typename std::underlying_type<MediaCodecInfo::Attributes>::type attrs = 0;
+        if (encoder) {
+            attrs |= MediaCodecInfo::kFlagIsEncoder;
+        }
+        // NOTE: we don't support software-only codecs in OMX
+        if (!hasPrefix(name, "OMX.google.")) {
+            attrs |= MediaCodecInfo::kFlagIsVendor;
+            if (properties.quirkSet.find("attribute::software-codec")
+                    == properties.quirkSet.end()) {
+                attrs |= MediaCodecInfo::kFlagIsHardwareAccelerated;
+            }
+        }
+        info->setAttributes(attrs);
         info->setRank(omxRank);
-        for (const MediaCodecsXmlParser::Type& type : properties.typeMap) {
-            const std::string &mime = type.first;
+        // OMX components don't have aliases
+        for (const MediaCodecsXmlParser::Type &type : properties.typeMap) {
+            const std::string &mediaType = type.first;
             std::unique_ptr<MediaCodecInfo::CapabilitiesWriter> caps =
-                    info->addMime(mime.c_str());
+                    info->addMediaType(mediaType.c_str());
             const MediaCodecsXmlParser::AttributeMap &attrMap = type.second;
             for (const MediaCodecsXmlParser::Attribute& attr : attrMap) {
                 const std::string &key = attr.first;
@@ -290,13 +303,13 @@
             }
             status_t err = queryOmxCapabilities(
                     name.c_str(),
-                    mime.c_str(),
+                    mediaType.c_str(),
                     encoder,
                     caps.get());
             if (err != OK) {
-                ALOGE("Failed to query capabilities for %s (mime: %s). Error: %d",
+                ALOGI("Failed to query capabilities for %s (media type: %s). Error: %d",
                         name.c_str(),
-                        mime.c_str(),
+                        mediaType.c_str(),
                         static_cast<int>(err));
             }
         }
@@ -339,12 +352,13 @@
     // Obtain Codec2Client
     std::vector<Traits> traits = Codec2Client::ListComponents();
 
-    MediaCodecsXmlParser parser(
-            MediaCodecsXmlParser::defaultSearchDirs,
-            option == 0 ? "media_codecs.xml" :
-                          "media_codecs_c2.xml",
-            option == 0 ? "media_codecs_performance.xml" :
-                          "media_codecs_performance_c2.xml");
+    MediaCodecsXmlParser parser;
+    if (option == 0) {
+        parser.parseXmlFilesInSearchDirs();
+    } else {
+        parser.parseXmlFilesInSearchDirs(
+                { "media_codecs_c2.xml", "media_codecs_performance_c2.xml" });
+    }
     if (parser.getParsingStatus() != OK) {
         ALOGD("XML parser no good");
         return OK;
@@ -411,18 +425,37 @@
         ALOGV("canonName = %s", canonName.c_str());
         std::unique_ptr<MediaCodecInfoWriter> codecInfo = writer->addMediaCodecInfo();
         codecInfo->setName(trait.name.c_str());
-        codecInfo->setOwner("codec2");
+        codecInfo->setOwner(("codec2::" + trait.owner).c_str());
+        const MediaCodecsXmlParser::CodecProperties &codec = parser.getCodecMap().at(canonName);
+
         bool encoder = trait.kind == C2Component::KIND_ENCODER;
-        codecInfo->setEncoder(encoder);
+        typename std::underlying_type<MediaCodecInfo::Attributes>::type attrs = 0;
+
+        if (encoder) {
+            attrs |= MediaCodecInfo::kFlagIsEncoder;
+        }
+        if (trait.owner == "software") {
+            attrs |= MediaCodecInfo::kFlagIsSoftwareOnly;
+        } else {
+            attrs |= MediaCodecInfo::kFlagIsVendor;
+            if (trait.owner == "vendor-software") {
+                attrs |= MediaCodecInfo::kFlagIsSoftwareOnly;
+            } else if (codec.quirkSet.find("attribute::software-codec") == codec.quirkSet.end()) {
+                attrs |= MediaCodecInfo::kFlagIsHardwareAccelerated;
+            }
+        }
+        codecInfo->setAttributes(attrs);
         codecInfo->setRank(rank);
-        const MediaCodecsXmlParser::CodecProperties &codec =
-            parser.getCodecMap().at(canonName);
+
+        for (const std::string &alias : codec.aliases) {
+            codecInfo->addAlias(alias.c_str());
+        }
 
         for (auto typeIt = codec.typeMap.begin(); typeIt != codec.typeMap.end(); ++typeIt) {
             const std::string &mediaType = typeIt->first;
             const MediaCodecsXmlParser::AttributeMap &attrMap = typeIt->second;
             std::unique_ptr<MediaCodecInfo::CapabilitiesWriter> caps =
-                codecInfo->addMime(mediaType.c_str());
+                codecInfo->addMediaType(mediaType.c_str());
             for (auto attrIt = attrMap.begin(); attrIt != attrMap.end(); ++attrIt) {
                 std::string key, value;
                 std::tie(key, value) = *attrIt;
diff --git a/media/sfplugin/InputSurfaceWrapper.h b/media/sfplugin/InputSurfaceWrapper.h
index 12e58b2..d9c4eec 100644
--- a/media/sfplugin/InputSurfaceWrapper.h
+++ b/media/sfplugin/InputSurfaceWrapper.h
@@ -33,33 +33,15 @@
 
     virtual ~InputSurfaceWrapper() = default;
 
-    struct InputGater {
-        /**
-         * Try to reserve an input in the pipeline. If this function returns
-         * true, the pipeline slot is reserved. An implementation of
-         * InputSurfaceWrapper should not call Component::queue() if canQueue()
-         * returns false.
-         *
-         * \return true if the input can be reserved; false otherwise.
-         */
-        virtual bool canQueue() = 0;
-        virtual ~InputGater() = default;
-    };
-
     /**
      * Connect the surface with |comp|. A surface can
      * connect to at most one component at a time.
      *
-     * `inputGater->canQueue()` will be called before queuing a buffer. If it
-     * returns false, the buffer will not be queued to `comp` and simply
-     * dropped.
-     *
      * \return OK               successfully connected to |comp|
      * \return ALREADY_EXISTS   already connected to another component.
      */
     virtual status_t connect(
-            const std::shared_ptr<Codec2Client::Component> &comp,
-            const std::shared_ptr<InputGater> &inputGater) = 0;
+            const std::shared_ptr<Codec2Client::Component> &comp) = 0;
 
     /**
      * Disconnect the surface from the component if any.
diff --git a/media/sfplugin/ReflectedParamUpdater.cpp b/media/sfplugin/ReflectedParamUpdater.cpp
index d2a5091..880d4a5 100644
--- a/media/sfplugin/ReflectedParamUpdater.cpp
+++ b/media/sfplugin/ReflectedParamUpdater.cpp
@@ -94,7 +94,7 @@
             s << "string " << it.first << " = \"" << strValue.c_str() << "\"";
         } else if (it.second.find(&bufValue)) {
             s << "Buffer " << it.first << " = ";
-            if (bufValue != NULL && bufValue->data() != NULL && bufValue->size() <= 64) {
+            if (bufValue != nullptr && bufValue->data() != nullptr && bufValue->size() <= 64) {
                 s << "{" << std::endl;
                 AString tmp;
                 hexdump(bufValue->data(), bufValue->size(), indent_ + 4, &tmp);
diff --git a/media/sfplugin/SkipCutBuffer.cpp b/media/sfplugin/SkipCutBuffer.cpp
index ee9016d..5762440 100644
--- a/media/sfplugin/SkipCutBuffer.cpp
+++ b/media/sfplugin/SkipCutBuffer.cpp
@@ -29,7 +29,7 @@
     mWriteHead = 0;
     mReadHead = 0;
     mCapacity = 0;
-    mCutBuffer = NULL;
+    mCutBuffer = nullptr;
 
     if (num16BitChannels == 0 || num16BitChannels > INT32_MAX / 2) {
         ALOGW("# channels out of range: %zu, using passthrough instead", num16BitChannels);
@@ -57,7 +57,7 @@
 }
 
 void SkipCutBuffer::submit(MediaBuffer *buffer) {
-    if (mCutBuffer == NULL) {
+    if (mCutBuffer == nullptr) {
         // passthrough mode
         return;
     }
@@ -90,7 +90,7 @@
 
 template <typename T>
 void SkipCutBuffer::submitInternal(const sp<T>& buffer) {
-    if (mCutBuffer == NULL) {
+    if (mCutBuffer == nullptr) {
         // passthrough mode
         return;
     }
diff --git a/media/sfplugin/tests/Android.bp b/media/sfplugin/tests/Android.bp
index f04aa41..b08d3d6 100644
--- a/media/sfplugin/tests/Android.bp
+++ b/media/sfplugin/tests/Android.bp
@@ -19,7 +19,6 @@
     cflags: [
         "-Werror",
         "-Wall",
-        "-std=c++14",
     ],
 }
 
@@ -49,6 +48,5 @@
     cflags: [
         "-Werror",
         "-Wall",
-        "-std=c++14",
     ],
 }
diff --git a/media/sfplugin/utils/Android.bp b/media/sfplugin/utils/Android.bp
index cd572a4..fb5d9e4 100644
--- a/media/sfplugin/utils/Android.bp
+++ b/media/sfplugin/utils/Android.bp
@@ -36,8 +36,5 @@
             "unsigned-integer-overflow",
             "signed-integer-overflow",
         ],
-        diag: {
-            cfi: true,
-        },
     },
 }