Merge "Remove __ANDROID_API__ #if checks."
diff --git a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
index 0e366cb..c62d302 100644
--- a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
@@ -310,8 +310,12 @@
     // FS/proc/*/mountinfo size > 0
     FileExists("FS/proc/1/mountinfo", 0U, 100000U);
 
-    // FS/data/misc/profiles/cur/0/*/primary.prof size > 0
-    FileExists("FS/data/misc/profiles/cur/0/com.android.phone/primary.prof", 0U, 100000U);
+    // FS/data/misc/profiles/cur/0/*/primary.prof should exist. Also, since dumpstate only adds
+    // profiles to the zip in the non-user build, a build checking is necessary here.
+    if (!PropertiesHelper::IsUserBuild()) {
+        ZipEntry entry;
+        GetEntry(handle, "FS/data/misc/profiles/cur/0/com.android.phone/primary.prof", &entry);
+    }
 }
 
 /**
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 65fc46e..4dfd1d0 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -1130,23 +1130,6 @@
     return true;
 }
 
-// Updates the access times of out_oat_path based on those from apk_path.
-void update_out_oat_access_times(const char* apk_path, const char* out_oat_path) {
-    struct stat input_stat;
-    memset(&input_stat, 0, sizeof(input_stat));
-    if (stat(apk_path, &input_stat) != 0) {
-        PLOG(ERROR) << "Could not stat " << apk_path << " during dexopt";
-        return;
-    }
-
-    struct utimbuf ut;
-    ut.actime = input_stat.st_atime;
-    ut.modtime = input_stat.st_mtime;
-    if (utime(out_oat_path, &ut) != 0) {
-        PLOG(WARNING) << "Could not update access times for " << apk_path << " during dexopt";
-    }
-}
-
 // Runs (execv) dexoptanalyzer on the given arguments.
 // The analyzer will check if the dex_file needs to be (re)compiled to match the compiler_filter.
 // If this is for a profile guided compilation, profile_was_updated will tell whether or not
@@ -1843,8 +1826,6 @@
         }
     }
 
-    update_out_oat_access_times(dex_path, out_oat.path().c_str());
-
     // We've been successful, don't delete output.
     out_oat.DisableCleanup();
     out_vdex.DisableCleanup();
diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp
index b21010d..0dbab4e 100644
--- a/cmds/servicemanager/ServiceManager.cpp
+++ b/cmds/servicemanager/ServiceManager.cpp
@@ -623,4 +623,21 @@
     return Status::ok();
 }
 
+Status ServiceManager::getServiceDebugInfo(std::vector<ServiceDebugInfo>* outReturn) {
+    if (!mAccess->canList(mAccess->getCallingContext())) {
+        return Status::fromExceptionCode(Status::EX_SECURITY);
+    }
+
+    outReturn->reserve(mNameToService.size());
+    for (auto const& [name, service] : mNameToService) {
+        ServiceDebugInfo info;
+        info.name = name;
+        info.debugPid = service.debugPid;
+
+        outReturn->push_back(std::move(info));
+    }
+
+    return Status::ok();
+}
+
 }  // namespace android
diff --git a/cmds/servicemanager/ServiceManager.h b/cmds/servicemanager/ServiceManager.h
index 9f43eb4..c089115 100644
--- a/cmds/servicemanager/ServiceManager.h
+++ b/cmds/servicemanager/ServiceManager.h
@@ -26,6 +26,7 @@
 
 using os::IClientCallback;
 using os::IServiceCallback;
+using os::ServiceDebugInfo;
 
 class ServiceManager : public os::BnServiceManager, public IBinder::DeathRecipient {
 public:
@@ -48,6 +49,7 @@
     binder::Status registerClientCallback(const std::string& name, const sp<IBinder>& service,
                                           const sp<IClientCallback>& cb) override;
     binder::Status tryUnregisterService(const std::string& name, const sp<IBinder>& binder) override;
+    binder::Status getServiceDebugInfo(std::vector<ServiceDebugInfo>* outReturn) override;
     void binderDied(const wp<IBinder>& who) override;
     void handleClientCallbacks();
 
diff --git a/data/etc/android.hardware.keystore.limited_use_key.xml b/data/etc/android.hardware.keystore.limited_use_key.xml
new file mode 100644
index 0000000..5217086
--- /dev/null
+++ b/data/etc/android.hardware.keystore.limited_use_key.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2021 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.
+-->
+
+<!-- Feature for devices with KeyMint that can enforce limited use key
+     in hardware with any max usage count (including count equals to 1). -->
+<permissions>
+    <feature name="android.hardware.keystore.limited_use_key" />
+</permissions>
\ No newline at end of file
diff --git a/data/etc/android.hardware.keystore.single_use_key.xml b/data/etc/android.hardware.keystore.single_use_key.xml
new file mode 100644
index 0000000..40e80aa
--- /dev/null
+++ b/data/etc/android.hardware.keystore.single_use_key.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2021 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.
+-->
+
+<!-- Feature for devices with KeyMint that only can enforce limited use key
+     in hardware with max usage count equals to 1. -->
+<permissions>
+    <feature name="android.hardware.keystore.single_use_key" />
+</permissions>
\ No newline at end of file
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index e754d74..ed079db 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -214,6 +214,7 @@
         "aidl/android/os/IClientCallback.aidl",
         "aidl/android/os/IServiceCallback.aidl",
         "aidl/android/os/IServiceManager.aidl",
+        "aidl/android/os/ServiceDebugInfo.aidl",
     ],
     path: "aidl",
 }
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index 5c34069..79a11d2 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -611,6 +611,12 @@
     mPostWriteStrongDerefs.clear();
 }
 
+void IPCThreadState::createTransactionReference(RefBase* ref)
+{
+    ref->incStrong(mProcess.get());
+    mPostWriteStrongDerefs.push(ref);
+}
+
 void IPCThreadState::joinThreadPool(bool isMain)
 {
     LOG_THREADPOOL("**** THREAD %p (PID %d) IS JOINING THE THREAD POOL\n", (void*)pthread_self(), getpid());
diff --git a/libs/binder/IpPrefix.cpp b/libs/binder/IpPrefix.cpp
index 8d62266..4edc493 100644
--- a/libs/binder/IpPrefix.cpp
+++ b/libs/binder/IpPrefix.cpp
@@ -24,12 +24,10 @@
 #include <log/log.h>
 #include <utils/Errors.h>
 
-using android::BAD_TYPE;
 using android::BAD_VALUE;
 using android::NO_ERROR;
 using android::Parcel;
 using android::status_t;
-using android::UNEXPECTED_NULL;
 
 namespace android {
 
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 8087443..8dab98e 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -2285,7 +2285,7 @@
         ssize_t written = TEMP_FAILURE_RETRY(
             ::write(comm, &message, sizeof(message)));
 
-        if (written == -1 || written != sizeof(message)) {
+        if (written != sizeof(message)) {
             ALOGW("Failed to detach ParcelFileDescriptor written: %zd err: %s",
                 written, strerror(errno));
             return BAD_TYPE;
diff --git a/libs/binder/PersistableBundle.cpp b/libs/binder/PersistableBundle.cpp
index c807cfe..406fee0 100644
--- a/libs/binder/PersistableBundle.cpp
+++ b/libs/binder/PersistableBundle.cpp
@@ -31,7 +31,6 @@
 using android::BAD_VALUE;
 using android::NO_ERROR;
 using android::Parcel;
-using android::sp;
 using android::status_t;
 using android::UNEXPECTED_NULL;
 
diff --git a/libs/binder/aidl/android/os/IServiceManager.aidl b/libs/binder/aidl/android/os/IServiceManager.aidl
index 2b1e492..ce30050 100644
--- a/libs/binder/aidl/android/os/IServiceManager.aidl
+++ b/libs/binder/aidl/android/os/IServiceManager.aidl
@@ -18,6 +18,7 @@
 
 import android.os.IClientCallback;
 import android.os.IServiceCallback;
+import android.os.ServiceDebugInfo;
 
 /**
  * Basic interface for finding and publishing system services.
@@ -116,4 +117,9 @@
      * Attempt to unregister and remove a service. Will fail if the service is still in use.
      */
     void tryUnregisterService(@utf8InCpp String name, IBinder service);
