Import Cobalt 9.174384

Change-Id: I66ce364c297afdd454e8db4e2d947f070dbf2f8b
diff --git a/src/base/message_pump_io_starboard.cc b/src/base/message_pump_io_starboard.cc
index e08ddb8..bb1b1de 100644
--- a/src/base/message_pump_io_starboard.cc
+++ b/src/base/message_pump_io_starboard.cc
@@ -28,7 +28,8 @@
 namespace base {
 
 MessagePumpIOStarboard::SocketWatcher::SocketWatcher()
-    : socket_(kSbSocketInvalid),
+    : interests_(kSbSocketWaiterInterestNone),
+      socket_(kSbSocketInvalid),
       pump_(NULL),
       watcher_(NULL),
       ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) {}
@@ -48,6 +49,7 @@
   }
   pump_ = NULL;
   watcher_ = NULL;
+  interests_ = kSbSocketWaiterInterestNone;
   return result;
 }
 
@@ -147,6 +149,7 @@
   controller->Init(socket, persistent);
   controller->set_watcher(delegate);
   controller->set_pump(this);
+  controller->set_interests(interests);
 
   return true;
 }
diff --git a/src/base/message_pump_io_starboard.h b/src/base/message_pump_io_starboard.h
index c840181..028115f 100644
--- a/src/base/message_pump_io_starboard.h
+++ b/src/base/message_pump_io_starboard.h
@@ -83,6 +83,7 @@
     SbSocket Release();
 
     int interests() const { return interests_; }
+    void set_interests(int interests) { interests_ = interests; }
 
     void set_pump(MessagePumpIOStarboard* pump) { pump_ = pump; }
     MessagePumpIOStarboard* pump() const { return pump_; }
diff --git a/src/cobalt/browser/application.h b/src/cobalt/browser/application.h
index e700d83..776d48b 100644
--- a/src/cobalt/browser/application.h
+++ b/src/cobalt/browser/application.h
@@ -143,7 +143,7 @@
     base::CVal<base::cval::SizeInBytes, base::CValPublic> exe_memory;
 #endif
 
-    base::CVal<int64> app_start_time;
+    base::CVal<int64, base::CValPublic> app_start_time;
     base::CVal<base::TimeDelta, base::CValPublic> app_lifetime;
   };
 
diff --git a/src/cobalt/browser/browser_module.h b/src/cobalt/browser/browser_module.h
index 5712937..8e6b08d 100644
--- a/src/cobalt/browser/browser_module.h
+++ b/src/cobalt/browser/browser_module.h
@@ -312,10 +312,10 @@
 
   // The time when a URL navigation starts. This is recorded after the previous
   // WebModule is destroyed.
-  base::CVal<int64> navigate_time_;
+  base::CVal<int64, base::CValPublic> navigate_time_;
 
   // The time when the WebModule's Window.onload event is fired.
-  base::CVal<int64> on_load_event_time_;
+  base::CVal<int64, base::CValPublic> on_load_event_time_;
 
 #if defined(ENABLE_DEBUG_CONSOLE)
   // Possibly null, but if not, will contain a reference to an instance of
diff --git a/src/cobalt/browser/splash_screen.cc b/src/cobalt/browser/splash_screen.cc
index 0ba834c..6df2dbe 100644
--- a/src/cobalt/browser/splash_screen.cc
+++ b/src/cobalt/browser/splash_screen.cc
@@ -22,7 +22,11 @@
 
 // Static
 const char SplashScreen::Options::kDefaultSplashScreenURL[] =
-    "h5vcc-embedded://splash_screen.html";
+#if defined(COBALT_USE_YOUTUBE_SPLASH_SCREEN)
+  "h5vcc-embedded://youtube_splash_screen.html";
+#else
+  "h5vcc-embedded://black_splash_screen.html";
+#endif  // COBALT_USE_YOUTUBE_SPLASH_SCREEN
 
 SplashScreen::SplashScreen(
     const WebModule::OnRenderTreeProducedCallback&
diff --git a/src/cobalt/browser/web_module.cc b/src/cobalt/browser/web_module.cc
index b575c58..3183d8b 100644
--- a/src/cobalt/browser/web_module.cc
+++ b/src/cobalt/browser/web_module.cc
@@ -226,6 +226,9 @@
     }
   }
 
+  void OnStartDispatchEvent(const scoped_refptr<dom::Event>& event);
+  void OnStopDispatchEvent(const scoped_refptr<dom::Event>& event);
+
   // Thread checker ensures all calls to the WebModule are made from the same
   // thread that it is created in.
   base::ThreadChecker thread_checker_;
@@ -499,6 +502,9 @@
       data.window_close_callback, data.window_minimize_callback,
       data.system_window_, data.options.input_poller,
       media_session_client_->GetMediaSession(),
+      base::Bind(&WebModule::Impl::OnStartDispatchEvent,
+                 base::Unretained(this)),
+      base::Bind(&WebModule::Impl::OnStopDispatchEvent, base::Unretained(this)),
       data.options.csp_insecure_allowed_token, data.dom_max_element_depth);
   DCHECK(window_);
 
@@ -614,17 +620,11 @@
   scoped_refptr<dom::KeyboardEvent> keyboard_event(
       new dom::KeyboardEvent(event));
 
-  web_module_stat_tracker_->OnStartInjectEvent(keyboard_event);
-
   if (element) {
     element->DispatchEvent(keyboard_event);
   } else {
     window_->InjectEvent(keyboard_event);
   }
-
-  web_module_stat_tracker_->OnEndInjectEvent(
-      window_->HasPendingAnimationFrameCallbacks(),
-      layout_manager_->IsRenderTreePending());
 }
 
 void WebModule::Impl::ExecuteJavascript(
@@ -753,6 +753,18 @@
   }
 }
 
