Merge "liboboe: initial checkin of the Oboe header files"
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/drm/drm_framework_common.h b/include/drm/drm_framework_common.h
index 0750406..d75f71c 100644
--- a/include/drm/drm_framework_common.h
+++ b/include/drm/drm_framework_common.h
@@ -234,10 +234,6 @@
      * POSIX based Decrypt API set for container based DRM
      */
     static const int CONTAINER_BASED = 0x02;
-    /**
-     * Decrypt API for Widevine streams
-     */
-    static const int WV_BASED = 0x3;
 };
 
 /**
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/MediaDefs.h b/include/media/MediaDefs.h
index 5f2a32d..0682413 100644
--- a/include/media/MediaDefs.h
+++ b/include/media/MediaDefs.h
@@ -59,8 +59,6 @@
 extern const char *MEDIA_MIMETYPE_CONTAINER_AVI;
 extern const char *MEDIA_MIMETYPE_CONTAINER_MPEG2PS;
 
-extern const char *MEDIA_MIMETYPE_CONTAINER_WVM;
-
 extern const char *MEDIA_MIMETYPE_TEXT_3GPP;
 extern const char *MEDIA_MIMETYPE_TEXT_SUBRIP;
 extern const char *MEDIA_MIMETYPE_TEXT_VTT;
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/MediaCodec.h b/include/media/stagefright/MediaCodec.h
index 89def5d..b0243ec 100644
--- a/include/media/stagefright/MediaCodec.h
+++ b/include/media/stagefright/MediaCodec.h
@@ -151,8 +151,6 @@
     status_t getOutputFormat(sp<AMessage> *format) const;
     status_t getInputFormat(sp<AMessage> *format) const;
 
-    status_t getWidevineLegacyBuffers(Vector<sp<MediaCodecBuffer> > *buffers) const;
-
     status_t getInputBuffers(Vector<sp<MediaCodecBuffer> > *buffers) const;
     status_t getOutputBuffers(Vector<sp<MediaCodecBuffer> > *buffers) const;
 
diff --git a/include/media/stagefright/NuMediaExtractor.h b/include/media/stagefright/NuMediaExtractor.h
index 03e2185..a8aca5a 100644
--- a/include/media/stagefright/NuMediaExtractor.h
+++ b/include/media/stagefright/NuMediaExtractor.h
@@ -108,7 +108,6 @@
     sp<DataSource> mDataSource;
 
     sp<IMediaExtractor> mImpl;
-    bool mIsWidevineExtractor;
 
     Vector<TrackInfo> mSelectedTracks;
     int64_t mTotalBitrate;  // in bits/sec
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/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/MediaDefs.cpp b/media/libmedia/MediaDefs.cpp
index a2110c9..2ae71f7 100644
--- a/media/libmedia/MediaDefs.cpp
+++ b/media/libmedia/MediaDefs.cpp
@@ -57,8 +57,6 @@
 const char *MEDIA_MIMETYPE_CONTAINER_AVI = "video/avi";
 const char *MEDIA_MIMETYPE_CONTAINER_MPEG2PS = "video/mp2p";
 
-const char *MEDIA_MIMETYPE_CONTAINER_WVM = "video/wvm";
-
 const char *MEDIA_MIMETYPE_TEXT_3GPP = "text/3gpp-tt";
 const char *MEDIA_MIMETYPE_TEXT_SUBRIP = "application/x-subrip";
 const char *MEDIA_MIMETYPE_TEXT_VTT = "text/vtt";
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/MediaPlayerFactory.cpp b/media/libmediaplayerservice/MediaPlayerFactory.cpp
index 605c710..0a9f791 100644
--- a/media/libmediaplayerservice/MediaPlayerFactory.cpp
+++ b/media/libmediaplayerservice/MediaPlayerFactory.cpp
@@ -26,7 +26,6 @@
 #include <media/stagefright/foundation/ADebug.h>
 #include <utils/Errors.h>
 #include <utils/misc.h>
-#include <../libstagefright/include/WVMExtractor.h>
 
 #include "MediaPlayerFactory.h"
 
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 cdbc2f8..cf1f84b 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
@@ -35,7 +35,6 @@
 #include <media/stagefright/Utils.h>
 #include "../../libstagefright/include/DRMExtractor.h"
 #include "../../libstagefright/include/NuCachedSource2.h"
-#include "../../libstagefright/include/WVMExtractor.h"
 #include "../../libstagefright/include/HTTPBase.h"
 
 namespace android {
@@ -59,7 +58,6 @@
       mFetchTimedTextDataGeneration(0),
       mDurationUs(-1ll),
       mAudioIsVorbis(false),
-      mIsWidevine(false),
       mIsSecure(false),
       mIsStreaming(false),
       mUIDValid(uidValid),
@@ -141,44 +139,9 @@
 
 status_t NuPlayer::GenericSource::initFromDataSource() {
     sp<IMediaExtractor> extractor;
-    String8 mimeType;
-    float confidence;
-    sp<AMessage> dummy;
-    bool isWidevineStreaming = false;
-
     CHECK(mDataSource != NULL);
 
-    if (mIsWidevine) {
-        isWidevineStreaming = SniffWVM(
-                mDataSource, &mimeType, &confidence, &dummy);
-        if (!isWidevineStreaming ||
-                strcasecmp(
-                    mimeType.string(), MEDIA_MIMETYPE_CONTAINER_WVM)) {
-            ALOGE("unsupported widevine mime: %s", mimeType.string());
-            return UNKNOWN_ERROR;
-        }
-    } else if (mIsStreaming) {
-        if (!mDataSource->sniff(&mimeType, &confidence, &dummy)) {
-            return UNKNOWN_ERROR;
-        }
-        isWidevineStreaming = !strcasecmp(
-                mimeType.string(), MEDIA_MIMETYPE_CONTAINER_WVM);
-    }
-
-    if (isWidevineStreaming) {
-        // we don't want cached source for widevine streaming.
-        mCachedSource.clear();
-        mDataSource = mHttpSource;
-        mWVMExtractor = new WVMExtractor(mDataSource);
-        mWVMExtractor->setAdaptiveStreamingMode(true);
-        if (mUIDValid) {
-            mWVMExtractor->setUID(mUID);
-        }
-        extractor = mWVMExtractor;
-    } else {
-        extractor = MediaExtractor::Create(mDataSource,
-                mimeType.isEmpty() ? NULL : mimeType.string());
-    }
+    extractor = MediaExtractor::Create(mDataSource, NULL);
 
     if (extractor == NULL) {
         return UNKNOWN_ERROR;
@@ -194,17 +157,6 @@
         if (mFileMeta->findInt64(kKeyDuration, &duration)) {
             mDurationUs = duration;
         }
-
-        if (!mIsWidevine) {
-            // Check mime to see if we actually have a widevine source.
-            // If the data source is not URL-type (eg. file source), we
-            // won't be able to tell until now.
-            const char *fileMime;
-            if (mFileMeta->findCString(kKeyMIMEType, &fileMime)
-                    && !strncasecmp(fileMime, "video/wvm", 9)) {
-                mIsWidevine = true;
-            }
-        }
     }
 
     int32_t totalBitrate = 0;
@@ -296,6 +248,9 @@
     // Widevine sources might re-initialize crypto when starting, if we delay
     // this to start(), all data buffered during prepare would be wasted.
     // (We don't actually start reading until start().)
+    //
+    // TODO: this logic may no longer be relevant after the removal of widevine
+    // support
     if (mAudioTrack.mSource != NULL && mAudioTrack.mSource->start() != OK) {
         ALOGE("failed to start audio track!");
         return UNKNOWN_ERROR;
@@ -378,11 +333,8 @@
         if (!mUri.empty()) {
             const char* uri = mUri.c_str();
             String8 contentType;
-            mIsWidevine = !strncasecmp(uri, "widevine://", 11);
 
-            if (!strncasecmp("http://", uri, 7)
-                    || !strncasecmp("https://", uri, 8)
-                    || mIsWidevine) {
+            if (!strncasecmp("http://", uri, 7) || !strncasecmp("https://", uri, 8)) {
                 mHttpSource = DataSource::CreateMediaHTTP(mHTTPService);
                 if (mHttpSource == NULL) {
                     ALOGE("Failed to create http source!");
@@ -395,8 +347,6 @@
                    mHTTPService, uri, &mUriHeaders, &contentType,
                    static_cast<HTTPBase *>(mHttpSource.get()));
         } else {
-            mIsWidevine = false;
-
             mDataSource = new FileSource(mFd, mOffset, mLength);
             mFd = -1;
         }
@@ -412,13 +362,9 @@
         mCachedSource = static_cast<NuCachedSource2 *>(mDataSource.get());
     }
 
-    // For widevine or other cached streaming cases, we need to wait for
-    // enough buffering before reporting prepared.
-    // Note that even when URL doesn't start with widevine://, mIsWidevine
-    // could still be set to true later, if the streaming or file source
-    // is sniffed to be widevine. We don't want to buffer for file source
-    // in that case, so must check the flag now.
-    mIsStreaming = (mIsWidevine || mCachedSource != NULL);
+    // For cached streaming cases, we need to wait for enough
+    // buffering before reporting prepared.
+    mIsStreaming = (mCachedSource != NULL);
 
     // init extractor from data source
     status_t err = initFromDataSource();
@@ -450,6 +396,9 @@
 
     if (mIsSecure) {
         // secure decoders must be instantiated before starting widevine source
+        //
+        // TODO: mIsSecure and FLAG_SECURE may be obsolete, revisit after
+        // removing widevine
         sp<AMessage> reply = new AMessage(kWhatSecureDecodersInstantiated, this);
         notifyInstantiateSecureDecoders(reply);
     } else {
@@ -476,7 +425,7 @@
 
     if (mIsStreaming) {
         if (mBufferingMonitorLooper == NULL) {
-            mBufferingMonitor->prepare(mCachedSource, mWVMExtractor, mDurationUs, mBitrate,
+            mBufferingMonitor->prepare(mCachedSource, mDurationUs, mBitrate,
                     mIsStreaming);
 
             mBufferingMonitorLooper = new ALooper;
@@ -536,12 +485,6 @@
     // nothing to do, just account for DRM playback status
     setDrmPlaybackStatusIfNeeded(Playback::STOP, 0);
     mStarted = false;
-    if (mIsWidevine || mIsSecure) {
-        // For widevine or secure sources we need to prevent any further reads.
-        sp<AMessage> msg = new AMessage(kWhatStopWidevine, this);
-        sp<AMessage> response;
-        (void) msg->postAndAwaitResponse(&response);
-    }
 }
 
 void NuPlayer::GenericSource::pause() {
@@ -665,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;
@@ -717,20 +662,6 @@
           break;
       }
 
-      case kWhatStopWidevine:
-      {
-          // mStopRead is only used for Widevine to prevent the video source
-          // from being read while the associated video decoder is shutting down.
-          mStopRead = true;
-          if (mVideoTrack.mSource != NULL) {
-              mVideoTrack.mPackets->clear();
-          }
-          sp<AMessage> response = new AMessage;
-          sp<AReplyToken> replyID;
-          CHECK(msg->senderAwaitsResponse(&replyID));
-          response->postReply(replyID);
-          break;
-      }
       default:
           Source::onMessageReceived(msg);
           break;
@@ -759,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) {
@@ -790,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);
@@ -886,11 +817,6 @@
         return -EWOULDBLOCK;
     }
 
-    if (mIsWidevine && !audio) {
-        // try to read a buffer as we may not have been able to the last time
-        postReadBuffer(MEDIA_TRACK_TYPE_VIDEO);
-    }
-
     status_t finalResult;
     if (!track->mPackets->hasBufferAvailable(&finalResult)) {
         if (finalResult == OK) {
@@ -1186,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);
@@ -1202,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;
@@ -1215,19 +1141,22 @@
     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
     // more buffers.
+    //
+    // TODO: revisit after widevine is removed.  May be able to
+    // combine mStopRead with mStarted.
     if (mStopRead) {
         return INVALID_OPERATION;
     }
     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;
@@ -1361,9 +1290,12 @@
 }
 
 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
+    //
+    // TODO: revisit after widevine is removed.  May be able to
+    // combine mStopRead with mStarted.
     if (mStopRead) {
         return;
     }
@@ -1372,19 +1304,11 @@
     switch (trackType) {
         case MEDIA_TRACK_TYPE_VIDEO:
             track = &mVideoTrack;
-            if (mIsWidevine) {
-                maxBuffers = 2;
-            } else {
-                maxBuffers = 8;  // too large of a number may influence seeks
-            }
+            maxBuffers = 8;  // too large of a number may influence seeks
             break;
         case MEDIA_TRACK_TYPE_AUDIO:
             track = &mAudioTrack;
-            if (mIsWidevine) {
-                maxBuffers = 8;
-            } else {
-                maxBuffers = 64;
-            }
+            maxBuffers = 64;
             break;
         case MEDIA_TRACK_TYPE_SUBTITLE:
             track = &mSubtitleTrack;
@@ -1408,13 +1332,13 @@
 
     bool seeking = false;
     if (seekTimeUs >= 0) {
-        options.setSeekTo(seekTimeUs, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
+        options.setSeekTo(seekTimeUs, mode);
         seeking = true;
     }
 
-    const bool couldReadMultiple = (!mIsWidevine && track->mSource->supportReadMultiple());
+    const bool couldReadMultiple = (track->mSource->supportReadMultiple());
 
-    if (mIsWidevine || couldReadMultiple) {
+    if (couldReadMultiple) {
         options.setNonBlocking();
     }
 
@@ -1461,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);
@@ -1535,17 +1460,16 @@
 
 void NuPlayer::GenericSource::BufferingMonitor::prepare(
         const sp<NuCachedSource2> &cachedSource,
-        const sp<WVMExtractor> &wvmExtractor,
         int64_t durationUs,
         int64_t bitrate,
         bool isStreaming) {
     Mutex::Autolock _l(mLock);
-    prepare_l(cachedSource, wvmExtractor, durationUs, bitrate, isStreaming);
+    prepare_l(cachedSource, durationUs, bitrate, isStreaming);
 }
 
 void NuPlayer::GenericSource::BufferingMonitor::stop() {
     Mutex::Autolock _l(mLock);
-    prepare_l(NULL /* cachedSource */, NULL /* wvmExtractor */, -1 /* durationUs */,
+    prepare_l(NULL /* cachedSource */, -1 /* durationUs */,
             -1 /* bitrate */, false /* isStreaming */);
 }
 
