Import Cobalt 22.master.0.303120
diff --git a/src/cobalt/base/wrap_main.h b/src/cobalt/base/wrap_main.h
index 7248992..bfdab78 100644
--- a/src/cobalt/base/wrap_main.h
+++ b/src/cobalt/base/wrap_main.h
@@ -41,7 +41,8 @@
 
 // A start-style function.
 typedef void (*StartFunction)(int argc, char** argv, const char* link,
-                              const base::Closure& quit_closure);
+                              const base::Closure& quit_closure,
+                              SbTimeMonotonic timestamp);
 
 // A function type that can be called at shutdown.
 typedef void (*StopFunction)();
@@ -52,7 +53,8 @@
 // No-operation function that can be passed into start_function if no start work
 // is needed.
 void NoopStartFunction(int argc, char** argv, const char* link,
-                       const base::Closure& quit_closure) {}
+                       const base::Closure& quit_closure,
+                       SbTimeMonotonic timestamp) {}
 
 // No-operation function that can be passed into event_function if no other
 // event handling work is needed.
@@ -90,7 +92,8 @@
   DCHECK(!message_loop.is_running());
   base::RunLoop run_loop;
 
-  start_function(argc, argv, NULL, run_loop.QuitClosure());
+  start_function(argc, argv, NULL, run_loop.QuitClosure(),
+                 0 /*Invalid timestamp*/);
   run_loop.Run();
   stop_function();
 
diff --git a/src/cobalt/base/wrap_main_starboard.h b/src/cobalt/base/wrap_main_starboard.h
index fdcf7c9..79524b4 100644
--- a/src/cobalt/base/wrap_main_starboard.h
+++ b/src/cobalt/base/wrap_main_starboard.h
@@ -53,9 +53,14 @@
       DCHECK(!g_loop);
       g_loop = new base::MessageLoopForUI();
       g_loop->Start();
-
+#if SB_API_VERSION >= 13
       preload_function(data->argument_count, data->argument_values, data->link,
-                       base::Bind(&SbSystemRequestStop, 0));
+                       base::Bind(&SbSystemRequestStop, 0), event->timestamp);
+#else  // SB_API_VERSION >= 13
+      preload_function(data->argument_count, data->argument_values, data->link,
+                       base::Bind(&SbSystemRequestStop, 0),
+                       SbTimeGetMonotonicNow());
+#endif  // SB_API_VERSION >= 13
       g_started = true;
       break;
     }
@@ -74,9 +79,14 @@
         g_loop = new base::MessageLoopForUI();
         g_loop->Start();
       }
-
+#if SB_API_VERSION >= 13
       start_function(data->argument_count, data->argument_values, data->link,
-                     base::Bind(&SbSystemRequestStop, 0));
+                     base::Bind(&SbSystemRequestStop, 0), event->timestamp);
+#else  // SB_API_VERSION >= 13
+      start_function(data->argument_count, data->argument_values, data->link,
+                     base::Bind(&SbSystemRequestStop, 0),
+                     SbTimeGetMonotonicNow());
+#endif  // SB_API_VERSION >= 13
       g_started = true;
       break;
     }
diff --git a/src/cobalt/bindings/testing/bindings_sandbox_main.cc b/src/cobalt/bindings/testing/bindings_sandbox_main.cc
index ec46c54..83adb20 100644
--- a/src/cobalt/bindings/testing/bindings_sandbox_main.cc
+++ b/src/cobalt/bindings/testing/bindings_sandbox_main.cc
@@ -28,7 +28,8 @@
 cobalt::script::StandaloneJavascriptRunner* g_javascript_runner = NULL;
 
 void StartApplication(int argc, char** argv, const char* link,
-                      const base::Closure& quit_closure) {
+                      const base::Closure& quit_closure,
+                      SbTimeMonotonic timestamp) {
   scoped_refptr<Window> test_window = new Window();
   cobalt::script::JavaScriptEngine::Options javascript_engine_options;
 
diff --git a/src/cobalt/browser/application.cc b/src/cobalt/browser/application.cc
index e186214..ba3c984 100644
--- a/src/cobalt/browser/application.cc
+++ b/src/cobalt/browser/application.cc
@@ -12,10 +12,6 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#if defined(STARBOARD)
-#include "starboard/client_porting/poem/stdio_leaks_poem.h"
-#endif
-
 #include "cobalt/browser/application.h"
 
 #include <map>
@@ -79,8 +75,8 @@
 #include "cobalt/trace_event/scoped_trace_to_file.h"
 #include "starboard/configuration.h"
 #include "starboard/event.h"
-#include "starboard/time.h"
 #include "starboard/system.h"
+#include "starboard/time.h"
 #include "url/gurl.h"
 
 #if SB_IS(EVERGREEN)
@@ -595,7 +591,8 @@
 ssize_t Application::available_memory_ = 0;
 int64 Application::lifetime_in_ms_ = 0;
 
-Application::Application(const base::Closure& quit_closure, bool should_preload)
+Application::Application(const base::Closure& quit_closure, bool should_preload,
+                         SbTimeMonotonic timestamp)
     : message_loop_(base::MessageLoop::current()),
       quit_closure_(quit_closure)
 #if defined(ENABLE_DEBUGGER) && defined(STARBOARD_ALLOWS_MEMORY_TRACKING)
@@ -855,6 +852,9 @@
 #endif
       options));
 
+  DCHECK(browser_module_);
+  browser_module_->SetApplicationStartOrPreloadTimestamp(should_preload,
+                                                         timestamp);
   UpdateUserAgent();
 
   // Register event callbacks.
@@ -1006,14 +1006,17 @@
 #endif
 }
 
-void Application::Start() {
+void Application::Start(SbTimeMonotonic timestamp) {
   if (base::MessageLoop::current() != message_loop_) {
     message_loop_->task_runner()->PostTask(
-        FROM_HERE, base::Bind(&Application::Start, base::Unretained(this)));
+        FROM_HERE, base::Bind(&Application::Start, base::Unretained(this),
+                              timestamp));
     return;
   }
 
-  OnApplicationEvent(kSbEventTypeStart, SbTimeGetMonotonicNow());
+  OnApplicationEvent(kSbEventTypeStart, timestamp);
+  browser_module_->SetApplicationStartOrPreloadTimestamp(
+      false /*is_preload*/, timestamp);
 }
 
 void Application::Quit() {
@@ -1046,8 +1049,7 @@
     case kSbEventTypeFreeze:
     case kSbEventTypeUnfreeze:
     case kSbEventTypeLowMemory:
-      OnApplicationEvent(starboard_event->type,
-                         starboard_event->timestamp);
+      OnApplicationEvent(starboard_event->type, starboard_event->timestamp);
       break;
 #else
     case kSbEventTypePause:
diff --git a/src/cobalt/browser/application.h b/src/cobalt/browser/application.h
index 620d376..1fa07da 100644
--- a/src/cobalt/browser/application.h
+++ b/src/cobalt/browser/application.h
@@ -52,11 +52,12 @@
  public:
   // The passed in |quit_closure| can be called internally by the Application
   // to signal that it would like to quit.
-  Application(const base::Closure& quit_closure, bool should_preload);
+  Application(const base::Closure& quit_closure, bool should_preload,
+              SbTimeMonotonic timestamp);
   virtual ~Application();
 
   // Start from a preloaded state.
-  void Start();
+  void Start(SbTimeMonotonic timestamp);
   void Quit();
   void HandleStarboardEvent(const SbEvent* event);
 
diff --git a/src/cobalt/browser/browser_module.cc b/src/cobalt/browser/browser_module.cc
index 18249fa..d724d9e 100644
--- a/src/cobalt/browser/browser_module.cc
+++ b/src/cobalt/browser/browser_module.cc
@@ -2094,5 +2094,12 @@
   return scoped_refptr<script::Wrappable>(new h5vcc::H5vcc(h5vcc_settings));
 }
 