+void WebModule::Impl::OnStartDispatchEvent(
+    const scoped_refptr<dom::Event>& event) {
+  web_module_stat_tracker_->OnStartDispatchEvent(event);
+}
+
+void WebModule::Impl::OnStopDispatchEvent(
+    const scoped_refptr<dom::Event>& event) {
+  web_module_stat_tracker_->OnStopDispatchEvent(
+      event, window_->HasPendingAnimationFrameCallbacks(),
+      layout_manager_->IsRenderTreePending());
+}
+
 void WebModule::Impl::SuspendLoaders() {
   TRACE_EVENT0("cobalt::browser", "WebModule::Impl::SuspendLoaders()");
 
diff --git a/src/cobalt/browser/web_module_stat_tracker.cc b/src/cobalt/browser/web_module_stat_tracker.cc
index 4151969..28905c9 100644
--- a/src/cobalt/browser/web_module_stat_tracker.cc
+++ b/src/cobalt/browser/web_module_stat_tracker.cc
@@ -34,6 +34,7 @@
       layout_stat_tracker_(new layout::LayoutStatTracker(name)),
       should_track_event_stats_(should_track_event_stats),
       current_event_type_(kEventTypeInvalid),
+      current_event_dispatched_event_(NULL),
       name_(name),
       event_is_processing_(StringPrintf("Event.%s.IsProcessing", name.c_str()),
                            false, "Nonzero when an event is being processed.") {
@@ -56,7 +57,7 @@
 
 WebModuleStatTracker::~WebModuleStatTracker() { EndCurrentEvent(false); }
 
-void WebModuleStatTracker::OnStartInjectEvent(
+void WebModuleStatTracker::OnStartDispatchEvent(
     const scoped_refptr<dom::Event>& event) {
   if (!should_track_event_stats_) {
     return;
@@ -81,28 +82,30 @@
   if (current_event_type_ != kEventTypeInvalid) {
     event_is_processing_ = true;
     event_start_time_ = base::TimeTicks::Now();
+    current_event_dispatched_event_ = event;
 
     dom_stat_tracker_->OnStartEvent();
     layout_stat_tracker_->OnStartEvent();
 
     stop_watch_durations_[kStopWatchTypeEvent] = base::TimeDelta();
-    stop_watch_durations_[kStopWatchTypeInjectEvent] = base::TimeDelta();
+    stop_watch_durations_[kStopWatchTypeDispatchEvent] = base::TimeDelta();
 
     stop_watches_[kStopWatchTypeEvent].Start();
-    stop_watches_[kStopWatchTypeInjectEvent].Start();
+    stop_watches_[kStopWatchTypeDispatchEvent].Start();
   }
 }
 
-void WebModuleStatTracker::OnEndInjectEvent(
+void WebModuleStatTracker::OnStopDispatchEvent(
+    const scoped_refptr<dom::Event>& event,
     bool are_animation_frame_callbacks_pending,
     bool is_new_render_tree_pending) {
-  // If the injection isn't currently being timed, then this event injection
-  // isn't being tracked. Simply return.
-  if (!stop_watches_[kStopWatchTypeInjectEvent].IsCounting()) {
+  // Verify that this dispatched event is the one currently being tracked.
+  if (event != current_event_dispatched_event_) {
     return;
   }
 
-  stop_watches_[kStopWatchTypeInjectEvent].Stop();
+  current_event_dispatched_event_ = NULL;
+  stop_watches_[kStopWatchTypeDispatchEvent].Stop();
 
   if (!are_animation_frame_callbacks_pending && !is_new_render_tree_pending) {
     EndCurrentEvent(false);
@@ -119,7 +122,9 @@
 void WebModuleStatTracker::OnRenderTreeProduced() { EndCurrentEvent(true); }
 
 WebModuleStatTracker::EventStats::EventStats(const std::string& name)
-    : produced_render_tree_(
+    : start_time(StringPrintf("Event.Time.%s.Start", name.c_str()), 0,
+          "The time that the event started."),
+      produced_render_tree(
           StringPrintf("Event.%s.ProducedRenderTree", name.c_str()), false,
           "Nonzero when the event produced a render tree."),
       count_dom_html_elements_created(
@@ -175,12 +180,12 @@
       duration_total(StringPrintf("Event.Duration.%s", name.c_str()),
                      base::TimeDelta(),
                      "Total duration of the event (in microseconds). This is "
-                     "the time elapsed from the event injection until the "
+                     "the time elapsed from the event dispatch until the "
                      "render tree is produced."),
-      duration_dom_inject_event(
-          StringPrintf("Event.Duration.%s.DOM.InjectEvent", name.c_str()),
+      duration_dom_dispatch_event(
+          StringPrintf("Event.Duration.%s.DOM.DispatchEvent", name.c_str()),
           base::TimeDelta(),
-          "Injection duration, which includes JS, for event (in "
+          "Dispatch duration, which includes JS, for event (in "
           "microseconds). This does not include subsequent DOM and Layout "
           "processing."),
       duration_dom_run_animation_frame_callbacks(
@@ -242,7 +247,8 @@
   stop_watches_[kStopWatchTypeEvent].Stop();
 
   EventStats* event_stats = event_stats_[current_event_type_];
-  event_stats->produced_render_tree_ = was_render_tree_produced;
+  event_stats->start_time = event_start_time_.ToInternalValue();
+  event_stats->produced_render_tree = was_render_tree_produced;
 
   // Update event counts
   event_stats->count_dom_html_elements_created =
@@ -274,8 +280,8 @@
 
   // Update event durations
   event_stats->duration_total = stop_watch_durations_[kStopWatchTypeEvent];
-  event_stats->duration_dom_inject_event =
-      stop_watch_durations_[kStopWatchTypeInjectEvent];
+  event_stats->duration_dom_dispatch_event =
+      stop_watch_durations_[kStopWatchTypeDispatchEvent];
   event_stats->duration_dom_run_animation_frame_callbacks =
       dom_stat_tracker_->GetStopWatchTypeDuration(
           dom::DomStatTracker::kStopWatchTypeRunAnimationFrameCallbacks);
@@ -345,7 +351,7 @@
       << "\"DurTotalUs\":"
       << stop_watch_durations_[kStopWatchTypeEvent].InMicroseconds() << ", "
       << "\"DurDomInjectEventUs\":"
-      << stop_watch_durations_[kStopWatchTypeInjectEvent].InMicroseconds()
+      << stop_watch_durations_[kStopWatchTypeDispatchEvent].InMicroseconds()
       << ", "
       << "\"DurDomRunAnimationFrameCallbacksUs\":"
       << dom_stat_tracker_
diff --git a/src/cobalt/browser/web_module_stat_tracker.h b/src/cobalt/browser/web_module_stat_tracker.h
index 08ae658..5417e06 100644
--- a/src/cobalt/browser/web_module_stat_tracker.h
+++ b/src/cobalt/browser/web_module_stat_tracker.h
@@ -34,7 +34,7 @@
 class WebModuleStatTracker : public base::StopWatchOwner {
  public:
   WebModuleStatTracker(const std::string& name,
-                       bool should_track_injected_events);
+                       bool should_track_dispatched_events);
   ~WebModuleStatTracker();
 
   dom::DomStatTracker* dom_stat_tracker() const {
@@ -45,15 +45,16 @@
     return layout_stat_tracker_.get();
   }
 
-  // |OnStartInjectEvent| starts event stat tracking if
-  // |should_track_injected_events_| is true. Otherwise, it does nothing.
-  void OnStartInjectEvent(const scoped_refptr<dom::Event>& event);
+  // |OnStartDispatchEvent| starts event stat tracking if
+  // |should_track_dispatched_events_| is true. Otherwise, it does nothing.
+  void OnStartDispatchEvent(const scoped_refptr<dom::Event>& event);
 
-  // |OnEndInjectEvent| notifies the event stat tracking that the event has
-  // finished being injected. If no animation frame callbacks and also no render
-  // tree is pending, it also ends tracking of the event.
-  void OnEndInjectEvent(bool are_animation_frame_callbacks_pending,
-                        bool is_new_render_tree_pending);
+  // |OnStopDispatchEvent| notifies the event stat tracking that |event| has
+  // finished being dispatched. If this is the event currently being tracked
+  // and nothing is pending, then it also ends tracking of the event.
+  void OnStopDispatchEvent(const scoped_refptr<dom::Event>& event,
+                           bool are_animation_frame_callbacks_pending,
+                           bool is_new_render_tree_pending);
 
   // |OnRanAnimationFrameCallbacks| ends stat tracking for the current event
   // if no render tree is pending.
@@ -72,14 +73,15 @@
 
   enum StopWatchType {
     kStopWatchTypeEvent,
-    kStopWatchTypeInjectEvent,
+    kStopWatchTypeDispatchEvent,
     kNumStopWatchTypes,
   };
 
   struct EventStats {
     explicit EventStats(const std::string& name);
 
-    base::CVal<bool, base::CValPublic> produced_render_tree_;
+    base::CVal<int64, base::CValPublic> start_time;
+    base::CVal<bool, base::CValPublic> produced_render_tree;
 
     // Count-related
     base::CVal<int, base::CValPublic> count_dom_html_elements_created;
@@ -100,7 +102,7 @@
 
     // Duration-related
     base::CVal<base::TimeDelta, base::CValPublic> duration_total;
-    base::CVal<base::TimeDelta, base::CValPublic> duration_dom_inject_event;
+    base::CVal<base::TimeDelta, base::CValPublic> duration_dom_dispatch_event;
     base::CVal<base::TimeDelta, base::CValPublic>
         duration_dom_run_animation_frame_callbacks;
     base::CVal<base::TimeDelta, base::CValPublic>
@@ -138,6 +140,10 @@
   // Event-related
   const bool should_track_event_stats_;
   EventType current_event_type_;
+  // Raw pointer to the current event. This is used to verify that the event in
+  // |OnStopDispatchEvent| is the dispatched event being tracked.
+  dom::Event* current_event_dispatched_event_;
+
   // Each individual |EventType| has its own entry in the vector.
   ScopedVector<EventStats> event_stats_;
 
diff --git a/src/cobalt/build/build.id b/src/cobalt/build/build.id
index 2f807b4..c10f57f 100644
--- a/src/cobalt/build/build.id
+++ b/src/cobalt/build/build.id
@@ -1 +1 @@
-140119
\ No newline at end of file
+174384
\ No newline at end of file
diff --git a/src/cobalt/build/config/base.gypi b/src/cobalt/build/config/base.gypi
index da47e25..3cdcb28 100644
--- a/src/cobalt/build/config/base.gypi
+++ b/src/cobalt/build/config/base.gypi
@@ -429,6 +429,17 @@
     # re-download video data.  Note that the JavaScript app may experience
     # significant difficulty if this value is too low.
     'cobalt_media_buffer_video_budget_4k%': 60 * 1024 * 1024,
+
+    # Specifies the duration threshold of media source garbage collection.  When
+    # the accumulated duration in a source buffer exceeds this value, the media
+    # source implementation will try to eject existing buffers from the cache.
+    # This is usually triggered when the video being played has a simple content
+    # and the encoded data is small.  In such case this can limit how much is
+    # allocated for the book keeping data of the media buffers and avoid OOM of
+    # system heap.
+    # This should be set to 170 for most of the platforms.  But it can be
+    # further reduced on systems with extremely low memory.
+    'cobalt_media_source_garbage_collection_duration_threshold_in_seconds%': 170,
   },
 
   'target_defaults': {
@@ -451,6 +462,7 @@
       'COBALT_MEDIA_BUFFER_VIDEO_BUDGET_4K=<(cobalt_media_buffer_video_budget_4k)',
       'COBALT_MEDIA_BUFFER_INITIAL_CAPACITY=<(cobalt_media_buffer_initial_capacity)',
       'COBALT_MEDIA_BUFFER_ALLOCATION_UNIT=<(cobalt_media_buffer_allocation_unit)',
+      'COBALT_MEDIA_SOURCE_GARBAGE_COLLECTION_DURATION_THRESHOLD_IN_SECONDS=<(cobalt_media_source_garbage_collection_duration_threshold_in_seconds)',
     ],
     'cflags': [ '<@(compiler_flags)' ],
     'ldflags': [ '<@(linker_flags)' ],
diff --git a/src/cobalt/build/copy_icu_data.gypi b/src/cobalt/build/copy_icu_data.gypi
index c2bfac3..9b9ba27 100644
--- a/src/cobalt/build/copy_icu_data.gypi
+++ b/src/cobalt/build/copy_icu_data.gypi
@@ -39,15 +39,21 @@
         'little_endian%': '<(little_endian)',
         'use_icu_dat_file%': '<(use_icu_dat_file)',
       },
+      'little_endian%': '<(little_endian)',
     },
 
-    #'inputs_icu%': [ '<(inputs_icu)' ],
-    'inputs_icu%': [ '<(static_contents_source_dir)/icu/' ],
+    'conditions': [
+      ['little_endian==1', {
+        'inputs_icu%': [ '<(static_contents_source_dir)/icu/icudt56l' ],
+      }, {
+        'inputs_icu%': [ '<(static_contents_source_dir)/icu/icudt56b' ],
+      }],
+    ],
   },
 
   'copies': [
     {
-      'destination': '<(static_contents_output_data_dir)/',
+      'destination': '<(static_contents_output_data_dir)/icu/',
       'files': [ '<(inputs_icu)' ],
     },
   ],
diff --git a/src/cobalt/cssom/css_declared_style_data.h b/src/cobalt/cssom/css_declared_style_data.h
index 0ac19c7..3263fa2 100644
--- a/src/cobalt/cssom/css_declared_style_data.h
+++ b/src/cobalt/cssom/css_declared_style_data.h
@@ -17,10 +17,11 @@
 
 #include <bitset>
 #include <functional>
+#include <map>
 #include <string>
 
 #include "base/compiler_specific.h"
-#include "base/hash_tables.h"
+#include "base/containers/small_map.h"
 #include "base/memory/ref_counted.h"
 #include "cobalt/base/unused.h"
 #include "cobalt/cssom/css_declaration_data.h"
@@ -36,7 +37,10 @@
  public:
   CSSDeclaredStyleData();
 
-  typedef base::hash_map<PropertyKey, scoped_refptr<PropertyValue> >
+  // NOTE: The array size of base::SmallMap is based on extensive testing. Do
+  // not change it unless additional profiling data justifies it.
+  typedef base::SmallMap<std::map<PropertyKey, scoped_refptr<PropertyValue> >,
+                         8, std::equal_to<PropertyKey> >
       PropertyValues;
 
   // The length attribute must return the number of CSS declarations in the
diff --git a/src/cobalt/debug/debug_web_server.cc b/src/cobalt/debug/debug_web_server.cc
index 6ffd152..84e3885 100644
--- a/src/cobalt/debug/debug_web_server.cc
+++ b/src/cobalt/debug/debug_web_server.cc
@@ -188,6 +188,11 @@
 
   // Construct the local disk path corresponding to the request path.
   FilePath file_path(content_root_dir_);
+  if (!IsStringASCII(url_path)) {
+    LOG(WARNING) << "Got HTTP request with non-ASCII URL path.";
+    server_->Send404(connection_id);
+    return;
+  }
   file_path = file_path.AppendASCII(url_path);
 
   // If the disk path is a directory, look for an index file.
diff --git a/src/cobalt/dom/dom_stat_tracker.h b/src/cobalt/dom/dom_stat_tracker.h
index 35cedb7..e967385 100644
--- a/src/cobalt/dom/dom_stat_tracker.h
+++ b/src/cobalt/dom/dom_stat_tracker.h
@@ -104,11 +104,11 @@
 
   // Tracking of videos produced by an event.
   base::StopWatch event_video_start_delay_stop_watch_;
-  base::CVal<base::TimeDelta> event_video_start_delay_;
+  base::CVal<base::TimeDelta, base::CValPublic> event_video_start_delay_;
 
   // Count of HtmlScriptElement::Execute() calls and time of last call.
-  base::CVal<int> script_element_execute_count_;
-  base::CVal<int64> script_element_execute_time_;
+  base::CVal<int, base::CValPublic> script_element_execute_count_;
+  base::CVal<int64, base::CValPublic> script_element_execute_time_;
 
   // Periodic counts. The counts are cleared after the CVals are updated in
   // |FlushPeriodicTracking|.
diff --git a/src/cobalt/dom/html_link_element.cc b/src/cobalt/dom/html_link_element.cc
index ade761c..52285ae 100644
--- a/src/cobalt/dom/html_link_element.cc
+++ b/src/cobalt/dom/html_link_element.cc
@@ -106,25 +106,19 @@
   document->IncreaseLoadingCounter();
 }
 
-void HTMLLinkElement::OnLoadingDone(const std::string& content) {
-  TRACK_MEMORY_SCOPE("DOM");
+void HTMLLinkElement::OnLoadingDone(scoped_ptr<std::string> content) {
   DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK(content);
+  TRACK_MEMORY_SCOPE("DOM");
   TRACE_EVENT0("cobalt::dom", "HTMLLinkElement::OnLoadingDone()");
 
   Document* document = node_document();
   scoped_refptr<cssom::CSSStyleSheet> style_sheet =
       document->html_element_context()->css_parser()->ParseStyleSheet(
-          content, base::SourceLocation(href(), 1, 1));
+          *content, base::SourceLocation(href(), 1, 1));
   style_sheet->SetLocationUrl(absolute_url_);
   document->style_sheets()->Append(style_sheet);
 
-  // Once the attempts to obtain the resource and its critical subresources are
-  // complete, the user agent must, if the loads were successful, queue a task
-  // to fire a simple event named load at the link element, or, if the resource
-  // or one of its critical subresources failed to completely load for any
-  // reason (e.g. DNS error, HTTP 404 response, a connection being prematurely
-  // closed, unsupported Content-Type), queue a task to fire a simple event
-  // named error at the link element.
   PostToDispatchEvent(FROM_HERE, base::Tokens::load());
 
   // The element must delay the load event of the element's document until all
diff --git a/src/cobalt/dom/html_link_element.h b/src/cobalt/dom/html_link_element.h
index 6f2e021..18860a8 100644
--- a/src/cobalt/dom/html_link_element.h
+++ b/src/cobalt/dom/html_link_element.h
@@ -66,7 +66,7 @@
   // From the spec: HTMLLinkElement.
   void Obtain();
 
-  void OnLoadingDone(const std::string& content);
+  void OnLoadingDone(scoped_ptr<std::string> content);
   void OnLoadingError(const std::string& error);
   void ReleaseLoader();
 
diff --git a/src/cobalt/dom/html_media_element.cc b/src/cobalt/dom/html_media_element.cc
index 0dbebf1..70a3f3f 100644
--- a/src/cobalt/dom/html_media_element.cc
+++ b/src/cobalt/dom/html_media_element.cc
@@ -1573,10 +1573,15 @@
 
   ScheduleOwnEvent(base::Tokens::durationchange());
 
-  float now = current_time(NULL);
-  float dur = duration();
-  if (now > dur) {
-    Seek(dur);
+  double now = current_time(NULL);
+  // Reset and update |duration_|.
+  duration_ = std::numeric_limits<double>::quiet_NaN();
+  if (player_ && ready_state_ >= WebMediaPlayer::kReadyStateHaveMetadata) {
+    duration_ = player_->GetDuration();
+  }
+
+  if (now > duration_) {
+    Seek(static_cast<float>(duration_));
   }
 
   EndProcessingMediaPlayerCallback();
diff --git a/src/cobalt/dom/html_script_element.cc b/src/cobalt/dom/html_script_element.cc
index 9af2bcc..6976ad3 100644
--- a/src/cobalt/dom/html_script_element.cc
+++ b/src/cobalt/dom/html_script_element.cc
@@ -15,6 +15,7 @@
 #include "cobalt/dom/html_script_element.h"
 
 #include <deque>
+#include <utility>
 
 #include "base/bind.h"
 #include "base/compiler_specific.h"
@@ -265,6 +266,8 @@
         PreventGarbageCollection();
         ExecuteExternal();
         AllowGarbageCollection();
+        // Release the content string now that we're finished with it.
+        content_.reset();
       } else {
         // Executing the script block must just consist of firing a simple event
         // named error at the element.
@@ -346,9 +349,9 @@
   }
 }
 
-void HTMLScriptElement::OnSyncLoadingDone(const std::string& content) {
+void HTMLScriptElement::OnSyncLoadingDone(scoped_ptr<std::string> content) {
   TRACE_EVENT0("cobalt::dom", "HTMLScriptElement::OnSyncLoadingDone()");
-  content_ = content;
+  content_ = content.Pass();
   is_sync_load_successful_ = true;
 }
 
@@ -359,16 +362,18 @@
 
 // Algorithm for OnLoadingDone:
 //   https://www.w3.org/TR/html5/scripting-1.html#prepare-a-script
-void HTMLScriptElement::OnLoadingDone(const std::string& content) {
+void HTMLScriptElement::OnLoadingDone(scoped_ptr<std::string> content) {
   DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(load_option_ == 4 || load_option_ == 5);
+  DCHECK(content);
   TRACE_EVENT0("cobalt::dom", "HTMLScriptElement::OnLoadingDone()");
   if (!document_) {
     AllowGarbageCollection();
     return;
   }
 
-  content_ = content;
+  content_ = content.Pass();
+
   switch (load_option_) {
     case 4: {
       // If the element has a src attribute, does not have an async attribute,
@@ -445,6 +450,13 @@
       document_->DecreaseLoadingCounterAndMaybeDispatchLoadEvent();
     } break;
   }
+
+  // Release the content string now that we're finished with it.
+  content_.reset();
+
+  // Post a task to release the loader.
+  MessageLoop::current()->PostTask(
+      FROM_HERE, base::Bind(&HTMLScriptElement::ReleaseLoader, this));
 }
 
 // Algorithm for OnLoadingError:
@@ -489,6 +501,19 @@
   // document until the task that is queued by the networking task source
   // once the resource has been fetched (defined above) has been run.
   document_->DecreaseLoadingCounterAndMaybeDispatchLoadEvent();
+
+  // Post a task to release the loader.
+  MessageLoop::current()->PostTask(
+      FROM_HERE, base::Bind(&HTMLScriptElement::ReleaseLoader, this));
+}
+
+void HTMLScriptElement::ExecuteExternal() {
+  DCHECK(content_);
+  Execute(*content_, base::SourceLocation(url_.spec(), 1, 1), true);
+}
+
+void HTMLScriptElement::ExecuteInternal() {
+  Execute(text_content().value(), inline_script_location_, false);
 }
 
 // Algorithm for Execute:
@@ -584,5 +609,11 @@
   }
 }
 
+void HTMLScriptElement::ReleaseLoader() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK(loader_);
+  loader_.reset();
+}
+
 }  // namespace dom
 }  // namespace cobalt
diff --git a/src/cobalt/dom/html_script_element.h b/src/cobalt/dom/html_script_element.h
index 8307158..d121d34 100644
--- a/src/cobalt/dom/html_script_element.h
+++ b/src/cobalt/dom/html_script_element.h
@@ -89,18 +89,14 @@
   //
   void Prepare();
 
-  void OnSyncLoadingDone(const std::string& content);
+  void OnSyncLoadingDone(scoped_ptr<std::string> content);
   void OnSyncLoadingError(const std::string& error);
 
-  void OnLoadingDone(const std::string& content);
+  void OnLoadingDone(scoped_ptr<std::string> content);
   void OnLoadingError(const std::string& error);
 
-  void ExecuteExternal() {
-    Execute(content_, base::SourceLocation(url_.spec(), 1, 1), true);
-  }
-  void ExecuteInternal() {
-    Execute(text_content().value(), inline_script_location_, false);
-  }
+  void ExecuteExternal();
+  void ExecuteInternal();
   void Execute(const std::string& content,
                const base::SourceLocation& script_location, bool is_external);
 
@@ -108,6 +104,7 @@
       const tracked_objects::Location& location, const base::Token& token);
   void PreventGarbageCollection();
   void AllowGarbageCollection();
+  void ReleaseLoader();
 
   // Whether the script has been started.
   bool is_already_started_;
@@ -131,8 +128,8 @@
   bool is_sync_load_successful_;
   // Resolved URL of the script.
   GURL url_;
-  // Content of the script.
-  std::string content_;
+  // Content of the script. Released after Execute is called.
+  scoped_ptr<std::string> content_;
   // Active requests disabling garbage collection.
   int prevent_garbage_collection_count_;
 
diff --git a/src/cobalt/dom/node.cc b/src/cobalt/dom/node.cc
index 6b15337..dc553cd 100644
--- a/src/cobalt/dom/node.cc
+++ b/src/cobalt/dom/node.cc
@@ -36,6 +36,7 @@
 #include "cobalt/dom/node_list_live.h"
 #include "cobalt/dom/rule_matching.h"
 #include "cobalt/dom/text.h"
+#include "cobalt/dom/window.h"
 #if defined(OS_STARBOARD)
 #include "starboard/configuration.h"
 #if SB_HAS(CORE_DUMP_HANDLER_SUPPORT)
@@ -102,6 +103,16 @@
   // The event is now being dispatched. Track it in the global stats.
   GlobalStats::GetInstance()->StartJavaScriptEvent();
 
+  scoped_refptr<Window> window;
+  if (IsInDocument()) {
+    DCHECK(node_document());
+    window = node_document()->default_view();
+  }
+
+  if (window) {
+    window->OnStartDispatchEvent(event);
+  }
+
   typedef std::vector<scoped_refptr<Node> > Ancestors;
   Ancestors ancestors;
   for (scoped_refptr<Node> current = this->parent_node(); current != NULL;
@@ -137,6 +148,10 @@
 
   event->set_event_phase(Event::kNone);
 
+  if (window) {
+    window->OnStopDispatchEvent(event);
+  }
+
   // The event has completed being dispatched. Stop tracking it in the global
   // stats.
   GlobalStats::GetInstance()->StopJavaScriptEvent();
diff --git a/src/cobalt/dom/testing/stub_window.h b/src/cobalt/dom/testing/stub_window.h
index ffe7834..418c7a0 100644
--- a/src/cobalt/dom/testing/stub_window.h
+++ b/src/cobalt/dom/testing/stub_window.h
@@ -63,8 +63,9 @@
         base::Closure() /* csp_policy_changed */,
         base::Closure() /* ran_animation_frame_callbacks */,
         base::Closure() /* window_close */,
-        base::Closure() /* window_minimize */,
-        NULL, NULL, NULL);
+        base::Closure() /* window_minimize */, NULL, NULL, NULL,
+        dom::Window::OnStartDispatchEventCallback(),
+        dom::Window::OnStopDispatchEventCallback());
     global_environment_->CreateGlobalObject(window_, &environment_settings_);
   }
 
diff --git a/src/cobalt/dom/window.cc b/src/cobalt/dom/window.cc
index 89dd4ff..e11ae87 100644
--- a/src/cobalt/dom/window.cc
+++ b/src/cobalt/dom/window.cc
@@ -74,38 +74,41 @@
 const int64_t kPerformanceTimerMinResolutionInMicroseconds = 20;
 }  // namespace
 
