Add IPC layer + Platform implementation for Windows

The final CL that adds the Windows-specific IPC bits.
This implements the IPC transport as a AF_UNIX socket
and a named shared memory region. AF_UNIX doesn't
bring any major benefits really and I wonder whether
we should just use a TCP socket. In fact, AF_UNIX on
Windows misses the interesting bits of UNIX sockets:
(1) FD-passing is not supported; (2) Peer credentials
are not supported. Given that the shared memory is
based on an unguessable string, we could send that
over TCP as well.


Bug: 174454879
Test: manual on Windows, the following works:
  perfetto_unittests.exe
  perfetto_integrationtests.exe
  traced.exe + perfetto.exe
  stress_test.exe (there is something odd scheduling-wise here but
                   seems unrelated with the IPC port)
Change-Id: I77cb42940d8bd2ffbee2454ec8d6982781a3096b
diff --git a/Android.bp b/Android.bp
index 2bdae45..c0add08 100644
--- a/Android.bp
+++ b/Android.bp
@@ -8384,6 +8384,7 @@
     "src/tracing/ipc/default_socket.cc",
     "src/tracing/ipc/memfd.cc",
     "src/tracing/ipc/posix_shared_memory.cc",
+    "src/tracing/ipc/shared_memory_windows.cc",
   ],
 }
 
@@ -8426,6 +8427,7 @@
   name: "perfetto_src_tracing_platform_impl",
   srcs: [
     "src/tracing/platform_posix.cc",
+    "src/tracing/platform_windows.cc",
   ],
 }
 
diff --git a/BUILD b/BUILD
index 35e71df..7c861f3 100644
--- a/BUILD
+++ b/BUILD
@@ -1582,6 +1582,8 @@
         "src/tracing/ipc/memfd.h",
         "src/tracing/ipc/posix_shared_memory.cc",
         "src/tracing/ipc/posix_shared_memory.h",
+        "src/tracing/ipc/shared_memory_windows.cc",
+        "src/tracing/ipc/shared_memory_windows.h",
     ],
 )
 
@@ -1634,6 +1636,7 @@
     name = "src_tracing_platform_impl",
     srcs = [
         "src/tracing/platform_posix.cc",
+        "src/tracing/platform_windows.cc",
     ],
 )
 
diff --git a/gn/perfetto.gni b/gn/perfetto.gni
index 13831a0..a1c5ff0 100644
--- a/gn/perfetto.gni
+++ b/gn/perfetto.gni
@@ -144,9 +144,12 @@
   # system backend in the client library.
   # This includes building things that rely on POSIX sockets, this places
   # limitations on the supported operating systems.
-  enable_perfetto_ipc = !is_win && !is_fuchsia && !is_nacl &&
-                        (perfetto_build_standalone ||
-                         perfetto_build_with_android || build_with_chromium)
+  # For now the IPC layer is conservatively not enabled on Chromium+Windows
+  # builds.
+  enable_perfetto_ipc =
+      !is_fuchsia && !is_nacl &&
+      (perfetto_build_standalone || perfetto_build_with_android ||
+       (build_with_chromium && !is_win))
 
   # Makes the heap profiling daemon target reachable. It works only on Android,
   # but is built on Linux as well for test/compiler coverage.
@@ -186,7 +189,7 @@
                               build_with_chromium || perfetto_build_with_android
 
   enable_perfetto_integration_tests =
-      (perfetto_build_standalone && !is_win) || perfetto_build_with_android
+      perfetto_build_standalone || perfetto_build_with_android
 
   enable_perfetto_benchmarks = perfetto_build_standalone && !is_win
 
@@ -310,9 +313,6 @@
 # |is_perfetto_build_generator| must be true.
 assert(!perfetto_build_with_android || is_perfetto_build_generator)
 
-# The IPC layer based on UNIX sockets can't be built on Win.
-assert(!enable_perfetto_ipc || !is_win)
-
 # We should never end up in a state where is_perfetto_embedder=true but
 # perfetto_build_with_embedder=false.
 assert(!is_perfetto_embedder || perfetto_build_with_embedder)
diff --git a/gn/proto_library.gni b/gn/proto_library.gni
index 03d6455..5b87753 100644
--- a/gn/proto_library.gni
+++ b/gn/proto_library.gni
@@ -173,6 +173,17 @@
     } else {
       deps += [ "$perfetto_root_path/src/ipc:common" ]
     }