+void BrowserModule::SetApplicationStartOrPreloadTimestamp(
+  bool is_preload, SbTimeMonotonic timestamp) {
+  DCHECK(web_module_);
+  web_module_->SetApplicationStartOrPreloadTimestamp(
+      is_preload, timestamp);
+}
+
 }  // namespace browser
 }  // namespace cobalt
diff --git a/src/cobalt/browser/browser_module.h b/src/cobalt/browser/browser_module.h
index 62bedea..ef8113f 100644
--- a/src/cobalt/browser/browser_module.h
+++ b/src/cobalt/browser/browser_module.h
@@ -229,6 +229,9 @@
   static void GetParamMap(const std::string& url,
                           std::map<std::string, std::string>& map);
 
+  // Pass the application preload or start timestamps from Starboard.
+  void SetApplicationStartOrPreloadTimestamp(bool is_preload,
+                                             SbTimeMonotonic timestamp);
  private:
 #if SB_HAS(CORE_DUMP_HANDLER_SUPPORT)
   static void CoreDumpHandler(void* browser_module_as_void);
diff --git a/src/cobalt/browser/main.cc b/src/cobalt/browser/main.cc
index 7464546..98ee605 100644
--- a/src/cobalt/browser/main.cc
+++ b/src/cobalt/browser/main.cc
@@ -55,7 +55,8 @@
 }
 
 void PreloadApplication(int argc, char** argv, const char* link,
-                        const base::Closure& quit_closure) {
+                        const base::Closure& quit_closure,
+                        SbTimeMonotonic timestamp) {
   if (CheckForAndExecuteStartupSwitches()) {
     SbSystemRequestStop(0);
     return;
@@ -63,12 +64,14 @@
   LOG(INFO) << "Concealing application.";
   DCHECK(!g_application);
   g_application =
-      new cobalt::browser::Application(quit_closure, true /*should_preload*/);
+      new cobalt::browser::Application(quit_closure, true /*should_preload*/,
+                                       timestamp);
   DCHECK(g_application);
 }
 
 void StartApplication(int argc, char** argv, const char* link,
-                      const base::Closure& quit_closure) {
+                      const base::Closure& quit_closure,
+                      SbTimeMonotonic timestamp) {
   if (CheckForAndExecuteStartupSwitches()) {
     SbSystemRequestStop(0);
     return;
@@ -77,15 +80,17 @@
 #if SB_API_VERSION >= 13
   DCHECK(!g_application);
   g_application =
-      new cobalt::browser::Application(quit_closure, false /*not_preload*/);
+      new cobalt::browser::Application(quit_closure, false /*not_preload*/,
+                                       timestamp);
   DCHECK(g_application);
 #else
   if (!g_application) {
     g_application = new cobalt::browser::Application(quit_closure,
-                                                     false /*should_preload*/);
+                                                     false /*should_preload*/,
+                                                     timestamp);
     DCHECK(g_application);
   } else {
-    g_application->Start();
+    g_application->Start(timestamp);
   }
 #endif  // SB_API_VERSION >= 13
 }
diff --git a/src/cobalt/browser/snapshot_app_stats.cc b/src/cobalt/browser/snapshot_app_stats.cc
index 41be3ce..e52b721 100644
--- a/src/cobalt/browser/snapshot_app_stats.cc
+++ b/src/cobalt/browser/snapshot_app_stats.cc
@@ -129,7 +129,8 @@
 base::Thread* g_snapshot_thread = NULL;
 
 void StartApplication(int argc, char* argv[], const char* link,
-                      const base::Closure& quit_closure) {
+                      const base::Closure& quit_closure,
+                      SbTimeMonotonic timestamp) {
   logging::SetMinLogLevel(100);
 
   // Use null storage for our savegame so that we don't persist state from
@@ -142,7 +143,8 @@
 
   // Create the application object just like is done in the Cobalt main app.
   g_application =
-      new cobalt::browser::Application(quit_closure, false /*should_preload*/);
+      new cobalt::browser::Application(quit_closure, false /*should_preload*/,
+                                       timestamp);
 
   // Create a thread to start a timer for kSecondsToWait seconds after which
   // we will take a snapshot of the CVals at that time and then quit the
diff --git a/src/cobalt/browser/web_module.cc b/src/cobalt/browser/web_module.cc
index 764516e..f4c2294 100644
--- a/src/cobalt/browser/web_module.cc
+++ b/src/cobalt/browser/web_module.cc
@@ -224,7 +224,8 @@
 
   // Sets the application state, asserts preconditions to transition to that
   // state, and dispatches any precipitate web events.
-  void SetApplicationState(base::ApplicationState state);
+  void SetApplicationState(base::ApplicationState state,
+                           SbTimeMonotonic timestamp);
 
   // See LifecycleObserver. These functions do not implement the interface, but
   // have the same basic function.
@@ -260,6 +261,9 @@
   void DoSynchronousLayoutAndGetRenderTree(
       scoped_refptr<render_tree::Node>* render_tree);
 
+  void SetApplicationStartOrPreloadTimestamp(
+      bool is_preload, SbTimeMonotonic timestamp);
+
  private:
   class DocumentLoadedObserver;
 
@@ -1023,6 +1027,13 @@
   *render_tree = tree;
 }
 
+void WebModule::Impl::SetApplicationStartOrPreloadTimestamp(
+    bool is_preload, SbTimeMonotonic timestamp) {
+  DCHECK(window_);
+  window_->performance()->SetApplicationStartOrPreloadTimestamp(
+      is_preload, timestamp);
+}
+
 void WebModule::Impl::OnCspPolicyChanged() {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   DCHECK(is_running_);
@@ -1118,8 +1129,9 @@
   window_->set_web_media_player_factory(media_module);
 }
 
-void WebModule::Impl::SetApplicationState(base::ApplicationState state) {
-  window_->SetApplicationState(state);
+void WebModule::Impl::SetApplicationState(base::ApplicationState state,
+                                          SbTimeMonotonic timestamp) {
+  window_->SetApplicationState(state, timestamp);
 }
 
 void WebModule::Impl::SetResourceProvider(
@@ -1150,7 +1162,7 @@
 
 void WebModule::Impl::Blur(SbTimeMonotonic timestamp) {
   TRACE_EVENT0("cobalt::browser", "WebModule::Impl::Blur()");
-  SetApplicationState(base::kApplicationStateBlurred);
+  SetApplicationState(base::kApplicationStateBlurred, timestamp);
 }
 
 void WebModule::Impl::Conceal(
@@ -1183,7 +1195,7 @@
   }
 
   loader_factory_->UpdateResourceProvider(resource_provider_);
-  SetApplicationState(base::kApplicationStateConcealed);
+  SetApplicationState(base::kApplicationStateConcealed, timestamp);
 }
 
 void WebModule::Impl::Freeze(SbTimeMonotonic timestamp) {
@@ -1192,7 +1204,7 @@
   // Clear out the loader factory's resource provider, possibly aborting any
   // in-progress loads.
   loader_factory_->Suspend();
-  SetApplicationState(base::kApplicationStateFrozen);
+  SetApplicationState(base::kApplicationStateFrozen, timestamp);
 }
 
 void WebModule::Impl::Unfreeze(
@@ -1203,7 +1215,7 @@
   DCHECK(resource_provider);
 
   loader_factory_->Resume(resource_provider);
-  SetApplicationState(base::kApplicationStateConcealed);
+  SetApplicationState(base::kApplicationStateConcealed, timestamp);
 }
 
 void WebModule::Impl::Reveal(
@@ -1220,13 +1232,13 @@
   loader_factory_->UpdateResourceProvider(resource_provider_);
   layout_manager_->Resume();
 
-  SetApplicationState(base::kApplicationStateBlurred);
+  SetApplicationState(base::kApplicationStateBlurred, timestamp);
 }
 
 void WebModule::Impl::Focus(SbTimeMonotonic timestamp) {
   TRACE_EVENT0("cobalt::browser", "WebModule::Impl::Focus()");
   synchronous_loader_interrupt_.Reset();
-  SetApplicationState(base::kApplicationStateStarted);
+  SetApplicationState(base::kApplicationStateStarted, timestamp);
 }
 
 void WebModule::Impl::ReduceMemory() {
@@ -1808,5 +1820,21 @@
   return render_tree;
 }
 
+void WebModule::SetApplicationStartOrPreloadTimestamp(
+    bool is_preload, SbTimeMonotonic timestamp) {
+  TRACE_EVENT0("cobalt::browser",
+               "WebModule::SetApplicationStartOrPreloadTimestamp()");
+  DCHECK(message_loop());
+  DCHECK(impl_);
+  if (base::MessageLoop::current() != message_loop()) {
+    message_loop()->task_runner()->PostBlockingTask(
+      FROM_HERE,
+      base::Bind(&WebModule::Impl::SetApplicationStartOrPreloadTimestamp,
+                 base::Unretained(impl_.get()), is_preload, timestamp));
+  } else {
+    impl_->SetApplicationStartOrPreloadTimestamp(is_preload, timestamp);
+  }
+}
+
 }  // namespace browser
 }  // namespace cobalt