-Window::Window(int width, int height, cssom::CSSParser* css_parser,
-               Parser* dom_parser, loader::FetcherFactory* fetcher_factory,
-               render_tree::ResourceProvider** resource_provider,
-               loader::image::AnimatedImageTracker* animated_image_tracker,
-               loader::image::ImageCache* image_cache,
-               loader::image::ReducedCacheCapacityManager*
-                   reduced_image_cache_capacity_manager,
-               loader::font::RemoteTypefaceCache* remote_typeface_cache,
-               loader::mesh::MeshCache* mesh_cache,
-               LocalStorageDatabase* local_storage_database,
-               media::CanPlayTypeHandler* can_play_type_handler,
-               media::WebMediaPlayerFactory* web_media_player_factory,
-               script::ExecutionState* execution_state,
-               script::ScriptRunner* script_runner,
-               script::ScriptValueFactory* script_value_factory,
-               MediaSource::Registry* media_source_registry,
-               DomStatTracker* dom_stat_tracker, const GURL& url,
-               const std::string& user_agent, const std::string& language,
-               const base::Callback<void(const GURL&)> navigation_callback,
-               const base::Callback<void(const std::string&)>& error_callback,
-               network_bridge::CookieJar* cookie_jar,
-               const network_bridge::PostSender& post_sender,
-               const std::string& default_security_policy,
-               CspEnforcementType csp_enforcement_mode,
-               const base::Closure& csp_policy_changed_callback,
-               const base::Closure& ran_animation_frame_callbacks_callback,
-               const base::Closure& window_close_callback,
-               const base::Closure& window_minimize_callback,
-               system_window::SystemWindow* system_window,
-               const scoped_refptr<input::InputPoller>& input_poller,
-               const scoped_refptr<MediaSession>& media_session,
-               int csp_insecure_allowed_token, int dom_max_element_depth)
+Window::Window(
+    int width, int height, cssom::CSSParser* css_parser, Parser* dom_parser,
+    loader::FetcherFactory* fetcher_factory,
+    render_tree::ResourceProvider** resource_provider,
+    loader::image::AnimatedImageTracker* animated_image_tracker,
+    loader::image::ImageCache* image_cache,
+    loader::image::ReducedCacheCapacityManager*
+        reduced_image_cache_capacity_manager,
+    loader::font::RemoteTypefaceCache* remote_typeface_cache,
+    loader::mesh::MeshCache* mesh_cache,
+    LocalStorageDatabase* local_storage_database,
+    media::CanPlayTypeHandler* can_play_type_handler,
+    media::WebMediaPlayerFactory* web_media_player_factory,
+    script::ExecutionState* execution_state,
+    script::ScriptRunner* script_runner,
+    script::ScriptValueFactory* script_value_factory,
+    MediaSource::Registry* media_source_registry,
+    DomStatTracker* dom_stat_tracker, const GURL& url,
+    const std::string& user_agent, const std::string& language,
+    const base::Callback<void(const GURL&)> navigation_callback,
+    const base::Callback<void(const std::string&)>& error_callback,
+    network_bridge::CookieJar* cookie_jar,
+    const network_bridge::PostSender& post_sender,
+    const std::string& default_security_policy,
+    CspEnforcementType csp_enforcement_mode,
+    const base::Closure& csp_policy_changed_callback,
+    const base::Closure& ran_animation_frame_callbacks_callback,
+    const base::Closure& window_close_callback,
+    const base::Closure& window_minimize_callback,
+    system_window::SystemWindow* system_window,
+    const scoped_refptr<input::InputPoller>& input_poller,
+    const scoped_refptr<MediaSession>& media_session,
+    const OnStartDispatchEventCallback& on_start_dispatch_event_callback,
+    const OnStopDispatchEventCallback& on_stop_dispatch_event_callback,
+    int csp_insecure_allowed_token, int dom_max_element_depth)
     : width_(width),
       height_(height),
       html_element_context_(new HTMLElementContext(
@@ -116,8 +119,8 @@
           remote_typeface_cache, mesh_cache, dom_stat_tracker, language)),
       performance_(new Performance(new base::MinimumResolutionClock(
           new base::SystemMonotonicClock(),
-              base::TimeDelta::FromMicroseconds(
-                  kPerformanceTimerMinResolutionInMicroseconds)))),
+          base::TimeDelta::FromMicroseconds(
+              kPerformanceTimerMinResolutionInMicroseconds)))),
       ALLOW_THIS_IN_INITIALIZER_LIST(document_(new Document(
           html_element_context_.get(),
           Document::Options(
@@ -151,7 +154,9 @@
           ran_animation_frame_callbacks_callback),
       window_close_callback_(window_close_callback),
       window_minimize_callback_(window_minimize_callback),
-      system_window_(system_window) {
+      system_window_(system_window),
+      on_start_dispatch_event_callback_(on_start_dispatch_event_callback),
+      on_stop_dispatch_event_callback_(on_stop_dispatch_event_callback) {
 #if defined(ENABLE_TEST_RUNNER)
   test_runner_ = new TestRunner();
 #endif  // ENABLE_TEST_RUNNER
@@ -431,6 +436,18 @@
   document_->set_synchronous_layout_callback(synchronous_layout_callback);
 }
 
+void Window::OnStartDispatchEvent(const scoped_refptr<dom::Event>& event) {
+  if (!on_start_dispatch_event_callback_.is_null()) {
+    on_start_dispatch_event_callback_.Run(event);
+  }
+}
+
+void Window::OnStopDispatchEvent(const scoped_refptr<dom::Event>& event) {
+  if (!on_stop_dispatch_event_callback_.is_null()) {
+    on_stop_dispatch_event_callback_.Run(event);
+  }
+}
+
 void Window::TraceMembers(script::Tracer* tracer) {
   tracer->Trace(performance_);
   tracer->Trace(document_);
diff --git a/src/cobalt/dom/window.h b/src/cobalt/dom/window.h
index 4752a01..f43bfc3 100644
--- a/src/cobalt/dom/window.h
+++ b/src/cobalt/dom/window.h
@@ -99,6 +99,10 @@
       const base::SourceLocation&, const base::Closure&,
       const base::Callback<void(const std::string&)>&)>
       HTMLDecoderCreatorCallback;
+  typedef base::Callback<void(const scoped_refptr<dom::Event>& event)>
+      OnStartDispatchEventCallback;
+  typedef base::Callback<void(const scoped_refptr<dom::Event>& event)>
+      OnStopDispatchEventCallback;
   typedef UrlRegistry<MediaSource> MediaSourceRegistry;
 
   Window(
@@ -133,6 +137,9 @@
       system_window::SystemWindow* system_window,
       const scoped_refptr<input::InputPoller>& input_poller,
       const scoped_refptr<cobalt::media_session::MediaSession>& media_session,
+      const OnStartDispatchEventCallback&
+          start_tracking_dispatch_event_callback,
+      const OnStopDispatchEventCallback& stop_tracking_dispatch_event_callback,
       int csp_insecure_allowed_token = 0, int dom_max_element_depth = 0);
 
   // Web API: Window
@@ -280,6 +287,9 @@
 
   void TraceMembers(script::Tracer* tracer) OVERRIDE;
 
+  void OnStartDispatchEvent(const scoped_refptr<dom::Event>& event);
+  void OnStopDispatchEvent(const scoped_refptr<dom::Event>& event);
+
   DEFINE_WRAPPABLE_TYPE(Window);
 
  private:
@@ -331,6 +341,9 @@
   scoped_refptr<TestRunner> test_runner_;
 #endif  // ENABLE_TEST_RUNNER
 
+  OnStartDispatchEventCallback on_start_dispatch_event_callback_;
+  OnStopDispatchEventCallback on_stop_dispatch_event_callback_;
+
   DISALLOW_COPY_AND_ASSIGN(Window);
 };
 
diff --git a/src/cobalt/dom/window_test.cc b/src/cobalt/dom/window_test.cc
index f087c28..3487ac4 100644
--- a/src/cobalt/dom/window_test.cc
+++ b/src/cobalt/dom/window_test.cc
@@ -64,7 +64,9 @@
             base::Closure() /* ran_animation_frame_callbacks */,
             base::Closure() /* window_close */,
             base::Closure() /* window_minimize */,
-            stub_media_module_->system_window(), NULL, NULL)) {}
+            stub_media_module_->system_window(), NULL, NULL,
+            dom::Window::OnStartDispatchEventCallback(),
+            dom::Window::OnStopDispatchEventCallback())) {}
 
   ~WindowTest() OVERRIDE {}
 