+
+    /**
+     * Get debug information for all currently registered services.
+     */
+    ServiceDebugInfo[] getServiceDebugInfo();
 }
diff --git a/libs/binder/aidl/android/os/ServiceDebugInfo.aidl b/libs/binder/aidl/android/os/ServiceDebugInfo.aidl
new file mode 100644
index 0000000..b95d222
--- /dev/null
+++ b/libs/binder/aidl/android/os/ServiceDebugInfo.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+/**
+ * Debug information associated with a registered service
+ * @hide
+ */
+parcelable ServiceDebugInfo {
+    /**
+     * Service name (see IServiceManager.addService/checkService/getService)
+     */
+    @utf8InCpp String name;
+    /**
+     * PID of service at the time of registration (may no longer be valid).
+     */
+    int debugPid;
+}
diff --git a/libs/binder/include/binder/IPCThreadState.h b/libs/binder/include/binder/IPCThreadState.h
index 0183324..23a0cb0 100644
--- a/libs/binder/include/binder/IPCThreadState.h
+++ b/libs/binder/include/binder/IPCThreadState.h
@@ -162,6 +162,12 @@
             // This constant needs to be kept in sync with Binder.UNSET_WORKSOURCE from the Java
             // side.
             static const int32_t kUnsetWorkSource = -1;