diff --git a/src/cobalt/browser/web_module.h b/src/cobalt/browser/web_module.h
index d2ebec1..d3350b3 100644
--- a/src/cobalt/browser/web_module.h
+++ b/src/cobalt/browser/web_module.h
@@ -409,6 +409,8 @@
 
   scoped_refptr<render_tree::Node> DoSynchronousLayoutAndGetRenderTree();
 
+  void SetApplicationStartOrPreloadTimestamp(bool is_preload,
+                                             SbTimeMonotonic timestamp);
  private:
   // Data required to construct a WebModule, initialized in the constructor and
   // passed to |Initialize|.
diff --git a/src/cobalt/build/build.id b/src/cobalt/build/build.id
index 6655f86..912bb2b 100644
--- a/src/cobalt/build/build.id
+++ b/src/cobalt/build/build.id
@@ -1 +1 @@
-303007
\ No newline at end of file
+303120
\ No newline at end of file
diff --git a/src/cobalt/doc/docker_build.md b/src/cobalt/doc/docker_build.md
index f200179..7a04812 100644
--- a/src/cobalt/doc/docker_build.md
+++ b/src/cobalt/doc/docker_build.md
@@ -1,15 +1,12 @@
-# Cobalt Docker builds [ Experimental ]
+# Cobalt Docker builds
 
-Cobalt includes minimal [Docker image][docker.com](https://www.docker.com/)
+Cobalt includes [Docker image][docker.com](https://www.docker.com/)
 definitions for simplifying managing build environments.
 
 The instructions below assume Docker is installed and is able to run basic
 [`hello-world` verification](https://docs.docker.com/get-started/#test-docker-installation).
 `docker-compose` command is expected to be available as well.
 
-Note: Docker build images are currently provided as experimental, and for
-reference only.
-
 ## Usage
 
 The simplest usage is:
@@ -55,6 +52,10 @@
 configurations. Edit or add new `service` entries as needed, to build custom
 configurations.
 
+## Pre-built images
+
+Note: Pre-built images from a public container registry are not yet available.
+
 ## Troubleshooting
 
 To debug build issues, enter the shell of the corresponding build container by
diff --git a/src/cobalt/dom/dom_test.gyp b/src/cobalt/dom/dom_test.gyp
index 3e9dbbc..456965d 100644
--- a/src/cobalt/dom/dom_test.gyp
+++ b/src/cobalt/dom/dom_test.gyp
@@ -68,6 +68,7 @@
         'text_test.cc',
         'time_ranges_test.cc',
         'url_utils_test.cc',
+        'user_agent_data_test.cc',
         'window_test.cc',
         'xml_document_test.cc',
       ],
diff --git a/src/cobalt/dom/performance.cc b/src/cobalt/dom/performance.cc
index 2428bc5..a90c2e8 100644
--- a/src/cobalt/dom/performance.cc
+++ b/src/cobalt/dom/performance.cc
@@ -77,7 +77,7 @@
       timing_(new PerformanceTiming(clock, time_origin_)),
       memory_(new MemoryInfo()),
       lifecycle_timing_(
-          new PerformanceLifecycleTiming("lifecycle timing", 0.0, 0.0)),
+          new PerformanceLifecycleTiming("lifecycle timing", time_origin_)),
       resource_timing_buffer_size_limit_(
           Performance::kMaxResourceTimingBufferSize),
       resource_timing_buffer_current_size_(0),
@@ -102,8 +102,6 @@
       ClampTimeStampMinimumResolution(time_origin,
       Performance::kPerformanceTimerMinResolutionInMicroseconds);
 
-  if (clamped_time < 0)
-    return 0.0;
   return clamped_time;
 }
 
@@ -613,5 +611,16 @@
   AddPerformanceResourceTimingEntry(resource_timing);
 }
 
+void Performance::SetApplicationState(base::ApplicationState state,
+                                      SbTimeMonotonic timestamp) {
+  lifecycle_timing_->SetApplicationState(state, timestamp);
+}
+
+void Performance::SetApplicationStartOrPreloadTimestamp(
+    bool is_preload, SbTimeMonotonic timestamp) {
+  lifecycle_timing_->SetApplicationStartOrPreloadTimestamp(
+      is_preload, timestamp);
+}
+
 }  // namespace dom
 }  // namespace cobalt
diff --git a/src/cobalt/dom/performance.h b/src/cobalt/dom/performance.h
index e69d9a8..753123d 100644
--- a/src/cobalt/dom/performance.h
+++ b/src/cobalt/dom/performance.h
@@ -20,10 +20,10 @@
 #include <map>
 #include <string>
 
-#include "cobalt/base/clock.h"
 #include "base/time/default_tick_clock.h"
 #include "base/threading/thread.h"
 #include "base/threading/thread_checker.h"
+#include "cobalt/base/application_state.h"
 #include "cobalt/base/clock.h"
 #include "cobalt/dom/event_target.h"
 #include "cobalt/dom/performance_entry_list_impl.h"
@@ -132,6 +132,12 @@
       const scoped_refptr<PerformanceObserver>& observer,
       const PerformanceObserverInit& options);
 
+  void SetApplicationState(base::ApplicationState state,
+                           SbTimeMonotonic timestamp);
+
+  void SetApplicationStartOrPreloadTimestamp(
+      bool is_preload, SbTimeMonotonic timestamp);
+
   void TraceMembers(script::Tracer* tracer) override;
   DEFINE_WRAPPABLE_TYPE(Performance);
 
