diff --git a/arm/arch-arm-armv7-a-neon/shared/vndk-core/libui.so b/arm/arch-arm-armv7-a-neon/shared/vndk-core/libui.so
index c09a87255ca7924bcfe43d15b269dc880d0ff986..5cceaa24a41dd114ede8e5429a03dc1fa39da75e 100755
Binary files a/arm/arch-arm-armv7-a-neon/shared/vndk-core/libui.so and b/arm/arch-arm-armv7-a-neon/shared/vndk-core/libui.so differ
diff --git a/arm/include/frameworks/av/media/libstagefright/include/media/stagefright/VideoRenderQualityTracker.h b/arm/include/frameworks/av/media/libstagefright/include/media/stagefright/VideoRenderQualityTracker.h
index 5cf674fad13f6fd67000013564c4056f6eb07455..82ba81caa1708dbeebe736371dd8006802e112af 100644
--- a/arm/include/frameworks/av/media/libstagefright/include/media/stagefright/VideoRenderQualityTracker.h
+++ b/arm/include/frameworks/av/media/libstagefright/include/media/stagefright/VideoRenderQualityTracker.h
@@ -62,20 +62,37 @@ struct VideoRenderQualityMetrics {
 
     // A histogram of the durations of freezes due to dropped/skipped frames.
     MediaHistogram<int32_t> freezeDurationMsHistogram;
-    // The computed overall freeze score using the above histogram and score conversion table.
+    // The computed overall freeze score using the above histogram and score conversion table. The
+    // score is based on counts in the histogram bucket, multiplied by the value in the score
+    // conversion table for that bucket. For example, the impact of a short freeze may be minimal,
+    // but the impact of long freeze may be disproportionally worse. Therefore, the score
+    // multipliers for each bucket might increase exponentially instead of linearly. A score
+    // multiplier of zero would reflect that small freeze durations have near-zero impact to the
+    // user experience.
     int32_t freezeScore;
     // The computed percentage of total playback duration that was frozen.
     float freezeRate;
+    // The number of freeze events.
+    int32_t freezeEventCount;
 
     // A histogram of the durations between each freeze.
     MediaHistogram<int32_t> freezeDistanceMsHistogram;
 
-    // A histogram of the judder scores.
+    // A histogram of the judder scores - based on the error tolerance between actual render
+    // duration of each frame and the ideal render duration.
     MediaHistogram<int32_t> judderScoreHistogram;
-    // The computed overall judder score using the above histogram and score conversion table.
+    // The computed overall judder score using the above histogram and score conversion table. The
+    // score is based on counts in the histogram bucket, multiplied by the value in the score
+    // conversion table for that bucket. For example, the impact of minimal judder may be small,
+    // but the impact of large judder may be disproportionally worse. Therefore, the score
+    // multipliers for each bucket might increase exponentially instead of linearly. A score
+    // multiplier of zero would reflect that small judder errors have near-zero impact to the user
+    // experience.
     int32_t judderScore;
     // The computed percentage of total frames that had judder.
     float judderRate;
+    // The number of judder events.
+    int32_t judderEventCount;
 };
 
 ///////////////////////////////////////////////////////
@@ -101,6 +118,15 @@ public:
     // Configurable elements of the metrics algorithms
     class Configuration {
     public:
+        // system/server_configurable_flags/libflags/include/get_flags.h:GetServerConfigurableFlag
+        typedef std::string (*GetServerConfigurableFlagFn)(
+                const std::string& experiment_category_name,
+                const std::string& experiment_flag_name,
+                const std::string& default_value);
+
+        static Configuration getFromServerConfigurableFlags(
+                GetServerConfigurableFlagFn getServerConfigurableFlagFn);
+
         Configuration();
 
         // Whether or not frame render quality is tracked.
@@ -124,27 +150,107 @@ public:
         // skip forward in content time is due to frame drops. If the app-desired frame duration is
         // short, but the content frame duration is large, it is assumed the app is intentionally
         // seeking forward.
-        int32_t contentTimeAdvancedForLiveContentToleranceUs;
+        int32_t liveContentFrameDropToleranceUs;
 
         // Freeze configuration
         //
         // The values used to distribute freeze durations across a histogram.
         std::vector<int32_t> freezeDurationMsHistogramBuckets;
-        // The values used to compare against freeze duration counts when determining an overall
-        // score.
+        //
+        // The values used to multiply the counts in the histogram buckets above to compute an
+        // overall score. This allows the score to reflect disproportionate impact as freeze
+        // durations increase.
         std::vector<int64_t> freezeDurationMsHistogramToScore;
+        //
         // The values used to distribute distances between freezes across a histogram.
         std::vector<int32_t> freezeDistanceMsHistogramBuckets;
+        //
+        // The maximum number of freeze events to send back to the caller.
+        int32_t freezeEventMax;
+        //
+        // The maximum number of detail entries tracked per freeze event.
+        int32_t freezeEventDetailsMax;
+        //
+        // The maximum distance in time between two freeze occurrences such that both will be
+        // lumped into the same freeze event.
+        int32_t freezeEventDistanceToleranceMs;
 
         // Judder configuration
         //
         // A judder error lower than this value is not scored as judder.
         int32_t judderErrorToleranceUs;
+        //
         // The values used to distribute judder scores across a histogram.
         std::vector<int32_t> judderScoreHistogramBuckets;
-        // The values used to compare against judder score histogram counts when determining an
-        // overall score.
-        std::vector<int32_t> judderScoreHistogramToScore;
+        //
+        // The values used to multiply the counts in the histogram buckets above to compute an
+        // overall score. This allows the score to reflect disproportionate impact as judder scores
+        // increase.
+        std::vector<int64_t> judderScoreHistogramToScore;
+        //
+        // The maximum number of judder events to send back to the caller.
+        int32_t judderEventMax;
+        //
+        // The maximum number of detail entries tracked per judder event.
+        int32_t judderEventDetailsMax;
+        //
+        // The maximum distance in time between two judder occurrences such that both will be
+        // lumped into the same judder event.
+        int32_t judderEventDistanceToleranceMs;
+    };
+
+    struct FreezeEvent {
+        // Details are captured for each freeze up to a limited number. The arrays are guaranteed to
+        // have the same size.
+        struct Details {
+            /// The duration of the freeze.
+            std::vector<int32_t> durationMs;
+            // The distance between the beginning of this freeze and the end of the previous freeze.
+            std::vector<int32_t> distanceMs;
+        };
+        // Whether or not the data in this structure is valid.
+        bool valid = false;
+        // The time at which the first freeze for this event was detected.
+        int64_t initialTimeUs;
+        // The total duration from the beginning of the first freeze to the end of the last freeze
+        // in this event.
+        int32_t durationMs;
+        // The number of freezes in this event.
+        int64_t count;
+        // The sum of all durations of all freezes in this event.
+        int64_t sumDurationMs;
+        // The sum of all distances between each freeze in this event.
+        int64_t sumDistanceMs;
+        // Detailed information for the first N freezes in this event.
+        Details details;
+    };
+
+    struct JudderEvent {
+        // Details are captured for each frame judder up to a limited number. The arrays are
+        // guaranteed to have the same size.
+        struct Details {
+            // The actual render duration of the frame for this judder occurrence.
+            std::vector<int32_t> actualRenderDurationUs;
+            // The content render duration of the frame for this judder occurrence.
+            std::vector<int32_t> contentRenderDurationUs;
+            // The distance from this judder occurrence and the previous judder occurrence.
+            std::vector<int32_t> distanceMs;
+        };
+        // Whether or not the data in this structure is valid.
+        bool valid = false;
+        // The time at which the first judder occurrence for this event was detected.
+        int64_t initialTimeUs;
+        // The total duration from the first judder occurrence to the last judder occurrence in this
+        // event.
+        int32_t durationMs;
+        // The number of judder occurrences in this event.
+        int64_t count;
+        // The sum of all judder scores in this event.
+        int64_t sumScore;
+        // The sum of all distances between each judder occurrence in this event.
+        int64_t sumDistanceMs;
+        // Detailed information for the first N judder occurrences in this event.
+        Details details;
     };
 
     VideoRenderQualityTracker();