@@ -1600,22 +1524,17 @@
 
 void NuPlayer::GenericSource::BufferingMonitor::prepare_l(
         const sp<NuCachedSource2> &cachedSource,
-        const sp<WVMExtractor> &wvmExtractor,
         int64_t durationUs,
         int64_t bitrate,
         bool isStreaming) {
-    ALOGW_IF(wvmExtractor != NULL && cachedSource != NULL,
-            "WVMExtractor and NuCachedSource are both present when "
-            "BufferingMonitor::prepare_l is called, ignore NuCachedSource");
 
     mCachedSource = cachedSource;
-    mWVMExtractor = wvmExtractor;
     mDurationUs = durationUs;
     mBitrate = bitrate;
     mIsStreaming = isStreaming;
     mAudioTimeUs = 0;
     mVideoTimeUs = 0;
-    mPrepareBuffering = (cachedSource != NULL || wvmExtractor != NULL);
+    mPrepareBuffering = (cachedSource != NULL);
     cancelPollBuffering_l();
     mOffloadAudio = false;
     mFirstDequeuedBufferRealUs = -1ll;
@@ -1699,9 +1618,7 @@
     int32_t kbps = 0;
     status_t err = UNKNOWN_ERROR;
 
-    if (mWVMExtractor != NULL) {
-        err = mWVMExtractor->getEstimatedBandwidthKbps(&kbps);
-    } else if (mCachedSource != NULL) {
+    if (mCachedSource != NULL) {
         err = mCachedSource->getEstimatedBandwidthKbps(&kbps);
     }
 
@@ -1741,10 +1658,7 @@
     int64_t cachedDurationUs = -1ll;
     ssize_t cachedDataRemaining = -1;
 
-    if (mWVMExtractor != NULL) {
-        cachedDurationUs =
-                mWVMExtractor->getCachedDurationUs(&finalStatus);
-    } else if (mCachedSource != NULL) {
+    if (mCachedSource != NULL) {
         cachedDataRemaining =
                 mCachedSource->approxDataRemaining(&finalStatus);
 
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/GenericSource.h
index 368d11c..38d8616 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.h
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.h
@@ -37,7 +37,6 @@
 struct MediaSource;
 class MediaBuffer;
 struct NuCachedSource2;
-class WVMExtractor;
 
 struct NuPlayer::GenericSource : public NuPlayer::Source {
     GenericSource(const sp<AMessage> &notify, bool uidValid, uid_t uid);
@@ -71,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);
 
@@ -101,7 +102,6 @@
         kWhatSelectTrack,
         kWhatSeek,
         kWhatReadBuffer,
-        kWhatStopWidevine,
         kWhatStart,
         kWhatResume,
         kWhatSecureDecodersInstantiated,
@@ -121,7 +121,6 @@
 
         // Set up state.
         void prepare(const sp<NuCachedSource2> &cachedSource,
-                const sp<WVMExtractor> &wvmExtractor,
                 int64_t durationUs,
                 int64_t bitrate,
                 bool isStreaming);
@@ -155,7 +154,6 @@
         sp<AMessage> mNotify;
 
         sp<NuCachedSource2> mCachedSource;
-        sp<WVMExtractor> mWVMExtractor;
         int64_t mDurationUs;
         int64_t mBitrate;
         bool mIsStreaming;
@@ -175,7 +173,6 @@
         int64_t mlastDequeuedBufferMediaUs;
 
         void prepare_l(const sp<NuCachedSource2> &cachedSource,
-                const sp<WVMExtractor> &wvmExtractor,
                 int64_t durationUs,
                 int64_t bitrate,
                 bool isStreaming);
@@ -204,7 +201,6 @@
     int32_t mFetchTimedTextDataGeneration;
     int64_t mDurationUs;
     bool mAudioIsVorbis;
-    bool mIsWidevine;
     bool mIsSecure;
     bool mIsStreaming;
     bool mUIDValid;
@@ -219,7 +215,6 @@
     sp<DataSource> mDataSource;
     sp<NuCachedSource2> mCachedSource;
     sp<DataSource> mHttpSource;
-    sp<WVMExtractor> mWVMExtractor;
     sp<MetaData> mFileMeta;
     DrmManagerClient *mDrmManagerClient;
     sp<DecryptHandle> mDecryptHandle;
@@ -258,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();
 
@@ -280,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 90b7b7f..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);
 };
@@ -263,9 +263,6 @@
     } else {
         sp<GenericSource> genericSource =
                 new GenericSource(notify, mUIDValid, mUID);
-        // Don't set FLAG_SECURE on mSourceFlags here for widevine.
-        // The correct flags will be updated in Source::kWhatFlagsChanged
-        // handler when  GenericSource is prepared.
 
         status_t err = genericSource->setDataSource(httpService, url, headers);
 
@@ -422,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();
 }
@@ -684,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 */));
                     }
                 }
 