diff --git a/src/cobalt/layout_tests/testdata/web-platform-tests/content-security-policy/web_platform_tests.txt b/src/cobalt/layout_tests/testdata/web-platform-tests/content-security-policy/web_platform_tests.txt
index 48b16c9..47bb2bd 100644
--- a/src/cobalt/layout_tests/testdata/web-platform-tests/content-security-policy/web_platform_tests.txt
+++ b/src/cobalt/layout_tests/testdata/web-platform-tests/content-security-policy/web_platform_tests.txt
@@ -165,7 +165,7 @@
 blink-contrib/policy-does-not-affect-child.sub.html,DISABLE
 
 blink-contrib/report-blocked-data-uri.sub.html,PASS
-blink-contrib/report-cross-origin-no-cookies.sub.html,PASS
+blink-contrib/report-cross-origin-no-cookies.sub.html,DISABLE
 
 blink-contrib/report-disallowed-from-meta.sub.html,PASS
 blink-contrib/report-same-origin-with-cookies.sub.html,PASS
diff --git a/src/cobalt/loader/embedded_resources/splash_screen.html b/src/cobalt/loader/embedded_resources/black_splash_screen.html
similarity index 100%
rename from src/cobalt/loader/embedded_resources/splash_screen.html
rename to src/cobalt/loader/embedded_resources/black_splash_screen.html
diff --git a/src/cobalt/loader/embedded_resources/splash_screen.css b/src/cobalt/loader/embedded_resources/splash_screen.css
deleted file mode 100644
index 9fbe2a3..0000000
--- a/src/cobalt/loader/embedded_resources/splash_screen.css
+++ /dev/null
@@ -1,142 +0,0 @@
-body {
-  overflow: hidden;
-  font-size: 1.4815vh;  /* Corresponds to 16px at 1080p. */
-}
-
-#splash {
-  background-color: #e62117;
-  background-image: url("h5vcc-embedded://you_tube_logo.png");
-  background-position: center center;
-  background-repeat: no-repeat;
-  background-size: 50%;
-  height: 100%;
-  left: 0;
-  position: absolute;
-  top: 0;
-  width: 100%;
-}
-
-#loading {
-  position: absolute;
-  top: 52em;
-  width: 100%;
-}
-
-#spinner {
-  /* The spinner starts with display set to none, and JavaScript will set this
-     to 'block' after some time has passed, if the splash screen is still
-     visible. */
-  display: none;
-
-  height: 5.33em;
-  margin: 0 auto;
-  position: relative;
-  width: 5.33em;
-}
-
-.dot {
-  background-color: #cbcbcb;
-  border-radius: 50%;
-  height: 1.17em;
-  position: absolute;
-  width: 1.17em;
-}
-
-@keyframes fade1 {
-  0%,100% {opacity: 0}
-  50% {opacity: 1}
-}
-
-@keyframes fade2 {
-  0%,100% {opacity: .25}
-  37.5% {opacity: 1}
-  87.5% {opacity: 0}
-}
-
-@keyframes fade3 {
-  0%,100% {opacity: .5}
-  25% {opacity: 1}
-  75% {opacity: 0}
-}
-
-@keyframes fade4 {
-  0%,100% {opacity: .75}
-  12.5% {opacity: 1}
-  62.5% {opacity: 0}
-}
-
-@keyframes fade5 {
-  0%,100% {opacity: 1}
-  50% {opacity: 0}
-}
-
-@keyframes fade6 {
-  0%,100% {opacity: .75}
-  37.5% {opacity: 0}
-  87.5% {opacity: 1}
-}
-
-@keyframes fade7 {
-  0%,100% {opacity: .5}
-  25% {opacity: 0}
-  75% {opacity: 1}
-}
-
-@keyframes fade8 {
-  0%,100% {opacity: .25}
-  12.5% {opacity: 0}
-  62.5% {opacity: 1}
-}
-
-#dot1 {
-  animation: fade8 .72s infinite ease;
-  left: 0;
-  top: 2.09em;
-}
-
-#dot2 {
-  animation: fade7 .72s infinite ease;
-  left: .61em;
-  top: .61em;
-}
-
-#dot3 {
-  animation: fade6 .72s infinite ease;
-  left: 2.09em;
-  top: 0;
-}
-
-#dot4 {
-  animation: fade5 .72s infinite ease;
-  right: .61em;
-  top: .61em;
-}
-
-#dot5 {
-  animation: fade4 .72s infinite ease;
-  right: 0;
-  top: 2.09em;
-}
-
-#dot6 {
-  animation: fade3 .72s infinite ease;
-  bottom: .61em;
-  right: .61em;
-}
-
-#dot7 {
-  animation: fade2 .72s infinite ease;
-  bottom: 0;
-  left: 2.09em;
-}
-
-#dot8 {
-  animation: fade1 .72s infinite ease;
-  bottom: .61em;
-  left: .61em;
-}
-
-.hidden {
-  height: 0;
-  visibility: hidden;
-}
diff --git a/src/cobalt/loader/embedded_resources/splash_screen.js b/src/cobalt/loader/embedded_resources/splash_screen.js
deleted file mode 100644
index 0d30edc..0000000
--- a/src/cobalt/loader/embedded_resources/splash_screen.js
+++ /dev/null
@@ -1,5 +0,0 @@
-  // Enable the spinner after 3 seconds have passed.
-  window.setTimeout(function() {
-    var spinner = document.getElementById('spinner');
-    spinner.style.display = 'block';
-  }, 3000);
diff --git a/src/cobalt/loader/embedded_resources/you_tube_logo.png b/src/cobalt/loader/embedded_resources/you_tube_logo.png
deleted file mode 100644
index 14563d0..0000000
--- a/src/cobalt/loader/embedded_resources/you_tube_logo.png
+++ /dev/null
Binary files differ
diff --git a/src/cobalt/loader/loader.gyp b/src/cobalt/loader/loader.gyp
index 0c9edff..aeebef5 100644
--- a/src/cobalt/loader/loader.gyp
+++ b/src/cobalt/loader/loader.gyp
@@ -175,11 +175,17 @@
         'input_directory': 'embedded_resources',
       },
       'sources': [
+        '<(input_directory)/black_splash_screen.html',
         '<(input_directory)/equirectangular_40_40.msh',
-        '<(input_directory)/splash_screen.css',
-        '<(input_directory)/splash_screen.html',
-        '<(input_directory)/splash_screen.js',
-        '<(input_directory)/you_tube_logo.png',
+      ],
+      'conditions': [
+        ['target_arch == "ps3"', {
+          'sources': [
+            '<(input_directory)/youtube_splash_screen.css',
+            '<(input_directory)/youtube_splash_screen.html',
+            '<(input_directory)/youtube_splash_screen.png',
+          ],
+        }],
       ],
       'actions': [
         {
diff --git a/src/cobalt/loader/loader_test.cc b/src/cobalt/loader/loader_test.cc
index 1e7872a..570d839 100644
--- a/src/cobalt/loader/loader_test.cc
+++ b/src/cobalt/loader/loader_test.cc
@@ -16,6 +16,7 @@
 
 #include "base/bind.h"
 #include "base/file_util.h"
+#include "base/memory/scoped_ptr.h"
 #include "base/message_loop.h"
 #include "base/path_service.h"
 #include "base/run_loop.h"
@@ -40,8 +41,8 @@
  public:
   explicit TextDecoderCallback(base::RunLoop* run_loop) : run_loop_(run_loop) {}
 
-  void OnDone(const std::string& text) {
-    text_ = text;
+  void OnDone(scoped_ptr<std::string> text) {
+    text_ = *text;
     MessageLoop::current()->PostTask(FROM_HERE, run_loop_->QuitClosure());
   }
 
diff --git a/src/cobalt/loader/resource_cache.h b/src/cobalt/loader/resource_cache.h
index 024cc55..5573eac 100644
--- a/src/cobalt/loader/resource_cache.h
+++ b/src/cobalt/loader/resource_cache.h
@@ -513,12 +513,13 @@
   base::CVal<base::cval::SizeInBytes, base::CValPublic> memory_size_in_bytes_;
   base::CVal<base::cval::SizeInBytes, base::CValPublic>
       memory_capacity_in_bytes_;
-  base::CVal<base::cval::SizeInBytes> memory_resources_loaded_in_bytes_;
+  base::CVal<base::cval::SizeInBytes, base::CValPublic>
+      memory_resources_loaded_in_bytes_;
 
-  base::CVal<int> count_resources_requested_;
-  base::CVal<int> count_resources_loading_;
-  base::CVal<int> count_resources_loaded_;
-  base::CVal<int> count_pending_callbacks_;
+  base::CVal<int, base::CValPublic> count_resources_requested_;
+  base::CVal<int, base::CValPublic> count_resources_loading_;
+  base::CVal<int, base::CValPublic> count_resources_loaded_;
+  base::CVal<int, base::CValPublic> count_pending_callbacks_;
 
   DISALLOW_COPY_AND_ASSIGN(ResourceCache);
 };
diff --git a/src/cobalt/loader/text_decoder.h b/src/cobalt/loader/text_decoder.h
index 11b78d4..2c1761c 100644
--- a/src/cobalt/loader/text_decoder.h
+++ b/src/cobalt/loader/text_decoder.h
@@ -17,6 +17,7 @@
 
 #include <algorithm>
 #include <string>
+#include <utility>
 
 #include "base/callback.h"
 #include "base/compiler_specific.h"
@@ -32,13 +33,14 @@
 // results.
 class TextDecoder : public Decoder {
  public:
-  explicit TextDecoder(base::Callback<void(const std::string&)> done_callback)
+  explicit TextDecoder(
+      base::Callback<void(scoped_ptr<std::string>)> done_callback)
       : done_callback_(done_callback), suspended_(false) {}
   ~TextDecoder() OVERRIDE {}
 
   // This function is used for binding callback for creating TextDecoder.
   static scoped_ptr<Decoder> Create(
-      base::Callback<void(const std::string&)> done_callback) {
+      base::Callback<void(scoped_ptr<std::string>)> done_callback) {
     return scoped_ptr<Decoder>(new TextDecoder(done_callback));
   }
 
@@ -48,7 +50,10 @@
     if (suspended_) {
       return;
     }
-    text_.append(data, size);
+    if (!text_) {
+      text_.reset(new std::string);
+    }
+    text_->append(data, size);
   }
 
   void DecodeChunkPassed(scoped_ptr<std::string> data) OVERRIDE {
@@ -58,10 +63,10 @@
       return;
     }
 
-    if (text_.empty()) {
-      std::swap(*data, text_);
+    if (!text_) {
+      text_ = data.Pass();
     } else {
-      text_.append(*data);
+      text_->append(*data);
     }
   }
 
@@ -70,11 +75,14 @@
     if (suspended_) {
       return;
     }
-    done_callback_.Run(text_);
+    if (!text_) {
+      text_.reset(new std::string);
+    }
+    done_callback_.Run(text_.Pass());
   }
   bool Suspend() OVERRIDE {
     suspended_ = true;
-    text_.clear();
+    text_.reset();
     return true;
   }
   void Resume(render_tree::ResourceProvider* /*resource_provider*/) OVERRIDE {
@@ -83,8 +91,8 @@
 
  private:
   base::ThreadChecker thread_checker_;
-  std::string text_;
-  base::Callback<void(const std::string&)> done_callback_;
+  base::Callback<void(scoped_ptr<std::string>)> done_callback_;
+  scoped_ptr<std::string> text_;
   bool suspended_;
 };
 
diff --git a/src/cobalt/loader/text_decoder_test.cc b/src/cobalt/loader/text_decoder_test.cc
index 7c62696..29402dd 100644
--- a/src/cobalt/loader/text_decoder_test.cc
+++ b/src/cobalt/loader/text_decoder_test.cc
@@ -15,6 +15,7 @@
 #include "cobalt/loader/text_decoder.h"
 
 #include "base/bind.h"
+#include "base/memory/scoped_ptr.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -23,7 +24,7 @@
 namespace {
 
 struct TextDecoderCallback {
-  void Callback(const std::string& value) { text = value; }
+  void Callback(scoped_ptr<std::string> value) { text = *value; }
   std::string text;
 };
 
diff --git a/src/cobalt/media/base/decoder_buffer.cc b/src/cobalt/media/base/decoder_buffer.cc
index b01b364..93c85d9 100644
--- a/src/cobalt/media/base/decoder_buffer.cc
+++ b/src/cobalt/media/base/decoder_buffer.cc
@@ -68,15 +68,19 @@
     return;
   }
 
-  SbMemoryCopy(data_.get(), data, size_);
+  if (has_data()) {
+    SbMemoryCopy(data_.get(), data, size_);
+  }
 
   if (!side_data) {
     CHECK_EQ(side_data_size, 0u);
     return;
   }
 
-  DCHECK_GT(side_data_size_, 0u);
-  SbMemoryCopy(side_data_.get(), side_data, side_data_size_);
+  if (has_side_data()) {
+    DCHECK_GT(side_data_size_, 0u);
+    SbMemoryCopy(side_data_.get(), side_data, side_data_size_);
+  }
 }
 
 DecoderBuffer::~DecoderBuffer() {}