@@ -164,7 +270,16 @@ public:
     void onFrameReleased(int64_t contentTimeUs, int64_t desiredRenderTimeNs);
 
     // Called when the system has detected that the frame has actually been rendered to the display.
-    void onFrameRendered(int64_t contentTimeUs, int64_t actualRenderTimeNs);
+    // Returns any freeze events or judder events that were detected.
+    void onFrameRendered(int64_t contentTimeUs, int64_t actualRenderTimeNs,
+                         FreezeEvent *freezeEventOut = nullptr,
+                         JudderEvent *judderEventOut = nullptr);
+
+    // Gets and resets data for the current freeze event.
+    FreezeEvent getAndResetFreezeEvent();
+
+    // Gets and resets data for the current judder event.
+    JudderEvent getAndResetJudderEvent();
 
     // Retrieve the metrics.
     const VideoRenderQualityMetrics &getMetrics();
@@ -233,13 +348,31 @@ private:
 
     // Process a frame freeze.
     static void processFreeze(int64_t actualRenderTimeUs, int64_t lastRenderTimeUs,
-                              int64_t lastFreezeEndTimeUs, VideoRenderQualityMetrics &m);
+                              int64_t lastFreezeEndTimeUs, FreezeEvent &e,
+                              VideoRenderQualityMetrics &m, const Configuration &c);
+
+    // Retrieve a freeze event if an event just finished.
+    static void maybeCaptureFreezeEvent(int64_t actualRenderTimeUs, int64_t lastFreezeEndTimeUs,
+                                        FreezeEvent &e, const VideoRenderQualityMetrics & m,
+                                        const Configuration &c, FreezeEvent *freezeEventOut);
 
     // Compute a judder score for the previously-rendered frame.
     static int64_t computePreviousJudderScore(const FrameDurationUs &actualRenderDurationUs,
                                               const FrameDurationUs &contentRenderDurationUs,
                                               const Configuration &c);
 
+    // Process a frame judder.
+    static void processJudder(int32_t judderScore, int64_t judderTimeUs,
+                              int64_t lastJudderEndTimeUs,
+                              const FrameDurationUs &contentDurationUs,
+                              const FrameDurationUs &actualDurationUs, JudderEvent &e,
+                              VideoRenderQualityMetrics &m, const Configuration &c);
+
+    // Retrieve a judder event if an event just finished.
+    static void maybeCaptureJudderEvent(int64_t actualRenderTimeUs, int64_t lastJudderEndTimeUs,
+                                        JudderEvent &e, const VideoRenderQualityMetrics & m,
+                                        const Configuration &c, JudderEvent *judderEventOut);
+
     // Check to see if a discontinuity has occurred by examining the content time and the
     // app-desired render time. If so, reset some internal state.
     bool resetIfDiscontinuity(int64_t contentTimeUs, int64_t desiredRenderTimeUs);
@@ -252,7 +385,8 @@ private:
 
     // Update the metrics because a rendered frame was detected.
     void processMetricsForRenderedFrame(int64_t contentTimeUs, int64_t desiredRenderTimeUs,
-                                        int64_t actualRenderTimeUs);
+                                        int64_t actualRenderTimeUs,
+                                        FreezeEvent *freezeEventOut, JudderEvent *judderEventOut);
 
     // Configurable elements of the metrics algorithms.
     const Configuration mConfiguration;
@@ -269,12 +403,21 @@ private:
     // The most recent timestamp of the first frame rendered after the freeze.
     int64_t mLastFreezeEndTimeUs;
 
-    // The previous video frame was dropped.
-    bool mWasPreviousFrameDropped;
+    // The most recent timestamp of frame judder.
+    int64_t mLastJudderEndTimeUs;
 
     // The render duration of the playback.
     int64_t mRenderDurationMs;
 
+    // True if the previous frame was dropped.
+    bool mWasPreviousFrameDropped;
+
+    // The freeze event that's currently being tracked.
+    FreezeEvent mFreezeEvent;
+
+    // The judder event that's currently being tracked.
+    JudderEvent mJudderEvent;
+
     // Frames skipped at the end of playback shouldn't really be considered skipped, therefore keep
     // a list of the frames, and process them as skipped frames the next time a frame is rendered.
     std::list<int64_t> mPendingSkippedFrameContentTimeUsList;
diff --git a/arm/include/frameworks/av/media/ndk/include/media/NdkImage.h b/arm/include/frameworks/av/media/ndk/include/media/NdkImage.h
index 814a327e94a820f5514dfce296288b230583481c..76270d3069b1d49da928e7021d8daf8987af30d1 100644
--- a/arm/include/frameworks/av/media/ndk/include/media/NdkImage.h
+++ b/arm/include/frameworks/av/media/ndk/include/media/NdkImage.h
@@ -829,7 +829,7 @@ media_status_t AImage_getHardwareBuffer(const AImage* image, /*out*/AHardwareBuf
 /**
  * Query the dataspace of the input {@link AImage}.
  *
- * Available since API level 33.
+ * Available since API level 34.
  *
  * @param image the {@link AImage} of interest.
  * @param dataSpace the dataspace of the image will be filled here if the method call succeeds.
@@ -843,7 +843,7 @@ media_status_t AImage_getHardwareBuffer(const AImage* image, /*out*/AHardwareBuf
  *                 image has been deleted.</li></ul>
  */
 media_status_t AImage_getDataSpace(const AImage* image,
-                                   /*out*/int32_t* dataSpace) __INTRODUCED_IN(33);
+                                   /*out*/int32_t* dataSpace) __INTRODUCED_IN(34);
 
 __END_DECLS
 