@@ -1200,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,
@@ -1215,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;
@@ -1231,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
@@ -1320,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;
         }
@@ -1542,7 +1540,7 @@
         mRenderer->flush(false /* audio */, false /* notifyComplete */);
     }
 
-    performSeek(currentPositionUs, false /* precise */);
+    performSeek(currentPositionUs, MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC /* mode */);
 
     if (forceNonOffload) {
         mRenderer->signalDisableOffloadAudio();
@@ -1670,29 +1668,6 @@
     (*decoder)->init();
     (*decoder)->configure(format);
 
-    // allocate buffers to decrypt widevine source buffers
-    if (!audio && (mSourceFlags & Source::FLAG_SECURE)) {
-        Vector<sp<MediaCodecBuffer> > inputBufs;
-        CHECK_EQ((*decoder)->getInputBuffers(&inputBufs), (status_t)OK);
-
-        Vector<MediaBuffer *> mediaBufs;
-        for (size_t i = 0; i < inputBufs.size(); i++) {
-            const sp<MediaCodecBuffer> &buffer = inputBufs[i];
-            MediaBuffer *mbuf = new MediaBuffer(buffer->data(), buffer->size());
-            mediaBufs.push(mbuf);
-        }
-
-        status_t err = mSource->setBuffers(audio, mediaBufs);
-        if (err != OK) {
-            for (size_t i = 0; i < mediaBufs.size(); ++i) {
-                mediaBufs[i]->release();
-            }
-            mediaBufs.clear();
-            ALOGE("Secure source didn't support secure mediaBufs.");
-            return err;
-        }
-    }
-
     if (!audio) {
         sp<AMessage> params = new AMessage();
         float rate = getFrameRate();
@@ -1999,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
@@ -2012,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/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
index d2452af..e1d426a 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
@@ -411,17 +411,7 @@
 }
 
 void NuPlayer::Decoder::onSetRenderer(const sp<Renderer> &renderer) {
-    bool hadNoRenderer = (mRenderer == NULL);
     mRenderer = renderer;
-    if (hadNoRenderer && mRenderer != NULL) {
-        // this means that the widevine legacy source is ready
-        onRequestInputBuffers();
-    }
-}
-
-void NuPlayer::Decoder::onGetInputBuffers(
-        Vector<sp<MediaCodecBuffer> > *dstBuffers) {
-    CHECK_EQ((status_t)OK, mCodec->getWidevineLegacyBuffers(dstBuffers));
 }
 
 void NuPlayer::Decoder::onResume(bool notifyComplete) {
@@ -518,9 +508,7 @@
  * returns true if we should request more data
  */
 bool NuPlayer::Decoder::doRequestBuffers() {
-    // mRenderer is only NULL if we have a legacy widevine source that
-    // is not yet ready. In this case we must not fetch input.
-    if (isDiscontinuityPending() || mRenderer == NULL) {
+    if (isDiscontinuityPending()) {
         return false;
     }
     status_t err = OK;
@@ -878,40 +866,6 @@
     bool hasBuffer = msg->findBuffer("buffer", &buffer);
     bool needsCopy = true;
 
-    // handle widevine classic source - that fills an arbitrary input buffer
-    MediaBuffer *mediaBuffer = NULL;
-    if (hasBuffer) {
-        mediaBuffer = (MediaBuffer *)(buffer->getMediaBufferBase());
-        if (mediaBuffer != NULL) {
-            // likely filled another buffer than we requested: adjust buffer index
-            size_t ix;
-            for (ix = 0; ix < mInputBuffers.size(); ix++) {
-                const sp<MediaCodecBuffer> &buf = mInputBuffers[ix];
-                if (buf->data() == mediaBuffer->data()) {
-                    // all input buffers are dequeued on start, hence the check
-                    if (!mInputBufferIsDequeued[ix]) {
-                        ALOGV("[%s] received MediaBuffer for #%zu instead of #%zu",
-                                mComponentName.c_str(), ix, bufferIx);
-                        mediaBuffer->release();
-                        return false;
-                    }
-
-                    // TRICKY: need buffer for the metadata, so instead, set
-                    // codecBuffer to the same (though incorrect) buffer to
-                    // avoid a memcpy into the codecBuffer
-                    codecBuffer = new MediaCodecBuffer(codecBuffer->format(), buffer);
-                    codecBuffer->setRange(
-                            mediaBuffer->range_offset(),
-                            mediaBuffer->range_length());
-                    bufferIx = ix;
-                    needsCopy = false;
-                    break;
-                }
-            }
-            CHECK(ix < mInputBuffers.size());
-        }
-    }
-
     if (buffer == NULL /* includes !hasBuffer */) {
         int32_t streamErr = ERROR_END_OF_STREAM;
         CHECK(msg->findInt32("err", &streamErr) || !hasBuffer);
@@ -981,18 +935,11 @@
                         timeUs,
                         flags);
         if (err != OK) {
-            if (mediaBuffer != NULL) {
-                mediaBuffer->release();
-            }
             ALOGE("Failed to queue input buffer for %s (err=%d)",
                     mComponentName.c_str(), err);
             handleError(err);
         } else {
             mInputBufferIsDequeued.editItemAt(bufferIx) = false;
-            if (mediaBuffer != NULL) {
-                CHECK(mMediaBuffers[bufferIx] == NULL);
-                mMediaBuffers.editItemAt(bufferIx) = mediaBuffer;
-            }
         }
     }
     return true;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h
index a576ae5..fcf601b 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h
@@ -47,7 +47,6 @@
     virtual void onConfigure(const sp<AMessage> &format);
     virtual void onSetParameters(const sp<AMessage> &params);
     virtual void onSetRenderer(const sp<Renderer> &renderer);
-    virtual void onGetInputBuffers(Vector<sp<MediaCodecBuffer> > *dstBuffers);
     virtual void onResume(bool notifyComplete);
     virtual void onFlush();
     virtual void onShutdown(bool notifyComplete);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.cpp
index 9c007ae..1210dc9 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.cpp
@@ -92,14 +92,6 @@
     PostAndAwaitResponse(msg, &response);
 }
 
-status_t NuPlayer::DecoderBase::getInputBuffers(Vector<sp<MediaCodecBuffer> > *buffers) const {
-    sp<AMessage> msg = new AMessage(kWhatGetInputBuffers, this);
-    msg->setPointer("buffers", buffers);
-
-    sp<AMessage> response;
-    return PostAndAwaitResponse(msg, &response);
-}
-
 void NuPlayer::DecoderBase::signalFlush() {
     (new AMessage(kWhatFlush, this))->post();
 }
@@ -166,20 +158,6 @@
             break;
         }
 
-        case kWhatGetInputBuffers:
-        {
-            sp<AReplyToken> replyID;
-            CHECK(msg->senderAwaitsResponse(&replyID));
-
-            Vector<sp<MediaCodecBuffer> > *dstBuffers;
-            CHECK(msg->findPointer("buffers", (void **)&dstBuffers));
-
-            onGetInputBuffers(dstBuffers);
-
-            (new AMessage)->postReply(replyID);
-            break;
-        }
-
         case kWhatRequestInputBuffers:
         {
             mRequestInputBuffersPending = false;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.h b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.h
index 6f4ead6..6811903 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.h
@@ -43,7 +43,6 @@
     void setRenderer(const sp<Renderer> &renderer);
     virtual status_t setVideoSurface(const sp<Surface> &) { return INVALID_OPERATION; }
 
-    status_t getInputBuffers(Vector<sp<MediaCodecBuffer> > *dstBuffers) const;
     void signalFlush();
     void signalResume(bool notifyComplete);
     void initiateShutdown();
@@ -71,7 +70,6 @@
     virtual void onConfigure(const sp<AMessage> &format) = 0;
     virtual void onSetParameters(const sp<AMessage> &params) = 0;
     virtual void onSetRenderer(const sp<Renderer> &renderer) = 0;
-    virtual void onGetInputBuffers(Vector<sp<MediaCodecBuffer> > *dstBuffers) = 0;
     virtual void onResume(bool notifyComplete) = 0;
     virtual void onFlush() = 0;
     virtual void onShutdown(bool notifyComplete) = 0;
@@ -91,7 +89,6 @@
         kWhatSetParameters       = 'setP',
         kWhatSetRenderer         = 'setR',
         kWhatPause               = 'paus',
-        kWhatGetInputBuffers     = 'gInB',
         kWhatRequestInputBuffers = 'reqB',
         kWhatFlush               = 'flus',
         kWhatShutdown            = 'shuD',
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp
index e4767ff..cb668e4 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp
@@ -93,11 +93,6 @@
             "ignoring request to change renderer");
 }
 