diff --git a/src/cobalt/dom/performance_lifecycle_timing.cc b/src/cobalt/dom/performance_lifecycle_timing.cc
index 6b64ff4..bb2e21b 100644
--- a/src/cobalt/dom/performance_lifecycle_timing.cc
+++ b/src/cobalt/dom/performance_lifecycle_timing.cc
@@ -19,51 +19,153 @@
 namespace cobalt {
 namespace dom {
 
+namespace {
+
+  std::string TranslateApplicationStateToString(
+      base::ApplicationState state) {
+    switch (state) {
+      case base::kApplicationStateBlurred:
+        return "ApplicationStateBlurred";
+      case base::kApplicationStateConcealed:
+        return "ApplicationStateConcealed";
+      case base::kApplicationStateFrozen:
+        return "ApplicationStateFrozen";
+      case base::kApplicationStateStarted:
+        return "ApplicationStateStarted";
+      case base::kApplicationStateStopped:
+        return "ApplicationStateStopped";
+    }
+
+    NOTREACHED() << "state = " << state;
+    return "INVALID_APPLICATION_STATE";
+  }
+
+  DOMHighResTimeStamp ConvertSbTimeMonotonicToDOMHiResTimeStamp(
+      base::TimeTicks time_origin, SbTimeMonotonic monotonic_time) {
+    SbTimeMonotonic time_delta = SbTimeGetNow() - SbTimeGetMonotonicNow();
+    base::TimeTicks time_ticks =
+        base::TimeTicks::FromInternalValue(time_delta + monotonic_time);
+    return Performance::MonotonicTimeToDOMHighResTimeStamp(
+        time_origin, time_ticks);
+  }
+
+}  // namespace
+
 PerformanceLifecycleTiming::PerformanceLifecycleTiming(
-    const std::string& name, DOMHighResTimeStamp start_time,
-    DOMHighResTimeStamp end_time)
-    : PerformanceEntry(name, start_time, end_time),
-    current_state_("unstarted"),
-    last_state_("unstarted") {}
+    const std::string& name, base::TimeTicks time_origin)
+    : PerformanceEntry(name, 0.0, 0.0), time_origin_(time_origin) {}
+
+
+DOMHighResTimeStamp PerformanceLifecycleTiming::app_preload() const {
+  return ReportDOMHighResTimeStamp(lifecycle_timing_info_.app_preload);
+}
 
 DOMHighResTimeStamp PerformanceLifecycleTiming::app_start() const {
-  return PerformanceEntry::start_time();
+  return ReportDOMHighResTimeStamp(lifecycle_timing_info_.app_start);
 }
 
 DOMHighResTimeStamp PerformanceLifecycleTiming::app_blur() const {
-  return PerformanceEntry::start_time();
+  return ReportDOMHighResTimeStamp(lifecycle_timing_info_.app_blur);
 }
 
 DOMHighResTimeStamp PerformanceLifecycleTiming::app_focus() const {
-  return PerformanceEntry::start_time();
+  return ReportDOMHighResTimeStamp(lifecycle_timing_info_.app_focus);
 }
 
 DOMHighResTimeStamp PerformanceLifecycleTiming::app_conceal() const {
-  return PerformanceEntry::start_time();
+  return ReportDOMHighResTimeStamp(lifecycle_timing_info_.app_conceal);
 }
 
 DOMHighResTimeStamp PerformanceLifecycleTiming::app_reveal() const {
-  return PerformanceEntry::start_time();
+  return ReportDOMHighResTimeStamp(lifecycle_timing_info_.app_reveal);
 }
 
 DOMHighResTimeStamp PerformanceLifecycleTiming::app_freeze() const {
-  return PerformanceEntry::start_time();
+  return ReportDOMHighResTimeStamp(lifecycle_timing_info_.app_freeze);
 }
 
 DOMHighResTimeStamp PerformanceLifecycleTiming::app_unfreeze() const {
-  return PerformanceEntry::start_time();
-}
-
-DOMHighResTimeStamp PerformanceLifecycleTiming::app_stop() const {
-  return PerformanceEntry::start_time();
+  return ReportDOMHighResTimeStamp(lifecycle_timing_info_.app_unfreeze);
 }
 
 std::string PerformanceLifecycleTiming::current_state() const {
-  return current_state_;
+  return TranslateApplicationStateToString(
+      lifecycle_timing_info_.current_state);
 }
 
 std::string PerformanceLifecycleTiming::last_state() const {
-  return last_state_;
+  return TranslateApplicationStateToString(
+      lifecycle_timing_info_.last_state);
+}
+
+void PerformanceLifecycleTiming::SetApplicationState(
+    base::ApplicationState state, SbTimeMonotonic timestamp) {
+  switch (state) {
+    case base::kApplicationStateBlurred:
+      if (GetLastState() == base::kApplicationStateStarted) {
+        lifecycle_timing_info_.app_blur = timestamp;
+      } else if (GetLastState() == base::kApplicationStateConcealed) {
+        lifecycle_timing_info_.app_reveal = timestamp;
+      }
+      break;
+    case base::kApplicationStateConcealed:
+      if (GetLastState() == base::kApplicationStateBlurred) {
+        lifecycle_timing_info_.app_conceal = timestamp;
+      } else if (GetLastState() == base::kApplicationStateFrozen) {
+        lifecycle_timing_info_.app_unfreeze = timestamp;
+      }
+      break;
+    case base::kApplicationStateFrozen:
+      lifecycle_timing_info_.app_freeze = timestamp;
+      break;
+    case base::kApplicationStateStarted:
+      if (GetLastState() == base::kApplicationStateBlurred) {
+        if (lifecycle_timing_info_.app_preload != 0) {
+          lifecycle_timing_info_.app_start = timestamp;
+        }
+        lifecycle_timing_info_.app_focus = timestamp;
+      }
+      break;
+    case base::kApplicationStateStopped:
+      NOTREACHED() << "Not support the application stopped state.";
+      break;
+    default:
+      NOTREACHED() << "Invalid application state = " << state;
+      break;
+  }
+  SetLifecycleTimingInfoState(state);
+}
+
+void PerformanceLifecycleTiming::SetApplicationStartOrPreloadTimestamp(
+      bool is_preload, SbTimeMonotonic timestamp) {
+  if (is_preload) {
+    lifecycle_timing_info_.app_preload = timestamp;
+    SetLifecycleTimingInfoState(base::kApplicationStateConcealed);
+  } else {
+    lifecycle_timing_info_.app_start = timestamp;
+    SetLifecycleTimingInfoState(base::kApplicationStateStarted);
+  }
+}
+
+base::ApplicationState PerformanceLifecycleTiming::GetLastState() const {
+  return lifecycle_timing_info_.last_state;
+}
+
+void PerformanceLifecycleTiming::SetLifecycleTimingInfoState(
+    base::ApplicationState state) {
+  lifecycle_timing_info_.last_state =
+      lifecycle_timing_info_.current_state;
+  lifecycle_timing_info_.current_state = state;
+}
+
+DOMHighResTimeStamp
+    PerformanceLifecycleTiming::ReportDOMHighResTimeStamp(
+        SbTimeMonotonic timestamp) const {
+  if (timestamp != 0) {
+    return ConvertSbTimeMonotonicToDOMHiResTimeStamp(
+        time_origin_, timestamp);
+  }
+  return PerformanceEntry::start_time();
 }
 
 }  // namespace dom
diff --git a/src/cobalt/dom/performance_lifecycle_timing.h b/src/cobalt/dom/performance_lifecycle_timing.h
index 08a3415..42fc320 100644
--- a/src/cobalt/dom/performance_lifecycle_timing.h
+++ b/src/cobalt/dom/performance_lifecycle_timing.h
@@ -17,11 +17,11 @@
 
 #include <string>
 
+#include "base/time/time.h"
+#include "cobalt/base/application_state.h"
 #include "cobalt/dom/performance_entry.h"
 #include "cobalt/dom/performance_high_resolution_time.h"
-
 #include "cobalt/script/wrappable.h"