diff --git a/arm/include/frameworks/av/media/ndk/include/media/NdkImageReader.h b/arm/include/frameworks/av/media/ndk/include/media/NdkImageReader.h
index 992955bb4a8bc722694c7ff141ae787a550fedb2..b6dcaaed0eb1f2261056d112f3d5af3192be9a86 100644
--- a/arm/include/frameworks/av/media/ndk/include/media/NdkImageReader.h
+++ b/arm/include/frameworks/av/media/ndk/include/media/NdkImageReader.h
@@ -395,7 +395,7 @@ media_status_t AImageReader_newWithUsage(
  * the combination of {@code hardwareBufferFormat} and {@code dataSpace} for the
  * format of the Image that the reader will produce.</p>
  *
- * Available since API level 33.
+ * Available since API level 34.
  *
  * @param width The default width in pixels of the Images that this reader will produce.
  * @param height The default height in pixels of the Images that this reader will produce.
@@ -422,7 +422,7 @@ media_status_t AImageReader_newWithUsage(
  */
 media_status_t AImageReader_newWithDataSpace(int32_t width, int32_t height, uint64_t usage,
         int32_t maxImages, uint32_t hardwareBufferFormat, int32_t dataSpace,
-        /*out*/ AImageReader** reader) __INTRODUCED_IN(33);
+        /*out*/ AImageReader** reader) __INTRODUCED_IN(34);
 
 /**
  * Acquire the next {@link AImage} from the image reader's queue asynchronously.
diff --git a/arm64/arch-arm-armv8-a/shared/vndk-core/libui.so b/arm64/arch-arm-armv8-a/shared/vndk-core/libui.so
index 2eee58660a64c14a0756e738ca52a6c14ab7aeec..7647c4bdcf064d3c817c38240add3743c02412f4 100755
Binary files a/arm64/arch-arm-armv8-a/shared/vndk-core/libui.so and b/arm64/arch-arm-armv8-a/shared/vndk-core/libui.so differ
diff --git a/arm64/arch-arm64-armv8-a/shared/vndk-core/libui.so b/arm64/arch-arm64-armv8-a/shared/vndk-core/libui.so
index d814dc3afaf3bc0ac4e741a5aaa3fa70b0d8e15c..2481260f2158cfc743144c4f7c1c0617be82f6ec 100755
Binary files a/arm64/arch-arm64-armv8-a/shared/vndk-core/libui.so and b/arm64/arch-arm64-armv8-a/shared/vndk-core/libui.so differ
diff --git a/arm64/include/frameworks/av/media/libstagefright/include/media/stagefright/VideoRenderQualityTracker.h b/arm64/include/frameworks/av/media/libstagefright/include/media/stagefright/VideoRenderQualityTracker.h
index 5cf674fad13f6fd67000013564c4056f6eb07455..82ba81caa1708dbeebe736371dd8006802e112af 100644
--- a/arm64/include/frameworks/av/media/libstagefright/include/media/stagefright/VideoRenderQualityTracker.h
+++ b/arm64/include/frameworks/av/media/libstagefright/include/media/stagefright/VideoRenderQualityTracker.h
@@ -62,20 +62,37 @@ struct VideoRenderQualityMetrics {
 
     // A histogram of the durations of freezes due to dropped/skipped frames.
     MediaHistogram<int32_t> freezeDurationMsHistogram;
-    // The computed overall freeze score using the above histogram and score conversion table.
+    // The computed overall freeze score using the above histogram and score conversion table. The
+    // score is based on counts in the histogram bucket, multiplied by the value in the score
+    // conversion table for that bucket. For example, the impact of a short freeze may be minimal,
+    // but the impact of long freeze may be disproportionally worse. Therefore, the score
+    // multipliers for each bucket might increase exponentially instead of linearly. A score
+    // multiplier of zero would reflect that small freeze durations have near-zero impact to the
+    // user experience.
     int32_t freezeScore;
     // The computed percentage of total playback duration that was frozen.
     float freezeRate;
+    // The number of freeze events.
+    int32_t freezeEventCount;
 
     // A histogram of the durations between each freeze.
     MediaHistogram<int32_t> freezeDistanceMsHistogram;
 
-    // A histogram of the judder scores.
+    // A histogram of the judder scores - based on the error tolerance between actual render
+    // duration of each frame and the ideal render duration.
     MediaHistogram<int32_t> judderScoreHistogram;
-    // The computed overall judder score using the above histogram and score conversion table.
+    // The computed overall judder score using the above histogram and score conversion table. The
+    // score is based on counts in the histogram bucket, multiplied by the value in the score
+    // conversion table for that bucket. For example, the impact of minimal judder may be small,
+    // but the impact of large judder may be disproportionally worse. Therefore, the score
+    // multipliers for each bucket might increase exponentially instead of linearly. A score
+    // multiplier of zero would reflect that small judder errors have near-zero impact to the user
+    // experience.
     int32_t judderScore;
     // The computed percentage of total frames that had judder.
     float judderRate;
+    // The number of judder events.
+    int32_t judderEventCount;
 };
 
 ///////////////////////////////////////////////////////
@@ -101,6 +118,15 @@ public:
     // Configurable elements of the metrics algorithms
     class Configuration {
     public:
+        // system/server_configurable_flags/libflags/include/get_flags.h:GetServerConfigurableFlag
+        typedef std::string (*GetServerConfigurableFlagFn)(
+                const std::string& experiment_category_name,
+                const std::string& experiment_flag_name,
+                const std::string& default_value);
+
+        static Configuration getFromServerConfigurableFlags(
+                GetServerConfigurableFlagFn getServerConfigurableFlagFn);
+
         Configuration();
 
         // Whether or not frame render quality is tracked.
@@ -124,27 +150,107 @@ public:
         // skip forward in content time is due to frame drops. If the app-desired frame duration is
         // short, but the content frame duration is large, it is assumed the app is intentionally
         // seeking forward.
-        int32_t contentTimeAdvancedForLiveContentToleranceUs;
+        int32_t liveContentFrameDropToleranceUs;
 
         // Freeze configuration
         //
         // The values used to distribute freeze durations across a histogram.
         std::vector<int32_t> freezeDurationMsHistogramBuckets;
-        // The values used to compare against freeze duration counts when determining an overall
-        // score.
+        //
+        // The values used to multiply the counts in the histogram buckets above to compute an
+        // overall score. This allows the score to reflect disproportionate impact as freeze
+        // durations increase.
         std::vector<int64_t> freezeDurationMsHistogramToScore;
+        //
         // The values used to distribute distances between freezes across a histogram.
         std::vector<int32_t> freezeDistanceMsHistogramBuckets;
+        //
+        // The maximum number of freeze events to send back to the caller.
+        int32_t freezeEventMax;
+        //
+        // The maximum number of detail entries tracked per freeze event.
+        int32_t freezeEventDetailsMax;
+        //
+        // The maximum distance in time between two freeze occurrences such that both will be
+        // lumped into the same freeze event.
+        int32_t freezeEventDistanceToleranceMs;
 
         // Judder configuration
         //
         // A judder error lower than this value is not scored as judder.
         int32_t judderErrorToleranceUs;
+        //
         // The values used to distribute judder scores across a histogram.
         std::vector<int32_t> judderScoreHistogramBuckets;
-        // The values used to compare against judder score histogram counts when determining an
-        // overall score.
-        std::vector<int32_t> judderScoreHistogramToScore;
+        //
+        // The values used to multiply the counts in the histogram buckets above to compute an
+        // overall score. This allows the score to reflect disproportionate impact as judder scores
+        // increase.
+        std::vector<int64_t> judderScoreHistogramToScore;
+        //
+        // The maximum number of judder events to send back to the caller.
+        int32_t judderEventMax;
+        //
+        // The maximum number of detail entries tracked per judder event.
+        int32_t judderEventDetailsMax;
+        //
+        // The maximum distance in time between two judder occurrences such that both will be
+        // lumped into the same judder event.
+        int32_t judderEventDistanceToleranceMs;
+    };
+
+    struct FreezeEvent {
+        // Details are captured for each freeze up to a limited number. The arrays are guaranteed to
+        // have the same size.
+        struct Details {
+            /// The duration of the freeze.
+            std::vector<int32_t> durationMs;
+            // The distance between the beginning of this freeze and the end of the previous freeze.
+            std::vector<int32_t> distanceMs;
+        };
+        // Whether or not the data in this structure is valid.
+        bool valid = false;
+        // The time at which the first freeze for this event was detected.
+        int64_t initialTimeUs;
+        // The total duration from the beginning of the first freeze to the end of the last freeze
+        // in this event.
+        int32_t durationMs;
+        // The number of freezes in this event.
+        int64_t count;
+        // The sum of all durations of all freezes in this event.
+        int64_t sumDurationMs;
+        // The sum of all distances between each freeze in this event.
+        int64_t sumDistanceMs;
+        // Detailed information for the first N freezes in this event.
+        Details details;
+    };
+
+    struct JudderEvent {
+        // Details are captured for each frame judder up to a limited number. The arrays are
+        // guaranteed to have the same size.
+        struct Details {
+            // The actual render duration of the frame for this judder occurrence.
+            std::vector<int32_t> actualRenderDurationUs;
+            // The content render duration of the frame for this judder occurrence.
+            std::vector<int32_t> contentRenderDurationUs;
+            // The distance from this judder occurrence and the previous judder occurrence.
+            std::vector<int32_t> distanceMs;
+        };
+        // Whether or not the data in this structure is valid.
+        bool valid = false;
+        // The time at which the first judder occurrence for this event was detected.
+        int64_t initialTimeUs;
+        // The total duration from the first judder occurrence to the last judder occurrence in this
+        // event.
+        int32_t durationMs;
+        // The number of judder occurrences in this event.
+        int64_t count;
+        // The sum of all judder scores in this event.
+        int64_t sumScore;
+        // The sum of all distances between each judder occurrence in this event.
+        int64_t sumDistanceMs;
+        // Detailed information for the first N judder occurrences in this event.
+        Details details;
     };
 
     VideoRenderQualityTracker();
@@ -164,7 +270,16 @@ public:
     void onFrameReleased(int64_t contentTimeUs, int64_t desiredRenderTimeNs);
 
     // Called when the system has detected that the frame has actually been rendered to the display.
-    void onFrameRendered(int64_t contentTimeUs, int64_t actualRenderTimeNs);
+    // Returns any freeze events or judder events that were detected.
+    void onFrameRendered(int64_t contentTimeUs, int64_t actualRenderTimeNs,
+                         FreezeEvent *freezeEventOut = nullptr,
+                         JudderEvent *judderEventOut = nullptr);
+
+    // Gets and resets data for the current freeze event.
+    FreezeEvent getAndResetFreezeEvent();
+
+    // Gets and resets data for the current judder event.
+    JudderEvent getAndResetJudderEvent();
 
     // Retrieve the metrics.
     const VideoRenderQualityMetrics &getMetrics();
@@ -233,13 +348,31 @@ private:
 
     // Process a frame freeze.
     static void processFreeze(int64_t actualRenderTimeUs, int64_t lastRenderTimeUs,
-                              int64_t lastFreezeEndTimeUs, VideoRenderQualityMetrics &m);
+                              int64_t lastFreezeEndTimeUs, FreezeEvent &e,
+                              VideoRenderQualityMetrics &m, const Configuration &c);
+
+    // Retrieve a freeze event if an event just finished.
+    static void maybeCaptureFreezeEvent(int64_t actualRenderTimeUs, int64_t lastFreezeEndTimeUs,
+                                        FreezeEvent &e, const VideoRenderQualityMetrics & m,
+                                        const Configuration &c, FreezeEvent *freezeEventOut);
 
     // Compute a judder score for the previously-rendered frame.
     static int64_t computePreviousJudderScore(const FrameDurationUs &actualRenderDurationUs,
                                               const FrameDurationUs &contentRenderDurationUs,
                                               const Configuration &c);
 
+    // Process a frame judder.
+    static void processJudder(int32_t judderScore, int64_t judderTimeUs,
+                              int64_t lastJudderEndTimeUs,
+                              const FrameDurationUs &contentDurationUs,
+                              const FrameDurationUs &actualDurationUs, JudderEvent &e,
+                              VideoRenderQualityMetrics &m, const Configuration &c);
+
+    // Retrieve a judder event if an event just finished.
+    static void maybeCaptureJudderEvent(int64_t actualRenderTimeUs, int64_t lastJudderEndTimeUs,
+                                        JudderEvent &e, const VideoRenderQualityMetrics & m,
+                                        const Configuration &c, JudderEvent *judderEventOut);
+
     // Check to see if a discontinuity has occurred by examining the content time and the
     // app-desired render time. If so, reset some internal state.
     bool resetIfDiscontinuity(int64_t contentTimeUs, int64_t desiredRenderTimeUs);
@@ -252,7 +385,8 @@ private:
 
     // Update the metrics because a rendered frame was detected.
     void processMetricsForRenderedFrame(int64_t contentTimeUs, int64_t desiredRenderTimeUs,
-                                        int64_t actualRenderTimeUs);
+                                        int64_t actualRenderTimeUs,
+                                        FreezeEvent *freezeEventOut, JudderEvent *judderEventOut);
 
     // Configurable elements of the metrics algorithms.
     const Configuration mConfiguration;
@@ -269,12 +403,21 @@ private:
     // The most recent timestamp of the first frame rendered after the freeze.
     int64_t mLastFreezeEndTimeUs;
 
-    // The previous video frame was dropped.
-    bool mWasPreviousFrameDropped;
+    // The most recent timestamp of frame judder.
+    int64_t mLastJudderEndTimeUs;
 
     // The render duration of the playback.
     int64_t mRenderDurationMs;
 
+    // True if the previous frame was dropped.
+    bool mWasPreviousFrameDropped;
+
+    // The freeze event that's currently being tracked.
+    FreezeEvent mFreezeEvent;
+
+    // The judder event that's currently being tracked.
+    JudderEvent mJudderEvent;
+
     // Frames skipped at the end of playback shouldn't really be considered skipped, therefore keep
     // a list of the frames, and process them as skipped frames the next time a frame is rendered.
     std::list<int64_t> mPendingSkippedFrameContentTimeUsList;
diff --git a/arm64/include/frameworks/av/media/ndk/include/media/NdkImage.h b/arm64/include/frameworks/av/media/ndk/include/media/NdkImage.h
index 814a327e94a820f5514dfce296288b230583481c..76270d3069b1d49da928e7021d8daf8987af30d1 100644
--- a/arm64/include/frameworks/av/media/ndk/include/media/NdkImage.h
+++ b/arm64/include/frameworks/av/media/ndk/include/media/NdkImage.h
@@ -829,7 +829,7 @@ media_status_t AImage_getHardwareBuffer(const AImage* image, /*out*/AHardwareBuf
 /**
  * Query the dataspace of the input {@link AImage}.
  *
- * Available since API level 33.
+ * Available since API level 34.
  *
  * @param image the {@link AImage} of interest.
  * @param dataSpace the dataspace of the image will be filled here if the method call succeeds.
@@ -843,7 +843,7 @@ media_status_t AImage_getHardwareBuffer(const AImage* image, /*out*/AHardwareBuf
  *                 image has been deleted.</li></ul>
  */
 media_status_t AImage_getDataSpace(const AImage* image,
-                                   /*out*/int32_t* dataSpace) __INTRODUCED_IN(33);
+                                   /*out*/int32_t* dataSpace) __INTRODUCED_IN(34);
 
 __END_DECLS
 