-void NuPlayer::DecoderPassThrough::onGetInputBuffers(
-        Vector<sp<MediaCodecBuffer> > * /* dstBuffers */) {
-    ALOGE("onGetInputBuffers() called unexpectedly");
-}
-
 bool NuPlayer::DecoderPassThrough::isStaleReply(const sp<AMessage> &msg) {
     int32_t generation;
     CHECK(msg->findInt32("generation", &generation));
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.h b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.h
index 9af25ff..173387a 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.h
@@ -38,7 +38,6 @@
     virtual void onConfigure(const sp<AMessage> &format);
     virtual void onSetParameters(const sp<AMessage> &params);
     virtual void onSetRenderer(const sp<Renderer> &renderer);
-    virtual void onGetInputBuffers(Vector<sp<MediaCodecBuffer> > *dstBuffers);
     virtual void onResume(bool notifyComplete);
     virtual void onFlush();
     virtual void onShutdown(bool notifyComplete);
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/Android.mk b/media/libstagefright/Android.mk
index 5e921e3..9e3b35a 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -59,7 +59,6 @@
         VBRISeeker.cpp                    \
         VideoFrameScheduler.cpp           \
         WAVExtractor.cpp                  \
-        WVMExtractor.cpp                  \
         XINGSeeker.cpp                    \
         avc_utils.cpp                     \
 
diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp
index 163a527..c78f1e9 100644
--- a/media/libstagefright/DataSource.cpp
+++ b/media/libstagefright/DataSource.cpp
@@ -31,7 +31,6 @@
 #include "include/NuCachedSource2.h"
 #include "include/OggExtractor.h"
 #include "include/WAVExtractor.h"
-#include "include/WVMExtractor.h"
 
 #include "matroska/MatroskaExtractor.h"
 
@@ -175,10 +174,6 @@
     RegisterSniffer_l(SniffMP3);
     RegisterSniffer_l(SniffAAC);
     RegisterSniffer_l(SniffMPEG2PS);
-    if (getuid() == AID_MEDIA) {
-        // WVM only in the media server process
-        RegisterSniffer_l(SniffWVM);
-    }
     RegisterSniffer_l(SniffMidi);
 
     char value[PROPERTY_VALUE_MAX];
@@ -200,14 +195,10 @@
         *contentType = "";
     }
 