diff --git a/src/cobalt/media/base/stream_parser_buffer.cc b/src/cobalt/media/base/stream_parser_buffer.cc
index 3680f9c..0656fb8 100644
--- a/src/cobalt/media/base/stream_parser_buffer.cc
+++ b/src/cobalt/media/base/stream_parser_buffer.cc
@@ -45,8 +45,13 @@
 scoped_refptr<StreamParserBuffer> StreamParserBuffer::CopyFrom(
     Allocator* allocator, const uint8_t* data, int data_size, bool is_key_frame,
     Type type, TrackId track_id) {
-  return make_scoped_refptr(new StreamParserBuffer(
-      allocator, data, data_size, NULL, 0, is_key_frame, type, track_id));
+  scoped_refptr<StreamParserBuffer> stream_parser_buffer =
+      make_scoped_refptr(new StreamParserBuffer(
+          allocator, data, data_size, NULL, 0, is_key_frame, type, track_id));
+  if (stream_parser_buffer->has_data()) {
+    return stream_parser_buffer;
+  }
+  return NULL;
 }
 
 scoped_refptr<StreamParserBuffer> StreamParserBuffer::CopyFrom(
@@ -93,6 +98,10 @@
     set_duration(kNoTimestamp);
   }
 
+  if (!has_data()) {
+    return;
+  }
+
   if (is_key_frame) set_is_key_frame(true);
 }
 
