Merge "Removing widevine classic"
diff --git a/camera/ndk/NdkCaptureRequest.cpp b/camera/ndk/NdkCaptureRequest.cpp
index 77b9a33..7c37955 100644
--- a/camera/ndk/NdkCaptureRequest.cpp
+++ b/camera/ndk/NdkCaptureRequest.cpp
@@ -51,8 +51,13 @@
         ACaptureRequest* req, const ACameraOutputTarget* target) {
     ATRACE_CALL();
     if (req == nullptr || req->targets == nullptr || target == nullptr) {
+        void* req_targets;
+        if (req != nullptr)
+            req_targets = req->targets;
+        else
+            req_targets = nullptr;
         ALOGE("%s: Error: invalid input: req %p, req-targets %p, target %p",
-                __FUNCTION__, req, req->targets, target);
+                __FUNCTION__, req, req_targets, target);
         return ACAMERA_ERROR_INVALID_PARAMETER;
     }
     auto pair = req->targets->mOutputs.insert(*target);
@@ -67,8 +72,13 @@
         ACaptureRequest* req, const ACameraOutputTarget* target) {
     ATRACE_CALL();
     if (req == nullptr || req->targets == nullptr || target == nullptr) {
+        void* req_targets;
+        if (req != nullptr)
+            req_targets = req->targets;
+        else
+            req_targets = nullptr;
         ALOGE("%s: Error: invalid input: req %p, req-targets %p, target %p",
-                __FUNCTION__, req, req->targets, target);
+                __FUNCTION__, req, req_targets, target);
         return ACAMERA_ERROR_INVALID_PARAMETER;
     }
     req->targets->mOutputs.erase(*target);
diff --git a/cmds/stagefright/sf2.cpp b/cmds/stagefright/sf2.cpp
index 8fe1dd4..76dbb78 100644
--- a/cmds/stagefright/sf2.cpp
+++ b/cmds/stagefright/sf2.cpp
@@ -230,7 +230,8 @@
                     mCodec->signalResume();
 
                     (new AMessage(kWhatSeek, this))->post(5000000ll);