+    if (is_win) {
+      # TODO(primiano): investigate this. In Windows standalone builds, some
+      # executable targets end up in a state where no code pulls a dep on the
+      # ipc:client (in turn that seems a subtle consequence of not having
+      # traced_probes on Windows). This dep here is effectively needed because
+      # the client-side code in the generated .ipc.cc effectively depends on the
+      # client-side IPC library. Perhaps we just should do this unconditionally
+      # on all platforms?
+      deps += [ "$perfetto_root_path/src/ipc:client" ]
+    }
+
     if (defined(invoker.deps)) {
       deps += invoker.deps
     }
diff --git a/gn/standalone/BUILD.gn b/gn/standalone/BUILD.gn
index af70070..31941ed 100644
--- a/gn/standalone/BUILD.gn
+++ b/gn/standalone/BUILD.gn
@@ -161,6 +161,8 @@
     cflags += [
       "/bigobj",  # Some of our files are bigger than the regular limits.
       "/Gy",  # Enable function-level linking.
+      "/FS",  # Preserve previous PDB behavior.
+      "/utf-8",  # Assume UTF-8 by default to avoid code page dependencies.
     ]
     defines += [
       "_CRT_NONSTDC_NO_WARNINGS",
diff --git a/protos/perfetto/ipc/producer_port.proto b/protos/perfetto/ipc/producer_port.proto
index 1b193eb..ac1b015 100644
--- a/protos/perfetto/ipc/producer_port.proto
+++ b/protos/perfetto/ipc/producer_port.proto
@@ -152,6 +152,11 @@
   // SetupTracing response. See TracingService::ConnectProducer() and
   // |using_shmem_provided_by_producer| in InitializeConnectionResponse.
   optional bool producer_provided_shmem = 6;
+
+  // On Windows, when producer_provided_shmem = true, the client creates a named
+  // SHM region and passes the name (an unguessable token) back to the service.
+  // Introduced in v13.
+  optional string shm_key_windows = 7;
 }
 
 message InitializeConnectionResponse {
@@ -262,9 +267,16 @@
 
   message StopDataSource { optional uint64 instance_id = 1; }
 
-  // This message also transports the file descriptor for the shared memory
-  // buffer (not a proto field).
-  message SetupTracing { optional uint32 shared_buffer_page_size_kb = 1; }
+  // On Android/Linux/Mac this message also transports the file descriptor for
+  // the shared memory buffer (not a proto field).
+  message SetupTracing {
+    optional uint32 shared_buffer_page_size_kb = 1;
+
+    // On Windows, instead, we pass the name (an unguessable token) of a shared
+    // memory region that can be attached by the other process by name.
+    // Introduced in v13.
+    optional string shm_key_windows = 2;
+  }
 
   message Flush {
     // The instance id (i.e. StartDataSource.new_instance_id) of the data
diff --git a/src/tracing/BUILD.gn b/src/tracing/BUILD.gn
index 43ce774..fcfddbf 100644
--- a/src/tracing/BUILD.gn
+++ b/src/tracing/BUILD.gn
@@ -50,14 +50,17 @@
   }
 }
 
-# Separate target because the embedder might not want this (e.g. on Windows).
+# Separate target because the embedder might not want this.
 source_set("platform_impl") {
   deps = [
     "../../gn:default_deps",
     "../../include/perfetto/tracing",
     "../base",
   ]
-  sources = [ "platform_posix.cc" ]
+  sources = [
+    "platform_posix.cc",
+    "platform_windows.cc",
+  ]
 }
 
 # Fake platform that allows buiding the client lib on all OSes. You can only use
diff --git a/src/tracing/ipc/BUILD.gn b/src/tracing/ipc/BUILD.gn
index 93c97a6..f86aeb5 100644
--- a/src/tracing/ipc/BUILD.gn
+++ b/src/tracing/ipc/BUILD.gn
@@ -32,6 +32,8 @@
     "memfd.h",
     "posix_shared_memory.cc",
     "posix_shared_memory.h",
+    "shared_memory_windows.cc",
+    "shared_memory_windows.h",
   ]
   deps = [
     "../../../gn:default_deps",
diff --git a/src/tracing/ipc/default_socket.cc b/src/tracing/ipc/default_socket.cc
index 3ad5cee..7349f92 100644
--- a/src/tracing/ipc/default_socket.cc
+++ b/src/tracing/ipc/default_socket.cc
@@ -23,7 +23,12 @@
 #include "perfetto/ext/tracing/core/basic_types.h"
 
 #include <stdlib.h>
+
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) ||   \
+    PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
+    PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
 #include <unistd.h>