-#include "net/base/load_timing_info.h"
 
 namespace cobalt {
 namespace dom {
@@ -31,10 +31,10 @@
 class PerformanceLifecycleTiming : public PerformanceEntry {
  public:
   PerformanceLifecycleTiming(const std::string& name,
-                            DOMHighResTimeStamp start_time,
-                            DOMHighResTimeStamp end_time);
+                             base::TimeTicks time_origin);
 
   // Web API.
+  DOMHighResTimeStamp app_preload() const;
   DOMHighResTimeStamp app_start() const;
   DOMHighResTimeStamp app_blur() const;
   DOMHighResTimeStamp app_focus() const;
@@ -42,7 +42,6 @@
   DOMHighResTimeStamp app_reveal() const;
   DOMHighResTimeStamp app_freeze() const;
   DOMHighResTimeStamp app_unfreeze() const;
-  DOMHighResTimeStamp app_stop() const;
   std::string current_state() const;
   std::string last_state() const;
 
@@ -51,11 +50,37 @@
     return PerformanceEntry::kLifecycle;
   }
 
+  void SetApplicationState(base::ApplicationState state,
+                           SbTimeMonotonic timestamp);
+  void SetApplicationStartOrPreloadTimestamp(
+      bool is_preload, SbTimeMonotonic timestamp);
+
   DEFINE_WRAPPABLE_TYPE(PerformanceLifecycleTiming);
 
  private:
-  std::string current_state_;
-  std::string last_state_;
+  void SetLifecycleTimingInfoState(base::ApplicationState state);
+  DOMHighResTimeStamp ReportDOMHighResTimeStamp(
+      SbTimeMonotonic timestamp) const;
+  base::ApplicationState GetLastState() const;
+ struct LifecycleTimingInfo {
+  SbTimeMonotonic app_preload = 0;
+  SbTimeMonotonic app_start = 0;
+  SbTimeMonotonic app_blur = 0;
+  SbTimeMonotonic app_conceal = 0;
+  SbTimeMonotonic app_focus = 0;
+  SbTimeMonotonic app_reveal = 0;
+  SbTimeMonotonic app_freeze = 0;
+  SbTimeMonotonic app_unfreeze = 0;
+
+  base::ApplicationState current_state =
+      base::kApplicationStateStopped;
+  base::ApplicationState last_state =
+      base::kApplicationStateStopped;
+ };
+
+  LifecycleTimingInfo lifecycle_timing_info_;
+
+  base::TimeTicks time_origin_;
 
   DISALLOW_COPY_AND_ASSIGN(PerformanceLifecycleTiming);
 };
diff --git a/src/cobalt/dom/performance_lifecycle_timing.idl b/src/cobalt/dom/performance_lifecycle_timing.idl
index 602331d..7d14eb8 100644
--- a/src/cobalt/dom/performance_lifecycle_timing.idl
+++ b/src/cobalt/dom/performance_lifecycle_timing.idl
@@ -14,6 +14,7 @@
 
 [Exposed=Window]
 interface PerformanceLifecycleTiming : PerformanceEntry {
+  readonly  attribute DOMHighResTimeStamp appPreload;
   readonly  attribute DOMHighResTimeStamp appStart;
   readonly  attribute DOMHighResTimeStamp appBlur;
   readonly  attribute DOMHighResTimeStamp appFocus;
@@ -21,7 +22,6 @@
   readonly  attribute DOMHighResTimeStamp appReveal;
   readonly  attribute DOMHighResTimeStamp appFreeze;
   readonly  attribute DOMHighResTimeStamp appUnfreeze;
-  readonly  attribute DOMHighResTimeStamp appStop;
   readonly  attribute DOMString  currentState;
   readonly  attribute DOMString  lastState;
 };
diff --git a/src/cobalt/dom/user_agent_data_test.cc b/src/cobalt/dom/user_agent_data_test.cc
new file mode 100644
index 0000000..d6f0a58
--- /dev/null
+++ b/src/cobalt/dom/user_agent_data_test.cc
@@ -0,0 +1,215 @@
+// Copyright 2021 The Cobalt Authors. All Rights Reserved.
+//
+// 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 <string>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/optional.h"
+#include "cobalt/bindings/testing/utils.h"
+#include "cobalt/browser/user_agent_platform_info.h"
+#include "cobalt/css_parser/parser.h"
+#include "cobalt/cssom/viewport_size.h"
+#include "cobalt/dom/global_stats.h"
+#include "cobalt/dom/local_storage_database.h"
+#include "cobalt/dom/navigator.h"
+#include "cobalt/dom/navigator_ua_data.h"
+#include "cobalt/dom/testing/gtest_workarounds.h"
+#include "cobalt/dom/testing/stub_environment_settings.h"
+#include "cobalt/dom/window.h"
+#include "cobalt/dom_parser/parser.h"
+#include "cobalt/h5vcc/h5vcc.h"
+#include "cobalt/loader/fetcher_factory.h"
+#include "cobalt/loader/loader_factory.h"
+#include "cobalt/script/global_environment.h"
+#include "cobalt/script/javascript_engine.h"
+#include "cobalt/script/source_code.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using cobalt::cssom::ViewportSize;
+
+namespace cobalt {
+namespace dom {
+
+namespace {
+
+class UserAgentDataTest : public ::testing::Test {
+ public:
+  UserAgentDataTest()
+      : environment_settings_(new testing::StubEnvironmentSettings),
+        css_parser_(css_parser::Parser::Create()),
+        dom_parser_(
+            new dom_parser::Parser(base::Bind(&StubLoadCompleteCallback))),
+        fetcher_factory_(new loader::FetcherFactory(NULL)),
+        loader_factory_(new loader::LoaderFactory(
+            "Test", fetcher_factory_.get(), NULL, null_debugger_hooks_, 0,
+            base::ThreadPriority::DEFAULT)),
+        local_storage_database_(NULL),
+        url_("about:blank"),
+        engine_(script::JavaScriptEngine::CreateEngine()),
+        global_environment_(engine_->CreateGlobalEnvironment()) {
+    InitializeEmptyPlatformInfo();
+    window_ = new Window(
+        environment_settings_.get(), ViewportSize(1920, 1080),
+        base::kApplicationStateStarted, css_parser_.get(), dom_parser_.get(),
+        fetcher_factory_.get(), loader_factory_.get(), NULL, NULL, NULL, NULL,
+        NULL, NULL, &local_storage_database_, NULL, NULL, NULL, NULL,
+        global_environment_->script_value_factory() /* script_value_factory */,
+        NULL, NULL, url_, "", platform_info_.get(), "en-US", "en",
+        base::Callback<void(const GURL&)>(),
+        base::Bind(&StubLoadCompleteCallback), NULL,
+        network_bridge::PostSender(), csp::kCSPRequired, kCspEnforcementEnable,
+        base::Closure() /* csp_policy_changed */,
+        base::Closure() /* ran_animation_frame_callbacks */,
+        dom::Window::CloseCallback() /* window_close */,
+        base::Closure() /* window_minimize */, NULL, NULL,
+        dom::Window::OnStartDispatchEventCallback(),
+        dom::Window::OnStopDispatchEventCallback(),
+        dom::ScreenshotManager::ProvideScreenshotFunctionCallback(), NULL);
+
+    // Make Navigator accessible via Window
+    global_environment_->CreateGlobalObject(window_,
+                                            environment_settings_.get());
+
+    // Inject H5vcc interface to make it also accessible via Window
+    h5vcc::H5vcc::Settings h5vcc_settings;
+    h5vcc_settings.media_module = NULL;
+    h5vcc_settings.network_module = NULL;
+#if SB_IS(EVERGREEN)
+    h5vcc_settings.updater_module = NULL;
+#endif
+    h5vcc_settings.account_manager = NULL;
+    h5vcc_settings.event_dispatcher = &event_dispatcher_;
+    h5vcc_settings.user_agent_data = window_->navigator()->user_agent_data();
+    h5vcc_settings.global_environment = global_environment_;
+    global_environment_->Bind("h5vcc", scoped_refptr<script::Wrappable>(
+                                           new h5vcc::H5vcc(h5vcc_settings)));
+  }
+
+  ~UserAgentDataTest() {
+    global_environment_->SetReportEvalCallback(base::Closure());
+    global_environment_->SetReportErrorCallback(
+        script::GlobalEnvironment::ReportErrorCallback());
+    window_->DispatchEvent(new dom::Event(base::Tokens::unload()));
+
+    window_ = nullptr;
+    global_environment_ = nullptr;
+    EXPECT_TRUE(GlobalStats::GetInstance()->CheckNoLeaks());
+  }
+
+  bool EvaluateScript(const std::string& js_code, std::string* result);
+
+  void SetUp() override;
+
+ private:
+  static void StubLoadCompleteCallback(
+      const base::Optional<std::string>& error) {}
+  const std::unique_ptr<testing::StubEnvironmentSettings> environment_settings_;
+  base::NullDebuggerHooks null_debugger_hooks_;
+  base::MessageLoop message_loop_;
+  std::unique_ptr<css_parser::Parser> css_parser_;
+  std::unique_ptr<dom_parser::Parser> dom_parser_;
+  std::unique_ptr<loader::FetcherFactory> fetcher_factory_;
+  std::unique_ptr<loader::LoaderFactory> loader_factory_;
+  dom::LocalStorageDatabase local_storage_database_;
+  GURL url_;
+  std::unique_ptr<script::JavaScriptEngine> engine_;
+  base::EventDispatcher event_dispatcher_;
+  scoped_refptr<script::GlobalEnvironment> global_environment_;
+  std::unique_ptr<browser::UserAgentPlatformInfo> platform_info_;
+  scoped_refptr<Window> window_;
+
+  void InitializeEmptyPlatformInfo();
+};
+
+bool UserAgentDataTest::EvaluateScript(const std::string& js_code,
+                                       std::string* result) {
+  DCHECK(global_environment_);
+  scoped_refptr<script::SourceCode> source_code =
+      script::SourceCode::CreateSourceCode(
+          js_code, base::SourceLocation(__FILE__, __LINE__, 1));
+
+  global_environment_->EnableEval();
+  global_environment_->SetReportEvalCallback(base::Closure());
+  bool succeeded = global_environment_->EvaluateScript(source_code, result);
+  return succeeded;
+}
+
+void UserAgentDataTest::SetUp() {
+  // Let's first check that the Web API is by default disabled, and that the
+  // switch to turn it on works
+  std::string result;
+  EXPECT_TRUE(EvaluateScript("navigator.userAgentData", &result));
+  EXPECT_FALSE(bindings::testing::IsAcceptablePrototypeString("NavigatorUAData",
+                                                              result));
+
+  EXPECT_TRUE(
+      EvaluateScript("h5vcc.settings.set('NavigatorUAData', 1)", &result));
+  EXPECT_EQ("true", result);
+
+  EXPECT_TRUE(EvaluateScript("navigator.userAgentData", &result));
+  EXPECT_TRUE(bindings::testing::IsAcceptablePrototypeString("NavigatorUAData",
+                                                             result));
+}
+
+void UserAgentDataTest::InitializeEmptyPlatformInfo() {
+  platform_info_.reset(new browser::UserAgentPlatformInfo());
+
+  platform_info_->set_starboard_version("");
+  platform_info_->set_os_name_and_version("");
+  platform_info_->set_original_design_manufacturer("");
+  platform_info_->set_device_type(kSbSystemDeviceTypeUnknown);
+  platform_info_->set_chipset_model_number("");
+  platform_info_->set_model_year("");
+  platform_info_->set_firmware_version("");
+  platform_info_->set_brand("");
+  platform_info_->set_model("");
+  platform_info_->set_aux_field("");
+  platform_info_->set_connection_type(base::nullopt);
+  platform_info_->set_javascript_engine_version("");
+  platform_info_->set_rasterizer_type("");
+  platform_info_->set_evergreen_version("");
+  platform_info_->set_cobalt_version("");
+  platform_info_->set_cobalt_build_version_number("");
+  platform_info_->set_build_configuration("");
+}
+
+}  // namespace
+
+TEST_F(UserAgentDataTest, Brands) {
+  std::string result;
+  EXPECT_TRUE(EvaluateScript("navigator.userAgentData.brands", &result));
+  EXPECT_TRUE(bindings::testing::IsAcceptablePrototypeString("Object", result));
+}
+
+TEST_F(UserAgentDataTest, Mobile) {
+  std::string result;
+  EXPECT_TRUE(EvaluateScript("navigator.userAgentData.mobile", &result));
+  EXPECT_EQ("false", result);
+}
+
+TEST_F(UserAgentDataTest, GetHighEntropyValues) {
+  std::string result;
+  EXPECT_TRUE(
+      EvaluateScript("navigator.userAgentData.getHighEntropyValues", &result));
+  EXPECT_PRED_FORMAT2(::testing::IsSubstring, "function getHighEntropyValues()",
+                      result.c_str());
+  EXPECT_TRUE(EvaluateScript("navigator.userAgentData.getHighEntropyValues([])",
+                             &result));
+  EXPECT_TRUE(
+      bindings::testing::IsAcceptablePrototypeString("Promise", result));
+}
+
+}  // namespace dom
+}  // namespace cobalt
diff --git a/src/cobalt/dom/window.cc b/src/cobalt/dom/window.cc
index c95ed07..a3bee80 100644
--- a/src/cobalt/dom/window.cc
+++ b/src/cobalt/dom/window.cc
@@ -534,9 +534,11 @@
   }
 }
 