-                } else if (what == CodecBase::kWhatShutdownCompleted) {
+                } else if (what == CodecBase::kWhatStopCompleted ||
+                        what == CodecBase::kWhatReleaseCompleted) {
                     mDecodeLooper->unregisterHandler(mCodec->id());
 
                     if (mDecodeLooper != looper()) {
diff --git a/include/media/IMediaPlayer.h b/include/media/IMediaPlayer.h
index edcca64..99ef59f 100644
--- a/include/media/IMediaPlayer.h
+++ b/include/media/IMediaPlayer.h
@@ -23,6 +23,8 @@
 #include <utils/KeyedVector.h>
 #include <system/audio.h>
 
+#include <media/IMediaSource.h>
+
 // Fwd decl to make sure everyone agrees that the scope of struct sockaddr_in is
 // global, and not in android::
 struct sockaddr_in;
@@ -38,6 +40,8 @@
 struct AudioPlaybackRate;
 struct AVSyncSettings;
 
+typedef IMediaSource::ReadOptions::SeekMode MediaPlayerSeekMode;
+
 class IMediaPlayer: public IInterface
 {
 public:
@@ -65,14 +69,9 @@
     virtual status_t        setSyncSettings(const AVSyncSettings& sync, float videoFpsHint) = 0;
     virtual status_t        getSyncSettings(AVSyncSettings* sync /* nonnull */,
                                             float* videoFps /* nonnull */) = 0;
-    // When |precise| is true, it's required that the first rendered media position after seekTo
-    // is precisely at |msec|, up to rounding error of granuality, e.g., video frame interval or
-    // audio length of decoding buffer. In this case, it might take a little long time to finish
-    // seekTo.
-    // When |precise| is false, |msec| is a hint to the mediaplayer which will try its best to
-    // fulfill the request, but it's not guaranteed. This option could result in fast finish of
-    // seekTo.
-    virtual status_t        seekTo(int msec, bool precise = false) = 0;
+    virtual status_t        seekTo(
+            int msec,
+            MediaPlayerSeekMode mode = MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC) = 0;
     virtual status_t        getCurrentPosition(int* msec) = 0;
     virtual status_t        getDuration(int* msec) = 0;
     virtual status_t        reset() = 0;
diff --git a/include/media/MediaPlayerInterface.h b/include/media/MediaPlayerInterface.h
index b488159..4e4878a 100644
--- a/include/media/MediaPlayerInterface.h
+++ b/include/media/MediaPlayerInterface.h
@@ -205,7 +205,8 @@
         *videoFps = -1.f;
         return OK;
     }
-    virtual status_t    seekTo(int msec, bool precise = false) = 0;
+    virtual status_t    seekTo(
+            int msec, MediaPlayerSeekMode mode = MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC) = 0;
     virtual status_t    getCurrentPosition(int *msec) = 0;
     virtual status_t    getDuration(int *msec) = 0;
     virtual status_t    reset() = 0;
diff --git a/include/media/mediaplayer.h b/include/media/mediaplayer.h
index c556f0a..be34d02 100644
--- a/include/media/mediaplayer.h
+++ b/include/media/mediaplayer.h
@@ -233,7 +233,9 @@
                                     float* videoFps /* nonnull */);
             status_t        getVideoWidth(int *w);
             status_t        getVideoHeight(int *h);
-            status_t        seekTo(int msec, bool precise = false);
+            status_t        seekTo(
+                    int msec,
+                    MediaPlayerSeekMode mode = MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC);
             status_t        getCurrentPosition(int *msec);
             status_t        getDuration(int *msec);
             status_t        reset();
@@ -257,7 +259,7 @@
 
 private:
             void            clear_l();
-            status_t        seekTo_l(int msec, bool precise);
+            status_t        seekTo_l(int msec, MediaPlayerSeekMode mode);
             status_t        prepareAsync_l();
             status_t        getDuration_l(int *msec);
             status_t        attachNewPlayer(const sp<IMediaPlayer>& player);
@@ -274,9 +276,9 @@
     void*                       mCookie;
     media_player_states         mCurrentState;
     int                         mCurrentPosition;
-    bool                        mCurrentSeekPrecise;
+    MediaPlayerSeekMode         mCurrentSeekMode;
     int                         mSeekPosition;
-    int                         mSeekPrecise;
+    MediaPlayerSeekMode         mSeekMode;
     bool                        mPrepareSync;
     status_t                    mPrepareStatus;
     audio_stream_type_t         mStreamType;
diff --git a/include/media/stagefright/CodecBase.h b/include/media/stagefright/CodecBase.h
index d8c43a4..39a9089 100644
--- a/include/media/stagefright/CodecBase.h
+++ b/include/media/stagefright/CodecBase.h
@@ -43,7 +43,8 @@
         kWhatFillThisBuffer      = 'fill',
         kWhatDrainThisBuffer     = 'drai',
         kWhatEOS                 = 'eos ',
-        kWhatShutdownCompleted   = 'scom',
+        kWhatStopCompleted       = 'scom',
+        kWhatReleaseCompleted    = 'rcom',
         kWhatFlushCompleted      = 'fcom',
         kWhatError               = 'erro',
         kWhatComponentAllocated  = 'cAll',
diff --git a/include/media/stagefright/foundation/Flagged.h b/include/media/stagefright/foundation/Flagged.h
new file mode 100644
index 0000000..bf0afbf
--- /dev/null
+++ b/include/media/stagefright/foundation/Flagged.h
@@ -0,0 +1,513 @@
+/*
+ * Copyright (C) 2016 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 STAGEFRIGHT_FOUNDATION_FLAGGED_H_
+#define STAGEFRIGHT_FOUNDATION_FLAGGED_H_
+
+#include <media/stagefright/foundation/TypeTraits.h>
+
+namespace android {
+
+/**
+ * Flagged<T, Flag> is basically a specialized std::pair<Flag, T> that automatically optimizes out
+ * the flag if the wrapped type T is already flagged and we can combine the outer and inner flags.
+ *
+ * Flags can be queried/manipulated via flags() an setFlags(Flags). The wrapped value can be
+ * accessed via get(). This template is meant to be inherited by other utility/wrapper classes
+ * that need to store integral information along with the value.
+ *
+ * Users must specify the used bits (MASK) in the flags. Flag getters and setters will enforce this
+ * mask. _Flagged_helper::minMask<Flag> is provided to easily calculate a mask for a max value.
+ *
+ * E.g. adding a safe flag can be achieved like this:
+ *
+ *
+ * enum SafeFlags : uint32_t {
+ *   kUnsafe,
+ *   kSafe,
+ *   kSafeMask = _Flagged_helper::minMask(kSafe),
+ * };
+ * typedef Flagged<int32_t, SafeFlags, kSafeMask> safeInt32;
+ *
+ * safeInt32 a;
+ * a.setFlags(kSafe);
+ * a.get() = 15;
+ * EXPECT_EQ(a.flags(), kSafe);
+ * EXPECT_EQ(a.get(), 15);
+ *
+ *
+ * Flagged also supports lazy or calculated wrapping of already flagged types. Lazy wrapping is
+ * provided automatically (flags are automatically shared if possible, e.g. mask is shifted
+ * automatically to not overlap with used bits of the wrapped type's flags, and fall back to
+ * unshared version of the template.):
+ *
+ * enum OriginFlags : uint32_t {
+ *   kUnknown,
+ *   kConst,
+ *   kCalculated,
+ *   kComponent,
+ *   kApplication,
+ *   kFile,
+ *   kBinder,
+ *   kOriginMask = _Flagged_helper::minMask(kBinder),
+ * };
+ * typedef Flagged<safeInt32, OriginFlags, kOriginMask>
+ *          trackedSafeInt32;
+ *
+ * static_assert(sizeof(trackedSafeInt32) == sizeof(safeInt32), "");
+ *
+ * trackedSafeInt32 b(kConst, kSafe, 1);
+ * EXPECT_EQ(b.flags(), kConst);
+ * EXPECT_EQ(b.get().flags(), kSafe);
+ * EXPECT_EQ(b.get().get(), 1);
+ * b.setFlags(kCalculated);
+ * b.get().setFlags(overflow ? kUnsafe : kSafe);
+ *
+ * One can also choose to share some flag-bits with the wrapped class:
+ *
+ * enum ValidatedFlags : uint32_t {
+ *   kUnsafeV = kUnsafe,
+ *   kSafeV = kSafe,
+ *   kValidated = kSafe | 2,
+ *   kSharedMaskV = kSafeMask,
+ *   kValidatedMask = _Flagged_helper::minMask(kValidated),
+ * };
+ * typedef Flagged<safeInt32, ValidatedFlags, kValidatedMask, kSharedMaskV> validatedInt32;
+ *
+ * validatedInt32 v(kUnsafeV, kSafe, 10);
+ * EXPECT_EQ(v.flags(), kUnsafeV);
+ * EXPECT_EQ(v.get().flags(), kUnsafe);  // !kUnsafeV overrides kSafe
+ * EXPECT_EQ(v.get().get(), 10);
+ * v.setFlags(kValidated);
+ * EXPECT_EQ(v.flags(), kValidated);
+ * EXPECT_EQ(v.get().flags(), kSafe);
+ * v.get().setFlags(kUnsafe);
+ * EXPECT_EQ(v.flags(), 2);  // NOTE: sharing masks with enums allows strange situations to occur
+ */
+
+/**
+ * Helper class for Flagged support. Encapsulates common utilities used by all
+ * templated classes.
+ */
+struct _Flagged_helper {
+    /**
+     * Calculates the value with a given number of top-most bits set.
+     *
+     * This method may be called with a signed flag.
+     *
+     * \param num number of bits to set. This must be between 0 and the number of bits in Flag.
+     *
+     * \return the value where only the given number of top-most bits are set.
+     */
+    template<typename Flag>
+    static constexpr Flag topBits(int num) {
+        return Flag(num > 0 ?
+                    ~((Flag(1) << (sizeof(Flag) * 8 - is_signed_integral<Flag>::value - num)) - 1) :
+                    0);
+    }
+
+    /**
+     * Calculates the minimum mask required to cover a value. Used with the maximum enum value for
+     * an unsigned flag.
+     *
+     * \param maxValue maximum value to cover
+     * \param shift DO NO USE. used internally
+     *
+     * \return mask that can be used that covers the maximum value.
+     */
+    template<typename Flag>
+    static constexpr Flag minMask(Flag maxValue, int shift=sizeof(Flag) * 4) {
+        static_assert(is_unsigned_integral<Flag>::value,
+                      "this method only makes sense for unsigned flags");
+        return shift ? minMask<Flag>(Flag(maxValue | (maxValue >> shift)), shift >> 1) : maxValue;
+    }
+
+    /**
+     * Returns a value left-shifted by an argument as a potential constexpr.
+     *
+     * This method helps around the C-language limitation, when left-shift of a negative value with
+     * even 0 cannot be a constexpr.
+     *
+     * \param value value to shift
+     * \param shift amount of shift
+     * \returns the shifted value as an integral type
+     */
+    template<typename Flag, typename IntFlag = typename underlying_integral_type<Flag>::type>
+    static constexpr IntFlag lshift(Flag value, int shift) {
+        return shift ? value << shift : value;
+    }
+
+private:
+
+    /**
+     * Determines whether mask can be combined with base-mask for a given left shift.
+     *
+     * \param mask desired mask
+     * \param baseMask mask used by T or 0 if T is not flagged by Flag
+     * \param sharedMask desired shared mask (if this is non-0, this must be mask & baseMask)
+     * \param shift desired left shift to be used for mask
+     * \param baseShift left shift used by T or 0 if T is not flagged by Flag
+     * \param effectiveMask effective mask used by T or 0 if T is not flagged by Flag
+     *
+     * \return bool whether mask can be combined with baseMask using the desired values.
+     */
+    template<typename Flag, typename IntFlag=typename underlying_integral_type<Flag>::type>
+    static constexpr bool canCombine(
+            Flag mask, IntFlag baseMask, Flag sharedMask, int shift,
+            int baseShift, IntFlag effectiveMask) {
+        return
+            // verify that shift is valid and mask can be shifted
+            shift >= 0 && (mask & topBits<Flag>(shift)) == 0 &&
+
+            // verify that base mask is part of effective mask (sanity check on arguments)
+            (baseMask & ~(effectiveMask >> baseShift)) == 0 &&
+
+            // if sharing masks, shift must be the base's shift.
+            // verify that shared mask is the overlap of base mask and mask
+            (sharedMask ?
+                    ((sharedMask ^ (baseMask & mask)) == 0 &&
+                     shift == baseShift) :
+
+
+            // otherwise, verify that there is no overlap between mask and base's effective mask
+                    (mask & (effectiveMask >> shift)) == 0);
+    }
+
+
+    /**
+     * Calculates the minimum (left) shift required to combine a mask with the mask of an
+     * underlying type (T, also flagged by Flag).
+     *
+     * \param mask desired mask
+     * \param baseMask mask used by T or 0 if T is not flagged by Flag
+     * \param sharedMask desired shared mask (if this is non-0, this must be mask & baseMask)
+     * \param baseShift left shift used by T
+     * \param effectiveMask effective mask used by T
+     *
+     * \return a non-negative minimum left shift value if mask can be combined with baseMask,
+     *         or -1 if the masks cannot be combined. -2 if the input is invalid.
+     */
+    template<typename Flag,
+             typename IntFlag = typename underlying_integral_type<Flag>::type>
+    static constexpr int getShift(
+            Flag mask, IntFlag baseMask, Flag sharedMask, int baseShift, IntFlag effectiveMask) {
+        return
+            // baseMask must be part of the effective mask
+            (baseMask & ~(effectiveMask >> baseShift)) ? -2 :
+
+            // if sharing masks, shift must be base's shift. verify that shared mask is part of
+            // base mask and mask, and that desired mask still fits with base's shift value
+            sharedMask ?
+                    (canCombine(mask, baseMask, sharedMask, baseShift /* shift */,
+                                baseShift, effectiveMask) ? baseShift : -1) :
+
+            // otherwise, see if 0-shift works
+            ((mask & effectiveMask) == 0) ? 0 :
+
+            // otherwise, verify that mask can be shifted up
+            ((mask & topBits<Flag>(1)) || (mask < 0)) ? -1 :
+
+            incShift(getShift(Flag(mask << 1), baseMask /* unused */, sharedMask /* 0 */,
+                              baseShift /* unused */, effectiveMask));
+    }
+
+    /**
+     * Helper method that increments a non-negative (shift) value.
+     *
+     * This method is used to make it easier to create a constexpr for getShift.
+     *
+     * \param shift (shift) value to increment
+     *
+     * \return original shift if it was negative; otherwise, the shift incremented by one.
+     */
+    static constexpr int incShift(int shift) {
+        return shift + (shift >= 0);
+    }
+
+#ifdef FRIEND_TEST
+    FRIEND_TEST(FlaggedTest, _Flagged_helper_Test);
+#endif
+
+public:
+    /**
+     * Base class for all Flagged<T, Flag> classes.
+     *
+     * \note flagged types do not have a member variable for the mask used by the type. As such,
+     * they should be be cast to this base class.
+     *
+     * \todo can we replace this base class check with a static member check to remove possibility
+     * of cast?
+     */
+    template<typename Flag>
+    struct base {};
+
+    /**
+     * Type support utility that retrieves the mask of a class (T) if it is a type flagged by
+     * Flag (e.g. Flagged<T, Flag>).
+     *
+     * \note This retrieves 0 if T is a flagged class, that is not flagged by Flag or an equivalent
+     * underlying type.
+     *
+     * Generic implementation for a non-flagged class.
+     */
+    template<
+        typename T, typename Flag,
+        bool=std::is_base_of<base<typename underlying_integral_type<Flag>::type>, T>::value>
+    struct mask_of {
+        using IntFlag = typename underlying_integral_type<Flag>::type;
+        static constexpr IntFlag value = Flag(0); ///< mask of a potentially flagged class
+        static constexpr int shift = 0; ///<left shift of flags in a potentially flagged class
+        static constexpr IntFlag effective_value = IntFlag(0); ///<effective mask of flagged class
+    };
+
+    /**
+     * Type support utility that calculates the minimum (left) shift required to combine a mask
+     * with the mask of an underlying type T also flagged by Flag.
+     *
+     * \note if T is not flagged, not flagged by Flag, or the masks cannot be combined due to
+     * incorrect sharing or the flags not having enough bits, the minimum is -1.
+     *
+     * \param MASK desired mask
+     * \param SHARED_MASK desired shared mask (if this is non-0, T must be an type flagged by
+     *        Flag with a mask that has exactly these bits common with MASK)
+     */
+    template<typename T, typename Flag, Flag MASK, Flag SHARED_MASK>
+    struct min_shift {
+        /// minimum (left) shift required, or -1 if masks cannot be combined
+        static constexpr int value =
+            getShift(MASK, mask_of<T, Flag>::value, SHARED_MASK,
+                     mask_of<T, Flag>::shift, mask_of<T, Flag>::effective_value);
+    };
+
+    /**
+     * Type support utility that calculates whether the flags of T can be combined with MASK.
+     *
+     * \param MASK desired mask
+     * \param SHARED_MASK desired shared mask (if this is non-0, T MUST be an type flagged by
+     *        Flag with a mask that has exactly these bits common with MASK)
+     */
+    template<
+            typename T, typename Flag, Flag MASK,
+            Flag SHARED_MASK=Flag(0),
+            int SHIFT=min_shift<T, Flag, MASK, SHARED_MASK>::value>
+    struct can_combine {
+        using IntFlag = typename underlying_integral_type<Flag>::type;
+        /// true if this mask can be combined with T's existing flag. false otherwise.
+        static constexpr bool value =
+                std::is_base_of<base<IntFlag>, T>::value
+                        && canCombine(MASK, mask_of<T, Flag>::value, SHARED_MASK, SHIFT,
+                                      mask_of<T, Flag>::shift, mask_of<T, Flag>::effective_value);
+    };
+};
+
+/**
+ * Template specialization for the case when T is flagged by Flag or a compatible type.
+ */
+template<typename T, typename Flag>
+struct _Flagged_helper::mask_of<T, Flag, true> {
+    using IntType = typename underlying_integral_type<Flag>::type;
+    static constexpr IntType value = T::sFlagMask;
+    static constexpr int shift = T::sFlagShift;
+    static constexpr IntType effective_value = T::sEffectiveMask;
+};
+
+/**
+ * Main Flagged template that adds flags to an object of another type (in essence, creates a pair)
+ *
+ * Flag must be an integral type (enums are allowed).
+ *
+ * \note We could make SHARED_MASK be a boolean as it must be either 0 or MASK & base's mask, but we
+ * want it to be spelled out for safety.
+ *
+ * \param T type of object wrapped
+ * \param Flag type of flag
+ * \param MASK mask for the bits used in flag (before any shift)
+ * \param SHARED_MASK optional mask to be shared with T (if this is not zero, SHIFT must be 0, and
+ *        it must equal to MASK & T's mask)
+ * \param SHIFT optional left shift for MASK to combine with T's mask (or -1, if masks should not
+ *        be combined.)
+ */
+template<
+        typename T, typename Flag, Flag MASK, Flag SHARED_MASK=(Flag)0,
+        int SHIFT=_Flagged_helper::min_shift<T, Flag, MASK, SHARED_MASK>::value,
+        typename IntFlag=typename underlying_integral_type<Flag>::type,
+        bool=_Flagged_helper::can_combine<T, IntFlag, MASK, SHARED_MASK, SHIFT>::value>
+class Flagged : public _Flagged_helper::base<IntFlag> {
+    static_assert(SHARED_MASK == 0,
+                  "shared mask can only be used with common flag types "
+                  "and must be part of mask and mask of base type");
+    static_assert((_Flagged_helper::topBits<Flag>(SHIFT) & MASK) == 0, "SHIFT overflows MASK");
+
+    static constexpr Flag sFlagMask = MASK;  ///< the mask
+    static constexpr int sFlagShift = SHIFT > 0 ? SHIFT : 0; ///< the left shift applied to flags
+
+    friend struct _Flagged_helper;
+#ifdef FRIEND_TEST
+    static constexpr bool sFlagCombined = false;
+    FRIEND_TEST(FlaggedTest, _Flagged_helper_Test);
+#endif
+
+    T       mValue; ///< wrapped value
+    IntFlag mFlags; ///< flags
+
+protected:
+    /// The effective combined mask used by this class and any wrapped classes if the flags are
+    /// combined.
+    static constexpr IntFlag sEffectiveMask = _Flagged_helper::lshift(MASK, sFlagShift);
+
+    /**
+     * Helper method used by subsequent flagged wrappers to query flags. Returns the
+     * flags for a particular mask and left shift.
+     *
+     * \param mask bitmask to use
+     * \param shift left shifts to use
+     *
+     * \return the requested flags
+     */
+    inline constexpr IntFlag getFlagsHelper(IntFlag mask, int shift) const {
+        return (mFlags >> shift) & mask;
+    }
+
+    /**
+     * Helper method used by subsequent flagged wrappers to apply combined flags. Sets the flags
+     * in the bitmask using a particulare left shift.
+     *
+     * \param mask bitmask to use
+     * \param shift left shifts to use
+     * \param flags flags to update (any flags within the bitmask are updated to their value in this
+     *        argument)
+     */
+    inline void setFlagsHelper(IntFlag mask, int shift, IntFlag flags) {
+        mFlags = Flag((mFlags & ~(mask << shift)) | ((flags & mask) << shift));
+    }
+
+public:
+    /**
+     * Wrapper around base class constructor. These take the flags as their first
+     * argument and pass the rest of the arguments to the base class constructor.
+     *
+     * \param flags initial flags
+     */
+    template<typename ...Args>
+    constexpr Flagged(Flag flags, Args... args)
+        : mValue(std::forward<Args>(args)...),
+          mFlags(Flag(_Flagged_helper::lshift(flags & sFlagMask, sFlagShift))) { }
+
+    /** Gets the wrapped value as const. */
+    inline constexpr const T &get() const { return mValue; }
+
+    /** Gets the wrapped value. */
+    inline T &get() { return mValue; }
+
+    /** Gets the flags. */
+    constexpr Flag flags() const {
+        return Flag(getFlagsHelper(sFlagMask, sFlagShift));
+    }
+
+    /** Sets the flags. */
+    void setFlags(Flag flags) {
+        setFlagsHelper(sFlagMask, sFlagShift, flags);
+    }
+};
+
+/*
+ * TRICKY: we cannot implement the specialization as:
+ *
+ * class Flagged : base<Flag> {
+ *    T value;
+ * };
+ *
+ * Because T also inherits from base<Flag> and this runs into a compiler bug where
+ * sizeof(Flagged) > sizeof(T).
+ *
+ * Instead, we must inherit directly from the wrapped class
+ *
+ */
+#if 0
+template<
+        typename T, typename Flag, Flag MASK, Flag SHARED_MASK, int SHIFT>
+class Flagged<T, Flag, MASK, SHARED_MASK, SHIFT, true> : public _Flagged_helper::base<Flag> {
+private:
+    T mValue;
+};
+#else
+/**
+ * Specialization for the case when T is derived from Flagged<U, Flag> and flags can be combined.
+ */
+template<
+        typename T, typename Flag, Flag MASK, Flag SHARED_MASK, int SHIFT, typename IntFlag>
+class Flagged<T, Flag, MASK, SHARED_MASK, SHIFT, IntFlag, true> : private T {
+    static_assert(is_integral_or_enum<Flag>::value, "flag must be integer or enum");
+
+    static_assert(SHARED_MASK == 0 || SHIFT == 0, "cannot overlap masks when using SHIFT");
+    static_assert((SHARED_MASK & ~MASK) == 0, "shared mask must be part of the mask");
+    static_assert((SHARED_MASK & ~T::sEffectiveMask) == 0,
+                  "shared mask must be part of the base mask");
+    static_assert(SHARED_MASK == 0 || (~SHARED_MASK & (MASK & T::sEffectiveMask)) == 0,
+                  "mask and base mask can only overlap in shared mask");
+
+    static constexpr Flag sFlagMask = MASK;  ///< the mask
+    static constexpr int sFlagShift = SHIFT;  ///< the left shift applied to the flags
+
+#ifdef FRIEND_TEST
+    const static bool sFlagCombined = true;
+    FRIEND_TEST(FlaggedTest, _Flagged_helper_Test);
+#endif
+
+protected:
+    /// The effective combined mask used by this class and any wrapped classes if the flags are
+    /// combined.
+    static constexpr IntFlag sEffectiveMask = Flag((MASK << SHIFT) | T::sEffectiveMask);
+    friend struct _Flagged_helper;
+
+public:
+    /**
+     * Wrapper around base class constructor. These take the flags as their first
+     * argument and pass the rest of the arguments to the base class constructor.
+     *
+     * \param flags initial flags
+     */
+    template<typename ...Args>
+    constexpr Flagged(Flag flags, Args... args)
+        : T(std::forward<Args>(args)...) {
+        // we construct the base class first and apply the flags afterwards as
+        // base class may not have a constructor that takes flags even if it is derived from
+        // Flagged<U, Flag>
+        setFlags(flags);
+    }
+
+    /** Gets the wrapped value as const. */
+    inline constexpr T &get() const { return *this; }
+
+    /** Gets the wrapped value. */
+    inline T &get() { return *this; }
+
+    /** Gets the flags. */
+    Flag constexpr flags() const {
+        return Flag(this->getFlagsHelper(sFlagMask, sFlagShift));
+    }
+
+    /** Sets the flags. */
+    void setFlags(Flag flags) {
+        this->setFlagsHelper(sFlagMask, sFlagShift, flags);
+    }
+};
+#endif
+
+}  // namespace android
+
+#endif  // STAGEFRIGHT_FOUNDATION_FLAGGED_H_
+
diff --git a/include/media/stagefright/foundation/TypeTraits.h b/include/media/stagefright/foundation/TypeTraits.h
new file mode 100644
index 0000000..2eaec35
--- /dev/null
+++ b/include/media/stagefright/foundation/TypeTraits.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2016 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 STAGEFRIGHT_FOUNDATION_TYPE_TRAITS_H_
+#define STAGEFRIGHT_FOUNDATION_TYPE_TRAITS_H_
+
+#include <type_traits>
+
+namespace android {
+
+/**
+ * std::is_signed, is_unsigned and is_integral does not consider enums even though the standard
+ * considers them integral. Create modified versions of these here. Also create a wrapper around
+ * std::underlying_type that does not require checking if the type is an enum.
+ */
+
+/**
+ * Type support utility class to check if a type is an integral type or an enum.
+ */
+template<typename T>
+struct is_integral_or_enum
+    : std::integral_constant<bool, std::is_integral<T>::value || std::is_enum<T>::value> { };
+
+/**
+ * Type support utility class to get the underlying std::is_integral supported type for a type.
+ * This returns the underlying type for enums, and the same type for types covered by
+ * std::is_integral.
+ *
+ * This is also used as a conditional to return an alternate type if the template param is not
+ * an integral or enum type (as in underlying_integral_type<T, TypeIfNotEnumOrIntegral>::type).
+ */
+template<typename T,
+        typename U=typename std::enable_if<is_integral_or_enum<T>::value>::type,
+        bool=std::is_enum<T>::value,
+        bool=std::is_integral<T>::value>
+struct underlying_integral_type {
+    static_assert(!std::is_enum<T>::value, "T should not be enum here");
+    static_assert(!std::is_integral<T>::value, "T should not be integral here");
+    typedef U type;
+};
+
+/** Specialization for enums. */
+template<typename T, typename U>
+struct underlying_integral_type<T, U, true, false> {
+    static_assert(std::is_enum<T>::value, "T should be enum here");
+    static_assert(!std::is_integral<T>::value, "T should not be integral here");
+    typedef typename std::underlying_type<T>::type type;
+};
+
+/** Specialization for non-enum std-integral types. */
+template<typename T, typename U>
+struct underlying_integral_type<T, U, false, true> {
+    static_assert(!std::is_enum<T>::value, "T should not be enum here");
+    static_assert(std::is_integral<T>::value, "T should be integral here");
+    typedef T type;
+};
+
+/**
+ * Type support utility class to check if the underlying integral type is signed.
+ */
+template<typename T>
+struct is_signed_integral
+    : std::integral_constant<bool, std::is_signed<
+            typename underlying_integral_type<T, unsigned>::type>::value> { };
+
+/**
+ * Type support utility class to check if the underlying integral type is unsigned.
+ */
+template<typename T>
+struct is_unsigned_integral
+    : std::integral_constant<bool, std::is_unsigned<
+            typename underlying_integral_type<T, signed>::type>::value> {
+};
+
+}  // namespace android
+
+#endif  // STAGEFRIGHT_FOUNDATION_TYPE_TRAITS_H_
+
diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
index 243e302..a3d6761 100644
--- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
+++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
@@ -340,8 +340,10 @@
             }
             delete pContext;
         }