diff --git a/src/cobalt/media/filters/source_buffer_stream.cc b/src/cobalt/media/filters/source_buffer_stream.cc
index 2602fd0..8ab87ce 100644
--- a/src/cobalt/media/filters/source_buffer_stream.cc
+++ b/src/cobalt/media/filters/source_buffer_stream.cc
@@ -730,10 +730,30 @@
     return false;
   }
 
-  // Return if we're under or at the memory limit.
-  if (ranges_size + newDataSize <= memory_limit_) return true;
+  base::TimeDelta duration = GetBufferedDurationForGarbageCollection();
 
-  size_t bytes_to_free = ranges_size + newDataSize - memory_limit_;
+  size_t bytes_to_free = 0;
+
+  // Check if we're under or at the memory/duration limit.
+  const int64 kGcDurationThresholdInMilliseconds =
+      COBALT_MEDIA_SOURCE_GARBAGE_COLLECTION_DURATION_THRESHOLD_IN_SECONDS *
+      1000;
+
+  if (ranges_size + newDataSize > memory_limit_) {
+    bytes_to_free = ranges_size + newDataSize - memory_limit_;
+  } else if (duration.InMilliseconds() > kGcDurationThresholdInMilliseconds) {
+    // Estimate the size to free.
+    int64 duration_to_free =
+        duration.InMilliseconds() - kGcDurationThresholdInMilliseconds;
+    bytes_to_free = static_cast<size_t>(ranges_size * duration_to_free /
+                                        duration.InMilliseconds());
+  }
+
+  if (bytes_to_free == 0) {
+    return true;
+  }
+
+  DCHECK_GT(bytes_to_free, 0);
 
   DVLOG(2) << __func__ << " " << GetStreamTypeName()
            << ": Before GC media_time=" << media_time.InSecondsF()
@@ -1833,5 +1853,15 @@
   return true;
 }
 
+base::TimeDelta SourceBufferStream::GetBufferedDurationForGarbageCollection()
+    const {
+  base::TimeDelta duration;
+  for (RangeList::const_iterator itr = ranges_.begin(); itr != ranges_.end();
+       ++itr) {
+    duration += (*itr)->GetEndTimestamp() - (*itr)->GetStartTimestamp();
+  }
+  return duration;
+}
+
 }  // namespace media
 }  // namespace cobalt
diff --git a/src/cobalt/media/filters/source_buffer_stream.h b/src/cobalt/media/filters/source_buffer_stream.h
index 6fe9229..c473d4a 100644
--- a/src/cobalt/media/filters/source_buffer_stream.h
+++ b/src/cobalt/media/filters/source_buffer_stream.h
@@ -471,6 +471,10 @@
   // appropriately and returns true.  Otherwise returns false.
   bool SetPendingBuffer(scoped_refptr<StreamParserBuffer>* out_buffer);
 
+  // Returns the accumulated duration of all ranges.  This is solely used by
+  // garbage collection.
+  base::TimeDelta GetBufferedDurationForGarbageCollection() const;
+
   // Used to report log messages that can help the web developer figure out what
   // is wrong with the content.
   scoped_refptr<MediaLog> media_log_;
diff --git a/src/cobalt/media/formats/mp4/mp4_stream_parser.cc b/src/cobalt/media/formats/mp4/mp4_stream_parser.cc
index d8074e9..dd13d30 100644
--- a/src/cobalt/media/formats/mp4/mp4_stream_parser.cc
+++ b/src/cobalt/media/formats/mp4/mp4_stream_parser.cc
@@ -618,6 +618,10 @@
       buffer_allocator_, &frame_buf[0], frame_buf.size(), runs_->is_keyframe(),
       buffer_type, runs_->track_id());
 
+  if (!stream_buf) {
+    return false;
+  }
+
   if (decrypt_config) stream_buf->set_decrypt_config(decrypt_config.Pass());
 
   stream_buf->set_duration(runs_->duration());
diff --git a/src/cobalt/media/formats/mpeg/mpeg_audio_stream_parser_base.cc b/src/cobalt/media/formats/mpeg/mpeg_audio_stream_parser_base.cc
index 31d415a..602b166 100644
--- a/src/cobalt/media/formats/mpeg/mpeg_audio_stream_parser_base.cc
+++ b/src/cobalt/media/formats/mpeg/mpeg_audio_stream_parser_base.cc
@@ -233,6 +233,9 @@
   scoped_refptr<StreamParserBuffer> buffer =
       StreamParserBuffer::CopyFrom(buffer_allocator_, data, frame_size, true,
                                    DemuxerStream::AUDIO, kMpegAudioTrackId);
+  if (!buffer) {
+    return -1;
+  }
   buffer->set_timestamp(timestamp_helper_->GetTimestamp());
   buffer->set_duration(timestamp_helper_->GetFrameDuration(sample_count));
   buffers->push_back(buffer);
diff --git a/src/cobalt/media/formats/webm/webm_cluster_parser.cc b/src/cobalt/media/formats/webm/webm_cluster_parser.cc
index a8fac84..48a4850 100644
--- a/src/cobalt/media/formats/webm/webm_cluster_parser.cc
+++ b/src/cobalt/media/formats/webm/webm_cluster_parser.cc
@@ -512,7 +512,10 @@
     buffer = StreamParserBuffer::CopyFrom(
         buffer_allocator_, data + data_offset, size - data_offset, additional,
         additional_size, is_keyframe, buffer_type, track_num);
-
+    if (!buffer) {
+      MEDIA_LOG(ERROR, media_log_) << "Failed to allocate StreamParserBuffer";
+      return false;
+    }
     if (decrypt_config) buffer->set_decrypt_config(decrypt_config.Pass());
   } else {
     std::string id, settings, content;
@@ -529,6 +532,10 @@
         buffer_allocator_, reinterpret_cast<const uint8_t*>(content.data()),
         content.length(), &side_data[0], side_data.size(), true, buffer_type,
         track_num);
+    if (!buffer) {
+      MEDIA_LOG(ERROR, media_log_) << "Failed to allocate StreamParserBuffer";
+      return false;
+    }
   }
 
   buffer->set_timestamp(timestamp);
diff --git a/src/cobalt/renderer/pipeline.cc b/src/cobalt/renderer/pipeline.cc
index 187e684..b2c7967 100644
--- a/src/cobalt/renderer/pipeline.cc
+++ b/src/cobalt/renderer/pipeline.cc
@@ -84,9 +84,6 @@
       last_did_rasterize_(false),
       last_animations_expired_(true),
       last_stat_tracked_animations_expired_(true),
-      rasterize_periodic_timer_("Renderer.Rasterize.Duration",
-                                kRasterizePeriodicTimerEntriesPerUpdate,
-                                false /*enable_entry_list_c_val*/),
       rasterize_animations_timer_("Renderer.Rasterize.Animations",
                                   kRasterizeAnimationsTimerMaxEntries,
                                   true /*enable_entry_list_c_val*/),
@@ -310,14 +307,6 @@
   bool animations_active =
       !are_stat_tracked_animations_expired && did_rasterize;
 
-  // The rasterization is only timed with the periodic timer when the render
-  // tree has changed. This ensures that the frames being timed are consistent
-  // between platforms that submit unchanged trees and those that don't.
-  if (did_rasterize) {
-    rasterize_periodic_timer_.Start(start_time);
-    rasterize_periodic_timer_.Stop(end_time);
-  }
-
   if (last_animations_active || animations_active) {
     // The rasterization is only timed with the animations timer when there are
     // animations to track. This applies when animations were active during
diff --git a/src/cobalt/renderer/pipeline.h b/src/cobalt/renderer/pipeline.h
index a9abff7..571f274 100644
--- a/src/cobalt/renderer/pipeline.h
+++ b/src/cobalt/renderer/pipeline.h
@@ -209,13 +209,9 @@
   bool last_did_rasterize_;
 
   // Timer tracking the amount of time spent in
-  // |RasterizeSubmissionToRenderTarget| when the render tree has changed.
-  // The tracking is flushed when the max count is hit.
-  base::CValCollectionTimerStats<base::CValPublic> rasterize_periodic_timer_;
-  // Timer tracking the amount of time spent in
   // |RasterizeSubmissionToRenderTarget| while animations are active. The
   // tracking is flushed when the animations expire.
-  base::CValCollectionTimerStats<base::CValDebug> rasterize_animations_timer_;
+  base::CValCollectionTimerStats<base::CValPublic> rasterize_animations_timer_;
 
   // Accumulates render tree rasterization interval times but does not flush
   // them until the maximum number of samples is gathered.
@@ -229,16 +225,16 @@
       rasterize_animations_interval_timer_;
 
   // The total number of new render trees that have been rasterized.
-  base::CVal<int> new_render_tree_rasterize_count_;
+  base::CVal<int, base::CValPublic> new_render_tree_rasterize_count_;
   // The last time that a newly encountered render tree was first rasterized.
-  base::CVal<int64> new_render_tree_rasterize_time_;
+  base::CVal<int64, base::CValPublic> new_render_tree_rasterize_time_;
 
   // Whether or not animations are currently playing.
-  base::CVal<bool> has_active_animations_c_val_;
+  base::CVal<bool, base::CValPublic> has_active_animations_c_val_;
   // The most recent time animations started playing.
-  base::CVal<int64> animations_start_time_;
+  base::CVal<int64, base::CValPublic> animations_start_time_;
   // The most recent time animations ended playing.
-  base::CVal<int64> animations_end_time_;
+  base::CVal<int64, base::CValPublic> animations_end_time_;
 
 #if defined(ENABLE_DEBUG_CONSOLE)
   // Dumps the current render tree to the console.
diff --git a/src/cobalt/renderer/rasterizer/blitter/cached_software_rasterizer.cc b/src/cobalt/renderer/rasterizer/blitter/cached_software_rasterizer.cc
index 1c5e2d4..2dd5667 100644
--- a/src/cobalt/renderer/rasterizer/blitter/cached_software_rasterizer.cc
+++ b/src/cobalt/renderer/rasterizer/blitter/cached_software_rasterizer.cc
@@ -234,6 +234,7 @@
       // This surface may have already been in the cache if it was in there
       // with a different scale.  In that case, replace the old one.
       cache_memory_usage_ -= found->second.GetEstimatedMemoryUsage();
+      SbBlitterDestroySurface(found->second.surface);
       surface_map_.erase(found);
     }
 