-    bool isWidevine = !strncasecmp("widevine://", uri, 11);
-
     sp<DataSource> source;
     if (!strncasecmp("file://", uri, 7)) {
         source = new FileSource(uri + 7);
-    } else if (!strncasecmp("http://", uri, 7)
-            || !strncasecmp("https://", uri, 8)
-            || isWidevine) {
+    } else if (!strncasecmp("http://", uri, 7) || !strncasecmp("https://", uri, 8)) {
         if (httpService == NULL) {
             ALOGE("Invalid http service!");
             return NULL;
@@ -222,14 +213,6 @@
             httpSource = new MediaHTTP(conn);
         }
 
-        String8 tmp;
-        if (isWidevine) {
-            tmp = String8("http://");
-            tmp.append(uri + 11);
-
-            uri = tmp.string();
-        }
-
         String8 cacheConfig;
         bool disconnectAtHighwatermark;
         KeyedVector<String8, String8> nonCacheSpecificHeaders;
@@ -246,20 +229,14 @@
             return NULL;
         }
 
-        if (!isWidevine) {
-            if (contentType != NULL) {
-                *contentType = httpSource->getMIMEType();
-            }
-
-            source = NuCachedSource2::Create(
-                    httpSource,
-                    cacheConfig.isEmpty() ? NULL : cacheConfig.string(),
-                    disconnectAtHighwatermark);
-        } else {
-            // We do not want that prefetching, caching, datasource wrapper
-            // in the widevine:// case.
-            source = httpSource;
+        if (contentType != NULL) {
+            *contentType = httpSource->getMIMEType();
         }
+
+        source = NuCachedSource2::Create(
+                httpSource,
+                cacheConfig.isEmpty() ? NULL : cacheConfig.string(),
+                disconnectAtHighwatermark);
     } else if (!strncasecmp("data:", uri, 5)) {
         source = DataURISource::Create(uri);
     } else {
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 80860db..5382689 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -843,16 +843,6 @@
     return OK;
 }
 