+
+            // Create a temp reference until commands in queue flushed to driver
+            // Internal only.
+            // @internal
+            void                 createTransactionReference(RefBase* ref);
+
 private:
                                 IPCThreadState();
                                 ~IPCThreadState();
diff --git a/libs/binder/include/binder/ParcelRef.h b/libs/binder/include/binder/ParcelRef.h
new file mode 100644
index 0000000..497da2d
--- /dev/null
+++ b/libs/binder/include/binder/ParcelRef.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#pragma once
+
+
+#include <binder/Parcel.h>
+#include <utils/RefBase.h>
+
+// ---------------------------------------------------------------------------
+namespace android {
+
+/**
+ * internal use only
+ * @internal
+ */
+class ParcelRef : public Parcel, public RefBase
+{
+public:
+    static sp<ParcelRef> create() {
+        return new ParcelRef();
+    }
+
+private:
+    ParcelRef() = default;
+};
+
+} // namespace android
+
+// ---------------------------------------------------------------------------
\ No newline at end of file
diff --git a/libs/binder/ndk/ibinder.cpp b/libs/binder/ndk/ibinder.cpp
index 454fbd0..3c90681 100644
--- a/libs/binder/ndk/ibinder.cpp
+++ b/libs/binder/ndk/ibinder.cpp
@@ -597,13 +597,6 @@
         return STATUS_INVALID_OPERATION;
     }
 
-    if (!binder->isRemote()) {
-        LOG(WARNING) << "A binder object at " << binder
-                     << " is being transacted on, however, this object is in the same process as "
-                        "its proxy. Transacting with this binder is expensive compared to just "
-                        "calling the corresponding functionality in the same process.";
-    }
-
     *in = new AParcel(binder);
     status_t status = (*in)->get()->writeInterfaceToken(clazz->getInterfaceDescriptor());
     binder_status_t ret = PruneStatusT(status);
diff --git a/libs/binder/rust/tests/serialization.rs b/libs/binder/rust/tests/serialization.rs
index 2ae13f4..2bf3d03 100644
--- a/libs/binder/rust/tests/serialization.rs
+++ b/libs/binder/rust/tests/serialization.rs
@@ -25,7 +25,6 @@
 use binder::parcel::ParcelFileDescriptor;
 
 use std::ffi::{c_void, CStr, CString};
-use std::panic::{self, AssertUnwindSafe};
 use std::sync::Once;
 
 #[allow(
@@ -73,22 +72,9 @@
 
 impl ReadParcelTest for () {}
 
-fn on_transact(
-    _service: &dyn ReadParcelTest,
-    code: TransactionCode,
-    parcel: &Parcel,
-    reply: &mut Parcel,
-) -> Result<()> {
-    panic::catch_unwind(AssertUnwindSafe(|| transact_inner(code, parcel, reply))).unwrap_or_else(
-        |e| {
-            eprintln!("Failure in Rust: {:?}", e.downcast_ref::<String>());
-            Err(StatusCode::FAILED_TRANSACTION)
-        },
-    )
-}
-
 #[allow(clippy::float_cmp)]