diff --git a/src/media/base/pipeline_impl.cc b/src/media/base/pipeline_impl.cc
index aff759d..cf2bef0 100644
--- a/src/media/base/pipeline_impl.cc
+++ b/src/media/base/pipeline_impl.cc
@@ -745,6 +745,25 @@
                              const BufferingStateCB& buffering_state_cb,
                              const base::Closure& duration_change_cb) {
   DCHECK(message_loop_->BelongsToCurrentThread());
+
+  // Suspend() can be called from a thread other than the WebModule thread.  In
+  // such case it is possible that Stop() is called before Start() and |state_|
+  // will be set to |kStopping| or |kStopped|.
+  if (state_ == kStopping || state_ == kStopped) {
+    return;
+  }
+
+  // Check for individual state so we have more clue when one of them is hit.
+  CHECK_NE(kInitDemuxer, state_) << "state shouldn't be kInitDemuxer";
+  CHECK_NE(kInitAudioRenderer, state_)
+      << "state shouldn't be kInitAudioRenderer";
+  CHECK_NE(kInitVideoRenderer, state_)
+      << "state shouldn't be kInitVideoRenderer";
+  CHECK_NE(kInitPrerolling, state_) << "state shouldn't be kInitPrerolling";
+  CHECK_NE(kSeeking, state_) << "state shouldn't be kSeeking";
+  CHECK_NE(kStarting, state_) << "state shouldn't be kStarting";
+  CHECK_NE(kStarted, state_) << "state shouldn't be kStarted";
+
   CHECK_EQ(kCreated, state_)
       << "Media pipeline cannot be started more than once";
 
diff --git a/src/starboard/linux/x64x11/clang/3.3/download_clang.sh b/src/starboard/linux/x64x11/clang/3.3/download_clang.sh
index f552ae8..54dded5 100755
--- a/src/starboard/linux/x64x11/clang/3.3/download_clang.sh
+++ b/src/starboard/linux/x64x11/clang/3.3/download_clang.sh
@@ -37,7 +37,7 @@
 
   cd llvm
   # Specify a bootstrap compiler that is known to be available.
-  CC=clang-3.6 CXX=clang++-3.6 \
+  CC=clang CXX=clang++ \
   ./configure --enable-optimized --disable-doxygen --prefix=${PWD}/bin
   make -j"$(nproc)"
   cd ${toolchain_path}
diff --git a/src/starboard/linux/x64x11/gcc/4.4/compiler_flags.gypi b/src/starboard/linux/x64x11/gcc/4.4/compiler_flags.gypi
index 9fc908e..6f7d411 100644
--- a/src/starboard/linux/x64x11/gcc/4.4/compiler_flags.gypi
+++ b/src/starboard/linux/x64x11/gcc/4.4/compiler_flags.gypi
@@ -47,6 +47,9 @@
       '-O2',
     ],
     'common_compiler_flags': [
+      # Add the target specific include path that is not compatible with gcc
+      # 4.4 default search locations.
+      '-I/usr/include/x86_64-linux-gnu',
       # Default visibility to hidden, to enable dead stripping.
       '-fvisibility=hidden',
       # protobuf uses hash_map.
diff --git a/src/starboard/linux/x64x11/gcc/4.4/download_gcc.sh b/src/starboard/linux/x64x11/gcc/4.4/download_gcc.sh
new file mode 100755
index 0000000..8bac360
--- /dev/null
+++ b/src/starboard/linux/x64x11/gcc/4.4/download_gcc.sh
@@ -0,0 +1,139 @@
+#!/bin/bash
+# Copyright 2018 Google Inc. 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 script downloads and compiles gcc version 4.4.7
+
+set -e
+unset GOMA_DIR
+export GOMA_DIR
+
+toolchain_name="gcc"
+version="4.4.7"
+toolchain_folder="x86_64-linux-gnu-${toolchain_name}-${version}"
+
+binary_path="gcc/bin/g++"
+build_duration="about 10 minutes"
+
+cd $(dirname $0)
+source ../../toolchain_paths.sh
+cd ${toolchain_path}
+
+(
+  texinfo_install_folder=${toolchain_path}/texinfo
+  if [ ! -f ${texinfo_install_folder}/bin/info ]; then
+    # Download and compile texinfo
+    texinfo_version="texinfo-4.13"
+    texinfo_tar_file=${texinfo_version}a.tar.gz
+    wget -c https://ftp.gnu.org/gnu/texinfo/${texinfo_tar_file}
+
+    checksum_invalid=$(sha256sum ${texinfo_tar_file} | grep -q -c 1303e91a1c752b69a32666a407e9fbdd6e936def4b09bc7de30f416301530d68)
+    if [ $checksum_invalid ]; then echo "Invalid checksum"; exit 1 ; fi
+    rm -rf texinfo ${texinfo_version}
+    tar -xzf ${texinfo_tar_file}
+    cd ${texinfo_version}/
+    ./configure --prefix=${texinfo_install_folder}
+    make -j$(nproc) && make install
+    cd ${toolchain_path}
+  fi
+  export PATH=${texinfo_install_folder}/bin:${PATH}
+
+  if [ ! -e gmp/lib/libgmp.a ]; then
+    gmp_version="gmp-4.3.2"
+    gmp_tar_file=${gmp_version}.tar.bz2
+    wget -c https://ftp.gnu.org/gnu/gmp/${gmp_tar_file}
+
+    checksum_invalid=$(sha256sum ${gmp_tar_file} | grep -q -c 936162c0312886c21581002b79932829aa048cfaf9937c6265aeaa14f1cd1775)
+    if [ $checksum_invalid ]; then echo "Invalid checksum" ; exit 1 ; fi
+
+    rm -rf gmp ${gmp_version}
+    tar -xjf ${gmp_tar_file}
+    cd ${gmp_version}
+    ./configure --disable-shared --enable-static --prefix=${PWD}/../gmp
+    make -j$(nproc) && make install
+    cd ${toolchain_path}
+  fi
+
+  if [ ! -e mpfr/lib/libmpfr.a ]; then
+    mpfr_version="mpfr-2.4.2"
+    mpfr_tar_file=${mpfr_version}.tar.xz
+    wget -c https://ftp.gnu.org/gnu/mpfr/${mpfr_version}.tar.xz
+
+    checksum_invalid=$(sha256sum ${mpfr_tar_file} | grep -q -c d7271bbfbc9ddf387d3919df8318cd7192c67b232919bfa1cb3202d07843da1b)
+    if [ $checksum_invalid ]; then echo "Invalid checksum" ; exit 1 ; fi
+
+    rm -rf mpfr ${mpfr_version}
+    tar -xJf ${mpfr_version}.tar.xz
+    cd ${mpfr_version}
+    ./configure --disable-shared --enable-static --with-gmp=../gmp --prefix=${PWD}/../mpfr
+    make -j$(nproc) && make install
+    cd ${toolchain_path}
+  fi
+
+  # Download gcc
+  if [ ! -e gcc-${version}/README ]; then
+    file="gcc-${version}.tar.bz2"
+    wget -c https://ftp.gnu.org/gnu/gcc/gcc-${version}/${file}
+    wget -c https://ftp.gnu.org/gnu/gcc/gcc-${version}/${file}.sig
+    wget -c https://ftp.gnu.org/gnu/gnu-keyring.gpg
+    signature_invalid=`gpg --verify --no-default-keyring --keyring ./gnu-keyring.gpg ${file}.sig`
+    if [ $signature_invalid ]; then echo "Invalid signature" ; exit 1 ; fi
+
+    checksum_invalid=$(sha256sum ${file} | grep -q -c 5ff75116b8f763fa0fb5621af80fc6fb3ea0f1b1a57520874982f03f26cd607f)
+    if [ $checksum_invalid ]; then echo "Invalid checksum" ; exit 1 ; fi
+
+    rm -rf gcc-${version}
+    tar -xjf ${file}
+    cd gcc-${version}
+    if [ -f ./contrib/download_prerequisites ]; then
+      ./contrib/download_prerequisites
+    fi
+
+    # Replace 'struct siginfo' with 'siginfo_t' in linux-unwind.h (compilation fix).
+    sed -i 's:struct siginfo:siginfo_t:g' ${toolchain_path}/gcc-${version}/gcc/config/i386/linux-unwind.h
+
+    cd ${toolchain_path}
+  fi
+
+  # Create clean build folder for gcc
+  rm -rf gcc gcc-${version}-build
+  mkdir gcc-${version}-build
+  cd gcc-${version}-build
+
+  export LIBRARY_PATH=/usr/lib/x86_64-linux-gnu:/usr/lib32:${toolchain_path}/gmp/lib:${toolchain_path}/mpfr/lib
+  export LD_LIBRARY_PATH=$LIBRARY_PATH
+  echo LIBRARY_PATH = $LIBRARY_PATH
+
+  export C_INCLUDE_PATH=/usr/include/x86_64-linux-gnu
+  export CPLUS_INCLUDE_PATH=/usr/include/x86_64-linux-gnu
+  export TARGET_SYSTEM_ROOT=/usr/include/x86_64-linux-gnu
+
+  export CC="gcc -fgnu89-inline"
+  export CXX="g++ -fgnu89-inline"
+
+  ${toolchain_path}/gcc-${version}/configure \
+    --prefix=${toolchain_path}/gcc \
+    --disable-multilib \
+    --enable-languages=c,c++ \
+    --with-gmp=${toolchain_path}/gmp \
+    --with-mpfr=${toolchain_path}/mpfr \
+    --with-mpfr-lib=${toolchain_path}/mpfr/lib
+
+  make -j$(nproc) && make install
+  cd ${toolchain_path}
+
+  ls -l ${toolchain_binary}
+  ${toolchain_binary} --version
+) >${logfile} 2>&1
+
diff --git a/src/starboard/linux/x64x11/gcc/4.4/gyp_configuration.py b/src/starboard/linux/x64x11/gcc/4.4/gyp_configuration.py
index 3d6e006..dbb14af 100644
--- a/src/starboard/linux/x64x11/gcc/4.4/gyp_configuration.py
+++ b/src/starboard/linux/x64x11/gcc/4.4/gyp_configuration.py
@@ -15,6 +15,7 @@
 
 import logging
 import os
+import subprocess
 import sys
 
 # Import the shared Linux platform configuration.
@@ -25,6 +26,7 @@
             'shared')))
 # pylint: disable=import-self,g-import-not-at-top
 import gyp_configuration as shared_configuration
+import gyp_utils
 
 
 class PlatformConfig(shared_configuration.PlatformConfig):
@@ -34,16 +36,28 @@
     super(PlatformConfig, self).__init__(
         platform, asan_enabled_by_default, goma_supports_compiler=False)
 
+    # Run the script that ensures gcc 4.4.7 is installed.
+    script_path = os.path.dirname(os.path.realpath(__file__))
+    subprocess.call(
+        os.path.join(script_path, 'download_gcc.sh'), cwd=script_path)
+
   def GetVariables(self, configuration):
     variables = super(PlatformConfig, self).GetVariables(configuration)
-    variables.update({'clang': 0,})
+    variables.update({
+        'clang': 0,
+    })
     return variables
 
   def GetEnvironmentVariables(self):
     env_variables = super(PlatformConfig, self).GetEnvironmentVariables()
+    toolchain_bin_dir = os.path.join(gyp_utils.GetToolchainsDir(),
+                                     'x86_64-linux-gnu-gcc-4.4.7', 'gcc', 'bin')
     env_variables.update({
-        'CC': 'gcc-4.4',
-        'CXX': 'g++-4.4',
+        'CC':
+            os.path.join(toolchain_bin_dir, 'gcc'),
+        'CXX':
+            'LIBRARY_PATH=/usr/lib/x86_64-linux-gnu ' +
+            os.path.join(toolchain_bin_dir, 'g++'),
     })
     return env_variables
 