+#endif
 
 namespace perfetto {
 #if !PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
diff --git a/src/tracing/ipc/producer/producer_ipc_client_impl.cc b/src/tracing/ipc/producer/producer_ipc_client_impl.cc
index 64b1023..694a3a9 100644
--- a/src/tracing/ipc/producer/producer_ipc_client_impl.cc
+++ b/src/tracing/ipc/producer/producer_ipc_client_impl.cc
@@ -29,7 +29,12 @@
 #include "perfetto/tracing/core/data_source_config.h"
 #include "perfetto/tracing/core/data_source_descriptor.h"
 #include "perfetto/tracing/core/trace_config.h"
+
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+#include "src/tracing/ipc/shared_memory_windows.h"
+#else
 #include "src/tracing/ipc/posix_shared_memory.h"
+#endif
 
 // TODO(fmayer): think to what happens when ProducerIPCClientImpl gets destroyed
 // w.r.t. the Producer pointer. Also think to lifetime of the Producer* during
@@ -158,8 +163,13 @@
 
   int shm_fd = -1;
   if (shared_memory_) {
-    shm_fd = static_cast<PosixSharedMemory*>(shared_memory_.get())->fd();
     req.set_producer_provided_shmem(true);
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+    auto key = static_cast<SharedMemoryWindows*>(shared_memory_.get())->key();
+    req.set_shm_key_windows(key);
+#else
+    shm_fd = static_cast<PosixSharedMemory*>(shared_memory_.get())->fd();
+#endif
   }
 
 #if PERFETTO_DCHECK_IS_ON()
@@ -253,15 +263,25 @@
   }
 
   if (cmd.has_setup_tracing()) {
+    std::unique_ptr<SharedMemory> ipc_shared_memory;
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+    const std::string& shm_key = cmd.setup_tracing().shm_key_windows();
+    if (!shm_key.empty())
+      ipc_shared_memory = SharedMemoryWindows::Attach(shm_key);
+#else
     base::ScopedFile shmem_fd = ipc_channel_->TakeReceivedFD();
     if (shmem_fd) {
+      // TODO(primiano): handle mmap failure in case of OOM.
+      ipc_shared_memory =
+          PosixSharedMemory::AttachToFd(std::move(shmem_fd),
+                                        /*require_seals_if_supported=*/false);
+    }
+#endif
+    if (ipc_shared_memory) {
       // This is the nominal case used in most configurations, where the service
       // provides the SMB.
       PERFETTO_CHECK(!is_shmem_provided_by_producer_ && !shared_memory_);
-      // TODO(primiano): handle mmap failure in case of OOM.
-      shared_memory_ =
-          PosixSharedMemory::AttachToFd(std::move(shmem_fd),
-                                        /*require_seals_if_supported=*/false);
+      shared_memory_ = std::move(ipc_shared_memory);
       shared_buffer_page_size_kb_ =
           cmd.setup_tracing().shared_buffer_page_size_kb();
       shared_memory_arbiter_ = SharedMemoryArbiter::CreateInstance(
diff --git a/src/tracing/ipc/service/producer_ipc_service.cc b/src/tracing/ipc/service/producer_ipc_service.cc
index cfa79b1..dc74374 100644
--- a/src/tracing/ipc/service/producer_ipc_service.cc
+++ b/src/tracing/ipc/service/producer_ipc_service.cc
@@ -26,7 +26,12 @@
 #include "perfetto/ext/tracing/core/tracing_service.h"
 #include "perfetto/tracing/core/data_source_config.h"
 #include "perfetto/tracing/core/data_source_descriptor.h"
+
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+#include "src/tracing/ipc/shared_memory_windows.h"
+#else
 #include "src/tracing/ipc/posix_shared_memory.h"
+#endif
 
 // The remote Producer(s) are not trusted. All the methods from the ProducerPort
 // IPC layer (e.g. RegisterDataSource()) must assume that the remote Producer is
@@ -93,7 +98,18 @@
   // If the producer provided an SMB, tell the service to attempt to adopt it.
   std::unique_ptr<SharedMemory> shmem;
   if (req.producer_provided_shmem()) {
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+    if (!req.has_shm_key_windows() || req.shm_key_windows().empty()) {
+      PERFETTO_ELOG(
+          "shm_key_windows must be non-empty when "
+          "producer_provided_shmem = true");
+    } else {
+      shmem = SharedMemoryWindows::Attach(req.shm_key_windows());
+      // Attach() does error logging if something fails, no need to extra ELOGs.
+    }
+#else
     base::ScopedFile shmem_fd = ipc::Service::TakeReceivedFD();
+
     if (shmem_fd) {
       shmem = PosixSharedMemory::AttachToFd(
           std::move(shmem_fd), /*require_seals_if_supported=*/true);
@@ -107,6 +123,7 @@
           "InitializeConnectionRequest's producer_provided_shmem flag is set "
           "but the producer didn't provide an FD");
     }
+#endif
   }
 
   // ConnectProducer will call OnConnect() on the next task.
@@ -455,10 +472,17 @@
     // Nominal case (% Chrome): service provides SMB.
     setup_tracing->set_shared_buffer_page_size_kb(
         static_cast<uint32_t>(service_endpoint->shared_buffer_page_size_kb()));
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+    const std::string& shm_key =
+        static_cast<SharedMemoryWindows*>(service_endpoint->shared_memory())
+            ->key();
+    setup_tracing->set_shm_key_windows(shm_key);
+#else
     const int shm_fd =
         static_cast<PosixSharedMemory*>(service_endpoint->shared_memory())
             ->fd();
     cmd.set_fd(shm_fd);
+#endif
   }
   async_producer_commands.Resolve(std::move(cmd));
 }