-        *pHandle = (effect_handle_t)NULL;
+        if (pHandle != NULL)
+          *pHandle = (effect_handle_t)NULL;
     } else {
+      if (pHandle != NULL)
         *pHandle = (effect_handle_t)pContext;
     }
     ALOGV("\tEffectCreate end..\n\n");
@@ -2669,8 +2671,8 @@
 
         case VOLUME_PARAM_ENABLESTEREOPOSITION:
             positionEnabled = *(uint32_t *)pValue;
-            status = VolumeEnableStereoPosition(pContext, positionEnabled);
-            status = VolumeSetStereoPosition(pContext, pContext->pBundledContext->positionSaved);
+            (void) VolumeEnableStereoPosition(pContext, positionEnabled);
+            (void) VolumeSetStereoPosition(pContext, pContext->pBundledContext->positionSaved);
             //ALOGV("\tVolume_setParameter() VOLUME_PARAM_ENABLESTEREOPOSITION called");
             break;
 
diff --git a/media/libmedia/IMediaPlayer.cpp b/media/libmedia/IMediaPlayer.cpp
index 41b6988..dda2570 100644
--- a/media/libmedia/IMediaPlayer.cpp
+++ b/media/libmedia/IMediaPlayer.cpp
@@ -246,12 +246,12 @@
         return reply.readInt32();
     }
 
-    status_t seekTo(int msec, bool precise)
+    status_t seekTo(int msec, MediaPlayerSeekMode mode)
     {
         Parcel data, reply;
         data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
         data.writeInt32(msec);
-        data.writeBool(precise);
+        data.writeInt32(mode);
         remote()->transact(SEEK_TO, data, &reply);
         return reply.readInt32();
     }
@@ -575,8 +575,8 @@
         case SEEK_TO: {
             CHECK_INTERFACE(IMediaPlayer, data, reply);
             int msec = data.readInt32();
-            bool precise = data.readBool();
-            reply->writeInt32(seekTo(msec, precise));
+            MediaPlayerSeekMode mode = (MediaPlayerSeekMode)data.readInt32();
+            reply->writeInt32(seekTo(msec, mode));
             return NO_ERROR;
         } break;
         case GET_CURRENT_POSITION: {
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
index 846a24c..699172b 100644
--- a/media/libmedia/mediaplayer.cpp
+++ b/media/libmedia/mediaplayer.cpp
@@ -55,9 +55,9 @@
     mStreamType = AUDIO_STREAM_MUSIC;
     mAudioAttributesParcel = NULL;
     mCurrentPosition = -1;
-    mCurrentSeekPrecise = false;
+    mCurrentSeekMode = MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC;
     mSeekPosition = -1;
-    mSeekPrecise = false;
+    mSeekMode = MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC;
     mCurrentState = MEDIA_PLAYER_IDLE;
     mPrepareSync = false;
     mPrepareStatus = NO_ERROR;
@@ -102,9 +102,9 @@
 void MediaPlayer::clear_l()
 {
     mCurrentPosition = -1;
-    mCurrentSeekPrecise = false;
+    mCurrentSeekMode = MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC;
     mSeekPosition = -1;
-    mSeekPrecise = false;
+    mSeekMode = MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC;
     mVideoWidth = mVideoHeight = 0;
     mRetransmitEndpointValid = false;
 }
@@ -512,9 +512,9 @@
     return getDuration_l(msec);
 }
 
-status_t MediaPlayer::seekTo_l(int msec, bool precise)
+status_t MediaPlayer::seekTo_l(int msec, MediaPlayerSeekMode mode)
 {
-    ALOGV("seekTo (%d, %d)", msec, precise);
+    ALOGV("seekTo (%d, %d)", msec, mode);
     if ((mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_STARTED | MEDIA_PLAYER_PREPARED |
             MEDIA_PLAYER_PAUSED |  MEDIA_PLAYER_PLAYBACK_COMPLETE) ) ) {
         if ( msec < 0 ) {
@@ -541,14 +541,14 @@
 
         // cache duration
         mCurrentPosition = msec;
-        mCurrentSeekPrecise = precise;
+        mCurrentSeekMode = mode;
         if (mSeekPosition < 0) {
             mSeekPosition = msec;
-            mSeekPrecise = precise;
-            return mPlayer->seekTo(msec, precise);
+            mSeekMode = mode;
+            return mPlayer->seekTo(msec, mode);
         }
         else {
-            ALOGV("Seek in progress - queue up seekTo[%d, %d]", msec, precise);
+            ALOGV("Seek in progress - queue up seekTo[%d, %d]", msec, mode);
             return NO_ERROR;
         }
     }
@@ -557,11 +557,11 @@
     return INVALID_OPERATION;
 }
 