-status_t MediaCodec::getWidevineLegacyBuffers(Vector<sp<MediaCodecBuffer> > *buffers) const {
-    sp<AMessage> msg = new AMessage(kWhatGetBuffers, this);
-    msg->setInt32("portIndex", kPortIndexInput);
-    msg->setPointer("buffers", buffers);
-    msg->setInt32("widevine", true);
-
-    sp<AMessage> response;
-    return PostAndAwaitResponse(msg, &response);
-}
-
 status_t MediaCodec::getInputBuffers(Vector<sp<MediaCodecBuffer> > *buffers) const {
     sp<AMessage> msg = new AMessage(kWhatGetBuffers, this);
     msg->setInt32("portIndex", kPortIndexInput);
@@ -1560,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));
@@ -2132,12 +2129,7 @@
         {
             sp<AReplyToken> replyID;
             CHECK(msg->senderAwaitsResponse(&replyID));
-            // Unfortunately widevine legacy source requires knowing all of the
-            // codec input buffers, so we have to provide them even in async mode.
-            int32_t widevine = 0;
-            msg->findInt32("widevine", &widevine);
-
-            if (!isExecuting() || ((mFlags & kFlagIsAsync) && !widevine)) {
+            if (!isExecuting() || (mFlags & kFlagIsAsync)) {
                 PostReplyWithError(replyID, INVALID_OPERATION);
                 break;
             } else if (mFlags & kFlagStickyError) {
@@ -2370,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/MediaExtractor.cpp b/media/libstagefright/MediaExtractor.cpp
index f2fdbc9..66bf7cb 100644
--- a/media/libstagefright/MediaExtractor.cpp
+++ b/media/libstagefright/MediaExtractor.cpp
@@ -28,7 +28,6 @@
 #include "include/MPEG2PSExtractor.h"
 #include "include/MPEG2TSExtractor.h"
 #include "include/DRMExtractor.h"
-#include "include/WVMExtractor.h"
 #include "include/FLACExtractor.h"
 #include "include/AACExtractor.h"
 #include "include/MidiExtractor.h"
@@ -151,15 +150,9 @@
         ALOGW("creating media extractor in calling process");
         return CreateFromService(source, mime);
     } else {
-        // Check if it's WVM, since WVMExtractor needs to be created in the media server process,
-        // not the extractor process.
         String8 mime8;
         float confidence;
         sp<AMessage> meta;
-        if (SniffWVM(source, &mime8, &confidence, &meta) &&
-                !strcasecmp(mime8, MEDIA_MIMETYPE_CONTAINER_WVM)) {
-            return new WVMExtractor(source);
-        }
 
         // Check if it's es-based DRM, since DRMExtractor needs to be created in the media server
         // process, not the extractor process.
@@ -251,9 +244,6 @@
         ret = new MatroskaExtractor(source);
     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2TS)) {
         ret = new MPEG2TSExtractor(source);
-    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_WVM) && getuid() == AID_MEDIA) {
-        // Return now.  WVExtractor should not have the DrmFlag set in the block below.
-        return new WVMExtractor(source);
     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC_ADTS)) {
         ret = new AACExtractor(source, meta);
     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2PS)) {
diff --git a/media/libstagefright/NuMediaExtractor.cpp b/media/libstagefright/NuMediaExtractor.cpp
index e3270ed..6f8220f 100644
--- a/media/libstagefright/NuMediaExtractor.cpp
+++ b/media/libstagefright/NuMediaExtractor.cpp
@@ -22,7 +22,6 @@
 
 #include "include/ESDS.h"
 #include "include/NuCachedSource2.h"
-#include "include/WVMExtractor.h"
 
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
@@ -40,8 +39,7 @@
 namespace android {
 
 NuMediaExtractor::NuMediaExtractor()
-    : mIsWidevineExtractor(false),
-      mTotalBitrate(-1ll),
+    : mTotalBitrate(-1ll),
       mDurationUs(-1ll) {
 }
 
@@ -78,48 +76,15 @@
         return -ENOENT;
     }
 
-    mIsWidevineExtractor = false;
-    if (!strncasecmp("widevine://", path, 11)) {
-        String8 mimeType;
-        float confidence;
-        sp<AMessage> dummy;
-        bool success = SniffWVM(dataSource, &mimeType, &confidence, &dummy);
-
-        if (!success
-                || strcasecmp(
-                    mimeType.string(), MEDIA_MIMETYPE_CONTAINER_WVM)) {
-            return ERROR_UNSUPPORTED;
-        }
-
-        sp<WVMExtractor> extractor = new WVMExtractor(dataSource);
-        extractor->setAdaptiveStreamingMode(true);
-
-        mImpl = extractor;
-        mIsWidevineExtractor = true;
-    } else {
-        mImpl = MediaExtractor::Create(dataSource);
-    }
+    mImpl = MediaExtractor::Create(dataSource);
 
     if (mImpl == NULL) {
         return ERROR_UNSUPPORTED;
     }
 
     sp<MetaData> fileMeta = mImpl->getMetaData();
-    const char *containerMime;
-    if (fileMeta != NULL
-            && fileMeta->findCString(kKeyMIMEType, &containerMime)
-            && !strcasecmp(containerMime, "video/wvm")) {
-        // We always want to use "cryptoPluginMode" when using the wvm
-        // extractor. We can tell that it is this extractor by looking
-        // at the container mime type.
-        // The cryptoPluginMode ensures that the extractor will actually
-        // give us data in a call to MediaSource::read(), unlike its
-        // default mode that we used in AwesomePlayer.
-        // TODO: change default mode
-        static_cast<WVMExtractor *>(mImpl.get())->setCryptoPluginMode(true);
-    } else if (mImpl->getDrmFlag()) {
-        // For all other drm content, we don't want to expose decrypted
-        // content to Java application.
+    if (mImpl->getDrmFlag()) {
+        // Don't expose decrypted content to Java application
         mImpl.clear();
         mImpl = NULL;
         return ERROR_UNSUPPORTED;
@@ -633,15 +598,7 @@
     Mutex::Autolock autoLock(mLock);
 
     int64_t bitrate;
-    if (mIsWidevineExtractor) {
-        sp<WVMExtractor> wvmExtractor =
-            static_cast<WVMExtractor *>(mImpl.get());
-
-        status_t finalStatus;
-        *durationUs = wvmExtractor->getCachedDurationUs(&finalStatus);
-        *eos = (finalStatus != OK);
-        return true;
-    } else if ((mDataSource->flags() & DataSource::kIsCachingDataSource)
+    if ((mDataSource->flags() & DataSource::kIsCachingDataSource)
             && getTotalBitrate(&bitrate)) {
         sp<NuCachedSource2> cachedSource =
             static_cast<NuCachedSource2 *>(mDataSource.get());
diff --git a/media/libstagefright/WVMExtractor.cpp b/media/libstagefright/WVMExtractor.cpp
deleted file mode 100644
index d1b2f54..0000000
--- a/media/libstagefright/WVMExtractor.cpp
+++ /dev/null
@@ -1,197 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "WVMExtractor"
-#include <utils/Log.h>
-
-#include "include/WVMExtractor.h"
-
-#include <arpa/inet.h>
-#include <utils/String8.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/Utils.h>
-#include <media/stagefright/DataSource.h>
-#include <media/stagefright/MediaSource.h>
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MetaData.h>
-#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaBuffer.h>
-#include <dlfcn.h>
-
-#include <utils/Errors.h>
-
-/* The extractor lifetime is short - just long enough to get
- * the media sources constructed - so the shared lib needs to remain open
- * beyond the lifetime of the extractor.  So keep the handle as a global
- * rather than a member of the extractor
- */
-void *gVendorLibHandle = NULL;
-
-namespace android {
-
-static Mutex gWVMutex;
-
-WVMExtractor::WVMExtractor(const sp<DataSource> &source)
-    : mDataSource(source)
-{
-    Mutex::Autolock autoLock(gWVMutex);
-
-    if (!getVendorLibHandle()) {
-        return;
-    }
-
-    typedef WVMLoadableExtractor *(*GetInstanceFunc)(sp<DataSource>);
-    GetInstanceFunc getInstanceFunc =
-        (GetInstanceFunc) dlsym(gVendorLibHandle,
-                "_ZN7android11GetInstanceENS_2spINS_10DataSourceEEE");
-
-    if (getInstanceFunc) {
-        if (source->DrmInitialization(
-                MEDIA_MIMETYPE_CONTAINER_WVM) != NULL) {
-            mImpl = (*getInstanceFunc)(source);
-            CHECK(mImpl != NULL);
-            setDrmFlag(true);
-        } else {
-            ALOGE("Drm manager failed to initialize.");
-        }
-    } else {
-        ALOGE("Failed to locate GetInstance in libwvm.so");
-    }
-}
-
-static void init_routine()
-{
-    gVendorLibHandle = dlopen("libwvm.so", RTLD_NOW);
-    if (gVendorLibHandle == NULL) {
-        ALOGE("Failed to open libwvm.so: %s", dlerror());
-    }
-}
-
-bool WVMExtractor::getVendorLibHandle()
-{
-    static pthread_once_t sOnceControl = PTHREAD_ONCE_INIT;
-    pthread_once(&sOnceControl, init_routine);
-
-    return gVendorLibHandle != NULL;
-}
-
-WVMExtractor::~WVMExtractor() {
-}
-
-size_t WVMExtractor::countTracks() {
-    return (mImpl != NULL) ? mImpl->countTracks() : 0;
-}
-
-sp<IMediaSource> WVMExtractor::getTrack(size_t index) {
-    if (mImpl == NULL) {
-        return NULL;
-    }
-    return mImpl->getTrack(index);
-}
-
-sp<MetaData> WVMExtractor::getTrackMetaData(size_t index, uint32_t flags) {
-    if (mImpl == NULL) {
-        return NULL;
-    }
-    return mImpl->getTrackMetaData(index, flags);
-}
-
-sp<MetaData> WVMExtractor::getMetaData() {
-    if (mImpl == NULL) {
-        return NULL;
-    }
-    return mImpl->getMetaData();
-}
-
-int64_t WVMExtractor::getCachedDurationUs(status_t *finalStatus) {
-    if (mImpl == NULL) {
-        return 0;
-    }
-
-    return mImpl->getCachedDurationUs(finalStatus);
-}
-
-status_t WVMExtractor::getEstimatedBandwidthKbps(int32_t *kbps) {
-    if (mImpl == NULL) {
-        return UNKNOWN_ERROR;
-    }
-
-    return mImpl->getEstimatedBandwidthKbps(kbps);
-}
-
-
-void WVMExtractor::setAdaptiveStreamingMode(bool adaptive) {
-    if (mImpl != NULL) {
-        mImpl->setAdaptiveStreamingMode(adaptive);
-    }
-}
-
-void WVMExtractor::setCryptoPluginMode(bool cryptoPluginMode) {
-    if (mImpl != NULL) {
-        mImpl->setCryptoPluginMode(cryptoPluginMode);
-    }
-}
-
-void WVMExtractor::setUID(uid_t uid) {
-    if (mImpl != NULL) {
-        mImpl->setUID(uid);
-    }
-}
-
-status_t WVMExtractor::getError() {
-    if (mImpl == NULL) {
-       return UNKNOWN_ERROR;
-    }
-
-    return mImpl->getError();
-}
-
-void WVMExtractor::setError(status_t err) {
-    if (mImpl != NULL) {
-        mImpl->setError(err);
-    }
-}
-
-bool SniffWVM(
-    const sp<DataSource> &source, String8 *mimeType, float *confidence,
-        sp<AMessage> *) {
-
-    Mutex::Autolock autoLock(gWVMutex);
-
-    if (!WVMExtractor::getVendorLibHandle()) {
-        return false;
-    }
-
-    typedef WVMLoadableExtractor *(*SnifferFunc)(const sp<DataSource>&);
-    SnifferFunc snifferFunc =
-        (SnifferFunc) dlsym(gVendorLibHandle,
-                            "_ZN7android15IsWidevineMediaERKNS_2spINS_10DataSourceEEE");
-
-    if (snifferFunc) {
-        if ((*snifferFunc)(source)) {
-            *mimeType = MEDIA_MIMETYPE_CONTAINER_WVM;
-            *confidence = 10.0f;
-            return true;
-        }
-    } else {
-        ALOGE("IsWidevineMedia not found in libwvm.so");
-    }
-
-    return false;
-}
-
-} //namespace android
-
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/include/WVMExtractor.h b/media/libstagefright/include/WVMExtractor.h
deleted file mode 100644
index 65cb99a..0000000
--- a/media/libstagefright/include/WVMExtractor.h
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef WVM_EXTRACTOR_H_
-
-#define WVM_EXTRACTOR_H_
-
-#include <media/stagefright/MediaExtractor.h>
-#include <utils/Errors.h>
-
-namespace android {
-
-struct AMessage;
-class String8;
-class DataSource;
-
-class WVMLoadableExtractor : public MediaExtractor {
-public:
-    WVMLoadableExtractor() {}
-    virtual ~WVMLoadableExtractor() {}
-
-    virtual int64_t getCachedDurationUs(status_t *finalStatus) = 0;
-    virtual status_t getError() = 0;
-    virtual status_t getEstimatedBandwidthKbps(int32_t *kbps) = 0;
-    virtual void setAdaptiveStreamingMode(bool adaptive) = 0;
-    virtual void setCryptoPluginMode(bool cryptoPluginMode) = 0;
-    virtual void setError(status_t err) = 0;
-    virtual void setUID(uid_t uid) = 0;
-};
-
-class WVMExtractor : public MediaExtractor {
-public:
-    explicit WVMExtractor(const sp<DataSource> &source);
-
-    virtual size_t countTracks();
-    virtual sp<IMediaSource> getTrack(size_t index);
-    virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);
-    virtual sp<MetaData> getMetaData();
-    virtual void setUID(uid_t uid);
-
-    // Return the amount of data cached from the current
-    // playback positiion (in us).
-    // While more data is still being fetched *finalStatus == OK,
-    // Once fetching is completed (no more data available), *finalStatus != OK
-    // If fetching completed normally (i.e. reached EOS instead of IO error)
-    // *finalStatus == ERROR_END_OF_STREAM
-    int64_t getCachedDurationUs(status_t *finalStatus);
-
-    // Return the current estimated bandwidth
-    status_t getEstimatedBandwidthKbps(int32_t *kbps);
-
-    // Set to use adaptive streaming mode by the WV component.
-    // If adaptive == true, adaptive streaming mode will be used.
-    // Default mode is non-adaptive streaming mode.
-    // Should set to use adaptive streaming mode only if widevine:// protocol
-    // is used.
-    void setAdaptiveStreamingMode(bool adaptive);
-
-    // setCryptoPluginMode(true) to select crypto plugin mode.
-    // In this mode, the extractor returns encrypted data for use
-    // with the MediaCodec model, which handles the decryption in the
-    // codec.
-    void setCryptoPluginMode(bool cryptoPluginMode);
-
-    static bool getVendorLibHandle();
-
-    status_t getError();
-
-    void setError(status_t err);
-
-protected:
-    virtual ~WVMExtractor();
-
-private:
-    sp<DataSource> mDataSource;
-    sp<WVMLoadableExtractor> mImpl;
-
-    WVMExtractor(const WVMExtractor &);
-    WVMExtractor &operator=(const WVMExtractor &);
-};
-
-bool SniffWVM(
-        const sp<DataSource> &source, String8 *mimeType, float *confidence,
-        sp<AMessage> *);
-
-}  // namespace android
-
-#endif  // DRM_EXTRACTOR_H_
-
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/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