diff --git a/src/tracing/ipc/service/service_ipc_host_impl.cc b/src/tracing/ipc/service/service_ipc_host_impl.cc
index d19fef6..5618b3c 100644
--- a/src/tracing/ipc/service/service_ipc_host_impl.cc
+++ b/src/tracing/ipc/service/service_ipc_host_impl.cc
@@ -20,10 +20,15 @@
 #include "perfetto/base/task_runner.h"
 #include "perfetto/ext/ipc/host.h"
 #include "perfetto/ext/tracing/core/tracing_service.h"
-#include "src/tracing/ipc/posix_shared_memory.h"
 #include "src/tracing/ipc/service/consumer_ipc_service.h"
 #include "src/tracing/ipc/service/producer_ipc_service.h"
 
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+#include "src/tracing/ipc/shared_memory_windows.h"
+#else
+#include "src/tracing/ipc/posix_shared_memory.h"
+#endif
+
 namespace perfetto {
 
 // TODO(fmayer): implement per-uid connection limit (b/69093705).
@@ -66,8 +71,13 @@
 
 bool ServiceIPCHostImpl::DoStart() {
   // Create and initialize the platform-independent tracing business logic.
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+  std::unique_ptr<SharedMemory::Factory> shm_factory(
+      new SharedMemoryWindows::Factory());
+#else
   std::unique_ptr<SharedMemory::Factory> shm_factory(
       new PosixSharedMemory::Factory());
+#endif
   svc_ = TracingService::CreateInstance(std::move(shm_factory), task_runner_);
 
   if (!producer_ipc_port_ || !consumer_ipc_port_) {
diff --git a/src/tracing/ipc/shared_memory_windows.cc b/src/tracing/ipc/shared_memory_windows.cc
new file mode 100644
index 0000000..579d810
--- /dev/null
+++ b/src/tracing/ipc/shared_memory_windows.cc
@@ -0,0 +1,113 @@
+/*
+ * 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.
+ */
+
+#include "src/tracing/ipc/shared_memory_windows.h"
+
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+
+#include <memory>
+#include <random>
+
+#include <Windows.h>
+
+#include "perfetto/base/logging.h"
+#include "perfetto/ext/base/string_utils.h"
+
+namespace perfetto {
+
+// static
+std::unique_ptr<SharedMemoryWindows> SharedMemoryWindows::Create(size_t size) {
+  base::ScopedPlatformHandle shmem_handle;
+  std::random_device rnd_dev;
+  uint64_t rnd_key = (static_cast<uint64_t>(rnd_dev()) << 32) | rnd_dev();
+  std::string key = "perfetto_shm_" + base::Uint64ToHexStringNoPrefix(rnd_key);
+  shmem_handle.reset(CreateFileMappingA(
+      INVALID_HANDLE_VALUE,  // Use paging file.
+      nullptr,               // Default security.
+      PAGE_READWRITE,
+      static_cast<DWORD>(size >> 32),  // maximum object size (high-order DWORD)
+      static_cast<DWORD>(size),        // maximum object size (low-order DWORD)
+      key.c_str()));
+
+  if (!shmem_handle) {
+    PERFETTO_PLOG("CreateFileMapping() call failed");
+    return nullptr;
+  }
+  void* start =
+      MapViewOfFile(*shmem_handle, FILE_MAP_ALL_ACCESS, /*offsetHigh=*/0,
+                    /*offsetLow=*/0, size);
+  if (!start) {
+    PERFETTO_PLOG("MapViewOfFile() failed");
+    return nullptr;
+  }
+
+  return std::unique_ptr<SharedMemoryWindows>(new SharedMemoryWindows(
+      start, size, std::move(key), std::move(shmem_handle)));
+}
+
+// static
+std::unique_ptr<SharedMemoryWindows> SharedMemoryWindows::Attach(
+    const std::string& key) {
+  base::ScopedPlatformHandle shmem_handle;
+  shmem_handle.reset(
+      OpenFileMappingA(FILE_MAP_ALL_ACCESS, /*inherit=*/false, key.c_str()));
+  if (!shmem_handle) {
+    PERFETTO_PLOG("Failed to OpenFileMapping()");
+    return nullptr;
+  }
+
+  void* start =
+      MapViewOfFile(*shmem_handle, FILE_MAP_ALL_ACCESS, /*offsetHigh=*/0,
+                    /*offsetLow=*/0, /*dwNumberOfBytesToMap=*/0);
+  if (!start) {
+    PERFETTO_PLOG("MapViewOfFile() failed");
+    return nullptr;
+  }
+
+  MEMORY_BASIC_INFORMATION info{};
+  if (!VirtualQuery(start, &info, sizeof(info))) {
+    PERFETTO_PLOG("VirtualQuery() failed");
+    return nullptr;
+  }
+  size_t size = info.RegionSize;
+  return std::unique_ptr<SharedMemoryWindows>(
+      new SharedMemoryWindows(start, size, key, std::move(shmem_handle)));
+}
+
+SharedMemoryWindows::SharedMemoryWindows(void* start,
+                                         size_t size,
+                                         std::string key,
+                                         base::ScopedPlatformHandle handle)
+    : start_(start),
+      size_(size),
+      key_(std::move(key)),
+      handle_(std::move(handle)) {}
+
+SharedMemoryWindows::~SharedMemoryWindows() {
+  if (start_)
+    UnmapViewOfFile(start_);
+}
+
+SharedMemoryWindows::Factory::~Factory() = default;
+
+std::unique_ptr<SharedMemory> SharedMemoryWindows::Factory::CreateSharedMemory(
+    size_t size) {
+  return SharedMemoryWindows::Create(size);
+}
+
+}  // namespace perfetto
+
+#endif  // !OS_WIN
diff --git a/src/tracing/ipc/shared_memory_windows.h b/src/tracing/ipc/shared_memory_windows.h
new file mode 100644
index 0000000..803c8a8
--- /dev/null
+++ b/src/tracing/ipc/shared_memory_windows.h
@@ -0,0 +1,69 @@
+/*
+ * 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.
+ */
+
+#ifndef SRC_TRACING_IPC_SHARED_MEMORY_WINDOWS_H_
+#define SRC_TRACING_IPC_SHARED_MEMORY_WINDOWS_H_
+
+#include "perfetto/base/build_config.h"
+
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+
+#include "perfetto/base/build_config.h"
+#include "perfetto/ext/base/scoped_file.h"
+#include "perfetto/ext/tracing/core/shared_memory.h"
+
+namespace perfetto {
+
+// Implements the SharedMemory and its factory for the Windows IPC transport.
+// This used only for standalone builds and NOT in chromium, which instead uses
+// a custom Mojo wrapper (MojoSharedMemory in chromium's //services/tracing/).
+class SharedMemoryWindows : public SharedMemory {
+ public:
+  class Factory : public SharedMemory::Factory {
+   public:
+    ~Factory() override;
+    std::unique_ptr<SharedMemory> CreateSharedMemory(size_t) override;
+  };
+
+  // Create a brand new SHM region.
+  static std::unique_ptr<SharedMemoryWindows> Create(size_t size);
+  static std::unique_ptr<SharedMemoryWindows> Attach(const std::string& key);
+  ~SharedMemoryWindows() override;
+  const std::string& key() const { return key_; }
+
+  // SharedMemory implementation.
+  void* start() const override { return start_; }
+  size_t size() const override { return size_; }
+
+ private:
+  SharedMemoryWindows(void* start,
+                      size_t size,
+                      std::string,
+                      base::ScopedPlatformHandle);
+  SharedMemoryWindows(const SharedMemoryWindows&) = delete;
+  SharedMemoryWindows& operator=(const SharedMemoryWindows&) = delete;
+
+  void* const start_;
+  const size_t size_;
+  std::string key_;
+  base::ScopedPlatformHandle handle_;
+};
+
+}  // namespace perfetto
+
+#endif  // OS_WIN
+
+#endif  // SRC_TRACING_IPC_SHARED_MEMORY_WINDOWS_H_
diff --git a/src/tracing/platform_windows.cc b/src/tracing/platform_windows.cc
new file mode 100644
index 0000000..e442c65
--- /dev/null
+++ b/src/tracing/platform_windows.cc
@@ -0,0 +1,166 @@
+/*
+ * 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.
+ */
+
+#include "perfetto/base/build_config.h"
+
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+
+#include <Windows.h>
+
+#include "perfetto/ext/base/thread_task_runner.h"
+#include "perfetto/tracing/internal/tracing_tls.h"
+#include "perfetto/tracing/platform.h"
+
+#ifndef _WIN64
+#error 32-bit Windows is not supported
+#endif
+
+// Thread Termination Callbacks.
+// Windows doesn't support a per-thread destructor with its
+// TLS primitives. So, we build it manually by inserting a
+// function to be called on each thread's exit.
+// This magic is from chromium's base/threading/thread_local_storage_win.cc
+// which in turn is from http://www.codeproject.com/threads/tls.asp.
+
+#pragma comment(linker, "/INCLUDE:_tls_used")
+#pragma comment(linker, "/INCLUDE:perfetto_thread_callback_base")
+
+namespace perfetto {
+
+namespace {
+
+char g_tls_destroyed_sentinel;  // Type is irrelevant, just need a ptr.
+
+class PlatformWindows : public Platform {
+ public:
+  static PlatformWindows* instance;
+  PlatformWindows();
+  ~PlatformWindows() override;
+
+  ThreadLocalObject* GetOrCreateThreadLocalObject() override;
+  std::unique_ptr<base::TaskRunner> CreateTaskRunner(
+      const CreateTaskRunnerArgs&) override;
+  std::string GetCurrentProcessName() override;
+  void OnThreadExit();
+
+ private:
+  DWORD tls_key_{};
+};
+
+using ThreadLocalObject = Platform::ThreadLocalObject;
+
+// static
+PlatformWindows* PlatformWindows::instance = nullptr;
+
+PlatformWindows::PlatformWindows() {
+  instance = this;
+  tls_key_ = ::TlsAlloc();
+  PERFETTO_CHECK(tls_key_ != TLS_OUT_OF_INDEXES);
+}
+
+PlatformWindows::~PlatformWindows() {
+  ::TlsFree(tls_key_);
+  instance = nullptr;
+}
+
+void PlatformWindows::OnThreadExit() {
+  auto tls = static_cast<ThreadLocalObject*>(::TlsGetValue(tls_key_));
+  if (tls) {
+    ::TlsSetValue(tls_key_, &g_tls_destroyed_sentinel);
+    delete tls;
+  }
+}
+
+ThreadLocalObject* PlatformWindows::GetOrCreateThreadLocalObject() {
+  void* tls_ptr = ::TlsGetValue(tls_key_);
+
+  // Detect attempts of re-creating the TLS while destroying it.
+  PERFETTO_CHECK(tls_ptr != &g_tls_destroyed_sentinel);
+
+  auto* tls = static_cast<ThreadLocalObject*>(tls_ptr);
+  if (!tls) {
+    tls = ThreadLocalObject::CreateInstance().release();
+    ::TlsSetValue(tls_key_, tls);
+  }
+  return tls;
+}
+
+std::unique_ptr<base::TaskRunner> PlatformWindows::CreateTaskRunner(
+    const CreateTaskRunnerArgs&) {
+  return std::unique_ptr<base::TaskRunner>(
+      new base::ThreadTaskRunner(base::ThreadTaskRunner::CreateAndStart()));
+}
+
+std::string PlatformWindows::GetCurrentProcessName() {
+  char buf[MAX_PATH];
+  auto len = ::GetModuleFileNameA(nullptr /*current*/, buf, sizeof(buf));
+  std::string name(buf, static_cast<size_t>(len));
+  size_t sep = name.find_last_of('\\');
+  if (sep != std::string::npos)
+    name = name.substr(sep + 1);
+  return name;
+}
+
+}  // namespace
+
+// static
+Platform* Platform::GetDefaultPlatform() {
+  static PlatformWindows* thread_safe_init_instance = new PlatformWindows();
+  return thread_safe_init_instance;
+}
+
+}  // namespace perfetto
+
+// -----------------------
+// Thread-local destructor
+// -----------------------
+
+// .CRT$XLA to .CRT$XLZ is an array of PIMAGE_TLS_CALLBACK pointers that are
+// called automatically by the OS loader code (not the CRT) when the module is
+// loaded and on thread creation. They are NOT called if the module has been
+// loaded by a LoadLibrary() call. It must have implicitly been loaded at
+// process startup.
+// See VC\crt\src\tlssup.c for reference.
+
+// extern "C" suppresses C++ name mangling so we know the symbol name for the
+// linker /INCLUDE:symbol pragma above.
+extern "C" {
+// The linker must not discard perfetto_thread_callback_base. (We force a
+// reference to this variable with a linker /INCLUDE:symbol pragma to ensure
+// that.) If this variable is discarded, the OnThreadExit function will never be
+// called.
+
+void NTAPI PerfettoOnThreadExit(PVOID, DWORD, PVOID);
+void NTAPI PerfettoOnThreadExit(PVOID module, DWORD reason, PVOID reserved) {
+  if (reason == DLL_THREAD_DETACH || reason == DLL_PROCESS_DETACH) {
+    if (perfetto::PlatformWindows::instance)
+      perfetto::PlatformWindows::instance->OnThreadExit();
+  }
+}
+
+// .CRT section is merged with .rdata on x64 so it must be constant data.
+#pragma const_seg(".CRT$XLP")
+
+// When defining a const variable, it must have external linkage to be sure the
+// linker doesn't discard it.
+extern const PIMAGE_TLS_CALLBACK perfetto_thread_callback_base;
+const PIMAGE_TLS_CALLBACK perfetto_thread_callback_base = PerfettoOnThreadExit;
+
+// Reset the default section.
+#pragma const_seg()
+}  // extern "C"
+
+#endif  // OS_WIN
diff --git a/test/test_helper.h b/test/test_helper.h
index 4ac4c46..d9a99b9 100644
--- a/test/test_helper.h
+++ b/test/test_helper.h
@@ -34,8 +34,7 @@
 #include "test/fake_producer.h"
 
 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
-// TODO(primiano): uncomment in next CL.
-// #include "src/tracing/ipc/shared_memory_windows.h"
+#include "src/tracing/ipc/shared_memory_windows.h"
 #else
 #include "src/traced/probes/probes_producer.h"
 #include "src/tracing/ipc/posix_shared_memory.h"
@@ -168,12 +167,12 @@
 
   void CreateProducerProvidedSmb() {
 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
-    // TODO(primiano): in next CLs introduce SharedMemoryWindows.
+    SharedMemoryWindows::Factory factory;
 #else
     PosixSharedMemory::Factory factory;
+#endif
     shm_ = factory.CreateSharedMemory(1024 * 1024);
     shm_arbiter_ = SharedMemoryArbiter::CreateUnboundInstance(shm_.get(), 4096);
-#endif
   }
 
   void ProduceStartupEventBatch(const protos::gen::TestConfig& config,
diff --git a/tools/trace_to_text/trace_to_profile.cc b/tools/trace_to_text/trace_to_profile.cc
index a394e2b..b9e6807 100644
--- a/tools/trace_to_text/trace_to_profile.cc
+++ b/tools/trace_to_text/trace_to_profile.cc
@@ -53,10 +53,9 @@
 std::string GetRandomString(size_t n) {
   std::random_device r;
   auto rng = std::default_random_engine(r());
-  std::uniform_int_distribution<char> dist('a', 'z');
   std::string result(n, ' ');
   for (size_t i = 0; i < n; ++i) {
-    result[i] = dist(rng);
+    result[i] = 'a' + (rng() % ('z' - 'a'));
   }
   return result;
 }