-fn transact_inner(code: TransactionCode, parcel: &Parcel, reply: &mut Parcel) -> Result<()> {
+fn on_transact(_service: &dyn ReadParcelTest, code: TransactionCode,
+               parcel: &Parcel, reply: &mut Parcel) -> Result<()> {
     match code {
         bindings::Transaction_TEST_BOOL => {
             assert_eq!(parcel.read::<bool>()?, true);
@@ -296,7 +282,7 @@
             ))?;
         }
         bindings::Transaction_TEST_FAIL => {
-            panic!("Testing expected failure");
+            return Err(StatusCode::FAILED_TRANSACTION)
         }
         _ => return Err(StatusCode::UNKNOWN_TRANSACTION),
     }
diff --git a/libs/cputimeinstate/cputimeinstate.cpp b/libs/cputimeinstate/cputimeinstate.cpp
index 2e72cc4..7e9bb7d 100644
--- a/libs/cputimeinstate/cputimeinstate.cpp
+++ b/libs/cputimeinstate/cputimeinstate.cpp
@@ -99,7 +99,7 @@
     struct dirent **dirlist;
     const char basepath[] = "/sys/devices/system/cpu/cpufreq";
     int ret = scandir(basepath, &dirlist, isPolicyFile, comparePolicyFiles);
-    if (ret == -1) return false;
+    if (ret == -1 || ret == 0) return false;
     gNPolicies = ret;
 
     std::vector<std::string> policyFileNames;
@@ -155,10 +155,14 @@
     return true;
 }
 
-static bool attachTracepointProgram(const std::string &eventType, const std::string &eventName) {
+static int retrieveProgramFd(const std::string &eventType, const std::string &eventName) {
     std::string path = StringPrintf(BPF_FS_PATH "prog_time_in_state_tracepoint_%s_%s",
                                     eventType.c_str(), eventName.c_str());
-    int prog_fd = retrieveProgram(path.c_str());
+    return retrieveProgram(path.c_str());
+}
+
+static bool attachTracepointProgram(const std::string &eventType, const std::string &eventName) {
+    int prog_fd = retrieveProgramFd(eventType, eventName);
     if (prog_fd < 0) return false;
     return bpf_attach_tracepoint(prog_fd, eventType.c_str(), eventName.c_str()) >= 0;
 }
@@ -174,6 +178,17 @@
     return {};
 }
 
+// Check if tracking is expected to work without activating it.
+bool isTrackingUidTimesSupported() {
+    auto freqs = getCpuFreqs();
+    if (!freqs || freqs->empty()) return false;
+    if (gTracking) return true;
+    if (retrieveProgramFd("sched", "sched_switch") < 0) return false;
+    if (retrieveProgramFd("power", "cpu_frequency") < 0) return false;
+    if (retrieveProgramFd("sched", "sched_process_free") < 0) return false;
+    return true;
+}
+
 // Start tracking and aggregating data to be reported by getUidCpuFreqTimes and getUidsCpuFreqTimes.
 // Returns true on success, false otherwise.
 // Tracking is active only once a live process has successfully called this function; if the calling
