Clipboard: Change sequence_number from uint64_t to UnguessableToken

The sequence number is supposed to uniquely identify clipboard state,
but in practice this is not true since there can exist multiple
clipboard instances.

Also includes a small change to TestRunnerBindings::CopyImageThen
which may help with some flaky tests.

Bug: 1226356, 1098369
Change-Id: I416a003b3d78966404924a973dfb4890615f8ea4
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3011783
Reviewed-by: Darwin Huang <[email protected]>
Reviewed-by: danakj <[email protected]>
Reviewed-by: Peter Kvitek <[email protected]>
Reviewed-by: Victor Costan <[email protected]>
Reviewed-by: Ahmed Fakhry <[email protected]>
Reviewed-by: Gary Kacmarcik <[email protected]>
Reviewed-by: Scott Violet <[email protected]>
Reviewed-by: Peter Beverloo <[email protected]>
Commit-Queue: Austin Sullivan <[email protected]>
Cr-Commit-Position: refs/heads/master@{#903688}
diff --git a/ash/capture_mode/capture_mode_unittests.cc b/ash/capture_mode/capture_mode_unittests.cc
index de3b823..d0a79d4 100644
--- a/ash/capture_mode/capture_mode_unittests.cc
+++ b/ash/capture_mode/capture_mode_unittests.cc
@@ -3214,14 +3214,14 @@
   auto* clipboard = ui::Clipboard::GetForCurrentThread();
   ASSERT_NE(clipboard, nullptr);
 
-  const uint64_t before_sequence_number =
+  const ui::ClipboardSequenceNumberToken before_sequence_number =
       clipboard->GetSequenceNumber(ui::ClipboardBuffer::kCopyPaste);
 
   CaptureNotificationWaiter waiter;
   CaptureModeController::Get()->CaptureScreenshotsOfAllDisplays();
   waiter.Wait();
 
-  const uint64_t after_sequence_number =
+  const ui::ClipboardSequenceNumberToken after_sequence_number =
       clipboard->GetSequenceNumber(ui::ClipboardBuffer::kCopyPaste);
 
   EXPECT_NE(before_sequence_number, after_sequence_number);
diff --git a/chrome/browser/sharing/shared_clipboard/remote_copy_message_handler.cc b/chrome/browser/sharing/shared_clipboard/remote_copy_message_handler.cc
index 2fb42d1..68648af 100644
--- a/chrome/browser/sharing/shared_clipboard/remote_copy_message_handler.cc
+++ b/chrome/browser/sharing/shared_clipboard/remote_copy_message_handler.cc
@@ -140,7 +140,7 @@
 
   LogRemoteCopyReceivedTextSize(text.size());
 
-  uint64_t old_sequence_number =
+  ui::ClipboardSequenceNumberToken old_sequence_number =
       ui::Clipboard::GetForCurrentThread()->GetSequenceNumber(
           ui::ClipboardBuffer::kCopyPaste);
   base::ElapsedTimer write_timer;
@@ -254,7 +254,7 @@
                "RemoteCopyMessageHandler::WriteImageAndShowNotification",
                "bytes", image.computeByteSize());
 
-  uint64_t old_sequence_number =
+  ui::ClipboardSequenceNumberToken old_sequence_number =
       ui::Clipboard::GetForCurrentThread()->GetSequenceNumber(
           ui::ClipboardBuffer::kCopyPaste);
   base::ElapsedTimer write_timer;
@@ -300,12 +300,13 @@
       NotificationHandler::Type::SHARING, notification, /*metadata=*/nullptr);
 }
 