diff --git a/arm64/include/frameworks/av/media/ndk/include/media/NdkImageReader.h b/arm64/include/frameworks/av/media/ndk/include/media/NdkImageReader.h
index 992955bb4a8bc722694c7ff141ae787a550fedb2..b6dcaaed0eb1f2261056d112f3d5af3192be9a86 100644
--- a/arm64/include/frameworks/av/media/ndk/include/media/NdkImageReader.h
+++ b/arm64/include/frameworks/av/media/ndk/include/media/NdkImageReader.h
@@ -395,7 +395,7 @@ media_status_t AImageReader_newWithUsage(
  * the combination of {@code hardwareBufferFormat} and {@code dataSpace} for the
  * format of the Image that the reader will produce.</p>
  *
- * Available since API level 33.
+ * Available since API level 34.
  *
  * @param width The default width in pixels of the Images that this reader will produce.
  * @param height The default height in pixels of the Images that this reader will produce.
@@ -422,7 +422,7 @@ media_status_t AImageReader_newWithUsage(
  */
 media_status_t AImageReader_newWithDataSpace(int32_t width, int32_t height, uint64_t usage,
         int32_t maxImages, uint32_t hardwareBufferFormat, int32_t dataSpace,
-        /*out*/ AImageReader** reader) __INTRODUCED_IN(33);
+        /*out*/ AImageReader** reader) __INTRODUCED_IN(34);
 
 /**
  * Acquire the next {@link AImage} from the image reader's queue asynchronously.
diff --git a/x86/arch-x86/shared/vndk-core/libui.so b/x86/arch-x86/shared/vndk-core/libui.so
index da280ffd3127ac13225d7099152874c197060ff8..7822b01711ab7e66789be0b514a4ec6ffd751068 100755
Binary files a/x86/arch-x86/shared/vndk-core/libui.so and b/x86/arch-x86/shared/vndk-core/libui.so differ
diff --git a/x86/include/frameworks/av/media/libstagefright/include/media/stagefright/VideoRenderQualityTracker.h b/x86/include/frameworks/av/media/libstagefright/include/media/stagefright/VideoRenderQualityTracker.h
index 5cf674fad13f6fd67000013564c4056f6eb07455..82ba81caa1708dbeebe736371dd8006802e112af 100644
--- a/x86/include/frameworks/av/media/libstagefright/include/media/stagefright/VideoRenderQualityTracker.h
+++ b/x86/include/frameworks/av/media/libstagefright/include/media/stagefright/VideoRenderQualityTracker.h
@@ -62,20 +62,37 @@ struct VideoRenderQualityMetrics {
 
     // A histogram of the durations of freezes due to dropped/skipped frames.
     MediaHistogram<int32_t> freezeDurationMsHistogram;
-    // The computed overall freeze score using the above histogram and score conversion table.
+    // The computed overall freeze score using the above histogram and score conversion table. The
+    // score is based on counts in the histogram bucket, multiplied by the value in the score
+    // conversion table for that bucket. For example, the impact of a short freeze may be minimal,
+    // but the impact of long freeze may be disproportionally worse. Therefore, the score
+    // multipliers for each bucket might increase exponentially instead of linearly. A score
+    // multiplier of zero would reflect that small freeze durations have near-zero impact to the
+    // user experience.
     int32_t freezeScore;
     // The computed percentage of total playback duration that was frozen.
     float freezeRate;
+    // The number of freeze events.
+    int32_t freezeEventCount;
 
     // A histogram of the durations between each freeze.
     MediaHistogram<int32_t> freezeDistanceMsHistogram;
 
-    // A histogram of the judder scores.
+    // A histogram of the judder scores - based on the error tolerance between actual render
+    // duration of each frame and the ideal render duration.
     MediaHistogram<int32_t> judderScoreHistogram;
-    // The computed overall judder score using the above histogram and score conversion table.
+    // The computed overall judder score using the above histogram and score conversion table. The
+    // score is based on counts in the histogram bucket, multiplied by the value in the score
+    // conversion table for that bucket. For example, the impact of minimal judder may be small,
+    // but the impact of large judder may be disproportionally worse. Therefore, the score
+    // multipliers for each bucket might increase exponentially instead of linearly. A score
+    // multiplier of zero would reflect that small judder errors have near-zero impact to the user
+    // experience.
     int32_t judderScore;
     // The computed percentage of total frames that had judder.
     float judderRate;
+    // The number of judder events.
+    int32_t judderEventCount;
 };
 
 ///////////////////////////////////////////////////////
@@ -101,6 +118,15 @@ public:
     // Configurable elements of the metrics algorithms
     class Configuration {
     public:
+        // system/server_configurable_flags/libflags/include/get_flags.h:GetServerConfigurableFlag
+        typedef std::string (*GetServerConfigurableFlagFn)(
+                const std::string& experiment_category_name,
+                const std::string& experiment_flag_name,
+                const std::string& default_value);
+
+        static Configuration getFromServerConfigurableFlags(
+                GetServerConfigurableFlagFn getServerConfigurableFlagFn);
+
         Configuration();
 
         // Whether or not frame render quality is tracked.
@@ -124,27 +150,107 @@ public:
         // skip forward in content time is due to frame drops. If the app-desired frame duration is
         // short, but the content frame duration is large, it is assumed the app is intentionally
         // seeking forward.
-        int32_t contentTimeAdvancedForLiveContentToleranceUs;
+        int32_t liveContentFrameDropToleranceUs;
 
         // Freeze configuration
         //
         // The values used to distribute freeze durations across a histogram.
         std::vector<int32_t> freezeDurationMsHistogramBuckets;
-        // The values used to compare against freeze duration counts when determining an overall
-        // score.
+        //
+        // The values used to multiply the counts in the histogram buckets above to compute an
+        // overall score. This allows the score to reflect disproportionate impact as freeze
+        // durations increase.
         std::vector<int64_t> freezeDurationMsHistogramToScore;
+        //
         // The values used to distribute distances between freezes across a histogram.
         std::vector<int32_t> freezeDistanceMsHistogramBuckets;
+        //
+        // The maximum number of freeze events to send back to the caller.
+        int32_t freezeEventMax;
+        //
+        // The maximum number of detail entries tracked per freeze event.
+        int32_t freezeEventDetailsMax;
+        //
+        // The maximum distance in time between two freeze occurrences such that both will be
+        // lumped into the same freeze event.
+        int32_t freezeEventDistanceToleranceMs;
 
         // Judder configuration
         //
         // A judder error lower than this value is not scored as judder.
         int32_t judderErrorToleranceUs;
+        //
         // The values used to distribute judder scores across a histogram.
         std::vector<int32_t> judderScoreHistogramBuckets;
-        // The values used to compare against judder score histogram counts when determining an
-        // overall score.
-        std::vector<int32_t> judderScoreHistogramToScore;
+        //
+        // The values used to multiply the counts in the histogram buckets above to compute an
+        // overall score. This allows the score to reflect disproportionate impact as judder scores
+        // increase.
+        std::vector<int64_t> judderScoreHistogramToScore;
+        //
+        // The maximum number of judder events to send back to the caller.
+        int32_t judderEventMax;
+        //
+        // The maximum number of detail entries tracked per judder event.
+        int32_t judderEventDetailsMax;
+        //
+        // The maximum distance in time between two judder occurrences such that both will be
+        // lumped into the same judder event.
+        int32_t judderEventDistanceToleranceMs;
+    };
+
+    struct FreezeEvent {
+        // Details are captured for each freeze up to a limited number. The arrays are guaranteed to
+        // have the same size.
+        struct Details {
+            /// The duration of the freeze.
+            std::vector<int32_t> durationMs;
+            // The distance between the beginning of this freeze and the end of the previous freeze.
+            std::vector<int32_t> distanceMs;
+        };
+        // Whether or not the data in this structure is valid.
+        bool valid = false;
+        // The time at which the first freeze for this event was detected.
+        int64_t initialTimeUs;
+        // The total duration from the beginning of the first freeze to the end of the last freeze
+        // in this event.
+        int32_t durationMs;
+        // The number of freezes in this event.
+        int64_t count;
+        // The sum of all durations of all freezes in this event.
+        int64_t sumDurationMs;
+        // The sum of all distances between each freeze in this event.
+        int64_t sumDistanceMs;
+        // Detailed information for the first N freezes in this event.
+        Details details;
+    };
+
+    struct JudderEvent {
+        // Details are captured for each frame judder up to a limited number. The arrays are
+        // guaranteed to have the same size.
+        struct Details {
+            // The actual render duration of the frame for this judder occurrence.
+            std::vector<int32_t> actualRenderDurationUs;
+            // The content render duration of the frame for this judder occurrence.
+            std::vector<int32_t> contentRenderDurationUs;
+            // The distance from this judder occurrence and the previous judder occurrence.
+            std::vector<int32_t> distanceMs;
+        };
+        // Whether or not the data in this structure is valid.
+        bool valid = false;
+        // The time at which the first judder occurrence for this event was detected.
+        int64_t initialTimeUs;
+        // The total duration from the first judder occurrence to the last judder occurrence in this
+        // event.
+        int32_t durationMs;
+        // The number of judder occurrences in this event.
+        int64_t count;
+        // The sum of all judder scores in this event.
+        int64_t sumScore;
+        // The sum of all distances between each judder occurrence in this event.
+        int64_t sumDistanceMs;
+        // Detailed information for the first N judder occurrences in this event.
+        Details details;
     };
 
     VideoRenderQualityTracker();
@@ -164,7 +270,16 @@ public:
     void onFrameReleased(int64_t contentTimeUs, int64_t desiredRenderTimeNs);
 
     // Called when the system has detected that the frame has actually been rendered to the display.
-    void onFrameRendered(int64_t contentTimeUs, int64_t actualRenderTimeNs);
+    // Returns any freeze events or judder events that were detected.
+    void onFrameRendered(int64_t contentTimeUs, int64_t actualRenderTimeNs,
+                         FreezeEvent *freezeEventOut = nullptr,
+                         JudderEvent *judderEventOut = nullptr);
+
+    // Gets and resets data for the current freeze event.
+    FreezeEvent getAndResetFreezeEvent();
+
+    // Gets and resets data for the current judder event.
+    JudderEvent getAndResetJudderEvent();
 
     // Retrieve the metrics.
     const VideoRenderQualityMetrics &getMetrics();
@@ -233,13 +348,31 @@ private:
 
     // Process a frame freeze.
     static void processFreeze(int64_t actualRenderTimeUs, int64_t lastRenderTimeUs,
-                              int64_t lastFreezeEndTimeUs, VideoRenderQualityMetrics &m);
+                              int64_t lastFreezeEndTimeUs, FreezeEvent &e,
+                              VideoRenderQualityMetrics &m, const Configuration &c);
+
+    // Retrieve a freeze event if an event just finished.
+    static void maybeCaptureFreezeEvent(int64_t actualRenderTimeUs, int64_t lastFreezeEndTimeUs,
+                                        FreezeEvent &e, const VideoRenderQualityMetrics & m,
+                                        const Configuration &c, FreezeEvent *freezeEventOut);
 
     // Compute a judder score for the previously-rendered frame.
     static int64_t computePreviousJudderScore(const FrameDurationUs &actualRenderDurationUs,
                                               const FrameDurationUs &contentRenderDurationUs,
                                               const Configuration &c);
 
+    // Process a frame judder.
+    static void processJudder(int32_t judderScore, int64_t judderTimeUs,
+                              int64_t lastJudderEndTimeUs,
+                              const FrameDurationUs &contentDurationUs,
+                              const FrameDurationUs &actualDurationUs, JudderEvent &e,
+                              VideoRenderQualityMetrics &m, const Configuration &c);
+
+    // Retrieve a judder event if an event just finished.
+    static void maybeCaptureJudderEvent(int64_t actualRenderTimeUs, int64_t lastJudderEndTimeUs,
+                                        JudderEvent &e, const VideoRenderQualityMetrics & m,
+                                        const Configuration &c, JudderEvent *judderEventOut);
+
     // Check to see if a discontinuity has occurred by examining the content time and the
     // app-desired render time. If so, reset some internal state.
     bool resetIfDiscontinuity(int64_t contentTimeUs, int64_t desiredRenderTimeUs);
@@ -252,7 +385,8 @@ private:
 
     // Update the metrics because a rendered frame was detected.
     void processMetricsForRenderedFrame(int64_t contentTimeUs, int64_t desiredRenderTimeUs,
-                                        int64_t actualRenderTimeUs);
+                                        int64_t actualRenderTimeUs,
+                                        FreezeEvent *freezeEventOut, JudderEvent *judderEventOut);
 
     // Configurable elements of the metrics algorithms.
     const Configuration mConfiguration;
@@ -269,12 +403,21 @@ private:
     // The most recent timestamp of the first frame rendered after the freeze.
     int64_t mLastFreezeEndTimeUs;
 
-    // The previous video frame was dropped.
-    bool mWasPreviousFrameDropped;
+    // The most recent timestamp of frame judder.
+    int64_t mLastJudderEndTimeUs;
 
     // The render duration of the playback.
     int64_t mRenderDurationMs;
 
+    // True if the previous frame was dropped.
+    bool mWasPreviousFrameDropped;
+
+    // The freeze event that's currently being tracked.
+    FreezeEvent mFreezeEvent;
+
+    // The judder event that's currently being tracked.
+    JudderEvent mJudderEvent;
+
     // Frames skipped at the end of playback shouldn't really be considered skipped, therefore keep
     // a list of the frames, and process them as skipped frames the next time a frame is rendered.
     std::list<int64_t> mPendingSkippedFrameContentTimeUsList;
diff --git a/x86/include/frameworks/av/media/ndk/include/media/NdkImage.h b/x86/include/frameworks/av/media/ndk/include/media/NdkImage.h
index 814a327e94a820f5514dfce296288b230583481c..76270d3069b1d49da928e7021d8daf8987af30d1 100644
--- a/x86/include/frameworks/av/media/ndk/include/media/NdkImage.h
+++ b/x86/include/frameworks/av/media/ndk/include/media/NdkImage.h
@@ -829,7 +829,7 @@ media_status_t AImage_getHardwareBuffer(const AImage* image, /*out*/AHardwareBuf
 /**
  * Query the dataspace of the input {@link AImage}.
  *
- * Available since API level 33.
+ * Available since API level 34.
  *
  * @param image the {@link AImage} of interest.
  * @param dataSpace the dataspace of the image will be filled here if the method call succeeds.
@@ -843,7 +843,7 @@ media_status_t AImage_getHardwareBuffer(const AImage* image, /*out*/AHardwareBuf
  *                 image has been deleted.</li></ul>
  */
 media_status_t AImage_getDataSpace(const AImage* image,
-                                   /*out*/int32_t* dataSpace) __INTRODUCED_IN(33);
+                                   /*out*/int32_t* dataSpace) __INTRODUCED_IN(34);
 
 __END_DECLS
 