diff --git a/src/starboard/nplb/socket_resolve_test.cc b/src/starboard/nplb/socket_resolve_test.cc
index ebca117..bf96ac3 100644
--- a/src/starboard/nplb/socket_resolve_test.cc
+++ b/src/starboard/nplb/socket_resolve_test.cc
@@ -37,7 +37,7 @@
 const void* kNull = NULL;
 
 // A random host name to use to test DNS resolution.
-const char* kTestHostName = "www.yahoo.com";
+const char kTestHostName[] = "www.example.com";
 
 #define LOG_ADDRESS(i) "In returned address #" << (i)
 
diff --git a/src/third_party/protobuf/src/google/protobuf/stubs/strutil.cc b/src/third_party/protobuf/src/google/protobuf/stubs/strutil.cc
index 296694c..8f5ff59 100644
--- a/src/third_party/protobuf/src/google/protobuf/stubs/strutil.cc
+++ b/src/third_party/protobuf/src/google/protobuf/stubs/strutil.cc
@@ -29,12 +29,39 @@
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 // from google3/strings/strutil.cc
-#include "starboard/client_porting/poem/stdlib_poem.h"
-#include "starboard/client_porting/poem/stdio_poem.h"
-#include "starboard/client_porting/poem/string_poem.h"
 
 #ifndef STARBOARD
+
 #include <stdio.h>
+
+// We need to be able to build this library using the host toolchain for some
+// platforms, and Starboard is not available there.  So we define these
+// "reverse poems" to move past this issue for host builds.  For why we don't
+// just use poems, see the comment in the #else clause.
+#define SbMemoryCopy memcpy
+#define SbMemoryMove memmove
+#define SbStringGetLength strlen
+#define SbStringCopyUnsafe strcpy
+#define PoemFindCharacterInString strchr
+#define SbStringFormatF snprintf
+#define SbStringFormatUnsafeF sprintf
+#define SbStringParseUnsignedInteger strtoul
+#define SbStringParseSignedInteger strtol
+#define SbStringParseDouble strtod
+
+#else  // STARBOARD
+
+// We avoid using poems here because a subsequent #include of math.h may
+// result, on some platforms, of the indirect inclusion of stdlib.h, which
+// will then conflict with our poem includes.
+#define POEM_NO_EMULATION
+// For access to PoemFindCharacterInString() as a replacement for strchr().
+#include "starboard/client_porting/poem/string_poem.h"
+#undef POEM_NO_EMULATION
+
+#include "starboard/memory.h"
+#include "starboard/string.h"
+
 #endif  // STARBOARD
 
 #include <errno.h>
@@ -276,7 +303,7 @@
                                 string* result) {
   GOOGLE_CHECK(result != NULL);
   result->clear();
-  int delim_length = strlen(delim);
+  int delim_length = SbStringGetLength(delim);
 
   // Precompute resulting length so we can reserve() memory in one shot.
   int length = 0;
@@ -515,7 +542,7 @@
              (last_hex_escape && isxdigit(*src)))) {
           if (dest_len - used < 4) // need space for 4 letter escape
             return -1;
-          sprintf(dest + used, (use_hex ? "\\x%02x" : "\\%03o"),
+          SbStringFormatUnsafeF(dest + used, (use_hex ? "\\x%02x" : "\\%03o"),
                   static_cast<uint8>(*src));
           is_hex_escape = use_hex;
           used += 4;
@@ -643,7 +670,7 @@
 int32 strto32_adaptor(const char *nptr, char **endptr, int base) {
   const int saved_errno = errno;
   errno = 0;
-  const long result = strtol(nptr, endptr, base);
+  const long result = SbStringParseSignedInteger(nptr, endptr, base);
   if (errno == ERANGE && result == LONG_MIN) {
     return kint32min;
   } else if (errno == ERANGE && result == LONG_MAX) {
@@ -663,7 +690,7 @@
 uint32 strtou32_adaptor(const char *nptr, char **endptr, int base) {
   const int saved_errno = errno;
   errno = 0;
-  const unsigned long result = strtoul(nptr, endptr, base);
+  const unsigned long result = SbStringParseUnsignedInteger(nptr, endptr, base);
   if (errno == ERANGE && result == ULONG_MAX) {
     return kuint32max;
   } else if (errno == 0 && result > kuint32max) {
@@ -1225,7 +1252,7 @@
 void DelocalizeRadix(char* buffer) {
   // Fast check:  if the buffer has a normal decimal point, assume no
   // translation is needed.
-  if (strchr(buffer, '.') != NULL) return;
+  if (PoemFindCharacterInString(buffer, '.') != NULL) return;
 
   // Find the first unknown character.
   while (IsValidFloatChar(*buffer)) ++buffer;
@@ -1245,7 +1272,7 @@
     // extra bytes.
     char* target = buffer;
     do { ++buffer; } while (!IsValidFloatChar(*buffer) && *buffer != '\0');
-    memmove(target, buffer, strlen(buffer) + 1);
+    SbMemoryMove(target, buffer, SbStringGetLength(buffer) + 1);
   }
 }
 
@@ -1257,20 +1284,20 @@
   GOOGLE_COMPILE_ASSERT(DBL_DIG < 20, DBL_DIG_is_too_big);
 
   if (value == numeric_limits<double>::infinity()) {
-    strcpy(buffer, "inf");
+    SbStringCopyUnsafe(buffer, "inf");
     return buffer;
   } else if (value == -numeric_limits<double>::infinity()) {
-    strcpy(buffer, "-inf");
+    SbStringCopyUnsafe(buffer, "-inf");
     return buffer;
   } else if (MathLimits<double>::IsNaN(value)) {
-    strcpy(buffer, "nan");
+    SbStringCopyUnsafe(buffer, "nan");
     return buffer;
   }
 
   int snprintf_result =
-    snprintf(buffer, kDoubleToBufferSize, "%.*g", DBL_DIG, value);
+    SbStringFormatF(buffer, kDoubleToBufferSize, "%.*g", DBL_DIG, value);
 
-  // The snprintf should never overflow because the buffer is significantly
+  // The SbStringFormatF should never overflow because the buffer is significantly
   // larger than the precision we asked for.
   GOOGLE_DCHECK(snprintf_result > 0 && snprintf_result < kDoubleToBufferSize);
 
@@ -1280,10 +1307,10 @@
   // of a double.  This long double may have extra bits that make it compare
   // unequal to "value" even though it would be exactly equal if it were
   // truncated to a double.
-  volatile double parsed_value = strtod(buffer, NULL);
+  volatile double parsed_value = SbStringParseDouble(buffer, NULL);
   if (parsed_value != value) {
     int snprintf_result =
-      snprintf(buffer, kDoubleToBufferSize, "%.*g", DBL_DIG+2, value);
+      SbStringFormatF(buffer, kDoubleToBufferSize, "%.*g", DBL_DIG+2, value);
 
     // Should never overflow; see above.
     GOOGLE_DCHECK(snprintf_result > 0 && snprintf_result < kDoubleToBufferSize);
@@ -1332,7 +1359,7 @@
   char* endptr;
   errno = 0;  // errno only gets set on errors
 #if defined(_WIN32) || defined (__hpux) || defined(STARBOARD)  // has no strtof()
-  *value = strtod(str, &endptr);
+  *value = SbStringParseDouble(str, &endptr);
 #else
   *value = strtof(str, &endptr);
 #endif
@@ -1341,7 +1368,7 @@
 
 bool safe_strtod(const char* str, double* value) {
   char* endptr;
-  *value = strtod(str, &endptr);
+  *value = SbStringParseDouble(str, &endptr);
   if (endptr != str) {
     while (ascii_isspace(*endptr)) ++endptr;
   }
@@ -1375,27 +1402,27 @@
   GOOGLE_COMPILE_ASSERT(FLT_DIG < 10, FLT_DIG_is_too_big);
 
   if (value == numeric_limits<double>::infinity()) {
-    strcpy(buffer, "inf");
+    SbStringCopyUnsafe(buffer, "inf");
     return buffer;
   } else if (value == -numeric_limits<double>::infinity()) {
-    strcpy(buffer, "-inf");
+    SbStringCopyUnsafe(buffer, "-inf");
     return buffer;
   } else if (MathLimits<float>::IsNaN(value)) {
-    strcpy(buffer, "nan");
+    SbStringCopyUnsafe(buffer, "nan");
     return buffer;
   }
 
   int snprintf_result =
-    snprintf(buffer, kFloatToBufferSize, "%.*g", FLT_DIG, value);
+    SbStringFormatF(buffer, kFloatToBufferSize, "%.*g", FLT_DIG, value);
 
-  // The snprintf should never overflow because the buffer is significantly
-  // larger than the precision we asked for.
+  // The SbStringFormatF should never overflow because the buffer is
+  // significantly larger than the precision we asked for.
   GOOGLE_DCHECK(snprintf_result > 0 && snprintf_result < kFloatToBufferSize);
 
   float parsed_value;
   if (!safe_strtof(buffer, &parsed_value) || parsed_value != value) {
     int snprintf_result =
-      snprintf(buffer, kFloatToBufferSize, "%.*g", FLT_DIG+2, value);
+      SbStringFormatF(buffer, kFloatToBufferSize, "%.*g", FLT_DIG+2, value);
 
     // Should never overflow; see above.
     GOOGLE_DCHECK(snprintf_result > 0 && snprintf_result < kFloatToBufferSize);
@@ -1435,35 +1462,35 @@
 //    of a mix of raw C strings, C++ strings, and integer values.
 // ----------------------------------------------------------------------
 
-// Append is merely a version of memcpy that returns the address of the byte
+// Append is merely a version of SbMemoryCopy that returns the address of the byte
 // after the area just overwritten.  It comes in multiple flavors to minimize
 // call overhead.
 static char *Append1(char *out, const AlphaNum &x) {
-  memcpy(out, x.data(), x.size());
+  SbMemoryCopy(out, x.data(), x.size());
   return out + x.size();
 }
 
 static char *Append2(char *out, const AlphaNum &x1, const AlphaNum &x2) {
-  memcpy(out, x1.data(), x1.size());
+  SbMemoryCopy(out, x1.data(), x1.size());
   out += x1.size();
 
-  memcpy(out, x2.data(), x2.size());
+  SbMemoryCopy(out, x2.data(), x2.size());
   return out + x2.size();
 }
 
 static char *Append4(char *out,
                      const AlphaNum &x1, const AlphaNum &x2,
                      const AlphaNum &x3, const AlphaNum &x4) {
-  memcpy(out, x1.data(), x1.size());
+  SbMemoryCopy(out, x1.data(), x1.size());
   out += x1.size();
 
-  memcpy(out, x2.data(), x2.size());
+  SbMemoryCopy(out, x2.data(), x2.size());
   out += x2.size();
 
-  memcpy(out, x3.data(), x3.size());
+  SbMemoryCopy(out, x3.data(), x3.size());
   out += x3.size();
 
-  memcpy(out, x4.data(), x4.size());
+  SbMemoryCopy(out, x4.data(), x4.size());
   return out + x4.size();
 }
 
@@ -2269,7 +2296,7 @@
     len = 4;
   }
   tmp = ghtonl(tmp);
-  memcpy(output, reinterpret_cast<const char*>(&tmp) + sizeof(tmp) - len, len);
+  SbMemoryCopy(output, reinterpret_cast<const char*>(&tmp) + sizeof(tmp) - len, len);
   return len;
 }