diff --git a/libs/cputimeinstate/cputimeinstate.h b/libs/cputimeinstate/cputimeinstate.h
index 46de669..4145374 100644
--- a/libs/cputimeinstate/cputimeinstate.h
+++ b/libs/cputimeinstate/cputimeinstate.h
@@ -22,6 +22,7 @@
 namespace android {
 namespace bpf {
 
+bool isTrackingUidTimesSupported();
 bool startTrackingUidTimes();
 std::optional<std::vector<std::vector<uint64_t>>> getTotalCpuFreqTimes();
 std::optional<std::vector<std::vector<uint64_t>>> getUidCpuFreqTimes(uint32_t uid);
diff --git a/libs/cputimeinstate/testtimeinstate.cpp b/libs/cputimeinstate/testtimeinstate.cpp
index d25b2e9..2112b10 100644
--- a/libs/cputimeinstate/testtimeinstate.cpp
+++ b/libs/cputimeinstate/testtimeinstate.cpp
@@ -40,6 +40,11 @@
 
 using std::vector;
 
+TEST(TimeInStateTest, IsTrackingSupported) {
+    isTrackingUidTimesSupported();
+    SUCCEED();
+}
+
 TEST(TimeInStateTest, TotalTimeInState) {
     auto times = getTotalCpuFreqTimes();
     ASSERT_TRUE(times.has_value());
diff --git a/libs/dumputils/dump_utils.cpp b/libs/dumputils/dump_utils.cpp
index 3faf792..8b3c3ad 100644
--- a/libs/dumputils/dump_utils.cpp
+++ b/libs/dumputils/dump_utils.cpp
@@ -52,7 +52,6 @@
 
 /* list of hal interface to dump containing process during native dumps */
 static const char* hal_interfaces_to_dump[] {
-        "android.hardware.audio@2.0::IDevicesFactory",
         "android.hardware.audio@4.0::IDevicesFactory",
         "android.hardware.audio@5.0::IDevicesFactory",
         "android.hardware.audio@6.0::IDevicesFactory",
diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
index 61f3fbb..708a5b8 100644
--- a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
@@ -78,8 +78,12 @@
 
     if (!validate(timestamp)) {
         // VSR could elect to ignore the incongruent timestamp or resetModel(). If ts is ignored,
-        // don't insert this ts into mTimestamps ringbuffer.
-        if (!mTimestamps.empty()) {
+        // don't insert this ts into mTimestamps ringbuffer. If we are still
+        // in the learning phase we should just clear all timestamps and start
+        // over.
+        if (mTimestamps.size() < kMinimumSamplesForPrediction) {
+            clearTimestamps();
+        } else if (!mTimestamps.empty()) {
             mKnownTimestamp =
                     std::max(timestamp, *std::max_element(mTimestamps.begin(), mTimestamps.end()));
         } else {
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 261722d..b15663e 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1725,8 +1725,14 @@
     // calculate the expected present time once and use the cached
     // value throughout this frame to make sure all layers are
     // seeing this same value.
-    const nsecs_t lastExpectedPresentTime = mExpectedPresentTime.load();
-    mExpectedPresentTime = expectedVSyncTime;
+    if (expectedVSyncTime >= frameStart) {
+        mExpectedPresentTime = expectedVSyncTime;
+    } else {
+        mExpectedPresentTime = mScheduler->getDispSyncExpectedPresentTime(frameStart);
+    }
+
+    const nsecs_t lastScheduledPresentTime = mScheduledPresentTime;
+    mScheduledPresentTime = expectedVSyncTime;
 
     // When Backpressure propagation is enabled we want to give a small grace period
     // for the present fence to fire instead of just giving up on this frame to handle cases
@@ -1756,7 +1762,7 @@
     const TracedOrdinal<bool> frameMissed = {"PrevFrameMissed",
                                              framePending ||
                                                      (previousPresentTime >= 0 &&
-                                                      (lastExpectedPresentTime <
+                                                      (lastScheduledPresentTime <
                                                        previousPresentTime - frameMissedSlop))};
     const TracedOrdinal<bool> hwcFrameMissed = {"PrevHwcFrameMissed",
                                                 mHadDeviceComposition && frameMissed};
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 61bd020..90ac856 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -1199,6 +1199,7 @@
     std::unique_ptr<scheduler::RefreshRateStats> mRefreshRateStats;
 
     std::atomic<nsecs_t> mExpectedPresentTime = 0;
+    nsecs_t mScheduledPresentTime = 0;
     hal::Vsync mHWCVsyncPendingState = hal::Vsync::DISABLE;
 
     /* ------------------------------------------------------------------------
diff --git a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
index d4cd11d..5e5d51c 100644
--- a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
@@ -450,6 +450,20 @@
     EXPECT_THAT(intercept, Eq(0));
 }
 
+TEST_F(VSyncPredictorTest, InconsistentVsyncValueIsFlushedEventually) {
+    EXPECT_TRUE(tracker.addVsyncTimestamp(600));
+    EXPECT_TRUE(tracker.needsMoreSamples());
+
+    EXPECT_FALSE(tracker.addVsyncTimestamp(mNow += mPeriod));
+
+    for (auto i = 0u; i < kMinimumSamplesForPrediction; i++) {
+        EXPECT_TRUE(tracker.needsMoreSamples());
+        EXPECT_TRUE(tracker.addVsyncTimestamp(mNow += mPeriod));
+    }
+
+    EXPECT_FALSE(tracker.needsMoreSamples());
+}
+
 } // namespace android::scheduler
 
 // TODO(b/129481165): remove the #pragma below and fix conversion issues