diff --git a/x86/include/frameworks/av/media/ndk/include/media/NdkImageReader.h b/x86/include/frameworks/av/media/ndk/include/media/NdkImageReader.h
index 992955bb4a8bc722694c7ff141ae787a550fedb2..b6dcaaed0eb1f2261056d112f3d5af3192be9a86 100644
--- a/x86/include/frameworks/av/media/ndk/include/media/NdkImageReader.h
+++ b/x86/include/frameworks/av/media/ndk/include/media/NdkImageReader.h
@@ -395,7 +395,7 @@ media_status_t AImageReader_newWithUsage(
  * the combination of {@code hardwareBufferFormat} and {@code dataSpace} for the
  * format of the Image that the reader will produce.</p>
  *
- * Available since API level 33.
+ * Available since API level 34.
  *
  * @param width The default width in pixels of the Images that this reader will produce.
  * @param height The default height in pixels of the Images that this reader will produce.
@@ -422,7 +422,7 @@ media_status_t AImageReader_newWithUsage(
  */
 media_status_t AImageReader_newWithDataSpace(int32_t width, int32_t height, uint64_t usage,
         int32_t maxImages, uint32_t hardwareBufferFormat, int32_t dataSpace,
-        /*out*/ AImageReader** reader) __INTRODUCED_IN(33);
+        /*out*/ AImageReader** reader) __INTRODUCED_IN(34);
 
 /**
  * Acquire the next {@link AImage} from the image reader's queue asynchronously.
diff --git a/x86_64/arch-x86-x86_64/shared/vndk-core/libui.so b/x86_64/arch-x86-x86_64/shared/vndk-core/libui.so
index ce3cdbd52e88b794b9fceb71e8816c8c18bc6ec6..fc0acebac47251e6a93f0048454ad56e2533b7e2 100755
Binary files a/x86_64/arch-x86-x86_64/shared/vndk-core/libui.so and b/x86_64/arch-x86-x86_64/shared/vndk-core/libui.so differ
diff --git a/x86_64/arch-x86_64/shared/vndk-core/libui.so b/x86_64/arch-x86_64/shared/vndk-core/libui.so
index 587d0d494cfdf17e176bf845395f56d249b453e4..82442f4d2f9f048d33f1e5dac7e1a9bab7315afe 100755
Binary files a/x86_64/arch-x86_64/shared/vndk-core/libui.so and b/x86_64/arch-x86_64/shared/vndk-core/libui.so differ
diff --git a/x86_64/include/frameworks/av/media/libstagefright/include/media/stagefright/VideoRenderQualityTracker.h b/x86_64/include/frameworks/av/media/libstagefright/include/media/stagefright/VideoRenderQualityTracker.h
index 5cf674fad13f6fd67000013564c4056f6eb07455..82ba81caa1708dbeebe736371dd8006802e112af 100644
--- a/x86_64/include/frameworks/av/media/libstagefright/include/media/stagefright/VideoRenderQualityTracker.h
+++ b/x86_64/include/frameworks/av/media/libstagefright/include/media/stagefright/VideoRenderQualityTracker.h
@@ -62,20 +62,37 @@ struct VideoRenderQualityMetrics {
 
     // A histogram of the durations of freezes due to dropped/skipped frames.
     MediaHistogram<int32_t> freezeDurationMsHistogram;
-    // The computed overall freeze score using the above histogram and score conversion table.
+    // The computed overall freeze score using the above histogram and score conversion table. The
+    // score is based on counts in the histogram bucket, multiplied by the value in the score
+    // conversion table for that bucket. For example, the impact of a short freeze may be minimal,
+    // but the impact of long freeze may be disproportionally worse. Therefore, the score
+    // multipliers for each bucket might increase exponentially instead of linearly. A score
+    // multiplier of zero would reflect that small freeze durations have near-zero impact to the
+    // user experience.
     int32_t freezeScore;
     // The computed percentage of total playback duration that was frozen.
     float freezeRate;
+    // The number of freeze events.
+    int32_t freezeEventCount;
 
     // A histogram of the durations between each freeze.
     MediaHistogram<int32_t> freezeDistanceMsHistogram;
 
-    // A histogram of the judder scores.
+    // A histogram of the judder scores - based on the error tolerance between actual render
+    // duration of each frame and the ideal render duration.
     MediaHistogram<int32_t> judderScoreHistogram;
-    // The computed overall judder score using the above histogram and score conversion table.
+    // The computed overall judder score using the above histogram and score conversion table. The
+    // score is based on counts in the histogram bucket, multiplied by the value in the score
+    // conversion table for that bucket. For example, the impact of minimal judder may be small,
+    // but the impact of large judder may be disproportionally worse. Therefore, the score
+    // multipliers for each bucket might increase exponentially instead of linearly. A score
+    // multiplier of zero would reflect that small judder errors have near-zero impact to the user
+    // experience.
     int32_t judderScore;
     // The computed percentage of total frames that had judder.
     float judderRate;
+    // The number of judder events.
+    int32_t judderEventCount;
 };
 
 ///////////////////////////////////////////////////////
@@ -101,6 +118,15 @@ public:
     // Configurable elements of the metrics algorithms
     class Configuration {
     public:
+        // system/server_configurable_flags/libflags/include/get_flags.h:GetServerConfigurableFlag
+        typedef std::string (*GetServerConfigurableFlagFn)(
+                const std::string& experiment_category_name,
+                const std::string& experiment_flag_name,
+                const std::string& default_value);
+
+        static Configuration getFromServerConfigurableFlags(
+                GetServerConfigurableFlagFn getServerConfigurableFlagFn);
+
         Configuration();
 
         // Whether or not frame render quality is tracked.
@@ -124,27 +150,107 @@ public:
         // skip forward in content time is due to frame drops. If the app-desired frame duration is
         // short, but the content frame duration is large, it is assumed the app is intentionally
         // seeking forward.
-        int32_t contentTimeAdvancedForLiveContentToleranceUs;
+        int32_t liveContentFrameDropToleranceUs;
 
         // Freeze configuration
         //
         // The values used to distribute freeze durations across a histogram.
         std::vector<int32_t> freezeDurationMsHistogramBuckets;
-        // The values used to compare against freeze duration counts when determining an overall
-        // score.
+        //
+        // The values used to multiply the counts in the histogram buckets above to compute an
+        // overall score. This allows the score to reflect disproportionate impact as freeze
+        // durations increase.
         std::vector<int64_t> freezeDurationMsHistogramToScore;
+        //
         // The values used to distribute distances between freezes across a histogram.
         std::vector<int32_t> freezeDistanceMsHistogramBuckets;
+        //
+        // The maximum number of freeze events to send back to the caller.
+        int32_t freezeEventMax;
+        //
+        // The maximum number of detail entries tracked per freeze event.
+        int32_t freezeEventDetailsMax;
+        //
+        // The maximum distance in time between two freeze occurrences such that both will be
+        // lumped into the same freeze event.
+        int32_t freezeEventDistanceToleranceMs;
 
         // Judder configuration
         //
         // A judder error lower than this value is not scored as judder.
         int32_t judderErrorToleranceUs;
+        //
         // The values used to distribute judder scores across a histogram.
         std::vector<int32_t> judderScoreHistogramBuckets;
-        // The values used to compare against judder score histogram counts when determining an
-        // overall score.
-        std::vector<int32_t> judderScoreHistogramToScore;
+        //
+        // The values used to multiply the counts in the histogram buckets above to compute an
+        // overall score. This allows the score to reflect disproportionate impact as judder scores
+        // increase.
+        std::vector<int64_t> judderScoreHistogramToScore;
+        //
+        // The maximum number of judder events to send back to the caller.
+        int32_t judderEventMax;
+        //
+        // The maximum number of detail entries tracked per judder event.
+        int32_t judderEventDetailsMax;
+        //
+        // The maximum distance in time between two judder occurrences such that both will be
+        // lumped into the same judder event.
+        int32_t judderEventDistanceToleranceMs;
+    };
+
+    struct FreezeEvent {
+        // Details are captured for each freeze up to a limited number. The arrays are guaranteed to
+        // have the same size.
+        struct Details {
+            /// The duration of the freeze.
+            std::vector<int32_t> durationMs;
+            // The distance between the beginning of this freeze and the end of the previous freeze.
+            std::vector<int32_t> distanceMs;
+        };
+        // Whether or not the data in this structure is valid.
+        bool valid = false;
+        // The time at which the first freeze for this event was detected.
+        int64_t initialTimeUs;
+        // The total duration from the beginning of the first freeze to the end of the last freeze
+        // in this event.
+        int32_t durationMs;
+        // The number of freezes in this event.
+        int64_t count;
+        // The sum of all durations of all freezes in this event.
+        int64_t sumDurationMs;
+        // The sum of all distances between each freeze in this event.
+        int64_t sumDistanceMs;
+        // Detailed information for the first N freezes in this event.
+        Details details;
+    };
+
+    struct JudderEvent {
+        // Details are captured for each frame judder up to a limited number. The arrays are
+        // guaranteed to have the same size.
+        struct Details {
+            // The actual render duration of the frame for this judder occurrence.
+            std::vector<int32_t> actualRenderDurationUs;
+            // The content render duration of the frame for this judder occurrence.
+            std::vector<int32_t> contentRenderDurationUs;
+            // The distance from this judder occurrence and the previous judder occurrence.
+            std::vector<int32_t> distanceMs;
+        };
+        // Whether or not the data in this structure is valid.
+        bool valid = false;
+        // The time at which the first judder occurrence for this event was detected.
+        int64_t initialTimeUs;
+        // The total duration from the first judder occurrence to the last judder occurrence in this
+        // event.
+        int32_t durationMs;
+        // The number of judder occurrences in this event.
+        int64_t count;
+        // The sum of all judder scores in this event.
+        int64_t sumScore;
+        // The sum of all distances between each judder occurrence in this event.
+        int64_t sumDistanceMs;
+        // Detailed information for the first N judder occurrences in this event.
+        Details details;
     };
 
     VideoRenderQualityTracker();
@@ -164,7 +270,16 @@ public:
     void onFrameReleased(int64_t contentTimeUs, int64_t desiredRenderTimeNs);
 
     // Called when the system has detected that the frame has actually been rendered to the display.
-    void onFrameRendered(int64_t contentTimeUs, int64_t actualRenderTimeNs);
+    // Returns any freeze events or judder events that were detected.
+    void onFrameRendered(int64_t contentTimeUs, int64_t actualRenderTimeNs,
+                         FreezeEvent *freezeEventOut = nullptr,
+                         JudderEvent *judderEventOut = nullptr);
+
+    // Gets and resets data for the current freeze event.
+    FreezeEvent getAndResetFreezeEvent();
+
+    // Gets and resets data for the current judder event.
+    JudderEvent getAndResetJudderEvent();
 
     // Retrieve the metrics.
     const VideoRenderQualityMetrics &getMetrics();
@@ -233,13 +348,31 @@ private:
 
     // Process a frame freeze.
     static void processFreeze(int64_t actualRenderTimeUs, int64_t lastRenderTimeUs,
-                              int64_t lastFreezeEndTimeUs, VideoRenderQualityMetrics &m);
+                              int64_t lastFreezeEndTimeUs, FreezeEvent &e,
+                              VideoRenderQualityMetrics &m, const Configuration &c);
+
+    // Retrieve a freeze event if an event just finished.
+    static void maybeCaptureFreezeEvent(int64_t actualRenderTimeUs, int64_t lastFreezeEndTimeUs,
+                                        FreezeEvent &e, const VideoRenderQualityMetrics & m,
+                                        const Configuration &c, FreezeEvent *freezeEventOut);
 
     // Compute a judder score for the previously-rendered frame.
     static int64_t computePreviousJudderScore(const FrameDurationUs &actualRenderDurationUs,
                                               const FrameDurationUs &contentRenderDurationUs,
                                               const Configuration &c);
 
+    // Process a frame judder.
+    static void processJudder(int32_t judderScore, int64_t judderTimeUs,
+                              int64_t lastJudderEndTimeUs,
+                              const FrameDurationUs &contentDurationUs,
+                              const FrameDurationUs &actualDurationUs, JudderEvent &e,
+                              VideoRenderQualityMetrics &m, const Configuration &c);
+
+    // Retrieve a judder event if an event just finished.
+    static void maybeCaptureJudderEvent(int64_t actualRenderTimeUs, int64_t lastJudderEndTimeUs,
+                                        JudderEvent &e, const VideoRenderQualityMetrics & m,
+                                        const Configuration &c, JudderEvent *judderEventOut);
+
     // Check to see if a discontinuity has occurred by examining the content time and the
     // app-desired render time. If so, reset some internal state.
     bool resetIfDiscontinuity(int64_t contentTimeUs, int64_t desiredRenderTimeUs);
@@ -252,7 +385,8 @@ private:
 
     // Update the metrics because a rendered frame was detected.
     void processMetricsForRenderedFrame(int64_t contentTimeUs, int64_t desiredRenderTimeUs,
-                                        int64_t actualRenderTimeUs);
+                                        int64_t actualRenderTimeUs,
+                                        FreezeEvent *freezeEventOut, JudderEvent *judderEventOut);
 
     // Configurable elements of the metrics algorithms.
     const Configuration mConfiguration;
@@ -269,12 +403,21 @@ private:
     // The most recent timestamp of the first frame rendered after the freeze.
     int64_t mLastFreezeEndTimeUs;
 
-    // The previous video frame was dropped.
-    bool mWasPreviousFrameDropped;
+    // The most recent timestamp of frame judder.
+    int64_t mLastJudderEndTimeUs;
 
     // The render duration of the playback.
     int64_t mRenderDurationMs;
 
+    // True if the previous frame was dropped.
+    bool mWasPreviousFrameDropped;
+
+    // The freeze event that's currently being tracked.
+    FreezeEvent mFreezeEvent;
+
+    // The judder event that's currently being tracked.
+    JudderEvent mJudderEvent;
+
     // Frames skipped at the end of playback shouldn't really be considered skipped, therefore keep
     // a list of the frames, and process them as skipped frames the next time a frame is rendered.
     std::list<int64_t> mPendingSkippedFrameContentTimeUsList;
diff --git a/x86_64/include/frameworks/av/media/ndk/include/media/NdkImage.h b/x86_64/include/frameworks/av/media/ndk/include/media/NdkImage.h
index 814a327e94a820f5514dfce296288b230583481c..76270d3069b1d49da928e7021d8daf8987af30d1 100644
--- a/x86_64/include/frameworks/av/media/ndk/include/media/NdkImage.h
+++ b/x86_64/include/frameworks/av/media/ndk/include/media/NdkImage.h
@@ -829,7 +829,7 @@ media_status_t AImage_getHardwareBuffer(const AImage* image, /*out*/AHardwareBuf
 /**
  * Query the dataspace of the input {@link AImage}.
  *
- * Available since API level 33.
+ * Available since API level 34.
  *
  * @param image the {@link AImage} of interest.
  * @param dataSpace the dataspace of the image will be filled here if the method call succeeds.
@@ -843,7 +843,7 @@ media_status_t AImage_getHardwareBuffer(const AImage* image, /*out*/AHardwareBuf
  *                 image has been deleted.</li></ul>
  */
 media_status_t AImage_getDataSpace(const AImage* image,
-                                   /*out*/int32_t* dataSpace) __INTRODUCED_IN(33);
+                                   /*out*/int32_t* dataSpace) __INTRODUCED_IN(34);
 
 __END_DECLS
 