-status_t MediaPlayer::seekTo(int msec, bool precise)
+status_t MediaPlayer::seekTo(int msec, MediaPlayerSeekMode mode)
 {
     mLockThreadId = getThreadId();
     Mutex::Autolock _l(mLock);
-    status_t result = seekTo_l(msec, precise);
+    status_t result = seekTo_l(msec, mode);
     mLockThreadId = 0;
 
     return result;
@@ -875,16 +875,16 @@
         break;
     case MEDIA_SEEK_COMPLETE:
         ALOGV("Received seek complete");
-        if (mSeekPosition != mCurrentPosition || (!mSeekPrecise && mCurrentSeekPrecise)) {
-            ALOGV("Executing queued seekTo(%d, %d)", mCurrentPosition, mCurrentSeekPrecise);
+        if (mSeekPosition != mCurrentPosition || (mSeekMode != mCurrentSeekMode)) {
+            ALOGV("Executing queued seekTo(%d, %d)", mCurrentPosition, mCurrentSeekMode);
             mSeekPosition = -1;
-            mSeekPrecise = false;
-            seekTo_l(mCurrentPosition, mCurrentSeekPrecise);
+            mSeekMode = MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC;
+            seekTo_l(mCurrentPosition, mCurrentSeekMode);
         }
         else {
             ALOGV("All seeks complete - return to regularly scheduled program");
             mCurrentPosition = mSeekPosition = -1;
-            mCurrentSeekPrecise = mSeekPrecise = false;
+            mCurrentSeekMode = mSeekMode = MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC;
         }
         break;
     case MEDIA_BUFFERING_UPDATE:
diff --git a/media/libmediaplayerservice/ActivityManager.cpp b/media/libmediaplayerservice/ActivityManager.cpp
index 60a209f..0e6cf7b 100644
--- a/media/libmediaplayerservice/ActivityManager.cpp
+++ b/media/libmediaplayerservice/ActivityManager.cpp
@@ -24,7 +24,7 @@
 
 namespace android {
 
-const uint32_t OPEN_CONTENT_URI_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION + 4;
+const uint32_t OPEN_CONTENT_URI_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION;
 
 // Perform ContentProvider.openFile() on the given URI, returning
 // the resulting native file descriptor.  Returns < 0 on error.
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 3ff9d98..6e163d9 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -1121,12 +1121,12 @@
     return OK;
 }
 
-status_t MediaPlayerService::Client::seekTo(int msec, bool precise)
+status_t MediaPlayerService::Client::seekTo(int msec, MediaPlayerSeekMode mode)
 {
-    ALOGV("[%d] seekTo(%d)", mConnId, msec);
+    ALOGV("[%d] seekTo(%d, %d)", mConnId, msec, mode);
     sp<MediaPlayerBase> p = getPlayer();
     if (p == 0) return UNKNOWN_ERROR;
-    return p->seekTo(msec, precise);
+    return p->seekTo(msec, mode);
 }
 
 status_t MediaPlayerService::Client::reset()
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index ef82b48..a4ea37f 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -298,7 +298,9 @@
         virtual status_t        setSyncSettings(const AVSyncSettings& rate, float videoFpsHint);
         virtual status_t        getSyncSettings(AVSyncSettings* rate /* nonnull */,
                                                 float* videoFps /* nonnull */);
-        virtual status_t        seekTo(int msec, bool precise = false);
+        virtual status_t        seekTo(
+                int msec,
+                MediaPlayerSeekMode mode = MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC);
         virtual status_t        getCurrentPosition(int* msec);
         virtual status_t        getDuration(int* msec);
         virtual status_t        reset();
diff --git a/media/libmediaplayerservice/MediaRecorderClient.cpp b/media/libmediaplayerservice/MediaRecorderClient.cpp
index 94ceae4..49c221b 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.cpp
+++ b/media/libmediaplayerservice/MediaRecorderClient.cpp
@@ -369,9 +369,13 @@
 
     sp<IServiceManager> sm = defaultServiceManager();
     sp<IBinder> binder = sm->getService(String16("media.camera"));
-    mCameraDeathListener = new ServiceDeathNotifier(binder, listener,
-            MediaPlayerService::CAMERA_PROCESS_DEATH);
-    binder->linkToDeath(mCameraDeathListener);
+
+    // If the device does not have a camera, do not create a death listener for it.
+    if (binder != NULL) {
+        mCameraDeathListener = new ServiceDeathNotifier(binder, listener,
+                MediaPlayerService::CAMERA_PROCESS_DEATH);
+        binder->linkToDeath(mCameraDeathListener);
+    }
 
     binder = sm->getService(String16("media.codec"));
     mCodecDeathListener = new ServiceDeathNotifier(binder, listener,
diff --git a/media/libmediaplayerservice/TestPlayerStub.h b/media/libmediaplayerservice/TestPlayerStub.h
index c0d6a59..11fddf6 100644
--- a/media/libmediaplayerservice/TestPlayerStub.h
+++ b/media/libmediaplayerservice/TestPlayerStub.h
@@ -87,7 +87,11 @@
     virtual status_t stop()  {return mPlayer->stop();}
     virtual status_t pause()  {return mPlayer->pause();}
     virtual bool isPlaying() {return mPlayer->isPlaying();}
-    virtual status_t seekTo(int msec, bool precise = false) {return mPlayer->seekTo(msec, precise);}
+    virtual status_t seekTo(
+            int msec,
+            MediaPlayerSeekMode mode = MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC) {
+        return mPlayer->seekTo(msec, mode);
+    }
     virtual status_t getCurrentPosition(int *p)  {
         return mPlayer->getCurrentPosition(p);
     }
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
index 846d7a6..cf1f84b 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
@@ -608,8 +608,10 @@
           } else {
               timeUs = mVideoLastDequeueTimeUs;
           }
-          readBuffer(trackType, timeUs, false /* precise */, &actualTimeUs, formatChange);
-          readBuffer(counterpartType, -1, false /* precise */, NULL, !formatChange);
+          readBuffer(trackType, timeUs, MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC /* mode */,
+                  &actualTimeUs, formatChange);
+          readBuffer(counterpartType, -1, MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC /* mode */,
+                  NULL, !formatChange);
           ALOGV("timeUs %lld actualTimeUs %lld", (long long)timeUs, (long long)actualTimeUs);
 
           break;
@@ -688,7 +690,7 @@
     CHECK(msg->findInt64("timeUs", &timeUs));
 
     int64_t subTimeUs;
-    readBuffer(type, timeUs, false /* precise */, &subTimeUs);
+    readBuffer(type, timeUs, MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC /* mode */, &subTimeUs);
 
     int64_t delayUs = subTimeUs - timeUs;
     if (msg->what() == kWhatFetchSubtitleData) {
@@ -719,7 +721,7 @@
     }
 
     int64_t nextSubTimeUs;
-    readBuffer(type, -1, false /* precise */, &nextSubTimeUs);
+    readBuffer(type, -1, MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC /* mode */, &nextSubTimeUs);
 
     sp<ABuffer> buffer;
     status_t dequeueStatus = packets->dequeueAccessUnit(&buffer);
@@ -1110,10 +1112,10 @@
     return INVALID_OPERATION;
 }
 
-status_t NuPlayer::GenericSource::seekTo(int64_t seekTimeUs, bool precise) {
+status_t NuPlayer::GenericSource::seekTo(int64_t seekTimeUs, MediaPlayerSeekMode mode) {
     sp<AMessage> msg = new AMessage(kWhatSeek, this);
     msg->setInt64("seekTimeUs", seekTimeUs);
-    msg->setInt32("precise", precise);
+    msg->setInt32("mode", mode);
 
     sp<AMessage> response;
     status_t err = msg->postAndAwaitResponse(&response);
@@ -1126,12 +1128,12 @@
 
 void NuPlayer::GenericSource::onSeek(const sp<AMessage>& msg) {
     int64_t seekTimeUs;
-    int32_t precise;
+    int32_t mode;
     CHECK(msg->findInt64("seekTimeUs", &seekTimeUs));
-    CHECK(msg->findInt32("precise", &precise));
+    CHECK(msg->findInt32("mode", &mode));
 
     sp<AMessage> response = new AMessage;
-    status_t err = doSeek(seekTimeUs, precise);
+    status_t err = doSeek(seekTimeUs, (MediaPlayerSeekMode)mode);
     response->setInt32("err", err);
 
     sp<AReplyToken> replyID;
@@ -1139,7 +1141,7 @@
     response->postReply(replyID);
 }
 
-status_t NuPlayer::GenericSource::doSeek(int64_t seekTimeUs, bool precise) {
+status_t NuPlayer::GenericSource::doSeek(int64_t seekTimeUs, MediaPlayerSeekMode mode) {
     mBufferingMonitor->updateDequeuedBufferTime(-1ll);
 
     // If the Widevine source is stopped, do not attempt to read any
@@ -1152,9 +1154,9 @@
     }
     if (mVideoTrack.mSource != NULL) {
         int64_t actualTimeUs;
-        readBuffer(MEDIA_TRACK_TYPE_VIDEO, seekTimeUs, precise, &actualTimeUs);
+        readBuffer(MEDIA_TRACK_TYPE_VIDEO, seekTimeUs, mode, &actualTimeUs);
 
-        if (!precise) {
+        if (mode != MediaPlayerSeekMode::SEEK_CLOSEST) {
             seekTimeUs = actualTimeUs;
         }
         mVideoLastDequeueTimeUs = actualTimeUs;
@@ -1288,7 +1290,7 @@
 }
 
 void NuPlayer::GenericSource::readBuffer(
-        media_track_type trackType, int64_t seekTimeUs, bool precise,
+        media_track_type trackType, int64_t seekTimeUs, MediaPlayerSeekMode mode,
         int64_t *actualTimeUs, bool formatChange) {
     // Do not read data if Widevine source is stopped
     //
@@ -1330,7 +1332,7 @@
 
     bool seeking = false;
     if (seekTimeUs >= 0) {
-        options.setSeekTo(seekTimeUs, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
+        options.setSeekTo(seekTimeUs, mode);
         seeking = true;
     }
 
@@ -1383,7 +1385,8 @@
             }
             if (seeking && buffer != nullptr) {
                 sp<AMessage> meta = buffer->meta();
-                if (meta != nullptr && precise && seekTimeUs > timeUs) {
+                if (meta != nullptr && mode == MediaPlayerSeekMode::SEEK_CLOSEST
+                        && seekTimeUs > timeUs) {
                     sp<AMessage> extra = new AMessage;
                     extra->setInt64("resume-at-mediaTimeUs", seekTimeUs);
                     meta->setMessage("extra", extra);
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/GenericSource.h
index 7126153..38d8616 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.h
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.h
@@ -70,7 +70,9 @@
     virtual sp<AMessage> getTrackInfo(size_t trackIndex) const;
     virtual ssize_t getSelectedTrack(media_track_type type) const;
     virtual status_t selectTrack(size_t trackIndex, bool select, int64_t timeUs);
-    virtual status_t seekTo(int64_t seekTimeUs, bool precise = false) override;
+    virtual status_t seekTo(
+        int64_t seekTimeUs,
+        MediaPlayerSeekMode mode = MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC) override;
 
     virtual status_t setBuffers(bool audio, Vector<MediaBuffer *> &buffers);
 
@@ -251,7 +253,7 @@
     status_t doSelectTrack(size_t trackIndex, bool select, int64_t timeUs);
 
     void onSeek(const sp<AMessage>& msg);
-    status_t doSeek(int64_t seekTimeUs, bool precise);
+    status_t doSeek(int64_t seekTimeUs, MediaPlayerSeekMode mode);
 
     void onPrepareAsync();
 
@@ -273,14 +275,15 @@
 
     void postReadBuffer(media_track_type trackType);
     void onReadBuffer(const sp<AMessage>& msg);
-    // |precise| is a modifier of |seekTimeUs|.
-    // When |precise| is true, the buffer read shall include an item indicating skipping
-    // rendering all buffers with timestamp earlier than |seekTimeUs|.
-    // When |precise| is false, the buffer read will not include the item as above in order
+    // When |mode| is MediaPlayerSeekMode::SEEK_CLOSEST, the buffer read shall
+    // include an item indicating skipping rendering all buffers with timestamp
+    // earlier than |seekTimeUs|.
+    // For other modes, the buffer read will not include the item as above in order
     // to facilitate fast seek operation.
     void readBuffer(
             media_track_type trackType,
-            int64_t seekTimeUs = -1ll, bool precise = false,
+            int64_t seekTimeUs = -1ll,
+            MediaPlayerSeekMode mode = MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC,
             int64_t *actualTimeUs = NULL, bool formatChange = false);
 
     void queueDiscontinuityIfNeeded(
diff --git a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
index 1a6a233..51bfad4 100644
--- a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
@@ -214,8 +214,8 @@
     return (err == OK || err == BAD_VALUE) ? (status_t)OK : err;
 }
 
-status_t NuPlayer::HTTPLiveSource::seekTo(int64_t seekTimeUs, bool precise) {
-    return mLiveSession->seekTo(seekTimeUs, precise);
+status_t NuPlayer::HTTPLiveSource::seekTo(int64_t seekTimeUs, MediaPlayerSeekMode mode) {
+    return mLiveSession->seekTo(seekTimeUs, mode);
 }
 
 void NuPlayer::HTTPLiveSource::pollForRawData(
diff --git a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h
index 16c3c37..45fc8c1 100644
--- a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h
+++ b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h
@@ -47,7 +47,9 @@
     virtual sp<AMessage> getTrackInfo(size_t trackIndex) const;
     virtual ssize_t getSelectedTrack(media_track_type /* type */) const;
     virtual status_t selectTrack(size_t trackIndex, bool select, int64_t timeUs);
-    virtual status_t seekTo(int64_t seekTimeUs, bool precise = false) override;
+    virtual status_t seekTo(
+            int64_t seekTimeUs,
+            MediaPlayerSeekMode mode = MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC) override;
 
 protected:
     virtual ~HTTPLiveSource();
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index fb4656f..1476206 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -70,18 +70,18 @@
 };
 
 struct NuPlayer::SeekAction : public Action {
-    explicit SeekAction(int64_t seekTimeUs, bool precise)
+    explicit SeekAction(int64_t seekTimeUs, MediaPlayerSeekMode mode)
         : mSeekTimeUs(seekTimeUs),
-          mPrecise(precise) {
+          mMode(mode) {
     }
 
     virtual void execute(NuPlayer *player) {
-        player->performSeek(mSeekTimeUs, mPrecise);
+        player->performSeek(mSeekTimeUs, mMode);
     }
 
 private:
     int64_t mSeekTimeUs;
-    bool mPrecise;
+    MediaPlayerSeekMode mMode;
 
     DISALLOW_EVIL_CONSTRUCTORS(SeekAction);
 };
@@ -419,10 +419,10 @@
     (new AMessage(kWhatReset, this))->post();
 }
 
-void NuPlayer::seekToAsync(int64_t seekTimeUs, bool precise, bool needNotify) {
+void NuPlayer::seekToAsync(int64_t seekTimeUs, MediaPlayerSeekMode mode, bool needNotify) {
     sp<AMessage> msg = new AMessage(kWhatSeek, this);
     msg->setInt64("seekTimeUs", seekTimeUs);
-    msg->setInt32("precise", precise);
+    msg->setInt32("mode", mode);
     msg->setInt32("needNotify", needNotify);
     msg->post();
 }
@@ -681,7 +681,8 @@
                     int64_t currentPositionUs = 0;
                     if (getCurrentPosition(&currentPositionUs) == OK) {
                         mDeferredActions.push_back(
-                                new SeekAction(currentPositionUs, false /* precise */));
+                                new SeekAction(currentPositionUs,
+                                        MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC /* mode */));
                     }
                 }
 
@@ -1197,14 +1198,14 @@
         case kWhatSeek:
         {
             int64_t seekTimeUs;
-            int32_t precise;
+            int32_t mode;
             int32_t needNotify;
             CHECK(msg->findInt64("seekTimeUs", &seekTimeUs));
-            CHECK(msg->findInt32("precise", &precise));
+            CHECK(msg->findInt32("mode", &mode));
             CHECK(msg->findInt32("needNotify", &needNotify));
 
-            ALOGV("kWhatSeek seekTimeUs=%lld us, precise=%d, needNotify=%d",
-                    (long long)seekTimeUs, precise, needNotify);
+            ALOGV("kWhatSeek seekTimeUs=%lld us, mode=%d, needNotify=%d",
+                    (long long)seekTimeUs, mode, needNotify);
 
             if (!mStarted) {
                 // Seek before the player is started. In order to preview video,
@@ -1212,7 +1213,7 @@
                 // only once if needed. After the player is started, any seek
                 // operation will go through normal path.
                 // Audio-only cases are handled separately.
-                onStart(seekTimeUs, precise);
+                onStart(seekTimeUs, (MediaPlayerSeekMode)mode);
                 if (mStarted) {
                     onPause();
                     mPausedByClient = true;
@@ -1228,7 +1229,7 @@
                                            FLUSH_CMD_FLUSH /* video */));
 
             mDeferredActions.push_back(
-                    new SeekAction(seekTimeUs, precise));
+                    new SeekAction(seekTimeUs, (MediaPlayerSeekMode)mode));
 
             // After a flush without shutdown, decoder is paused.
             // Don't resume it until source seek is done, otherwise it could
@@ -1317,13 +1318,13 @@
     return OK;
 }
 
-void NuPlayer::onStart(int64_t startPositionUs, bool precise) {
+void NuPlayer::onStart(int64_t startPositionUs, MediaPlayerSeekMode mode) {
     if (!mSourceStarted) {
         mSourceStarted = true;
         mSource->start();
     }
     if (startPositionUs > 0) {
-        performSeek(startPositionUs, precise);
+        performSeek(startPositionUs, mode);
         if (mSource->getFormat(false /* audio */) == NULL) {
             return;
         }
@@ -1539,7 +1540,7 @@
         mRenderer->flush(false /* audio */, false /* notifyComplete */);
     }
 
-    performSeek(currentPositionUs, false /* precise */);
+    performSeek(currentPositionUs, MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC /* mode */);
 
     if (forceNonOffload) {
         mRenderer->signalDisableOffloadAudio();
@@ -1973,9 +1974,9 @@
     }
 }
 
-void NuPlayer::performSeek(int64_t seekTimeUs, bool precise) {
-    ALOGV("performSeek seekTimeUs=%lld us (%.2f secs), precise=%d",
-          (long long)seekTimeUs, seekTimeUs / 1E6, precise);
+void NuPlayer::performSeek(int64_t seekTimeUs, MediaPlayerSeekMode mode) {
+    ALOGV("performSeek seekTimeUs=%lld us (%.2f secs), mode=%d",
+          (long long)seekTimeUs, seekTimeUs / 1E6, mode);
 
     if (mSource == NULL) {
         // This happens when reset occurs right before the loop mode
@@ -1986,7 +1987,7 @@
         return;
     }
     mPreviousSeekTimeUs = seekTimeUs;
-    mSource->seekTo(seekTimeUs, precise);
+    mSource->seekTo(seekTimeUs, mode);
     ++mTimedTextGeneration;
 
     // everything's flushed, continue playback.
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h
index 3ae2ada..c8b0102 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h
@@ -70,7 +70,10 @@
 
     // Will notify the driver through "notifySeekComplete" once finished
     // and needNotify is true.
-    void seekToAsync(int64_t seekTimeUs, bool precise = false, bool needNotify = false);
+    void seekToAsync(
+            int64_t seekTimeUs,
+            MediaPlayerSeekMode mode = MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC,
+            bool needNotify = false);
 
     status_t setVideoScalingMode(int32_t mode);
     status_t getTrackInfo(Parcel* reply) const;
@@ -245,7 +248,9 @@
     void handleFlushComplete(bool audio, bool isDecoder);
     void finishFlushIfPossible();
 
-    void onStart(int64_t startPositionUs = -1, bool precise = false);
+    void onStart(
+            int64_t startPositionUs = -1,
+            MediaPlayerSeekMode mode = MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC);
     void onResume();
     void onPause();
 
@@ -263,7 +268,7 @@
 
     void processDeferredActions();
 
-    void performSeek(int64_t seekTimeUs, bool precise);
+    void performSeek(int64_t seekTimeUs, MediaPlayerSeekMode mode);
     void performDecoderFlush(FlushCommand audio, FlushCommand video);
     void performReset();
     void performScanSources();
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
index 7f287e3..3efa54c 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
@@ -208,7 +208,8 @@
             mAtEOS = false;
             mState = STATE_STOPPED_AND_PREPARING;
             mIsAsyncPrepare = false;
-            mPlayer->seekToAsync(0, false /* precise */, true /* needNotify */);
+            mPlayer->seekToAsync(0, MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC /* mode */,
+                    true /* needNotify */);
             while (mState == STATE_STOPPED_AND_PREPARING) {
                 mCondition.wait(mLock);
             }
@@ -233,7 +234,8 @@
             mAtEOS = false;
             mState = STATE_STOPPED_AND_PREPARING;
             mIsAsyncPrepare = true;
-            mPlayer->seekToAsync(0, false /* precise */, true /* needNotify */);
+            mPlayer->seekToAsync(0, MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC /* mode */,
+                    true /* needNotify */);
             return OK;
         default:
             return INVALID_OPERATION;
@@ -382,8 +384,8 @@
     return mPlayer->getSyncSettings(sync, videoFps);
 }
 
-status_t NuPlayerDriver::seekTo(int msec, bool precise) {
-    ALOGD("seekTo(%p) (%d ms, %d) at state %d", this, msec, precise, mState);
+status_t NuPlayerDriver::seekTo(int msec, MediaPlayerSeekMode mode) {
+    ALOGD("seekTo(%p) (%d ms, %d) at state %d", this, msec, mode, mState);
     Mutex::Autolock autoLock(mLock);
 
     int64_t seekTimeUs = msec * 1000ll;
@@ -398,7 +400,7 @@
             mSeekInProgress = true;
             // seeks can take a while, so we essentially paused
             notifyListener_l(MEDIA_PAUSED);
-            mPlayer->seekToAsync(seekTimeUs, precise, true /* needNotify */);
+            mPlayer->seekToAsync(seekTimeUs, mode, true /* needNotify */);
             break;
         }
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
index 034b3f9..317b34c 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
@@ -53,7 +53,8 @@
     virtual status_t getPlaybackSettings(AudioPlaybackRate *rate);
     virtual status_t setSyncSettings(const AVSyncSettings &sync, float videoFpsHint);
     virtual status_t getSyncSettings(AVSyncSettings *sync, float *videoFps);
-    virtual status_t seekTo(int msec, bool precise = false);
+    virtual status_t seekTo(
+            int msec, MediaPlayerSeekMode mode = MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC);
     virtual status_t getCurrentPosition(int *msec);
     virtual status_t getDuration(int *msec);
     virtual status_t reset();
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
index fe4fc63..5197167 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
@@ -104,8 +104,9 @@
         return INVALID_OPERATION;
     }
 
-    // Refer to comment of seekTo in IMediaPlayer.h for meaning of |precise|.
-    virtual status_t seekTo(int64_t /* seekTimeUs */, bool /* precise */ = false) {
+    virtual status_t seekTo(
+            int64_t /* seekTimeUs */,
+            MediaPlayerSeekMode /* mode */ = MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC) {
         return INVALID_OPERATION;
     }
 
diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
index f430f03..fb1f31a 100644
--- a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
@@ -279,11 +279,11 @@
     return OK;
 }
 
-status_t NuPlayer::RTSPSource::seekTo(int64_t seekTimeUs, bool precise) {
+status_t NuPlayer::RTSPSource::seekTo(int64_t seekTimeUs, MediaPlayerSeekMode mode) {
     sp<AMessage> msg = new AMessage(kWhatPerformSeek, this);
     msg->setInt32("generation", ++mSeekGeneration);
     msg->setInt64("timeUs", seekTimeUs);
-    msg->setInt32("precise", precise);
+    msg->setInt32("mode", mode);
 
     sp<AMessage> response;
     status_t err = msg->postAndAwaitResponse(&response);
@@ -466,12 +466,12 @@
         }
 
         int64_t seekTimeUs;
-        int32_t precise;
+        int32_t mode;
         CHECK(msg->findInt64("timeUs", &seekTimeUs));
-        CHECK(msg->findInt32("precise", &precise));
+        CHECK(msg->findInt32("mode", &mode));
 
-        // TODO: add "precise" to performSeek.
-        performSeek(seekTimeUs);
+        // TODO: add "mode" to performSeek.
+        performSeek(seekTimeUs/*, (MediaPlayerSeekMode)mode */);
         return;
     } else if (msg->what() == kWhatPollBuffering) {
         onPollBuffering();
diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.h b/media/libmediaplayerservice/nuplayer/RTSPSource.h
index b2962ed6..363f8bb 100644
--- a/media/libmediaplayerservice/nuplayer/RTSPSource.h
+++ b/media/libmediaplayerservice/nuplayer/RTSPSource.h
@@ -49,7 +49,9 @@
     virtual status_t dequeueAccessUnit(bool audio, sp<ABuffer> *accessUnit);
 
     virtual status_t getDuration(int64_t *durationUs);
-    virtual status_t seekTo(int64_t seekTimeUs, bool precise = false) override;
+    virtual status_t seekTo(
+            int64_t seekTimeUs,
+            MediaPlayerSeekMode mode = MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC) override;
 
     void onMessageReceived(const sp<AMessage> &msg);
 
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index cf0a031..21c90f0 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -1201,6 +1201,10 @@
         info.mDequeuedAt = mDequeueCounter;
 
         info.mData = new MediaCodecBuffer(mOutputFormat, new ABuffer(bufferSize));
+
+        // Initialize fence fd to -1 to avoid warning in freeBuffer().
+        ((VideoNativeMetadata *)info.mData->base())->nFenceFd = -1;
+
         info.mCodecData = info.mData;
 
         err = mOMXNode->useBuffer(kPortIndexOutput, OMXBuffer::sPreset, &info.mBufferID);
@@ -1836,11 +1840,8 @@
                         inputFormat->setInt32("adaptive-playback", true);
                     }
                 }
-                // Fall back to legacy mode (use fixed ANWBuffer)
-                err = setPortMode(kPortIndexOutput, IOMX::kPortModePresetANWBuffer);
-                if (err != OK) {
-                    return err;
-                }
+                // allow failure
+                err = OK;
             } else {
                 ALOGV("[%s] setPortMode on output to %s succeeded",
                         mComponentName.c_str(), asString(IOMX::kPortModeDynamicANWBuffer));
@@ -1873,6 +1874,12 @@
         if (haveNativeWindow && mComponentName.startsWith("OMX.google.")) {
             usingSwRenderer = true;
             haveNativeWindow = false;
+            (void)setPortMode(kPortIndexOutput, IOMX::kPortModePresetByteBuffer);
+        } else if (haveNativeWindow && !storingMetadataInDecodedBuffers()) {
+            err = setPortMode(kPortIndexOutput, IOMX::kPortModePresetANWBuffer);
+            if (err != OK) {
+                return err;
+            }
         }
 
         if (encoder) {
@@ -1887,10 +1894,8 @@
 
         if (haveNativeWindow) {
             mNativeWindow = static_cast<Surface *>(obj.get());
-        }
 
-        // fallback for devices that do not handle flex-YUV for native buffers
-        if (haveNativeWindow) {
+            // fallback for devices that do not handle flex-YUV for native buffers
             int32_t requestedColorFormat = OMX_COLOR_FormatUnused;
             if (msg->findInt32("color-format", &requestedColorFormat) &&
                     requestedColorFormat == OMX_COLOR_FormatYUV420Flexible) {
@@ -5258,7 +5263,7 @@
             ALOGE_IF("[%s] failed to release codec instance: err=%d",
                        mCodec->mComponentName.c_str(), err);
             sp<AMessage> notify = mCodec->mNotify->dup();
-            notify->setInt32("what", CodecBase::kWhatShutdownCompleted);
+            notify->setInt32("what", CodecBase::kWhatReleaseCompleted);
             notify->post();
             break;
         }
@@ -6147,7 +6152,8 @@
                      "cannot keep component allocated on shutdown in Uninitialized state");
 
             sp<AMessage> notify = mCodec->mNotify->dup();
-            notify->setInt32("what", CodecBase::kWhatShutdownCompleted);
+            notify->setInt32("what", keepComponentAllocated ?
+                    CodecBase::kWhatStopCompleted : CodecBase::kWhatReleaseCompleted);
             notify->post();
 
             handled = true;
@@ -6344,7 +6350,8 @@
 
     if (mCodec->mExplicitShutdown) {
         sp<AMessage> notify = mCodec->mNotify->dup();
-        notify->setInt32("what", CodecBase::kWhatShutdownCompleted);
+        notify->setInt32("what", keepComponentAllocated ?
+                CodecBase::kWhatStopCompleted : CodecBase::kWhatReleaseCompleted);
         notify->post();
         mCodec->mExplicitShutdown = false;
     }
@@ -7346,8 +7353,7 @@
 
         case kWhatShutdown:
         {
-            // We're already doing that...
-
+            mCodec->deferMessage(msg);
             handled = true;
             break;
         }
@@ -7456,8 +7462,7 @@
     switch (msg->what()) {
         case kWhatShutdown:
         {
-            // We're already doing that...
-
+            mCodec->deferMessage(msg);
             handled = true;
             break;
         }
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index f2dfca7..5382689 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -1550,19 +1550,26 @@
                     break;
                 }
 
-                case CodecBase::kWhatShutdownCompleted:
+                case CodecBase::kWhatStopCompleted:
                 {
-                    if (mState == UNINITIALIZED) {
-                        // Ignore shutdown complete if we're already released.
+                    if (mState != STOPPING) {
+                        ALOGW("Received kWhatStopCompleted in state %d", mState);
                         break;
                     }
-                    if (mState == STOPPING) {
-                        setState(INITIALIZED);
-                    } else {
-                        CHECK_EQ(mState, RELEASING);
-                        setState(UNINITIALIZED);
-                        mComponentName.clear();
+                    setState(INITIALIZED);
+                    (new AMessage)->postReply(mReplyID);
+                    break;
+                }
+
+                case CodecBase::kWhatReleaseCompleted:
+                {
+                    if (mState != RELEASING) {
+                        ALOGW("Received kWhatReleaseCompleted in state %d", mState);
+                        break;
                     }
+                    setState(UNINITIALIZED);
+                    mComponentName.clear();
+
                     mFlags &= ~kFlagIsComponentAllocated;
 
                     mResourceManagerService->removeResource(getId(mResourceManagerClient));
@@ -2355,8 +2362,6 @@
         if (info->mNotify != NULL) {
             sp<AMessage> msg = info->mNotify;
             info->mNotify = NULL;
-            msg->setObject("buffer", (portIndex == kPortIndexInput && mCrypto != NULL)
-                    ? info->mSecureData : info->mData);
             if (isReclaim && info->mOwnedByClient) {
                 ALOGD("port %d buffer %zu still owned by client when codec is reclaimed",
                         portIndex, i);
diff --git a/media/libstagefright/filters/MediaFilter.cpp b/media/libstagefright/filters/MediaFilter.cpp
index 30e3643..877aead 100644
--- a/media/libstagefright/filters/MediaFilter.cpp
+++ b/media/libstagefright/filters/MediaFilter.cpp
@@ -676,7 +676,8 @@
     }
 
     sp<AMessage> notify = mNotify->dup();
-    notify->setInt32("what", CodecBase::kWhatShutdownCompleted);
+    notify->setInt32("what", keepComponentAllocated ?
+            CodecBase::kWhatStopCompleted : CodecBase::kWhatReleaseCompleted);
     notify->post();
 }
 
diff --git a/media/libstagefright/foundation/tests/Android.mk b/media/libstagefright/foundation/tests/Android.mk
new file mode 100644
index 0000000..e7598ca
--- /dev/null
+++ b/media/libstagefright/foundation/tests/Android.mk
@@ -0,0 +1,33 @@
+# Build the unit tests.
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+
+LOCAL_MODULE := sf_foundation_test
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := \
+	Flagged_test.cpp \
+	TypeTraits_test.cpp \
+	Utils_test.cpp \
+
+LOCAL_SHARED_LIBRARIES := \
+	libstagefright_foundation \
+
+LOCAL_C_INCLUDES := \
+	frameworks/av/include \
+
+LOCAL_CFLAGS += -Werror -Wall
+LOCAL_CLANG := true
+
+include $(BUILD_NATIVE_TEST)
+
+# Include subdirectory makefiles
+# ============================================================
+
+# If we're building with ONE_SHOT_MAKEFILE (mm, mmm), then what the framework
+# team really wants is to build the stuff defined by this makefile.
+ifeq (,$(ONE_SHOT_MAKEFILE))
+include $(call first-makefiles-under,$(LOCAL_PATH))
+endif
diff --git a/media/libstagefright/foundation/tests/Flagged_test.cpp b/media/libstagefright/foundation/tests/Flagged_test.cpp
new file mode 100644
index 0000000..3c90699
--- /dev/null
+++ b/media/libstagefright/foundation/tests/Flagged_test.cpp
@@ -0,0 +1,639 @@
+/*
+ * Copyright 2016 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 "Flagged_test"
+
+#include <gtest/gtest.h>
+
+#include <media/stagefright/foundation/Flagged.h>
+
+namespace android {
+
+/**
+ * Helper template that can be used to print values in static_assert error messages.
+ *
+ * Use integers here.
+ */
+template<bool, int ...N>
+struct _print_as_warning { };
+
+template<int ...N>
+struct _print_as_warning<true, N...> : std::true_type { };
+
+#define static_assert_equals(a, b, msg) \
+static_assert(_print_as_warning<(a) == (b), a, b>::value, msg)
+
+class FlaggedTest : public ::testing::Test {
+protected:
+    // empty structs
+    struct A0 { };
+    struct A1 { };
+    struct A_A0 : public A0 { };
+
+    // simple struct
+    struct BB {
+        int32_t i;
+        uint32_t u;
+    };
+
+    // struct inheriting from A0
+    struct BB_A0 : public A0 {
+        int32_t i;
+        uint32_t u;
+    };
+
+    // struct inheriting from struct inheriting A0
+    struct BB_AA0 : public A_A0 {
+        int32_t i;
+        uint32_t u;
+    };
+
+    // struct that wraps
+    struct WBBA0 {
+        BB_A0 b;
+    };
+
+    struct WBBA0_A1 : public A1 {
+        BB_A0 b;
+    };
+
+    struct WBBA0_A0 : public A0 {
+        BB_A0 b;
+    };
+
+    struct WBB_A0 : public A0 {
+        BB b;
+    };
+
+    struct WBBA0_AA0 : public A_A0 {
+        BB_A0 b;
+    };
+
+    struct WBBAA0_A0 : public A0 {
+        BB_AA0 b;
+    };
+
+    struct WWBBA0_A0 : public A0 {
+        WBBA0 b;
+    };
+};
+
+/**
+ * This test is here to confirm the handling of wrapping classes that inherit from an interface
+ * while also inheriting from that same interface. While we no longer use this construct, we want
+ * to track if this defect is ever fixed.
+ */
+TEST_F(FlaggedTest, StaticSanityTests) {
+    static_assert(sizeof(A0) == 1, "");
+    static_assert(sizeof(A1) == 1, "");
+    static_assert(sizeof(A_A0) == 1, "");
+
+    static constexpr size_t size = sizeof(BB); // original [pair]
+
+    // inheriting from A0 does not increase size
+    static_assert(sizeof(BB_A0) == size, ""); // [pair]:A0
+    static_assert(sizeof(BB_AA0) == size, ""); // [pair]:[:A0]
+
+     // wrapping a class that inherits from A0 does not increase size
+    static_assert(sizeof(WBBA0) == size, ""); // [ [pair]:[:A0] ]
+
+    // wrapping a class that inherits from A0 while also inheriting from A1 does not increase size
+    static_assert(sizeof(WBBA0_A1) == size, ""); // [ [pair]:A0 ]:A1
+
+    // wrapping a class that inherits from A0 while also inheriting from A0 DOES increase size
+    EXPECT_GT(sizeof(WBBA0_A0), size); // [ [pair]:A0 ]:A0
+
+    // wrapping a class that does not inherit from A0 while inheriting from A0 does not increase
+    // size
+    static_assert(sizeof(WBB_A0) == size, ""); // [[pair]]:A0
+
+    // wrapping a class that inherits from A0 while also inheriting from a class that inherits
+    // from A0 does increase size
+    EXPECT_GT(sizeof(WBBA0_AA0), size); // [ [pair]:A0 ]:[:A0]
+
+    // wrapping a class that indirectly inherits from A0 while also inheriting from A0 does
+    // increase size
+    EXPECT_GT(sizeof(WBBAA0_A0), size); // [ [pair]:[:A0] ]:A0
+
+    // wrapping a class that inherits from A0 while also inheriting A0 does increase size
+    EXPECT_GT(sizeof(WWBBA0_A0), size); //  [ [pair]:A0 ]:A0
+}
+
+enum FLAG : int32_t {
+    kMask0 = 0x0FF,
+    kFlag0_A = 0x0AA,
+    kFlag0_B = 0x0BB,
+    kFlag0_C = 0x0CC,
+    kMask1 = 0xFF0,
+    kFlag1_A = 0xAA0,
+    kFlag1_B = 0xBB0,
+    kFlag1_C = 0xCC0,
+    kMaskCommon = 0x0F0,
+};
+
+TEST_F(FlaggedTest, BasicExample) {
+    enum SafeFlags : uint32_t {
+      kUnsafe,
+      kSafe,
+      kSafeMask = _Flagged_helper::minMask(kSafe),
+    };
+    typedef Flagged<int32_t, SafeFlags, kSafeMask> safeInt32;
+
+    safeInt32 a(kUnsafe);
+    a.setFlags(kSafe);
+    a.get() = 15;
+    EXPECT_EQ(a.flags(), kSafe);
+    EXPECT_EQ(a.get(), 15);
+
+    enum OriginFlags : uint32_t {
+      kUnknown,
+      kConst,
+      kCalculated,
+      kComponent,
+      kApplication,
+      kFile,
+      kBinder,
+      kOriginMask = _Flagged_helper::minMask(kBinder),
+    };
+    typedef Flagged<safeInt32, OriginFlags, kOriginMask>
+             trackedSafeInt32;
+
+    static_assert(sizeof(trackedSafeInt32) == sizeof(safeInt32), "");
+
+    trackedSafeInt32 b(kConst, kSafe, 1);
+    EXPECT_EQ(b.flags(), kConst);
+    EXPECT_EQ(b.get().flags(), kSafe);
+    EXPECT_EQ(b.get().get(), 1);
+    b.setFlags(kCalculated);
+    volatile bool overflow = true;
+    b.get().setFlags(overflow ? kUnsafe : kSafe);
+
+    enum ValidatedFlags : uint32_t {
+      kUnsafeV = kUnsafe,
+      kSafeV = kSafe,
+      kValidated = kSafe | 2,
+      kSharedMaskV = kSafeMask,
+      kValidatedMask = _Flagged_helper::minMask(kValidated),
+    };
+    typedef Flagged<safeInt32, ValidatedFlags, kValidatedMask, kSharedMaskV> validatedInt32;
+
+    validatedInt32 v(kUnsafeV, kSafe, 10);
+    EXPECT_EQ(v.flags(), kUnsafeV);
+    EXPECT_EQ(v.get().flags(), kUnsafe);  // !kUnsafeV overrides kSafe
+    EXPECT_EQ(v.get().get(), 10);
+    v.setFlags(kValidated);
+    EXPECT_EQ(v.flags(), kValidated);
+    EXPECT_EQ(v.get().flags(), kSafe);
+    v.get().setFlags(kUnsafe);
+    EXPECT_EQ(v.flags(), 2);  // NOTE: sharing masks with enums allows strange situations to occur
+}
+
+TEST_F(FlaggedTest, _Flagged_helper_Test) {
+    using helper = _Flagged_helper;
+
+    using i32 = int32_t;
+    using u32 = uint32_t;
+    using u8 = uint8_t;
+
+    // base2
+    static_assert(Flagged<i32, u32, 0u, 0u, 0>::sFlagMask == 0u, "");
+    static_assert(Flagged<i32, u32, 0u, 0u, 0>::sFlagShift == 0, "");
+    static_assert(Flagged<i32, u32, 0u, 0u, 0>::sEffectiveMask == 0u, "");
+
+    static_assert(Flagged<i32, u32, 0u, 0u, 10>::sFlagMask == 0u, "");
+    static_assert(Flagged<i32, u32, 0u, 0u, 10>::sFlagShift == 10, "");
+    static_assert(Flagged<i32, u32, 0u, 0u, 10>::sEffectiveMask == 0u, "");
+
+    static_assert(Flagged<i32, u32, 0u, 0u, -1>::sFlagMask == 0u, "");
+    static_assert(Flagged<i32, u32, 0u, 0u, -1>::sFlagShift == 0, "");
+    static_assert(Flagged<i32, u32, 0u, 0u, -1>::sEffectiveMask == 0u, "");
+
+    static_assert(Flagged<i32, u32, 99u, 0u, 0>::sFlagMask == 99u, "");
+    static_assert(Flagged<i32, u32, 99u, 0u, 0>::sFlagShift == 0, "");
+    static_assert(Flagged<i32, u32, 99u, 0u, 0>::sEffectiveMask == 99u, "");
+
+    static_assert(Flagged<i32, u32, 0x99u, 0u, 12>::sFlagMask == 0x99u, "");
+    static_assert(Flagged<i32, u32, 0x99u, 0u, 12>::sFlagShift == 12, "");
+    static_assert(Flagged<i32, u32, 0x99u, 0u, 12>::sEffectiveMask == 0x99000u, "");
+
+    static_assert(Flagged<i32, u32, 99u, 0u, -1>::sFlagMask == 99u, "");
+    static_assert(Flagged<i32, u32, 99u, 0u, -1>::sFlagShift == 0, "");
+    static_assert(Flagged<i32, u32, 99u, 0u, -1>::sEffectiveMask == 99u, "");
+
+    // mask_of<T, Flag>
+    // also Flagged<> no default
+    typedef Flagged<i32, u32, 0x800F /* mask */, 0 /* shared mask */, 0 /* shift */> i32_800f_0;
+    typedef Flagged<i32, u32, 0x800F /* mask */, 0 /* shared mask */, 4 /* shift */> i32_800f_4;
+    // this also tests that these types can be instantiated
+    static_assert(sizeof(i32_800f_0) >= sizeof(i32) + sizeof(u32),
+                  "should be at least size of component types");
+    static_assert(sizeof(i32_800f_4) == sizeof(i32_800f_0), "regardless of shift");
+    static_assert(!i32_800f_0::sFlagCombined, "");
+    static_assert(!i32_800f_4::sFlagCombined, "");
+
+    static_assert(helper::mask_of<i32_800f_0, u32>::value == 0x800F, "incorrect mask");
+    static_assert(helper::mask_of<i32_800f_0, i32>::value == 0,
+                  "mask should be 0 when types mismatch");
+    static_assert(helper::mask_of<i32_800f_0, u32>::effective_value == 0x800F, "incorrect mask");
+    static_assert(helper::mask_of<i32_800f_0, i32>::effective_value == 0,
+                  "mask should be 0 when types mismatch");
+    static_assert(helper::mask_of<i32_800f_0, u32>::shift == 0, "incorrect shift");
+    static_assert(helper::mask_of<i32_800f_0, i32>::shift == 0,
+                  "shift should be 0 when types mismatch");
+
+    static_assert(helper::mask_of<i32_800f_4, u32>::value == 0x800F, "incorrect mask");
+    static_assert(helper::mask_of<i32_800f_4, i32>::value == 0,
+                  "mask should be 0 when types mismatch");
+    static_assert(helper::mask_of<i32_800f_4, u32>::effective_value == 0x800F0, "incorrect mask");
+    static_assert(helper::mask_of<i32_800f_4, i32>::effective_value == 0,
+                  "mask should be 0 when types mismatch");
+    static_assert(helper::mask_of<i32_800f_4, u32>::shift == 4, "incorrect shift");
+    static_assert(helper::mask_of<i32_800f_4, i32>::shift == 0,
+                  "shift should be 0 when types mismatch");
+    static_assert(helper::mask_of<i32, u32>::value == 0, "mask should be 0 if not masked");
+    static_assert(helper::mask_of<i32, i32>::value == 0, "mask should be 0 if not masked");
+
+    // lshift(value, n)
+    static_assert(helper::lshift(0U, 0) == 0U, "");
+    static_assert(helper::lshift(0U, 30) == 0U, "");
+    static_assert(helper::lshift(1U, 0) == 1U, "");
+    static_assert(helper::lshift(1U, 10) == 1024U, "");
+    static_assert(helper::lshift(10U, 10) == 10240U, "");
+    static_assert(helper::lshift(10, 10) == 10240, "");
+    static_assert(helper::lshift(-10, 0) == -10, "");
+    // static_assert(helper::lshift(-10, 10) == -10240, ""); // error: left shift of negative value
+
+    // minMask(maxValue)
+    static_assert(helper::minMask(0U) == 0U, "lowest 0 bits");
+    static_assert(helper::minMask(1U) == 1U, "lowest 1 bit");
+    static_assert(helper::minMask(2U) == 3U, "lowest 2 bits");
+    static_assert(helper::minMask(3U) == 3U, "lowest 2 bits");
+    static_assert(helper::minMask(4U) == 7U, "lowest 3 bits");
+    static_assert(helper::minMask(~0U) == ~0U, "all bits");
+    // static_assert(helper::minMask(10) == 0xF, "all bits"); // error: must be unsigned
+
+    // topBits(n)
+    static_assert(helper::topBits<u32>(0) == 0U, "top 0 bit");
+    static_assert(helper::topBits<u32>(1) == 0x80000000U, "top 1 bit");
+    static_assert(helper::topBits<u32>(2) == 0xC0000000U, "top 2 bits");
+    static_assert(helper::topBits<u32>(12) == 0xFFF00000U, "top 12 bits");
+    static_assert(helper::topBits<u32>(32) == 0xFFFFFFFFU, "all bits");
+    // static_assert(helper::topBits<u32>(33) == 0xFFFFFFFFU, ""); // should OVERFLOW
+
+    static_assert(helper::topBits<u8>(0) == 0U, "top 0 bit");
+    static_assert(helper::topBits<u8>(1) == 0x80U, "top 1 bit");
+    static_assert(helper::topBits<u8>(2) == 0xC0U, "top 2 bit");
+    static_assert(helper::topBits<u8>(8) == 0xFFU, "all bits");
+    // static_assert(helper::topBits<u8>(9) == 0xFFU, ""); // should OVERFLOW
+
+    // getShift(mask, base, shared, base-shift, base-effective)
+    static_assert(helper::getShift(0u, 0u, 0u, 0, 0u) == 0, "no flag require no shift");
+    static_assert(helper::getShift(0u, 0u, 1u, 0, 0u) == -1,
+                  "shared must be within mask and base mask");
+    static_assert(helper::getShift(0u, 1u, 1u, 0, 1u) == -1, "shared must be within mask");
+    static_assert(helper::getShift(0u, 1u, 0u, 0, 1u) == 0,
+                  "no flags require no shift even with base mask");
+    static_assert(helper::getShift(0u, 1u, 0u, 1, 2u) == 0,
+                  "no flags require no shift even with shifted base mask");
+    static_assert(helper::getShift(1u, 0u, 0u, 0, 0u) == 0, "no base mask requires no shift");
+    static_assert(helper::getShift(1u, 1u, 0u, 0, 1u) == 1,
+                  "overlapping mask and basemask requires shift");
+    static_assert(helper::getShift(1u, 1u, 0u, 0, 1u) == 1,
+                  "overlapping mask and basemask requires shift");
+    static_assert(helper::getShift(1u, 1u, 1u, 0, 1u) == 0,
+                  "shared mask requires using base shift");
+    static_assert(helper::getShift(1u, 1u, 1u, 1, 2u) == 1,
+                  "shared mask requires using base shift");
+    static_assert(helper::getShift(3u, 5u, 1u, 0, 5u) == 0,
+                  "mask and basemask that overlap only in shared region requires no shift");
+    static_assert(helper::getShift(3u, 7u, 1u, 0, 7u) == -1,
+                  "mask and basemask must not overlap in more than shared region");
+    static_assert(helper::getShift(1u, 0u, 1u, 0, 0u) == -1, "shared must be within base mask");
+
+    static_assert(helper::getShift(0u, 1u, 0u, 1, 1u) == -2, "effective mask must cover base mask");
+    static_assert(helper::getShift(0u, 5u, 0u, 1, 2u) == -2, "effective mask must cover base mask");
+    static_assert(helper::getShift(0u, 5u, 0u, 1, 10u) == 0, "");
+    static_assert(helper::getShift(0u, 5u, 0u, 1, 31u) == 0,
+                  "effective mask can be larger than base mask");
+
+    static_assert(helper::getShift(0x800Fu, 0x800Fu, 0x800Fu, 0, 0x800Fu) == 0,
+                  "(0x800F << 0) & 0x800F == 0x800F");
+    static_assert(helper::getShift(0x800Fu, 0x800Fu, 0x800Fu, 16, 0x800F0000u) == 16,
+                  "(0x800F << 0) & 0x800F == 0x800F");
+    static_assert(helper::getShift(0x1800Fu, 0x800Fu, 0x800Fu, 0, 0x800Fu) == 0,
+                  "(0x1800F << 0) & 0x800F == 0x800F");
+    static_assert(helper::getShift(0x1800Fu, 0x800Fu, 0x800Fu, 16, 0x800F0000u) == -1,
+                  "(0x1800F << 16) overflows");
+
+    // verify that when not sharing masks, effective mask makes the difference
+    static_assert(helper::getShift(0x800Fu, 0u, 0u, 0, 0x800Fu) == 4,
+                  "(0x800F << 4) & 0x800F == 0");
+    static_assert(helper::getShift(0x800Fu, 0x2u, 0u, 0, 0x8002u) == 2,
+                  "(0x800F << 2) & 0x8002 == 0");
+    static_assert(helper::getShift(0x800Fu, 0x1u, 0u, 15, 0x8001u) == 1,
+                  "(0x800F << 1) & 0x8001 == 0");
+    static_assert(helper::getShift(0x800Fu, 0x800Fu, 0u, 16, 0x800F0000u) == 0,
+                  "0x800F & 0x800F0000 == 0");
+    static_assert(helper::getShift(0x800Fu, 0x800F8000u, 0u, 0, 0x800F8000u) == 5,
+                  "(0x800F << 5) & 0x800F8000 == 0");
+    static_assert(helper::getShift(0x800Fu, 0xF0000u, 0u, 0, 0x800F8000u) == 5,
+                  "(0x800F << 5) & 0x800F8000 == 0");
+    static_assert(helper::getShift(0x800Fu, 0x1Fu, 0u, 15, 0x800F8000u) == 5,
+                  "(0x800F << 5) & 0x800F8000 == 0");
+    static_assert(helper::getShift(0xFFu, 0x80808080u, 0u, 0, 0x80808080u) == -1,
+                  "0xFF always overlaps with 0x80808080");
+    static_assert(helper::getShift(0xFFu, 0x10001000u, 0u, 3, 0x80808080u) == -1,
+                  "0xFF always overlaps with 0x80808080");
+    static_assert(helper::getShift(0xFFu, 0x80808040u, 0u, 0, 0x80808040u) == 7,
+                  "(0xFF << 7) & 0x 80808040 == 0");
+
+    // verify min_shift (mask must be positive or no shift can be required)
+    static_assert(helper::getShift(0xFF, 0x40808040, 0, 0, 0x40808040) == 7, "");
+    static_assert(helper::getShift((i32)0x800000FF, 0x40808040, 0, 0, 0x40808040) == -1, "");
+    static_assert(helper::getShift(0x100000FF, 0x40808040, 0, 0, 0x40808040) == -1, "");
+    static_assert(helper::getShift(0xFF, (i32)0x80808040, 0, 0, (i32)0x80808040) == 7, "");
+    static_assert(helper::getShift((i32)0x80007F80, 0x40808040, 0, 0, 0x40808040) == 0, "");
+
+    // shared mask can also be negative (but not shift can be required)
+    static_assert(helper::getShift((i32)0x80007F80, (i32)0xC0808040, (i32)0x80000000,
+                                   0, (i32)0xC0808040) == 0, "");
+    static_assert(helper::getShift((i32)0x80007F80, (i32)0xC0808040, (i32)0xC0000000,
+                                   0, (i32)0xC0808040) == -1, "");
+    static_assert(helper::getShift((i32)0x80007F80, (i32)0x60404020, (i32)0x60000000,
+                                   1, (i32)0xC0808040) == -1, "");
+
+    // min_shift
+    typedef Flagged<i32, u32, 0u> i32_0_0;
+    typedef Flagged<i32, u32, 1u> i32_1_0;
+    typedef Flagged<i32, u32, 1u, 0u, 1> i32_1_1;
+
+    // this is a wrapper over getShift, so same test cases apply when T is flagged
+    static_assert(helper::min_shift<i32_0_0, u32, 0u, 0u>::value == 0, "");
+    static_assert(helper::min_shift<i32_0_0, u32, 0u, 1u>::value == -1, "");
+    static_assert(helper::min_shift<i32_1_0, u32, 0u, 1u>::value == -1, "");
+    static_assert(helper::min_shift<i32_1_0, u32, 0u, 0u>::value == 0, "");
+    static_assert(helper::min_shift<i32_0_0, u32, 1u, 0u>::value == 0, "");
+    static_assert(helper::min_shift<i32_1_0, u32, 1u, 0u>::value == 1, "");
+    static_assert(helper::min_shift<i32_1_0, u32, 1u, 1u>::value == 0, "");
+    static_assert(helper::min_shift<i32_1_1, u32, 1u, 1u>::value == 1, "");
+    static_assert(helper::min_shift<i32_1_1, u32, 3u, 0u>::value == 2, "");
+    static_assert(helper::min_shift<Flagged<i32, u32, 5u>, u32, 3u, 1u>::value == 0, "");
+    static_assert(helper::min_shift<Flagged<i32, u32, 7u>, u32, 3u, 1u>::value == -1, "");
+    static_assert(helper::min_shift<i32_0_0, u32, 1u, 1u>::value == -1, "");
+
+    static_assert(helper::min_shift<i32_800f_0, u32, 0x800Fu, 0u>::value == 4, "");
+    static_assert(helper::min_shift<i32_800f_4, u32, 0x1800Fu, 0x800Fu>::value == 4, "");
+    static_assert(helper::min_shift<i32_800f_4, u32, 0x800Fu, 0u>::value == 0, "");
+    static_assert(helper::min_shift<Flagged<i32, u32, 0x8002u>, u32, 0x800Fu, 0u>::value == 2, "");
+    static_assert(helper::min_shift<Flagged<i32, u32, 0x8001u>, u32, 0x800Fu, 0u>::value == 1, "");
+    static_assert(
+            helper::min_shift<Flagged<i32, u32, 0x800Fu, 0u, 16>, u32, 0x800Fu, 0u>::value == 0, "");
+    static_assert(
+            helper::min_shift<Flagged<i32, u32, 0x800F8000u>, u32, 0x800Fu, 0u>::value == 5, "");
+    static_assert(
+            helper::min_shift<Flagged<i32, u32, 0x80808080u>, u32, 0xFFu, 0u>::value == -1, "");
+    static_assert(
+            helper::min_shift<Flagged<i32, u32, 0x80808040u>, u32, 0xFFu, 0u>::value == 7, "");
+
+    // for min_shift, non-tagged type behaves as if having base mask of 0
+    static_assert(helper::min_shift<i32, u32, 0u, 0u>::value == 0, "");
+    static_assert(helper::min_shift<u32, u32, 0u, 0u>::value == 0, "");
+    static_assert(helper::min_shift<i32, u32, 0u, 0u>::value == 0, "");
+    static_assert(helper::min_shift<i32, u32, 0u, 1u>::value == -1, "");
+    static_assert(helper::min_shift<i32, u32, 1u, 0u>::value == 0, "");
+    static_assert(helper::min_shift<i32, u32, 1u, 1u>::value == -1, "");
+
+    // verify min_shift (mask must be positive or no shift can be required)
+    static_assert(helper::min_shift<Flagged<i32, i32, 0x40808040>, i32, 0xFF, 0>::value == 7, "");
+    static_assert(helper::min_shift<Flagged<i32, i32, 0x40808040>,
+                                    i32, (i32)0x800000FF, 0>::value == -1, "");
+    static_assert(helper::min_shift<Flagged<i32, i32, 0x40808040>,
+                                    i32, 0x100000FF, 0>::value == -1, "");
+    static_assert(helper::min_shift<Flagged<i32, i32, (i32)0x80808040>,
+                                    i32, 0xFF, 0>::value == 7, "");
+    static_assert(helper::min_shift<Flagged<i32, i32, 0x40808040>,
+                                    i32, (i32)0x80007F80, 0>::value == 0, "");
+
+    static_assert(helper::min_shift<Flagged<i32, i32, (i32)0x80808040>,
+                                    i32, (i32)0x80007F80, (i32)0x80000000>::value == 0, "");
+    static_assert(helper::min_shift<Flagged<i32, i32, (i32)0xC0808040>,
+                                    i32, (i32)0x80007F80, (i32)0xC0000000>::value == -1, "");
+    // note: cannot create a flagged type with signed flag and shift
+    // static_assert(helper::min_shift<Flagged<i32, i32, (i32)0x60404020, 0, 1>,
+    //                                i32, (i32)0x40003FC0, (i32)0x40000000>::value == -1, "");
+
+    typedef Flagged<i32, u32, 0x800F /* mask */, 0 /* shared mask */, 16 /* shift */> i32_800f_16;
+    static_assert_equals(sizeof(i32_800f_16), sizeof(i32_800f_0), "");
+    // shifted mask overflows!
+    // typedef Flagged<i32, u32, 0x800F /* mask */, 0 /* shared mask */, 17 /* shift */> i32_800f_17;
+    // static_assert(sizeof(i32_800f_17) == sizeof(i32_800f_0), "");
+    typedef Flagged<i32, i32, 0x800F /* mask */, 0 /* shared mask */, 15 /* shift */> i32_800f_15i;
+    static_assert_equals(sizeof(i32_800f_15i), sizeof(i32_800f_0), "");
+    // shifted mask overflows!
+    // typedef Flagged<i32, i32, 0x800F /* mask */, 0 /* shared mask */, 16 /* shift */> i32_800f_16i;
+    // static_assert(sizeof(i32_800f_16i) == sizeof(i32_800f_0), "");
+
+    // canCombine(mask, base, shared, shift, base-shift, base-effective)
+    static_assert(helper::canCombine(0u, 0u, 0u, 0, 0, 0u), "using no mask is valid");
+    static_assert(helper::canCombine(0u, 0u, 0u, 0, 0, 0u), "");
+    static_assert(helper::canCombine(0u, 0u, 0u, 4, 0, 0u), "");
+    static_assert(!helper::canCombine(0u, 0u, 1u, 0, 0, 0u),
+                  "shared mask must be the overlap of masks");
+    static_assert(helper::canCombine(1u, 0u, 0u, 0, 0, 0u), "");
+    static_assert(helper::canCombine(1u, 0u, 0u, 4, 0, 0u), "");
+    static_assert(helper::canCombine(3u, 5u, 1u, 0, 0, 5u), "");
+    static_assert(!helper::canCombine(3u, 3u, 3u, 1, 0, 3u), "shift must match when sharing mask");
+    static_assert(helper::canCombine(3u, 3u, 3u, 1, 1, 6u), "");
+    static_assert(!helper::canCombine(3u, 3u, 3u, 1, 2, 12u), "shift must match when sharing mask");
+    static_assert(!helper::canCombine(3u, 7u, 1u, 0, 0, 7u), "");
+    static_assert(!helper::canCombine(1u, 0u, 1u, 0, 0, 0u), "");
+
+    static_assert(!helper::canCombine(0u, 1u, 1u, 0, 0, 1u),
+                  "shared mask must be the overlap of masks");
+    static_assert(helper::canCombine(0u, 1u, 0u, 0, 0, 1u), "");
+    static_assert(helper::canCombine(0u, 1u, 0u, 4, 0, 1u), "");
+    static_assert(helper::canCombine(1u, 1u, 0u, 1, 0, 1u), "");
+    static_assert(!helper::canCombine(1u, 1u, 0u, 0, 0, 1u), "");
+    static_assert(helper::canCombine(1u, 1u, 0u, 1, 0, 1u), "");
+    static_assert(helper::canCombine(1u, 1u, 1u, 0, 0, 1u), "");
+    static_assert(!helper::canCombine(1u, 1u, 1u, 1, 0, 1u), "shift must match when sharing mask");
+
+    static_assert(helper::canCombine(0x800Fu, 0x800Fu, 0u, 4, 0, 0x800Fu), "");
+    static_assert(!helper::canCombine(0x800Fu, 0x800Fu, 0u, 1, 0, 0x800Fu), "");
+    static_assert(helper::canCombine(0x800Fu, 0x8002u, 0u, 2, 0, 0x8002u), "");
+    static_assert(helper::canCombine(0x800Fu, 0x8001u, 0u, 1, 0, 0x8001u), "");
+    static_assert(helper::canCombine(0x800Fu, 0x800Fu, 0u, 0, 16, 0x800F0000u), "");
+    static_assert(helper::canCombine(0x800Fu, 0x800Fu, 0x800Fu, 16, 16, 0x800F0000u), "");
+    static_assert(!helper::canCombine(0x1800Fu, 0x800Fu, 0u, 0, 16, 0x800F0000u), "");
+    static_assert(!helper::canCombine(0x1800Fu, 0x800Fu, 0x800Fu, 16, 16, 0x800F0000u), "");
+    static_assert(helper::canCombine(0x800Fu, 0x800F8000u, 0u, 8, 0, 0x800F8000u), "");
+    static_assert(!helper::canCombine(0xFFu, 0x80808080u, 0u, -1, 0, 0x80808080u), "");
+    static_assert(helper::canCombine(0xFFu, 0x80808040u, 0u, 7, 0, 0x80808040u), "");
+    static_assert(helper::canCombine(0xFFu, 0x8000u, 0u, 7, 0, 0x80808040u), "");
+    static_assert(helper::canCombine(0xFFu, 0x101u, 0u, 7, 15, 0x80808040u), "");
+
+    // can combine signed-flagged types only if mask is positive or no shift is required
+    static_assert(!helper::canCombine(0xFF, 0x40808040, 0, 0, 0, 0x40808040), "");
+    static_assert(helper::canCombine(0xFF, 0x40808040, 0, 7, 0, 0x40808040), "");
+    static_assert(!helper::canCombine((i32)0x800000FF, 0x40808040, 0, 0, 0, 0x40808040), "");
+    static_assert(!helper::canCombine((i32)0x800000FF, 0x40808040, 0, 7, 0, 0x40808040), "");
+    static_assert(!helper::canCombine(0x100000FF, 0x40808040, 0, 0, 0, 0x40808040), "");
+    static_assert(!helper::canCombine(0x100000FF, 0x40808040, 0, 7, 0, 0x40808040), "");
+    static_assert(!helper::canCombine(0xFF, (i32)0x80808040, 0, 0, 0, (i32)0x80808040), "");
+    static_assert(helper::canCombine(0xFF, (i32)0x80808040, 0, 7, 0, (i32)0x80808040), "");
+    static_assert(helper::canCombine((i32)0x80007F80, 0x40808040, 0, 0, 0, 0x40808040), "");
+
+    static_assert(helper::canCombine((i32)0x80007F80, (i32)0x80808040, (i32)0x80000000, 0, 0, (i32)0x80808040), "");
+    static_assert(!helper::canCombine((i32)0xC0007F80, (i32)0x80808040, (i32)0xC0000000, 0, 0, (i32)0x80808040), "");
+    static_assert(!helper::canCombine((i32)0x80007F80, (i32)0x80808040, (i32)0x80000000, 1, 0, (i32)0x80808040), "");
+    static_assert(!helper::canCombine((i32)0xC0007F80, (i32)0x80808040, (i32)0xC0000000, 1, 0, (i32)0x80808040), "");
+
+    // can_combine<T, Flag, MASK, [SHARED_MASK], [SHIFT]
+    static_assert(helper::can_combine<i32_0_0, u32, 0u>::value, "");
+    static_assert(helper::can_combine<i32_0_0, u32, 0u, 0u>::value, "");
+    static_assert(helper::can_combine<i32_0_0, u32, 0u, 0u, 4>::value, "");
+    static_assert(!helper::can_combine<i32_0_0, u32, 0u, 1u>::value, "");
+    static_assert(helper::can_combine<i32_0_0, u32, 1u, 0u>::value, "");
+    static_assert(helper::can_combine<i32_0_0, u32, 1u, 0u, 4>::value, "");
+    static_assert(!helper::can_combine<i32_0_0, u32, 1u, 1u>::value, "");
+
+    static_assert(!helper::can_combine<i32_1_0, u32, 0u, 1u>::value, "");
+    static_assert(helper::can_combine<i32_1_0, u32, 0u, 0u>::value, "");
+    static_assert(helper::can_combine<i32_1_0, u32, 0u, 0u, 4>::value, "");
+    static_assert(helper::can_combine<i32_1_0, u32, 1u, 0u>::value, "");
+    static_assert(!helper::can_combine<i32_1_0, u32, 1u, 0u, 0>::value, "");
+    static_assert(helper::can_combine<i32_1_0, u32, 1u, 0u, 1>::value, "");
+    static_assert(helper::can_combine<i32_1_0, u32, 1u, 1u>::value, "");
+    static_assert(helper::can_combine<i32_1_0, u32, 1u, 1u, 0>::value, "");
+    static_assert(!helper::can_combine<i32_1_0, u32, 1u, 1u, 1>::value,
+                  "shouldn't be able to use SHIFT with SHARED_MASK");
+
+    static_assert(helper::can_combine<i32_800f_0, u32, 0x800Fu, 0u, 4>::value, "");
+    static_assert(!helper::can_combine<i32_800f_0, u32, 0x800Fu, 0u, 1>::value, "");
+    static_assert(helper::can_combine<i32_800f_0, u32, 0x800Fu, 0u>::value, "");
+    static_assert(helper::can_combine<Flagged<i32, u32, 0x8002u>, u32, 0x800Fu, 0u>::value, "");
+    static_assert(helper::can_combine<Flagged<i32, u32, 0x8001u>, u32, 0x800Fu, 0u>::value, "");
+    static_assert(helper::can_combine<Flagged<i32, u32, 0x800F0000u>, u32, 0x800Fu, 0u>::value, "");
+    static_assert(helper::can_combine<Flagged<i32, u32, 0x800F8000u>, u32, 0x800Fu, 0u>::value, "");
+    static_assert(!helper::can_combine<Flagged<i32, u32, 0x80808080u>, u32, 0xFFu, 0u>::value, "");
+    static_assert(helper::can_combine<Flagged<i32, u32, 0x80808040u>, u32, 0xFFu, 0u>::value, "");
+
+    // can combine signed-flagged types only if mask is positive or no shift is required
+    static_assert(helper::can_combine<Flagged<i32, i32, 0x40808040>, i32, 0xFF, 0>::value, "");
+    static_assert(!helper::can_combine<Flagged<i32, i32, 0x40808040>,
+                                       i32, (i32)0x800000FF, 0>::value, "");
+    static_assert(!helper::can_combine<Flagged<i32, i32, 0x40808040>,
+                                       i32, 0x100000FF, 0>::value, "");
+    static_assert(helper::can_combine<Flagged<i32, i32, (i32)0x80808040>, i32, 0xFF, 0>::value, "");
+    static_assert(helper::can_combine<Flagged<i32, i32, 0x40808040>,
+                                      i32, (i32)0x80007F80, 0>::value, "");
+
+    static_assert(helper::can_combine<Flagged<i32, i32, (i32)0x80808040>,
+                                      i32, (i32)0x80007F80, (i32)0x80000000>::value, "");
+    static_assert(!helper::can_combine<Flagged<i32, i32, (i32)0xC0808040>,
+                                       i32, (i32)0x80007F80, (i32)0xC0000000>::value, "");
+
+    static_assert(helper::min_shift<Flagged<i32, FLAG, (FLAG)0x80808040>,
+                                    FLAG, (FLAG)0x80007F80, (FLAG)0x80000000>::value == 0, "");
+    static_assert(helper::can_combine<Flagged<i32, FLAG, (FLAG)0x80808040>,
+                                      FLAG, (FLAG)0x80007F80, (FLAG)0x80000000>::value, "");
+
+    // cannot combine non-tagged types
+    static_assert(!helper::can_combine<i32, u32, 0u, 0u>::value, "");
+    static_assert(!helper::can_combine<u32, u32, 0u, 0u>::value, "");
+    static_assert(!helper::can_combine<i32, u32, 0u, 0u>::value, "");
+    static_assert(!helper::can_combine<i32, u32, 0u, 1u>::value, "");
+    static_assert(!helper::can_combine<i32, u32, 1u, 0u>::value, "");
+    static_assert(!helper::can_combine<i32, u32, 1u, 1u>::value, "");
+
+    typedef Flagged<i32_800f_0, u32, 0x800F /* mask */, 0 /* shared mask */> i32_800f_800f;
+    static_assert(i32_800f_800f::sFlagMask == 0x800F, "");
+    static_assert(i32_800f_800f::sFlagShift == 4, "");
+    static_assert(i32_800f_800f::sEffectiveMask == 0x880FF, "");
+    static_assert(!i32_800f_0::sFlagCombined, "");
+    static_assert(!i32_800f_4::sFlagCombined, "");
+
+    static_assert(i32_800f_800f::sFlagCombined, "");
+    static_assert_equals(sizeof(i32_800f_800f), sizeof(i32_800f_0), "");
+
+    typedef Flagged<i32_800f_0, u32, 0x1FFFF /* mask */> i32_800f_1ffff;
+    static_assert(i32_800f_1ffff::sFlagMask == 0x1FFFF, "");
+    static_assert(i32_800f_1ffff::sFlagShift == 0, "");
+    static_assert(i32_800f_1ffff::sEffectiveMask == 0x1FFFF, "");
+    static_assert(!i32_800f_1ffff::sFlagCombined, "");
+
+    // operational tests
+    i32_800f_800f val(0x8000, 0x1234, 56);
+    EXPECT_EQ(val.get().get(), 56);
+    EXPECT_EQ(val.flags(), 0x8000u);
+    EXPECT_EQ(val.get().flags(), 0x1234u & 0x800F);
+    val.setFlags(0x12345);
+    EXPECT_EQ(val.flags(), 0x12345u & 0x800F);
+    EXPECT_EQ(val.get().flags(), 0x1234u & 0x800F);
+    val.get().setFlags(0x54321);
+    EXPECT_EQ(val.flags(), 0x12345u & 0x800F);
+    EXPECT_EQ(val.get().flags(), 0x54321u & 0x800F);
+    EXPECT_EQ(val.get().get(), 56);
+
+    typedef Flagged<i32_800f_4, u32, 0x800F /* mask */, 0 /* shared mask */> i32_800f_800f_B;
+    static_assert(i32_800f_800f_B::sFlagMask == 0x800F, "");
+    static_assert(i32_800f_800f_B::sFlagShift == 0, "");
+    static_assert(i32_800f_800f_B::sEffectiveMask == 0x880FF, "");
+
+    i32_800f_800f_B valB(0x8000, 0x1234, -987);
+    EXPECT_EQ(valB.get().get(), -987);
+    EXPECT_EQ(valB.flags(), 0x8000u);
+    EXPECT_EQ(valB.get().flags(), 0x1234u & 0x800F);
+    valB.setFlags(0x12345);
+    EXPECT_EQ(valB.flags(), 0x12345u & 0x800F);
+    EXPECT_EQ(valB.get().flags(), 0x1234u & 0x800F);
+    valB.get().setFlags(0x5C321);
+    EXPECT_EQ(valB.flags(), 0x12345u & 0x800F);
+    EXPECT_EQ(valB.get().flags(), 0x5C321u & 0x800F);
+    EXPECT_EQ(valB.get().get(), -987);
+
+    typedef Flagged<Flagged<i32, u32, 0xFF>, u32, 0xFF0, 0xF0> i32_ff_ff0;
+    i32_ff_ff0 valC(0xABCD, 0x1234, 101);
+    EXPECT_EQ(valC.get().get(), 101);
+    EXPECT_EQ(valC.flags(), 0xBC0u);
+    EXPECT_EQ(valC.get().flags(), 0xC4u);
+    valC.setFlags(0x12345);
+    EXPECT_EQ(valC.flags(), 0x340u);
+    EXPECT_EQ(valC.get().flags(), 0x44u);
+    valC.get().setFlags(0x54321);
+    EXPECT_EQ(valC.flags(), 0x320u);
+    EXPECT_EQ(valC.get().flags(), 0x21u);
+    EXPECT_EQ(valC.get().get(), 101);
+
+    // when combining flags (with no shift), it should work with signed flags
+    typedef Flagged<Flagged<i32, FLAG, kMask0>, FLAG, kMask1, kMaskCommon> i32_F_ff_ff0;
+    static_assert(i32_F_ff_ff0::sFlagCombined, "flags should be combined");
+
+    i32_F_ff_ff0 valD(kFlag1_A, kFlag0_A, 1023);
+    EXPECT_EQ(valD.get().get(), 1023);
+    EXPECT_EQ(valD.flags(), kFlag1_A);
+    EXPECT_EQ(valD.get().flags(), kFlag0_A);
+    valD.setFlags(kFlag1_B);
+    EXPECT_EQ(valD.flags(), kFlag1_B);
+    EXPECT_EQ(valD.get().flags(), FLAG(0x0BA));
+    valD.get().setFlags(kFlag0_C);
+    EXPECT_EQ(valD.flags(), FLAG(0xBC0));
+    EXPECT_EQ(valD.get().flags(), kFlag0_C);
+    EXPECT_EQ(valD.get().get(), 1023);
+}
+
+} // namespace android
diff --git a/media/libstagefright/foundation/tests/TypeTraits_test.cpp b/media/libstagefright/foundation/tests/TypeTraits_test.cpp
new file mode 100644
index 0000000..9fba435
--- /dev/null
+++ b/media/libstagefright/foundation/tests/TypeTraits_test.cpp
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2016 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 "TypeTraits_test"
+
+#include <gtest/gtest.h>
+
+#include <media/stagefright/foundation/TypeTraits.h>
+
+namespace android {
+
+class TypeTraitsTest : public ::testing::Test {
+protected:
+    enum A { };
+    enum UA : uint32_t { };
+    enum IA : int32_t { };
+};
+
+// =========== basic sanity tests for type-support templates
+TEST_F(TypeTraitsTest, StaticTests) {
+    static_assert(!std::is_integral<A>::value, "enums should not be integral");
+    static_assert(!std::is_integral<UA>::value, "enums should not be integral");
+    static_assert(!std::is_integral<IA>::value, "enums should not be integral");
+    static_assert(is_integral_or_enum<A>::value, "enums should be integral_or_enum");
+    static_assert(is_integral_or_enum<UA>::value, "enums should be integral_or_enum");
+    static_assert(is_integral_or_enum<IA>::value, "enums should be integral_or_enum");
+    static_assert(is_integral_or_enum<int>::value, "ints should be integral_or_enum");
+    static_assert(is_integral_or_enum<unsigned>::value, "unsigned ints should be integral_or_enum");
+    static_assert(!is_integral_or_enum<float>::value, "floats should not be integral_or_enum");
+
+    static_assert(!std::is_unsigned<UA>::value,
+                  "unsigned enums should not be unsigned");
+    static_assert(!std::is_unsigned<IA>::value,
+                  "unsigned enums should not be unsigned");
+    static_assert(std::is_unsigned<typename std::underlying_type<UA>::type>::value,
+                  "underlying type of unsigned enums should be unsigned");
+    static_assert(!std::is_unsigned<typename std::underlying_type<IA>::type>::value,
+                  "underlying type of unsigned enums should be unsigned");
+    static_assert(is_unsigned_integral<UA>::value,
+                  "unsigned enums should be unsigned_integral");
+    static_assert(!is_unsigned_integral<IA>::value,
+                  "signed enums should not be unsigned_integral");
+    static_assert(is_unsigned_integral<unsigned>::value,
+                  "unsigned ints should be unsigned_integral");
+    static_assert(!is_unsigned_integral<int>::value,
+                  "ints should not be unsigned_integral");
+    static_assert(!is_unsigned_integral<float>::value,
+                  "floats should not be unsigned_integral");
+
+    static_assert(!std::is_signed<UA>::value,
+                  "unsigned enums should not be signed");
+    static_assert(!std::is_signed<IA>::value,
+                  "unsigned enums should not be signed");
+    static_assert(!std::is_signed<typename std::underlying_type<UA>::type>::value,
+                  "underlying type of unsigned enums should be signed");
+    static_assert(std::is_signed<typename std::underlying_type<IA>::type>::value,
+                  "underlying type of unsigned enums should be signed");
+    static_assert(!is_signed_integral<UA>::value,
+                  "unsigned enums should not be signed_integral");
+    static_assert(is_signed_integral<IA>::value,
+                  "signed enums should be signed_integral");
+    static_assert(!is_signed_integral<unsigned>::value,
+                  "unsigned ints should not be signed_integral");
+    static_assert(is_signed_integral<int>::value,
+                  "ints should be signed_integral");
+    static_assert(!is_signed_integral<float>::value,
+                  "floats should not be signed_integral");
+
+    static_assert(std::is_same<uint64_t, typename underlying_integral_type<uint64_t>::type>::value,
+                  "underlying integral type of uint64_t should be uint64_t");
+    static_assert(std::is_same<uint32_t, typename underlying_integral_type<UA>::type>::value,
+                  "underlying integral type of uint32_t based enums should be uint32_t");
+    static_assert(std::is_same<int64_t, typename underlying_integral_type<int64_t>::type>::value,
+                  "underlying integral type of int64_t should be int64_t");
+    static_assert(std::is_same<int32_t, typename underlying_integral_type<IA>::type>::value,
+                  "underlying integral type of int32_t based enums should be int32_t");
+    //typedef underlying_integral_type<float>::type no_type;
+    static_assert(std::is_same<void, typename underlying_integral_type<float, void>::type>::value,
+                  "underlying integral type of float cannot be specified");
+}
+
+} // namespace android
diff --git a/media/libstagefright/tests/Utils_test.cpp b/media/libstagefright/foundation/tests/Utils_test.cpp
similarity index 98%
rename from media/libstagefright/tests/Utils_test.cpp
rename to media/libstagefright/foundation/tests/Utils_test.cpp
index d736501..0439d5c 100644
--- a/media/libstagefright/tests/Utils_test.cpp
+++ b/media/libstagefright/foundation/tests/Utils_test.cpp
@@ -18,15 +18,11 @@
 #define LOG_TAG "Utils_test"
 
 #include <gtest/gtest.h>
-#include <utils/String8.h>
-#include <utils/Errors.h>
-#include <fcntl.h>
-#include <unistd.h>
 
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AStringUtils.h>
 #include <media/stagefright/foundation/AUtils.h>
-#include <media/stagefright/Utils.h>
+#include <media/stagefright/Utils.h> // for FOURCC
 
 namespace android {
 
diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp
index e654a01..477280a 100644
--- a/media/libstagefright/httplive/LiveSession.cpp
+++ b/media/libstagefright/httplive/LiveSession.cpp
@@ -178,7 +178,7 @@
         *shortTermBps = mShortTermEstimate;
     }
 
-    int32_t minEstimate = -1, maxEstimate = -1;
+    int64_t minEstimate = -1, maxEstimate = -1;
     List<int32_t>::iterator it;
     for (it = mPrevEstimates.begin(); it != mPrevEstimates.end(); it++) {
         int32_t estimate = *it;
@@ -518,10 +518,10 @@
     return err;
 }
 
-status_t LiveSession::seekTo(int64_t timeUs, bool precise) {
+status_t LiveSession::seekTo(int64_t timeUs, MediaPlayerSeekMode mode) {
     sp<AMessage> msg = new AMessage(kWhatSeek, this);
     msg->setInt64("timeUs", timeUs);
-    msg->setInt32("precise", precise);
+    msg->setInt32("mode", mode);
 
     sp<AMessage> response;
     status_t err = msg->postAndAwaitResponse(&response);
@@ -1442,11 +1442,11 @@
 
 void LiveSession::onSeek(const sp<AMessage> &msg) {
     int64_t timeUs;
-    int32_t precise;
+    int32_t mode;
     CHECK(msg->findInt64("timeUs", &timeUs));
-    CHECK(msg->findInt32("precise", &precise));
-    // TODO: add "precise" to changeConfiguration.
-    changeConfiguration(timeUs);
+    CHECK(msg->findInt32("mode", &mode));
+    // TODO: add "mode" to changeConfiguration.
+    changeConfiguration(timeUs/* , (MediaPlayerSeekMode)mode */);
 }
 
 status_t LiveSession::getDuration(int64_t *durationUs) const {
diff --git a/media/libstagefright/httplive/LiveSession.h b/media/libstagefright/httplive/LiveSession.h
index 4dc529c..a0138be 100644
--- a/media/libstagefright/httplive/LiveSession.h
+++ b/media/libstagefright/httplive/LiveSession.h
@@ -86,7 +86,7 @@
     status_t disconnect();
 
     // Blocks until seek is complete.
-    status_t seekTo(int64_t timeUs, bool precise);
+    status_t seekTo(int64_t timeUs, MediaPlayerSeekMode mode);
 
     status_t getDuration(int64_t *durationUs) const;
     size_t getTrackCount() const;
diff --git a/media/libstagefright/tests/Android.mk b/media/libstagefright/tests/Android.mk
index a93770a..c6963b1 100644
--- a/media/libstagefright/tests/Android.mk
+++ b/media/libstagefright/tests/Android.mk
@@ -38,35 +38,6 @@
 
 include $(BUILD_NATIVE_TEST)
 
-
-include $(CLEAR_VARS)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-
-LOCAL_MODULE := Utils_test
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := \
-	Utils_test.cpp \
-
-LOCAL_SHARED_LIBRARIES := \
-	libcutils \
-	liblog \
-	libmedia \
-	libstagefright \
-	libstagefright_foundation \
-	libstagefright_omx \
-
-LOCAL_C_INCLUDES := \
-	frameworks/av/include \
-	frameworks/av/media/libstagefright \
-	frameworks/av/media/libstagefright/include \
-	$(TOP)/frameworks/native/include/media/openmax \
-
-LOCAL_CFLAGS += -Werror -Wall
-
-include $(BUILD_NATIVE_TEST)
-
 include $(CLEAR_VARS)
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 
diff --git a/services/audiopolicy/engineconfigurable/Android.mk b/services/audiopolicy/engineconfigurable/Android.mk
index 6b18921..08c677e 100644
--- a/services/audiopolicy/engineconfigurable/Android.mk
+++ b/services/audiopolicy/engineconfigurable/Android.mk
@@ -48,6 +48,7 @@
     libxml2
 
 LOCAL_SHARED_LIBRARIES := \
+    liblog \
     libcutils \
     libutils \
     liblog \
diff --git a/services/audiopolicy/engineconfigurable/wrapper/Android.mk b/services/audiopolicy/engineconfigurable/wrapper/Android.mk
index 3cc112f..d031bc3 100644
--- a/services/audiopolicy/engineconfigurable/wrapper/Android.mk
+++ b/services/audiopolicy/engineconfigurable/wrapper/Android.mk
@@ -8,7 +8,6 @@
 
 LOCAL_C_INCLUDES := \
     $(LOCAL_PATH)/include \
-    $(TARGET_OUT_HEADERS)/parameter \
     $(TOPDIR)frameworks/av/services/audiopolicy/engineconfigurable/include \
     $(TOPDIR)frameworks/av/services/audiopolicy/engineconfigurable/interface \
     $(TOPDIR)frameworks/av/services/audiopolicy/utilities/convert \
@@ -17,6 +16,9 @@
 
 LOCAL_WHOLE_STATIC_LIBRARIES := libmedia_helper
 
+LOCAL_SHARED_LIBRARIES := \
+    libparameter \
+
 LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
 
 LOCAL_MODULE:= libaudiopolicypfwwrapper
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 2f01b02..5ef0216 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -1754,7 +1754,7 @@
 
             audio_devices_t primaryInputDevices = availablePrimaryInputDevices();
             if (((device & primaryInputDevices & ~AUDIO_DEVICE_BIT_IN) != 0) &&
-                    mInputs.activeInputsCountOnDevices(primaryInputDevices) == 0) {
+                    mInputs.activeInputsCountOnDevices(primaryInputDevices) == 1) {
                 SoundTrigger::setCaptureState(true);
             }
 
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 3437e9d..3705e8f 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -2962,6 +2962,8 @@
         }
     }
     mRequestQueue.clear();
+
+    Mutex::Autolock al(mTriggerMutex);
     mTriggerMap.clear();
     if (lastFrameNumber != NULL) {
         *lastFrameNumber = mRepeatingLastFrameNumber;
diff --git a/services/mediaextractor/minijail/seccomp_policy/mediaextractor-seccomp-x86.policy b/services/mediaextractor/minijail/seccomp_policy/mediaextractor-seccomp-x86.policy
index 67976ff..189855c 100644
--- a/services/mediaextractor/minijail/seccomp_policy/mediaextractor-seccomp-x86.policy
+++ b/services/mediaextractor/minijail/seccomp_policy/mediaextractor-seccomp-x86.policy
@@ -35,6 +35,7 @@
 getgid32: 1
 getegid32: 1
 getgroups32: 1
+nanosleep: 1
 
 # for attaching to debuggerd on process crash
 socketcall: 1
diff --git a/services/soundtrigger/Android.mk b/services/soundtrigger/Android.mk
index 5d01999..e1e1fb1 100644
--- a/services/soundtrigger/Android.mk
+++ b/services/soundtrigger/Android.mk
@@ -42,7 +42,8 @@
 
 LOCAL_SHARED_LIBRARIES += \
 		libhwbinder \
-		libhidl \
+		libhidlbase \
+		libhidltransport \
 		libbase \
 		android.hardware.soundtrigger@2.0 \
 		android.hardware.audio.common@2.0