-void RemoteCopyMessageHandler::DetectWrite(uint64_t old_sequence_number,
-                                           base::TimeTicks start_ticks,
-                                           bool is_image) {
+void RemoteCopyMessageHandler::DetectWrite(
+    const ui::ClipboardSequenceNumberToken& old_sequence_number,
+    base::TimeTicks start_ticks,
+    bool is_image) {
   TRACE_EVENT0("sharing", "RemoteCopyMessageHandler::DetectWrite");
 
-  uint64_t current_sequence_number =
+  ui::ClipboardSequenceNumberToken current_sequence_number =
       ui::Clipboard::GetForCurrentThread()->GetSequenceNumber(
           ui::ClipboardBuffer::kCopyPaste);
   base::TimeDelta elapsed = base::TimeTicks::Now() - start_ticks;
diff --git a/chrome/browser/sharing/shared_clipboard/remote_copy_message_handler.h b/chrome/browser/sharing/shared_clipboard/remote_copy_message_handler.h
index 4d7ee5f4..b127bd1 100644
--- a/chrome/browser/sharing/shared_clipboard/remote_copy_message_handler.h
+++ b/chrome/browser/sharing/shared_clipboard/remote_copy_message_handler.h
@@ -13,6 +13,7 @@
 #include "chrome/browser/image_decoder/image_decoder.h"
 #include "chrome/browser/sharing/shared_clipboard/remote_copy_handle_message_result.h"
 #include "chrome/browser/sharing/sharing_message_handler.h"
+#include "ui/base/clipboard/clipboard.h"
 #include "url/gurl.h"
 
 class Profile;
@@ -49,7 +50,7 @@
   void OnURLLoadComplete(std::unique_ptr<std::string> content);
   void WriteImageAndShowNotification(const SkBitmap& image);
   void ShowNotification(const std::u16string& title, const SkBitmap& image);
-  void DetectWrite(uint64_t old_sequence_number,
+  void DetectWrite(const ui::ClipboardSequenceNumberToken& old_sequence_number,
                    base::TimeTicks start_ticks,
                    bool is_image);
   void Finish(RemoteCopyHandleMessageResult result);
diff --git a/chrome/browser/ui/ash/clipboard_util.cc b/chrome/browser/ui/ash/clipboard_util.cc
index 9412f5b..e3f11f6 100644
--- a/chrome/browser/ui/ash/clipboard_util.cc
+++ b/chrome/browser/ui/ash/clipboard_util.cc
@@ -54,7 +54,7 @@
  * `decoded_image` is the image we are attempting to copy to the clipboard.
  */
 void CopyImageToClipboard(bool maintain_clipboard,
-                          uint64_t clipboard_sequence,
+                          ui::ClipboardSequenceNumberToken clipboard_sequence,
                           base::OnceCallback<void(bool)> callback,
                           scoped_refptr<base::RefCountedString> png_data,
                           const SkBitmap& decoded_image) {
@@ -81,7 +81,7 @@
     return;
   }
 
-  uint64_t current_sequence =
+  ui::ClipboardSequenceNumberToken current_sequence =
       ui::ClipboardNonBacked::GetForCurrentThread()->GetSequenceNumber(
           ui::ClipboardBuffer::kCopyPaste);
   if (current_sequence != clipboard_sequence) {
@@ -119,14 +119,15 @@
   }
 
   content::GetUIThreadTaskRunner({})->PostTask(
-      FROM_HERE, base::BindOnce(&DecodeImageFileAndCopyToClipboard,
-                                /*clipboard_sequence=*/0,
-                                /*maintain_clipboard=*/false, png_data,
-                                base::DoNothing::Once<bool>()));
+      FROM_HERE,
+      base::BindOnce(&DecodeImageFileAndCopyToClipboard,
+                     /*clipboard_sequence=*/ui::ClipboardSequenceNumberToken(),
+                     /*maintain_clipboard=*/false, png_data,
+                     base::DoNothing::Once<bool>()));
 }
 
 void DecodeImageFileAndCopyToClipboard(
-    uint64_t clipboard_sequence,
+    ui::ClipboardSequenceNumberToken clipboard_sequence,
     bool maintain_clipboard,
     scoped_refptr<base::RefCountedString> png_data,
     base::OnceCallback<void(bool)> callback) {
diff --git a/chrome/browser/ui/ash/clipboard_util.h b/chrome/browser/ui/ash/clipboard_util.h
index ce7683a0..e707656 100644
--- a/chrome/browser/ui/ash/clipboard_util.h
+++ b/chrome/browser/ui/ash/clipboard_util.h
@@ -10,6 +10,8 @@
 #include "base/callback_forward.h"
 #include "base/memory/ref_counted_memory.h"
 #include "base/memory/scoped_refptr.h"
+#include "ui/base/clipboard/clipboard.h"
+
 namespace base {
 class FilePath;
 }  // namespace base
@@ -23,16 +25,16 @@
 // Takes an image file as a string and copies it to the system clipboard.
 //
 // `clipboard_sequence` - Clipboard version to determine whether the clipboard
-// state has changed. A sequence of 0 is used to specify an invalid sequence.
+// state has changed. An empty token is used to specify an invalid sequence.
 // `maintain_clipboard` - Used to determine whether or not we care about
 // maintaining the clipboard state or not. If this value is false, it is okay to
-// pass a `clipboard_sequence` of 0.
+// pass an empty `clipboard_sequence` token.
 // `png_data` - The image we want to copy to the clipboard as a string.
 // `callback` - Reports if the copy was successful. Reasons that this could
 // return false include that the sequence numbers do not match and when
 // `maintain_clipboard` is true.
 void DecodeImageFileAndCopyToClipboard(
-    uint64_t clipboard_sequence,
+    ui::ClipboardSequenceNumberToken clipboard_sequence,
     bool maintain_clipboard,
     scoped_refptr<base::RefCountedString> png_data,
     base::OnceCallback<void(bool)> callback);
diff --git a/content/browser/renderer_host/clipboard_host_impl.cc b/content/browser/renderer_host/clipboard_host_impl.cc
index 47d848a..08a3fde 100644
--- a/content/browser/renderer_host/clipboard_host_impl.cc
+++ b/content/browser/renderer_host/clipboard_host_impl.cc
@@ -542,7 +542,7 @@
 }
 
 void ClipboardHostImpl::PerformPasteIfContentAllowed(
-    uint64_t seqno,
+    const ui::ClipboardSequenceNumberToken& seqno,
     const ui::ClipboardFormatType& data_type,
     std::string data,
     IsClipboardPasteContentAllowedCallback callback) {
@@ -555,7 +555,7 @@
 }
 
 void ClipboardHostImpl::StartIsPasteContentAllowedRequest(
-    uint64_t seqno,
+    const ui::ClipboardSequenceNumberToken& seqno,
     const ui::ClipboardFormatType& data_type,
     std::string data) {
   static_cast<RenderFrameHostImpl*>(render_frame_host())
@@ -566,7 +566,7 @@
 }
 
 void ClipboardHostImpl::FinishPasteIfContentAllowed(
-    uint64_t seqno,
+    const ui::ClipboardSequenceNumberToken& seqno,
     ClipboardPasteContentAllowed allowed) {
   if (is_allowed_requests_.count(seqno) == 0)
     return;
diff --git a/content/browser/renderer_host/clipboard_host_impl.h b/content/browser/renderer_host/clipboard_host_impl.h
index da2a301..e920098 100644
--- a/content/browser/renderer_host/clipboard_host_impl.h
+++ b/content/browser/renderer_host/clipboard_host_impl.h
@@ -113,7 +113,7 @@
   // already been checked. |data| and |seqno| should corresponds to the same
   // clipboard data.
   void PerformPasteIfContentAllowed(
-      uint64_t seqno,
+      const ui::ClipboardSequenceNumberToken& seqno,
       const ui::ClipboardFormatType& data_type,
       std::string data,
       IsClipboardPasteContentAllowedCallback callback);
@@ -127,10 +127,12 @@
 
   // Completion callback of PerformPasteIfContentAllowed(). Sets the allowed
   // status for the clipboard data corresponding to sequence number |seqno|.
-  void FinishPasteIfContentAllowed(uint64_t seqno,
-                                   ClipboardPasteContentAllowed allowed);
+  void FinishPasteIfContentAllowed(
+      const ui::ClipboardSequenceNumberToken& seqno,
+      ClipboardPasteContentAllowed allowed);
 
-  const std::map<uint64_t, IsPasteContentAllowedRequest>&
+  const std::map<ui::ClipboardSequenceNumberToken,
+                 IsPasteContentAllowedRequest>&
   is_paste_allowed_requests_for_testing() {
     return is_allowed_requests_;
   }
@@ -191,7 +193,7 @@
   // Called by PerformPasteIfContentAllowed() when an is allowed request is
   // needed. Virtual to be overridden in tests.
   virtual void StartIsPasteContentAllowedRequest(
-      uint64_t seqno,
+      const ui::ClipboardSequenceNumberToken& seqno,
       const ui::ClipboardFormatType& data_type,
       std::string data);
 
@@ -218,7 +220,8 @@
 
   // Outstanding is allowed requests per clipboard contents.  Maps a clipboard
   // sequence number to an outstanding request.
-  std::map<uint64_t, IsPasteContentAllowedRequest> is_allowed_requests_;
+  std::map<ui::ClipboardSequenceNumberToken, IsPasteContentAllowedRequest>
+      is_allowed_requests_;
 
   base::WeakPtrFactory<ClipboardHostImpl> weak_ptr_factory_{this};
 };
diff --git a/content/browser/renderer_host/clipboard_host_impl_unittest.cc b/content/browser/renderer_host/clipboard_host_impl_unittest.cc
index cd6c9a75..ea62fd9 100644
--- a/content/browser/renderer_host/clipboard_host_impl_unittest.cc
+++ b/content/browser/renderer_host/clipboard_host_impl_unittest.cc
@@ -20,7 +20,9 @@
 #include "skia/ext/skia_utils_base.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/mojom/tokens/tokens.mojom-forward.h"
 #include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/base/clipboard/clipboard.h"
 #include "ui/base/clipboard/clipboard_buffer.h"
 #include "ui/base/clipboard/clipboard_format_type.h"
 #include "ui/base/clipboard/test/clipboard_test_util.h"
@@ -45,11 +47,11 @@
       : ClipboardHostImpl(render_frame_host, std::move(receiver)) {}
 
   void StartIsPasteContentAllowedRequest(
-      uint64_t seqno,
+      const ui::ClipboardSequenceNumberToken& seqno,
       const ui::ClipboardFormatType& data_type,
       std::string data) override {}
 
-  void CompleteRequest(uint64_t seqno) {
+  void CompleteRequest(const ui::ClipboardSequenceNumberToken& seqno) {
     FinishPasteIfContentAllowed(
         seqno, ClipboardHostImpl::ClipboardPasteContentAllowed(true));
   }
@@ -128,7 +130,7 @@
   bitmap.allocN32Pixels(3, 2);
   bitmap.eraseARGB(255, 0, 255, 0);
   mojo_clipboard()->WriteImage(bitmap);
-  uint64_t sequence_number =
+  ui::ClipboardSequenceNumberToken sequence_number =
       system_clipboard()->GetSequenceNumber(ui::ClipboardBuffer::kCopyPaste);
   mojo_clipboard()->CommitWrite();
   base::RunLoop().RunUntilIdle();
@@ -151,7 +153,7 @@
   bitmap.allocN32Pixels(3, 2);
   bitmap.eraseARGB(255, 0, 255, 0);
   mojo_clipboard()->WriteImage(bitmap);
-  uint64_t sequence_number =
+  ui::ClipboardSequenceNumberToken sequence_number =
       system_clipboard()->GetSequenceNumber(ui::ClipboardBuffer::kCopyPaste);
   mojo_clipboard()->CommitWrite();
   base::RunLoop().RunUntilIdle();
@@ -176,7 +178,7 @@
 }
 
 TEST_F(ClipboardHostImplTest, DoesNotCacheClipboard) {
-  uint64_t unused_sequence_number;
+  ui::ClipboardSequenceNumberToken unused_sequence_number;
   mojo_clipboard()->GetSequenceNumber(ui::ClipboardBuffer::kCopyPaste,
                                       &unused_sequence_number);
 
@@ -312,9 +314,9 @@
 
 TEST_F(ClipboardHostImplScanTest, PerformPasteIfContentAllowed) {
   int count = 0;
-
+  ui::ClipboardSequenceNumberToken sequence_number;
   clipboard_host_impl()->PerformPasteIfContentAllowed(
-      1, ui::ClipboardFormatType::GetPlainTextType(), "data",
+      sequence_number, ui::ClipboardFormatType::GetPlainTextType(), "data",
       base::BindLambdaForTesting(
           [&count](ClipboardHostImpl::ClipboardPasteContentAllowed allowed) {
             ++count;
@@ -327,7 +329,7 @@
 
   // Completing the request invokes the callback.  The request will
   // remain pending until it is cleaned up.
-  clipboard_host_impl()->CompleteRequest(1);
+  clipboard_host_impl()->CompleteRequest(sequence_number);
   EXPECT_EQ(
       1u,
       clipboard_host_impl()->is_paste_allowed_requests_for_testing().size());
@@ -335,11 +337,12 @@
 }
 
 TEST_F(ClipboardHostImplScanTest, CleanupObsoleteScanRequests) {
+  ui::ClipboardSequenceNumberToken sequence_number;
   // Perform a request and complete it.
   clipboard_host_impl()->PerformPasteIfContentAllowed(
-      1, ui::ClipboardFormatType::GetPlainTextType(), "data",
+      sequence_number, ui::ClipboardFormatType::GetPlainTextType(), "data",
       base::DoNothing());
-  clipboard_host_impl()->CompleteRequest(1);
+  clipboard_host_impl()->CompleteRequest(sequence_number);
   EXPECT_EQ(
       1u,
       clipboard_host_impl()->is_paste_allowed_requests_for_testing().size());
diff --git a/content/test/mock_clipboard_host.cc b/content/test/mock_clipboard_host.cc
index f819259..346e9d269 100644
--- a/content/test/mock_clipboard_host.cc
+++ b/content/test/mock_clipboard_host.cc
@@ -10,6 +10,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "mojo/public/cpp/base/big_buffer.h"
 #include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/base/clipboard/clipboard.h"
 #include "ui/gfx/codec/png_codec.h"
 
 namespace content {
@@ -171,7 +172,7 @@
 }
 
 void MockClipboardHost::CommitWrite() {
-  ++sequence_number_;
+  sequence_number_ = ui::ClipboardSequenceNumberToken();
   needs_reset_ = true;
 }
 
diff --git a/content/test/mock_clipboard_host.h b/content/test/mock_clipboard_host.h
index 24c16ae..368695a2 100644
--- a/content/test/mock_clipboard_host.h
+++ b/content/test/mock_clipboard_host.h
@@ -12,6 +12,7 @@
 #include "mojo/public/cpp/bindings/receiver_set.h"
 #include "third_party/blink/public/mojom/clipboard/clipboard.mojom.h"
 #include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/base/clipboard/clipboard.h"
 
 namespace content {
 
@@ -64,7 +65,7 @@
 #endif
  private:
   mojo::ReceiverSet<blink::mojom::ClipboardHost> receivers_;
-  uint64_t sequence_number_ = 0;
+  ui::ClipboardSequenceNumberToken sequence_number_;
   std::u16string plain_text_;
   std::u16string html_text_;
   std::u16string svg_text_;
diff --git a/content/web_test/renderer/test_runner.cc b/content/web_test/renderer/test_runner.cc
index 1025e7d..4473e32 100644
--- a/content/web_test/renderer/test_runner.cc
+++ b/content/web_test/renderer/test_runner.cc
@@ -1923,14 +1923,14 @@
   frame_->GetBrowserInterfaceBroker()->GetInterface(
       remote_clipboard.BindNewPipeAndPassReceiver());
 
-  uint64_t sequence_number_before = 0;
-  remote_clipboard->GetSequenceNumber(ui::ClipboardBuffer::kCopyPaste,
-                                      &sequence_number_before);
+  blink::ClipboardSequenceNumberToken sequence_number_before;
+  CHECK(remote_clipboard->GetSequenceNumber(ui::ClipboardBuffer::kCopyPaste,
+                                            &sequence_number_before));
   GetWebFrame()->CopyImageAtForTesting(gfx::Point(x, y));
-  uint64_t sequence_number_after = 0;
-  while (sequence_number_before == sequence_number_after) {
-    remote_clipboard->GetSequenceNumber(ui::ClipboardBuffer::kCopyPaste,
-                                        &sequence_number_after);
+  auto sequence_number_after = sequence_number_before;
+  while (sequence_number_before.value() == sequence_number_after.value()) {
+    CHECK(remote_clipboard->GetSequenceNumber(ui::ClipboardBuffer::kCopyPaste,
+                                              &sequence_number_after));
   }
 
   SkBitmap bitmap;
diff --git a/headless/lib/browser/headless_clipboard.cc b/headless/lib/browser/headless_clipboard.cc
index 3345b50..aceadbc 100644
--- a/headless/lib/browser/headless_clipboard.cc
+++ b/headless/lib/browser/headless_clipboard.cc
@@ -8,6 +8,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/numerics/safe_conversions.h"
 #include "base/strings/utf_string_conversions.h"
+#include "ui/base/clipboard/clipboard.h"
 #include "ui/base/clipboard/clipboard_constants.h"
 #include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
 #include "ui/gfx/codec/png_codec.h"
@@ -27,7 +28,7 @@
   return nullptr;
 }
 
-uint64_t HeadlessClipboard::GetSequenceNumber(
+const ui::ClipboardSequenceNumberToken& HeadlessClipboard::GetSequenceNumber(
     ui::ClipboardBuffer buffer) const {
   return GetStore(buffer).sequence_number;
 }
@@ -291,7 +292,7 @@
   GetDefaultStore().data[format] = std::string(data_data, data_len);
 }
 
-HeadlessClipboard::DataStore::DataStore() : sequence_number(0) {}
+HeadlessClipboard::DataStore::DataStore() = default;
 
 HeadlessClipboard::DataStore::DataStore(const DataStore& other) = default;
 
@@ -314,7 +315,7 @@
     ui::ClipboardBuffer buffer) {
   CHECK(IsSupportedClipboardBuffer(buffer));
   DataStore& store = stores_[buffer];
-  ++store.sequence_number;
+  store.sequence_number = ui::ClipboardSequenceNumberToken();
   return store;
 }
 
diff --git a/headless/lib/browser/headless_clipboard.h b/headless/lib/browser/headless_clipboard.h
index 582aa08c..2956529e 100644
--- a/headless/lib/browser/headless_clipboard.h
+++ b/headless/lib/browser/headless_clipboard.h
@@ -28,7 +28,8 @@
   void OnPreShutdown() override;
   ui::DataTransferEndpoint* GetSource(
       ui::ClipboardBuffer buffer) const override;
-  uint64_t GetSequenceNumber(ui::ClipboardBuffer buffer) const override;
+  const ui::ClipboardSequenceNumberToken& GetSequenceNumber(
+      ui::ClipboardBuffer buffer) const override;
   bool IsFormatAvailable(
       const ui::ClipboardFormatType& format,
       ui::ClipboardBuffer buffer,
@@ -108,7 +109,7 @@
     DataStore(const DataStore& other);
     ~DataStore();
     void Clear();
-    uint64_t sequence_number;
+    ui::ClipboardSequenceNumberToken sequence_number;
     std::map<ui::ClipboardFormatType, std::string> data;
     std::string url_title;
     std::string html_src_url;
diff --git a/remoting/host/chromeos/clipboard_aura.cc b/remoting/host/chromeos/clipboard_aura.cc
index e95356c..54ac117 100644
--- a/remoting/host/chromeos/clipboard_aura.cc
+++ b/remoting/host/chromeos/clipboard_aura.cc
@@ -25,10 +25,8 @@
 namespace remoting {
 
 ClipboardAura::ClipboardAura()
-    : current_change_count_(0),
-      polling_interval_(
-          base::TimeDelta::FromMilliseconds(kClipboardPollingIntervalMs)) {
-}
+    : polling_interval_(
+          base::TimeDelta::FromMilliseconds(kClipboardPollingIntervalMs)) {}
 
 ClipboardAura::~ClipboardAura() {
   DCHECK(thread_checker_.CalledOnValidThread());
@@ -58,9 +56,9 @@
   ui::ScopedClipboardWriter clipboard_writer(ui::ClipboardBuffer::kCopyPaste);
   clipboard_writer.WriteText(base::UTF8ToUTF16(event.data()));
 
-  // Update local change-count to prevent this change from being picked up by
+  // Update local change-token to prevent this change from being picked up by
   // CheckClipboardForChanges.
-  current_change_count_++;
+  current_change_token_ = ui::ClipboardSequenceNumberToken();
 }
 
 void ClipboardAura::SetPollingIntervalForTesting(
@@ -74,14 +72,14 @@
   DCHECK(thread_checker_.CalledOnValidThread());
 
   ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
-  uint64_t change_count =
+  ui::ClipboardSequenceNumberToken change_token =
       clipboard->GetSequenceNumber(ui::ClipboardBuffer::kCopyPaste);
 
-  if (change_count == current_change_count_) {
+  if (change_token == current_change_token_) {
     return;
   }
 
-  current_change_count_ = change_count;
+  current_change_token_ = change_token;
 
   protocol::ClipboardEvent event;
   std::string data;
diff --git a/remoting/host/chromeos/clipboard_aura.h b/remoting/host/chromeos/clipboard_aura.h
index b3f8053..5262fc37 100644
--- a/remoting/host/chromeos/clipboard_aura.h
+++ b/remoting/host/chromeos/clipboard_aura.h
@@ -13,6 +13,7 @@
 #include "base/threading/thread_checker.h"
 #include "base/timer/timer.h"
 #include "remoting/host/clipboard.h"
+#include "ui/base/clipboard/clipboard.h"
 
 namespace remoting {
 
@@ -49,7 +50,7 @@
   base::ThreadChecker thread_checker_;
   std::unique_ptr<protocol::ClipboardStub> client_clipboard_;
   base::RepeatingTimer clipboard_polling_timer_;
-  uint64_t current_change_count_;
+  ui::ClipboardSequenceNumberToken current_change_token_;
   base::TimeDelta polling_interval_;
 
   DISALLOW_COPY_AND_ASSIGN(ClipboardAura);
diff --git a/third_party/blink/public/common/DEPS b/third_party/blink/public/common/DEPS
index 5942ca7..0118a7b0 100644
--- a/third_party/blink/public/common/DEPS
+++ b/third_party/blink/public/common/DEPS
@@ -21,6 +21,7 @@
     "+skia/public/mojom",
     "+third_party/blink/public/common",
     "+third_party/blink/public/mojom",
+    "+ui/base/clipboard/clipboard_sequence_number_token.h",
     "+ui/base/pointer/pointer_device.h",
     "+ui/base/page_transition_types.h",
     "+ui/base/ui_base_types.h",
diff --git a/third_party/blink/public/common/tokens/BUILD.gn b/third_party/blink/public/common/tokens/BUILD.gn
index b198ad40..f38a11f 100644
--- a/third_party/blink/public/common/tokens/BUILD.gn
+++ b/third_party/blink/public/common/tokens/BUILD.gn
@@ -20,5 +20,6 @@
     "//mojo/public/cpp/system",
     "//mojo/public/mojom/base",
     "//third_party/blink/public/common:common_export",
+    "//ui/base/clipboard:clipboard",
   ]
 }
diff --git a/third_party/blink/public/common/tokens/tokens.h b/third_party/blink/public/common/tokens/tokens.h
index d96a7eb..f353ba4 100644
--- a/third_party/blink/public/common/tokens/tokens.h
+++ b/third_party/blink/public/common/tokens/tokens.h
@@ -7,6 +7,7 @@
 
 #include "base/types/token_type.h"
 #include "third_party/blink/public/common/tokens/multi_token.h"
+#include "ui/base/clipboard/clipboard_sequence_number_token.h"
 
 namespace blink {
 
@@ -107,6 +108,9 @@
 // Identifies a v8::Context / blink::ScriptState.
 using V8ContextToken = base::TokenType<class V8ContextTokenTypeMarker>;
 
+// Identifies a unique clipboard state.
+using ClipboardSequenceNumberToken = ui::ClipboardSequenceNumberToken;
+
 }  // namespace blink
 
 #endif  // THIRD_PARTY_BLINK_PUBLIC_COMMON_TOKENS_TOKENS_H_
diff --git a/third_party/blink/public/common/tokens/tokens_mojom_traits.h b/third_party/blink/public/common/tokens/tokens_mojom_traits.h
index aa03898..22a38727 100644
--- a/third_party/blink/public/common/tokens/tokens_mojom_traits.h
+++ b/third_party/blink/public/common/tokens/tokens_mojom_traits.h
@@ -177,6 +177,13 @@
     : public blink::TokenMojomTraitsHelper<blink::mojom::V8ContextTokenDataView,
                                            blink::V8ContextToken> {};
 
+template <>
+struct StructTraits<blink::mojom::ClipboardSequenceNumberTokenDataView,
+                    blink::ClipboardSequenceNumberToken>
+    : public blink::TokenMojomTraitsHelper<
+          blink::mojom::ClipboardSequenceNumberTokenDataView,
+          blink::ClipboardSequenceNumberToken> {};
+
 }  // namespace mojo
 
 #endif  // THIRD_PARTY_BLINK_PUBLIC_COMMON_TOKENS_TOKENS_MOJOM_TRAITS_H_
diff --git a/third_party/blink/public/mojom/clipboard/clipboard.mojom b/third_party/blink/public/mojom/clipboard/clipboard.mojom
index 10dd825..e2a005e 100644
--- a/third_party/blink/public/mojom/clipboard/clipboard.mojom
+++ b/third_party/blink/public/mojom/clipboard/clipboard.mojom
@@ -4,11 +4,12 @@
 
 module blink.mojom;
 
-import "mojo/public/mojom/base/string16.mojom";
 import "mojo/public/mojom/base/big_buffer.mojom";
 import "mojo/public/mojom/base/big_string.mojom";
+import "mojo/public/mojom/base/string16.mojom";
 import "skia/public/mojom/bitmap.mojom";
 import "third_party/blink/public/mojom/data_transfer/data_transfer.mojom";
+import "third_party/blink/public/mojom/tokens/tokens.mojom";
 import "url/mojom/url.mojom";
 
 enum ClipboardFormat {
@@ -40,8 +41,12 @@
 // Therefore, it's possible that one may see text available from
 // ReadAvailableTypes(), but that a subsequent ReadText() may then fail.
 interface ClipboardHost {
+  // Returns a token which uniquely identifies clipboard state.
+  // This can be used to version the data on the clipboard and determine
+  // whether it has changed.
   [Sync]
-  GetSequenceNumber(ClipboardBuffer buffer) => (uint64 result);
+  GetSequenceNumber(ClipboardBuffer buffer) =>
+      (blink.mojom.ClipboardSequenceNumberToken result);
 
   [Sync]
   IsFormatAvailable(ClipboardFormat format,
diff --git a/third_party/blink/public/mojom/tokens/BUILD.gn b/third_party/blink/public/mojom/tokens/BUILD.gn
index 38d35a7..c7f9a0d 100644
--- a/third_party/blink/public/mojom/tokens/BUILD.gn
+++ b/third_party/blink/public/mojom/tokens/BUILD.gn
@@ -83,6 +83,10 @@
           mojom = "blink.mojom.V8ContextToken"
           cpp = "::blink::V8ContextToken"
         },
+        {
+          mojom = "blink.mojom.ClipboardSequenceNumberToken"
+          cpp = "::blink::ClipboardSequenceNumberToken"
+        },
       ]
       traits_headers = [
         "//third_party/blink/public/common/tokens/token_mojom_traits_helper.h",
diff --git a/third_party/blink/public/mojom/tokens/tokens.mojom b/third_party/blink/public/mojom/tokens/tokens.mojom
index 6db6fbb..9a0d9e9 100644
--- a/third_party/blink/public/mojom/tokens/tokens.mojom
+++ b/third_party/blink/public/mojom/tokens/tokens.mojom
@@ -106,3 +106,7 @@
 struct V8ContextToken {
   mojo_base.mojom.UnguessableToken value;
 };
+
+struct ClipboardSequenceNumberToken {
+  mojo_base.mojom.UnguessableToken value;
+};
\ No newline at end of file
diff --git a/third_party/blink/renderer/core/clipboard/data_object.cc b/third_party/blink/renderer/core/clipboard/data_object.cc
index ee6da6d3..a328b62 100644
--- a/third_party/blink/renderer/core/clipboard/data_object.cc
+++ b/third_party/blink/renderer/core/clipboard/data_object.cc
@@ -51,7 +51,8 @@
 #if DCHECK_IS_ON()
   HashSet<String> types_seen;
 #endif
-  uint64_t sequence_number = system_clipboard->SequenceNumber();
+  ClipboardSequenceNumberToken sequence_number =
+      system_clipboard->SequenceNumber();
   for (const String& type : system_clipboard->ReadAvailableTypes()) {
     if (paste_mode == PasteMode::kPlainTextOnly && type != kMimeTypeTextPlain)
       continue;
diff --git a/third_party/blink/renderer/core/clipboard/data_object_item.cc b/third_party/blink/renderer/core/clipboard/data_object_item.cc
index bcbd518..e4ddd63 100644
--- a/third_party/blink/renderer/core/clipboard/data_object_item.cc
+++ b/third_party/blink/renderer/core/clipboard/data_object_item.cc
@@ -31,6 +31,8 @@
 #include "third_party/blink/renderer/core/clipboard/data_object_item.h"
 
 #include "base/time/time.h"
+#include "base/unguessable_token.h"
+#include "third_party/blink/public/common/tokens/tokens.h"
 #include "third_party/blink/public/mojom/file_system_access/file_system_access_data_transfer_token.mojom-blink.h"
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/renderer/core/clipboard/clipboard_mime_types.h"
@@ -114,7 +116,7 @@
 DataObjectItem* DataObjectItem::CreateFromClipboard(
     SystemClipboard* system_clipboard,
     const String& type,
-    uint64_t sequence_number) {
+    const ClipboardSequenceNumberToken& sequence_number) {
   if (type == kMimeTypeImagePng) {
     return MakeGarbageCollected<DataObjectItem>(
         kFileKind, type, sequence_number, system_clipboard);
@@ -127,13 +129,14 @@
     : source_(DataSource::kInternalSource),
       kind_(kind),
       type_(type),
-      sequence_number_(0),
+      sequence_number_(base::UnguessableToken::Create()),
       system_clipboard_(nullptr) {}
 
-DataObjectItem::DataObjectItem(ItemKind kind,
-                               const String& type,
-                               uint64_t sequence_number,
-                               SystemClipboard* system_clipboard)
+DataObjectItem::DataObjectItem(
+    ItemKind kind,
+    const String& type,
+    const ClipboardSequenceNumberToken& sequence_number,
+    SystemClipboard* system_clipboard)
     : source_(DataSource::kClipboardSource),
       kind_(kind),
       type_(type),
diff --git a/third_party/blink/renderer/core/clipboard/data_object_item.h b/third_party/blink/renderer/core/clipboard/data_object_item.h
index 9c54d95..08aa539f 100644
--- a/third_party/blink/renderer/core/clipboard/data_object_item.h
+++ b/third_party/blink/renderer/core/clipboard/data_object_item.h
@@ -68,14 +68,15 @@
       const KURL&,
       const String& file_extension,
       const AtomicString& content_disposition);
-  static DataObjectItem* CreateFromClipboard(SystemClipboard* system_clipboard,
-                                             const String& type,
-                                             uint64_t sequence_number);
+  static DataObjectItem* CreateFromClipboard(
+      SystemClipboard* system_clipboard,
+      const String& type,
+      const ClipboardSequenceNumberToken& sequence_number);
 
   DataObjectItem(ItemKind kind, const String& type);
   DataObjectItem(ItemKind,
                  const String& type,
-                 uint64_t sequence_number,
+                 const ClipboardSequenceNumberToken& sequence_number,
                  SystemClipboard* system_clipboard);
 
   ItemKind Kind() const { return kind_; }
@@ -119,9 +120,9 @@
   String title_;
   KURL base_url_;
 
-  uint64_t sequence_number_;  // Only valid when |source_| ==
-                              // DataSource::kClipboardSource.
-  String file_system_id_;     // Only valid when |file_| is backed by FileEntry.
+  ClipboardSequenceNumberToken  // Only valid when |source_| ==
+      sequence_number_;         // DataSource::kClipboardSource.
+  String file_system_id_;  // Only valid when |file_| is backed by FileEntry.
 
   // Access to the global system clipboard.
   Member<SystemClipboard> system_clipboard_;
diff --git a/third_party/blink/renderer/core/clipboard/system_clipboard.cc b/third_party/blink/renderer/core/clipboard/system_clipboard.cc
index fb8f46c..66b07e3 100644
--- a/third_party/blink/renderer/core/clipboard/system_clipboard.cc
+++ b/third_party/blink/renderer/core/clipboard/system_clipboard.cc
@@ -86,10 +86,10 @@
   return result;
 }
 
-uint64_t SystemClipboard::SequenceNumber() {
+ClipboardSequenceNumberToken SystemClipboard::SequenceNumber() {
   if (!IsValidBufferType(buffer_) || !clipboard_.is_bound())
-    return 0;
-  uint64_t result = 0;
+    return ClipboardSequenceNumberToken();
+  ClipboardSequenceNumberToken result;
   clipboard_->GetSequenceNumber(buffer_, &result);
   return result;
 }
diff --git a/third_party/blink/renderer/core/clipboard/system_clipboard.h b/third_party/blink/renderer/core/clipboard/system_clipboard.h
index afd2a90..38a0a8f 100644
--- a/third_party/blink/renderer/core/clipboard/system_clipboard.h
+++ b/third_party/blink/renderer/core/clipboard/system_clipboard.h
@@ -36,7 +36,7 @@
   SystemClipboard(const SystemClipboard&) = delete;
   SystemClipboard& operator=(const SystemClipboard&) = delete;
 
-  uint64_t SequenceNumber();
+  ClipboardSequenceNumberToken SequenceNumber();
   bool IsSelectionMode() const;
   void SetSelectionMode(bool);
   Vector<String> ReadAvailableTypes();
diff --git a/third_party/blink/renderer/core/testing/mock_clipboard_host.cc b/third_party/blink/renderer/core/testing/mock_clipboard_host.cc
index 61975376..e0ff1f0 100644
--- a/third_party/blink/renderer/core/testing/mock_clipboard_host.cc
+++ b/third_party/blink/renderer/core/testing/mock_clipboard_host.cc
@@ -7,6 +7,7 @@
 #include "base/containers/contains.h"
 #include "build/build_config.h"
 #include "mojo/public/cpp/base/big_buffer.h"
+#include "third_party/blink/public/common/tokens/tokens.h"
 #include "third_party/blink/renderer/platform/graphics/color_behavior.h"
 #include "third_party/blink/renderer/platform/image-encoders/image_encoder.h"
 #include "third_party/skia/include/core/SkBitmap.h"
@@ -179,7 +180,7 @@
 }
 
 void MockClipboardHost::CommitWrite() {
-  ++sequence_number_;
+  sequence_number_ = ClipboardSequenceNumberToken();
   needs_reset_ = true;
 }
 
diff --git a/third_party/blink/renderer/core/testing/mock_clipboard_host.h b/third_party/blink/renderer/core/testing/mock_clipboard_host.h
index 7249b7f..8c40b95e 100644
--- a/third_party/blink/renderer/core/testing/mock_clipboard_host.h
+++ b/third_party/blink/renderer/core/testing/mock_clipboard_host.h
@@ -8,6 +8,7 @@
 #include "build/build_config.h"
 #include "mojo/public/cpp/bindings/receiver_set.h"
 #include "third_party/blink/public/common/common_export.h"
+#include "third_party/blink/public/common/tokens/tokens.h"
 #include "third_party/blink/public/mojom/clipboard/clipboard.mojom-blink.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 
@@ -63,7 +64,7 @@
 #endif
 
   mojo::ReceiverSet<mojom::blink::ClipboardHost> receivers_;
-  uint64_t sequence_number_ = 0;
+  ClipboardSequenceNumberToken sequence_number_;
   String plain_text_ = g_empty_string;
   String html_text_ = g_empty_string;
   String svg_text_ = g_empty_string;
diff --git a/ui/base/clipboard/BUILD.gn b/ui/base/clipboard/BUILD.gn
index 42d2fb4..52d88ba 100644
--- a/ui/base/clipboard/BUILD.gn
+++ b/ui/base/clipboard/BUILD.gn
@@ -78,6 +78,7 @@
     "clipboard_monitor.h",
     "clipboard_observer.cc",
     "clipboard_observer.h",
+    "clipboard_sequence_number_token.h",
     "custom_data_helper.cc",
     "custom_data_helper.h",
     "scoped_clipboard_writer.cc",
diff --git a/ui/base/clipboard/clipboard.h b/ui/base/clipboard/clipboard.h
index 2ee52a5..8bb95a13 100644
--- a/ui/base/clipboard/clipboard.h
+++ b/ui/base/clipboard/clipboard.h
@@ -25,6 +25,7 @@
 #include "mojo/public/cpp/base/big_buffer.h"
 #include "ui/base/clipboard/clipboard_buffer.h"
 #include "ui/base/clipboard/clipboard_format_type.h"
+#include "ui/base/clipboard/clipboard_sequence_number_token.h"
 #include "ui/base/clipboard/file_info.h"
 #include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
 
@@ -117,14 +118,11 @@
   virtual const DataTransferEndpoint* GetSource(
       ClipboardBuffer buffer) const = 0;
 
-  // Returns a sequence number which uniquely identifies clipboard state.
-  // This can be used to version the data on the clipboard and determine
-  // whether it has changed.
-  // TODO(https://crbug.com/1226356): Note that the sequence number uniquely
-  // identifies the clipboard state within this particular ui::Clipboard
-  // instance. It is not guaranteed to be unique across multiple / subsequent
-  // ui::Clipborad instances. Consider changing that.
-  virtual uint64_t GetSequenceNumber(ClipboardBuffer buffer) const = 0;
+  // Returns a token which uniquely identifies clipboard state.
+  // ClipboardSequenceNumberTokens are used since there may be multiple
+  // ui::Clipboard instances that have the same sequence number.
+  virtual const ClipboardSequenceNumberToken& GetSequenceNumber(
+      ClipboardBuffer buffer) const = 0;
 
   // Tests whether the clipboard contains a certain format.
   virtual bool IsFormatAvailable(
diff --git a/ui/base/clipboard/clipboard_android.cc b/ui/base/clipboard/clipboard_android.cc
index db350f0..683ea33 100644
--- a/ui/base/clipboard/clipboard_android.cc
+++ b/ui/base/clipboard/clipboard_android.cc
@@ -133,7 +133,7 @@
   void GetImage(ReadImageCallback callback);
   void DidGetPng(ReadPngCallback callback, std::vector<uint8_t> result);
   void DidGetImage(ReadImageCallback callback, const SkBitmap& result);
-  uint64_t GetSequenceNumber() const;
+  const ClipboardSequenceNumberToken& GetSequenceNumber() const;
   base::Time GetLastModifiedTime() const;
   void ClearLastModifiedTime();
   bool HasFormat(const ClipboardFormatType& format);
@@ -170,7 +170,7 @@
   // This lock is for read/write |map_|.
   base::Lock lock_;
 
-  uint64_t sequence_number_;
+  ClipboardSequenceNumberToken sequence_number_;
   base::Time last_modified_time_;
 
   ClipboardAndroid::ModifiedCallback modified_cb_;
@@ -260,7 +260,7 @@
   std::move(callback).Run(std::move(bitmap));
 }
 
-uint64_t ClipboardMap::GetSequenceNumber() const {
+const ClipboardSequenceNumberToken& ClipboardMap::GetSequenceNumber() const {
   return sequence_number_;
 }
 
@@ -349,7 +349,7 @@
 }
 
 void ClipboardMap::OnPrimaryClipboardChanged() {
-  sequence_number_++;
+  sequence_number_ = ClipboardSequenceNumberToken();
   UpdateLastModifiedTime(base::Time::Now());
   map_state_ = MapState::kOutOfDate;
 }
@@ -357,7 +357,7 @@
 void ClipboardMap::OnPrimaryClipTimestampInvalidated(int64_t timestamp_ms) {
   base::Time timestamp = base::Time::FromJavaTime(timestamp_ms);
   if (GetLastModifiedTime() < timestamp) {
-    sequence_number_++;
+    sequence_number_ = ClipboardSequenceNumberToken();
     UpdateLastModifiedTime(timestamp);
     map_state_ = MapState::kOutOfDate;
   }
@@ -413,7 +413,7 @@
     NOTIMPLEMENTED();
   }
   map_state_ = MapState::kUpToDate;
-  sequence_number_++;
+  sequence_number_ = ClipboardSequenceNumberToken();
   UpdateLastModifiedTime(base::Time::Now());
 }
 
@@ -423,7 +423,7 @@
   map_.clear();
   Java_Clipboard_clear(env, clipboard_manager_);
   map_state_ = MapState::kUpToDate;
-  sequence_number_++;
+  sequence_number_ = ClipboardSequenceNumberToken();
   UpdateLastModifiedTime(base::Time::Now());
 }
 
@@ -523,7 +523,7 @@
   return nullptr;
 }
 
-uint64_t ClipboardAndroid::GetSequenceNumber(
+const ClipboardSequenceNumberToken& ClipboardAndroid::GetSequenceNumber(
     ClipboardBuffer /* buffer */) const {
   DCHECK(CalledOnValidThread());
   return g_map.Get().GetSequenceNumber();
diff --git a/ui/base/clipboard/clipboard_android.h b/ui/base/clipboard/clipboard_android.h
index d0187149..0ea561e 100644
--- a/ui/base/clipboard/clipboard_android.h
+++ b/ui/base/clipboard/clipboard_android.h
@@ -61,7 +61,8 @@
   // Clipboard overrides:
   void OnPreShutdown() override;
   DataTransferEndpoint* GetSource(ClipboardBuffer buffer) const override;
-  uint64_t GetSequenceNumber(ClipboardBuffer buffer) const override;
+  const ClipboardSequenceNumberToken& GetSequenceNumber(
+      ClipboardBuffer buffer) const override;
   bool IsFormatAvailable(const ClipboardFormatType& format,
                          ClipboardBuffer buffer,
                          const DataTransferEndpoint* data_dst) const override;
diff --git a/ui/base/clipboard/clipboard_mac.h b/ui/base/clipboard/clipboard_mac.h
index ddcf76a..642a7f8 100644
--- a/ui/base/clipboard/clipboard_mac.h
+++ b/ui/base/clipboard/clipboard_mac.h
@@ -10,6 +10,7 @@
 
 #include "base/component_export.h"
 #include "base/gtest_prod_util.h"
+#include "base/mac/foundation_util.h"
 #include "ui/base/clipboard/clipboard.h"
 
 @class NSPasteboard;
@@ -38,7 +39,8 @@
   // Clipboard overrides:
   void OnPreShutdown() override;
   DataTransferEndpoint* GetSource(ClipboardBuffer buffer) const override;
-  uint64_t GetSequenceNumber(ClipboardBuffer buffer) const override;
+  const ClipboardSequenceNumberToken& GetSequenceNumber(
+      ClipboardBuffer buffer) const override;
   bool IsFormatAvailable(const ClipboardFormatType& format,
                          ClipboardBuffer buffer,
                          const DataTransferEndpoint* data_dst) const override;
@@ -115,6 +117,12 @@
                                        NSPasteboard* pasteboard) const;
   SkBitmap ReadImageInternal(ClipboardBuffer buffer,
                              NSPasteboard* pasteboard) const;
+
+  // Mapping of OS-provided sequence number to a unique token.
+  mutable struct {
+    NSInteger sequence_number;
+    ClipboardSequenceNumberToken token;
+  } clipboard_sequence_;
 };
 
 }  // namespace ui
diff --git a/ui/base/clipboard/clipboard_mac.mm b/ui/base/clipboard/clipboard_mac.mm
index 141fbc1..19a32707 100644
--- a/ui/base/clipboard/clipboard_mac.mm
+++ b/ui/base/clipboard/clipboard_mac.mm
@@ -6,6 +6,7 @@
 
 #import <Cocoa/Cocoa.h>
 #include <stdint.h>
+#include "ui/base/clipboard/clipboard.h"
 
 #include <limits>
 
@@ -94,11 +95,17 @@
   return nullptr;
 }
 
-uint64_t ClipboardMac::GetSequenceNumber(ClipboardBuffer buffer) const {
+const ClipboardSequenceNumberToken& ClipboardMac::GetSequenceNumber(
+    ClipboardBuffer buffer) const {
   DCHECK(CalledOnValidThread());
   DCHECK_EQ(buffer, ClipboardBuffer::kCopyPaste);
 
-  return [GetPasteboard() changeCount];
+  NSInteger sequence_number = [GetPasteboard() changeCount];
+  if (sequence_number != clipboard_sequence_.sequence_number) {
+    // Generate a unique token associated with the current sequence number.
+    clipboard_sequence_ = {sequence_number, ClipboardSequenceNumberToken()};
+  }
+  return clipboard_sequence_.token;
 }
 
 // |data_dst| is not used. It's only passed to be consistent with other
diff --git a/ui/base/clipboard/clipboard_non_backed.cc b/ui/base/clipboard/clipboard_non_backed.cc
index 6287549..dee5b3d 100644
--- a/ui/base/clipboard/clipboard_non_backed.cc
+++ b/ui/base/clipboard/clipboard_non_backed.cc
@@ -91,12 +91,14 @@
   ~ClipboardInternal() = default;
 
   void Clear() {
-    ++sequence_number_;
+    sequence_number_ = ClipboardSequenceNumberToken();
     data_.reset();
     ClipboardMonitor::GetInstance()->NotifyClipboardDataChanged();
   }
 
-  uint64_t sequence_number() const { return sequence_number_; }
+  const ClipboardSequenceNumberToken& sequence_number() const {
+    return sequence_number_;
+  }
 
   // Returns the current clipboard data, which may be nullptr if nothing has
   // been written since the last Clear().
@@ -250,7 +252,7 @@
     DCHECK(data);
     std::unique_ptr<ClipboardData> previous_data = std::move(data_);
     data_ = std::move(data);
-    ++sequence_number_;
+    sequence_number_ = ClipboardSequenceNumberToken();
     ClipboardMonitor::GetInstance()->NotifyClipboardDataChanged();
     return previous_data;
   }
@@ -276,7 +278,7 @@
   std::unique_ptr<ClipboardData> data_;
 
   // Sequence number uniquely identifying clipboard state.
-  uint64_t sequence_number_ = 0;
+  ClipboardSequenceNumberToken sequence_number_;
 };
 
 // Helper class to build a ClipboardData object and write it to clipboard.
@@ -413,7 +415,8 @@
   return data ? data->source() : nullptr;
 }
 
-uint64_t ClipboardNonBacked::GetSequenceNumber(ClipboardBuffer buffer) const {
+const ClipboardSequenceNumberToken& ClipboardNonBacked::GetSequenceNumber(
+    ClipboardBuffer buffer) const {
   DCHECK(CalledOnValidThread());
   return clipboard_internal_->sequence_number();
 }
diff --git a/ui/base/clipboard/clipboard_non_backed.h b/ui/base/clipboard/clipboard_non_backed.h
index 0c23cc3..7b67ca0 100644
--- a/ui/base/clipboard/clipboard_non_backed.h
+++ b/ui/base/clipboard/clipboard_non_backed.h
@@ -44,7 +44,8 @@
 
   // Clipboard overrides:
   DataTransferEndpoint* GetSource(ClipboardBuffer buffer) const override;
-  uint64_t GetSequenceNumber(ClipboardBuffer buffer) const override;
+  const ClipboardSequenceNumberToken& GetSequenceNumber(
+      ClipboardBuffer buffer) const override;
 
  private:
   friend class Clipboard;
diff --git a/ui/base/clipboard/clipboard_ozone.cc b/ui/base/clipboard/clipboard_ozone.cc
index f97d5bd..ca230093 100644
--- a/ui/base/clipboard/clipboard_ozone.cc
+++ b/ui/base/clipboard/clipboard_ozone.cc
@@ -164,7 +164,8 @@
     }
   }
 
-  uint64_t GetSequenceNumber(ClipboardBuffer buffer) {
+  const ClipboardSequenceNumberToken& GetSequenceNumber(
+      ClipboardBuffer buffer) const {
     return buffer == ClipboardBuffer::kCopyPaste ? clipboard_sequence_number_
                                                  : selection_sequence_number_;
   }
@@ -275,9 +276,9 @@
     DCHECK(buffer == ClipboardBuffer::kCopyPaste ||
            platform_clipboard_->IsSelectionBufferAvailable());
     if (buffer == ClipboardBuffer::kCopyPaste)
-      clipboard_sequence_number_++;
+      clipboard_sequence_number_ = ClipboardSequenceNumberToken();
     else
-      selection_sequence_number_++;
+      selection_sequence_number_ = ClipboardSequenceNumberToken();
     ClipboardMonitor::GetInstance()->NotifyClipboardDataChanged();
   }
 
@@ -296,8 +297,8 @@
   // Provides communication to a system clipboard under ozone level.
   PlatformClipboard* const platform_clipboard_ = nullptr;
 
-  uint64_t clipboard_sequence_number_ = 0;
-  uint64_t selection_sequence_number_ = 0;
+  ClipboardSequenceNumberToken clipboard_sequence_number_;
+  ClipboardSequenceNumberToken selection_sequence_number_;
 
   base::WeakPtrFactory<AsyncClipboardOzone> weak_factory_;
 };
@@ -327,7 +328,8 @@
   return it == data_src_.end() ? nullptr : it->second.get();
 }
 
-uint64_t ClipboardOzone::GetSequenceNumber(ClipboardBuffer buffer) const {
+const ClipboardSequenceNumberToken& ClipboardOzone::GetSequenceNumber(
+    ClipboardBuffer buffer) const {
   return async_clipboard_ozone_->GetSequenceNumber(buffer);
 }
 
diff --git a/ui/base/clipboard/clipboard_ozone.h b/ui/base/clipboard/clipboard_ozone.h
index 18bd232f..a4b1f2a2 100644
--- a/ui/base/clipboard/clipboard_ozone.h
+++ b/ui/base/clipboard/clipboard_ozone.h
@@ -29,7 +29,8 @@
   // Clipboard overrides:
   void OnPreShutdown() override;
   DataTransferEndpoint* GetSource(ClipboardBuffer buffer) const override;
-  uint64_t GetSequenceNumber(ClipboardBuffer buffer) const override;
+  const ClipboardSequenceNumberToken& GetSequenceNumber(
+      ClipboardBuffer buffer) const override;
   bool IsFormatAvailable(const ClipboardFormatType& format,
                          ClipboardBuffer buffer,
                          const DataTransferEndpoint* data_dst) const override;
diff --git a/ui/base/clipboard/clipboard_sequence_number_token.h b/ui/base/clipboard/clipboard_sequence_number_token.h
new file mode 100644
index 0000000..b76e163
--- /dev/null
+++ b/ui/base/clipboard/clipboard_sequence_number_token.h
@@ -0,0 +1,19 @@
+// Copyright (c) 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_BASE_CLIPBOARD_CLIPBOARD_SEQUENCE_NUMBER_TOKEN_H_
+#define UI_BASE_CLIPBOARD_CLIPBOARD_SEQUENCE_NUMBER_TOKEN_H_
+
+#include "base/types/token_type.h"
+
+namespace ui {
+
+// Identifies a unique clipboard state. This can be used to version the data on
+// the clipboard and determine whether it has changed.
+using ClipboardSequenceNumberToken =
+    base::TokenType<class ClipboardSequenceNumberTokenTypeMarker>;
+
+}  // namespace ui
+
+#endif  // UI_BASE_CLIPBOARD_CLIPBOARD_SEQUENCE_NUMBER_TOKEN_H_
diff --git a/ui/base/clipboard/clipboard_test_template.h b/ui/base/clipboard/clipboard_test_template.h
index abc3364..c938552 100644
--- a/ui/base/clipboard/clipboard_test_template.h
+++ b/ui/base/clipboard/clipboard_test_template.h
@@ -1201,7 +1201,7 @@
 // written to.
 // TODO(dcheng): Add a version to test ClipboardBuffer::kSelection.
 TYPED_TEST(ClipboardTest, GetSequenceNumber) {
-  const uint64_t first_sequence_number =
+  const ClipboardSequenceNumberToken first_sequence_number =
       this->clipboard().GetSequenceNumber(ClipboardBuffer::kCopyPaste);
 
   {
@@ -1213,7 +1213,7 @@
   // the message loop to make sure we get the notification.
   base::RunLoop().RunUntilIdle();
 
-  const uint64_t second_sequence_number =
+  const ClipboardSequenceNumberToken second_sequence_number =
       this->clipboard().GetSequenceNumber(ClipboardBuffer::kCopyPaste);
 
   EXPECT_NE(first_sequence_number, second_sequence_number);
diff --git a/ui/base/clipboard/clipboard_win.cc b/ui/base/clipboard/clipboard_win.cc
index a9fd6d6..3e24b5c 100644
--- a/ui/base/clipboard/clipboard_win.cc
+++ b/ui/base/clipboard/clipboard_win.cc
@@ -256,9 +256,16 @@
   return nullptr;
 }
 
-uint64_t ClipboardWin::GetSequenceNumber(ClipboardBuffer buffer) const {
+const ClipboardSequenceNumberToken& ClipboardWin::GetSequenceNumber(
+    ClipboardBuffer buffer) const {
   DCHECK_EQ(buffer, ClipboardBuffer::kCopyPaste);
-  return ::GetClipboardSequenceNumber();
+
+  DWORD sequence_number = ::GetClipboardSequenceNumber();
+  if (sequence_number != clipboard_sequence_.sequence_number) {
+    // Generate a unique token associated with the current sequence number.
+    clipboard_sequence_ = {sequence_number, ClipboardSequenceNumberToken()};
+  }
+  return clipboard_sequence_.token;
 }
 
 // |data_dst| is not used. It's only passed to be consistent with other
diff --git a/ui/base/clipboard/clipboard_win.h b/ui/base/clipboard/clipboard_win.h
index d8c8296..c07a811 100644
--- a/ui/base/clipboard/clipboard_win.h
+++ b/ui/base/clipboard/clipboard_win.h
@@ -35,7 +35,8 @@
   // Clipboard overrides:
   void OnPreShutdown() override;
   DataTransferEndpoint* GetSource(ClipboardBuffer buffer) const override;
-  uint64_t GetSequenceNumber(ClipboardBuffer buffer) const override;
+  const ClipboardSequenceNumberToken& GetSequenceNumber(
+      ClipboardBuffer buffer) const override;
   bool IsFormatAvailable(const ClipboardFormatType& format,
                          ClipboardBuffer buffer,
                          const DataTransferEndpoint* data_dst) const override;
@@ -118,6 +119,12 @@
 
   // Mark this as mutable so const methods can still do lazy initialization.
   mutable std::unique_ptr<base::win::MessageWindow> clipboard_owner_;
+
+  // Mapping of OS-provided sequence number to a unique token.
+  mutable struct {
+    DWORD sequence_number;
+    ClipboardSequenceNumberToken token;
+  } clipboard_sequence_;
 };
 
 }  // namespace ui
diff --git a/ui/base/clipboard/clipboard_x11.cc b/ui/base/clipboard/clipboard_x11.cc
index cfe608e1..1966c12 100644
--- a/ui/base/clipboard/clipboard_x11.cc
+++ b/ui/base/clipboard/clipboard_x11.cc
@@ -51,7 +51,8 @@
   return it == data_src_.end() ? nullptr : it->second.get();
 }
 
-uint64_t ClipboardX11::GetSequenceNumber(ClipboardBuffer buffer) const {
+const ClipboardSequenceNumberToken& ClipboardX11::GetSequenceNumber(
+    ClipboardBuffer buffer) const {
   DCHECK(CalledOnValidThread());
   return buffer == ClipboardBuffer::kCopyPaste ? clipboard_sequence_number_
                                                : primary_sequence_number_;
@@ -449,9 +450,9 @@
 
 void ClipboardX11::OnSelectionChanged(ClipboardBuffer buffer) {
   if (buffer == ClipboardBuffer::kCopyPaste)
-    clipboard_sequence_number_++;
+    clipboard_sequence_number_ = ClipboardSequenceNumberToken();
   else
-    primary_sequence_number_++;
+    primary_sequence_number_ = ClipboardSequenceNumberToken();
   ClipboardMonitor::GetInstance()->NotifyClipboardDataChanged();
 }
 
diff --git a/ui/base/clipboard/clipboard_x11.h b/ui/base/clipboard/clipboard_x11.h
index e72298a..be7eb96 100644
--- a/ui/base/clipboard/clipboard_x11.h
+++ b/ui/base/clipboard/clipboard_x11.h
@@ -29,7 +29,8 @@
   // Clipboard overrides:
   void OnPreShutdown() override;
   DataTransferEndpoint* GetSource(ClipboardBuffer buffer) const override;
-  uint64_t GetSequenceNumber(ClipboardBuffer buffer) const override;
+  const ClipboardSequenceNumberToken& GetSequenceNumber(
+      ClipboardBuffer buffer) const override;
   bool IsFormatAvailable(const ClipboardFormatType& format,
                          ClipboardBuffer buffer,
                          const DataTransferEndpoint* data_dst) const override;
@@ -110,8 +111,8 @@
 
   std::unique_ptr<XClipboardHelper> x_clipboard_helper_;
 
-  uint64_t clipboard_sequence_number_ = 0;
-  uint64_t primary_sequence_number_ = 0;
+  ClipboardSequenceNumberToken clipboard_sequence_number_;
+  ClipboardSequenceNumberToken primary_sequence_number_;
 
   base::flat_map<ClipboardBuffer, std::unique_ptr<DataTransferEndpoint>>
       data_src_;
diff --git a/ui/base/clipboard/test/test_clipboard.cc b/ui/base/clipboard/test/test_clipboard.cc
index ebdd29c..fe01e65 100644
--- a/ui/base/clipboard/test/test_clipboard.cc
+++ b/ui/base/clipboard/test/test_clipboard.cc
@@ -18,6 +18,7 @@
 #include "build/chromeos_buildflags.h"
 #include "skia/ext/skia_utils_base.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
+#include "ui/base/clipboard/clipboard.h"
 #include "ui/base/clipboard/clipboard_constants.h"
 #include "ui/base/clipboard/clipboard_monitor.h"
 #include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
@@ -60,7 +61,8 @@
   return GetStore(buffer).GetDataSource();
 }
 
-uint64_t TestClipboard::GetSequenceNumber(ClipboardBuffer buffer) const {
+const ClipboardSequenceNumberToken& TestClipboard::GetSequenceNumber(
+    ClipboardBuffer buffer) const {
   return GetStore(buffer).sequence_number;
 }
 
@@ -469,7 +471,7 @@
 TestClipboard::DataStore& TestClipboard::GetStore(ClipboardBuffer buffer) {
   CHECK(IsSupportedClipboardBuffer(buffer));
   DataStore& store = stores_[buffer];
-  ++store.sequence_number;
+  store.sequence_number = ClipboardSequenceNumberToken();
   return store;
 }
 
diff --git a/ui/base/clipboard/test/test_clipboard.h b/ui/base/clipboard/test/test_clipboard.h
index 4a00b24..5c58382 100644
--- a/ui/base/clipboard/test/test_clipboard.h
+++ b/ui/base/clipboard/test/test_clipboard.h
@@ -38,7 +38,8 @@
   // Clipboard overrides.
   void OnPreShutdown() override;
   DataTransferEndpoint* GetSource(ClipboardBuffer buffer) const override;
-  uint64_t GetSequenceNumber(ClipboardBuffer buffer) const override;
+  const ClipboardSequenceNumberToken& GetSequenceNumber(
+      ClipboardBuffer buffer) const override;
   bool IsFormatAvailable(const ClipboardFormatType& format,
                          ClipboardBuffer buffer,
                          const DataTransferEndpoint* data_dst) const override;
@@ -123,7 +124,7 @@
     void Clear();
     void SetDataSource(std::unique_ptr<DataTransferEndpoint> data_src);
     DataTransferEndpoint* GetDataSource() const;
-    uint64_t sequence_number = 0;
+    ClipboardSequenceNumberToken sequence_number;
     base::flat_map<ClipboardFormatType, std::string> data;
     std::string url_title;
     std::string html_src_url;
@@ -132,7 +133,7 @@
     std::unique_ptr<DataTransferEndpoint> data_src;
   };
 
-  // The non-const versions increment the sequence number as a side effect.
+  // The non-const versions update the sequence number as a side effect.
   const DataStore& GetStore(ClipboardBuffer buffer) const;
   const DataStore& GetDefaultStore() const;
   DataStore& GetStore(ClipboardBuffer buffer);