diff --git a/x86_64/include/frameworks/av/media/ndk/include/media/NdkImageReader.h b/x86_64/include/frameworks/av/media/ndk/include/media/NdkImageReader.h
index 992955bb4a8bc722694c7ff141ae787a550fedb2..b6dcaaed0eb1f2261056d112f3d5af3192be9a86 100644
--- a/x86_64/include/frameworks/av/media/ndk/include/media/NdkImageReader.h
+++ b/x86_64/include/frameworks/av/media/ndk/include/media/NdkImageReader.h
@@ -395,7 +395,7 @@ media_status_t AImageReader_newWithUsage(
  * the combination of {@code hardwareBufferFormat} and {@code dataSpace} for the
  * format of the Image that the reader will produce.</p>
  *
- * Available since API level 33.
+ * Available since API level 34.
  *
  * @param width The default width in pixels of the Images that this reader will produce.
  * @param height The default height in pixels of the Images that this reader will produce.
@@ -422,7 +422,7 @@ media_status_t AImageReader_newWithUsage(
  */
 media_status_t AImageReader_newWithDataSpace(int32_t width, int32_t height, uint64_t usage,
         int32_t maxImages, uint32_t hardwareBufferFormat, int32_t dataSpace,
-        /*out*/ AImageReader** reader) __INTRODUCED_IN(33);
+        /*out*/ AImageReader** reader) __INTRODUCED_IN(34);
 
 /**
  * Acquire the next {@link AImage} from the image reader's queue asynchronously.