-void Window::SetApplicationState(base::ApplicationState state) {
+void Window::SetApplicationState(base::ApplicationState state,
+                                 SbTimeMonotonic timestamp) {
   html_element_context_->application_lifecycle_state()->SetApplicationState(
       state);
+  performance_->SetApplicationState(state, timestamp);
 }
 
 bool Window::ReportScriptError(const script::ErrorReport& error_report) {
diff --git a/src/cobalt/dom/window.h b/src/cobalt/dom/window.h
index dce79c2..81467b4 100644
--- a/src/cobalt/dom/window.h
+++ b/src/cobalt/dom/window.h
@@ -358,7 +358,8 @@
   // Sets the current application state, forwarding on to the
   // ApplicationLifecycleState associated with it and its document, causing
   // precipitate events to be dispatched.
-  void SetApplicationState(base::ApplicationState state);
+  void SetApplicationState(base::ApplicationState state,
+                           SbTimeMonotonic timestamp);
 
   // Performs the steps specified for runtime script errors:
   //   https://www.w3.org/TR/html50/webappapis.html#runtime-script-errors
diff --git a/src/cobalt/h5vcc/h5vcc_settings.cc b/src/cobalt/h5vcc/h5vcc_settings.cc
index e53ba06..2607bed 100644
--- a/src/cobalt/h5vcc/h5vcc_settings.cc
+++ b/src/cobalt/h5vcc/h5vcc_settings.cc
@@ -39,6 +39,7 @@
 
   if (name.compare(kNavigatorUAData) == 0 && value == 1) {
     global_environment_->BindTo("userAgentData", user_agent_data_, "navigator");
+    return true;
   }
 
   if (name.compare(kQUIC) == 0) {
diff --git a/src/cobalt/renderer/sandbox/renderer_sandbox_main.cc b/src/cobalt/renderer/sandbox/renderer_sandbox_main.cc
index fbcaa13..5f14c46 100644
--- a/src/cobalt/renderer/sandbox/renderer_sandbox_main.cc
+++ b/src/cobalt/renderer/sandbox/renderer_sandbox_main.cc
@@ -82,7 +82,8 @@
 RendererSandbox* g_renderer_sandbox = NULL;
 
 void StartApplication(int argc, char** argv, const char* link,
-                      const base::Closure& quit_closure) {
+                      const base::Closure& quit_closure,
+                      SbTimeMonotonic timestamp) {
   DCHECK(!g_renderer_sandbox);
   g_renderer_sandbox = new RendererSandbox();
   DCHECK(g_renderer_sandbox);
diff --git a/src/cobalt/script/v8c/v8c.cc b/src/cobalt/script/v8c/v8c.cc
index 3f91c6d..5ff424f 100644
--- a/src/cobalt/script/v8c/v8c.cc
+++ b/src/cobalt/script/v8c/v8c.cc
@@ -75,7 +75,8 @@
 cobalt::script::StandaloneJavascriptRunner* g_javascript_runner = NULL;
 
 void StartApplication(int argc, char** argv, const char* /*link */,
-                      const base::Closure& quit_closure) {
+                      const base::Closure& quit_closure,
+                      SbTimeMonotonic timestamp) {
   DCHECK(!g_javascript_runner);
   g_javascript_runner = new cobalt::script::StandaloneJavascriptRunner(
       base::MessageLoop::current()->task_runner());
diff --git a/src/cobalt/speech/sandbox/speech_sandbox_main.cc b/src/cobalt/speech/sandbox/speech_sandbox_main.cc
index c79448b..55e0481 100644
--- a/src/cobalt/speech/sandbox/speech_sandbox_main.cc
+++ b/src/cobalt/speech/sandbox/speech_sandbox_main.cc
@@ -29,7 +29,8 @@
 // The timeout is optional. If it is not set or set to 0, the application
 // doesn't shut down.
 void StartApplication(int argc, char** argv, const char* link,
-                      const base::Closure& quit_closure) {
+                      const base::Closure& quit_closure,
+                      SbTimeMonotonic timestamp) {
   if (argc != 3 && argc != 2) {
     LOG(ERROR) << "Usage: " << argv[0]
                << " <audio url|path> [timeout in seconds]";
diff --git a/src/cobalt/updater/one_app_only_sandbox.cc b/src/cobalt/updater/one_app_only_sandbox.cc
index 864c166..8b31ce4 100644
--- a/src/cobalt/updater/one_app_only_sandbox.cc
+++ b/src/cobalt/updater/one_app_only_sandbox.cc
@@ -67,7 +67,8 @@
 }
 
 void PreloadApplication(int argc, char** argv, const char* link,
-                        const base::Closure& quit_closure) {
+                        const base::Closure& quit_closure,
+                        SbTimeMonotonic timestamp) {
   if (CheckForAndExecuteStartupSwitches()) {
     SbSystemRequestStop(0);
     return;
@@ -75,12 +76,14 @@
   LOG(INFO) << "Concealing application.";
   DCHECK(!g_application);
   g_application =
-      new cobalt::browser::Application(quit_closure, true /*should_preload*/);
+      new cobalt::browser::Application(quit_closure, true /*should_preload*/,
+                                       timestamp);
   DCHECK(g_application);
 }
 
 void StartApplication(int argc, char** argv, const char* link,
-                      const base::Closure& quit_closure) {
+                      const base::Closure& quit_closure,
+                      SbTimeMonotonic timestamp) {
   if (CheckForAndExecuteStartupSwitches()) {
     SbSystemRequestStop(0);
     return;
@@ -89,15 +92,17 @@
 #if SB_API_VERSION >= 13
   DCHECK(!g_application);
   g_application =
-      new cobalt::browser::Application(quit_closure, false /*not_preload*/);
+      new cobalt::browser::Application(quit_closure, false /*not_preload*/,
+                                       timestamp);
   DCHECK(g_application);
 #else
   if (!g_application) {
     g_application = new cobalt::browser::Application(quit_closure,
-                                                     false /*should_preload*/);
+                                                     false /*should_preload*/,
+                                                     timestamp);
     DCHECK(g_application);
   } else {
-    g_application->Start();
+    g_application->Start(timestamp);
   }
 #endif  // SB_API_VERSION >= 13
 }
diff --git a/src/cobalt/webdriver/testdata/simple_test.py b/src/cobalt/webdriver/testdata/simple_test.py
index d470c61..bf532b0 100755
--- a/src/cobalt/webdriver/testdata/simple_test.py
+++ b/src/cobalt/webdriver/testdata/simple_test.py
@@ -276,9 +276,41 @@
   DeleteSession(session_id)
 
 
+def ElementUniqueTest():
+  # Do a simple test that keeps running as long as the element IDs stay the
+  # same.
+  session_id = GetSessionID()
+  try:
+    initial_active_element = GetActiveElement(session_id)
+    print('initial active_element : %s' % initial_active_element)
+
+    initial_selected_element = ElementFind(session_id, 'class name',
+                                           'ytlr-tile-renderer--focused')
+    print('Selected List element : %s' % initial_selected_element)
+    while True:
+      active_element = GetActiveElement(session_id)
+      print('active_element : %s' % active_element)
+
+      if initial_active_element != active_element:
+        break
+
+      selected_element = ElementFind(session_id, 'class name',
+                                     'ytlr-tile-renderer--focused')
+      print('Selected List element : %s' % selected_element)
+
+      if initial_selected_element != selected_element:
+        break
+
+      time.sleep(1)
+
+  except KeyboardInterrupt:
+    print('Bye')
+
+
 def main():
   MouseTest()
   ElementScreenShotTest()
+  # ElementUniqueTest()
 
 
 if __name__ == '__main__':
diff --git a/src/cobalt/webdriver/window_driver.cc b/src/cobalt/webdriver/window_driver.cc
index 79085d1..6a33518 100644
--- a/src/cobalt/webdriver/window_driver.cc
+++ b/src/cobalt/webdriver/window_driver.cc
@@ -399,6 +399,14 @@
 protocol::ElementId WindowDriver::ElementToId(
     const scoped_refptr<dom::Element>& element) {
   DCHECK_EQ(base::MessageLoop::current()->task_runner(), window_task_runner_);
+  for (auto i : element_drivers_) {
+    // Note: The element_task_runner_ is the same as the window_task_runner_.
+    auto weak_element = i.second->GetWeakElement();
+    if (element == weak_element) {
+      return i.second->element_id();
+    }
+  }
+
   return CreateNewElementDriver(base::AsWeakPtr(element.get()));
 }
 
diff --git a/src/requirements.txt b/src/requirements.txt
index e9215ea..b666306 100644
--- a/src/requirements.txt
+++ b/src/requirements.txt
@@ -2,3 +2,4 @@
 pre-commit==2.6.0
 pylint==2.6.0
 yapf==0.30.0
+requests==2.25.1
diff --git a/src/starboard/android/apk/build.id b/src/starboard/android/apk/build.id
deleted file mode 100644
index 85e1550..0000000
--- a/src/starboard/android/apk/build.id
+++ /dev/null
@@ -1 +0,0 @@
-302995
\ No newline at end of file
diff --git a/src/starboard/build/config/base_configuration.gni b/src/starboard/build/config/base_configuration.gni
index 3b798ea..8a80d04 100644
--- a/src/starboard/build/config/base_configuration.gni
+++ b/src/starboard/build/config/base_configuration.gni
@@ -21,7 +21,7 @@
 
   # The Starboard API version of the current build configuration. The default
   # value is meant to be overridden by a Starboard ABI file.
-  sb_api_version = 13
+  sb_api_version = 14
 
   # Enabling this variable enables pedantic levels of warnings for the current
   # toolchain.
diff --git a/src/starboard/client_porting/poem/stdio_leaks_poem.h b/src/starboard/client_porting/poem/stdio_leaks_poem.h
deleted file mode 100644
index 12369d1..0000000
--- a/src/starboard/client_porting/poem/stdio_leaks_poem.h
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright 2019 The Cobalt Authors. All Rights Reserved.
-//
-// 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.
-
-// This header plugs in the leaks of stdio functions called as std::<function>
-// and __builtin_<function>.
-
-// IMPORTANT: This header has to be included as the very first header in a file,
-// because the order of the included headers and redefininitions matter.
-
-// In this header, it includes <cstdio> at the very beginning, so that the
-// attempts to include <cstdio> afterward are omitted. Then we define a function
-// in the std namespace that has the name of the Starboard counterpart of the
-// function to be plugged, and redirect it to the Starboard counterpart in the
-// global namespace. In this way, the calls to std::<function> will be replaced
-// with std::<SbCounterpart>, and redirected to ::<SbCounterpart>. With this
-// specific order of included headers and redefininitions, it's guaranteed that
-// the calls of the functions afterward are cleanly plugged.
-
-#ifndef STARBOARD_CLIENT_PORTING_POEM_STDIO_LEAKS_POEM_H_
-#define STARBOARD_CLIENT_PORTING_POEM_STDIO_LEAKS_POEM_H_
-
-#if defined(STARBOARD)
-
-#include <cstdio>
-
-#include "starboard/common/string.h"
-
-namespace std {
-
-inline int SbStringFormat(char* buffer,
-                          size_t size,
-                          const char* format,
-                          va_list arguments) {
-  return ::SbStringFormat(buffer, size, format, arguments);
-}
-
-}  // namespace std
-
-#undef __builtin_vsnprintf
-#define __builtin_vsnprintf SbStringFormat
-#undef vsnprintf
-#define vsnprintf SbStringFormat
-
-#endif  // STARBOARD
-
-#endif  // STARBOARD_CLIENT_PORTING_POEM_STDIO_LEAKS_POEM_H_
diff --git a/src/starboard/client_porting/walk_dir.py b/src/starboard/client_porting/walk_dir.py
index 4e18e0c..c1f8d70 100644
--- a/src/starboard/client_porting/walk_dir.py
+++ b/src/starboard/client_porting/walk_dir.py
@@ -121,8 +121,6 @@
 """
 
 SB_CHARACTER_REPLACEMENT_DICT = {
-    'isdigit': 'SbCharacterIsDigit',
-    'isspace': 'SbCharacterIsSpace',
 }
 
 SB_MEMORY_REPLACEMENT_DICT = {
@@ -132,7 +130,6 @@
 }
 
 SB_STRING_REPLACEMENT_DICT = {
-    'atoi': 'SbStringAToI',
 }
 
 c_function_list = []
diff --git a/src/starboard/evergreen/testing/run_all_tests.sh b/src/starboard/evergreen/testing/run_all_tests.sh
index 9114777..c59ef84 100755
--- a/src/starboard/evergreen/testing/run_all_tests.sh
+++ b/src/starboard/evergreen/testing/run_all_tests.sh
@@ -47,8 +47,9 @@
 
   log "info" " [ RUN      ] ${TEST_NAME}"
 
-  # Temporarily disable all tests until Omaha config handles SB14.
-  RESULT=2
+  run_test
+
+  RESULT=$?
 
   if [[ "${RESULT}" -eq 0 ]]; then
     log "info"  " [   PASSED ] ${TEST_NAME}"
diff --git a/src/third_party/angle/src/common/angleutils.cpp b/src/third_party/angle/src/common/angleutils.cpp
index ab6b4dd..ad95da3 100644
--- a/src/third_party/angle/src/common/angleutils.cpp
+++ b/src/third_party/angle/src/common/angleutils.cpp
@@ -13,7 +13,7 @@
 #include <vector>
 
 #if defined(STARBOARD)
-#include "starboard/client_porting/poem/stdio_leaks_poem.h"
+#include "starboard/client_porting/poem/string_poem.h"
 #endif
 
 namespace angle
diff --git a/src/third_party/skia/modules/skottie/src/Skottie.cpp b/src/third_party/skia/modules/skottie/src/Skottie.cpp
index 55052e3..b8ea15f 100644
--- a/src/third_party/skia/modules/skottie/src/Skottie.cpp
+++ b/src/third_party/skia/modules/skottie/src/Skottie.cpp
@@ -37,7 +37,7 @@
 #include "stdlib.h"
 
 #if defined(STARBOARD)
-#include "starboard/client_porting/poem/stdio_leaks_poem.h"
+#include "starboard/client_porting/poem/string_poem.h"
 #endif
 
 namespace skottie {
diff --git a/src/third_party/skia/src/sksl/SkSLCPPCodeGenerator.cpp b/src/third_party/skia/src/sksl/SkSLCPPCodeGenerator.cpp
index 04b4fe8..b59810f 100644
--- a/src/third_party/skia/src/sksl/SkSLCPPCodeGenerator.cpp
+++ b/src/third_party/skia/src/sksl/SkSLCPPCodeGenerator.cpp
@@ -14,7 +14,7 @@
 #include <algorithm>
 
 #if defined(STARBOARD)
-#include "starboard/client_porting/poem/stdio_leaks_poem.h"
+#include "starboard/client_porting/poem/string_poem.h"
 #include "starboard/common/log.h"
 #endif
 
diff --git a/src/third_party/skia/src/sksl/SkSLHCodeGenerator.cpp b/src/third_party/skia/src/sksl/SkSLHCodeGenerator.cpp
index ebaf5d3..4b56937 100644
--- a/src/third_party/skia/src/sksl/SkSLHCodeGenerator.cpp
+++ b/src/third_party/skia/src/sksl/SkSLHCodeGenerator.cpp
@@ -18,7 +18,7 @@
 #include <set>
 
 #if defined(STARBOARD)
-#include "starboard/client_porting/poem/stdio_leaks_poem.h"
+#include "starboard/client_porting/poem/string_poem.h"
 #endif
 
 namespace SkSL {
diff --git a/src/third_party/skia/src/sksl/SkSLString.cpp b/src/third_party/skia/src/sksl/SkSLString.cpp
index bb9855d..5cabe9f 100644
--- a/src/third_party/skia/src/sksl/SkSLString.cpp
+++ b/src/third_party/skia/src/sksl/SkSLString.cpp
@@ -17,7 +17,7 @@
 #include <string>
 
 #if defined(STARBOARD)
-#include "starboard/client_porting/poem/stdio_leaks_poem.h"
+#include "starboard/client_porting/poem/string_poem.h"
 #endif
 
 namespace SkSL {
diff --git a/src/third_party/skia/src/utils/SkJSONWriter.cpp b/src/third_party/skia/src/utils/SkJSONWriter.cpp
index d5a5208..f608113 100644
--- a/src/third_party/skia/src/utils/SkJSONWriter.cpp
+++ b/src/third_party/skia/src/utils/SkJSONWriter.cpp
@@ -16,7 +16,7 @@
 #include "src/utils/SkJSONWriter.h"
 
 #if defined(STARBOARD)
-#include "starboard/client_porting/poem/stdio_leaks_poem.h"
+#include "starboard/client_porting/poem/string_poem.h"
 #endif
 
 void SkJSONWriter::appendS64(int64_t value) {
diff --git a/src/third_party/v8/src/ic/ic.cc b/src/third_party/v8/src/ic/ic.cc
index 1eeff83..2a46a75 100644
--- a/src/third_party/v8/src/ic/ic.cc
+++ b/src/third_party/v8/src/ic/ic.cc
@@ -2,10 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#if defined(V8_OS_STARBOARD)
-#include "starboard/client_porting/poem/stdio_leaks_poem.h"
-#endif
-
 #include "src/ic/ic.h"
 
 #include "src/api/api-arguments-inl.h"
diff --git a/src/third_party/v8/src/parsing/parser.cc b/src/third_party/v8/src/parsing/parser.cc
index 3e2f747..c65c1dc 100644
--- a/src/third_party/v8/src/parsing/parser.cc
+++ b/src/third_party/v8/src/parsing/parser.cc
@@ -2,10 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#if defined(V8_OS_STARBOARD)
-#include "starboard/client_porting/poem/stdio_leaks_poem.h"
-#endif
-
 #include "src/parsing/parser.h"
 
 #include <algorithm>
diff --git a/src/third_party/v8/src/parsing/preparser.cc b/src/third_party/v8/src/parsing/preparser.cc
index dcf1f4a..2764e00 100644
--- a/src/third_party/v8/src/parsing/preparser.cc
+++ b/src/third_party/v8/src/parsing/preparser.cc
@@ -2,10 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#if defined(V8_OS_STARBOARD)
-#include "starboard/client_porting/poem/stdio_leaks_poem.h"
-#endif
-
 #include <cmath>
 
 #include "src/base/logging.h"
diff --git a/src/third_party/v8/src/tracing/traced-value.cc b/src/third_party/v8/src/tracing/traced-value.cc
index a381223..bc5398a 100644
--- a/src/third_party/v8/src/tracing/traced-value.cc
+++ b/src/third_party/v8/src/tracing/traced-value.cc
@@ -2,10 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#if defined(V8_OS_STARBOARD)
-#include "starboard/client_porting/poem/stdio_leaks_poem.h"
-#endif
-
 #include "src/tracing/traced-value.h"
 
 #include "src/base/platform/platform.h"