diff --git a/.gn b/.gn index 853c59a..30f5ee55 100644 --- a/.gn +++ b/.gn
@@ -45,6 +45,8 @@ "//google_update/*", #"//gpu/*", # Lots of errors. + "//gpu:*", + #"//ios/*", "//ipc/*", @@ -101,6 +103,7 @@ "//chrome/browser/BUILD.gn", "//chrome/browser/chromeos/BUILD.gn", "//chrome/browser/extensions/BUILD.gn", + "//chrome/browser/media/router/BUILD.gn", "//chrome/browser/ui/BUILD.gn", "//chrome/chrome_tests.gni", "//chrome/common/BUILD.gn",
diff --git a/BUILD.gn b/BUILD.gn index 97caab49..65f40e0 100644 --- a/BUILD.gn +++ b/BUILD.gn
@@ -169,10 +169,7 @@ } if (enable_media_router) { - deps += [ - "//chrome/browser/media/router/", - "//chrome/browser/media/router:unit_tests", - ] + deps += [ "//chrome/browser/media/router" ] } if (enable_remoting) { @@ -393,7 +390,6 @@ "//ppapi:pepper_hash_for_uma", "//ppapi:ppapi_perftests", "//sync:run_sync_testserver", - "//sync:sync_endtoend_tests", "//third_party/codesighs:maptsvdifftool", "//third_party/leveldatabase:env_chromium_unittests", "//third_party/libaddressinput:libaddressinput_unittests", @@ -751,8 +747,8 @@ if (is_win) { deps += [ + "//content/shell:crash_service", "//content/shell:layout_test_helper", - #'../content/content_shell_and_tests.gyp:content_shell_crash_service', TODO(GYP) ] }
diff --git a/DEPS b/DEPS index 92a0e07f..a9ff9f9 100644 --- a/DEPS +++ b/DEPS
@@ -34,7 +34,7 @@ 'llvm_url': 'http://src.chromium.org/llvm-project', 'llvm_git': 'https://llvm.googlesource.com', 'webkit_trunk': 'http://src.chromium.org/blink/trunk', - 'webkit_revision': 'ea59f1aee78b31b87f82df18927014a053db612d', # from svn revision 195394 + 'webkit_revision': 'ae8e1952e123dd09d9fb2da286461a617f2c501a', # from svn revision 195438 'chromium_git': 'https://chromium.googlesource.com', 'chromiumos_git': 'https://chromium.googlesource.com/chromiumos', 'pdfium_git': 'https://pdfium.googlesource.com', @@ -42,7 +42,7 @@ 'boringssl_git': 'https://boringssl.googlesource.com', 'libvpx_revision': 'd1c022c097f22987d521643c4802b623e572393a', 'sfntly_revision': '1bdaae8fc788a5ac8936d68bf24f37d977a13dac', - 'skia_revision': '27e517ae533775889c98c65fa2f07b98357ecbc2', + 'skia_revision': '465706820d0d373f76ab4831c286115ee0d86b7a', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling Skia # and V8 without interference from each other. @@ -58,7 +58,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling ANGLE # and whatever else without interference from each other. - 'angle_revision': '21ce9b02de90b81d3c3fab95f02ad45fbffd7350', + 'angle_revision': '8befcff50d9d3c3f8b1295eb420e9cd4beeae2f4', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling build tools # and whatever else without interference from each other. @@ -70,11 +70,11 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling openmax_dl # and whatever else without interference from each other. - 'openmax_dl_revision': '0b238cb62c32b6f45680cf577eddb1b051ae0219', + 'openmax_dl_revision': '22bb1085a6a0f6f3589a8c3d60ed0a9b82248275', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling BoringSSL # and whatever else without interference from each other. - 'boringssl_revision': '771a138f2612c581a547cb3f045b3f6753fe5571', + 'boringssl_revision': '966003273dc1a8b92f376aefa81232f14eecde8a', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling nss # and whatever else without interference from each other. @@ -94,7 +94,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling NaCl # and whatever else without interference from each other. - 'nacl_revision': 'b5365b48a73962904e04229ca3bf97948d03d034', + 'nacl_revision': '862ca265aa1fdcabe8b3ab518251381bfbf48468', } # Only these hosts are allowed for dependencies in this DEPS file. @@ -138,7 +138,7 @@ Var('chromium_git') + '/chromium/blink.git' + '@' + Var('webkit_revision'), 'src/third_party/icu': - Var('chromium_git') + '/chromium/deps/icu.git' + '@' + 'ce41627e388fb46ab49671bd16a5db81dcd75a71', + Var('chromium_git') + '/chromium/deps/icu.git' + '@' + '5788e2736b3bc642994b6351a6096124895afa01', 'src/third_party/libexif/sources': Var('chromium_git') + '/chromium/deps/libexif/sources.git' + '@' + 'ed98343daabd7b4497f97fda972e132e6877c48a', @@ -210,7 +210,7 @@ Var('chromium_git') + '/external/usrsctplib.git' + '@' + '36444a999739e9e408f8f587cb4c3ffeef2e50ac', # from svn revision 9215 'src/third_party/libsrtp': - Var('chromium_git') + '/chromium/deps/libsrtp.git' + '@' + '6446144c7f083552f21cc4e6768e891bcb767574', + Var('chromium_git') + '/chromium/deps/libsrtp.git' + '@' + '9c53f858cddd4d890e405e91ff3af0b48dfd90e6', # from svn revision 295151 'src/third_party/yasm/source/patched-yasm': Var('chromium_git') + '/chromium/deps/yasm/patched-yasm.git' + '@' + '4671120cd8558ce62ee8672ebf3eb6f5216f909b', @@ -426,7 +426,7 @@ Var('chromium_git') + '/external/android_protobuf.git' + '@' + '94f522f907e3f34f70d9e7816b947e62fddbb267', 'src/third_party/android_tools': - Var('chromium_git') + '/android_tools.git' + '@' + '0c03d3bfef2606a30c3ccec9f6856e6acb75c2fb', + Var('chromium_git') + '/android_tools.git' + '@' + '3445d55bd6a9bedd04ecd9deabc9071fa5b93ca1', 'src/third_party/apache-mime4j': Var('chromium_git') + '/chromium/deps/apache-mime4j.git' + '@' + '28cb1108bff4b6cf0a2e86ff58b3d025934ebe3a',
diff --git a/android_webview/browser/aw_browser_context.cc b/android_webview/browser/aw_browser_context.cc index e6587fc..fbdb5cd 100644 --- a/android_webview/browser/aw_browser_context.cc +++ b/android_webview/browser/aw_browser_context.cc
@@ -171,7 +171,8 @@ new data_reduction_proxy::DataReductionProxyService( scoped_ptr< data_reduction_proxy::DataReductionProxyCompressionStats>(), - data_reduction_proxy_settings_.get(), GetAwURLRequestContext(), + data_reduction_proxy_settings_.get(), nullptr, + GetAwURLRequestContext(), BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO))); data_reduction_proxy_io_data_->SetDataReductionProxyService( data_reduction_proxy_service_->GetWeakPtr());
diff --git a/android_webview/browser/aw_dev_tools_discovery_provider.cc b/android_webview/browser/aw_dev_tools_discovery_provider.cc index 4117358..fe1e61e 100644 --- a/android_webview/browser/aw_dev_tools_discovery_provider.cc +++ b/android_webview/browser/aw_dev_tools_discovery_provider.cc
@@ -35,7 +35,7 @@ description.SetInteger("height", screen_rect.height()); } std::string json; - base::JSONWriter::Write(&description, &json); + base::JSONWriter::Write(description, &json); return json; }
diff --git a/android_webview/java/src/org/chromium/android_webview/AwContents.java b/android_webview/java/src/org/chromium/android_webview/AwContents.java index 0a0e853..972360b 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwContents.java +++ b/android_webview/java/src/org/chromium/android_webview/AwContents.java
@@ -77,6 +77,7 @@ import java.util.HashMap; import java.util.Locale; import java.util.Map; +import java.util.WeakHashMap; import java.util.concurrent.Callable; /** @@ -207,7 +208,7 @@ private final Context mContext; private final int mAppTargetSdkVersion; private ContentViewCore mContentViewCore; - private WindowAndroid mWindowAndroid; + private WindowAndroidWrapper mWindowAndroid; private WebContents mWebContents; private NavigationController mNavigationController; private final AwContentsClient mContentsClient; @@ -287,16 +288,13 @@ private static final class DestroyRunnable implements Runnable { private final long mNativeAwContents; - private final WindowAndroid mWindowAndroid; - private DestroyRunnable(long nativeAwContents, WindowAndroid windowAndroid) { + private DestroyRunnable(long nativeAwContents) { mNativeAwContents = nativeAwContents; - mWindowAndroid = windowAndroid; } @Override public void run() { nativeDestroy(mNativeAwContents); - mWindowAndroid.destroy(); } } @@ -848,6 +846,60 @@ mContainerView.requestLayout(); } + // This class destroys the WindowAndroid when after it is gc-ed. + private static class WindowAndroidWrapper { + private final WindowAndroid mWindowAndroid; + private final CleanupReference mCleanupReference; + + private static final class DestroyRunnable implements Runnable { + private final WindowAndroid mWindowAndroid; + private DestroyRunnable(WindowAndroid windowAndroid) { + mWindowAndroid = windowAndroid; + } + @Override + public void run() { + mWindowAndroid.destroy(); + } + } + + public WindowAndroidWrapper(WindowAndroid windowAndroid) { + mWindowAndroid = windowAndroid; + mCleanupReference = + new CleanupReference(this, new DestroyRunnable(windowAndroid)); + } + + public WindowAndroid getWindowAndroid() { + return mWindowAndroid; + } + } + private static WindowAndroidWrapper sCachedWindowAndroid; + private static WeakHashMap<Activity, WindowAndroidWrapper> sActivityWindowMap; + + // getWindowAndroid is only called on UI thread, so there are no threading issues with lazy + // initialization. + @SuppressFBWarnings("LI_LAZY_INIT_STATIC") + private static WindowAndroidWrapper getWindowAndroid(Context context) { + // TODO(boliu): WebView does not currently initialize ApplicationStatus, crbug.com/470582. + Activity activity = ContentViewCore.activityFromContext(context); + if (activity == null) { + if (sCachedWindowAndroid == null) { + sCachedWindowAndroid = new WindowAndroidWrapper( + new WindowAndroid(context.getApplicationContext())); + } + return sCachedWindowAndroid; + } + + if (sActivityWindowMap == null) sActivityWindowMap = new WeakHashMap<>(); + WindowAndroidWrapper activityWindowAndroid = sActivityWindowMap.get(activity); + if (activityWindowAndroid == null) { + final boolean listenToActivityState = false; + activityWindowAndroid = new WindowAndroidWrapper( + new ActivityWindowAndroid(activity, listenToActivityState)); + sActivityWindowMap.put(activity, activityWindowAndroid); + } + return activityWindowAndroid; + } + /* Common initialization routine for adopting a native AwContents instance into this * java instance. * @@ -871,15 +923,10 @@ WebContents webContents = nativeGetWebContents(mNativeAwContents); - // WebView does not currently initialize ApplicationStatus, crbug.com/470582. - final boolean listenToActivityState = false; - Activity activity = ContentViewCore.activityFromContext(mContext); - mWindowAndroid = activity != null - ? new ActivityWindowAndroid(activity, listenToActivityState) - : new WindowAndroid(mContext.getApplicationContext()); - mContentViewCore = createAndInitializeContentViewCore( - mContainerView, mContext, mInternalAccessAdapter, webContents, - new AwGestureStateListener(), mContentViewClient, mZoomControls, mWindowAndroid); + mWindowAndroid = getWindowAndroid(mContext); + mContentViewCore = createAndInitializeContentViewCore(mContainerView, mContext, + mInternalAccessAdapter, webContents, new AwGestureStateListener(), + mContentViewClient, mZoomControls, mWindowAndroid.getWindowAndroid()); nativeSetJavaPeers(mNativeAwContents, this, mWebContentsDelegate, mContentsClientBridge, mIoThreadClient, mInterceptNavigationDelegate); mWebContents = mContentViewCore.getWebContents(); @@ -892,7 +939,7 @@ // The native side object has been bound to this java instance, so now is the time to // bind all the native->java relationships. mCleanupReference = - new CleanupReference(this, new DestroyRunnable(mNativeAwContents, mWindowAndroid)); + new CleanupReference(this, new DestroyRunnable(mNativeAwContents)); } private void installWebContentsObserver() { @@ -2452,7 +2499,7 @@ @CalledByNative private void postInvalidateOnAnimation() { - if (!mWindowAndroid.isInsideVSync()) { + if (!mWindowAndroid.getWindowAndroid().isInsideVSync()) { mContainerView.postInvalidateOnAnimation(); } else { mContainerView.invalidate();
diff --git a/android_webview/renderer/aw_render_view_ext.cc b/android_webview/renderer/aw_render_view_ext.cc index c2877c5..7aa901d5 100644 --- a/android_webview/renderer/aw_render_view_ext.cc +++ b/android_webview/renderer/aw_render_view_ext.cc
@@ -247,12 +247,12 @@ if (node.isNull() || !node.isElementNode() || !render_view()) return; - // Note: element is not const due to innerText() is not const. + // Note: element is not const due to textContent() is not const. blink::WebElement element = node.toConst<blink::WebElement>(); AwHitTestData data; data.href = GetHref(element); - data.anchor_text = element.innerText(); + data.anchor_text = element.textContent(); GURL absolute_link_url; if (node.isLink()) @@ -280,7 +280,7 @@ GURL absolute_image_url = result.absoluteImageURL(); if (!result.urlElement().isNull()) { - data.anchor_text = result.urlElement().innerText(); + data.anchor_text = result.urlElement().textContent(); data.href = GetHref(result.urlElement()); // If we hit an image that failed to load, Blink won't give us its URL. // Fall back to walking the DOM in this case.
diff --git a/ash/accelerators/key_hold_detector.cc b/ash/accelerators/key_hold_detector.cc index 8326d9a..46c17ea 100644 --- a/ash/accelerators/key_hold_detector.cc +++ b/ash/accelerators/key_hold_detector.cc
@@ -4,11 +4,6 @@ #include "ash/accelerators/key_hold_detector.h" -#include <X11/Xlib.h> - -#undef RootWindow -#undef Status - #include "ash/shell.h" #include "base/message_loop/message_loop.h" #include "ui/aura/window_tracker.h"
diff --git a/ash/ash.gyp b/ash/ash.gyp index e8e819b..082a6f8 100644 --- a/ash/ash.gyp +++ b/ash/ash.gyp
@@ -43,6 +43,8 @@ 'autoclick/autoclick_controller.h', 'cancel_mode.cc', 'cancel_mode.h', + 'cast_config_delegate.cc', + 'cast_config_delegate.h', 'content/display/display_color_manager_chromeos.cc', 'content/display/display_color_manager_chromeos.h', 'content/display/screen_orientation_controller_chromeos.cc',
diff --git a/ash/cast_config_delegate.cc b/ash/cast_config_delegate.cc new file mode 100644 index 0000000..5cbbc07 --- /dev/null +++ b/ash/cast_config_delegate.cc
@@ -0,0 +1,27 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/cast_config_delegate.h" + +namespace ash { + +CastConfigDelegate::Receiver::Receiver() { +} + +CastConfigDelegate::Receiver::~Receiver() { +} + +CastConfigDelegate::Activity::Activity() { +} + +CastConfigDelegate::Activity::~Activity() { +} + +CastConfigDelegate::ReceiverAndActivity::ReceiverAndActivity() { +} + +CastConfigDelegate::ReceiverAndActivity::~ReceiverAndActivity() { +} + +} // namespace ash
diff --git a/ash/cast_config_delegate.h b/ash/cast_config_delegate.h new file mode 100644 index 0000000..2f5e334 --- /dev/null +++ b/ash/cast_config_delegate.h
@@ -0,0 +1,103 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_CAST_CONFIG_DELEGATE_H_ +#define ASH_CAST_CONFIG_DELEGATE_H_ + +#include <map> +#include <string> + +#include "ash/ash_export.h" +#include "base/callback.h" +#include "base/macros.h" +#include "base/memory/scoped_ptr.h" +#include "base/strings/string16.h" +#include "url/gurl.h" + +namespace ash { + +// This delegate allows the UI code in ash, e.g. |TrayCastDetailedView|, +// to access the cast extension. +class CastConfigDelegate { + public: + struct ASH_EXPORT Receiver { + Receiver(); + ~Receiver(); + + std::string id; + base::string16 name; + }; + + struct ASH_EXPORT Activity { + // The tab identifier that we are casting. These are the special tab values + // taken from the chromecast extension itself. If an actual tab is being + // casted, then the TabId will be >= 0. + enum TabId { + EXTENSION = -1, + DESKTOP = -2, + DISCOVERED_ACTIVITY = -3, + EXTERNAL_EXTENSION_CLIENT = -4 + }; + + Activity(); + ~Activity(); + + std::string id; + base::string16 title; + std::string activity_type; + bool allow_stop = false; + + // The id for the tab we are casting. Could be one of the TabId values, + // or a value >= 0 that represents that tab index of the tab we are + // casting. We default to casting the desktop, as a tab may not + // necessarily exist. + int tab_id = TabId::DESKTOP; + }; + + struct ASH_EXPORT ReceiverAndActivity { + ReceiverAndActivity(); + ~ReceiverAndActivity(); + + Receiver receiver; + Activity activity; + }; + + // The key is the receiver id. + using ReceiversAndActivites = std::map<std::string, ReceiverAndActivity>; + using ReceiversAndActivitesCallback = + base::Callback<void(const ReceiversAndActivites&)>; + + virtual ~CastConfigDelegate() {} + + // Returns true if cast extension is installed. + virtual bool HasCastExtension() const = 0; + + // Fetches the current set of receivers and their possible activities. This + // method will lookup the current chromecast extension and query its current + // state. The |callback| will be invoked when the receiver/activity data is + // available. + virtual void GetReceiversAndActivities( + const ReceiversAndActivitesCallback& callback) = 0; + + // Cast to a receiver specified by |receiver_id|. + virtual void CastToReceiver(const std::string& receiver_id) = 0; + + // Stop ongoing cast. The |activity_id| is the unique identifier associated + // with the ongoing cast. Each receiver has only one possible activity + // associated with it. The |activity_id| is available by invoking + // GetReceiversAndActivities(); if the receiver is currently casting, then the + // associated activity data will have an id. This id can be used to stop the + // cast in this method. + virtual void StopCasting(const std::string& activity_id) = 0; + + // Opens Options page for cast. + virtual void LaunchCastOptions() = 0; + + private: + DISALLOW_ASSIGN(CastConfigDelegate); +}; + +} // namespace ash + +#endif // ASH_CAST_CONFIG_DELEGATE_H_
diff --git a/ash/content/display/display_color_manager_chromeos.cc b/ash/content/display/display_color_manager_chromeos.cc index 9692e624..1f177fd 100644 --- a/ash/content/display/display_color_manager_chromeos.cc +++ b/ash/content/display/display_color_manager_chromeos.cc
@@ -11,6 +11,7 @@ #include "base/format_macros.h" #include "base/logging.h" #include "base/path_service.h" +#include "base/stl_util.h" #include "base/strings/stringprintf.h" #include "chromeos/chromeos_paths.h" #include "chromeos/chromeos_switches.h" @@ -91,11 +92,7 @@ DisplayColorManager::~DisplayColorManager() { configurator_->RemoveObserver(this); - - for (auto it : calibration_map_) { - delete it.second; - calibration_map_.erase(it.first); - } + STLDeleteValues(&calibration_map_); } void DisplayColorManager::OnDisplayModeChanged(
diff --git a/ash/metrics/task_switch_metrics_recorder.cc b/ash/metrics/task_switch_metrics_recorder.cc index 667c7e4..b8b57fe 100644 --- a/ash/metrics/task_switch_metrics_recorder.cc +++ b/ash/metrics/task_switch_metrics_recorder.cc
@@ -13,12 +13,31 @@ const char kShelfHistogramName[] = "Ash.Shelf.TimeBetweenNavigateToTaskSwitches"; +const char kTabStripHistogramName[] = + "Ash.Tab.TimeBetweenSwitchToExistingTabUserActions"; + +const char kAcceleratorWindowCycleHistogramName[] = + "Ash.WindowCycleController.TimeBetweenTaskSwitches"; + +const char kAppListHistogramName[] = "Ash.AppList.TimeBetweenTaskSwitches"; + +const char kOverviewModeHistogramName[] = + "Ash.WindowSelector.TimeBetweenActiveWindowChanges"; + // Returns the histogram name for the given |task_switch_source|. const char* GetHistogramName( TaskSwitchMetricsRecorder::TaskSwitchSource task_switch_source) { switch (task_switch_source) { + case TaskSwitchMetricsRecorder::kAppList: + return kAppListHistogramName; + case TaskSwitchMetricsRecorder::kOverviewMode: + return kOverviewModeHistogramName; case TaskSwitchMetricsRecorder::kShelf: return kShelfHistogramName; + case TaskSwitchMetricsRecorder::kTabStrip: + return kTabStripHistogramName; + case TaskSwitchMetricsRecorder::kWindowCycleController: + return kAcceleratorWindowCycleHistogramName; } NOTREACHED(); return nullptr;
diff --git a/ash/metrics/task_switch_metrics_recorder.h b/ash/metrics/task_switch_metrics_recorder.h index 87a77600..b2103be 100644 --- a/ash/metrics/task_switch_metrics_recorder.h +++ b/ash/metrics/task_switch_metrics_recorder.h
@@ -22,8 +22,17 @@ // Enumeration of the different user interfaces that could be the source of // a task switch. Note this is not necessarily comprehensive of all sources. enum TaskSwitchSource { + // Task switches from selecting items in the app list. + kAppList, + // Task switches caused by selecting a window from overview mode which is + // different from the previously-active window. + kOverviewMode, // All task switches caused by shelf buttons, not including sub-menus. - kShelf + kShelf, + // All task switches caused by the tab strip. + kTabStrip, + // Task switches caused by the WindowCycleController (ie Alt+Tab). + kWindowCycleController }; TaskSwitchMetricsRecorder();
diff --git a/ash/metrics/task_switch_metrics_recorder_unittest.cc b/ash/metrics/task_switch_metrics_recorder_unittest.cc index 155be5b..90a0db1 100644 --- a/ash/metrics/task_switch_metrics_recorder_unittest.cc +++ b/ash/metrics/task_switch_metrics_recorder_unittest.cc
@@ -62,6 +62,21 @@ } // namespace +// Verifies that the TaskSwitchMetricsRecorder::kWindowCycleController source +// adds data to the Ash.WindowCycleController.TimeBetweenTaskSwitches histogram. +TEST_F(TaskSwitchMetricsRecorderTest, + VerifyTaskSwitchesForWindowCycleControllerAreRecorded) { + const std::string kHistogramName = + "Ash.WindowCycleController.TimeBetweenTaskSwitches"; + + OnTaskSwitch(TaskSwitchMetricsRecorder::kWindowCycleController); + OnTaskSwitch(TaskSwitchMetricsRecorder::kWindowCycleController); + histogram_tester_->ExpectTotalCount(kHistogramName, 1); + + OnTaskSwitch(TaskSwitchMetricsRecorder::kWindowCycleController); + histogram_tester_->ExpectTotalCount(kHistogramName, 2); +} + // Verifies that the TaskSwitchMetricsRecorder::kShelf source adds data to the // Ash.Shelf.TimeBetweenNavigateToTaskSwitches histogram. TEST_F(TaskSwitchMetricsRecorderTest, @@ -77,4 +92,48 @@ histogram_tester_->ExpectTotalCount(kHistogramName, 2); } +// Verifies that the TaskSwitchMetricsRecorder::kTabStrip source adds data to +// the Ash.Tab.TimeBetweenSwitchToExistingTabUserActions histogram. +TEST_F(TaskSwitchMetricsRecorderTest, + VerifyTaskSwitchesFromTheTabStripAreRecorded) { + const std::string kHistogramName = + "Ash.Tab.TimeBetweenSwitchToExistingTabUserActions"; + + OnTaskSwitch(TaskSwitchMetricsRecorder::kTabStrip); + OnTaskSwitch(TaskSwitchMetricsRecorder::kTabStrip); + histogram_tester_->ExpectTotalCount(kHistogramName, 1); + + OnTaskSwitch(TaskSwitchMetricsRecorder::kTabStrip); + histogram_tester_->ExpectTotalCount(kHistogramName, 2); +} + +// Verifies that the TaskSwitchMetricsRecorder::kOverviewMode source adds data +// to the Ash.WindowSelector.TimeBetweenActiveWindowChanges histogram. +TEST_F(TaskSwitchMetricsRecorderTest, + VerifyTaskSwitchesFromOverviewModeAreRecorded) { + const std::string kHistogramName = + "Ash.WindowSelector.TimeBetweenActiveWindowChanges"; + + OnTaskSwitch(TaskSwitchMetricsRecorder::kOverviewMode); + OnTaskSwitch(TaskSwitchMetricsRecorder::kOverviewMode); + histogram_tester_->ExpectTotalCount(kHistogramName, 1); + + OnTaskSwitch(TaskSwitchMetricsRecorder::kOverviewMode); + histogram_tester_->ExpectTotalCount(kHistogramName, 2); +} + +// Verifies that the TaskSwitchMetricsRecorder::kAppList source adds data to the +// Ash.AppList.TimeBetweenTaskSwitches histogram. +TEST_F(TaskSwitchMetricsRecorderTest, + VerifyTaskSwitchesFromApplistAreRecorded) { + const std::string kHistogramName = "Ash.AppList.TimeBetweenTaskSwitches"; + + OnTaskSwitch(TaskSwitchMetricsRecorder::kAppList); + OnTaskSwitch(TaskSwitchMetricsRecorder::kAppList); + histogram_tester_->ExpectTotalCount(kHistogramName, 1); + + OnTaskSwitch(TaskSwitchMetricsRecorder::kAppList); + histogram_tester_->ExpectTotalCount(kHistogramName, 2); +} + } // namespace ash
diff --git a/ash/metrics/user_metrics_recorder.cc b/ash/metrics/user_metrics_recorder.cc index e992940..cfc4d8e 100644 --- a/ash/metrics/user_metrics_recorder.cc +++ b/ash/metrics/user_metrics_recorder.cc
@@ -584,6 +584,8 @@ case ash::UMA_WINDOW_OVERVIEW_ACTIVE_WINDOW_CHANGED: base::RecordAction( base::UserMetricsAction("WindowSelector_ActiveWindowChanged")); + task_switch_metrics_recorder_.OnTaskSwitch( + TaskSwitchMetricsRecorder::kOverviewMode); break; case ash::UMA_WINDOW_OVERVIEW_ENTER_KEY: base::RecordAction(
diff --git a/ash/metrics/user_metrics_recorder.h b/ash/metrics/user_metrics_recorder.h index 956bb40..7bb6f9d 100644 --- a/ash/metrics/user_metrics_recorder.h +++ b/ash/metrics/user_metrics_recorder.h
@@ -149,6 +149,10 @@ // Records an Ash owned user action. void RecordUserMetricsAction(ash::UserMetricsAction action); + TaskSwitchMetricsRecorder& task_switch_metrics_recorder() { + return task_switch_metrics_recorder_; + } + private: friend class test::UserMetricsRecorderTestAPI;
diff --git a/ash/rotator/screen_rotation_animator.cc b/ash/rotator/screen_rotation_animator.cc index 9b746b68..742ade9 100644 --- a/ash/rotator/screen_rotation_animator.cc +++ b/ash/rotator/screen_rotation_animator.cc
@@ -12,6 +12,7 @@ #include "ash/display/display_info.h" #include "ash/display/display_manager.h" #include "ash/rotator/screen_rotation_animation.h" +#include "ash/session/session_state_delegate.h" #include "ash/shell.h" #include "base/command_line.h" #include "base/time/time.h" @@ -280,10 +281,19 @@ } bool ScreenRotationAnimator::CanAnimate() const { + // Animations are currently broken on the login screen. + // (chrome-os-partners:40118). Disabling the animations on this screen for + // M-43 return Shell::GetInstance() - ->display_manager() - ->GetDisplayForId(display_id_) - .is_valid(); + ->display_manager() + ->GetDisplayForId(display_id_) + .is_valid() && + Shell::GetInstance() + ->session_state_delegate() + ->IsActiveUserSessionStarted() && + !Shell::GetInstance()->session_state_delegate()->IsScreenLocked() && + Shell::GetInstance()->session_state_delegate()->GetSessionState() == + SessionStateDelegate::SESSION_STATE_ACTIVE; } void ScreenRotationAnimator::Rotate(gfx::Display::Rotation new_rotation,
diff --git a/ash/system/tray/system_tray_delegate.cc b/ash/system/tray/system_tray_delegate.cc index eaab406..ed999b6a 100644 --- a/ash/system/tray/system_tray_delegate.cc +++ b/ash/system/tray/system_tray_delegate.cc
@@ -223,6 +223,10 @@ void SystemTrayDelegate::ChangeProxySettings() { } +CastConfigDelegate* SystemTrayDelegate::GetCastConfigDelegate() const { + return nullptr; +} + NetworkingConfigDelegate* SystemTrayDelegate::GetNetworkingConfigDelegate() const { return nullptr;
diff --git a/ash/system/tray/system_tray_delegate.h b/ash/system/tray/system_tray_delegate.h index fb2601a..857ee093 100644 --- a/ash/system/tray/system_tray_delegate.h +++ b/ash/system/tray/system_tray_delegate.h
@@ -98,6 +98,7 @@ using IMEInfoList = std::vector<IMEInfo>; +class CastConfigDelegate; class NetworkingConfigDelegate; class VPNDelegate; @@ -284,6 +285,9 @@ // Shows UI for changing proxy settings. virtual void ChangeProxySettings(); + // Returns CastConfigDelegate. May return nullptr. + virtual CastConfigDelegate* GetCastConfigDelegate() const; + // Returns NetworkingConfigDelegate. May return nullptr. virtual NetworkingConfigDelegate* GetNetworkingConfigDelegate() const;
diff --git a/ash/wm/window_cycle_controller.cc b/ash/wm/window_cycle_controller.cc index 42f866e..d2366c3 100644 --- a/ash/wm/window_cycle_controller.cc +++ b/ash/wm/window_cycle_controller.cc
@@ -4,11 +4,13 @@ #include "ash/wm/window_cycle_controller.h" +#include "ash/metrics/user_metrics_recorder.h" #include "ash/session/session_state_delegate.h" #include "ash/shell.h" #include "ash/wm/mru_window_tracker.h" #include "ash/wm/window_cycle_list.h" #include "base/metrics/histogram.h" +#include "ui/aura/window.h" #include "ui/events/event.h" #include "ui/events/event_handler.h" @@ -16,6 +18,12 @@ namespace { +// Returns the most recently active window from the |window_list| or nullptr +// if the list is empty. +aura::Window* GetActiveWindow(const MruWindowTracker::WindowList& window_list) { + return window_list.empty() ? nullptr : window_list[0]; +} + // Filter to watch for the termination of a keyboard gesture to cycle through // multiple windows. class WindowCycleEventFilter : public ui::EventHandler { @@ -77,8 +85,12 @@ } void WindowCycleController::StartCycling() { - window_cycle_list_.reset(new WindowCycleList(ash::Shell::GetInstance()-> - mru_window_tracker()->BuildMruWindowList())); + MruWindowTracker::WindowList window_list = + Shell::GetInstance()->mru_window_tracker()->BuildMruWindowList(); + + active_window_before_window_cycle_ = GetActiveWindow(window_list); + + window_cycle_list_.reset(new WindowCycleList(window_list)); event_handler_.reset(new WindowCycleEventFilter()); cycle_start_time_ = base::Time::Now(); Shell::GetInstance()->metrics()->RecordUserMetricsAction(UMA_WINDOW_CYCLE); @@ -94,10 +106,23 @@ void WindowCycleController::StopCycling() { window_cycle_list_.reset(); + + aura::Window* active_window_after_window_cycle = GetActiveWindow( + Shell::GetInstance()->mru_window_tracker()->BuildMruWindowList()); + // Remove our key event filter. event_handler_.reset(); UMA_HISTOGRAM_MEDIUM_TIMES("Ash.WindowCycleController.CycleTime", base::Time::Now() - cycle_start_time_); + + if (active_window_after_window_cycle != nullptr && + active_window_before_window_cycle_ != active_window_after_window_cycle) { + Shell::GetInstance() + ->metrics() + ->task_switch_metrics_recorder() + .OnTaskSwitch(TaskSwitchMetricsRecorder::kWindowCycleController); + } + active_window_before_window_cycle_ = nullptr; } } // namespace ash
diff --git a/ash/wm/window_cycle_controller.h b/ash/wm/window_cycle_controller.h index 4120bc05..8cfd2a58 100644 --- a/ash/wm/window_cycle_controller.h +++ b/ash/wm/window_cycle_controller.h
@@ -14,6 +14,10 @@ class EventHandler; } +namespace aura { +class Window; +} // namespace aura + namespace ash { class WindowCycleList; @@ -63,6 +67,10 @@ scoped_ptr<WindowCycleList> window_cycle_list_; + // Tracks what Window was active when starting to cycle and used to determine + // if the active Window changed in when ending cycling. + aura::Window* active_window_before_window_cycle_ = nullptr; + // Event handler to watch for release of alt key. scoped_ptr<ui::EventHandler> event_handler_;
diff --git a/base/json/json_string_value_serializer.cc b/base/json/json_string_value_serializer.cc index debf9f08..3787fdb6d 100644 --- a/base/json/json_string_value_serializer.cc +++ b/base/json/json_string_value_serializer.cc
@@ -37,7 +37,7 @@ if (pretty_print_) options |= base::JSONWriter::OPTIONS_PRETTY_PRINT; - return base::JSONWriter::WriteWithOptions(&root, options, json_string_); + return base::JSONWriter::WriteWithOptions(root, options, json_string_); } JSONStringValueDeserializer::JSONStringValueDeserializer(
diff --git a/base/json/json_value_serializer_unittest.cc b/base/json/json_value_serializer_unittest.cc index b8aebe06..61860fd 100644 --- a/base/json/json_value_serializer_unittest.cc +++ b/base/json/json_value_serializer_unittest.cc
@@ -302,7 +302,7 @@ std::string output_js; DictionaryValue valueRoot; valueRoot.SetString("all_chars", all_chars); - JSONWriter::Write(&valueRoot, &output_js); + JSONWriter::Write(valueRoot, &output_js); ASSERT_EQ(expected_output, output_js); // Test JSONValueSerializer interface (uses JSONWriter).
diff --git a/base/json/json_writer.cc b/base/json/json_writer.cc index d14c92c0..abfead800 100644 --- a/base/json/json_writer.cc +++ b/base/json/json_writer.cc
@@ -21,12 +21,13 @@ #endif // static -bool JSONWriter::Write(const Value* const node, std::string* json) { +bool JSONWriter::Write(const Value& node, std::string* json) { return WriteWithOptions(node, 0, json); } // static -bool JSONWriter::WriteWithOptions(const Value* const node, int options, +bool JSONWriter::WriteWithOptions(const Value& node, + int options, std::string* json) { json->clear(); // Is there a better way to estimate the size of the output? @@ -50,8 +51,8 @@ DCHECK(json); } -bool JSONWriter::BuildJSONString(const Value* const node, size_t depth) { - switch (node->GetType()) { +bool JSONWriter::BuildJSONString(const Value& node, size_t depth) { + switch (node.GetType()) { case Value::TYPE_NULL: { json_string_->append("null"); return true; @@ -59,7 +60,7 @@ case Value::TYPE_BOOLEAN: { bool value; - bool result = node->GetAsBoolean(&value); + bool result = node.GetAsBoolean(&value); DCHECK(result); json_string_->append(value ? "true" : "false"); return result; @@ -67,7 +68,7 @@ case Value::TYPE_INTEGER: { int value; - bool result = node->GetAsInteger(&value); + bool result = node.GetAsInteger(&value); DCHECK(result); json_string_->append(IntToString(value)); return result; @@ -75,7 +76,7 @@ case Value::TYPE_DOUBLE: { double value; - bool result = node->GetAsDouble(&value); + bool result = node.GetAsDouble(&value); DCHECK(result); if (omit_double_type_preservation_ && value <= kint64max && @@ -107,7 +108,7 @@ case Value::TYPE_STRING: { std::string value; - bool result = node->GetAsString(&value); + bool result = node.GetAsString(&value); DCHECK(result); EscapeJSONString(value, true, json_string_); return result; @@ -120,7 +121,7 @@ const ListValue* list = NULL; bool first_value_has_been_output = false; - bool result = node->GetAsList(&list); + bool result = node.GetAsList(&list); DCHECK(result); for (ListValue::const_iterator it = list->begin(); it != list->end(); ++it) { @@ -134,7 +135,7 @@ json_string_->push_back(' '); } - if (!BuildJSONString(value, depth)) + if (!BuildJSONString(*value, depth)) result = false; first_value_has_been_output = true; @@ -153,7 +154,7 @@ const DictionaryValue* dict = NULL; bool first_value_has_been_output = false; - bool result = node->GetAsDictionary(&dict); + bool result = node.GetAsDictionary(&dict); DCHECK(result); for (DictionaryValue::Iterator itr(*dict); !itr.IsAtEnd(); itr.Advance()) { @@ -176,7 +177,7 @@ if (pretty_print_) json_string_->push_back(' '); - if (!BuildJSONString(&itr.value(), depth + 1U)) + if (!BuildJSONString(itr.value(), depth + 1U)) result = false; first_value_has_been_output = true;
diff --git a/base/json/json_writer.h b/base/json/json_writer.h index 9709c7e7..5711665 100644 --- a/base/json/json_writer.h +++ b/base/json/json_writer.h
@@ -38,11 +38,12 @@ // TODO(tc): Should we generate json if it would be invalid json (e.g., // |node| is not a DictionaryValue/ListValue or if there are inf/-inf float // values)? Return true on success and false on failure. - static bool Write(const Value* const node, std::string* json); + static bool Write(const Value& node, std::string* json); // Same as above but with |options| which is a bunch of JSONWriter::Options // bitwise ORed together. Return true on success and false on failure. - static bool WriteWithOptions(const Value* const node, int options, + static bool WriteWithOptions(const Value& node, + int options, std::string* json); private: @@ -50,7 +51,7 @@ // Called recursively to build the JSON string. When completed, // |json_string_| will contain the JSON. - bool BuildJSONString(const Value* const node, size_t depth); + bool BuildJSONString(const Value& node, size_t depth); // Adds space to json_string_ for the indent level. void IndentLine(size_t depth);
diff --git a/base/json/json_writer_unittest.cc b/base/json/json_writer_unittest.cc index 5ac2590..0daeafc 100644 --- a/base/json/json_writer_unittest.cc +++ b/base/json/json_writer_unittest.cc
@@ -12,47 +12,39 @@ std::string output_js; // Test null. - EXPECT_TRUE(JSONWriter::Write(Value::CreateNullValue().get(), &output_js)); + EXPECT_TRUE(JSONWriter::Write(*Value::CreateNullValue(), &output_js)); EXPECT_EQ("null", output_js); // Test empty dict. - DictionaryValue dict; - EXPECT_TRUE(JSONWriter::Write(&dict, &output_js)); + EXPECT_TRUE(JSONWriter::Write(DictionaryValue(), &output_js)); EXPECT_EQ("{}", output_js); // Test empty list. - ListValue list; - EXPECT_TRUE(JSONWriter::Write(&list, &output_js)); + EXPECT_TRUE(JSONWriter::Write(ListValue(), &output_js)); EXPECT_EQ("[]", output_js); // Test integer values. - FundamentalValue int_value(42); - EXPECT_TRUE(JSONWriter::Write(&int_value, &output_js)); + EXPECT_TRUE(JSONWriter::Write(FundamentalValue(42), &output_js)); EXPECT_EQ("42", output_js); // Test boolean values. - FundamentalValue bool_value(true); - EXPECT_TRUE(JSONWriter::Write(&bool_value, &output_js)); + EXPECT_TRUE(JSONWriter::Write(FundamentalValue(true), &output_js)); EXPECT_EQ("true", output_js); // Test Real values should always have a decimal or an 'e'. - FundamentalValue double_value(1.0); - EXPECT_TRUE(JSONWriter::Write(&double_value, &output_js)); + EXPECT_TRUE(JSONWriter::Write(FundamentalValue(1.0), &output_js)); EXPECT_EQ("1.0", output_js); // Test Real values in the the range (-1, 1) must have leading zeros - FundamentalValue double_value2(0.2); - EXPECT_TRUE(JSONWriter::Write(&double_value2, &output_js)); + EXPECT_TRUE(JSONWriter::Write(FundamentalValue(0.2), &output_js)); EXPECT_EQ("0.2", output_js); // Test Real values in the the range (-1, 1) must have leading zeros - FundamentalValue double_value3(-0.8); - EXPECT_TRUE(JSONWriter::Write(&double_value3, &output_js)); + EXPECT_TRUE(JSONWriter::Write(FundamentalValue(-0.8), &output_js)); EXPECT_EQ("-0.8", output_js); // Test String values. - StringValue string_value("foo"); - EXPECT_TRUE(JSONWriter::Write(&string_value, &output_js)); + EXPECT_TRUE(JSONWriter::Write(StringValue("foo"), &output_js)); EXPECT_EQ("\"foo\"", output_js); } @@ -71,11 +63,10 @@ root_dict.Set("list", list.Pass()); // Test the pretty-printer. - EXPECT_TRUE(JSONWriter::Write(&root_dict, &output_js)); + EXPECT_TRUE(JSONWriter::Write(root_dict, &output_js)); EXPECT_EQ("{\"list\":[{\"inner int\":10},[],true]}", output_js); - EXPECT_TRUE(JSONWriter::WriteWithOptions(&root_dict, - JSONWriter::OPTIONS_PRETTY_PRINT, - &output_js)); + EXPECT_TRUE(JSONWriter::WriteWithOptions( + root_dict, JSONWriter::OPTIONS_PRETTY_PRINT, &output_js)); // The pretty-printer uses a different newline style on Windows than on // other platforms. @@ -102,13 +93,13 @@ scoped_ptr<DictionaryValue> period_dict2(new DictionaryValue()); period_dict2->SetIntegerWithoutPathExpansion("g.h.i.j", 1); period_dict.SetWithoutPathExpansion("d.e.f", period_dict2.Pass()); - EXPECT_TRUE(JSONWriter::Write(&period_dict, &output_js)); + EXPECT_TRUE(JSONWriter::Write(period_dict, &output_js)); EXPECT_EQ("{\"a.b\":3,\"c\":2,\"d.e.f\":{\"g.h.i.j\":1}}", output_js); DictionaryValue period_dict3; period_dict3.SetInteger("a.b", 2); period_dict3.SetIntegerWithoutPathExpansion("a.b", 1); - EXPECT_TRUE(JSONWriter::Write(&period_dict3, &output_js)); + EXPECT_TRUE(JSONWriter::Write(period_dict3, &output_js)); EXPECT_EQ("{\"a\":{\"b\":2},\"a.b\":1}", output_js); } @@ -118,9 +109,9 @@ // Binary values should return errors unless suppressed via the // OPTIONS_OMIT_BINARY_VALUES flag. scoped_ptr<Value> root(BinaryValue::CreateWithCopiedBuffer("asdf", 4)); - EXPECT_FALSE(JSONWriter::Write(root.get(), &output_js)); + EXPECT_FALSE(JSONWriter::Write(*root, &output_js)); EXPECT_TRUE(JSONWriter::WriteWithOptions( - root.get(), JSONWriter::OPTIONS_OMIT_BINARY_VALUES, &output_js)); + *root, JSONWriter::OPTIONS_OMIT_BINARY_VALUES, &output_js)); EXPECT_TRUE(output_js.empty()); ListValue binary_list; @@ -129,9 +120,9 @@ binary_list.Append(BinaryValue::CreateWithCopiedBuffer("asdf", 4)); binary_list.Append(make_scoped_ptr(new FundamentalValue(2))); binary_list.Append(BinaryValue::CreateWithCopiedBuffer("asdf", 4)); - EXPECT_FALSE(JSONWriter::Write(&binary_list, &output_js)); + EXPECT_FALSE(JSONWriter::Write(binary_list, &output_js)); EXPECT_TRUE(JSONWriter::WriteWithOptions( - &binary_list, JSONWriter::OPTIONS_OMIT_BINARY_VALUES, &output_js)); + binary_list, JSONWriter::OPTIONS_OMIT_BINARY_VALUES, &output_js)); EXPECT_EQ("[5,2]", output_js); DictionaryValue binary_dict; @@ -143,9 +134,9 @@ binary_dict.SetInteger("d", 2); binary_dict.Set( "e", make_scoped_ptr(BinaryValue::CreateWithCopiedBuffer("asdf", 4))); - EXPECT_FALSE(JSONWriter::Write(&binary_dict, &output_js)); + EXPECT_FALSE(JSONWriter::Write(binary_dict, &output_js)); EXPECT_TRUE(JSONWriter::WriteWithOptions( - &binary_dict, JSONWriter::OPTIONS_OMIT_BINARY_VALUES, &output_js)); + binary_dict, JSONWriter::OPTIONS_OMIT_BINARY_VALUES, &output_js)); EXPECT_EQ("{\"b\":5,\"d\":2}", output_js); } @@ -155,8 +146,7 @@ // Test allowing a double with no fractional part to be written as an integer. FundamentalValue double_value(1e10); EXPECT_TRUE(JSONWriter::WriteWithOptions( - &double_value, - JSONWriter::OPTIONS_OMIT_DOUBLE_TYPE_PRESERVATION, + double_value, JSONWriter::OPTIONS_OMIT_DOUBLE_TYPE_PRESERVATION, &output_js)); EXPECT_EQ("10000000000", output_js); }
diff --git a/base/trace_event/trace_event_argument.cc b/base/trace_event/trace_event_argument.cc index 88b1879..e83aa737 100644 --- a/base/trace_event/trace_event_argument.cc +++ b/base/trace_event/trace_event_argument.cc
@@ -108,7 +108,7 @@ void TracedValue::AppendAsTraceFormat(std::string* out) const { std::string tmp; - JSONWriter::Write(stack_.front(), &tmp); + JSONWriter::Write(*stack_.front(), &tmp); *out += tmp; DCHECK_EQ(1u, stack_.size()) << tmp; }
diff --git a/base/trace_event/trace_event_system_stats_monitor.cc b/base/trace_event/trace_event_system_stats_monitor.cc index 98f361a..c08d9b9 100644 --- a/base/trace_event/trace_event_system_stats_monitor.cc +++ b/base/trace_event/trace_event_system_stats_monitor.cc
@@ -125,7 +125,7 @@ void AppendSystemProfileAsTraceFormat(const SystemMetrics& system_metrics, std::string* output) { std::string tmp; - base::JSONWriter::Write(system_metrics.ToValue().get(), &tmp); + base::JSONWriter::Write(*system_metrics.ToValue(), &tmp); *output += tmp; }
diff --git a/base/values.cc b/base/values.cc index 4093eba..ebd7157 100644 --- a/base/values.cc +++ b/base/values.cc
@@ -1168,9 +1168,7 @@ std::ostream& operator<<(std::ostream& out, const Value& value) { std::string json; - JSONWriter::WriteWithOptions(&value, - JSONWriter::OPTIONS_PRETTY_PRINT, - &json); + JSONWriter::WriteWithOptions(value, JSONWriter::OPTIONS_PRETTY_PRINT, &json); return out << json; }
diff --git a/build/all.gyp b/build/all.gyp index 4837097..04ba3f8 100644 --- a/build/all.gyp +++ b/build/all.gyp
@@ -884,11 +884,6 @@ '../chrome/chrome.gyp:unit_tests_apk', ], }], - ['enable_webrtc==1 and "<(libpeer_target_type)"=="static_library"', { - 'dependencies': [ - '../components/devtools_bridge.gyp:devtools_bridge_tests_apk', - ], - }], ], }, { @@ -900,8 +895,6 @@ '../content/content_shell_and_tests.gyp:content_browsertests', '../tools/android/android_tools.gyp:android_tools', '../tools/android/android_tools.gyp:memconsumer', - # Unit test bundles packaged as an apk. - '../components/devtools_bridge.gyp:devtools_bridge_tests_apk', '../content/content_shell_and_tests.gyp:content_browsertests_apk', ], }, # target_name: android_builder_chromium_webrtc
diff --git a/build/android/ant/apk-package.xml b/build/android/ant/apk-package.xml index 99279a4..e8b76f7e 100644 --- a/build/android/ant/apk-package.xml +++ b/build/android/ant/apk-package.xml
@@ -67,7 +67,7 @@ debugpackaging="${build.is.packaging.debug}" debugsigning="${build.is.signing.debug}" verbose="${verbose}" - hascode="true" + hascode="${HAS_CODE}" previousBuildType="/" buildType="${build.is.packaging.debug}/${build.is.signing.debug}"> <dex path="${intermediate.dex.file}"/>
diff --git a/build/android/apkbuilder_action.gypi b/build/android/apkbuilder_action.gypi new file mode 100644 index 0000000..27807d8 --- /dev/null +++ b/build/android/apkbuilder_action.gypi
@@ -0,0 +1,79 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# This file is a helper to java_apk.gypi. It should be used to create an +# action that runs ApkBuilder via ANT. +# +# Required variables: +# apk_name - File name (minus path & extension) of the output apk. +# apk_path - Path to output apk. +# package_input_paths - Late-evaluated list of resource zips. +# native_libs_dir - Path to lib/ directory to use. Set to an empty directory +# if no native libs are needed. +# Optional variables: +# has_code - Whether to include classes.dex in the apk. +# dex_path - Path to classes.dex. Used only when has_code=1. +# extra_inputs - List of extra action inputs. +{ + 'variables': { + 'variables': { + 'has_code%': 1, + }, + 'conditions': [ + ['has_code == 0', { + 'has_code_str': 'false', + }, { + 'has_code_str': 'true', + }], + ], + 'has_code%': '<(has_code)', + 'extra_inputs%': [], + # Write the inputs list to a file, so that its mtime is updated when + # the list of inputs changes. + 'inputs_list_file': '>|(apk_package.<(_target_name).<(apk_name).gypcmd >@(package_input_paths))', + 'resource_packaged_apk_name': '<(apk_name)-resources.ap_', + 'resource_packaged_apk_path': '<(intermediate_dir)/<(resource_packaged_apk_name)', + }, + 'action_name': 'apkbuilder_<(apk_name)', + 'message': 'Packaging <(apk_name)', + 'inputs': [ + '<(DEPTH)/build/android/ant/apk-package.xml', + '<(DEPTH)/build/android/gyp/util/build_utils.py', + '<(DEPTH)/build/android/gyp/ant.py', + '<(resource_packaged_apk_path)', + '<@(extra_inputs)', + '>@(package_input_paths)', + '>(inputs_list_file)', + ], + 'outputs': [ + '<(apk_path)', + ], + 'conditions': [ + ['has_code == 1', { + 'inputs': ['<(dex_path)'], + 'action': [ + '-DDEX_FILE_PATH=<(dex_path)', + ] + }], + ], + 'action': [ + 'python', '<(DEPTH)/build/android/gyp/ant.py', + '--', + '-quiet', + '-DHAS_CODE=<(has_code_str)', + '-DANDROID_SDK_ROOT=<(android_sdk_root)', + '-DANDROID_SDK_TOOLS=<(android_sdk_tools)', + '-DRESOURCE_PACKAGED_APK_NAME=<(resource_packaged_apk_name)', + '-DNATIVE_LIBS_DIR=<(native_libs_dir)', + '-DAPK_NAME=<(apk_name)', + '-DCONFIGURATION_NAME=<(CONFIGURATION_NAME)', + '-DOUT_DIR=<(intermediate_dir)', + '-DUNSIGNED_APK_PATH=<(apk_path)', + '-DEMMA_INSTRUMENT=<(emma_instrument)', + '-DEMMA_DEVICE_JAR=<(emma_device_jar)', + '-Dbasedir=.', + '-buildfile', + '<(DEPTH)/build/android/ant/apk-package.xml', + ] +}
diff --git a/build/android/gyp/package_resources.py b/build/android/gyp/package_resources.py index 2251de00..53937664 100755 --- a/build/android/gyp/package_resources.py +++ b/build/android/gyp/package_resources.py
@@ -60,7 +60,7 @@ # Check that required options have been provided. required_options = ('android_sdk', 'android_sdk_tools', 'configuration_name', 'android_manifest', 'version_code', 'version_name', - 'resource_zips', 'asset_dir', 'apk_path') + 'apk_path') build_utils.CheckOptions(options, parser, required=required_options) @@ -140,16 +140,17 @@ if options.shared_resources: package_command.append('--shared-lib') - if os.path.exists(options.asset_dir): + if options.asset_dir and os.path.exists(options.asset_dir): package_command += ['-A', options.asset_dir] - dep_zips = build_utils.ParseGypList(options.resource_zips) - for z in dep_zips: - subdir = os.path.join(temp_dir, os.path.basename(z)) - if os.path.exists(subdir): - raise Exception('Resource zip name conflict: ' + os.path.basename(z)) - build_utils.ExtractAll(z, path=subdir) - package_command += PackageArgsForExtractedZip(subdir) + if options.resource_zips: + dep_zips = build_utils.ParseGypList(options.resource_zips) + for z in dep_zips: + subdir = os.path.join(temp_dir, os.path.basename(z)) + if os.path.exists(subdir): + raise Exception('Resource zip name conflict: ' + os.path.basename(z)) + build_utils.ExtractAll(z, path=subdir) + package_command += PackageArgsForExtractedZip(subdir) if 'Debug' in options.configuration_name: package_command += ['--debug-mode']
diff --git a/build/android/package_resources_action.gypi b/build/android/package_resources_action.gypi new file mode 100644 index 0000000..fe1645f8 --- /dev/null +++ b/build/android/package_resources_action.gypi
@@ -0,0 +1,73 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# This file is a helper to java_apk.gypi. It should be used to create an +# action that runs ApkBuilder via ANT. +# +# Required variables: +# apk_name - File name (minus path & extension) of the output apk. +# android_manifest_path - Path to AndroidManifest.xml. +# app_manifest_version_name - set the apps 'human readable' version number. +# app_manifest_version_code - set the apps version number. +# Optional variables: +# asset_location - The directory where assets are located (if any). +# resource_zips - List of paths to resource zip files. +# shared_resources - Make a resource package that can be loaded by a different +# application at runtime to access the package's resources. +# extensions_to_not_compress - E.g.: 'pak,dat,bin' +# extra_inputs - List of extra action inputs. +{ + 'variables': { + 'asset_location%': '', + 'resource_zips%': [], + 'shared_resources%': 0, + 'extensions_to_not_compress%': '', + 'extra_inputs%': [], + 'resource_packaged_apk_name': '<(apk_name)-resources.ap_', + 'resource_packaged_apk_path': '<(intermediate_dir)/<(resource_packaged_apk_name)', + }, + 'action_name': 'package_resources_<(apk_name)', + 'message': 'packaging resources for <(apk_name)', + 'inputs': [ + # TODO: This isn't always rerun correctly, http://crbug.com/351928 + '<(DEPTH)/build/android/gyp/util/build_utils.py', + '<(DEPTH)/build/android/gyp/package_resources.py', + '<(android_manifest_path)', + '<@(extra_inputs)', + ], + 'outputs': [ + '<(resource_packaged_apk_path)', + ], + 'action': [ + 'python', '<(DEPTH)/build/android/gyp/package_resources.py', + '--android-sdk', '<(android_sdk)', + '--android-sdk-tools', '<(android_sdk_tools)', + '--configuration-name', '<(CONFIGURATION_NAME)', + '--android-manifest', '<(android_manifest_path)', + '--version-code', '<(app_manifest_version_code)', + '--version-name', '<(app_manifest_version_name)', + '--no-compress', '<(extensions_to_not_compress)', + '--apk-path', '<(resource_packaged_apk_path)', + ], + 'conditions': [ + ['shared_resources == 1', { + 'action': [ + '--shared-resources', + ], + }], + ['asset_location != ""', { + 'action': [ + '--asset-dir', '<(asset_location)', + ], + }], + ['resource_zips != []', { + 'action': [ + '--resource-zips', '>(resource_zips)', + ], + 'inputs': [ + '>@(resource_zips)', + ], + }], + ], +}
diff --git a/build/config/BUILD.gn b/build/config/BUILD.gn index 5eb5e0a..26bcd7d 100644 --- a/build/config/BUILD.gn +++ b/build/config/BUILD.gn
@@ -248,6 +248,9 @@ } else { defines += [ "CHROMIUM_BUILD" ] } + if (enable_media_router) { + defines += [ "ENABLE_MEDIA_ROUTER=1" ] + } } # Debug/release ----------------------------------------------------------------
diff --git a/build/config/android/internal_rules.gni b/build/config/android/internal_rules.gni index 07a05e1..a5a12352 100644 --- a/build/config/android/internal_rules.gni +++ b/build/config/android/internal_rules.gni
@@ -449,8 +449,13 @@ _android_manifest = invoker.android_manifest _base_path = invoker.base_path _final_apk_path = invoker.apk_path - _resources_zip = invoker.resources_zip - _dex_path = invoker.dex_path + + if (defined(invoker.resources_zip)) { + _resources_zip = invoker.resources_zip + } + if (defined(invoker.dex_path)) { + _dex_path = invoker.dex_path + } _keystore_path = invoker.keystore_path _keystore_name = invoker.keystore_name _keystore_password = invoker.keystore_password @@ -466,7 +471,6 @@ _native_libs_dir = invoker.native_libs_dir } - _asset_location = "//build/android/empty/res" if (defined(invoker.asset_location)) { _asset_location = invoker.asset_location } @@ -493,14 +497,15 @@ depfile = "${target_gen_dir}/${target_name}.d" inputs = [ _android_manifest, - _resources_zip, ] + if (defined(_resources_zip)) { + inputs += [ _resources_zip ] + } outputs = [ depfile, _resource_packaged_apk_path, ] - _rebased_resources_zips = [ rebase_path(_resources_zip, root_build_dir) ] args = [ "--depfile", rebase_path(depfile, root_build_dir), @@ -515,13 +520,22 @@ _version_code, "--version-name", _version_name, - "--asset-dir", - rebase_path(_asset_location, root_build_dir), - "--resource-zips=$_rebased_resources_zips", "--apk-path", rebase_path(_resource_packaged_apk_path, root_build_dir), ] + if (defined(_asset_location)) { + args += [ + "--asset-dir", + rebase_path(_asset_location, root_build_dir), + ] + } + if (defined(_resources_zip)) { + args += [ + "--resource-zips", + rebase_path(_resources_zip, root_build_dir), + ] + } if (_shared_resources) { args += [ "--shared-resources" ] } @@ -534,10 +548,12 @@ depfile = "$target_gen_dir/$target_name.d" inputs = [ - _dex_path, _resource_packaged_apk_path, _ant_script, ] + if (defined(_dex_path)) { + inputs += [ _dex_path ] + } outputs = [ depfile, @@ -549,7 +565,6 @@ rebase_path(_resource_packaged_apk_path, root_build_dir) _rebased_packaged_apk_path = rebase_path(_packaged_apk_path, root_build_dir) _rebased_native_libs_dir = rebase_path(_native_libs_dir, root_build_dir) - _rebased_dex_path = rebase_path(_dex_path, root_build_dir) args = [ "--depfile", rebase_path(depfile, root_build_dir), @@ -564,11 +579,19 @@ "-DUNSIGNED_APK_PATH=$_rebased_packaged_apk_path", "-DEMMA_INSTRUMENT=0", "-DEMMA_DEVICE_JAR=$_rebased_emma_jar", - "-DDEX_FILE_PATH=$_rebased_dex_path", "-Dbasedir=.", "-buildfile", rebase_path(_ant_script, root_build_dir), ] + if (defined(_dex_path)) { + _rebased_dex_path = rebase_path(_dex_path, root_build_dir) + args += [ + "-DDEX_FILE_PATH=$_rebased_dex_path", + "-DHAS_CODE=true", + ] + } else { + args += [ "-DHAS_CODE=false" ] + } } action("${target_name}__finalize") { @@ -616,6 +639,7 @@ group(target_name) { deps = [ ":${target_name}__finalize", + ":${target_name}__package_resources", ] } } @@ -1080,6 +1104,10 @@ args += [ "--v14-verify-only" ] } + if (defined(invoker.v14_skip) && invoker.v14_skip) { + args += [ "--v14-skip" ] + } + if (defined(invoker.shared_resources) && invoker.shared_resources) { args += [ "--shared-resources" ] }
diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni index 0b7593d2..6140b5e 100644 --- a/build/config/android/rules.gni +++ b/build/config/android/rules.gni
@@ -583,6 +583,10 @@ v14_verify_only = invoker.v14_verify_only } + if (defined(invoker.v14_skip)) { + v14_skip = invoker.v14_skip + } + if (defined(invoker.shared_resources)) { shared_resources = invoker.shared_resources }
diff --git a/build/gn_migration.gypi b/build/gn_migration.gypi index ab16c05..f9a4db8 100644 --- a/build/gn_migration.gypi +++ b/build/gn_migration.gypi
@@ -168,7 +168,6 @@ '../skia/skia.gyp:image_operations_bench', '../sql/sql.gyp:sql_unittests', '../sync/sync.gyp:run_sync_testserver', - '../sync/sync.gyp:sync_endtoend_tests', '../sync/sync.gyp:sync_unit_tests', '../sync/tools/sync_tools.gyp:sync_client', '../sync/tools/sync_tools.gyp:sync_listen_notifications',
diff --git a/build/java_apk.gypi b/build/java_apk.gypi index 154c16e83..ab415a9 100644 --- a/build/java_apk.gypi +++ b/build/java_apk.gypi
@@ -128,10 +128,7 @@ 'android_manifest_path%': '<(java_in_dir)/AndroidManifest.xml', 'push_stamp': '<(intermediate_dir)/push.stamp', 'link_stamp': '<(intermediate_dir)/link.stamp', - 'package_resources_stamp': '<(intermediate_dir)/package_resources.stamp', 'resource_zip_path': '<(intermediate_dir)/<(_target_name).resources.zip', - 'resource_packaged_apk_name': '<(apk_name)-resources.ap_', - 'resource_packaged_apk_path': '<(intermediate_dir)/<(resource_packaged_apk_name)', 'shared_resources%': 0, 'unsigned_apk_path': '<(intermediate_dir)/<(apk_name)-unsigned.apk', 'final_apk_path%': '<(PRODUCT_DIR)/apks/<(apk_name).apk', @@ -867,109 +864,32 @@ 'includes': [ 'android/dex_action.gypi' ], }, { - 'action_name': 'package_resources', - 'message': 'packaging resources for <(_target_name)', 'variables': { - 'package_resources_options': [], - 'package_resource_zip_input_paths': [ + 'extra_inputs': ['<(codegen_stamp)'], + 'resource_zips': [ '<(resource_zip_path)', - '>@(dependencies_res_zip_paths)', ], 'conditions': [ - ['shared_resources == 1', { - 'package_resources_options+': ['--shared-resources'] + ['is_test_apk == 0', { + 'resource_zips': [ + '>@(dependencies_res_zip_paths)', + ], }], ], }, - 'conditions': [ - ['is_test_apk == 1', { - 'variables': { - 'dependencies_res_zip_paths=': [], - 'additional_res_packages=': [], - } - }], - ], - 'inputs': [ - # TODO: This isn't always rerun correctly, http://crbug.com/351928 - '<(DEPTH)/build/android/gyp/util/build_utils.py', - '<(DEPTH)/build/android/gyp/package_resources.py', - '<(android_manifest_path)', - - '>@(package_resource_zip_input_paths)', - - '<(codegen_stamp)', - ], - 'outputs': [ - '<(resource_packaged_apk_path)', - ], - 'action': [ - 'python', '<(DEPTH)/build/android/gyp/package_resources.py', - '--android-sdk', '<(android_sdk)', - '--android-sdk-tools', '<(android_sdk_tools)', - - '--configuration-name', '<(CONFIGURATION_NAME)', - - '--android-manifest', '<(android_manifest_path)', - '--version-code', '<(app_manifest_version_code)', - '--version-name', '<(app_manifest_version_name)', - - '--asset-dir', '<(asset_location)', - '--resource-zips', '>(package_resource_zip_input_paths)', - - '--no-compress', '<(extensions_to_not_compress)', - - '--apk-path', '<(resource_packaged_apk_path)', - - '<@(package_resources_options)', - ], + 'includes': [ 'android/package_resources_action.gypi' ], }, { - 'action_name': 'ant_package_<(_target_name)', - 'message': 'Packaging <(_target_name)', 'variables': { - # Write the inputs list to a file, so that its mtime is updated when - # the list of inputs changes. - 'inputs_list_file': '>|(apk_package.<(_target_name).gypcmd >@(package_input_paths))' + 'apk_path': '<(unsigned_apk_path)', + 'native_libs_dir': '<(apk_package_native_libs_dir)', + 'conditions': [ + ['native_lib_target != ""', { + 'extra_inputs': ['<(native_lib_placeholder_stamp)'], + }], + ], }, - 'inputs': [ - '<(DEPTH)/build/android/ant/apk-package.xml', - '<(DEPTH)/build/android/gyp/util/build_utils.py', - '<(DEPTH)/build/android/gyp/ant.py', - '<(dex_path)', - '<(codegen_stamp)', - '<(obfuscate_stamp)', - '<(resource_packaged_apk_path)', - '>@(package_input_paths)', - '>(inputs_list_file)', - ], - 'outputs': [ - '<(unsigned_apk_path)', - ], - 'conditions': [ - ['native_lib_target != ""', { - 'inputs': ['<(native_lib_placeholder_stamp)'], - }], - ], - 'action': [ - 'python', '<(DEPTH)/build/android/gyp/ant.py', - '--', - '-quiet', - '-DDEX_FILE_PATH=<(intermediate_dir)/classes.dex', - '-DANDROID_SDK_ROOT=<(android_sdk_root)', - '-DANDROID_SDK_TOOLS=<(android_sdk_tools)', - '-DRESOURCE_PACKAGED_APK_NAME=<(resource_packaged_apk_name)', - '-DAPK_NAME=<(apk_name)', - '-DCONFIGURATION_NAME=<(CONFIGURATION_NAME)', - '-DNATIVE_LIBS_DIR=<(apk_package_native_libs_dir)', - '-DOUT_DIR=<(intermediate_dir)', - '-DUNSIGNED_APK_PATH=<(unsigned_apk_path)', - '-DEMMA_INSTRUMENT=<(emma_instrument)', - '-DEMMA_DEVICE_JAR=<(emma_device_jar)', - - '-Dbasedir=.', - '-buildfile', - '<(DEPTH)/build/android/ant/apk-package.xml', - ] + 'includes': ['android/apkbuilder_action.gypi'], }, ], }
diff --git a/build/secondary/third_party/android_tools/BUILD.gn b/build/secondary/third_party/android_tools/BUILD.gn index 099b892..f054125f 100644 --- a/build/secondary/third_party/android_tools/BUILD.gn +++ b/build/secondary/third_party/android_tools/BUILD.gn
@@ -34,7 +34,7 @@ } android_resources("android_support_v7_appcompat_resources") { - v14_verify_only = true + v14_skip = true resource_dirs = [ "$android_sdk_root/extras/android/support/v7/appcompat/res" ] custom_package = "android.support.v7.appcompat" @@ -48,7 +48,7 @@ } android_resources("android_support_v7_mediarouter_resources") { - v14_verify_only = true + v14_skip = true resource_dirs = [ "$android_sdk_root/extras/android/support/v7/mediarouter/res" ] deps = [ @@ -73,7 +73,7 @@ } android_resources("google_play_services_default_resources") { - v14_verify_only = true + v14_skip = true resource_dirs = [ "$android_sdk_root/extras/google/google_play_services/libproject/google-play-services_lib/res" ] custom_package = "com.google.android.gms" }
diff --git a/build/secondary/third_party/libsrtp/BUILD.gn b/build/secondary/third_party/libsrtp/BUILD.gn index 8b9647c..7601bea0 100644 --- a/build/secondary/third_party/libsrtp/BUILD.gn +++ b/build/secondary/third_party/libsrtp/BUILD.gn
@@ -4,12 +4,15 @@ declare_args() { use_system_libsrtp = false + use_srtp_boringssl = true } config("libsrtp_config") { defines = [ + "HAVE_CONFIG_H", "HAVE_STDLIB_H", "HAVE_STRING_H", + "TESTAPP_SOURCE", ] include_dirs = [ @@ -18,6 +21,10 @@ "srtp/crypto/include", ] + if (use_srtp_boringssl) { + defines += [ "OPENSSL" ] + } + if (is_posix) { defines += [ "HAVE_INT16_T", @@ -30,13 +37,14 @@ "HAVE_STDINT_H", "HAVE_INTTYPES_H", "HAVE_NETINET_IN_H", - "INLINE=inline", + "HAVE_ARPA_INET_H", + "HAVE_UNISTD_H", ] + cflags = [ "-Wno-unused-variable" ] } if (is_win) { defines += [ - "INLINE=__inline", "HAVE_BYTESWAP_METHODS_H", # All Windows architectures are this way. @@ -149,6 +157,30 @@ if (is_clang) { cflags = [ "-Wno-implicit-function-declaration" ] } + + if (use_srtp_boringssl) { + deps = [ + "//third_party/boringssl:boringssl", + ] + public_deps = [ + "//third_party/boringssl:boringssl", + ] + sources -= [ + "srtp/crypto/cipher/aes_cbc.c", + "srtp/crypto/cipher/aes_icm.c", + "srtp/crypto/hash/hmac.c", + "srtp/crypto/hash/sha1.c", + "srtp/crypto/rng/ctr_prng.c", + "srtp/crypto/rng/prng.c", + ] + sources += [ + "srtp/crypto/cipher/aes_gcm_ossl.c", + "srtp/crypto/cipher/aes_icm_ossl.c", + "srtp/crypto/hash/hmac_ossl.c", + "srtp/crypto/include/aes_gcm_ossl.h", + "srtp/crypto/include/aes_icm_ossl.h", + ] + } } # TODO(GYP): A bunch of these tests don't compile (in gyp either). They're @@ -238,6 +270,8 @@ ] sources = [ "srtp/crypto/test/cipher_driver.c", + "srtp/include/getopt_s.h", + "srtp/test/getopt_s.c", ] } @@ -282,6 +316,8 @@ ] sources = [ "srtp/crypto/test/kernel_driver.c", + "srtp/include/getopt_s.h", + "srtp/test/getopt_s.c", ] } @@ -304,6 +340,21 @@ ] sources = [ "srtp/crypto/test/rand_gen.c", + "srtp/include/getopt_s.h", + "srtp/test/getopt_s.c", + ] + } + + executable("srtp_test_rand_gen_soak") { + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ "//build/config/compiler:no_chromium_code" ] + deps = [ + ":libsrtp", + ] + sources = [ + "srtp/crypto/test/rand_gen_soak.c", + "srtp/include/getopt_s.h", + "srtp/test/getopt_s.c", ] } @@ -332,6 +383,7 @@ ":srtp_test_kernel_driver", ":srtp_test_aes_calc", ":srtp_test_rand_gen", + ":srtp_test_rand_gen_soak", ":srtp_test_env", ] }
diff --git a/cc/blink/BUILD.gn b/cc/blink/BUILD.gn index 1769efb..4854ead 100644 --- a/cc/blink/BUILD.gn +++ b/cc/blink/BUILD.gn
@@ -78,11 +78,15 @@ "web_animation_unittest.cc", "web_float_animation_curve_unittest.cc", "web_layer_impl_fixed_bounds_unittest.cc", + + # Setup. + "test/cc_blink_test_suite.cc", + "test/run_all_unittests.cc", ] deps = [ ":blink", - "//base/test:run_all_unittests", + "//base/test:test_support", "//base/third_party/dynamic_annotations", "//skia", "//testing/gtest",
diff --git a/cc/blink/cc_blink_tests.gyp b/cc/blink/cc_blink_tests.gyp index 2e3fef5..f20c463 100644 --- a/cc/blink/cc_blink_tests.gyp +++ b/cc/blink/cc_blink_tests.gyp
@@ -20,7 +20,8 @@ 'cc_blink.gyp:cc_blink', ], 'sources': [ - '../../base/test/run_all_unittests.cc', + 'test/cc_blink_test_suite.cc', + 'test/run_all_unittests.cc', 'web_animation_unittest.cc', 'web_float_animation_curve_unittest.cc', 'web_layer_impl_fixed_bounds_unittest.cc',
diff --git a/cc/blink/test/cc_blink_test_suite.cc b/cc/blink/test/cc_blink_test_suite.cc new file mode 100644 index 0000000..6202cfd3 --- /dev/null +++ b/cc/blink/test/cc_blink_test_suite.cc
@@ -0,0 +1,33 @@ +// Copyright (c) 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "cc/blink/test/cc_blink_test_suite.h" + +#include "base/message_loop/message_loop.h" +#include "base/threading/thread_id_name_manager.h" + +namespace cc_blink { + +CCBlinkTestSuite::CCBlinkTestSuite(int argc, char** argv) + : base::TestSuite(argc, argv) {} + +CCBlinkTestSuite::~CCBlinkTestSuite() {} + +void CCBlinkTestSuite::Initialize() { + base::TestSuite::Initialize(); + + message_loop_.reset(new base::MessageLoop); + + base::ThreadIdNameManager::GetInstance()->SetName( + base::PlatformThread::CurrentId(), + "Main"); +} + +void CCBlinkTestSuite::Shutdown() { + message_loop_ = nullptr; + + base::TestSuite::Shutdown(); +} + +} // namespace cc_blink
diff --git a/cc/blink/test/cc_blink_test_suite.h b/cc/blink/test/cc_blink_test_suite.h new file mode 100644 index 0000000..faa76840 --- /dev/null +++ b/cc/blink/test/cc_blink_test_suite.h
@@ -0,0 +1,36 @@ +// Copyright (c) 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CC_BLINK_TEST_CC_BLINK_TEST_SUITE_H_ +#define CC_BLINK_TEST_CC_BLINK_TEST_SUITE_H_ + +#include "base/macros.h" +#include "base/memory/scoped_ptr.h" +#include "base/test/test_suite.h" + +namespace base { +class MessageLoop; +} + +namespace cc_blink { + +class CCBlinkTestSuite : public base::TestSuite { + public: + CCBlinkTestSuite(int argc, char** argv); + ~CCBlinkTestSuite() override; + + protected: + // Overridden from base::TestSuite: + void Initialize() override; + void Shutdown() override; + + private: + scoped_ptr<base::MessageLoop> message_loop_; + + DISALLOW_COPY_AND_ASSIGN(CCBlinkTestSuite); +}; + +} // namespace cc_blink + +#endif // CC_BLINK_TEST_CC_BLINK_TEST_SUITE_H_
diff --git a/cc/blink/test/run_all_unittests.cc b/cc/blink/test/run_all_unittests.cc new file mode 100644 index 0000000..294039a --- /dev/null +++ b/cc/blink/test/run_all_unittests.cc
@@ -0,0 +1,17 @@ +// Copyright (c) 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/bind.h" +#include "base/test/launcher/unit_test_launcher.h" +#include "cc/blink/test/cc_blink_test_suite.h" + +int main(int argc, char** argv) { + cc_blink::CCBlinkTestSuite test_suite(argc, argv); + + return base::LaunchUnitTests( + argc, + argv, + base::Bind(&cc_blink::CCBlinkTestSuite::Run, + base::Unretained(&test_suite))); +}
diff --git a/cc/debug/traced_picture.cc b/cc/debug/traced_picture.cc index 2c7622b6..3241871d 100644 --- a/cc/debug/traced_picture.cc +++ b/cc/debug/traced_picture.cc
@@ -40,18 +40,16 @@ scoped_ptr<base::DictionaryValue> alias(new base::DictionaryValue()); alias->SetString("id_ref", base::StringPrintf("%p", picture_.get())); - scoped_ptr<base::DictionaryValue> res(new base::DictionaryValue()); - res->Set("alias", alias.release()); - + base::DictionaryValue res; + res.Set("alias", alias.release()); std::string tmp; - base::JSONWriter::Write(res.get(), &tmp); + base::JSONWriter::Write(res, &tmp); out->append(tmp); } void TracedPicture::AppendPicture(std::string* out) const { - scoped_ptr<base::Value> value = picture_->AsValue(); std::string tmp; - base::JSONWriter::Write(value.get(), &tmp); + base::JSONWriter::Write(*picture_->AsValue(), &tmp); out->append(tmp); }
diff --git a/cc/layers/delegated_renderer_layer_impl.cc b/cc/layers/delegated_renderer_layer_impl.cc index 63039fb..a99cd17 100644 --- a/cc/layers/delegated_renderer_layer_impl.cc +++ b/cc/layers/delegated_renderer_layer_impl.cc
@@ -78,6 +78,7 @@ own_child_id_ = false; if (have_render_passes_to_push_) { + DCHECK(child_id_); // This passes ownership of the render passes to the active tree. delegated_layer->SetRenderPasses(&render_passes_in_draw_order_); // Once resources are on the active tree, give them to the ResourceProvider @@ -216,6 +217,7 @@ void DelegatedRendererLayerImpl::ReleaseResources() { ClearRenderPasses(); ClearChildId(); + have_render_passes_to_push_ = false; } static inline int IndexToId(int index) { return index + 1; }
diff --git a/cc/layers/picture_layer_impl_unittest.cc b/cc/layers/picture_layer_impl_unittest.cc index 13d39ac..fb056aa 100644 --- a/cc/layers/picture_layer_impl_unittest.cc +++ b/cc/layers/picture_layer_impl_unittest.cc
@@ -2443,9 +2443,9 @@ // Gpu rasterization is disabled by default. EXPECT_FALSE(host_impl_.use_gpu_rasterization()); // Toggling the gpu rasterization clears all tilings on both trees. - host_impl_.set_has_gpu_rasterization_trigger(true); - host_impl_.set_content_is_suitable_for_gpu_rasterization(true); - host_impl_.UpdateGpuRasterizationStatus(); + host_impl_.SetHasGpuRasterizationTrigger(true); + host_impl_.SetContentIsSuitableForGpuRasterization(true); + host_impl_.UpdateTreeResourcesForGpuRasterizationIfNeeded(); EXPECT_EQ(0u, pending_layer_->tilings()->num_tilings()); EXPECT_EQ(0u, active_layer_->tilings()->num_tilings()); @@ -2466,16 +2466,15 @@ // Toggling the gpu rasterization clears all tilings on both trees. EXPECT_TRUE(host_impl_.use_gpu_rasterization()); - host_impl_.set_has_gpu_rasterization_trigger(false); - host_impl_.UpdateGpuRasterizationStatus(); + host_impl_.SetHasGpuRasterizationTrigger(false); + host_impl_.UpdateTreeResourcesForGpuRasterizationIfNeeded(); EXPECT_EQ(GpuRasterizationStatus::OFF_VIEWPORT, host_impl_.gpu_rasterization_status()); EXPECT_EQ(0u, pending_layer_->tilings()->num_tilings()); EXPECT_EQ(0u, active_layer_->tilings()->num_tilings()); - host_impl_.set_has_gpu_rasterization_trigger(true); - host_impl_.set_content_is_suitable_for_gpu_rasterization(false); - host_impl_.UpdateGpuRasterizationStatus(); + host_impl_.SetHasGpuRasterizationTrigger(true); + host_impl_.SetContentIsSuitableForGpuRasterization(false); EXPECT_EQ(GpuRasterizationStatus::OFF_CONTENT, host_impl_.gpu_rasterization_status()); } @@ -2521,8 +2520,7 @@ gfx::Size layer_bounds(default_tile_size.width() * 4, default_tile_size.height() * 4); - host_impl_.set_has_gpu_rasterization_trigger(false); - host_impl_.UpdateGpuRasterizationStatus(); + host_impl_.SetHasGpuRasterizationTrigger(false); SetupDefaultTrees(layer_bounds); EXPECT_FALSE(host_impl_.use_gpu_rasterization()); @@ -2535,9 +2533,8 @@ gfx::Size layer_bounds(default_tile_size.width() * 4, default_tile_size.height() * 4); - host_impl_.set_has_gpu_rasterization_trigger(true); - host_impl_.set_content_is_suitable_for_gpu_rasterization(true); - host_impl_.UpdateGpuRasterizationStatus(); + host_impl_.SetHasGpuRasterizationTrigger(true); + host_impl_.SetContentIsSuitableForGpuRasterization(true); SetupDefaultTrees(layer_bounds); EXPECT_TRUE(host_impl_.use_gpu_rasterization()); @@ -2546,9 +2543,8 @@ } TEST_F(PictureLayerImplTest, RequiredTilesWithGpuRasterization) { - host_impl_.set_has_gpu_rasterization_trigger(true); - host_impl_.set_content_is_suitable_for_gpu_rasterization(true); - host_impl_.UpdateGpuRasterizationStatus(); + host_impl_.SetHasGpuRasterizationTrigger(true); + host_impl_.SetContentIsSuitableForGpuRasterization(true); gfx::Size viewport_size(1000, 1000); host_impl_.SetViewportSize(viewport_size); @@ -2848,9 +2844,9 @@ gfx::Size viewport_size(1000, 1000); SetupDefaultTrees(layer_bounds); host_impl_.SetViewportSize(viewport_size); - host_impl_.set_has_gpu_rasterization_trigger(true); - host_impl_.set_content_is_suitable_for_gpu_rasterization(true); - host_impl_.UpdateGpuRasterizationStatus(); + host_impl_.SetHasGpuRasterizationTrigger(true); + host_impl_.SetContentIsSuitableForGpuRasterization(true); + host_impl_.UpdateTreeResourcesForGpuRasterizationIfNeeded(); float contents_scale = 1.f; float device_scale = 1.3f; @@ -5042,9 +5038,8 @@ host_impl_.SetViewportSize(gfx::Size(1000, 1000)); gfx::Size result; - host_impl_.set_content_is_suitable_for_gpu_rasterization(true); - host_impl_.set_has_gpu_rasterization_trigger(false); - host_impl_.UpdateGpuRasterizationStatus(); + host_impl_.SetContentIsSuitableForGpuRasterization(true); + host_impl_.SetHasGpuRasterizationTrigger(false); EXPECT_EQ(host_impl_.gpu_rasterization_status(), GpuRasterizationStatus::OFF_VIEWPORT); @@ -5065,8 +5060,7 @@ // Gpu-rasterization uses 25% viewport-height tiles. // The +2's below are for border texels. - host_impl_.set_has_gpu_rasterization_trigger(true); - host_impl_.UpdateGpuRasterizationStatus(); + host_impl_.SetHasGpuRasterizationTrigger(true); EXPECT_EQ(host_impl_.gpu_rasterization_status(), GpuRasterizationStatus::ON); host_impl_.SetViewportSize(gfx::Size(2000, 2000));
diff --git a/cc/layers/surface_layer.cc b/cc/layers/surface_layer.cc index 1a690b6e..67a26322 100644 --- a/cc/layers/surface_layer.cc +++ b/cc/layers/surface_layer.cc
@@ -19,6 +19,7 @@ ~SatisfySwapPromise() override {} private: + void DidActivate() override {} void DidSwap(CompositorFrameMetadata* metadata) override { metadata->satisfies_sequences.push_back(sequence_.sequence); }
diff --git a/cc/output/gl_renderer.cc b/cc/output/gl_renderer.cc index bdb537a..93a4114 100644 --- a/cc/output/gl_renderer.cc +++ b/cc/output/gl_renderer.cc
@@ -163,7 +163,13 @@ public: static scoped_ptr<ScopedUseGrContext> Create(GLRenderer* renderer, DrawingFrame* frame) { - return make_scoped_ptr(new ScopedUseGrContext(renderer, frame)); + // GrContext for filters is created lazily, and may fail if the context + // is lost. + // TODO(vmiura,bsalomon): crbug.com/487850 Ensure that + // ContextProvider::GrContext() does not return NULL. + if (renderer->output_surface_->context_provider()->GrContext()) + return make_scoped_ptr(new ScopedUseGrContext(renderer, frame)); + return nullptr; } ~ScopedUseGrContext() {
diff --git a/cc/output/latency_info_swap_promise.cc b/cc/output/latency_info_swap_promise.cc index 3c07162..afc0f2d 100644 --- a/cc/output/latency_info_swap_promise.cc +++ b/cc/output/latency_info_swap_promise.cc
@@ -10,7 +10,7 @@ ui::LatencyComponentType DidNotSwapReasonToLatencyComponentType( cc::SwapPromise::DidNotSwapReason reason) { switch (reason) { - case cc::SwapPromise::DID_NOT_SWAP_UNKNOWN: + case cc::SwapPromise::ACTIVATION_FAILS: case cc::SwapPromise::SWAP_FAILS: return ui::INPUT_EVENT_LATENCY_TERMINATED_SWAP_FAILED_COMPONENT; case cc::SwapPromise::COMMIT_FAILS:
diff --git a/cc/output/latency_info_swap_promise.h b/cc/output/latency_info_swap_promise.h index afd1633..74810b8 100644 --- a/cc/output/latency_info_swap_promise.h +++ b/cc/output/latency_info_swap_promise.h
@@ -16,6 +16,7 @@ explicit LatencyInfoSwapPromise(const ui::LatencyInfo& latency_info); ~LatencyInfoSwapPromise() override; + void DidActivate() override {} void DidSwap(CompositorFrameMetadata* metadata) override; void DidNotSwap(DidNotSwapReason reason) override;
diff --git a/cc/output/swap_promise.h b/cc/output/swap_promise.h index 1d6dabcb..45deee8 100644 --- a/cc/output/swap_promise.h +++ b/cc/output/swap_promise.h
@@ -15,30 +15,43 @@ // completed in the compositor, i.e. the compositor knows it has been sent // to its output or not. // -// If the new compositor state is sent to the output, SwapPromise::DidSwap() -// will be called, and if the compositor fails to send its new state to the -// output, SwapPromise::DidNotSwap() will be called. +// If the commit results in a successful activation of the pending layer tree, +// SwapPromise::DidActivate() will be called. // -// Client wishes to use SwapPromise should have a subclass that defines -// the behavior of DidSwap() and DidNotSwap(). Notice that the promise can -// be broken at either main or impl thread, e.g. commit fails on main thread, -// new frame data has no actual damage so LayerTreeHostImpl::SwapBuffers() -// bails out early on impl thread, so don't assume that DidSwap() and -// DidNotSwap() are called at a particular thread. It is better to let the -// subclass carry thread-safe member data and operate on that member data in -// DidSwap() and DidNotSwap(). +// If the new compositor state is sent to the output, SwapPromise::DidSwap() +// will be called. +// +// If the scheduler fails to activate the pending tree, or the compositor +// fails to send its new state to the output, SwapPromise::DidNotSwap() will +// be called. Note that it is possible to activate, and subsequently not swap. +// +// Promises complete afer either DidSwap() or DidNotSwap() is called, thus +// there are three possible call sequences: +// DidNotSwap() +// DidActivate() ; DidSwap() +// DidActivate() ; DidNotSwap() +// +// Clients that wish to use SwapPromise should have a subclass that defines +// the behavior of DidActivate(), DidSwap() and DidNotSwap(). Notice that the +// promise can be broken at either main or impl thread, e.g. commit fails on +// main thread, new frame data has no actual damage so +// LayerTreeHostImpl::SwapBuffers() bails out early on impl thread, so don't +// assume that Did*() methods are called at a particular thread. It is better +// to let the subclass carry thread-safe member data and operate on that +// member data in Did*(). class CC_EXPORT SwapPromise { public: enum DidNotSwapReason { - DID_NOT_SWAP_UNKNOWN, SWAP_FAILS, COMMIT_FAILS, COMMIT_NO_UPDATE, + ACTIVATION_FAILS, }; SwapPromise() {} virtual ~SwapPromise() {} + virtual void DidActivate() = 0; virtual void DidSwap(CompositorFrameMetadata* metadata) = 0; virtual void DidNotSwap(DidNotSwapReason reason) = 0;
diff --git a/cc/resources/picture_layer_tiling.cc b/cc/resources/picture_layer_tiling.cc index 70c4b11..b90d28d1 100644 --- a/cc/resources/picture_layer_tiling.cc +++ b/cc/resources/picture_layer_tiling.cc
@@ -806,7 +806,9 @@ tile->set_required_for_draw(IsTileRequiredForDraw(tile)); } -PrioritizedTile PictureLayerTiling::MakePrioritizedTile(Tile* tile) const { +PrioritizedTile PictureLayerTiling::MakePrioritizedTile( + Tile* tile, + PriorityRectType priority_rect_type) const { DCHECK(tile); DCHECK( raster_source()->CoversRect(tile->content_rect(), tile->contents_scale())) @@ -814,7 +816,8 @@ << gfx::ScaleToEnclosingRect(tile->content_rect(), 1.f / tile->contents_scale()).ToString(); - return PrioritizedTile(tile, raster_source(), ComputePriorityForTile(tile), + return PrioritizedTile(tile, raster_source(), + ComputePriorityForTile(tile, priority_rect_type), IsTileOccluded(tile)); } @@ -822,53 +825,83 @@ PictureLayerTiling::UpdateAndGetAllPrioritizedTilesForTesting() const { std::map<const Tile*, PrioritizedTile> result; for (const auto& key_tile_pair : tiles_) { - UpdateRequiredStatesOnTile(key_tile_pair.second); + Tile* tile = key_tile_pair.second; + UpdateRequiredStatesOnTile(tile); PrioritizedTile prioritized_tile = - MakePrioritizedTile(key_tile_pair.second); + MakePrioritizedTile(tile, ComputePriorityRectTypeForTile(tile)); result.insert(std::make_pair(prioritized_tile.tile(), prioritized_tile)); } return result; } TilePriority PictureLayerTiling::ComputePriorityForTile( - const Tile* tile) const { + const Tile* tile, + PriorityRectType priority_rect_type) const { // TODO(vmpstr): See if this can be moved to iterators. TilePriority::PriorityBin max_tile_priority_bin = client_->GetMaxTilePriorityBin(); + DCHECK_EQ(ComputePriorityRectTypeForTile(tile), priority_rect_type); DCHECK_EQ(TileAt(tile->tiling_i_index(), tile->tiling_j_index()), tile); + + TilePriority::PriorityBin priority_bin = max_tile_priority_bin; + + switch (priority_rect_type) { + case VISIBLE_RECT: + return TilePriority(resolution_, priority_bin, 0); + case PENDING_VISIBLE_RECT: + if (max_tile_priority_bin <= TilePriority::SOON) + return TilePriority(resolution_, TilePriority::SOON, 0); + priority_bin = TilePriority::EVENTUALLY; + break; + case SKEWPORT_RECT: + case SOON_BORDER_RECT: + if (max_tile_priority_bin <= TilePriority::SOON) + priority_bin = TilePriority::SOON; + break; + case EVENTUALLY_RECT: + priority_bin = TilePriority::EVENTUALLY; + break; + } + gfx::Rect tile_bounds = tiling_data_.TileBounds(tile->tiling_i_index(), tile->tiling_j_index()); - - if (max_tile_priority_bin <= TilePriority::NOW && - current_visible_rect_.Intersects(tile_bounds)) { - return TilePriority(resolution_, TilePriority::NOW, 0); - } - - if (max_tile_priority_bin <= TilePriority::SOON && - pending_visible_rect().Intersects(tile_bounds)) { - return TilePriority(resolution_, TilePriority::SOON, 0); - } - DCHECK_GT(current_content_to_screen_scale_, 0.f); float distance_to_visible = current_visible_rect_.ManhattanInternalDistance(tile_bounds) * current_content_to_screen_scale_; - if (max_tile_priority_bin <= TilePriority::SOON && - (current_soon_border_rect_.Intersects(tile_bounds) || - current_skewport_rect_.Intersects(tile_bounds))) { - return TilePriority(resolution_, TilePriority::SOON, distance_to_visible); - } + return TilePriority(resolution_, priority_bin, distance_to_visible); +} - return TilePriority(resolution_, TilePriority::EVENTUALLY, - distance_to_visible); +PictureLayerTiling::PriorityRectType +PictureLayerTiling::ComputePriorityRectTypeForTile(const Tile* tile) const { + DCHECK_EQ(TileAt(tile->tiling_i_index(), tile->tiling_j_index()), tile); + gfx::Rect tile_bounds = + tiling_data_.TileBounds(tile->tiling_i_index(), tile->tiling_j_index()); + + if (current_visible_rect_.Intersects(tile_bounds)) + return VISIBLE_RECT; + + if (pending_visible_rect().Intersects(tile_bounds)) + return PENDING_VISIBLE_RECT; + + if (current_skewport_rect_.Intersects(tile_bounds)) + return SKEWPORT_RECT; + + if (current_soon_border_rect_.Intersects(tile_bounds)) + return SOON_BORDER_RECT; + + DCHECK(current_eventually_rect_.Intersects(tile_bounds)); + return EVENTUALLY_RECT; } void PictureLayerTiling::GetAllPrioritizedTilesForTracing( std::vector<PrioritizedTile>* prioritized_tiles) const { for (const auto& tile_pair : tiles_) { - prioritized_tiles->push_back(MakePrioritizedTile(tile_pair.second)); + Tile* tile = tile_pair.second; + prioritized_tiles->push_back( + MakePrioritizedTile(tile, ComputePriorityRectTypeForTile(tile))); } }
diff --git a/cc/resources/picture_layer_tiling.h b/cc/resources/picture_layer_tiling.h index 4a555a28..8ae68e1 100644 --- a/cc/resources/picture_layer_tiling.h +++ b/cc/resources/picture_layer_tiling.h
@@ -212,6 +212,19 @@ friend class TilingSetRasterQueueRequired; friend class TilingSetEvictionQueue; + // PENDING VISIBLE RECT refers to the visible rect that will become current + // upon activation (ie, the pending tree's visible rect). Tiles in this + // region that are not part of the current visible rect are all handled + // here. Note that when processing a pending tree, this rect is the same as + // the visible rect so no tiles are processed in this case. + enum PriorityRectType { + VISIBLE_RECT, + PENDING_VISIBLE_RECT, + SKEWPORT_RECT, + SOON_BORDER_RECT, + EVENTUALLY_RECT + }; + using TileMapKey = std::pair<int, int>; using TileMap = base::ScopedPtrHashMap<TileMapKey, ScopedTilePtr>; @@ -272,8 +285,13 @@ bool ShouldCreateTileAt(int i, int j) const; bool IsTileOccluded(const Tile* tile) const; void UpdateRequiredStatesOnTile(Tile* tile) const; - PrioritizedTile MakePrioritizedTile(Tile* tile) const; - TilePriority ComputePriorityForTile(const Tile* tile) const; + PrioritizedTile MakePrioritizedTile( + Tile* tile, + PriorityRectType priority_rect_type) const; + TilePriority ComputePriorityForTile( + const Tile* tile, + PriorityRectType priority_rect_type) const; + PriorityRectType ComputePriorityRectTypeForTile(const Tile* tile) const; bool has_visible_rect_tiles() const { return has_visible_rect_tiles_; } bool has_skewport_rect_tiles() const { return has_skewport_rect_tiles_; } bool has_soon_border_rect_tiles() const {
diff --git a/cc/resources/tiling_set_eviction_queue.cc b/cc/resources/tiling_set_eviction_queue.cc index fde0a85a..f494da3 100644 --- a/cc/resources/tiling_set_eviction_queue.cc +++ b/cc/resources/tiling_set_eviction_queue.cc
@@ -188,10 +188,10 @@ TilingSetEvictionQueue::EvictionRectIterator::EvictionRectIterator( std::vector<PictureLayerTiling*>* tilings, WhichTree tree, - bool skip_pending_visible_rect) + PictureLayerTiling::PriorityRectType priority_rect_type) : tilings_(tilings), tree_(tree), - skip_pending_visible_rect_(skip_pending_visible_rect), + priority_rect_type_(priority_rect_type), tiling_index_(0) { } @@ -219,12 +219,16 @@ // If there's nothing to evict, return false. if (!tile || !tile->draw_info().has_resource()) return false; - if (skip_pending_visible_rect_ && + // After the pending visible rect has been processed, we must return false + // for pending visible rect tiles as tiling iterators do not ignore those + // tiles. + if (priority_rect_type_ > PictureLayerTiling::PENDING_VISIBLE_RECT && tiling->pending_visible_rect().Intersects(tile->content_rect())) { return false; } (*tilings_)[tiling_index_]->UpdateRequiredStatesOnTile(tile); - prioritized_tile_ = (*tilings_)[tiling_index_]->MakePrioritizedTile(tile); + prioritized_tile_ = (*tilings_)[tiling_index_]->MakePrioritizedTile( + tile, priority_rect_type_); // In other cases, the tile we got is a viable candidate, return true. return true; } @@ -233,9 +237,7 @@ TilingSetEvictionQueue::EventuallyTilingIterator::EventuallyTilingIterator( std::vector<PictureLayerTiling*>* tilings, WhichTree tree) - : EvictionRectIterator(tilings, - tree, - true /* skip_pending_visible_rect */) { + : EvictionRectIterator(tilings, tree, PictureLayerTiling::EVENTUALLY_RECT) { // Find the first tiling with a tile. while (tiling_index_ < tilings_->size()) { if (!(*tilings_)[tiling_index_]->has_eventually_rect_tiles()) { @@ -287,7 +289,7 @@ WhichTree tree) : EvictionRectIterator(tilings, tree, - true /* skip_pending_visible_rect */) { + PictureLayerTiling::SOON_BORDER_RECT) { // Find the first tiling with a tile. while (tiling_index_ < tilings_->size()) { if (!(*tilings_)[tiling_index_]->has_soon_border_rect_tiles()) { @@ -337,9 +339,7 @@ TilingSetEvictionQueue::SkewportTilingIterator::SkewportTilingIterator( std::vector<PictureLayerTiling*>* tilings, WhichTree tree) - : EvictionRectIterator(tilings, - tree, - true /* skip_pending_visible_rect */) { + : EvictionRectIterator(tilings, tree, PictureLayerTiling::SKEWPORT_RECT) { // Find the first tiling with a tile. while (tiling_index_ < tilings_->size()) { if (!(*tilings_)[tiling_index_]->has_skewport_rect_tiles()) { @@ -392,7 +392,7 @@ bool return_required_for_activation_tiles) : EvictionRectIterator(tilings, tree, - false /* skip_pending_visible_rect */), + PictureLayerTiling::PENDING_VISIBLE_RECT), return_required_for_activation_tiles_( return_required_for_activation_tiles) { // Find the first tiling with a tile. @@ -456,9 +456,7 @@ WhichTree tree, bool return_occluded_tiles, bool return_required_for_activation_tiles) - : EvictionRectIterator(tilings, - tree, - false /* skip_pending_visible_rect */), + : EvictionRectIterator(tilings, tree, PictureLayerTiling::VISIBLE_RECT), return_occluded_tiles_(return_occluded_tiles), return_required_for_activation_tiles_( return_required_for_activation_tiles) {
diff --git a/cc/resources/tiling_set_eviction_queue.h b/cc/resources/tiling_set_eviction_queue.h index f5e2c10..58e5a7d7 100644 --- a/cc/resources/tiling_set_eviction_queue.h +++ b/cc/resources/tiling_set_eviction_queue.h
@@ -91,9 +91,10 @@ class EvictionRectIterator { public: EvictionRectIterator(); - EvictionRectIterator(std::vector<PictureLayerTiling*>* tilings, - WhichTree tree, - bool skip_pending_visible_rect); + EvictionRectIterator( + std::vector<PictureLayerTiling*>* tilings, + WhichTree tree, + PictureLayerTiling::PriorityRectType priority_rect_type); bool done() const { return !prioritized_tile_.tile(); } const PrioritizedTile& operator*() const { return prioritized_tile_; } @@ -109,7 +110,7 @@ PrioritizedTile prioritized_tile_; std::vector<PictureLayerTiling*>* tilings_; WhichTree tree_; - bool skip_pending_visible_rect_; + PictureLayerTiling::PriorityRectType priority_rect_type_; size_t tiling_index_; };
diff --git a/cc/resources/tiling_set_raster_queue_all.cc b/cc/resources/tiling_set_raster_queue_all.cc index ba2f115..330f0883 100644 --- a/cc/resources/tiling_set_raster_queue_all.cc +++ b/cc/resources/tiling_set_raster_queue_all.cc
@@ -148,24 +148,25 @@ TilingSetRasterQueueAll::OnePriorityRectIterator::OnePriorityRectIterator( PictureLayerTiling* tiling, - TilingData* tiling_data) - : tiling_(tiling), tiling_data_(tiling_data) { + TilingData* tiling_data, + PictureLayerTiling::PriorityRectType priority_rect_type) + : tiling_(tiling), + tiling_data_(tiling_data), + priority_rect_type_(priority_rect_type) { } template <typename TilingIteratorType> void TilingSetRasterQueueAll::OnePriorityRectIterator::AdvanceToNextTile( TilingIteratorType* iterator) { - current_tile_ = PrioritizedTile(); - Tile* tile = nullptr; - while (!tile || !TileNeedsRaster(tile)) { + bool found_tile = false; + while (!found_tile) { ++(*iterator); if (!(*iterator)) { - return; + current_tile_ = PrioritizedTile(); + break; } - tile = tiling_->TileAt(iterator->index_x(), iterator->index_y()); + found_tile = GetFirstTileAndCheckIfValid(iterator); } - tiling_->UpdateRequiredStatesOnTile(tile); - current_tile_ = tiling_->MakePrioritizedTile(tile); } template <typename TilingIteratorType> @@ -176,8 +177,16 @@ current_tile_ = PrioritizedTile(); return false; } + // After the pending visible rect has been processed, we must return false + // for pending visible rect tiles as tiling iterators do not ignore those + // tiles. + if (priority_rect_type_ > PictureLayerTiling::PENDING_VISIBLE_RECT && + tiling_->pending_visible_rect().Intersects(tile->content_rect())) { + current_tile_ = PrioritizedTile(); + return false; + } tiling_->UpdateRequiredStatesOnTile(tile); - current_tile_ = tiling_->MakePrioritizedTile(tile); + current_tile_ = tiling_->MakePrioritizedTile(tile, priority_rect_type_); return true; } @@ -185,7 +194,9 @@ TilingSetRasterQueueAll::VisibleTilingIterator::VisibleTilingIterator( PictureLayerTiling* tiling, TilingData* tiling_data) - : OnePriorityRectIterator(tiling, tiling_data) { + : OnePriorityRectIterator(tiling, + tiling_data, + PictureLayerTiling::VISIBLE_RECT) { if (!tiling_->has_visible_rect_tiles()) return; iterator_ = @@ -208,7 +219,9 @@ TilingSetRasterQueueAll::PendingVisibleTilingIterator:: PendingVisibleTilingIterator(PictureLayerTiling* tiling, TilingData* tiling_data) - : OnePriorityRectIterator(tiling, tiling_data) { + : OnePriorityRectIterator(tiling, + tiling_data, + PictureLayerTiling::PENDING_VISIBLE_RECT) { iterator_ = TilingData::DifferenceIterator(tiling_data_, tiling_->pending_visible_rect(), tiling_->current_visible_rect()); @@ -229,7 +242,9 @@ TilingSetRasterQueueAll::SkewportTilingIterator::SkewportTilingIterator( PictureLayerTiling* tiling, TilingData* tiling_data) - : OnePriorityRectIterator(tiling, tiling_data), + : OnePriorityRectIterator(tiling, + tiling_data, + PictureLayerTiling::SKEWPORT_RECT), pending_visible_rect_(tiling->pending_visible_rect()) { if (!tiling_->has_skewport_rect_tiles()) return; @@ -242,6 +257,8 @@ ++(*this); return; } + // TODO(e_hakkinen): This is not needed as GetFirstTileAndCheckIfValid + // does the same checking. if (current_tile_.tile()->content_rect().Intersects(pending_visible_rect_)) ++(*this); } @@ -250,6 +267,8 @@ TilingSetRasterQueueAll::SkewportTilingIterator:: operator++() { AdvanceToNextTile(&iterator_); + // TODO(e_hakkinen): This is not needed as GetFirstTileAndCheckIfValid called + // by AdvanceToNextTile does the same checking. while (!done()) { if (!current_tile_.tile()->content_rect().Intersects(pending_visible_rect_)) break; @@ -262,7 +281,9 @@ TilingSetRasterQueueAll::SoonBorderTilingIterator::SoonBorderTilingIterator( PictureLayerTiling* tiling, TilingData* tiling_data) - : OnePriorityRectIterator(tiling, tiling_data), + : OnePriorityRectIterator(tiling, + tiling_data, + PictureLayerTiling::SOON_BORDER_RECT), pending_visible_rect_(tiling->pending_visible_rect()) { if (!tiling_->has_soon_border_rect_tiles()) return; @@ -275,6 +296,8 @@ ++(*this); return; } + // TODO(e_hakkinen): This is not needed as GetFirstTileAndCheckIfValid + // does the same checking. if (current_tile_.tile()->content_rect().Intersects(pending_visible_rect_)) ++(*this); } @@ -283,6 +306,8 @@ TilingSetRasterQueueAll::SoonBorderTilingIterator:: operator++() { AdvanceToNextTile(&iterator_); + // TODO(e_hakkinen): This is not needed as GetFirstTileAndCheckIfValid called + // by AdvanceToNextTile does the same checking. while (!done()) { if (!current_tile_.tile()->content_rect().Intersects(pending_visible_rect_)) break; @@ -295,7 +320,9 @@ TilingSetRasterQueueAll::EventuallyTilingIterator::EventuallyTilingIterator( PictureLayerTiling* tiling, TilingData* tiling_data) - : OnePriorityRectIterator(tiling, tiling_data), + : OnePriorityRectIterator(tiling, + tiling_data, + PictureLayerTiling::EVENTUALLY_RECT), pending_visible_rect_(tiling->pending_visible_rect()) { if (!tiling_->has_eventually_rect_tiles()) return; @@ -308,6 +335,8 @@ ++(*this); return; } + // TODO(e_hakkinen): This is not needed as GetFirstTileAndCheckIfValid + // does the same checking. if (current_tile_.tile()->content_rect().Intersects(pending_visible_rect_)) ++(*this); } @@ -316,6 +345,8 @@ TilingSetRasterQueueAll::EventuallyTilingIterator:: operator++() { AdvanceToNextTile(&iterator_); + // TODO(e_hakkinen): This is not needed as GetFirstTileAndCheckIfValid called + // by AdvanceToNextTile does the same checking. while (!done()) { if (!current_tile_.tile()->content_rect().Intersects(pending_visible_rect_)) break; @@ -331,7 +362,7 @@ TilingSetRasterQueueAll::TilingIterator::TilingIterator( PictureLayerTiling* tiling, TilingData* tiling_data) - : tiling_(tiling), tiling_data_(tiling_data), phase_(VISIBLE_RECT) { + : tiling_(tiling), tiling_data_(tiling_data), phase_(Phase::VISIBLE_RECT) { visible_iterator_ = VisibleTilingIterator(tiling_, tiling_data_); if (visible_iterator_.done()) { AdvancePhase(); @@ -344,32 +375,32 @@ } void TilingSetRasterQueueAll::TilingIterator::AdvancePhase() { - DCHECK_LT(phase_, EVENTUALLY_RECT); + DCHECK_LT(phase_, Phase::EVENTUALLY_RECT); current_tile_ = PrioritizedTile(); - while (!current_tile_.tile() && phase_ < EVENTUALLY_RECT) { + while (!current_tile_.tile() && phase_ < Phase::EVENTUALLY_RECT) { phase_ = static_cast<Phase>(phase_ + 1); switch (phase_) { - case VISIBLE_RECT: + case Phase::VISIBLE_RECT: NOTREACHED(); return; - case PENDING_VISIBLE_RECT: + case Phase::PENDING_VISIBLE_RECT: pending_visible_iterator_ = PendingVisibleTilingIterator(tiling_, tiling_data_); if (!pending_visible_iterator_.done()) current_tile_ = *pending_visible_iterator_; break; - case SKEWPORT_RECT: + case Phase::SKEWPORT_RECT: skewport_iterator_ = SkewportTilingIterator(tiling_, tiling_data_); if (!skewport_iterator_.done()) current_tile_ = *skewport_iterator_; break; - case SOON_BORDER_RECT: + case Phase::SOON_BORDER_RECT: soon_border_iterator_ = SoonBorderTilingIterator(tiling_, tiling_data_); if (!soon_border_iterator_.done()) current_tile_ = *soon_border_iterator_; break; - case EVENTUALLY_RECT: + case Phase::EVENTUALLY_RECT: eventually_iterator_ = EventuallyTilingIterator(tiling_, tiling_data_); if (!eventually_iterator_.done()) current_tile_ = *eventually_iterator_; @@ -382,7 +413,7 @@ TilingSetRasterQueueAll::TilingIterator:: operator++() { switch (phase_) { - case VISIBLE_RECT: + case Phase::VISIBLE_RECT: ++visible_iterator_; if (visible_iterator_.done()) { AdvancePhase(); @@ -390,7 +421,7 @@ } current_tile_ = *visible_iterator_; break; - case PENDING_VISIBLE_RECT: + case Phase::PENDING_VISIBLE_RECT: ++pending_visible_iterator_; if (pending_visible_iterator_.done()) { AdvancePhase(); @@ -398,7 +429,7 @@ } current_tile_ = *pending_visible_iterator_; break; - case SKEWPORT_RECT: + case Phase::SKEWPORT_RECT: ++skewport_iterator_; if (skewport_iterator_.done()) { AdvancePhase(); @@ -406,7 +437,7 @@ } current_tile_ = *skewport_iterator_; break; - case SOON_BORDER_RECT: + case Phase::SOON_BORDER_RECT: ++soon_border_iterator_; if (soon_border_iterator_.done()) { AdvancePhase(); @@ -414,7 +445,7 @@ } current_tile_ = *soon_border_iterator_; break; - case EVENTUALLY_RECT: + case Phase::EVENTUALLY_RECT: ++eventually_iterator_; if (eventually_iterator_.done()) { current_tile_ = PrioritizedTile();
diff --git a/cc/resources/tiling_set_raster_queue_all.h b/cc/resources/tiling_set_raster_queue_all.h index dd3a7a8..8c8b012 100644 --- a/cc/resources/tiling_set_raster_queue_all.h +++ b/cc/resources/tiling_set_raster_queue_all.h
@@ -31,8 +31,10 @@ class OnePriorityRectIterator { public: OnePriorityRectIterator(); - OnePriorityRectIterator(PictureLayerTiling* tiling, - TilingData* tiling_data); + OnePriorityRectIterator( + PictureLayerTiling* tiling, + TilingData* tiling_data, + PictureLayerTiling::PriorityRectType priority_rect_type); bool done() const { return !current_tile_.tile(); } const PrioritizedTile& operator*() const { return current_tile_; } @@ -51,6 +53,7 @@ PrioritizedTile current_tile_; PictureLayerTiling* tiling_; TilingData* tiling_data_; + PictureLayerTiling::PriorityRectType priority_rect_type_; }; // Iterates over visible rect only, left to right top to bottom order. @@ -131,13 +134,13 @@ const PrioritizedTile& operator*() const { return current_tile_; } TilePriority::PriorityBin type() const { switch (phase_) { - case VISIBLE_RECT: + case Phase::VISIBLE_RECT: return TilePriority::NOW; - case PENDING_VISIBLE_RECT: - case SKEWPORT_RECT: - case SOON_BORDER_RECT: + case Phase::PENDING_VISIBLE_RECT: + case Phase::SKEWPORT_RECT: + case Phase::SOON_BORDER_RECT: return TilePriority::SOON; - case EVENTUALLY_RECT: + case Phase::EVENTUALLY_RECT: return TilePriority::EVENTUALLY; } NOTREACHED(); @@ -147,18 +150,7 @@ TilingIterator& operator++(); private: - // PENDING VISIBLE RECT refers to the visible rect that will become current - // upon activation (ie, the pending tree's visible rect). Tiles in this - // region that are not part of the current visible rect are all handled - // here. Note that when processing a pending tree, this rect is the same as - // the visible rect so no tiles are processed in this case. - enum Phase { - VISIBLE_RECT, - PENDING_VISIBLE_RECT, - SKEWPORT_RECT, - SOON_BORDER_RECT, - EVENTUALLY_RECT - }; + using Phase = PictureLayerTiling::PriorityRectType; void AdvancePhase();
diff --git a/cc/resources/tiling_set_raster_queue_required.cc b/cc/resources/tiling_set_raster_queue_required.cc index 19c2c814..f95cd42 100644 --- a/cc/resources/tiling_set_raster_queue_required.cc +++ b/cc/resources/tiling_set_raster_queue_required.cc
@@ -104,7 +104,8 @@ if (tile && tile->draw_info().NeedsRaster() && !tiling_->IsTileOccluded(tile)) { tiling_->UpdateRequiredStatesOnTile(tile); - current_tile_ = tiling_->MakePrioritizedTile(tile); + current_tile_ = tiling_->MakePrioritizedTile( + tile, tiling_->ComputePriorityRectTypeForTile(tile)); return; } ++(*this); @@ -143,7 +144,8 @@ } tiling_->UpdateRequiredStatesOnTile(tile); - current_tile_ = tiling_->MakePrioritizedTile(tile); + current_tile_ = tiling_->MakePrioritizedTile( + tile, tiling_->ComputePriorityRectTypeForTile(tile)); return *this; }
diff --git a/cc/test/fake_output_surface.h b/cc/test/fake_output_surface.h index 6028cad..7041a44 100644 --- a/cc/test/fake_output_surface.h +++ b/cc/test/fake_output_surface.h
@@ -29,7 +29,8 @@ static scoped_ptr<FakeOutputSurface> Create3d( scoped_refptr<ContextProvider> context_provider) { - return make_scoped_ptr(new FakeOutputSurface(context_provider, false)); + return make_scoped_ptr(new FakeOutputSurface( + context_provider, TestContextProvider::Create(), false)); } static scoped_ptr<FakeOutputSurface> Create3d( @@ -41,8 +42,9 @@ static scoped_ptr<FakeOutputSurface> Create3d( scoped_ptr<TestWebGraphicsContext3D> context) { - return make_scoped_ptr(new FakeOutputSurface( - TestContextProvider::Create(context.Pass()), false)); + return make_scoped_ptr( + new FakeOutputSurface(TestContextProvider::Create(context.Pass()), + TestContextProvider::Create(), false)); } static scoped_ptr<FakeOutputSurface> CreateSoftware(
diff --git a/cc/trees/layer_tree_host.cc b/cc/trees/layer_tree_host.cc index 45ecee4..6c4696e 100644 --- a/cc/trees/layer_tree_host.cc +++ b/cc/trees/layer_tree_host.cc
@@ -330,8 +330,8 @@ sync_tree->set_top_controls_height(top_controls_height_); sync_tree->PushTopControlsFromMainThread(top_controls_shown_ratio_); - host_impl->set_has_gpu_rasterization_trigger(has_gpu_rasterization_trigger_); - host_impl->set_content_is_suitable_for_gpu_rasterization( + host_impl->SetHasGpuRasterizationTrigger(has_gpu_rasterization_trigger_); + host_impl->SetContentIsSuitableForGpuRasterization( content_is_suitable_for_gpu_rasterization_); RecordGpuRasterizationHistogram(); @@ -434,8 +434,8 @@ settings_, client, proxy_.get(), rendering_stats_instrumentation_.get(), shared_bitmap_manager_, gpu_memory_buffer_manager_, task_graph_runner_, id_); - host_impl->set_has_gpu_rasterization_trigger(has_gpu_rasterization_trigger_); - host_impl->set_content_is_suitable_for_gpu_rasterization( + host_impl->SetHasGpuRasterizationTrigger(has_gpu_rasterization_trigger_); + host_impl->SetContentIsSuitableForGpuRasterization( content_is_suitable_for_gpu_rasterization_); shared_bitmap_manager_ = NULL; gpu_memory_buffer_manager_ = NULL; @@ -1279,8 +1279,8 @@ } void LayerTreeHost::BreakSwapPromises(SwapPromise::DidNotSwapReason reason) { - for (size_t i = 0; i < swap_promise_list_.size(); i++) - swap_promise_list_[i]->DidNotSwap(reason); + for (auto* swap_promise : swap_promise_list_) + swap_promise->DidNotSwap(reason); swap_promise_list_.clear(); }
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc index 6125337..d421f84b 100644 --- a/cc/trees/layer_tree_host_impl.cc +++ b/cc/trees/layer_tree_host_impl.cc
@@ -195,6 +195,7 @@ use_gpu_rasterization_(false), use_msaa_(false), gpu_rasterization_status_(GpuRasterizationStatus::OFF_DEVICE), + tree_resources_for_gpu_rasterization_dirty_(false), input_handler_client_(NULL), did_lock_scrolling_layer_(false), should_bubble_scrolls_(false), @@ -308,7 +309,9 @@ void LayerTreeHostImpl::CommitComplete() { TRACE_EVENT0("cc", "LayerTreeHostImpl::CommitComplete"); - UpdateGpuRasterizationStatus(); + // LayerTreeHost may have changed the GPU rasterization flags state, which + // may require an update of the tree resources. + UpdateTreeResourcesForGpuRasterizationIfNeeded(); sync_tree()->set_needs_update_draw_properties(); if (settings_.impl_side_painting) { @@ -1584,6 +1587,20 @@ renderer_->Finish(); } +bool LayerTreeHostImpl::CanUseGpuRasterization() { + if (!(output_surface_ && output_surface_->context_provider() && + output_surface_->worker_context_provider())) + return false; + + ContextProvider* context_provider = + output_surface_->worker_context_provider(); + base::AutoLock context_lock(*context_provider->GetLock()); + if (!context_provider->GrContext()) + return false; + + return true; +} + void LayerTreeHostImpl::UpdateGpuRasterizationStatus() { bool use_gpu = false; bool use_msaa = false; @@ -1613,6 +1630,17 @@ gpu_rasterization_status_ = GpuRasterizationStatus::OFF_CONTENT; } + if (use_gpu && !use_gpu_rasterization_) { + if (!CanUseGpuRasterization()) { + // If GPU rasterization is unusable, e.g. if GlContext could not + // be created due to losing the GL context, force use of software + // raster. + use_gpu = false; + use_msaa = false; + gpu_rasterization_status_ = GpuRasterizationStatus::OFF_DEVICE; + } + } + if (use_gpu == use_gpu_rasterization_ && use_msaa == use_msaa_) return; @@ -1621,6 +1649,13 @@ use_gpu_rasterization_ = use_gpu; use_msaa_ = use_msaa; + tree_resources_for_gpu_rasterization_dirty_ = true; +} + +void LayerTreeHostImpl::UpdateTreeResourcesForGpuRasterizationIfNeeded() { + if (!tree_resources_for_gpu_rasterization_dirty_) + return; + // Clean up and replace existing tile manager with another one that uses // appropriate rasterizer. ReleaseTreeResources(); @@ -1634,6 +1669,8 @@ // We would not have any content to draw until the pending tree is activated. // Prevent the active tree from drawing until activation. SetRequiresHighResToDraw(); + + tree_resources_for_gpu_rasterization_dirty_ = false; } const RendererCapabilitiesImpl& @@ -1990,8 +2027,6 @@ } DCHECK(renderer_); - // Since the new renderer may be capable of MSAA, update status here. - UpdateGpuRasterizationStatus(); renderer_->SetVisible(visible_); SetFullRootLayerDamage(); @@ -2176,6 +2211,9 @@ CreateAndSetRenderer(); + // Since the new renderer may be capable of MSAA, update status here. + UpdateGpuRasterizationStatus(); + if (settings_.impl_side_painting && settings_.raster_enabled) CreateAndSetTileManager(); RecreateTreeResources(); @@ -3086,7 +3124,7 @@ if (active_tree_->root_layer()) { scoped_ptr<base::Value> json(active_tree_->root_layer()->LayerTreeAsJson()); base::JSONWriter::WriteWithOptions( - json.get(), base::JSONWriter::OPTIONS_PRETTY_PRINT, &str); + *json, base::JSONWriter::OPTIONS_PRETTY_PRINT, &str); } return str; }
diff --git a/cc/trees/layer_tree_host_impl.h b/cc/trees/layer_tree_host_impl.h index 54776e7..82955d4e 100644 --- a/cc/trees/layer_tree_host_impl.h +++ b/cc/trees/layer_tree_host_impl.h
@@ -321,13 +321,16 @@ virtual bool InitializeRenderer(scoped_ptr<OutputSurface> output_surface); TileManager* tile_manager() { return tile_manager_.get(); } - void set_has_gpu_rasterization_trigger(bool flag) { + void SetHasGpuRasterizationTrigger(bool flag) { has_gpu_rasterization_trigger_ = flag; + UpdateGpuRasterizationStatus(); } - void set_content_is_suitable_for_gpu_rasterization(bool flag) { + void SetContentIsSuitableForGpuRasterization(bool flag) { content_is_suitable_for_gpu_rasterization_ = flag; + UpdateGpuRasterizationStatus(); } - void UpdateGpuRasterizationStatus(); + bool CanUseGpuRasterization(); + void UpdateTreeResourcesForGpuRasterizationIfNeeded(); bool use_gpu_rasterization() const { return use_gpu_rasterization_; } bool use_msaa() const { return use_msaa_; } @@ -571,6 +574,8 @@ void ReleaseTreeResources(); void RecreateTreeResources(); + void UpdateGpuRasterizationStatus(); + bool IsSynchronousSingleThreaded() const; Viewport* viewport() { return viewport_.get(); } @@ -646,6 +651,7 @@ bool use_gpu_rasterization_; bool use_msaa_; GpuRasterizationStatus gpu_rasterization_status_; + bool tree_resources_for_gpu_rasterization_dirty_; scoped_ptr<TileTaskWorkerPool> tile_task_worker_pool_; scoped_ptr<ResourcePool> resource_pool_; scoped_ptr<ResourcePool> staging_resource_pool_;
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc index cc239da..15994ef9 100644 --- a/cc/trees/layer_tree_host_impl_unittest.cc +++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -5931,11 +5931,9 @@ // when visible. LayerTreeSettings settings; settings.gpu_rasterization_enabled = true; - host_impl_ = LayerTreeHostImpl::Create( - settings, this, &proxy_, &stats_instrumentation_, NULL, NULL, NULL, 0); - host_impl_->set_content_is_suitable_for_gpu_rasterization(true); - host_impl_->set_has_gpu_rasterization_trigger(true); - host_impl_->UpdateGpuRasterizationStatus(); + CreateHostImpl(settings, CreateOutputSurface()); + host_impl_->SetContentIsSuitableForGpuRasterization(true); + host_impl_->SetHasGpuRasterizationTrigger(true); host_impl_->SetVisible(true); host_impl_->SetMemoryPolicy(policy1); EXPECT_EQ(policy1.bytes_limit_when_visible, current_limit_bytes_); @@ -5977,22 +5975,22 @@ host_impl_->ResetRequiresHighResToDraw(); - host_impl_->set_content_is_suitable_for_gpu_rasterization(true); - host_impl_->set_has_gpu_rasterization_trigger(false); - host_impl_->UpdateGpuRasterizationStatus(); + host_impl_->SetContentIsSuitableForGpuRasterization(true); + host_impl_->SetHasGpuRasterizationTrigger(false); + host_impl_->UpdateTreeResourcesForGpuRasterizationIfNeeded(); EXPECT_FALSE(host_impl_->RequiresHighResToDraw()); - host_impl_->set_has_gpu_rasterization_trigger(true); - host_impl_->UpdateGpuRasterizationStatus(); + host_impl_->SetHasGpuRasterizationTrigger(true); + host_impl_->UpdateTreeResourcesForGpuRasterizationIfNeeded(); EXPECT_TRUE(host_impl_->RequiresHighResToDraw()); - host_impl_->set_has_gpu_rasterization_trigger(false); - host_impl_->UpdateGpuRasterizationStatus(); + host_impl_->SetHasGpuRasterizationTrigger(false); + host_impl_->UpdateTreeResourcesForGpuRasterizationIfNeeded(); EXPECT_TRUE(host_impl_->RequiresHighResToDraw()); host_impl_->ResetRequiresHighResToDraw(); EXPECT_FALSE(host_impl_->RequiresHighResToDraw()); - host_impl_->set_has_gpu_rasterization_trigger(true); - host_impl_->UpdateGpuRasterizationStatus(); + host_impl_->SetHasGpuRasterizationTrigger(true); + host_impl_->UpdateTreeResourcesForGpuRasterizationIfNeeded(); EXPECT_TRUE(host_impl_->RequiresHighResToDraw()); } @@ -7727,22 +7725,19 @@ TEST_F(LayerTreeHostImplTest, GpuRasterizationStatusModes) { EXPECT_FALSE(host_impl_->use_gpu_rasterization()); - host_impl_->set_has_gpu_rasterization_trigger(true); - host_impl_->set_content_is_suitable_for_gpu_rasterization(true); - host_impl_->UpdateGpuRasterizationStatus(); + host_impl_->SetHasGpuRasterizationTrigger(true); + host_impl_->SetContentIsSuitableForGpuRasterization(true); EXPECT_EQ(GpuRasterizationStatus::ON, host_impl_->gpu_rasterization_status()); EXPECT_TRUE(host_impl_->use_gpu_rasterization()); - host_impl_->set_has_gpu_rasterization_trigger(false); - host_impl_->set_content_is_suitable_for_gpu_rasterization(true); - host_impl_->UpdateGpuRasterizationStatus(); + host_impl_->SetHasGpuRasterizationTrigger(false); + host_impl_->SetContentIsSuitableForGpuRasterization(true); EXPECT_EQ(GpuRasterizationStatus::OFF_VIEWPORT, host_impl_->gpu_rasterization_status()); EXPECT_FALSE(host_impl_->use_gpu_rasterization()); - host_impl_->set_has_gpu_rasterization_trigger(true); - host_impl_->set_content_is_suitable_for_gpu_rasterization(false); - host_impl_->UpdateGpuRasterizationStatus(); + host_impl_->SetHasGpuRasterizationTrigger(true); + host_impl_->SetContentIsSuitableForGpuRasterization(false); EXPECT_EQ(GpuRasterizationStatus::OFF_CONTENT, host_impl_->gpu_rasterization_status()); EXPECT_FALSE(host_impl_->use_gpu_rasterization()); @@ -7756,9 +7751,8 @@ msaaSettings.gpu_rasterization_msaa_sample_count = 4; EXPECT_TRUE(CreateHostImpl( msaaSettings, FakeOutputSurface::Create3d(context_with_msaa.Pass()))); - host_impl_->set_has_gpu_rasterization_trigger(true); - host_impl_->set_content_is_suitable_for_gpu_rasterization(false); - host_impl_->UpdateGpuRasterizationStatus(); + host_impl_->SetHasGpuRasterizationTrigger(true); + host_impl_->SetContentIsSuitableForGpuRasterization(false); EXPECT_EQ(GpuRasterizationStatus::MSAA_CONTENT, host_impl_->gpu_rasterization_status()); EXPECT_TRUE(host_impl_->use_gpu_rasterization()); @@ -7767,9 +7761,8 @@ LayerTreeSettings settings = DefaultSettings(); settings.gpu_rasterization_enabled = false; EXPECT_TRUE(CreateHostImpl(settings, FakeOutputSurface::Create3d())); - host_impl_->set_has_gpu_rasterization_trigger(true); - host_impl_->set_content_is_suitable_for_gpu_rasterization(true); - host_impl_->UpdateGpuRasterizationStatus(); + host_impl_->SetHasGpuRasterizationTrigger(true); + host_impl_->SetContentIsSuitableForGpuRasterization(true); EXPECT_EQ(GpuRasterizationStatus::OFF_DEVICE, host_impl_->gpu_rasterization_status()); EXPECT_FALSE(host_impl_->use_gpu_rasterization()); @@ -7777,9 +7770,8 @@ settings.gpu_rasterization_forced = true; EXPECT_TRUE(CreateHostImpl(settings, FakeOutputSurface::Create3d())); - host_impl_->set_has_gpu_rasterization_trigger(false); - host_impl_->set_content_is_suitable_for_gpu_rasterization(false); - host_impl_->UpdateGpuRasterizationStatus(); + host_impl_->SetHasGpuRasterizationTrigger(false); + host_impl_->SetContentIsSuitableForGpuRasterization(false); EXPECT_EQ(GpuRasterizationStatus::ON_FORCED, host_impl_->gpu_rasterization_status()); EXPECT_TRUE(host_impl_->use_gpu_rasterization());
diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc index 51ea3d9..98ac5a1 100644 --- a/cc/trees/layer_tree_host_unittest.cc +++ b/cc/trees/layer_tree_host_unittest.cc
@@ -4927,11 +4927,13 @@ struct TestSwapPromiseResult { TestSwapPromiseResult() - : did_swap_called(false), + : did_activate_called(false), + did_swap_called(false), did_not_swap_called(false), dtor_called(false), - reason(SwapPromise::DID_NOT_SWAP_UNKNOWN) {} + reason(SwapPromise::COMMIT_FAILS) {} + bool did_activate_called; bool did_swap_called; bool did_not_swap_called; bool dtor_called; @@ -4948,8 +4950,17 @@ result_->dtor_called = true; } + void DidActivate() override { + base::AutoLock lock(result_->lock); + EXPECT_FALSE(result_->did_activate_called); + EXPECT_FALSE(result_->did_swap_called); + EXPECT_FALSE(result_->did_not_swap_called); + result_->did_activate_called = true; + } + void DidSwap(CompositorFrameMetadata* metadata) override { base::AutoLock lock(result_->lock); + EXPECT_TRUE(result_->did_activate_called); EXPECT_FALSE(result_->did_swap_called); EXPECT_FALSE(result_->did_not_swap_called); result_->did_swap_called = true; @@ -4959,6 +4970,8 @@ base::AutoLock lock(result_->lock); EXPECT_FALSE(result_->did_swap_called); EXPECT_FALSE(result_->did_not_swap_called); + EXPECT_FALSE(result_->did_activate_called && + reason != DidNotSwapReason::SWAP_FAILS); result_->did_not_swap_called = true; result_->reason = reason; } @@ -4992,6 +5005,22 @@ } } + void WillActivateTreeOnThread(LayerTreeHostImpl* host_impl) override { + if (host_impl->pending_tree()) { + int frame = host_impl->pending_tree()->source_frame_number(); + base::AutoLock lock(swap_promise_result_[frame].lock); + EXPECT_FALSE(swap_promise_result_[frame].did_activate_called); + EXPECT_FALSE(swap_promise_result_[frame].did_swap_called); + } + } + + void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) override { + int frame = host_impl->active_tree()->source_frame_number(); + base::AutoLock lock(swap_promise_result_[frame].lock); + EXPECT_TRUE(swap_promise_result_[frame].did_activate_called); + EXPECT_FALSE(swap_promise_result_[frame].did_swap_called); + } + void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override { commit_complete_count_++; if (commit_complete_count_ == 1) { @@ -5019,6 +5048,7 @@ { // The second commit is aborted since it contains no updates. base::AutoLock lock(swap_promise_result_[1].lock); + EXPECT_FALSE(swap_promise_result_[1].did_activate_called); EXPECT_FALSE(swap_promise_result_[1].did_swap_called); EXPECT_TRUE(swap_promise_result_[1].did_not_swap_called); EXPECT_EQ(SwapPromise::COMMIT_NO_UPDATE, swap_promise_result_[1].reason); @@ -5029,6 +5059,7 @@ // The last commit completes but it does not cause swap buffer because // there is no damage in the frame data. base::AutoLock lock(swap_promise_result_[2].lock); + EXPECT_TRUE(swap_promise_result_[2].did_activate_called); EXPECT_FALSE(swap_promise_result_[2].did_swap_called); EXPECT_TRUE(swap_promise_result_[2].did_not_swap_called); EXPECT_EQ(SwapPromise::SWAP_FAILS, swap_promise_result_[2].reason); @@ -5078,6 +5109,41 @@ } } + void WillActivateTreeOnThread(LayerTreeHostImpl* host_impl) override { + if (host_impl->pending_tree()) { + if (host_impl->pending_tree()->source_frame_number() == 1) { + base::AutoLock lock(swap_promise_result_.lock); + EXPECT_FALSE(swap_promise_result_.did_activate_called); + EXPECT_FALSE(swap_promise_result_.did_swap_called); + SetCallback(true); + } else { + SetCallback(false); + } + } + } + + void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) override { + if (host_impl->active_tree()->source_frame_number() == 1) { + base::AutoLock lock(swap_promise_result_.lock); + EXPECT_TRUE(swap_promise_result_.did_activate_called); + EXPECT_FALSE(swap_promise_result_.did_swap_called); + } + } + + void ActivationCallback() { + // DidActivate needs to happen before the tree activation callback. + base::AutoLock lock(swap_promise_result_.lock); + EXPECT_TRUE(swap_promise_result_.did_activate_called); + } + + void SetCallback(bool enable) { + output_surface()->SetTreeActivationCallback( + enable + ? base::Bind(&LayerTreeHostTestKeepSwapPromise::ActivationCallback, + base::Unretained(this)) + : base::Closure()); + } + void SwapBuffersOnThread(LayerTreeHostImpl* host_impl, bool result) override { EXPECT_TRUE(result); if (host_impl->active_tree()->source_frame_number() >= 1) { @@ -5127,6 +5193,7 @@ void AfterTest() override { { base::AutoLock lock(swap_promise_result_.lock); + EXPECT_FALSE(swap_promise_result_.did_activate_called); EXPECT_FALSE(swap_promise_result_.did_swap_called); EXPECT_TRUE(swap_promise_result_.did_not_swap_called); EXPECT_EQ(SwapPromise::COMMIT_FAILS, swap_promise_result_.reason); @@ -5176,6 +5243,7 @@ void AfterTest() override { { base::AutoLock lock(swap_promise_result_.lock); + EXPECT_FALSE(swap_promise_result_.did_activate_called); EXPECT_FALSE(swap_promise_result_.did_swap_called); EXPECT_TRUE(swap_promise_result_.did_not_swap_called); EXPECT_EQ(SwapPromise::COMMIT_FAILS, swap_promise_result_.reason); @@ -5829,6 +5897,7 @@ // Second swap promise fails to swap. { base::AutoLock lock(swap_promise_result_[1].lock); + EXPECT_TRUE(swap_promise_result_[1].did_activate_called); EXPECT_FALSE(swap_promise_result_[1].did_swap_called); EXPECT_TRUE(swap_promise_result_[1].did_not_swap_called); EXPECT_EQ(SwapPromise::SWAP_FAILS, swap_promise_result_[1].reason); @@ -5838,6 +5907,7 @@ // Third swap promises also fails to swap (and draw). { base::AutoLock lock(swap_promise_result_[2].lock); + EXPECT_TRUE(swap_promise_result_[2].did_activate_called); EXPECT_FALSE(swap_promise_result_[2].did_swap_called); EXPECT_TRUE(swap_promise_result_[2].did_not_swap_called); EXPECT_EQ(SwapPromise::SWAP_FAILS, swap_promise_result_[2].reason);
diff --git a/cc/trees/layer_tree_host_unittest_delegated.cc b/cc/trees/layer_tree_host_unittest_delegated.cc index 6d0fb0a..2864eb8 100644 --- a/cc/trees/layer_tree_host_unittest_delegated.cc +++ b/cc/trees/layer_tree_host_unittest_delegated.cc
@@ -404,6 +404,37 @@ SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostDelegatedTestCreateChildId); +class LayerTreeHostDelegatedTestDontUseLostChildIdAfterCommit + : public LayerTreeHostDelegatedTestCaseSingleDelegatedLayer { + protected: + void BeginTest() override { + SetFrameData(CreateFrameData(gfx::Rect(0, 0, 1, 1), gfx::Rect(0, 0, 1, 1))); + LayerTreeHostDelegatedTestCaseSingleDelegatedLayer::BeginTest(); + } + + void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override { + // Act like the context was lost while the layer is in the pending tree. + LayerImpl* root_impl = host_impl->sync_tree()->root_layer(); + FakeDelegatedRendererLayerImpl* delegated_impl = + static_cast<FakeDelegatedRendererLayerImpl*>(root_impl->children()[0]); + delegated_impl->ReleaseResources(); + } + + void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) override { + LayerImpl* root_impl = host_impl->active_tree()->root_layer(); + FakeDelegatedRendererLayerImpl* delegated_impl = + static_cast<FakeDelegatedRendererLayerImpl*>(root_impl->children()[0]); + + // Should not try to activate a frame without a child id. If we did try to + // activate we would crash. + EXPECT_FALSE(delegated_impl->ChildId()); + EndTest(); + } +}; + +MULTI_THREAD_IMPL_TEST_F( + LayerTreeHostDelegatedTestDontUseLostChildIdAfterCommit); + // Test that we can gracefully handle invalid frames after the context was lost. // For example, we might be trying to use the previous frame in that case and // have to make sure we don't crash because our resource accounting goes wrong.
diff --git a/cc/trees/layer_tree_impl.cc b/cc/trees/layer_tree_impl.cc index 276885914..01a4cfd 100644 --- a/cc/trees/layer_tree_impl.cc +++ b/cc/trees/layer_tree_impl.cc
@@ -70,7 +70,8 @@ } LayerTreeImpl::~LayerTreeImpl() { - BreakSwapPromises(SwapPromise::SWAP_FAILS); + BreakSwapPromises(IsActiveTree() ? SwapPromise::SWAP_FAILS + : SwapPromise::ACTIVATION_FAILS); // Need to explicitly clear the tree prior to destroying this so that // the LayerTreeImpl pointer is still valid in the LayerImpl dtor. @@ -744,6 +745,8 @@ root_layer(), [](LayerImpl* layer) { layer->DidBecomeActive(); }); } + for (auto* swap_promise : swap_promise_list_) + swap_promise->DidActivate(); devtools_instrumentation::DidActivateLayerTree(layer_tree_host_impl_->id(), source_frame_number_); } @@ -990,8 +993,8 @@ state->EndArray(); state->BeginArray("swap_promise_trace_ids"); - for (size_t i = 0; i < swap_promise_list_.size(); i++) - state->AppendDouble(swap_promise_list_[i]->TraceId()); + for (auto* swap_promise : swap_promise_list_) + state->AppendDouble(swap_promise->TraceId()); state->EndArray(); } @@ -1072,20 +1075,20 @@ void LayerTreeImpl::PassSwapPromises( ScopedPtrVector<SwapPromise>* new_swap_promise) { - swap_promise_list_.insert_and_take(swap_promise_list_.end(), - new_swap_promise); - new_swap_promise->clear(); + // Any left over promises have failed to swap before the next frame. + BreakSwapPromises(SwapPromise::SWAP_FAILS); + swap_promise_list_.swap(*new_swap_promise); } void LayerTreeImpl::FinishSwapPromises(CompositorFrameMetadata* metadata) { - for (size_t i = 0; i < swap_promise_list_.size(); i++) - swap_promise_list_[i]->DidSwap(metadata); + for (auto* swap_promise : swap_promise_list_) + swap_promise->DidSwap(metadata); swap_promise_list_.clear(); } void LayerTreeImpl::BreakSwapPromises(SwapPromise::DidNotSwapReason reason) { - for (size_t i = 0; i < swap_promise_list_.size(); i++) - swap_promise_list_[i]->DidNotSwap(reason); + for (auto* swap_promise : swap_promise_list_) + swap_promise->DidNotSwap(reason); swap_promise_list_.clear(); }
diff --git a/chrome/VERSION b/chrome/VERSION index d58fd78..53df3fab 100644 --- a/chrome/VERSION +++ b/chrome/VERSION
@@ -1,4 +1,4 @@ -MAJOR=44 +MAJOR=45 MINOR=0 -BUILD=2403 +BUILD=2405 PATCH=0
diff --git a/chrome/android/java/res/menu/chrome_context_menu.xml b/chrome/android/java/res/menu/chrome_context_menu.xml index c7256088..83bb617 100644 --- a/chrome/android/java/res/menu/chrome_context_menu.xml +++ b/chrome/android/java/res/menu/chrome_context_menu.xml
@@ -20,6 +20,8 @@ android:title="@string/contextmenu_save_link" /> </group> <group android:id="@+id/contextmenu_group_image"> + <item android:id="@+id/contextmenu_show_original_image" + android:title="@string/contextmenu_show_original_image"/> <item android:id="@+id/contextmenu_save_image" android:title="@string/contextmenu_save_image"/> <item android:id="@+id/contextmenu_open_image"
diff --git a/chrome/android/java/res/values/values.xml b/chrome/android/java/res/values/values.xml index 6e3b4343..f6049288 100644 --- a/chrome/android/java/res/values/values.xml +++ b/chrome/android/java/res/values/values.xml
@@ -11,7 +11,7 @@ <item type="id" name="button_secondary" /> <item type="id" name="button_tertiary" /> <item type="id" name="infobar_extra_check" /> - + <!-- Menu Animation Constants --> <item type="fraction" format="fraction" name="menu_animation_pivot_x">95%</item> @@ -41,5 +41,8 @@ <!-- Cast notification --> <item type="id" name="remote_notification" /> - + + <!-- Sync UI constants --> + <item type="id" name="passphrase_type_list" /> + </resources>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/PasswordUIView.java b/chrome/android/java/src/org/chromium/chrome/browser/PasswordUIView.java index c1eb3f0..adfb14f 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/PasswordUIView.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/PasswordUIView.java
@@ -146,6 +146,10 @@ return nativeShouldDisplayManageAccountLink(); } + public static boolean shouldUseSmartLockBranding() { + return nativeShouldUseSmartLockBranding(); + } + /** * Destroy the native object. */ @@ -180,6 +184,8 @@ private static native boolean nativeShouldDisplayManageAccountLink(); + private static native boolean nativeShouldUseSmartLockBranding(); + private native void nativeDestroy(long nativePasswordUIViewAndroid); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/Tab.java b/chrome/android/java/src/org/chromium/chrome/browser/Tab.java index e1875cf..41e3958 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/Tab.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/Tab.java
@@ -342,6 +342,11 @@ } @Override + public void onShowOriginalImage() { + if (mNativeTabAndroid != 0) nativeShowOriginalImage(mNativeTabAndroid); + } + + @Override public String getPageUrl() { return getUrl(); } @@ -2769,6 +2774,7 @@ private native void nativeCreateHistoricalTab(long nativeTabAndroid); private native void nativeUpdateTopControlsState( long nativeTabAndroid, int constraints, int current, boolean animate); + private native void nativeShowOriginalImage(long nativeTabAndroid); private native void nativeSearchByImageInNewTabAsync(long nativeTabAndroid); private native long nativeGetBookmarkId(long nativeTabAndroid, boolean onlyEditable); private native void nativeSetInterceptNavigationDelegate(long nativeTabAndroid,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/WebsiteSettingsPopup.java b/chrome/android/java/src/org/chromium/chrome/browser/WebsiteSettingsPopup.java index 806cb94..9d37ff6 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/WebsiteSettingsPopup.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/WebsiteSettingsPopup.java
@@ -381,7 +381,7 @@ SpannableStringBuilder urlBuilder = new SpannableStringBuilder(mFullUrl); OmniboxUrlEmphasizer.emphasizeUrl(urlBuilder, mContext.getResources(), mProfile, - mSecurityLevel, mIsInternalPage, true); + mSecurityLevel, mIsInternalPage, true, true); mUrlTitle.setText(urlBuilder); // Set the URL connection message now, and the URL after layout (so it
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuItemDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuItemDelegate.java index 96d88b7b..3544fb0 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuItemDelegate.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuItemDelegate.java
@@ -63,6 +63,11 @@ void onOpenImageInNewTab(String url, Referrer referrer); /** + * Called when the original image should be shown. + */ + void onShowOriginalImage(); + + /** * Called when the {@code text} should be saved to the clipboard. * @param text The text to save to the clipboard. * @param isUrl Whether or not the text is a URL.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuPopulator.java b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuPopulator.java index ab25498..7c02f17 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuPopulator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuPopulator.java
@@ -41,6 +41,8 @@ public void buildContextMenu(ContextMenu menu, Context context, ContextMenuParams params) { if (!TextUtils.isEmpty(params.getLinkUrl()) && !params.getLinkUrl().equals(BLANK_URL)) { menu.setHeaderTitle(params.getLinkUrl()); + } else if (!TextUtils.isEmpty(params.getTitleText())) { + menu.setHeaderTitle(params.getTitleText()); } if (mMenuInflater == null) mMenuInflater = new MenuInflater(context); @@ -81,6 +83,10 @@ menu.findItem(R.id.contextmenu_open_original_image_in_new_tab).setVisible(false); } + if (!params.imageWasFetchedLoFi()) { + menu.findItem(R.id.contextmenu_show_original_image).setVisible(false); + } + // Avoid showing open image option for same image which is already opened. if (mDelegate.getPageUrl().equals(params.getSrcUrl())) { menu.findItem(R.id.contextmenu_open_image).setVisible(false); @@ -114,6 +120,8 @@ } else if (itemId == R.id.contextmenu_open_image_in_new_tab || itemId == R.id.contextmenu_open_original_image_in_new_tab) { mDelegate.onOpenImageInNewTab(params.getSrcUrl(), params.getReferrer()); + } else if (itemId == R.id.contextmenu_show_original_image) { + mDelegate.onShowOriginalImage(); } else if (itemId == R.id.contextmenu_copy_link_address_text) { mDelegate.onSaveToClipboard(params.getUnfilteredLinkUrl(), true); } else if (itemId == R.id.contextmenu_copy_email_address) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuParams.java b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuParams.java index 861cd9b..71d168f 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuParams.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuParams.java
@@ -42,8 +42,10 @@ private final String mPageUrl; private final String mLinkUrl; private final String mLinkText; + private final String mTitleText; private final String mUnfilteredLinkUrl; private final String mSrcUrl; + private final boolean mImageWasFetchedLoFi; private final boolean mIsEditable; private final Referrer mReferrer; @@ -110,6 +112,13 @@ } /** + * @return The title or alt attribute (if title is not available). + */ + public String getTitleText() { + return mTitleText; + } + + /** * @return The unfiltered link URL, if any. */ public String getUnfilteredLinkUrl() { @@ -124,6 +133,13 @@ } /** + * @return Whether or not an image was fetched using Lo-Fi. + */ + public boolean imageWasFetchedLoFi() { + return mImageWasFetchedLoFi; + } + + /** * @return Whether or not the context menu is being shown for an editable piece of content. */ public boolean isEditable() { @@ -166,13 +182,15 @@ } private ContextMenuParams(int mediaType, String pageUrl, String linkUrl, String linkText, - String unfilteredLinkUrl, String srcUrl, String selectionText, boolean isEditable, - Referrer referrer) { + String unfilteredLinkUrl, String srcUrl, String selectionText, String titleText, + boolean imageWasFetchedLoFi, boolean isEditable, Referrer referrer) { mPageUrl = pageUrl; mLinkUrl = linkUrl; mLinkText = linkText; + mTitleText = titleText; mUnfilteredLinkUrl = unfilteredLinkUrl; mSrcUrl = srcUrl; + mImageWasFetchedLoFi = imageWasFetchedLoFi; mIsEditable = isEditable; mReferrer = referrer; @@ -185,11 +203,12 @@ @CalledByNative private static ContextMenuParams create(int mediaType, String pageUrl, String linkUrl, String linkText, String unfilteredLinkUrl, String srcUrl, String selectionText, - boolean isEditable, String sanitizedReferrer, int referrerPolicy) { + String titleText, boolean imageWasFetchedLoFi, boolean isEditable, + String sanitizedReferrer, int referrerPolicy) { Referrer referrer = TextUtils.isEmpty(sanitizedReferrer) ? null : new Referrer(sanitizedReferrer, referrerPolicy); return new ContextMenuParams(mediaType, pageUrl, linkUrl, linkText, unfilteredLinkUrl, - srcUrl, selectionText, isEditable, referrer); + srcUrl, selectionText, titleText, imageWasFetchedLoFi, isEditable, referrer); } @CalledByNative
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/EmptyChromeContextMenuItemDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/EmptyChromeContextMenuItemDelegate.java index 26ec1ab3..d8b01ce 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/EmptyChromeContextMenuItemDelegate.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/EmptyChromeContextMenuItemDelegate.java
@@ -36,6 +36,10 @@ } @Override + public void onShowOriginalImage() { + } + + @Override public void onOpenInNewIncognitoTab(String url) { }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/feedback/ConnectivityChecker.java b/chrome/android/java/src/org/chromium/chrome/browser/feedback/ConnectivityChecker.java index 4c370f84..2af5bd9 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/feedback/ConnectivityChecker.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/feedback/ConnectivityChecker.java
@@ -4,18 +4,31 @@ package org.chromium.chrome.browser.feedback; +import android.os.AsyncTask; + import org.chromium.base.CalledByNative; import org.chromium.base.JNINamespace; +import org.chromium.base.Log; import org.chromium.base.ThreadUtils; import org.chromium.base.VisibleForTesting; import org.chromium.chrome.browser.profiles.Profile; +import java.io.IOException; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URL; + /** * A utility class for checking if the device is currently connected to the Internet. */ @JNINamespace("chrome::android") public final class ConnectivityChecker { - private static final String DEFAULT_NO_CONTENT_URL = "http://clients4.google.com/generate_204"; + private static final String TAG = "ConnectivityChecker"; + + private static final String DEFAULT_HTTP_NO_CONTENT_URL = + "http://clients4.google.com/generate_204"; + private static final String DEFAULT_HTTPS_NO_CONTENT_URL = + "https://clients4.google.com/generate_204"; /** * A callback for whether the device is currently connected to the Internet. @@ -29,8 +42,69 @@ /** * Starts an asynchronous request for checking whether the device is currently connected to the - * Internet. The result passed to the callback denotes whether the attempt to connect to the - * server was successful. + * Internet using the Android system network stack. The result passed to the callback denotes + * whether the attempt to connect to the server was successful. + * + * If the profile or URL is invalid, the callback will be called with false. + * The server reply for the URL must respond with HTTP 204 without any redirects for the + * connectivity check to be successful. + * + * This method takes ownership of the callback object until the callback has happened. + * This method must be called on the main thread. + * @param timeoutMs number of milliseconds to wait before giving up waiting for a connection. + * @param callback the callback which will get the result. + */ + public static void checkConnectivitySystemNetworkStack( + boolean useHttps, int timeoutMs, final ConnectivityCheckerCallback callback) { + try { + URL url = useHttps ? new URL(DEFAULT_HTTPS_NO_CONTENT_URL) + : new URL(DEFAULT_HTTP_NO_CONTENT_URL); + checkConnectivitySystemNetworkStack(url, timeoutMs, callback); + } catch (MalformedURLException e) { + Log.w(TAG, "Failed to predefined URL: " + e); + ThreadUtils.postOnUiThread(new Runnable() { + @Override + public void run() { + callback.onResult(false); + } + }); + } + } + + static void checkConnectivitySystemNetworkStack( + final URL url, final int timeoutMs, final ConnectivityCheckerCallback callback) { + new AsyncTask<String, Void, Boolean>() { + @Override + protected Boolean doInBackground(String... strings) { + try { + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + conn.setInstanceFollowRedirects(false); + conn.setRequestMethod("GET"); + conn.setDoInput(false); + conn.setDoOutput(false); + conn.setConnectTimeout(timeoutMs); + conn.setReadTimeout(timeoutMs); + + conn.connect(); + int responseCode = conn.getResponseCode(); + return responseCode == HttpURLConnection.HTTP_NO_CONTENT; + } catch (IOException e) { + return false; + } + } + + @Override + protected void onPostExecute(Boolean connected) { + callback.onResult(connected); + } + }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + } + + /** + * Starts an asynchronous request for checking whether the device is currently connected to the + * Internet using the Chrome network stack. The result passed to the callback denotes whether + *the + * attempt to connect to the server was successful. * * If the profile or URL is invalid, the callback will be called with false. * The server reply for the URL must respond with HTTP 204 without any redirects for the @@ -42,13 +116,14 @@ * @param timeoutMs number of milliseconds to wait before giving up waiting for a connection. * @param callback the callback which will get the result. */ - public static void checkConnectivity( - Profile profile, long timeoutMs, ConnectivityCheckerCallback callback) { - checkConnectivity(profile, DEFAULT_NO_CONTENT_URL, timeoutMs, callback); + public static void checkConnectivityChromeNetworkStack(Profile profile, boolean useHttps, + long timeoutMs, ConnectivityCheckerCallback callback) { + String url = useHttps ? DEFAULT_HTTPS_NO_CONTENT_URL : DEFAULT_HTTP_NO_CONTENT_URL; + checkConnectivityChromeNetworkStack(profile, url, timeoutMs, callback); } @VisibleForTesting - static void checkConnectivity( + static void checkConnectivityChromeNetworkStack( Profile profile, String url, long timeoutMs, ConnectivityCheckerCallback callback) { ThreadUtils.assertOnUiThread(); nativeCheckConnectivity(profile, url, timeoutMs, callback);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/AppBannerInfoBarDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/AppBannerInfoBarDelegate.java index c76db8c5..686fe8f 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/AppBannerInfoBarDelegate.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/AppBannerInfoBarDelegate.java
@@ -14,6 +14,7 @@ import org.chromium.base.ApplicationStatus; import org.chromium.base.CalledByNative; import org.chromium.base.JNINamespace; +import org.chromium.base.VisibleForTesting; import org.chromium.chrome.browser.Tab; import org.chromium.chrome.browser.banners.AppData; import org.chromium.chrome.browser.banners.InstallerDelegate; @@ -25,6 +26,9 @@ */ @JNINamespace("banners") public class AppBannerInfoBarDelegate { + /** PackageManager to use in place of the real one. */ + private static PackageManager sPackageManagerForTests; + /** Weak pointer to the native AppBannerInfoBarDelegate. */ private long mNativePointer; @@ -34,6 +38,12 @@ /** Monitors for application state changes. */ private final ApplicationStatus.ApplicationStateListener mListener; + /** Overrides the PackageManager for testing. */ + @VisibleForTesting + public static void setPackageManagerForTesting(PackageManager manager) { + sPackageManagerForTests = manager; + } + private AppBannerInfoBarDelegate(long nativePtr) { mNativePointer = nativePtr; mListener = createApplicationStateListener(); @@ -64,7 +74,7 @@ private boolean installOrOpenNativeApp(Tab tab, AppData appData) { Context context = ApplicationStatus.getApplicationContext(); String packageName = appData.packageName(); - PackageManager packageManager = context.getPackageManager(); + PackageManager packageManager = getPackageManager(context); if (InstallerDelegate.isInstalled(packageManager, packageName)) { // Open the app. @@ -89,7 +99,7 @@ if (isInstalling) { // Start monitoring the install. PackageManager pm = - ApplicationStatus.getApplicationContext().getPackageManager(); + getPackageManager(ApplicationStatus.getApplicationContext()); mInstallTask = new InstallerDelegate( Looper.getMainLooper(), pm, createInstallerDelegateObserver(), appData.packageName()); @@ -121,12 +131,17 @@ private int determineInstallState(AppData data) { if (mInstallTask != null) return AppBannerInfoBar.INSTALL_STATE_INSTALLING; - PackageManager pm = ApplicationStatus.getApplicationContext().getPackageManager(); + PackageManager pm = getPackageManager(ApplicationStatus.getApplicationContext()); boolean isInstalled = InstallerDelegate.isInstalled(pm, data.packageName()); return isInstalled ? AppBannerInfoBar.INSTALL_STATE_INSTALLED : AppBannerInfoBar.INSTALL_STATE_NOT_INSTALLED; } + private PackageManager getPackageManager(Context context) { + if (sPackageManagerForTests != null) return sPackageManagerForTests; + return context.getPackageManager(); + } + @CalledByNative private static AppBannerInfoBarDelegate create(long nativePtr) { return new AppBannerInfoBarDelegate(nativePtr);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/OmniboxUrlEmphasizer.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/OmniboxUrlEmphasizer.java index 9cf8e69..cfbffe0 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/OmniboxUrlEmphasizer.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/OmniboxUrlEmphasizer.java
@@ -140,9 +140,15 @@ * @param isInternalPage Whether this page is an internal Chrome page. * @param useDarkColors Whether the text colors should be dark (i.e. * appropriate for use on a light background). + * @param emphasizeHttpsScheme Whether the https scheme should be emphasized. */ public static void emphasizeUrl(Spannable url, Resources resources, Profile profile, - int securityLevel, boolean isInternalPage, boolean useDarkColors) { + int securityLevel, boolean isInternalPage, + boolean useDarkColors, boolean emphasizeHttpsScheme) { + assert (securityLevel == ConnectionSecurityHelperSecurityLevel.SECURITY_ERROR + || securityLevel == ConnectionSecurityHelperSecurityLevel.SECURITY_WARNING) + ? emphasizeHttpsScheme : true; + String urlString = url.toString(); EmphasizeComponentsResponse emphasizeResponse = @@ -163,10 +169,7 @@ ForegroundColorSpan span; if (emphasizeResponse.hasScheme()) { int colorId = nonEmphasizedColorId; - if (!isInternalPage - && (useDarkColors - || securityLevel - == ConnectionSecurityHelperSecurityLevel.SECURITY_ERROR)) { + if (!isInternalPage && emphasizeHttpsScheme) { switch (securityLevel) { case ConnectionSecurityHelperSecurityLevel.NONE: colorId = nonEmphasizedColorId;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/ManageSavedPasswordsPreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/ManageSavedPasswordsPreferences.java index 61da69c..863c9c7 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/ManageSavedPasswordsPreferences.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/ManageSavedPasswordsPreferences.java
@@ -76,7 +76,11 @@ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - getActivity().setTitle(R.string.prefs_saved_passwords); + if (PasswordUIView.shouldUseSmartLockBranding()) { + getActivity().setTitle(R.string.prefs_smart_lock_for_passwords); + } else { + getActivity().setTitle(R.string.prefs_saved_passwords); + } setPreferenceScreen(getPreferenceManager().createPreferenceScreen(getActivity())); mPasswordManagerHandler.addObserver(this);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sync/ui/PassphraseTypeDialogFragment.java b/chrome/android/java/src/org/chromium/chrome/browser/sync/ui/PassphraseTypeDialogFragment.java index 76f95f8..ce293ab4 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/sync/ui/PassphraseTypeDialogFragment.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/sync/ui/PassphraseTypeDialogFragment.java
@@ -31,6 +31,7 @@ */ public class PassphraseTypeDialogFragment extends DialogFragment implements DialogInterface.OnClickListener, OnItemClickListener { + private static final String TAG = "PassphraseTypeDialogFragment"; interface Listener { void onPassphraseTypeSelected(PassphraseType type); @@ -96,7 +97,11 @@ return new Adapter(container, container.getDisplayNames()); } - private class Adapter extends ArrayAdapter<String> { + /** + * The adapter for our ListView; only visible for testing purposes. + */ + @VisibleForTesting + public class Adapter extends ArrayAdapter<String> { private final PassphraseTypeUiElementContainer mElementsContainer; @@ -176,6 +181,7 @@ ListView list = new ListView(getActivity()); Adapter adapter = createAdapter(getCurrentTypeFromArguments()); list.setAdapter(adapter); + list.setId(R.id.passphrase_type_list); list.setOnItemClickListener(this); list.setDividerHeight(0); PassphraseType currentType = getCurrentTypeFromArguments();
diff --git a/chrome/android/java/strings/android_chrome_strings.grd b/chrome/android/java/strings/android_chrome_strings.grd index 95ec26b..f114c86 100644 --- a/chrome/android/java/strings/android_chrome_strings.grd +++ b/chrome/android/java/strings/android_chrome_strings.grd
@@ -235,7 +235,10 @@ <message name="IDS_PREFS_SAVED_PASSWORDS" desc="Title for the Saved Passwords preferences. [CHAR-LIMIT=32]"> Save passwords </message> - <message name="IDS_PASSWORDS_AUTO_SIGNIN_TITLE" desc="Title for checkbox to enable automatically signing the user in to websites"> + <message name="IDS_PREFS_SMART_LOCK_FOR_PASSWORDS" desc="The brand name of the password manager to be displayed in preferences instead of the title 'Save Passwords' when a user is signed in. [CHAR-LIMIT=32]"> + Smart Lock for Passwords + </message> + <message name="IDS_PASSWORDS_AUTO_SIGNIN_TITLE" desc="Title for checkbox to enable automatically signing the user in to websites"> Auto Sign-in </message> <message name="IDS_PASSWORDS_AUTO_SIGNIN_DESCRIPTION" desc="Text under 'Auto sign-in' checkbox"> @@ -248,7 +251,7 @@ Never saved </message> <message name="IDS_MANAGE_PASSWORDS_TEXT" desc="Text for link to manage passwords on Account Central."> - Manage saved passwords in your <ph name="BEGIN_LINK"><link></ph>Google Account<ph name="END_LINK"></link></ph> + View and manage saved passwords at <ph name="BEGIN_LINK"><link></ph>passwords.google.com<ph name="END_LINK"></link></ph> </message> <message name="IDS_SAVED_PASSWORDS_NONE_TEXT" desc="Text when there are no saved passwords/exceptions."> Saved passwords will appear here. @@ -1147,6 +1150,9 @@ <message name="IDS_CONTEXTMENU_OPEN_ORIGINAL_IMAGE_IN_NEW_TAB" desc="Context sensitive menu item for opening/viewing the original version of the selected image in a new tab. [CHAR-LIMIT=30]"> Open original image in new tab </message> + <message name="IDS_CONTEXTMENU_SHOW_ORIGINAL_IMAGE" desc="Context sensitive menu item for Data Saver low fidelity placeholder images that shows the original version in place. [CHAR-LIMIT=30]"> + Show image + </message> <message name="IDS_CONTEXTMENU_SEARCH_WEB_FOR_IMAGE" desc="Context sensitive menu item for search-for-Image command in a new tab. [CHAR-LIMIT=30]"> Search <ph name="SEARCH_ENGINE">%1$s<ex>Google</ex></ph> for this image </message>
diff --git a/chrome/android/javatests_shell/src/org/chromium/chrome/browser/banners/AppBannerManagerTest.java b/chrome/android/javatests_shell/src/org/chromium/chrome/browser/banners/AppBannerManagerTest.java index 538c34bd..6107c0b6 100644 --- a/chrome/android/javatests_shell/src/org/chromium/chrome/browser/banners/AppBannerManagerTest.java +++ b/chrome/android/javatests_shell/src/org/chromium/chrome/browser/banners/AppBannerManagerTest.java
@@ -4,11 +4,19 @@ package org.chromium.chrome.browser.banners; +import android.app.Activity; +import android.app.Instrumentation.ActivityMonitor; +import android.app.Instrumentation.ActivityResult; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.PackageInfo; import android.net.Uri; +import android.test.mock.MockPackageManager; import android.test.suitebuilder.annotation.MediumTest; import android.test.suitebuilder.annotation.SmallTest; import android.text.TextUtils; import android.view.View; +import android.widget.Button; import android.widget.TextView; import org.chromium.base.ThreadUtils; @@ -18,6 +26,7 @@ import org.chromium.chrome.browser.ChromeSwitches; import org.chromium.chrome.browser.infobar.AnimationHelper; import org.chromium.chrome.browser.infobar.AppBannerInfoBar; +import org.chromium.chrome.browser.infobar.AppBannerInfoBarDelegate; import org.chromium.chrome.browser.infobar.InfoBar; import org.chromium.chrome.browser.infobar.InfoBarContainer; import org.chromium.chrome.shell.ChromeShellTestBase; @@ -28,6 +37,7 @@ import org.chromium.content.browser.test.util.TouchCommon; import java.util.ArrayList; +import java.util.List; /** * Tests the app banners. @@ -42,24 +52,33 @@ private static final String NATIVE_APP_TITLE = "Mock app title"; + private static final String NATIVE_APP_PACKAGE = "123456"; + + private static final String NATIVE_APP_INSTALL_TEXT = "Install this"; + private static final String WEB_APP_URL = TestHttpServerClient.getUrl("chrome/test/data/banners/manifest_test_page.html"); private static final String WEB_APP_TITLE = "Manifest test app"; + private static final String INSTALL_ACTION = "INSTALL_ACTION"; + private static class MockAppDetailsDelegate extends AppDetailsDelegate { private Observer mObserver; private AppData mAppData; private int mNumRetrieved; + private Intent mInstallIntent; @Override protected void getAppDetailsAsynchronously( Observer observer, String url, String packageName, int iconSize) { mNumRetrieved += 1; mObserver = observer; + mInstallIntent = new Intent(INSTALL_ACTION); + mAppData = new AppData(url, packageName); - mAppData.setPackageInfo( - NATIVE_APP_TITLE, NATIVE_ICON_URL, 4.5f, "Install this", null, null); + mAppData.setPackageInfo(NATIVE_APP_TITLE, NATIVE_ICON_URL, 4.5f, + NATIVE_APP_INSTALL_TEXT, null, mInstallIntent); ThreadUtils.runOnUiThread(new Runnable() { @Override public void run() { @@ -73,6 +92,23 @@ } } + private static class TestPackageManager extends MockPackageManager { + public boolean isInstalled = false; + + @Override + public List<PackageInfo> getInstalledPackages(int flags) { + List<PackageInfo> packages = new ArrayList<PackageInfo>(); + + if (isInstalled) { + PackageInfo info = new PackageInfo(); + info.packageName = NATIVE_APP_PACKAGE; + packages.add(info); + } + + return packages; + } + } + private static class InfobarListener implements InfoBarContainer.InfoBarAnimationListener { private boolean mDoneAnimating; @@ -83,12 +119,15 @@ } private MockAppDetailsDelegate mDetailsDelegate; + private TestPackageManager mPackageManager; @Override protected void setUp() throws Exception { mDetailsDelegate = new MockAppDetailsDelegate(); + mPackageManager = new TestPackageManager(); AppBannerManager.setAppDetailsDelegate(mDetailsDelegate); AppBannerManager.setIsEnabledForTesting(true); + AppBannerInfoBarDelegate.setPackageManagerForTesting(mPackageManager); clearAppData(); super.setUp(); @@ -139,19 +178,63 @@ @SmallTest @Feature({"AppBanners"}) - public void testBannerAppears() throws Exception { + public void testFullNativeInstallPathway() throws Exception { // Visit a site that requests a banner. assertTrue(CriteriaHelper.pollForUIThreadCriteria( new TabLoadObserver(getActivity().getActiveTab(), NATIVE_APP_URL))); assertTrue(waitUntilAppDetailsRetrieved(1)); assertTrue(waitUntilNoInfoBarsExist()); - // Indicate a day has passed, then revisit the page. + // Indicate a day has passed, then revisit the page to get the banner to appear. + InfoBarContainer container = getActivity().getActiveTab().getInfoBarContainer(); + final InfobarListener listener = new InfobarListener(); + container.setAnimationListener(listener); AppBannerManager.setTimeDeltaForTesting(1); assertTrue(CriteriaHelper.pollForUIThreadCriteria( new TabLoadObserver(getActivity().getActiveTab(), NATIVE_APP_URL))); assertTrue(waitUntilAppDetailsRetrieved(2)); assertTrue(waitUntilAppBannerInfoBarAppears(NATIVE_APP_TITLE)); + assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() { + @Override + public boolean isSatisfied() { + return listener.mDoneAnimating; + } + })); + + // Check that the button asks if the user wants to install the app. + InfoBar infobar = container.getInfoBars().get(0); + final Button button = + (Button) infobar.getContentWrapper().findViewById(R.id.button_primary); + assertEquals(NATIVE_APP_INSTALL_TEXT, button.getText()); + + // Click the button to trigger the install. + final ActivityMonitor activityMonitor = new ActivityMonitor( + new IntentFilter(INSTALL_ACTION), new ActivityResult(Activity.RESULT_OK, null), + true); + getInstrumentation().addMonitor(activityMonitor); + TouchCommon.singleClickView(button); + + // Wait for the infobar to register that the app is installing. + final String installingText = + getInstrumentation().getTargetContext().getString(R.string.app_banner_installing); + assertTrue(CriteriaHelper.pollForCriteria(new Criteria() { + @Override + public boolean isSatisfied() { + return getInstrumentation().checkMonitorHit(activityMonitor, 1) + && TextUtils.equals(button.getText(), installingText); + } + })); + + // Say that the package is installed. Infobar should say that the app is ready to open. + mPackageManager.isInstalled = true; + final String openText = + getInstrumentation().getTargetContext().getString(R.string.app_banner_open); + assertTrue(CriteriaHelper.pollForCriteria(new Criteria() { + @Override + public boolean isSatisfied() { + return TextUtils.equals(button.getText(), openText); + } + })); } @MediumTest
diff --git a/chrome/android/javatests_shell/src/org/chromium/chrome/browser/feedback/ConnectivityCheckerTest.java b/chrome/android/javatests_shell/src/org/chromium/chrome/browser/feedback/ConnectivityCheckerTest.java index c05ee25..9ebf8c5 100644 --- a/chrome/android/javatests_shell/src/org/chromium/chrome/browser/feedback/ConnectivityCheckerTest.java +++ b/chrome/android/javatests_shell/src/org/chromium/chrome/browser/feedback/ConnectivityCheckerTest.java
@@ -22,7 +22,9 @@ import org.chromium.net.test.BaseHttpTestServer; import java.io.IOException; +import java.net.MalformedURLException; import java.net.Socket; +import java.net.URL; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; @@ -121,39 +123,78 @@ } } - @MediumTest - public void testNoContentShouldWork() throws Exception { - executeTest(GENERATE_204_URL, true, TIMEOUT_MS); + private static URL getURLNoException(String url) { + try { + return new URL(url); + } catch (MalformedURLException e) { + return null; + } } @MediumTest - public void testSlowNoContentShouldNotWork() throws Exception { + public void testNoContentShouldWorkSystemStack() throws Exception { + executeTest(GENERATE_204_URL, true, TIMEOUT_MS, true); + } + + @MediumTest + public void testNoContentShouldWorkChromeStack() throws Exception { + executeTest(GENERATE_204_URL, true, TIMEOUT_MS, false); + } + + @MediumTest + public void testSlowNoContentShouldNotWorkSystemStack() throws Exception { // Force quick timeout. The server will wait TIMEOUT_MS, so this triggers well before. - executeTest(GENERATE_204_SLOW_URL, false, 100); + executeTest(GENERATE_204_SLOW_URL, false, 100, true); } @MediumTest - public void testHttpOKShouldFail() throws Exception { - executeTest(GENERATE_200_URL, false, TIMEOUT_MS); + public void testSlowNoContentShouldNotWorkChromeStack() throws Exception { + // Force quick timeout. The server will wait TIMEOUT_MS, so this triggers well before. + executeTest(GENERATE_204_SLOW_URL, false, 100, false); } @MediumTest - public void testMovedTemporarilyShouldFail() throws Exception { - executeTest(GENERATE_302_URL, false, TIMEOUT_MS); + public void testHttpOKShouldFailSystemStack() throws Exception { + executeTest(GENERATE_200_URL, false, TIMEOUT_MS, true); } @MediumTest - public void testNotFoundShouldFail() throws Exception { - executeTest(GENERATE_404_URL, false, TIMEOUT_MS); + public void testHttpOKShouldFailChromeStack() throws Exception { + executeTest(GENERATE_200_URL, false, TIMEOUT_MS, false); } @MediumTest - public void testInvalidURLShouldFail() throws Exception { - executeTest("http:google.com:foo", false, TIMEOUT_MS); + public void testMovedTemporarilyShouldFailSystemStack() throws Exception { + executeTest(GENERATE_302_URL, false, TIMEOUT_MS, true); } - private void executeTest(final String url, boolean expectedResult, final long timeoutMs) - throws Exception { + @MediumTest + public void testMovedTemporarilyShouldFailChromeStack() throws Exception { + executeTest(GENERATE_302_URL, false, TIMEOUT_MS, false); + } + + @MediumTest + public void testNotFoundShouldFailSystemStack() throws Exception { + executeTest(GENERATE_404_URL, false, TIMEOUT_MS, true); + } + + @MediumTest + public void testNotFoundShouldFailChromeStack() throws Exception { + executeTest(GENERATE_404_URL, false, TIMEOUT_MS, false); + } + + @MediumTest + public void testInvalidURLShouldFailSystemStack() throws Exception { + executeTest("http:google.com:foo", false, TIMEOUT_MS, true); + } + + @MediumTest + public void testInvalidURLShouldFailChromeStack() throws Exception { + executeTest("http:google.com:foo", false, TIMEOUT_MS, false); + } + + private void executeTest(final String url, boolean expectedResult, final long timeoutMs, + final boolean useSystemStack) throws Exception { Context targetContext = getInstrumentation().getTargetContext(); startChromeBrowserProcessSync(targetContext); ConnectivityTestServer testServer = new ConnectivityTestServer(); @@ -166,8 +207,13 @@ ThreadUtils.runOnUiThreadBlocking(new Runnable() { @Override public void run() { - ConnectivityChecker.checkConnectivity( - Profile.getLastUsedProfile(), url, timeoutMs, callback); + if (useSystemStack) { + ConnectivityChecker.checkConnectivitySystemNetworkStack( + getURLNoException(url), ((int) timeoutMs), callback); + } else { + ConnectivityChecker.checkConnectivityChromeNetworkStack( + Profile.getLastUsedProfile(), url, timeoutMs, callback); + } } });
diff --git a/chrome/android/javatests_shell/src/org/chromium/chrome/browser/omnibox/OmniboxUrlEmphasizerTest.java b/chrome/android/javatests_shell/src/org/chromium/chrome/browser/omnibox/OmniboxUrlEmphasizerTest.java index 0173353c..46a1613 100644 --- a/chrome/android/javatests_shell/src/org/chromium/chrome/browser/omnibox/OmniboxUrlEmphasizerTest.java +++ b/chrome/android/javatests_shell/src/org/chromium/chrome/browser/omnibox/OmniboxUrlEmphasizerTest.java
@@ -126,7 +126,7 @@ public void testShortSecureHTTPSUrl() { Spannable url = new SpannableStringBuilder("https://www.google.com/"); OmniboxUrlEmphasizer.emphasizeUrl(url, mResources, mProfile, - ConnectionSecurityHelperSecurityLevel.SECURE, false, true); + ConnectionSecurityHelperSecurityLevel.SECURE, false, true, true); EmphasizedUrlSpanHelper[] spans = EmphasizedUrlSpanHelper.getSpansForEmphasizedUrl(url); assertEquals("Unexpected number of spans:", 4, spans.length); @@ -150,7 +150,7 @@ public void testShortSecureHTTPSUrlWithLightColors() { Spannable url = new SpannableStringBuilder("https://www.google.com/"); OmniboxUrlEmphasizer.emphasizeUrl(url, mResources, mProfile, - ConnectionSecurityHelperSecurityLevel.SECURE, false, false); + ConnectionSecurityHelperSecurityLevel.SECURE, false, false, false); EmphasizedUrlSpanHelper[] spans = EmphasizedUrlSpanHelper.getSpansForEmphasizedUrl(url); assertEquals("Unexpected number of spans:", 4, spans.length); @@ -175,7 +175,7 @@ Spannable url = new SpannableStringBuilder( "https://www.google.com/q?query=abc123&results=1"); OmniboxUrlEmphasizer.emphasizeUrl(url, mResources, mProfile, - ConnectionSecurityHelperSecurityLevel.SECURITY_ERROR, false, true); + ConnectionSecurityHelperSecurityLevel.SECURITY_ERROR, false, true, true); EmphasizedUrlSpanHelper[] spans = EmphasizedUrlSpanHelper.getSpansForEmphasizedUrl(url); assertEquals("Unexpected number of spans:", 5, spans.length); @@ -200,7 +200,7 @@ public void testVeryShortWarningHTTPSUrl() { Spannable url = new SpannableStringBuilder("https://www.dodgysite.com"); OmniboxUrlEmphasizer.emphasizeUrl(url, mResources, mProfile, - ConnectionSecurityHelperSecurityLevel.SECURITY_WARNING, false, true); + ConnectionSecurityHelperSecurityLevel.SECURITY_WARNING, false, true, true); EmphasizedUrlSpanHelper[] spans = EmphasizedUrlSpanHelper.getSpansForEmphasizedUrl(url); assertEquals("Unexpected number of spans:", 3, spans.length); @@ -221,8 +221,8 @@ @Feature({"Browser", "Main"}) public void testAboutPageUrl() { Spannable url = new SpannableStringBuilder("about:blank"); - OmniboxUrlEmphasizer.emphasizeUrl( - url, mResources, mProfile, ConnectionSecurityHelperSecurityLevel.NONE, true, true); + OmniboxUrlEmphasizer.emphasizeUrl(url, mResources, mProfile, + ConnectionSecurityHelperSecurityLevel.NONE, true, true, true); EmphasizedUrlSpanHelper[] spans = EmphasizedUrlSpanHelper.getSpansForEmphasizedUrl(url); assertEquals("Unexpected number of spans:", 3, spans.length); @@ -244,8 +244,8 @@ public void testDataUrl() { Spannable url = new SpannableStringBuilder( "data:text/plain;charset=utf-8;base64,VGVzdCBVUkw="); - OmniboxUrlEmphasizer.emphasizeUrl( - url, mResources, mProfile, ConnectionSecurityHelperSecurityLevel.NONE, true, true); + OmniboxUrlEmphasizer.emphasizeUrl(url, mResources, mProfile, + ConnectionSecurityHelperSecurityLevel.NONE, true, true, true); EmphasizedUrlSpanHelper[] spans = EmphasizedUrlSpanHelper.getSpansForEmphasizedUrl(url); assertEquals("Unexpected number of spans:", 1, spans.length); @@ -262,8 +262,8 @@ @Feature({"Browser", "Main"}) public void testInternalChromePageUrl() { Spannable url = new SpannableStringBuilder("chrome://bookmarks"); - OmniboxUrlEmphasizer.emphasizeUrl( - url, mResources, mProfile, ConnectionSecurityHelperSecurityLevel.NONE, true, true); + OmniboxUrlEmphasizer.emphasizeUrl(url, mResources, mProfile, + ConnectionSecurityHelperSecurityLevel.NONE, true, true, true); EmphasizedUrlSpanHelper[] spans = EmphasizedUrlSpanHelper.getSpansForEmphasizedUrl(url); assertEquals("Unexpected number of spans:", 3, spans.length); @@ -284,8 +284,8 @@ @Feature({"Browser", "Main"}) public void testInternalChromeNativePageUrl() { Spannable url = new SpannableStringBuilder("chrome-native://bookmarks"); - OmniboxUrlEmphasizer.emphasizeUrl( - url, mResources, mProfile, ConnectionSecurityHelperSecurityLevel.NONE, true, true); + OmniboxUrlEmphasizer.emphasizeUrl(url, mResources, mProfile, + ConnectionSecurityHelperSecurityLevel.NONE, true, true, true); EmphasizedUrlSpanHelper[] spans = EmphasizedUrlSpanHelper.getSpansForEmphasizedUrl(url); assertEquals("Unexpected number of spans:", 3, spans.length); @@ -306,8 +306,8 @@ @Feature({"Browser", "Main"}) public void testInvalidUrl() { Spannable url = new SpannableStringBuilder("invalidurl"); - OmniboxUrlEmphasizer.emphasizeUrl( - url, mResources, mProfile, ConnectionSecurityHelperSecurityLevel.NONE, true, true); + OmniboxUrlEmphasizer.emphasizeUrl(url, mResources, mProfile, + ConnectionSecurityHelperSecurityLevel.NONE, true, true, true); EmphasizedUrlSpanHelper[] spans = EmphasizedUrlSpanHelper.getSpansForEmphasizedUrl(url); assertEquals("Unexpected number of spans:", 1, spans.length);
diff --git a/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/SyncCustomizationFragmentTest.java b/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/SyncCustomizationFragmentTest.java index 71016f8a..496f87d 100644 --- a/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/SyncCustomizationFragmentTest.java +++ b/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/SyncCustomizationFragmentTest.java
@@ -12,13 +12,17 @@ import android.preference.SwitchPreference; import android.preference.TwoStatePreference; import android.test.suitebuilder.annotation.SmallTest; +import android.view.View; +import android.widget.ListView; import org.chromium.base.ThreadUtils; import org.chromium.base.test.util.Feature; +import org.chromium.chrome.browser.sync.ui.PassphraseTypeDialogFragment; import org.chromium.chrome.browser.sync.ui.SyncCustomizationFragment; import org.chromium.chrome.shell.R; import org.chromium.chrome.test.util.browser.sync.SyncTestUtil; import org.chromium.sync.AndroidSyncSettings; +import org.chromium.sync.internal_api.pub.PassphraseType; import org.chromium.sync.internal_api.pub.base.ModelType; import java.util.Collection; @@ -138,6 +142,12 @@ assertFalse(mAndroidSyncSettings.isChromeSyncEnabled()); } + /** + * Make sure that the encryption UI presents the correct options. + * + * By default it should show the CUSTOM and KEYSTORE options, in that order. + * KEYSTORE should be selected but both should be enabled. + */ @SmallTest @Feature({"Sync"}) public void testSettingDataTypes() throws Exception { @@ -167,6 +177,33 @@ assertDataTypesAre(expectedTypes); } + @SmallTest + @Feature({"Sync"}) + public void testDefaultEncryptionOptions() throws Exception { + setupTestAccountAndSignInToSync(CLIENT_ID); + startSync(); + SyncCustomizationFragment fragment = startSyncCustomizationFragment(); + Preference encryption = getEncryption(fragment); + clickPreference(encryption); + + PassphraseTypeDialogFragment typeFragment = getPassphraseTypeDialogFragment(); + ListView listView = (ListView) typeFragment.getDialog() + .findViewById(R.id.passphrase_type_list); + PassphraseTypeDialogFragment.Adapter adapter = + (PassphraseTypeDialogFragment.Adapter) listView.getAdapter(); + + // Confirm that correct types show up in the correct order. + assertEquals(PassphraseType.CUSTOM_PASSPHRASE, adapter.getType(0)); + assertEquals(PassphraseType.KEYSTORE_PASSPHRASE, adapter.getType(1)); + assertEquals(2, listView.getCount()); + // Make sure they are both enabled and the correct on is selected. + View customView = listView.getChildAt(0); + View keystoreView = listView.getChildAt(1); + assertTrue(customView.isEnabled()); + assertTrue(keystoreView.isEnabled()); + assertEquals(keystoreView, listView.getSelectedView()); + } + private SyncCustomizationFragment startSyncCustomizationFragment() { SyncCustomizationFragment fragment = new SyncCustomizationFragment(); Bundle args = new Bundle(); @@ -217,6 +254,11 @@ SyncCustomizationFragment.PREFERENCE_SYNC_MANAGE_DATA); } + private PassphraseTypeDialogFragment getPassphraseTypeDialogFragment() { + return (PassphraseTypeDialogFragment) mActivity.getFragmentManager() + .findFragmentByTag(SyncCustomizationFragment.FRAGMENT_PASSWORD_TYPE); + } + private void assertDefaultSyncOnState(SyncCustomizationFragment fragment) { assertTrue("The sync switch should be on.", getSyncSwitch(fragment).isChecked()); assertTrue("The sync switch should be enabled.", getSyncSwitch(fragment).isEnabled()); @@ -279,4 +321,14 @@ }); getInstrumentation().waitForIdleSync(); } + + private void clickPreference(final Preference pref) { + ThreadUtils.runOnUiThreadBlocking(new Runnable() { + @Override + public void run() { + pref.getOnPreferenceClickListener().onPreferenceClick(pref); + } + }); + getInstrumentation().waitForIdleSync(); + } }
diff --git a/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/SyncTest.java b/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/SyncTest.java index b0ec148..38b48a9 100644 --- a/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/SyncTest.java +++ b/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/SyncTest.java
@@ -130,6 +130,22 @@ @LargeTest @Feature({"Sync"}) + public void testSignInAndOut() throws InterruptedException { + setupTestAccountAndSignInToSync(CLIENT_ID); + Account account = + AccountManagerHelper.createAccountFromName(SyncTestUtil.DEFAULT_TEST_ACCOUNT); + + // Signing out should disable sync. + signOut(); + SyncTestUtil.verifySyncIsSignedOut(mContext); + + // Signing back in should re-enable sync. + signIn(account); + SyncTestUtil.verifySyncIsSignedIn(mContext, account); + } + + @LargeTest + @Feature({"Sync"}) public void testDisableAndEnableSyncThroughAndroid() throws InterruptedException { setupTestAccountAndSignInToSync(CLIENT_ID); SyncTestUtil.ensureSyncInitialized(mContext);
diff --git a/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/SyncTestBase.java b/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/SyncTestBase.java index 6b429df3..f28ab17 100644 --- a/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/SyncTestBase.java +++ b/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/SyncTestBase.java
@@ -5,7 +5,6 @@ package org.chromium.chrome.browser.sync; import android.accounts.Account; -import android.app.Activity; import android.content.Context; import org.chromium.base.ThreadUtils; @@ -13,6 +12,7 @@ import org.chromium.chrome.browser.identity.UniqueIdentificationGeneratorFactory; import org.chromium.chrome.browser.identity.UuidBasedUniqueIdentificationGenerator; import org.chromium.chrome.browser.signin.AccountIdProvider; +import org.chromium.chrome.browser.signin.SigninManager; import org.chromium.chrome.shell.ChromeShellTestBase; import org.chromium.chrome.test.util.browser.sync.SyncTestUtil; import org.chromium.content.browser.test.util.Criteria; @@ -131,15 +131,7 @@ }, true); SyncTestUtil.verifySyncIsSignedOut(getActivity()); - - final Activity activity = launchChromeShellWithBlankPage(); - ThreadUtils.runOnUiThreadBlocking(new Runnable() { - @Override - public void run() { - mSyncController.signIn(activity, SyncTestUtil.DEFAULT_TEST_ACCOUNT); - } - }); - + signIn(defaultTestAccount); SyncTestUtil.verifySyncIsSignedIn(mContext, defaultTestAccount); assertTrue("Sync everything should be enabled", SyncTestUtil.isSyncEverythingEnabled(mContext)); @@ -165,6 +157,24 @@ getInstrumentation().waitForIdleSync(); } + protected void signIn(final Account account) { + ThreadUtils.runOnUiThreadBlocking(new Runnable() { + @Override + public void run() { + mSyncController.signIn(getActivity(), account.name); + } + }); + } + + protected void signOut() throws InterruptedException { + ThreadUtils.runOnUiThreadBlocking(new Runnable() { + @Override + public void run() { + SigninManager.get(mContext).signOut(getActivity(), null); + } + }); + } + protected void waitForSyncInitialized() throws InterruptedException { assertTrue(CriteriaHelper.pollForCriteria(new Criteria() { @Override
diff --git a/chrome/app/chrome_command_ids.h b/chrome/app/chrome_command_ids.h index 3e91a9e..797e782 100644 --- a/chrome/app/chrome_command_ids.h +++ b/chrome/app/chrome_command_ids.h
@@ -282,6 +282,7 @@ #define IDC_CONTENT_CONTEXT_OPENIMAGENEWTAB 50113 #define IDC_CONTENT_CONTEXT_SEARCHWEBFORIMAGE 50114 #define IDC_CONTENT_CONTEXT_OPEN_ORIGINAL_IMAGE_NEW_TAB 50115 +#define IDC_CONTENT_CONTEXT_SHOW_ORIGINAL_IMAGE 50116 // Audio/video items. #define IDC_CONTENT_CONTEXT_SAVEAVAS 50120 #define IDC_CONTENT_CONTEXT_COPYAVLOCATION 50121
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp index 096d7037..65d4177d 100644 --- a/chrome/app/chromeos_strings.grdp +++ b/chrome/app/chromeos_strings.grdp
@@ -6362,5 +6362,11 @@ <message name="IDS_WEBSTORE_WIDGET_DEFAULT_ERROR" desc="Default message shown when Chrome Web Store Widget app window content fails to load (e.g. if it fails to load Chrome Web Store Gallery in a webview)."> Could not connect to the Chrome Web Store. </message> + <message name="IDS_FLAGS_PRINTER_PROVIDER_SEARCH_APP_NAME" desc="Name of the flag used to enable launching Chrome Web Store Gallery widget app for searching for printer provider apps."> + Chrome Web Store Gallery app for printer drivers + </message> + <message name="IDS_FLAGS_PRINTER_PROVIDER_SEARCH_APP_DESCRIPTION" desc="Description of a flag in chrome://flags that enables launching Chrome Web Store Gallery widget app for searching for printer provider apps."> + Enables Chrome Web Store Gallery app for printer drivers. The app searches Chrome Web Store for extensions that support printing to a USB printer with specific USB ID. + </message> </grit-part>
diff --git a/chrome/app/chromium_strings.grd b/chrome/app/chromium_strings.grd index 4d67e1cc..2b1f9f1a 100644 --- a/chrome/app/chromium_strings.grd +++ b/chrome/app/chromium_strings.grd
@@ -460,8 +460,11 @@ </message> </if> <!-- Password generation strings --> - <message name="IDS_PASSWORD_GENERATION_PROMPT" desc="Autofill dropdown text describing password generation. The text inside |bars| is link text."> - Chromium will store this in your |Google saved passwords| and remember it the next time you need it. + <message name="IDS_PASSWORD_GENERATION_PROMPT" desc="Autofill dropdown text describing password generation. The link text is a separate string in the translation console and appears here as placeholder text."> + Chromium will store this in your <ph name="SAVED_PASSWORD_LINK">$1<ex>Google saved passwords</ex></ph> and remember it the next time you need it. + </message> + <message name="IDS_PASSWORD_GENERATION_SMART_LOCK_PROMPT" desc="Autofill dropdown text describing password generation. Used when we change the branding to SmartLock. The link text is a separate string in the translation console and appears here as placeholder text."> + Chromium will store this with <ph name="SAVED_PASSWORD_LINK">$1<ex>Google Smart Lock for Passwords</ex></ph> and remember it the next time you need it. </message> <message name="IDS_PASSWORD_GENERATION_SUGGESTION" desc="Text shown next to a generated password describing it as a suggestion."> Use password generated by Chromium @@ -784,9 +787,12 @@ </message> <if expr="enable_extensions"> - <message name="IDS_EXTENSIONS_UNSUPPORTED_DISABLED_BODY" desc="Body of the dialog shown when unsupported extensions have been disabled"> + <message name="IDS_EXTENSIONS_MULTIPLE_UNSUPPORTED_DISABLED_BODY" desc="Body of the dialog shown when multiple unsupported extensions have been disabled."> To make Chromium safer, we disabled some extensions that aren't listed in the <ph name="IDS_EXTENSION_WEB_STORE_TITLE">$1<ex>Chrome Web Store</ex></ph> and may have been added without your knowledge. </message> + <message name="IDS_EXTENSIONS_SINGLE_UNSUPPORTED_DISABLED_BODY" desc="Body of the dialog shown when a single unsupported extension has been disabled."> + To make Chromium safer, we disabled the following extension that isn't listed in the <ph name="IDS_EXTENSION_WEB_STORE_TITLE">$1<ex>Chrome Web Store</ex></ph> and may have been added without your knowledge. + </message> </if> <!-- Main Chrome menu -->
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index 5687fb83..6462dc6 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd
@@ -806,6 +806,9 @@ <message name="IDS_CONTENT_CONTEXT_OPEN_ORIGINAL_IMAGE_NEW_TAB" desc="The name of the Open Original Image in New Tab command in the content area context menu"> Open original &image in new tab </message> + <message name="IDS_CONTENT_CONTEXT_SHOW_ORIGINAL_IMAGE" desc="The name of the Show Original Image command in the content area context menu"> + Show image + </message> <message name="IDS_CONTENT_CONTEXT_LOOP" desc="The name of the Loop command for audio and video playback in the content area context menu"> &Loop @@ -1009,6 +1012,9 @@ <message name="IDS_CONTENT_CONTEXT_OPEN_ORIGINAL_IMAGE_NEW_TAB" desc="In Title Case: The name of the Open Original Image in New Tab command in the content area context menu"> Open Original &Image in New Tab </message> + <message name="IDS_CONTENT_CONTEXT_SHOW_ORIGINAL_IMAGE" desc="In Title Case: The name of the Show Original Image command in the content area context menu"> + Show Image + </message> <message name="IDS_CONTENT_CONTEXT_LOOP" desc="In Title Case: The name of the Loop command for audio and video playback in the content area context menu"> &Loop @@ -6379,8 +6385,11 @@ <message name="IDS_PASSWORD_MANAGER_SMART_LOCK" desc="The brand name of the password manager for the title of the save password bubble when a user is signed in."> Google Smart Lock </message> + <message name="IDS_PASSWORD_MANAGER_SMART_LOCK_FOR_PASSWORDS" desc="The more descriptive brand name of the password manager when the user is signed in. Used in various UI elements, can be in link format."> + Google Smart Lock for Passwords + </message> <message name="IDS_PASSWORD_MANAGER_SMART_LOCK_ARTICLE" desc="URL of help center page explaining what the 'Google Smart Lock' is."> - https://support.google.com/chromebook/answer/6070209?hl=[GRITLANGCODE] + https://support.google.com/accounts/answer/6197437?hl=[GRITLANGCODE] </message> <message name="IDS_PASSWORD_MANAGER_SAVE_PASSWORD_SMART_LOCK_NO_THANKS_BUTTON" desc="Text for the button the user clicks to dismiss save password bubble."> No thanks @@ -7655,6 +7664,9 @@ <message name="IDS_PASSWORDS_EXCEPTIONS_WINDOW_TITLE" desc="Title for 'Passwords and exceptions dialog'"> Passwords </message> + <message name="IDS_PASSWORDS_EXCEPTIONS_SMART_LOCK_WINDOW_TITLE" desc="Title for 'Passwords and exceptions dialog'"> + Google Smart Lock for Passwords + </message> <message name="IDS_PASSWORDS_AUTO_SIGNIN_TITLE" desc="Title for 'Auto sign-in' checkbox in the password dialog"> Auto Sign-in </message> @@ -10552,6 +10564,9 @@ <message name="IDS_OPTIONS_PASSWORD_MANAGER_ENABLE" desc="The label of the password manager checkbox"> Offer to save your web passwords. </message> + <message name="IDS_OPTIONS_PASSWORD_MANAGER_SMART_LOCK_ENABLE" desc="The label of the password manager checkbox if Smart Lock is enabled."> + Offer to save passwords with Google Smart Lock for Passwords. + </message> <message name="IDS_OPTIONS_PASSWORDS_AUTOLOGIN" desc="The label of the 'autologinEnabled' checkbox"> Offer to sign in to Google sites automatically with this account </message> @@ -11673,10 +11688,6 @@ <!-- Strings used for non-Android builds --> <if expr="not is_android"> - <message name="IDS_NEW_TAB_SUGGESTIONS" - desc="The name for the 'Suggestions' navigation control on the New Tab Page."> - Suggested - </message> <message name="IDS_APP_DEFAULT_PAGE_NAME" desc="Default name for the first 'Apps' page on the New Tab Page."> Apps @@ -13617,15 +13628,18 @@ </if> <message name="IDS_MANAGE_PASSWORDS_CONFIRM_GENERATED_TITLE" desc="The title text that is used in the manage passwords bubble when the user has generated a password."> - Generated password saved + Password saved </message> <message name="IDS_MANAGE_PASSWORDS_CONFIRM_GENERATED_TEXT" desc="A message that the browser shows after saving a password it has autogenerated for the user. This message appears in a bubble and contains a link to all the user's saved autogenerated passwords. The link text is a separate string in the translation console and appears here as placeholder text."> You can access it and all your <ph name="SAVED_PASSWORDS_LINK">$1<ex>Google saved passwords</ex></ph> from any browser. </message> - <message name="IDS_MANAGE_PASSWORDS_CONFIRM_GENERATED_TEXT_INFOBAR" desc="A message that the browser shows after saving a password it has autogenerated for the user. This message appears in an infobar and contains a link to all the user's saved autogenerated passwords. The link text is a separate string in the translation console and appears here as placeholder text."> - Generated password saved. You can access it and all your <ph name="SAVED_PASSWORDS_LINK">$1<ex>Google saved passwords</ex></ph> from any browser. + <message name="IDS_MANAGE_PASSWORDS_CONFIRM_GENERATED_SMART_LOCK_TEXT" desc="A message that the browser shows after saving a password it has autogenerated for the user if Smart Lock branding is enabled. This message appears in a bubble and contains a link to all the user's saved autogenerated passwords."> + Access your passwords from any device at <ph name="MANAGEMENT_LINK">$1<ex>passwords.google.com</ex></ph>. </message> - <message name="IDS_MANAGE_PASSWORDS_CONFIRM_GENERATED_LINK" desc="The text for a link to the user's saved autogenerated passwords. This is inserted into an infobar or a bubble that the browser shows to the user after it saves an autogenerated password. The infobar and the bubble use a separate string in the translation console that has a placeholder for this link title."> + <message name="IDS_MANAGE_PASSWORDS_CONFIRM_GENERATED_TEXT_INFOBAR" desc="A message that the browser shows after saving a password it has autogenerated for the user. This message appears in an infobar and contains a link to all the user's saved autogenerated passwords. The link text is a separate string in the translation console and appears here as placeholder text."> + Password saved. You can access it and all your <ph name="SAVED_PASSWORDS_LINK">$1<ex>Google saved passwords</ex></ph> from any browser. + </message> + <message name="IDS_MANAGE_PASSWORDS_LINK" desc="The text for a link to the user's saved passwords. This is inserted into an infobar or a bubble that the browser shows to the user. The infobar and the bubble use a separate string in the translation console that has a placeholder for this link title."> Google saved passwords </message> <message name="IDS_MANAGE_PASSWORDS_TITLE" desc="The title text that is used in the manage passwords bubble when a password is autofilled or after a user has stored a password."> @@ -13646,8 +13660,8 @@ <message name="IDS_MANAGE_PASSWORDS_BLACKLIST_CONFIRMATION_BUTTON" desc="The confirmation button that is used in the manage passwords bubble when confirming blacklisting a site."> Delete saved passwords </message> - <message name="IDS_MANAGE_PASSWORDS_REMOTE_TEXT" desc="The text used to tell inform users of how to manage their passwords from a website. Text between |bars| is link text."> - Manage passwords remotely on your |Google Account| + <message name="IDS_MANAGE_PASSWORDS_REMOTE_TEXT" desc="The text used to tell inform users of how to manage their passwords from a website."> + Access your passwords from any device at <ph name="LINK_TEXT">$1<ex>passwords.google.com</ex></ph> </message> <message name="IDS_MANAGE_PASSWORDS_NO_PASSWORDS" desc="The text that is used in the manage passwords bubble when all passwords have been deleted.">
diff --git a/chrome/app/google_chrome_strings.grd b/chrome/app/google_chrome_strings.grd index b63d643..2e849a2 100644 --- a/chrome/app/google_chrome_strings.grd +++ b/chrome/app/google_chrome_strings.grd
@@ -383,8 +383,11 @@ </message> </if> <!-- Password generation strings --> - <message name="IDS_PASSWORD_GENERATION_PROMPT" desc="Autofill dropdown text describing password generation. The text inside |bars| is link text."> - Chrome will store this in your |Google saved passwords| and remember it the next time you need it. + <message name="IDS_PASSWORD_GENERATION_PROMPT" desc="Autofill dropdown text describing password generation. The link text is a separate string in the translation console and appears here as placeholder text."> + Chrome will store this in your <ph name="SAVED_PASSWORDS_LINK">$1<ex>Google saved passwords</ex></ph> and remember it the next time you need it. + </message> + <message name="IDS_PASSWORD_GENERATION_SMART_LOCK_PROMPT" desc="Autofill dropdown text describing password generation. Used when we change the branding to SmartLock. The link text is a separate string in the translation console and appears here as placeholder text."> + Chrome will store this with <ph name="SAVED_PASSWORD_LINK">$1<ex>Google Smart Lock for Passwords</ex></ph> and remember it the next time you need it. </message> <message name="IDS_PASSWORD_GENERATION_SUGGESTION" desc="Text shown next to a generated password describing it as a suggestion."> Use password generated by Chrome @@ -707,9 +710,12 @@ </message> <if expr="enable_extensions"> - <message name="IDS_EXTENSIONS_UNSUPPORTED_DISABLED_BODY" desc="Body of the dialog shown when unsupported extensions have been disabled"> + <message name="IDS_EXTENSIONS_MULTIPLE_UNSUPPORTED_DISABLED_BODY" desc="Body of the dialog shown when multiple unsupported extensions have been disabled."> To make Chrome safer, we disabled some extensions that aren't listed in the <ph name="IDS_EXTENSION_WEB_STORE_TITLE">$1<ex>Chrome Web Store</ex></ph> and may have been added without your knowledge. </message> + <message name="IDS_EXTENSIONS_SINGLE_UNSUPPORTED_DISABLED_BODY" desc="Body of the dialog shown when a single unsupported extension has been disabled."> + To make Chrome safer, we disabled the following extension that isn't listed in the <ph name="IDS_EXTENSION_WEB_STORE_TITLE">$1<ex>Chrome Web Store</ex></ph> and may have been added without your knowledge. + </message> </if> <!-- Wrench menu -->
diff --git a/chrome/app/resources/locale_settings_chromiumos.grd b/chrome/app/resources/locale_settings_chromiumos.grd index 5e85a4e0..7f97e2b 100644 --- a/chrome/app/resources/locale_settings_chromiumos.grd +++ b/chrome/app/resources/locale_settings_chromiumos.grd
@@ -214,7 +214,7 @@ <!-- The default value for |WebPreference::fixed_font_family_map| for Japanese script. --> <message name="IDS_FIXED_FONT_FAMILY_JAPANESE" use_name_for_id="true"> - IPAGothic + Noto Sans Mono CJK JP </message> <!-- The default value for |WebPreference::serif_font_family_map| for @@ -238,7 +238,7 @@ <!-- The default value for |WebPreference::fixed_font_family_map| for Korean script. --> <message name="IDS_FIXED_FONT_FAMILY_KOREAN" use_name_for_id="true"> - Monospace + Noto Sans Mono CJK KR </message> <!-- The default value for |WebPreference::serif_font_family_map| for @@ -262,7 +262,7 @@ <!-- The default value for |WebPreference::fixed_font_family_map| for Simplified Chinese script. --> <message name="IDS_FIXED_FONT_FAMILY_SIMPLIFIED_HAN" use_name_for_id="true"> - Noto Sans CJK SC + Noto Sans Mono CJK SC </message> <!-- The default value for |WebPreference::serif_font_family_map| for @@ -280,7 +280,7 @@ <!-- The default value for |WebPreference::standard_font_family_map| for Traditional Chinese script. --> <message name="IDS_STANDARD_FONT_FAMILY_TRADITIONAL_HAN" use_name_for_id="true"> - Noto Sans CJK TC + Noto Sans Mono CJK TC </message> <!-- The default value for |WebPreference::fixed_font_family_map| for
diff --git a/chrome/app/resources/locale_settings_google_chromeos.grd b/chrome/app/resources/locale_settings_google_chromeos.grd index 0a4ea4a..5aa2429 100644 --- a/chrome/app/resources/locale_settings_google_chromeos.grd +++ b/chrome/app/resources/locale_settings_google_chromeos.grd
@@ -214,7 +214,7 @@ <!-- The default value for |WebPreference::fixed_font_family_map| for Japanese script. --> <message name="IDS_FIXED_FONT_FAMILY_JAPANESE" use_name_for_id="true"> - MotoyaG04GothicMono + Noto Sans Mono CJK JP </message> <!-- The default value for |WebPreference::serif_font_family_map| for @@ -238,7 +238,7 @@ <!-- The default value for |WebPreference::fixed_font_family_map| for Korean script. --> <message name="IDS_FIXED_FONT_FAMILY_KOREAN" use_name_for_id="true"> - Monospace + Noto Sans Mono CJK KR </message> <!-- The default value for |WebPreference::serif_font_family_map| for @@ -262,7 +262,7 @@ <!-- The default value for |WebPreference::fixed_font_family_map| for Simplified Chinese script. --> <message name="IDS_FIXED_FONT_FAMILY_SIMPLIFIED_HAN" use_name_for_id="true"> - Noto Sans CJK SC + Noto Sans Mono CJK SC </message> <!-- The default value for |WebPreference::serif_font_family_map| for @@ -280,7 +280,7 @@ <!-- The default value for |WebPreference::standard_font_family_map| for Traditional Chinese script. --> <message name="IDS_STANDARD_FONT_FAMILY_TRADITIONAL_HAN" use_name_for_id="true"> - Noto Sans CJK TC + Noto Sans Mono CJK TC </message> <!-- The default value for |WebPreference::fixed_font_family_map| for
diff --git a/chrome/app/resources/platform_locale_settings/locale_settings_cros_ja.xtb b/chrome/app/resources/platform_locale_settings/locale_settings_cros_ja.xtb index 94845c8..3df405be 100644 --- a/chrome/app/resources/platform_locale_settings/locale_settings_cros_ja.xtb +++ b/chrome/app/resources/platform_locale_settings/locale_settings_cros_ja.xtb
@@ -4,7 +4,7 @@ <translation id="IDS_STANDARD_FONT_FAMILY">Noto Sans CJK JP</translation> <translation id="IDS_SANS_SERIF_FONT_FAMILY">Noto Sans CJK JP</translation> <if expr="_google_chrome"> - <translation id="IDS_FIXED_FONT_FAMILY">MotoyaG04GothicMono</translation> + <translation id="IDS_FIXED_FONT_FAMILY">Noto Sans Mono CJK JP</translation> <translation id="IDS_SERIF_FONT_FAMILY">MotoyaG04Mincho</translation> </if> <if expr="not _google_chrome">
diff --git a/chrome/app/resources/platform_locale_settings/locale_settings_cros_ko.xtb b/chrome/app/resources/platform_locale_settings/locale_settings_cros_ko.xtb index 62ccd020..16b3c59e 100644 --- a/chrome/app/resources/platform_locale_settings/locale_settings_cros_ko.xtb +++ b/chrome/app/resources/platform_locale_settings/locale_settings_cros_ko.xtb
@@ -3,7 +3,7 @@ <translationbundle lang="ko"> <!-- TODO(jungshik): remove this line once we fix bug 14691 --> <translation id="IDS_STANDARD_FONT_FAMILY">Noto Sans CJK KR</translation> -<translation id="IDS_FIXED_FONT_FAMILY">Monospace</translation> +<translation id="IDS_FIXED_FONT_FAMILY">Noto Sans Mono CJK KR</translation> <translation id="IDS_SERIF_FONT_FAMILY">NanumMyeongjo</translation> <translation id="IDS_SANS_SERIF_FONT_FAMILY">Noto Sans CJK KR</translation> <translation id="IDS_MINIMUM_FONT_SIZE">10</translation>
diff --git a/chrome/app/resources/platform_locale_settings/locale_settings_cros_zh-CN.xtb b/chrome/app/resources/platform_locale_settings/locale_settings_cros_zh-CN.xtb index 167449d..9848e4c7 100644 --- a/chrome/app/resources/platform_locale_settings/locale_settings_cros_zh-CN.xtb +++ b/chrome/app/resources/platform_locale_settings/locale_settings_cros_zh-CN.xtb
@@ -2,7 +2,7 @@ <!DOCTYPE translationbundle> <translationbundle lang="zh-CN"> <translation id="IDS_STANDARD_FONT_FAMILY">Noto Sans CJK SC</translation> -<translation id="IDS_FIXED_FONT_FAMILY">Noto Sans CJK SC</translation> +<translation id="IDS_FIXED_FONT_FAMILY">Noto Sans Mono CJK SC</translation> <translation id="IDS_SANS_SERIF_FONT_FAMILY">Noto Sans CJK SC</translation> <if expr="_google_chrome"> <translation id="IDS_SERIF_FONT_FAMILY">MSung GB18030</translation>
diff --git a/chrome/app/resources/platform_locale_settings/locale_settings_cros_zh-TW.xtb b/chrome/app/resources/platform_locale_settings/locale_settings_cros_zh-TW.xtb index 3f462ad..c7bcdbc 100644 --- a/chrome/app/resources/platform_locale_settings/locale_settings_cros_zh-TW.xtb +++ b/chrome/app/resources/platform_locale_settings/locale_settings_cros_zh-TW.xtb
@@ -2,7 +2,7 @@ <!DOCTYPE translationbundle> <translationbundle lang="zh-TW"> <translation id="IDS_STANDARD_FONT_FAMILY">Noto Sans CJK TC</translation> -<translation id="IDS_FIXED_FONT_FAMILY">Noto Sans CJK TC</translation> +<translation id="IDS_FIXED_FONT_FAMILY">Noto Sans Mono CJK TC</translation> <translation id="IDS_SANS_SERIF_FONT_FAMILY">Noto Sans CJK TC</translation> <if expr="_google_chrome"> <translation id="IDS_SERIF_FONT_FAMILY">MSung B5HK</translation>
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index 7a7efe90..96b968b 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -795,7 +795,7 @@ } } if (enable_media_router) { - defines += [ "ENABLE_MEDIA_ROUTER=1" ] + deps += [ "//chrome/browser/media/router" ] } }
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index 4ccd43b..9d576acc 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -2341,7 +2341,8 @@ IDS_FLAGS_V8_PAC_MOJO_OUT_OF_PROCESS_NAME, IDS_FLAGS_V8_PAC_MOJO_OUT_OF_PROCESS_DESCRIPTION, kOsDesktop, - SINGLE_VALUE_TYPE(switches::kV8PacMojoOutOfProcess), + ENABLE_DISABLE_VALUE_TYPE(switches::kV8PacMojoOutOfProcess, + switches::kDisableOutOfProcessPac) }, #if defined(ENABLE_MEDIA_ROUTER) { @@ -2404,6 +2405,15 @@ kOsAll, SINGLE_VALUE_TYPE(switches::kDisableNewVideoRenderer) }, +#if defined(OS_CHROMEOS) + { + "enable-printer-app-search", + IDS_FLAGS_PRINTER_PROVIDER_SEARCH_APP_NAME, + IDS_FLAGS_PRINTER_PROVIDER_SEARCH_APP_DESCRIPTION, + kOsCrOS, + SINGLE_VALUE_TYPE(chromeos::switches::kEnablePrinterAppSearch) + }, +#endif // OS_CHROMEOS // Temporary flag to ease the transition to standard-compliant scrollTop // behavior. Will be removed shortly after http://crbug.com/157855 ships. {
diff --git a/chrome/browser/android/password_ui_view_android.cc b/chrome/browser/android/password_ui_view_android.cc index 2bd4850..7e0dd80b 100644 --- a/chrome/browser/android/password_ui_view_android.cc +++ b/chrome/browser/android/password_ui_view_android.cc
@@ -11,6 +11,7 @@ #include "base/prefs/pref_service.h" #include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/ui/passwords/manage_passwords_view_utils.h" +#include "chrome/browser/ui/passwords/password_bubble_experiment.h" #include "chrome/common/pref_names.h" #include "chrome/common/url_constants.h" #include "components/autofill/core/common/password_form.h" @@ -114,6 +115,12 @@ return password_manager::ManageAccountLinkExperimentEnabled(); } +static jboolean ShouldUseSmartLockBranding( + JNIEnv* env, jclass) { + return password_bubble_experiment::IsSmartLockBrandingEnabled( + ProfileManager::GetLastUsedProfile()); +} + // static static jlong Init(JNIEnv* env, jobject obj) { PasswordUIViewAndroid* controller = new PasswordUIViewAndroid(env, obj);
diff --git a/chrome/browser/android/tab_android.cc b/chrome/browser/android/tab_android.cc index a0e0cbaa7..fc37e028 100644 --- a/chrome/browser/android/tab_android.cc +++ b/chrome/browser/android/tab_android.cc
@@ -752,6 +752,12 @@ } } +void TabAndroid::ShowOriginalImage(JNIEnv* env, jobject obj) { + content::RenderFrameHost* render_frame_host = web_contents()->GetMainFrame(); + render_frame_host->Send(new ChromeViewMsg_RequestReloadImageForContextNode( + render_frame_host->GetRoutingID())); +} + void TabAndroid::SearchByImageInNewTabAsync(JNIEnv* env, jobject obj) { content::RenderFrameHost* render_frame_host = web_contents()->GetMainFrame();
diff --git a/chrome/browser/android/tab_android.h b/chrome/browser/android/tab_android.h index 3ff8b9b..220ae3ba 100644 --- a/chrome/browser/android/tab_android.h +++ b/chrome/browser/android/tab_android.h
@@ -191,6 +191,8 @@ jint current, jboolean animate); + void ShowOriginalImage(JNIEnv* env, jobject obj); + void SearchByImageInNewTabAsync(JNIEnv* env, jobject obj); jlong GetBookmarkId(JNIEnv* env, jobject obj, jboolean only_editable);
diff --git a/chrome/browser/apps/custom_launcher_page_browsertest_views.cc b/chrome/browser/apps/custom_launcher_page_browsertest_views.cc index 6ac62479..f39ec2e 100644 --- a/chrome/browser/apps/custom_launcher_page_browsertest_views.cc +++ b/chrome/browser/apps/custom_launcher_page_browsertest_views.cc
@@ -315,10 +315,11 @@ contents_view->IsStateActive(app_list::AppListModel::STATE_START)); } -IN_PROC_BROWSER_TEST_F(CustomLauncherPageBrowserTest, - LauncherPageShow) { +IN_PROC_BROWSER_TEST_F(CustomLauncherPageBrowserTest, LauncherPageShowAndHide) { const base::string16 kLauncherPageShowScript = base::ASCIIToUTF16("chrome.launcherPage.show();"); + const base::string16 kLauncherPageHideScript = + base::ASCIIToUTF16("hideCustomLauncherPage()"); LoadAndLaunchPlatformApp(kCustomLauncherPagePath, "Launched"); app_list::AppListView* app_list_view = GetAppListView(); @@ -362,6 +363,29 @@ EXPECT_TRUE(contents_view->IsStateActive( app_list::AppListModel::STATE_CUSTOM_LAUNCHER_PAGE)); } + + // Ensure launcherPage.hide() hides the launcher page when it's showing. + { + ExtensionTestMessageListener listener("onPageProgressAt0", false); + custom_page_frame->ExecuteJavaScript(kLauncherPageHideScript); + + listener.WaitUntilSatisfied(); + + EXPECT_TRUE( + contents_view->IsStateActive(app_list::AppListModel::STATE_START)); + } + + // Nothing should happen if hide() is called from the apps page. + { + contents_view->SetActiveState(app_list::AppListModel::STATE_APPS, false); + + ExtensionTestMessageListener listener("launcherPageHidden", false); + custom_page_frame->ExecuteJavaScript(kLauncherPageHideScript); + listener.WaitUntilSatisfied(); + + EXPECT_TRUE( + contents_view->IsStateActive(app_list::AppListModel::STATE_APPS)); + } } IN_PROC_BROWSER_TEST_F(CustomLauncherPageBrowserTest, LauncherPageSetEnabled) {
diff --git a/chrome/browser/apps/guest_view/web_view_browsertest.cc b/chrome/browser/apps/guest_view/web_view_browsertest.cc index 6fbd4c0..3920397 100644 --- a/chrome/browser/apps/guest_view/web_view_browsertest.cc +++ b/chrome/browser/apps/guest_view/web_view_browsertest.cc
@@ -2139,17 +2139,17 @@ EXPECT_FALSE( chromeos::AccessibilityManager::Get()->IsSpokenFeedbackEnabled()); + chromeos::SpeechMonitor monitor; + chromeos::AccessibilityManager::Get()->EnableSpokenFeedback( + true, ui::A11Y_NOTIFICATION_NONE); + EXPECT_TRUE(monitor.SkipChromeVoxEnabledMessage()); + ASSERT_TRUE(StartEmbeddedTestServer()); content::WebContents* guest_web_contents = LoadGuest( "/extensions/platform_apps/web_view/chromevox_injection/guest.html", "web_view/chromevox_injection"); ASSERT_TRUE(guest_web_contents); - chromeos::SpeechMonitor monitor; - chromeos::AccessibilityManager::Get()->EnableSpokenFeedback( - true, ui::A11Y_NOTIFICATION_NONE); - EXPECT_TRUE(monitor.SkipChromeVoxEnabledMessage()); - EXPECT_EQ("chrome vox test title", monitor.GetNextUtterance()); } #endif
diff --git a/chrome/browser/autocomplete/history_quick_provider.cc b/chrome/browser/autocomplete/history_quick_provider.cc index 57c86ae..1871bf2 100644 --- a/chrome/browser/autocomplete/history_quick_provider.cc +++ b/chrome/browser/autocomplete/history_quick_provider.cc
@@ -12,12 +12,10 @@ #include "base/i18n/break_iterator.h" #include "base/logging.h" #include "base/metrics/field_trial.h" -#include "base/metrics/histogram.h" #include "base/prefs/pref_service.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" -#include "base/time/time.h" #include "chrome/browser/autocomplete/chrome_autocomplete_scheme_classifier.h" #include "chrome/browser/autocomplete/history_url_provider.h" #include "chrome/browser/autocomplete/in_memory_url_index.h" @@ -75,16 +73,7 @@ // someone unloads the history backend, we'll get inconsistent inline // autocomplete behavior here. if (in_memory_url_index_) { - base::TimeTicks start_time = base::TimeTicks::Now(); DoAutocomplete(); - if (input.text().length() < 6) { - base::TimeTicks end_time = base::TimeTicks::Now(); - std::string name = "HistoryQuickProvider.QueryIndexTime." + - base::IntToString(input.text().length()); - base::HistogramBase* counter = base::Histogram::FactoryGet( - name, 1, 1000, 50, base::Histogram::kUmaTargetedHistogramFlag); - counter->Add(static_cast<int>((end_time - start_time).InMilliseconds())); - } } }
diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd index e275dca..ed14ec7 100644 --- a/chrome/browser/browser_resources.grd +++ b/chrome/browser/browser_resources.grd
@@ -279,13 +279,6 @@ <if expr="enable_google_now"> <include name="IDR_GOOGLE_NOW_MANIFEST" file="resources\google_now\manifest.json" type="BINDATA" /> </if> - <if expr="not is_android"> - <include name="IDR_SUGGESTIONS_INTERNALS_HTML" file="resources\suggestions_internals\suggestions_internals.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" /> - <include name="IDR_SUGGESTIONS_INTERNALS_CSS" file="resources\suggestions_internals\suggestions_internals.css" type="BINDATA" /> - <include name="IDR_SUGGESTIONS_INTERNALS_JS" file="resources\suggestions_internals\suggestions_internals.js" type="BINDATA" /> - <include name="IDR_SUGGESTIONS_PAGE_CSS" file="resources\ntp4\suggestions_page.css" type="BINDATA" /> - <include name="IDR_SUGGESTIONS_PAGE_JS" file="resources\ntp4\suggestions_page.js" type="BINDATA" /> - </if> <include name="IDR_UBER_HTML" file="resources\uber\uber.html" flattenhtml="true" type="BINDATA" /> <include name="IDR_UBER_JS" file="resources\uber\uber.js" type="BINDATA" /> <include name="IDR_UBER_FRAME_HTML" file="resources\uber\uber_frame.html" flattenhtml="true" type="BINDATA" />
diff --git a/chrome/browser/caps/generate_state_json.cc b/chrome/browser/caps/generate_state_json.cc index 3857d27..41a2a5d 100644 --- a/chrome/browser/caps/generate_state_json.cc +++ b/chrome/browser/caps/generate_state_json.cc
@@ -90,7 +90,7 @@ std::string json; auto options = base::JSONWriter::OPTIONS_PRETTY_PRINT; - if (!base::JSONWriter::WriteWithOptions(&dict, options, &json)) + if (!base::JSONWriter::WriteWithOptions(dict, options, &json)) return; file_.WriteAtCurrentPos(json.c_str(), json.size());
diff --git a/chrome/browser/chromeos/app_mode/kiosk_app_data.cc b/chrome/browser/chromeos/app_mode/kiosk_app_data.cc index 5245aad4..22d73d3 100644 --- a/chrome/browser/chromeos/app_mode/kiosk_app_data.cc +++ b/chrome/browser/chromeos/app_mode/kiosk_app_data.cc
@@ -76,7 +76,7 @@ return false; } -std::string ValueToString(const base::Value* value) { +std::string ValueToString(const base::Value& value) { std::string json; base::JSONWriter::Write(value, &json); return json; @@ -602,7 +602,7 @@ icon_url_string); if (!icon_url.is_valid()) { LOG(ERROR) << "Webstore response error (icon url): " - << ValueToString(webstore_data.get()); + << ValueToString(*webstore_data); OnWebstoreResponseParseFailure(kInvalidWebstoreResponseError); return; } @@ -626,7 +626,7 @@ std::string* value) { if (!response->GetString(key, value)) { LOG(ERROR) << "Webstore response error (" << key - << "): " << ValueToString(response); + << "): " << ValueToString(*response); OnWebstoreResponseParseFailure(kInvalidWebstoreResponseError); return false; }
diff --git a/chrome/browser/chromeos/bluetooth/bluetooth_pairing_dialog.cc b/chrome/browser/chromeos/bluetooth/bluetooth_pairing_dialog.cc index ff089f38..68712f28 100644 --- a/chrome/browser/chromeos/bluetooth/bluetooth_pairing_dialog.cc +++ b/chrome/browser/chromeos/bluetooth/bluetooth_pairing_dialog.cc
@@ -76,7 +76,7 @@ std::string BluetoothPairingDialog::GetDialogArgs() const { std::string data; - base::JSONWriter::Write(&device_data_, &data); + base::JSONWriter::Write(device_data_, &data); return data; }
diff --git a/chrome/browser/chromeos/boot_times_recorder.cc b/chrome/browser/chromeos/boot_times_recorder.cc index e9a3cec..268aef6 100644 --- a/chrome/browser/chromeos/boot_times_recorder.cc +++ b/chrome/browser/chromeos/boot_times_recorder.cc
@@ -152,7 +152,7 @@ dictionary.SetString(kDisk, disk_); std::string result; - if (!base::JSONWriter::Write(&dictionary, &result)) { + if (!base::JSONWriter::Write(dictionary, &result)) { LOG(WARNING) << "BootTimesRecorder::Stats::SerializeToString(): failed."; return std::string(); }
diff --git a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc index ee6e257..a69241b 100644 --- a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc +++ b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
@@ -767,6 +767,9 @@ g_browser_process->platform_part()->DestroyChromeUserManager(); + // Make sure that there is no pending URLRequests. + UserSessionManager::GetInstance()->Shutdown(); + g_browser_process->platform_part()->ShutdownSessionManager(); }
diff --git a/chrome/browser/chromeos/events/OWNERS b/chrome/browser/chromeos/events/OWNERS new file mode 100644 index 0000000..3b4e32e6 --- /dev/null +++ b/chrome/browser/chromeos/events/OWNERS
@@ -0,0 +1,3 @@ +sadrul@chromium.org + +per-file *event_rewriter* = kpschoedel@chromium.org
diff --git a/chrome/browser/chromeos/extensions/accessibility_features_apitest.cc b/chrome/browser/chromeos/extensions/accessibility_features_apitest.cc index 8245a9e4..25765814 100644 --- a/chrome/browser/chromeos/extensions/accessibility_features_apitest.cc +++ b/chrome/browser/chromeos/extensions/accessibility_features_apitest.cc
@@ -158,7 +158,7 @@ disabled_list->AppendString(disabled_features[i]); test_arg.Set(kDisabledFeaturesKey, disabled_list.release()); - return base::JSONWriter::Write(&test_arg, result); + return base::JSONWriter::Write(test_arg, result); } };
diff --git a/chrome/browser/chromeos/extensions/file_manager/file_manager_private_apitest.cc b/chrome/browser/chromeos/extensions/file_manager/file_manager_private_apitest.cc index 32523c1..3653a7f5 100644 --- a/chrome/browser/chromeos/extensions/file_manager/file_manager_private_apitest.cc +++ b/chrome/browser/chromeos/extensions/file_manager/file_manager_private_apitest.cc
@@ -8,7 +8,9 @@ #include "chrome/browser/chromeos/extensions/file_manager/event_router.h" #include "chrome/browser/chromeos/file_manager/drive_test_util.h" #include "chrome/browser/chromeos/file_manager/file_watcher.h" +#include "chrome/browser/chromeos/file_system_provider/provided_file_system_info.h" #include "chrome/browser/extensions/extension_apitest.h" +#include "chrome/common/extensions/api/file_system_provider_capabilities/file_system_provider_capabilities_handler.h" #include "chrome/test/base/testing_profile.h" #include "chrome/test/base/ui_test_utils.h" #include "chromeos/dbus/cros_disks_client.h" @@ -311,6 +313,17 @@ file_manager::test_util::WaitUntilDriveMountPointIsAdded( browser()->profile()); + // Add a provided file system, to test passing the |configurable| and + // |source| flags properly down to Files app. + chromeos::file_system_provider::ProvidedFileSystemInfo info( + "testing-extension-id", chromeos::file_system_provider::MountOptions(), + base::FilePath(), true /* configurable */, extensions::SOURCE_NETWORK); + + file_manager::VolumeManager::Get(browser()->profile()) + ->AddVolumeForTesting( + make_linked_ptr(file_manager::Volume::CreateForProvidedFileSystem( + info, file_manager::MOUNT_CONTEXT_AUTO))); + // We will call fileManagerPrivate.unmountVolume once. To test that method, we // check that UnmountPath is really called with the same value. EXPECT_CALL(*disk_mount_manager_mock_, UnmountPath(_, _, _))
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_misc.cc b/chrome/browser/chromeos/extensions/file_manager/private_api_misc.cc index 06e9cfa5..6cbc10b 100644 --- a/chrome/browser/chromeos/extensions/file_manager/private_api_misc.cc +++ b/chrome/browser/chromeos/extensions/file_manager/private_api_misc.cc
@@ -492,15 +492,14 @@ return RespondNow(NoArguments()); } -FileManagerPrivateConfigureProvidedFileSystemFunction:: - FileManagerPrivateConfigureProvidedFileSystemFunction() +FileManagerPrivateConfigureVolumeFunction:: + FileManagerPrivateConfigureVolumeFunction() : chrome_details_(this) { } ExtensionFunction::ResponseAction -FileManagerPrivateConfigureProvidedFileSystemFunction::Run() { - using extensions::api::file_manager_private::ConfigureProvidedFileSystem:: - Params; +FileManagerPrivateConfigureVolumeFunction::Run() { + using extensions::api::file_manager_private::ConfigureVolume::Params; const scoped_ptr<Params> params(Params::Create(*args_)); EXTENSION_FUNCTION_VALIDATE(params); @@ -512,24 +511,32 @@ volume_manager->FindVolumeById(params->volume_id); if (!volume.get()) return RespondNow(Error("Volume not found.")); + if (!volume->configurable()) + return RespondNow(Error("Volume not configurable.")); - using chromeos::file_system_provider::Service; - Service* const service = Service::Get(chrome_details_.GetProfile()); - DCHECK(service); + switch (volume->type()) { + case file_manager::VOLUME_TYPE_PROVIDED: { + using chromeos::file_system_provider::Service; + Service* const service = Service::Get(chrome_details_.GetProfile()); + DCHECK(service); - using chromeos::file_system_provider::ProvidedFileSystemInterface; - ProvidedFileSystemInterface* const file_system = - service->GetProvidedFileSystem(volume->extension_id(), - volume->file_system_id()); - DCHECK(file_system); + using chromeos::file_system_provider::ProvidedFileSystemInterface; + ProvidedFileSystemInterface* const file_system = + service->GetProvidedFileSystem(volume->extension_id(), + volume->file_system_id()); + if (file_system) + file_system->Configure(base::Bind( + &FileManagerPrivateConfigureVolumeFunction::OnCompleted, this)); + break; + } + default: + NOTIMPLEMENTED(); + } - file_system->Configure(base::Bind( - &FileManagerPrivateConfigureProvidedFileSystemFunction::OnCompleted, - this)); return RespondLater(); } -void FileManagerPrivateConfigureProvidedFileSystemFunction::OnCompleted( +void FileManagerPrivateConfigureVolumeFunction::OnCompleted( base::File::Error result) { if (result != base::File::FILE_OK) { Respond(Error("Failed to complete configuration."));
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_misc.h b/chrome/browser/chromeos/extensions/file_manager/private_api_misc.h index c744bf43..e681280 100644 --- a/chrome/browser/chromeos/extensions/file_manager/private_api_misc.h +++ b/chrome/browser/chromeos/extensions/file_manager/private_api_misc.h
@@ -225,23 +225,22 @@ DISALLOW_COPY_AND_ASSIGN(FileManagerPrivateAddProvidedFileSystemFunction); }; -// Implements the chrome.fileManagerPrivate.addProvidedFileSystem method. -class FileManagerPrivateConfigureProvidedFileSystemFunction +// Implements the chrome.fileManagerPrivate.configureVolume method. +class FileManagerPrivateConfigureVolumeFunction : public UIThreadExtensionFunction { public: - FileManagerPrivateConfigureProvidedFileSystemFunction(); - DECLARE_EXTENSION_FUNCTION("fileManagerPrivate.configureProvidedFileSystem", - FILEMANAGERPRIVATE_CONFIGUREPROVIDEDFILESYSTEM) + FileManagerPrivateConfigureVolumeFunction(); + DECLARE_EXTENSION_FUNCTION("fileManagerPrivate.configureVolume", + FILEMANAGERPRIVATE_CONFIGUREVOLUME) protected: - ~FileManagerPrivateConfigureProvidedFileSystemFunction() override {} + ~FileManagerPrivateConfigureVolumeFunction() override {} private: ResponseAction Run() override; void OnCompleted(base::File::Error result); const ChromeExtensionFunctionDetails chrome_details_; - DISALLOW_COPY_AND_ASSIGN( - FileManagerPrivateConfigureProvidedFileSystemFunction); + DISALLOW_COPY_AND_ASSIGN(FileManagerPrivateConfigureVolumeFunction); }; } // namespace extensions
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_util.cc b/chrome/browser/chromeos/extensions/file_manager/private_api_util.cc index fdcfdc6..9447ae6 100644 --- a/chrome/browser/chromeos/extensions/file_manager/private_api_util.cc +++ b/chrome/browser/chromeos/extensions/file_manager/private_api_util.cc
@@ -182,6 +182,25 @@ new std::string(volume.source_path().AsUTF8Unsafe())); } + switch (volume.source()) { + case SOURCE_FILE: + volume_metadata->source = file_manager_private::SOURCE_FILE; + break; + case SOURCE_DEVICE: + volume_metadata->source = file_manager_private::SOURCE_DEVICE; + break; + case SOURCE_NETWORK: + volume_metadata->source = + extensions::api::file_manager_private::SOURCE_NETWORK; + break; + case SOURCE_SYSTEM: + volume_metadata->source = + extensions::api::file_manager_private::SOURCE_SYSTEM; + break; + } + + volume_metadata->configurable = volume.configurable(); + if (volume.type() == VOLUME_TYPE_PROVIDED) { volume_metadata->extension_id.reset(new std::string(volume.extension_id())); volume_metadata->file_system_id.reset(
diff --git a/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc b/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc index 1aa481f..f4aab53c 100644 --- a/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc +++ b/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
@@ -681,13 +681,15 @@ if (name == "getRootPaths") { // Pass the root paths. - const scoped_ptr<base::DictionaryValue> res(new base::DictionaryValue()); - res->SetString("downloads", - "/" + util::GetDownloadsMountPointName(profile())); - res->SetString("drive", - "/" + drive::util::GetDriveMountPointPath(profile() - ).BaseName().AsUTF8Unsafe() + "/root"); - base::JSONWriter::Write(res.get(), output); + base::DictionaryValue res; + res.SetString("downloads", + "/" + util::GetDownloadsMountPointName(profile())); + res.SetString("drive", "/" + + drive::util::GetDriveMountPointPath(profile()) + .BaseName() + .AsUTF8Unsafe() + + "/root"); + base::JSONWriter::Write(res, output); return; } @@ -707,10 +709,10 @@ if (*origin.rbegin() == '/') origin.resize(origin.length() - 1); - const scoped_ptr<base::DictionaryValue> res(new base::DictionaryValue()); - res->SetString("url", url.spec()); - res->SetString("origin", origin); - base::JSONWriter::Write(res.get(), output); + base::DictionaryValue res; + res.SetString("url", url.spec()); + res.SetString("origin", origin); + base::JSONWriter::Write(res, output); return; }
diff --git a/chrome/browser/chromeos/file_manager/url_util.cc b/chrome/browser/chromeos/file_manager/url_util.cc index 088751b..1f3e9d86 100644 --- a/chrome/browser/chromeos/file_manager/url_util.cc +++ b/chrome/browser/chromeos/file_manager/url_util.cc
@@ -111,7 +111,7 @@ !file_types || !file_types->support_drive); std::string json_args; - base::JSONWriter::Write(&arg_value, &json_args); + base::JSONWriter::Write(arg_value, &json_args); std::string url = GetFileManagerMainPageUrl().spec() + '?' + net::EscapeUrlEncodedData(json_args,
diff --git a/chrome/browser/chromeos/file_manager/url_util_unittest.cc b/chrome/browser/chromeos/file_manager/url_util_unittest.cc index 1360d00..569617dc 100644 --- a/chrome/browser/chromeos/file_manager/url_util_unittest.cc +++ b/chrome/browser/chromeos/file_manager/url_util_unittest.cc
@@ -23,9 +23,8 @@ query, net::UnescapeRule::SPACES | net::UnescapeRule::URL_SPECIAL_CHARS); scoped_ptr<base::Value> value(base::JSONReader::Read(json)); std::string pretty_json; - base::JSONWriter::WriteWithOptions(value.get(), - base::JSONWriter::OPTIONS_PRETTY_PRINT, - &pretty_json); + base::JSONWriter::WriteWithOptions( + *value, base::JSONWriter::OPTIONS_PRETTY_PRINT, &pretty_json); return pretty_json; }
diff --git a/chrome/browser/chromeos/file_manager/volume_manager.cc b/chrome/browser/chromeos/file_manager/volume_manager.cc index 6f0e6efb..e03e5bc 100644 --- a/chrome/browser/chromeos/file_manager/volume_manager.cc +++ b/chrome/browser/chromeos/file_manager/volume_manager.cc
@@ -130,13 +130,15 @@ } // namespace Volume::Volume() - : type_(VOLUME_TYPE_GOOGLE_DRIVE), + : source_(SOURCE_FILE), + type_(VOLUME_TYPE_GOOGLE_DRIVE), device_type_(chromeos::DEVICE_TYPE_UNKNOWN), mount_condition_(chromeos::disks::MOUNT_CONDITION_NONE), mount_context_(MOUNT_CONTEXT_UNKNOWN), is_parent_(false), is_read_only_(false), - has_media_(false) { + has_media_(false), + configurable_(false) { } Volume::~Volume() { @@ -150,11 +152,9 @@ volume->type_ = VOLUME_TYPE_GOOGLE_DRIVE; volume->device_type_ = chromeos::DEVICE_TYPE_UNKNOWN; volume->source_path_ = drive_path; + volume->source_ = SOURCE_NETWORK; volume->mount_path_ = drive_path; volume->mount_condition_ = chromeos::disks::MOUNT_CONDITION_NONE; - volume->is_parent_ = false; - volume->is_read_only_ = false; - volume->has_media_ = false; volume->volume_id_ = GenerateVolumeId(*volume); return volume; } @@ -165,11 +165,9 @@ volume->type_ = VOLUME_TYPE_DOWNLOADS_DIRECTORY; volume->device_type_ = chromeos::DEVICE_TYPE_UNKNOWN; // Keep source_path empty. + volume->source_ = SOURCE_SYSTEM; volume->mount_path_ = downloads_path; volume->mount_condition_ = chromeos::disks::MOUNT_CONDITION_NONE; - volume->is_parent_ = false; - volume->is_read_only_ = false; - volume->has_media_ = false; volume->volume_id_ = GenerateVolumeId(*volume); return volume; } @@ -181,6 +179,9 @@ Volume* const volume = new Volume; volume->type_ = MountTypeToVolumeType(mount_point.mount_type); volume->source_path_ = base::FilePath(mount_point.source_path); + volume->source_ = mount_point.mount_type == chromeos::MOUNT_TYPE_ARCHIVE + ? SOURCE_FILE + : SOURCE_DEVICE; volume->mount_path_ = base::FilePath(mount_point.mount_path); volume->mount_condition_ = mount_point.mount_condition; volume->volume_label_ = volume->mount_path().BaseName().AsUTF8Unsafe(); @@ -192,10 +193,8 @@ volume->has_media_ = disk->has_media(); } else { volume->device_type_ = chromeos::DEVICE_TYPE_UNKNOWN; - volume->is_parent_ = false; volume->is_read_only_ = (mount_point.mount_type == chromeos::MOUNT_TYPE_ARCHIVE); - volume->has_media_ = false; } volume->volume_id_ = GenerateVolumeId(*volume); return volume; @@ -209,6 +208,17 @@ Volume* const volume = new Volume; volume->file_system_id_ = file_system_info.file_system_id(); volume->extension_id_ = file_system_info.extension_id(); + switch (file_system_info.source()) { + case extensions::SOURCE_FILE: + volume->source_ = SOURCE_FILE; + break; + case extensions::SOURCE_DEVICE: + volume->source_ = SOURCE_DEVICE; + break; + case extensions::SOURCE_NETWORK: + volume->source_ = SOURCE_NETWORK; + break; + } volume->volume_label_ = file_system_info.display_name(); volume->type_ = VOLUME_TYPE_PROVIDED; volume->mount_path_ = file_system_info.mount_path(); @@ -216,7 +226,7 @@ volume->mount_context_ = mount_context; volume->is_parent_ = true; volume->is_read_only_ = !file_system_info.writable(); - volume->has_media_ = false; + volume->configurable_ = file_system_info.configurable(); volume->volume_id_ = GenerateVolumeId(*volume); return volume; } @@ -234,6 +244,7 @@ volume->volume_id_ = kMtpVolumeIdPrefix + label; volume->volume_label_ = label; volume->source_path_ = mount_path; + volume->source_ = SOURCE_DEVICE; volume->device_type_ = chromeos::DEVICE_TYPE_MOBILE; return volume; } @@ -247,11 +258,10 @@ volume->type_ = volume_type; volume->device_type_ = device_type; // Keep source_path empty. + volume->source_ = SOURCE_DEVICE; volume->mount_path_ = path; volume->mount_condition_ = chromeos::disks::MOUNT_CONDITION_NONE; - volume->is_parent_ = false; volume->is_read_only_ = read_only; - volume->has_media_ = false; volume->volume_id_ = GenerateVolumeId(*volume); return volume; } @@ -421,6 +431,11 @@ path, volume_type, device_type, read_only))); } +void VolumeManager::AddVolumeForTesting(const linked_ptr<Volume>& volume) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + DoMountEvent(chromeos::MOUNT_ERROR_NONE, volume); +} + void VolumeManager::OnFileSystemMounted() { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); @@ -785,7 +800,7 @@ } void VolumeManager::DoMountEvent(chromeos::MountError error_code, - linked_ptr<Volume> volume) { + const linked_ptr<Volume>& volume) { // Archive files are mounted globally in system. We however don't want to show // archives from profile-specific folders (Drive/Downloads) of other users in // multi-profile session. To this end, we filter out archives not on the @@ -821,7 +836,7 @@ } void VolumeManager::DoUnmountEvent(chromeos::MountError error_code, - linked_ptr<Volume> volume) { + const linked_ptr<Volume>& volume) { if (mounted_volumes_.find(volume->volume_id()) == mounted_volumes_.end()) return; if (error_code == chromeos::MOUNT_ERROR_NONE)
diff --git a/chrome/browser/chromeos/file_manager/volume_manager.h b/chrome/browser/chromeos/file_manager/volume_manager.h index efaf20f..2e19149 100644 --- a/chrome/browser/chromeos/file_manager/volume_manager.h +++ b/chrome/browser/chromeos/file_manager/volume_manager.h
@@ -66,6 +66,9 @@ MOUNT_CONTEXT_UNKNOWN }; +// Source of a volume's data. +enum Source { SOURCE_FILE, SOURCE_DEVICE, SOURCE_NETWORK, SOURCE_SYSTEM }; + // Represents a volume (mount point) in the volume manager. Validity of the data // is guaranteed by the weak pointer. Simply saying, the weak pointer should be // valid as long as the volume is mounted. @@ -97,6 +100,7 @@ const std::string& volume_id() const { return volume_id_; } const std::string& file_system_id() const { return file_system_id_; } const std::string& extension_id() const { return extension_id_; } + Source source() const { return source_; } VolumeType type() const { return type_; } chromeos::DeviceType device_type() const { return device_type_; } const base::FilePath& source_path() const { return source_path_; } @@ -112,6 +116,7 @@ bool is_parent() const { return is_parent_; } bool is_read_only() const { return is_read_only_; } bool has_media() const { return has_media_; } + bool configurable() const { return configurable_; } private: Volume(); @@ -127,6 +132,9 @@ // to an empty string. std::string extension_id_; + // The source of the volume's data. + Source source_; + // The type of mounted volume. VolumeType type_; @@ -170,6 +178,9 @@ // True if the volume contains media. bool has_media_; + // True if the volume is configurable. + bool configurable_; + DISALLOW_COPY_AND_ASSIGN(Volume); }; @@ -228,6 +239,9 @@ chromeos::DeviceType device_type, bool read_only); + // For testing purpose, adds the volume info to the volume manager. + void AddVolumeForTesting(const linked_ptr<Volume>& volume); + // drive::DriveIntegrationServiceObserver overrides. void OnFileSystemMounted() override; void OnFileSystemBeingUnmounted() override; @@ -271,9 +285,10 @@ private: void OnDiskMountManagerRefreshed(bool success); void OnStorageMonitorInitialized(); - void DoMountEvent(chromeos::MountError error_code, linked_ptr<Volume> volume); + void DoMountEvent(chromeos::MountError error_code, + const linked_ptr<Volume>& volume); void DoUnmountEvent(chromeos::MountError error_code, - linked_ptr<Volume> volume); + const linked_ptr<Volume>& volume); Profile* profile_; drive::DriveIntegrationService* drive_integration_service_; // Not owned.
diff --git a/chrome/browser/chromeos/file_system_provider/mount_path_util_unittest.cc b/chrome/browser/chromeos/file_system_provider/mount_path_util_unittest.cc index ae8be916..7c5ee2d8 100644 --- a/chrome/browser/chromeos/file_system_provider/mount_path_util_unittest.cc +++ b/chrome/browser/chromeos/file_system_provider/mount_path_util_unittest.cc
@@ -15,6 +15,7 @@ #include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h" #include "chrome/browser/chromeos/login/users/scoped_user_manager_enabler.h" #include "chrome/browser/profiles/profile.h" +#include "chrome/common/extensions/api/file_system_provider_capabilities/file_system_provider_capabilities_handler.h" #include "chrome/test/base/testing_browser_process.h" #include "chrome/test/base/testing_profile.h" #include "chrome/test/base/testing_profile_manager.h" @@ -177,9 +178,9 @@ TEST_F(FileSystemProviderMountPathUtilTest, Parser_WrongUrl) { const ProvidedFileSystemInfo file_system_info( - kExtensionId, - MountOptions(kFileSystemId, kDisplayName), - GetMountPath(profile_, kExtensionId, kFileSystemId)); + kExtensionId, MountOptions(kFileSystemId, kDisplayName), + GetMountPath(profile_, kExtensionId, kFileSystemId), + false /* configurable */, extensions::SOURCE_FILE); const base::FilePath kFilePath = base::FilePath(FILE_PATH_LITERAL("/hello")); const storage::FileSystemURL url =
diff --git a/chrome/browser/chromeos/file_system_provider/operations/abort_unittest.cc b/chrome/browser/chromeos/file_system_provider/operations/abort_unittest.cc index ad0c31c..27b016f54 100644 --- a/chrome/browser/chromeos/file_system_provider/operations/abort_unittest.cc +++ b/chrome/browser/chromeos/file_system_provider/operations/abort_unittest.cc
@@ -14,6 +14,7 @@ #include "chrome/browser/chromeos/file_system_provider/operations/test_util.h" #include "chrome/browser/chromeos/file_system_provider/provided_file_system_interface.h" #include "chrome/common/extensions/api/file_system_provider.h" +#include "chrome/common/extensions/api/file_system_provider_capabilities/file_system_provider_capabilities_handler.h" #include "chrome/common/extensions/api/file_system_provider_internal.h" #include "extensions/browser/event_router.h" #include "storage/browser/fileapi/async_file_util.h" @@ -38,9 +39,8 @@ void SetUp() override { file_system_info_ = ProvidedFileSystemInfo( - kExtensionId, - MountOptions(kFileSystemId, "" /* display_name */), - base::FilePath()); + kExtensionId, MountOptions(kFileSystemId, "" /* display_name */), + base::FilePath(), false /* configurable */, extensions::SOURCE_FILE); } ProvidedFileSystemInfo file_system_info_;
diff --git a/chrome/browser/chromeos/file_system_provider/operations/add_watcher_unittest.cc b/chrome/browser/chromeos/file_system_provider/operations/add_watcher_unittest.cc index 0707d533..c076b002 100644 --- a/chrome/browser/chromeos/file_system_provider/operations/add_watcher_unittest.cc +++ b/chrome/browser/chromeos/file_system_provider/operations/add_watcher_unittest.cc
@@ -14,6 +14,7 @@ #include "chrome/browser/chromeos/file_system_provider/operations/test_util.h" #include "chrome/browser/chromeos/file_system_provider/provided_file_system_interface.h" #include "chrome/common/extensions/api/file_system_provider.h" +#include "chrome/common/extensions/api/file_system_provider_capabilities/file_system_provider_capabilities_handler.h" #include "chrome/common/extensions/api/file_system_provider_internal.h" #include "extensions/browser/event_router.h" #include "storage/browser/fileapi/async_file_util.h" @@ -39,9 +40,8 @@ void SetUp() override { file_system_info_ = ProvidedFileSystemInfo( - kExtensionId, - MountOptions(kFileSystemId, "" /* display_name */), - base::FilePath()); + kExtensionId, MountOptions(kFileSystemId, "" /* display_name */), + base::FilePath(), false /* configurable */, extensions::SOURCE_FILE); } ProvidedFileSystemInfo file_system_info_;
diff --git a/chrome/browser/chromeos/file_system_provider/operations/close_file_unittest.cc b/chrome/browser/chromeos/file_system_provider/operations/close_file_unittest.cc index 2be3706..e46657f 100644 --- a/chrome/browser/chromeos/file_system_provider/operations/close_file_unittest.cc +++ b/chrome/browser/chromeos/file_system_provider/operations/close_file_unittest.cc
@@ -13,6 +13,7 @@ #include "chrome/browser/chromeos/file_system_provider/operations/test_util.h" #include "chrome/browser/chromeos/file_system_provider/provided_file_system_interface.h" #include "chrome/common/extensions/api/file_system_provider.h" +#include "chrome/common/extensions/api/file_system_provider_capabilities/file_system_provider_capabilities_handler.h" #include "chrome/common/extensions/api/file_system_provider_internal.h" #include "extensions/browser/event_router.h" #include "storage/browser/fileapi/async_file_util.h" @@ -37,9 +38,8 @@ void SetUp() override { file_system_info_ = ProvidedFileSystemInfo( - kExtensionId, - MountOptions(kFileSystemId, "" /* display_name */), - base::FilePath()); + kExtensionId, MountOptions(kFileSystemId, "" /* display_name */), + base::FilePath(), false /* configurable */, extensions::SOURCE_FILE); } ProvidedFileSystemInfo file_system_info_;
diff --git a/chrome/browser/chromeos/file_system_provider/operations/configure_unittest.cc b/chrome/browser/chromeos/file_system_provider/operations/configure_unittest.cc index 984ca847..03b52a626 100644 --- a/chrome/browser/chromeos/file_system_provider/operations/configure_unittest.cc +++ b/chrome/browser/chromeos/file_system_provider/operations/configure_unittest.cc
@@ -13,6 +13,7 @@ #include "chrome/browser/chromeos/file_system_provider/operations/test_util.h" #include "chrome/browser/chromeos/file_system_provider/provided_file_system_interface.h" #include "chrome/common/extensions/api/file_system_provider.h" +#include "chrome/common/extensions/api/file_system_provider_capabilities/file_system_provider_capabilities_handler.h" #include "chrome/common/extensions/api/file_system_provider_internal.h" #include "extensions/browser/event_router.h" #include "testing/gtest/include/gtest/gtest.h" @@ -36,7 +37,7 @@ void SetUp() override { file_system_info_ = ProvidedFileSystemInfo( kExtensionId, MountOptions(kFileSystemId, "" /* display_name */), - base::FilePath()); + base::FilePath(), false /* configurable */, extensions::SOURCE_FILE); } ProvidedFileSystemInfo file_system_info_;
diff --git a/chrome/browser/chromeos/file_system_provider/operations/copy_entry_unittest.cc b/chrome/browser/chromeos/file_system_provider/operations/copy_entry_unittest.cc index 8a5654ed..f864780 100644 --- a/chrome/browser/chromeos/file_system_provider/operations/copy_entry_unittest.cc +++ b/chrome/browser/chromeos/file_system_provider/operations/copy_entry_unittest.cc
@@ -14,6 +14,7 @@ #include "chrome/browser/chromeos/file_system_provider/operations/test_util.h" #include "chrome/browser/chromeos/file_system_provider/provided_file_system_interface.h" #include "chrome/common/extensions/api/file_system_provider.h" +#include "chrome/common/extensions/api/file_system_provider_capabilities/file_system_provider_capabilities_handler.h" #include "chrome/common/extensions/api/file_system_provider_internal.h" #include "extensions/browser/event_router.h" #include "storage/browser/fileapi/async_file_util.h" @@ -42,8 +43,9 @@ void SetUp() override { MountOptions mount_options(kFileSystemId, "" /* display_name */); mount_options.writable = true; - file_system_info_ = - ProvidedFileSystemInfo(kExtensionId, mount_options, base::FilePath()); + file_system_info_ = ProvidedFileSystemInfo( + kExtensionId, mount_options, base::FilePath(), false /* configurable */, + extensions::SOURCE_FILE); } ProvidedFileSystemInfo file_system_info_; @@ -102,9 +104,9 @@ util::StatusCallbackLog callback_log; const ProvidedFileSystemInfo read_only_file_system_info( - kExtensionId, - MountOptions(kFileSystemId, "" /* display_name */), - base::FilePath() /* mount_path */); + kExtensionId, MountOptions(kFileSystemId, "" /* display_name */), + base::FilePath() /* mount_path */, false /* configurable */, + extensions::SOURCE_FILE); CopyEntry copy_entry(NULL, read_only_file_system_info, base::FilePath(kSourcePath), base::FilePath(kTargetPath),
diff --git a/chrome/browser/chromeos/file_system_provider/operations/create_directory_unittest.cc b/chrome/browser/chromeos/file_system_provider/operations/create_directory_unittest.cc index c5d31797..d7d2274 100644 --- a/chrome/browser/chromeos/file_system_provider/operations/create_directory_unittest.cc +++ b/chrome/browser/chromeos/file_system_provider/operations/create_directory_unittest.cc
@@ -14,6 +14,7 @@ #include "chrome/browser/chromeos/file_system_provider/operations/test_util.h" #include "chrome/browser/chromeos/file_system_provider/provided_file_system_interface.h" #include "chrome/common/extensions/api/file_system_provider.h" +#include "chrome/common/extensions/api/file_system_provider_capabilities/file_system_provider_capabilities_handler.h" #include "chrome/common/extensions/api/file_system_provider_internal.h" #include "extensions/browser/event_router.h" #include "storage/browser/fileapi/async_file_util.h" @@ -40,8 +41,9 @@ void SetUp() override { MountOptions mount_options(kFileSystemId, "" /* display_name */); mount_options.writable = true; - file_system_info_ = - ProvidedFileSystemInfo(kExtensionId, mount_options, base::FilePath()); + file_system_info_ = ProvidedFileSystemInfo( + kExtensionId, mount_options, base::FilePath(), false /* configurable */, + extensions::SOURCE_FILE); } ProvidedFileSystemInfo file_system_info_; @@ -103,9 +105,9 @@ util::StatusCallbackLog callback_log; const ProvidedFileSystemInfo read_only_file_system_info( - kExtensionId, - MountOptions(kFileSystemId, "" /* display_name */), - base::FilePath() /* mount_path */); + kExtensionId, MountOptions(kFileSystemId, "" /* display_name */), + base::FilePath() /* mount_path */, false /* configurable */, + extensions::SOURCE_FILE); CreateDirectory create_directory( NULL, read_only_file_system_info, base::FilePath(kDirectoryPath),
diff --git a/chrome/browser/chromeos/file_system_provider/operations/create_file_unittest.cc b/chrome/browser/chromeos/file_system_provider/operations/create_file_unittest.cc index 3b38e0c..3e40b90 100644 --- a/chrome/browser/chromeos/file_system_provider/operations/create_file_unittest.cc +++ b/chrome/browser/chromeos/file_system_provider/operations/create_file_unittest.cc
@@ -14,6 +14,7 @@ #include "chrome/browser/chromeos/file_system_provider/operations/test_util.h" #include "chrome/browser/chromeos/file_system_provider/provided_file_system_interface.h" #include "chrome/common/extensions/api/file_system_provider.h" +#include "chrome/common/extensions/api/file_system_provider_capabilities/file_system_provider_capabilities_handler.h" #include "chrome/common/extensions/api/file_system_provider_internal.h" #include "extensions/browser/event_router.h" #include "storage/browser/fileapi/async_file_util.h" @@ -40,8 +41,9 @@ void SetUp() override { MountOptions mount_options(kFileSystemId, "" /* display_name */); mount_options.writable = true; - file_system_info_ = - ProvidedFileSystemInfo(kExtensionId, mount_options, base::FilePath()); + file_system_info_ = ProvidedFileSystemInfo( + kExtensionId, mount_options, base::FilePath(), false /* configurable */, + extensions::SOURCE_FILE); } ProvidedFileSystemInfo file_system_info_; @@ -98,9 +100,9 @@ util::StatusCallbackLog callback_log; const ProvidedFileSystemInfo read_only_file_system_info( - kExtensionId, - MountOptions(kFileSystemId, "" /* display_name */), - base::FilePath() /* mount_path */); + kExtensionId, MountOptions(kFileSystemId, "" /* display_name */), + base::FilePath() /* mount_path */, false /* configurable */, + extensions::SOURCE_FILE); CreateFile create_file(NULL, read_only_file_system_info, base::FilePath(kFilePath),
diff --git a/chrome/browser/chromeos/file_system_provider/operations/delete_entry_unittest.cc b/chrome/browser/chromeos/file_system_provider/operations/delete_entry_unittest.cc index faaae1f..a7067e1 100644 --- a/chrome/browser/chromeos/file_system_provider/operations/delete_entry_unittest.cc +++ b/chrome/browser/chromeos/file_system_provider/operations/delete_entry_unittest.cc
@@ -14,6 +14,7 @@ #include "chrome/browser/chromeos/file_system_provider/operations/test_util.h" #include "chrome/browser/chromeos/file_system_provider/provided_file_system_interface.h" #include "chrome/common/extensions/api/file_system_provider.h" +#include "chrome/common/extensions/api/file_system_provider_capabilities/file_system_provider_capabilities_handler.h" #include "chrome/common/extensions/api/file_system_provider_internal.h" #include "extensions/browser/event_router.h" #include "storage/browser/fileapi/async_file_util.h" @@ -40,8 +41,9 @@ void SetUp() override { MountOptions mount_options(kFileSystemId, "" /* display_name */); mount_options.writable = true; - file_system_info_ = - ProvidedFileSystemInfo(kExtensionId, mount_options, base::FilePath()); + file_system_info_ = ProvidedFileSystemInfo( + kExtensionId, mount_options, base::FilePath(), false /* configurable */, + extensions::SOURCE_FILE); } ProvidedFileSystemInfo file_system_info_; @@ -101,9 +103,9 @@ util::StatusCallbackLog callback_log; const ProvidedFileSystemInfo read_only_file_system_info( - kExtensionId, - MountOptions(kFileSystemId, "" /* display_name */), - base::FilePath() /* mount_path */); + kExtensionId, MountOptions(kFileSystemId, "" /* display_name */), + base::FilePath() /* mount_path */, false /* configurable */, + extensions::SOURCE_FILE); DeleteEntry delete_entry(NULL, read_only_file_system_info, base::FilePath(kEntryPath), true /* recursive */,
diff --git a/chrome/browser/chromeos/file_system_provider/operations/get_metadata_unittest.cc b/chrome/browser/chromeos/file_system_provider/operations/get_metadata_unittest.cc index 60e269a..f8f2545 100644 --- a/chrome/browser/chromeos/file_system_provider/operations/get_metadata_unittest.cc +++ b/chrome/browser/chromeos/file_system_provider/operations/get_metadata_unittest.cc
@@ -14,6 +14,7 @@ #include "base/values.h" #include "chrome/browser/chromeos/file_system_provider/operations/test_util.h" #include "chrome/common/extensions/api/file_system_provider.h" +#include "chrome/common/extensions/api/file_system_provider_capabilities/file_system_provider_capabilities_handler.h" #include "chrome/common/extensions/api/file_system_provider_internal.h" #include "extensions/browser/event_router.h" #include "storage/browser/fileapi/async_file_util.h" @@ -98,9 +99,8 @@ void SetUp() override { file_system_info_ = ProvidedFileSystemInfo( - kExtensionId, - MountOptions(kFileSystemId, "" /* display_name */), - base::FilePath()); + kExtensionId, MountOptions(kFileSystemId, "" /* display_name */), + base::FilePath(), false /* configurable */, extensions::SOURCE_FILE); } ProvidedFileSystemInfo file_system_info_;
diff --git a/chrome/browser/chromeos/file_system_provider/operations/move_entry_unittest.cc b/chrome/browser/chromeos/file_system_provider/operations/move_entry_unittest.cc index 9ebce8d..63518205 100644 --- a/chrome/browser/chromeos/file_system_provider/operations/move_entry_unittest.cc +++ b/chrome/browser/chromeos/file_system_provider/operations/move_entry_unittest.cc
@@ -14,6 +14,8 @@ #include "chrome/browser/chromeos/file_system_provider/operations/test_util.h" #include "chrome/browser/chromeos/file_system_provider/provided_file_system_interface.h" #include "chrome/common/extensions/api/file_system_provider.h" +#include "chrome/common/extensions/api/file_system_provider_capabilities/file_system_provider_capabilities_handler.h" +#include "chrome/common/extensions/api/file_system_provider_capabilities/file_system_provider_capabilities_handler.h" #include "chrome/common/extensions/api/file_system_provider_internal.h" #include "extensions/browser/event_router.h" #include "storage/browser/fileapi/async_file_util.h" @@ -42,8 +44,9 @@ void SetUp() override { MountOptions mount_options(kFileSystemId, "" /* display_name */); mount_options.writable = true; - file_system_info_ = - ProvidedFileSystemInfo(kExtensionId, mount_options, base::FilePath()); + file_system_info_ = ProvidedFileSystemInfo( + kExtensionId, mount_options, base::FilePath(), false /* configurable */, + extensions::SOURCE_FILE); } ProvidedFileSystemInfo file_system_info_; @@ -102,9 +105,9 @@ util::StatusCallbackLog callback_log; const ProvidedFileSystemInfo read_only_file_system_info( - kExtensionId, - MountOptions(kFileSystemId, "" /* display_name */), - base::FilePath() /* mount_path */); + kExtensionId, MountOptions(kFileSystemId, "" /* display_name */), + base::FilePath() /* mount_path */, false /* configurable */, + extensions::SOURCE_FILE); MoveEntry move_entry(NULL, read_only_file_system_info, base::FilePath(kSourcePath), base::FilePath(kTargetPath),
diff --git a/chrome/browser/chromeos/file_system_provider/operations/open_file_unittest.cc b/chrome/browser/chromeos/file_system_provider/operations/open_file_unittest.cc index 8cc3088..f6bd6d9b 100644 --- a/chrome/browser/chromeos/file_system_provider/operations/open_file_unittest.cc +++ b/chrome/browser/chromeos/file_system_provider/operations/open_file_unittest.cc
@@ -14,6 +14,7 @@ #include "chrome/browser/chromeos/file_system_provider/operations/test_util.h" #include "chrome/browser/chromeos/file_system_provider/provided_file_system_interface.h" #include "chrome/common/extensions/api/file_system_provider.h" +#include "chrome/common/extensions/api/file_system_provider_capabilities/file_system_provider_capabilities_handler.h" #include "chrome/common/extensions/api/file_system_provider_internal.h" #include "extensions/browser/event_router.h" #include "storage/browser/fileapi/async_file_util.h" @@ -73,9 +74,8 @@ void SetUp() override { file_system_info_ = ProvidedFileSystemInfo( - kExtensionId, - MountOptions(kFileSystemId, "" /* display_name */), - base::FilePath()); + kExtensionId, MountOptions(kFileSystemId, "" /* display_name */), + base::FilePath(), false /* configurable */, extensions::SOURCE_FILE); } ProvidedFileSystemInfo file_system_info_; @@ -137,9 +137,9 @@ CallbackLogger callback_logger; const ProvidedFileSystemInfo read_only_file_system_info( - kExtensionId, - MountOptions(kFileSystemId, "" /* display_name */), - base::FilePath() /* mount_path */); + kExtensionId, MountOptions(kFileSystemId, "" /* display_name */), + base::FilePath() /* mount_path */, false /* configurable */, + extensions::SOURCE_FILE); // Opening for read on a read-only file system is allowed. {
diff --git a/chrome/browser/chromeos/file_system_provider/operations/read_directory_unittest.cc b/chrome/browser/chromeos/file_system_provider/operations/read_directory_unittest.cc index 3855147..ecf38a1 100644 --- a/chrome/browser/chromeos/file_system_provider/operations/read_directory_unittest.cc +++ b/chrome/browser/chromeos/file_system_provider/operations/read_directory_unittest.cc
@@ -15,6 +15,7 @@ #include "chrome/browser/chromeos/file_system_provider/operations/get_metadata.h" #include "chrome/browser/chromeos/file_system_provider/operations/test_util.h" #include "chrome/common/extensions/api/file_system_provider.h" +#include "chrome/common/extensions/api/file_system_provider_capabilities/file_system_provider_capabilities_handler.h" #include "chrome/common/extensions/api/file_system_provider_internal.h" #include "extensions/browser/event_router.h" #include "storage/browser/fileapi/async_file_util.h" @@ -102,9 +103,8 @@ void SetUp() override { file_system_info_ = ProvidedFileSystemInfo( - kExtensionId, - MountOptions(kFileSystemId, "" /* display_name */), - base::FilePath()); + kExtensionId, MountOptions(kFileSystemId, "" /* display_name */), + base::FilePath(), false /* configurable */, extensions::SOURCE_FILE); } ProvidedFileSystemInfo file_system_info_;
diff --git a/chrome/browser/chromeos/file_system_provider/operations/read_file_unittest.cc b/chrome/browser/chromeos/file_system_provider/operations/read_file_unittest.cc index 6a83834..b9d28f2 100644 --- a/chrome/browser/chromeos/file_system_provider/operations/read_file_unittest.cc +++ b/chrome/browser/chromeos/file_system_provider/operations/read_file_unittest.cc
@@ -14,6 +14,7 @@ #include "base/values.h" #include "chrome/browser/chromeos/file_system_provider/operations/test_util.h" #include "chrome/common/extensions/api/file_system_provider.h" +#include "chrome/common/extensions/api/file_system_provider_capabilities/file_system_provider_capabilities_handler.h" #include "chrome/common/extensions/api/file_system_provider_internal.h" #include "extensions/browser/event_router.h" #include "net/base/io_buffer.h" @@ -77,9 +78,8 @@ void SetUp() override { file_system_info_ = ProvidedFileSystemInfo( - kExtensionId, - MountOptions(kFileSystemId, "" /* display_name */), - base::FilePath()); + kExtensionId, MountOptions(kFileSystemId, "" /* display_name */), + base::FilePath(), false /* configurable */, extensions::SOURCE_FILE); io_buffer_ = make_scoped_refptr(new net::IOBuffer(kOffset + kLength)); }
diff --git a/chrome/browser/chromeos/file_system_provider/operations/remove_watcher_unittest.cc b/chrome/browser/chromeos/file_system_provider/operations/remove_watcher_unittest.cc index d72fcef..56f488d7 100644 --- a/chrome/browser/chromeos/file_system_provider/operations/remove_watcher_unittest.cc +++ b/chrome/browser/chromeos/file_system_provider/operations/remove_watcher_unittest.cc
@@ -14,6 +14,7 @@ #include "chrome/browser/chromeos/file_system_provider/operations/test_util.h" #include "chrome/browser/chromeos/file_system_provider/provided_file_system_interface.h" #include "chrome/common/extensions/api/file_system_provider.h" +#include "chrome/common/extensions/api/file_system_provider_capabilities/file_system_provider_capabilities_handler.h" #include "chrome/common/extensions/api/file_system_provider_internal.h" #include "extensions/browser/event_router.h" #include "storage/browser/fileapi/async_file_util.h" @@ -39,9 +40,8 @@ void SetUp() override { file_system_info_ = ProvidedFileSystemInfo( - kExtensionId, - MountOptions(kFileSystemId, "" /* display_name */), - base::FilePath()); + kExtensionId, MountOptions(kFileSystemId, "" /* display_name */), + base::FilePath(), false /* configurable */, extensions::SOURCE_FILE); } ProvidedFileSystemInfo file_system_info_;
diff --git a/chrome/browser/chromeos/file_system_provider/operations/truncate_unittest.cc b/chrome/browser/chromeos/file_system_provider/operations/truncate_unittest.cc index 54012e5..6439602 100644 --- a/chrome/browser/chromeos/file_system_provider/operations/truncate_unittest.cc +++ b/chrome/browser/chromeos/file_system_provider/operations/truncate_unittest.cc
@@ -14,6 +14,7 @@ #include "chrome/browser/chromeos/file_system_provider/operations/test_util.h" #include "chrome/browser/chromeos/file_system_provider/provided_file_system_interface.h" #include "chrome/common/extensions/api/file_system_provider.h" +#include "chrome/common/extensions/api/file_system_provider_capabilities/file_system_provider_capabilities_handler.h" #include "chrome/common/extensions/api/file_system_provider_internal.h" #include "extensions/browser/event_router.h" #include "storage/browser/fileapi/async_file_util.h" @@ -41,8 +42,9 @@ void SetUp() override { MountOptions mount_options(kFileSystemId, "" /* display_name */); mount_options.writable = true; - file_system_info_ = - ProvidedFileSystemInfo(kExtensionId, mount_options, base::FilePath()); + file_system_info_ = ProvidedFileSystemInfo( + kExtensionId, mount_options, base::FilePath(), false /* configurable */, + extensions::SOURCE_FILE); } ProvidedFileSystemInfo file_system_info_; @@ -101,9 +103,9 @@ util::StatusCallbackLog callback_log; const ProvidedFileSystemInfo read_only_file_system_info( - kExtensionId, - MountOptions(kFileSystemId, "" /* display_name */), - base::FilePath() /* mount_path */); + kExtensionId, MountOptions(kFileSystemId, "" /* display_name */), + base::FilePath() /* mount_path */, false /* configurable */, + extensions::SOURCE_FILE); Truncate truncate(NULL, file_system_info_, base::FilePath(kFilePath), kTruncateLength,
diff --git a/chrome/browser/chromeos/file_system_provider/operations/unmount_unittest.cc b/chrome/browser/chromeos/file_system_provider/operations/unmount_unittest.cc index e53bda4..4ae1f94 100644 --- a/chrome/browser/chromeos/file_system_provider/operations/unmount_unittest.cc +++ b/chrome/browser/chromeos/file_system_provider/operations/unmount_unittest.cc
@@ -13,6 +13,7 @@ #include "chrome/browser/chromeos/file_system_provider/operations/test_util.h" #include "chrome/browser/chromeos/file_system_provider/provided_file_system_interface.h" #include "chrome/common/extensions/api/file_system_provider.h" +#include "chrome/common/extensions/api/file_system_provider_capabilities/file_system_provider_capabilities_handler.h" #include "chrome/common/extensions/api/file_system_provider_internal.h" #include "extensions/browser/event_router.h" #include "testing/gtest/include/gtest/gtest.h" @@ -35,9 +36,8 @@ void SetUp() override { file_system_info_ = ProvidedFileSystemInfo( - kExtensionId, - MountOptions(kFileSystemId, "" /* display_name */), - base::FilePath()); + kExtensionId, MountOptions(kFileSystemId, "" /* display_name */), + base::FilePath(), false /* configurable */, extensions::SOURCE_FILE); } ProvidedFileSystemInfo file_system_info_;
diff --git a/chrome/browser/chromeos/file_system_provider/operations/write_file_unittest.cc b/chrome/browser/chromeos/file_system_provider/operations/write_file_unittest.cc index f1aac0af..e6d576f 100644 --- a/chrome/browser/chromeos/file_system_provider/operations/write_file_unittest.cc +++ b/chrome/browser/chromeos/file_system_provider/operations/write_file_unittest.cc
@@ -16,6 +16,7 @@ #include "base/values.h" #include "chrome/browser/chromeos/file_system_provider/operations/test_util.h" #include "chrome/common/extensions/api/file_system_provider.h" +#include "chrome/common/extensions/api/file_system_provider_capabilities/file_system_provider_capabilities_handler.h" #include "chrome/common/extensions/api/file_system_provider_internal.h" #include "extensions/browser/event_router.h" #include "net/base/io_buffer.h" @@ -44,8 +45,9 @@ void SetUp() override { MountOptions mount_options(kFileSystemId, "" /* display_name */); mount_options.writable = true; - file_system_info_ = - ProvidedFileSystemInfo(kExtensionId, mount_options, base::FilePath()); + file_system_info_ = ProvidedFileSystemInfo( + kExtensionId, mount_options, base::FilePath(), false /* configurable */, + extensions::SOURCE_FILE); io_buffer_ = make_scoped_refptr(new net::StringIOBuffer(kWriteData)); } @@ -117,9 +119,9 @@ util::StatusCallbackLog callback_log; const ProvidedFileSystemInfo read_only_file_system_info( - kExtensionId, - MountOptions(kFileSystemId, "" /* display_name */), - base::FilePath() /* mount_path */); + kExtensionId, MountOptions(kFileSystemId, "" /* display_name */), + base::FilePath() /* mount_path */, false /* configurable */, + extensions::SOURCE_FILE); WriteFile write_file(NULL, read_only_file_system_info,
diff --git a/chrome/browser/chromeos/file_system_provider/provided_file_system_info.cc b/chrome/browser/chromeos/file_system_provider/provided_file_system_info.cc index db8d82d..a35c5c5 100644 --- a/chrome/browser/chromeos/file_system_provider/provided_file_system_info.cc +++ b/chrome/browser/chromeos/file_system_provider/provided_file_system_info.cc
@@ -3,6 +3,7 @@ // found in the LICENSE file. #include "chrome/browser/chromeos/file_system_provider/provided_file_system_info.h" + #include "base/logging.h" namespace chromeos { @@ -24,20 +25,27 @@ } ProvidedFileSystemInfo::ProvidedFileSystemInfo() - : writable_(false), supports_notify_tag_(false) { + : writable_(false), + supports_notify_tag_(false), + configurable_(false), + source_(extensions::SOURCE_FILE) { } ProvidedFileSystemInfo::ProvidedFileSystemInfo( const std::string& extension_id, const MountOptions& mount_options, - const base::FilePath& mount_path) + const base::FilePath& mount_path, + bool configurable, + extensions::FileSystemProviderSource source) : extension_id_(extension_id), file_system_id_(mount_options.file_system_id), display_name_(mount_options.display_name), writable_(mount_options.writable), supports_notify_tag_(mount_options.supports_notify_tag), opened_files_limit_(mount_options.opened_files_limit), - mount_path_(mount_path) { + mount_path_(mount_path), + configurable_(configurable), + source_(source) { DCHECK_LE(0, mount_options.opened_files_limit); }
diff --git a/chrome/browser/chromeos/file_system_provider/provided_file_system_info.h b/chrome/browser/chromeos/file_system_provider/provided_file_system_info.h index 795577ce..f2b51e6e 100644 --- a/chrome/browser/chromeos/file_system_provider/provided_file_system_info.h +++ b/chrome/browser/chromeos/file_system_provider/provided_file_system_info.h
@@ -8,6 +8,7 @@ #include <string> #include "base/files/file_path.h" +#include "chrome/common/extensions/api/file_system_provider_capabilities/file_system_provider_capabilities_handler.h" namespace chromeos { namespace file_system_provider { @@ -34,7 +35,9 @@ ProvidedFileSystemInfo(const std::string& extension_id, const MountOptions& mount_options, - const base::FilePath& mount_path); + const base::FilePath& mount_path, + bool configurable, + extensions::FileSystemProviderSource source); ~ProvidedFileSystemInfo(); @@ -45,6 +48,8 @@ bool supports_notify_tag() const { return supports_notify_tag_; } int opened_files_limit() const { return opened_files_limit_; } const base::FilePath& mount_path() const { return mount_path_; } + const bool configurable() const { return configurable_; } + extensions::FileSystemProviderSource source() const { return source_; } private: // ID of the extension providing this file system. @@ -67,6 +72,12 @@ // Mount path of the underlying file system. base::FilePath mount_path_; + + // Whether the file system is configurable. + bool configurable_; + + // Source of the file system's data. + extensions::FileSystemProviderSource source_; }; } // namespace file_system_provider
diff --git a/chrome/browser/chromeos/file_system_provider/provided_file_system_unittest.cc b/chrome/browser/chromeos/file_system_provider/provided_file_system_unittest.cc index 3c1f14b..2a4488f1 100644 --- a/chrome/browser/chromeos/file_system_provider/provided_file_system_unittest.cc +++ b/chrome/browser/chromeos/file_system_provider/provided_file_system_unittest.cc
@@ -22,6 +22,7 @@ #include "chrome/browser/chromeos/file_system_provider/request_manager.h" #include "chrome/browser/chromeos/file_system_provider/watcher.h" #include "chrome/common/extensions/api/file_system_provider.h" +#include "chrome/common/extensions/api/file_system_provider_capabilities/file_system_provider_capabilities_handler.h" #include "chrome/common/extensions/api/file_system_provider_internal.h" #include "chrome/test/base/testing_profile.h" #include "content/public/test/test_browser_thread_bundle.h" @@ -231,8 +232,9 @@ mount_options.display_name = kDisplayName; mount_options.supports_notify_tag = true; mount_options.writable = true; - file_system_info_.reset( - new ProvidedFileSystemInfo(kExtensionId, mount_options, mount_path)); + file_system_info_.reset(new ProvidedFileSystemInfo( + kExtensionId, mount_options, mount_path, false /* configurable */, + extensions::SOURCE_FILE)); provided_file_system_.reset( new ProvidedFileSystem(profile_.get(), *file_system_info_.get())); event_router_.reset( @@ -411,7 +413,8 @@ mount_options.display_name = kDisplayName; mount_options.supports_notify_tag = false; ProvidedFileSystemInfo file_system_info( - kExtensionId, mount_options, mount_path); + kExtensionId, mount_options, mount_path, false /* configurable */, + extensions::SOURCE_FILE); ProvidedFileSystem simple_provided_file_system(profile_.get(), file_system_info); simple_provided_file_system.SetEventRouterForTesting(event_router_.get());
diff --git a/chrome/browser/chromeos/file_system_provider/registry_unittest.cc b/chrome/browser/chromeos/file_system_provider/registry_unittest.cc index b02359f..a2c914d 100644 --- a/chrome/browser/chromeos/file_system_provider/registry_unittest.cc +++ b/chrome/browser/chromeos/file_system_provider/registry_unittest.cc
@@ -10,6 +10,7 @@ #include "base/files/file_path.h" #include "base/memory/scoped_ptr.h" #include "chrome/browser/chromeos/file_system_provider/provided_file_system_info.h" +#include "chrome/common/extensions/api/file_system_provider_capabilities/file_system_provider_capabilities_handler.h" #include "chrome/common/pref_names.h" #include "chrome/test/base/testing_browser_process.h" #include "chrome/test/base/testing_pref_service_syncable.h" @@ -157,7 +158,8 @@ options.opened_files_limit = kOpenedFilesLimit; ProvidedFileSystemInfo file_system_info( - kExtensionId, options, base::FilePath(FILE_PATH_LITERAL("/a/b/c"))); + kExtensionId, options, base::FilePath(FILE_PATH_LITERAL("/a/b/c")), + false /* configurable */, extensions::SOURCE_FILE); Watchers watchers; watchers[WatcherKey(fake_watcher_.entry_path, fake_watcher_.recursive)] = @@ -272,7 +274,8 @@ options.supports_notify_tag = true; ProvidedFileSystemInfo file_system_info( - kExtensionId, options, base::FilePath(FILE_PATH_LITERAL("/a/b/c"))); + kExtensionId, options, base::FilePath(FILE_PATH_LITERAL("/a/b/c")), + false /* configurable */, extensions::SOURCE_FILE); Watchers watchers; watchers[WatcherKey(fake_watcher_.entry_path, fake_watcher_.recursive)] =
diff --git a/chrome/browser/chromeos/file_system_provider/service.cc b/chrome/browser/chromeos/file_system_provider/service.cc index 94ef49dd..faa6ce5c 100644 --- a/chrome/browser/chromeos/file_system_provider/service.cc +++ b/chrome/browser/chromeos/file_system_provider/service.cc
@@ -160,6 +160,9 @@ return base::File::FILE_ERROR_INVALID_OPERATION; } + ProvidingExtensionInfo provider_info; + // TODO(mtomasz): Set up a testing extension in unit tests. + GetProvidingExtensionInfo(extension_id, &provider_info); // Store the file system descriptor. Use the mount point name as the file // system provider file system id. // Examples: @@ -168,7 +171,12 @@ // writable = false // supports_notify_tag = false // mount_path = /provided/b33f1337-hello_world-5aa5 - ProvidedFileSystemInfo file_system_info(extension_id, options, mount_path); + // configurable = true + // source = SOURCE_FILE + ProvidedFileSystemInfo file_system_info( + extension_id, options, mount_path, + provider_info.capabilities.configurable(), + provider_info.capabilities.source()); ProvidedFileSystemInterface* file_system = file_system_factory_.Run(profile_, file_system_info); @@ -310,24 +318,39 @@ std::vector<ProvidingExtensionInfo> result; for (const auto& extension : registry->enabled_extensions()) { - if (!extension->permissions_data()->HasAPIPermission( - extensions::APIPermission::kFileSystemProvider)) { - continue; - } - ProvidingExtensionInfo info; - info.extension_id = extension->id(); - info.name = extension->name(); - const extensions::FileSystemProviderCapabilities* const capabilities = - extensions::FileSystemProviderCapabilities::Get(extension.get()); - DCHECK(capabilities); - info.capabilities = *capabilities; - result.push_back(info); + if (GetProvidingExtensionInfo(extension->id(), &info)) + result.push_back(info); } return result; } +bool Service::GetProvidingExtensionInfo(const std::string& extension_id, + ProvidingExtensionInfo* result) const { + DCHECK(result); + extensions::ExtensionRegistry* const registry = + extensions::ExtensionRegistry::Get(profile_); + DCHECK(registry); + + const extensions::Extension* const extension = registry->GetExtensionById( + extension_id, extensions::ExtensionRegistry::ENABLED); + if (!extension || + !extension->permissions_data()->HasAPIPermission( + extensions::APIPermission::kFileSystemProvider)) { + return false; + } + + result->extension_id = extension->id(); + result->name = extension->name(); + const extensions::FileSystemProviderCapabilities* const capabilities = + extensions::FileSystemProviderCapabilities::Get(extension); + DCHECK(capabilities); + result->capabilities = *capabilities; + + return true; +} + void Service::OnExtensionUnloaded( content::BrowserContext* browser_context, const extensions::Extension* extension,
diff --git a/chrome/browser/chromeos/file_system_provider/service.h b/chrome/browser/chromeos/file_system_provider/service.h index 54d6bf3..d072bd9 100644 --- a/chrome/browser/chromeos/file_system_provider/service.h +++ b/chrome/browser/chromeos/file_system_provider/service.h
@@ -133,6 +133,12 @@ // extensions. std::vector<ProvidingExtensionInfo> GetProvidingExtensionInfoList() const; + // Fills information of the specified providing extension and returns true. + // If the extension is not a provider, or it doesn't exist, then false is + // returned. + bool GetProvidingExtensionInfo(const std::string& extension_id, + ProvidingExtensionInfo* result) const; + // Adds and removes observers. void AddObserver(Observer* observer); void RemoveObserver(Observer* observer);
diff --git a/chrome/browser/chromeos/file_system_provider/service_unittest.cc b/chrome/browser/chromeos/file_system_provider/service_unittest.cc index ccee9c36..db7c33d 100644 --- a/chrome/browser/chromeos/file_system_provider/service_unittest.cc +++ b/chrome/browser/chromeos/file_system_provider/service_unittest.cc
@@ -18,6 +18,7 @@ #include "chrome/browser/chromeos/file_system_provider/registry_interface.h" #include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h" #include "chrome/browser/chromeos/login/users/scoped_user_manager_enabler.h" +#include "chrome/common/extensions/api/file_system_provider_capabilities/file_system_provider_capabilities_handler.h" #include "chrome/test/base/testing_browser_process.h" #include "chrome/test/base/testing_pref_service_syncable.h" #include "chrome/test/base/testing_profile.h" @@ -415,7 +416,8 @@ MountOptions options(kFileSystemId, kDisplayName); options.supports_notify_tag = true; ProvidedFileSystemInfo file_system_info( - kExtensionId, options, base::FilePath(FILE_PATH_LITERAL("/a/b/c"))); + kExtensionId, options, base::FilePath(FILE_PATH_LITERAL("/a/b/c")), + false /* configurable */, extensions::SOURCE_FILE); Watchers fake_watchers; fake_watchers[WatcherKey(fake_watcher_.entry_path, fake_watcher_.recursive)] = fake_watcher_;
diff --git a/chrome/browser/chromeos/file_system_provider/throttled_file_system_unittest.cc b/chrome/browser/chromeos/file_system_provider/throttled_file_system_unittest.cc index 5b65a75a..d9333085 100644 --- a/chrome/browser/chromeos/file_system_provider/throttled_file_system_unittest.cc +++ b/chrome/browser/chromeos/file_system_provider/throttled_file_system_unittest.cc
@@ -13,6 +13,7 @@ #include "chrome/browser/chromeos/file_system_provider/abort_callback.h" #include "chrome/browser/chromeos/file_system_provider/fake_provided_file_system.h" #include "chrome/browser/chromeos/file_system_provider/provided_file_system_info.h" +#include "chrome/common/extensions/api/file_system_provider_capabilities/file_system_provider_capabilities_handler.h" #include "content/public/test/test_browser_thread_bundle.h" #include "testing/gtest/include/gtest/gtest.h" @@ -52,8 +53,9 @@ MountOptions options(kFileSystemId, kDisplayName); options.opened_files_limit = limit; - ProvidedFileSystemInfo file_system_info(kExtensionId, options, - base::FilePath() /* mount_path */); + ProvidedFileSystemInfo file_system_info( + kExtensionId, options, base::FilePath() /* mount_path */, + false /* configurable */, extensions::SOURCE_FILE); file_system_.reset(new ThrottledFileSystem( make_scoped_ptr(new FakeProvidedFileSystem(file_system_info))));
diff --git a/chrome/browser/chromeos/first_run/first_run.cc b/chrome/browser/chromeos/first_run/first_run.cc index 27b94fa..81c860d 100644 --- a/chrome/browser/chromeos/first_run/first_run.cc +++ b/chrome/browser/chromeos/first_run/first_run.cc
@@ -10,6 +10,7 @@ #include "chrome/browser/chromeos/first_run/first_run_controller.h" #include "chrome/browser/chromeos/profiles/profile_helper.h" #include "chrome/browser/extensions/extension_service.h" +#include "chrome/browser/prefs/pref_service_syncable.h" #include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/ui/extensions/app_launch_params.h" #include "chrome/browser/ui/extensions/application_launch.h" @@ -76,8 +77,13 @@ bool first_run_forced = command_line->HasSwitch(switches::kForceFirstRunUI); bool first_run_seen = profile_->GetPrefs()->GetBoolean(prefs::kFirstRunTutorialShown); + bool is_pref_synced = + PrefServiceSyncable::FromProfile(profile_)->IsPrioritySyncing(); + bool is_user_ephemeral = user_manager::UserManager::Get() + ->IsCurrentUserNonCryptohomeDataEphemeral(); if (!launched_in_telemetry && - ((is_user_new && !first_run_seen && !launched_in_test) || + ((is_user_new && !first_run_seen && + (is_pref_synced || !is_user_ephemeral) && !launched_in_test) || first_run_forced)) { LaunchDialogForProfile(profile_); }
diff --git a/chrome/browser/chromeos/login/existing_user_controller.cc b/chrome/browser/chromeos/login/existing_user_controller.cc index e9367efc..9866456 100644 --- a/chrome/browser/chromeos/login/existing_user_controller.cc +++ b/chrome/browser/chromeos/login/existing_user_controller.cc
@@ -44,6 +44,7 @@ #include "chrome/browser/chromeos/profiles/profile_helper.h" #include "chrome/browser/chromeos/settings/cros_settings.h" #include "chrome/browser/chromeos/system/device_disabling_manager.h" +#include "chrome/browser/signin/chrome_signin_client.h" #include "chrome/browser/signin/easy_unlock_service.h" #include "chrome/browser/ui/aura/accessibility/automation_manager_aura.h" #include "chrome/browser/ui/webui/chromeos/login/l10n_util.h" @@ -1119,7 +1120,20 @@ continuation.Run(); } -void ExistingUserController::DoCompleteLogin(const UserContext& user_context) { +void ExistingUserController::DoCompleteLogin( + const UserContext& user_context_wo_device_id) { + UserContext user_context = user_context_wo_device_id; + std::string device_id = + user_manager::UserManager::Get()->GetKnownUserDeviceId( + user_context.GetUserID()); + if (device_id.empty()) { + bool is_ephemeral = + ChromeUserManager::Get()->AreEphemeralUsersEnabled() && + user_context.GetUserID() != ChromeUserManager::Get()->GetOwnerEmail(); + device_id = ChromeSigninClient::GenerateSigninScopedDeviceID(is_ephemeral); + } + user_context.SetDeviceId(device_id); + PerformPreLoginActions(user_context); if (!time_init_.is_null()) { @@ -1236,38 +1250,8 @@ OnAuthFailure(AuthFailure(AuthFailure::FAILED_TO_INITIALIZE_TOKEN)); return; } - if (StartupUtils::IsWebviewSigninEnabled() && TokenHandlesEnabled()) { - if (!token_handle_util_.get()) { - token_handle_util_.reset( - new TokenHandleUtil(user_manager::UserManager::Get())); - } - if (token_handle_util_->ShouldObtainHandle(user_context.GetUserID())) { - token_handle_util_->GetTokenHandle( - user_context.GetUserID(), user_context.GetAccessToken(), - base::Bind(&ExistingUserController::OnTokenHandleObtained, - weak_factory_.GetWeakPtr())); - } - } + UserSessionManager::GetInstance()->OnOAuth2TokensFetched(user_context); PerformLogin(user_context, LoginPerformer::AUTH_MODE_EXTENSION); } -void ExistingUserController::OnTokenHandleObtained( - const user_manager::UserID& id, - TokenHandleUtil::TokenHandleStatus status) { - if (status != TokenHandleUtil::VALID) { - LOG(ERROR) << "OAuth2 token handle fetch failed."; - return; - } -} - -bool ExistingUserController::TokenHandlesEnabled() { - bool ephemeral_users_enabled = false; - bool show_names_on_signin = true; - cros_settings_->GetBoolean(kAccountsPrefEphemeralUsersEnabled, - &ephemeral_users_enabled); - cros_settings_->GetBoolean(kAccountsPrefShowUserNamesOnSignIn, - &show_names_on_signin); - return show_names_on_signin && !ephemeral_users_enabled; -} - } // namespace chromeos
diff --git a/chrome/browser/chromeos/login/existing_user_controller.h b/chrome/browser/chromeos/login/existing_user_controller.h index eea1471d..0eb01b89 100644 --- a/chrome/browser/chromeos/login/existing_user_controller.h +++ b/chrome/browser/chromeos/login/existing_user_controller.h
@@ -18,7 +18,6 @@ #include "base/timer/timer.h" #include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h" #include "chrome/browser/chromeos/login/session/user_session_manager.h" -#include "chrome/browser/chromeos/login/signin/token_handle_util.h" #include "chrome/browser/chromeos/login/ui/login_display.h" #include "chrome/browser/chromeos/settings/cros_settings.h" #include "chrome/browser/chromeos/settings/device_settings_service.h" @@ -243,13 +242,6 @@ // Callback invoked when |oauth2_token_initializer_| has finished. void OnOAuth2TokensFetched(bool success, const UserContext& user_context); - // Callback invoked when |token_handle_util_| has finished. - void OnTokenHandleObtained(const user_manager::UserID& id, - TokenHandleUtil::TokenHandleStatus status); - - // Returns |true| if token handles should be used on this device. - bool TokenHandlesEnabled(); - // Public session auto-login timer. scoped_ptr<base::OneShotTimer<ExistingUserController> > auto_login_timer_; @@ -338,7 +330,6 @@ bootstrap_user_context_initializer_; scoped_ptr<OAuth2TokenInitializer> oauth2_token_initializer_; - scoped_ptr<TokenHandleUtil> token_handle_util_; FRIEND_TEST_ALL_PREFIXES(ExistingUserControllerTest, ExistingUserLogin);
diff --git a/chrome/browser/chromeos/login/screens/user_image_screen.cc b/chrome/browser/chromeos/login/screens/user_image_screen.cc index f450f9e..7805543 100644 --- a/chrome/browser/chromeos/login/screens/user_image_screen.cc +++ b/chrome/browser/chromeos/login/screens/user_image_screen.cc
@@ -109,6 +109,11 @@ } void UserImageScreen::HideCurtain() { + // Skip user image selection for ephemeral users. + if (user_manager::UserManager::Get()->IsUserNonCryptohomeDataEphemeral( + GetUser()->GetUserID())) { + ExitScreen(); + } if (view_) view_->HideCurtain(); } @@ -125,6 +130,7 @@ void UserImageScreen::OnInitialSync(bool local_image_updated) { DCHECK(sync_timer_); + ReportSyncResult(SyncResult::SUCCEEDED); if (!local_image_updated) { sync_timer_.reset(); GetSyncObserver()->RemoveObserver(this); @@ -136,6 +142,7 @@ } void UserImageScreen::OnSyncTimeout() { + ReportSyncResult(SyncResult::TIMED_OUT); sync_timer_.reset(); GetSyncObserver()->RemoveObserver(this); if (is_screen_ready_) @@ -261,8 +268,10 @@ if (GetUser()->CanSyncImage()) { if (UserImageSyncObserver* sync_observer = GetSyncObserver()) { + sync_waiting_start_time_ = base::Time::Now(); // We have synced image already. if (sync_observer->is_synced()) { + ReportSyncResult(SyncResult::SUCCEEDED); ExitScreen(); return; } @@ -342,4 +351,12 @@ Finish(BaseScreenDelegate::USER_IMAGE_SELECTED); } +void UserImageScreen::ReportSyncResult(SyncResult timed_out) const { + base::TimeDelta duration = base::Time::Now() - sync_waiting_start_time_; + UMA_HISTOGRAM_TIMES("Login.NewUserPriorityPrefsSyncTime", duration); + UMA_HISTOGRAM_ENUMERATION("Login.NewUserPriorityPrefsSyncResult", + static_cast<int>(timed_out), + static_cast<int>(SyncResult::COUNT)); +} + } // namespace chromeos
diff --git a/chrome/browser/chromeos/login/screens/user_image_screen.h b/chrome/browser/chromeos/login/screens/user_image_screen.h index 8afe9c29..5050f99 100644 --- a/chrome/browser/chromeos/login/screens/user_image_screen.h +++ b/chrome/browser/chromeos/login/screens/user_image_screen.h
@@ -7,6 +7,7 @@ #include "base/compiler_specific.h" #include "base/memory/scoped_ptr.h" +#include "base/time/time.h" #include "chrome/browser/chromeos/camera_presence_notifier.h" #include "chrome/browser/chromeos/login/screens/base_screen.h" #include "chrome/browser/chromeos/login/screens/user_image_model.h" @@ -75,6 +76,15 @@ bool user_selected_image() const { return user_has_selected_image_; } private: + // Must be kept synced with |NewUserPriorityPrefsSyncResult| enum from + // histograms.xml. + enum class SyncResult { + SUCCEEDED, + TIMED_OUT, + // Keeps a number of different sync results. Should be the last in the list. + COUNT + }; + // Called when whaiting for sync timed out. void OnSyncTimeout(); @@ -101,6 +111,9 @@ // Closes the screen. void ExitScreen(); + // Reports sync duration and result to UMA. + void ReportSyncResult(SyncResult timed_out) const; + content::NotificationRegistrar notification_registrar_; scoped_ptr<policy::PolicyChangeRegistrar> policy_registrar_; @@ -127,6 +140,9 @@ // True if user has explicitly selected some image. bool user_has_selected_image_; + // The time when we started wait for user image sync. + base::Time sync_waiting_start_time_; + DISALLOW_COPY_AND_ASSIGN(UserImageScreen); };
diff --git a/chrome/browser/chromeos/login/session/user_session_manager.cc b/chrome/browser/chromeos/login/session/user_session_manager.cc index edecf3a..a07149b 100644 --- a/chrome/browser/chromeos/login/session/user_session_manager.cc +++ b/chrome/browser/chromeos/login/session/user_session_manager.cc
@@ -423,6 +423,12 @@ // TODO(nkostylev): Notify UserLoggedIn() after profile is actually // ready to be used (http://crbug.com/361528). NotifyUserLoggedIn(); + + if (!user_context.GetDeviceId().empty()) { + user_manager::UserManager::Get()->SetKnownUserDeviceId( + user_context.GetUserID(), user_context.GetDeviceId()); + } + PrepareProfile(); } @@ -896,20 +902,6 @@ ChromeUserManager::Get()->SetIsCurrentUserNew(true); } - std::string device_id = profile->GetPrefs()->GetString( - prefs::kGoogleServicesSigninScopedDeviceId); - if (device_id.empty()) { - device_id = user_context.GetDeviceId(); - if (!device_id.empty()) { - profile->GetPrefs()->SetString(prefs::kGoogleServicesSigninScopedDeviceId, - device_id); - } - } - if (!device_id.empty()) { - user_manager::UserManager::Get()->SetKnownUserDeviceId(user->GetUserID(), - device_id); - } - if (user->is_active()) { input_method::InputMethodManager* manager = input_method::InputMethodManager::Get(); @@ -1121,10 +1113,8 @@ user_manager::UserManager* user_manager = user_manager::UserManager::Get(); - bool can_show_getstarted_guide = - user_manager->GetActiveUser()->GetType() == - user_manager::USER_TYPE_REGULAR && - !user_manager->IsCurrentUserNonCryptohomeDataEphemeral(); + bool can_show_getstarted_guide = user_manager->GetActiveUser()->GetType() == + user_manager::USER_TYPE_REGULAR; // Skip the default first-run behavior for public accounts. if (!user_manager->IsLoggedInAsPublicAccount()) { @@ -1672,4 +1662,43 @@ NUM_USER_PODS_DISPLAY); } +void UserSessionManager::OnOAuth2TokensFetched(UserContext context) { + if (StartupUtils::IsWebviewSigninEnabled() && TokenHandlesEnabled()) { + if (!token_handle_util_.get()) { + token_handle_util_.reset( + new TokenHandleUtil(user_manager::UserManager::Get())); + } + if (token_handle_util_->ShouldObtainHandle(context.GetUserID())) { + token_handle_util_->GetTokenHandle( + context.GetUserID(), context.GetAccessToken(), + base::Bind(&UserSessionManager::OnTokenHandleObtained, + weak_factory_.GetWeakPtr())); + } + } +} + +void UserSessionManager::OnTokenHandleObtained( + const user_manager::UserID& id, + TokenHandleUtil::TokenHandleStatus status) { + if (status != TokenHandleUtil::VALID) { + LOG(ERROR) << "OAuth2 token handle fetch failed."; + return; + } +} + +bool UserSessionManager::TokenHandlesEnabled() { + bool ephemeral_users_enabled = false; + bool show_names_on_signin = true; + auto cros_settings = CrosSettings::Get(); + cros_settings->GetBoolean(kAccountsPrefEphemeralUsersEnabled, + &ephemeral_users_enabled); + cros_settings->GetBoolean(kAccountsPrefShowUserNamesOnSignIn, + &show_names_on_signin); + return show_names_on_signin && !ephemeral_users_enabled; +} + +void UserSessionManager::Shutdown() { + token_handle_util_.reset(); +} + } // namespace chromeos
diff --git a/chrome/browser/chromeos/login/session/user_session_manager.h b/chrome/browser/chromeos/login/session/user_session_manager.h index b86b2034..b1e7466 100644 --- a/chrome/browser/chromeos/login/session/user_session_manager.h +++ b/chrome/browser/chromeos/login/session/user_session_manager.h
@@ -15,6 +15,7 @@ #include "base/observer_list.h" #include "chrome/browser/chromeos/base/locale_util.h" #include "chrome/browser/chromeos/login/signin/oauth2_login_manager.h" +#include "chrome/browser/chromeos/login/signin/token_handle_util.h" #include "chromeos/dbus/session_manager_client.h" #include "chromeos/login/auth/authenticator.h" #include "chromeos/login/auth/user_context.h" @@ -218,6 +219,9 @@ void ActiveUserChanged(const user_manager::User* active_user) override; + // This method will be called when user have obtained oauth2 tokens. + void OnOAuth2TokensFetched(UserContext context); + // Returns default IME state for user session. scoped_refptr<input_method::InputMethodManager::State> GetDefaultIMEState( Profile* profile); @@ -237,6 +241,8 @@ const UserContext& user_context() const { return user_context_; } bool has_auth_cookies() const { return has_auth_cookies_; } + void Shutdown(); + private: friend class test::UserSessionManagerTestApi; friend struct DefaultSingletonTraits<UserSessionManager>; @@ -360,6 +366,13 @@ InputEventsBlocker* input_events_blocker, const locale_util::LanguageSwitchResult& result); + // Callback invoked when |token_handle_util_| has finished. + void OnTokenHandleObtained(const user_manager::UserID& id, + TokenHandleUtil::TokenHandleStatus status); + + // Returns |true| if token handles should be used on this device. + bool TokenHandlesEnabled(); + // Test API methods. // Injects |user_context| that will be used to create StubAuthenticator @@ -444,6 +457,8 @@ bool running_easy_unlock_key_ops_; base::Closure easy_unlock_key_ops_finished_callback_; + scoped_ptr<TokenHandleUtil> token_handle_util_; + // Whether should launch browser, tests may override this value. bool should_launch_browser_;
diff --git a/chrome/browser/chromeos/login/signin/oauth2_token_fetcher.cc b/chrome/browser/chromeos/login/signin/oauth2_token_fetcher.cc index b898018f..c98f7905f 100644 --- a/chrome/browser/chromeos/login/signin/oauth2_token_fetcher.cc +++ b/chrome/browser/chromeos/login/signin/oauth2_token_fetcher.cc
@@ -68,9 +68,11 @@ } void OAuth2TokenFetcher::StartExchangeFromAuthCode( - const std::string& auth_code) { + const std::string& auth_code, + const std::string& signin_scoped_device_id) { DCHECK_CURRENTLY_ON(BrowserThread::UI); auth_code_ = auth_code; + signin_scoped_device_id_ = signin_scoped_device_id; // Delay the verification if the network is not connected or on a captive // portal. const NetworkState* default_network = @@ -81,13 +83,13 @@ VLOG(1) << "Network is offline. Deferring OAuth2 token fetch."; BrowserThread::PostDelayedTask( BrowserThread::UI, FROM_HERE, - base::Bind(&OAuth2TokenFetcher::StartExchangeFromAuthCode, - AsWeakPtr(), - auth_code), + base::Bind(&OAuth2TokenFetcher::StartExchangeFromAuthCode, AsWeakPtr(), + auth_code, signin_scoped_device_id), base::TimeDelta::FromMilliseconds(kRequestRestartDelay)); return; } - auth_fetcher_.StartAuthCodeForOAuth2TokenExchange(auth_code); + auth_fetcher_.StartAuthCodeForOAuth2TokenExchangeWithDeviceId( + auth_code, signin_scoped_device_id); } void OAuth2TokenFetcher::OnClientOAuthSuccess( @@ -102,17 +104,15 @@ void OAuth2TokenFetcher::OnClientOAuthFailure( const GoogleServiceAuthError& error) { DCHECK_CURRENTLY_ON(BrowserThread::UI); - RetryOnError(error, - auth_code_.empty() - ? base::Bind(&OAuth2TokenFetcher::StartExchangeFromCookies, - AsWeakPtr(), - session_index_, - signin_scoped_device_id_) - : base::Bind(&OAuth2TokenFetcher::StartExchangeFromAuthCode, - AsWeakPtr(), - auth_code_), - base::Bind(&Delegate::OnOAuth2TokensFetchFailed, - base::Unretained(delegate_))); + RetryOnError( + error, + auth_code_.empty() + ? base::Bind(&OAuth2TokenFetcher::StartExchangeFromCookies, + AsWeakPtr(), session_index_, signin_scoped_device_id_) + : base::Bind(&OAuth2TokenFetcher::StartExchangeFromAuthCode, + AsWeakPtr(), auth_code_, signin_scoped_device_id_), + base::Bind(&Delegate::OnOAuth2TokensFetchFailed, + base::Unretained(delegate_))); } void OAuth2TokenFetcher::RetryOnError(const GoogleServiceAuthError& error,
diff --git a/chrome/browser/chromeos/login/signin/oauth2_token_fetcher.h b/chrome/browser/chromeos/login/signin/oauth2_token_fetcher.h index 5dd2e6d7..3cea28b8f 100644 --- a/chrome/browser/chromeos/login/signin/oauth2_token_fetcher.h +++ b/chrome/browser/chromeos/login/signin/oauth2_token_fetcher.h
@@ -40,7 +40,8 @@ void StartExchangeFromCookies(const std::string& session_index, const std::string& signin_scoped_device_id); - void StartExchangeFromAuthCode(const std::string& auth_code); + void StartExchangeFromAuthCode(const std::string& auth_code, + const std::string& signin_scoped_device_id); private: // Decides how to proceed on GAIA |error|. If the error looks temporary,
diff --git a/chrome/browser/chromeos/login/signin/oauth2_token_initializer.cc b/chrome/browser/chromeos/login/signin/oauth2_token_initializer.cc index c0bcbc9..953c5d5 100644 --- a/chrome/browser/chromeos/login/signin/oauth2_token_initializer.cc +++ b/chrome/browser/chromeos/login/signin/oauth2_token_initializer.cc
@@ -21,7 +21,10 @@ user_context_ = user_context; oauth2_token_fetcher_.reset(new OAuth2TokenFetcher( this, g_browser_process->system_request_context())); - oauth2_token_fetcher_->StartExchangeFromAuthCode(user_context.GetAuthCode()); + if (user_context.GetDeviceId().empty()) + NOTREACHED() << "Device ID is not set"; + oauth2_token_fetcher_->StartExchangeFromAuthCode(user_context.GetAuthCode(), + user_context.GetDeviceId()); } void OAuth2TokenInitializer::OnOAuth2TokensAvailable(
diff --git a/chrome/browser/chromeos/login/users/avatar/user_image_manager_browsertest.cc b/chrome/browser/chromeos/login/users/avatar/user_image_manager_browsertest.cc index b3542385..63cab01 100644 --- a/chrome/browser/chromeos/login/users/avatar/user_image_manager_browsertest.cc +++ b/chrome/browser/chromeos/login/users/avatar/user_image_manager_browsertest.cc
@@ -656,10 +656,12 @@ ADD_FAILURE(); } std::string policy; - base::JSONWriter::Write(policy::test::ConstructExternalDataReference( - embedded_test_server()->GetURL(std::string("/") + relative_path).spec(), - image_data).get(), - &policy); + base::JSONWriter::Write(*policy::test::ConstructExternalDataReference( + embedded_test_server() + ->GetURL(std::string("/") + relative_path) + .spec(), + image_data), + &policy); return policy; }
diff --git a/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager_policy_browsertest.cc b/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager_policy_browsertest.cc index 576d9f3c..8455a40e 100644 --- a/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager_policy_browsertest.cc +++ b/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager_policy_browsertest.cc
@@ -220,10 +220,12 @@ ADD_FAILURE(); } std::string policy; - base::JSONWriter::Write(policy::test::ConstructExternalDataReference( - embedded_test_server()->GetURL(std::string("/") + relative_path).spec(), - image_data).get(), - &policy); + base::JSONWriter::Write(*policy::test::ConstructExternalDataReference( + embedded_test_server() + ->GetURL(std::string("/") + relative_path) + .spec(), + image_data), + &policy); return policy; }
diff --git a/chrome/browser/chromeos/login/wizard_controller.cc b/chrome/browser/chromeos/login/wizard_controller.cc index 493fabb..2677dc9 100644 --- a/chrome/browser/chromeos/login/wizard_controller.cc +++ b/chrome/browser/chromeos/login/wizard_controller.cc
@@ -401,9 +401,12 @@ void WizardController::ShowUserImageScreen() { const user_manager::UserManager* user_manager = user_manager::UserManager::Get(); - // Skip user image selection for public sessions and ephemeral logins. + // Skip user image selection for public sessions and ephemeral non-regual user + // logins. if (user_manager->IsLoggedInAsPublicAccount() || - user_manager->IsCurrentUserNonCryptohomeDataEphemeral()) { + (user_manager->IsCurrentUserNonCryptohomeDataEphemeral() && + user_manager->GetLoggedInUser()->GetType() != + user_manager::USER_TYPE_REGULAR)) { OnUserImageSkipped(); return; }
diff --git a/chrome/browser/chromeos/net/onc_utils.cc b/chrome/browser/chromeos/net/onc_utils.cc index abcd08a3..2e4194eb 100644 --- a/chrome/browser/chromeos/net/onc_utils.cc +++ b/chrome/browser/chromeos/net/onc_utils.cc
@@ -228,7 +228,7 @@ base::DictionaryValue ui_data_dict; ui_data->FillDictionary(&ui_data_dict); std::string ui_data_json; - base::JSONWriter::Write(&ui_data_dict, &ui_data_json); + base::JSONWriter::Write(ui_data_dict, &ui_data_json); shill_dict->SetStringWithoutPathExpansion(shill::kUIDataProperty, ui_data_json);
diff --git a/chrome/browser/chromeos/net/proxy_config_handler.cc b/chrome/browser/chromeos/net/proxy_config_handler.cc index 4fa3d662..0351f34 100644 --- a/chrome/browser/chromeos/net/proxy_config_handler.cc +++ b/chrome/browser/chromeos/net/proxy_config_handler.cc
@@ -112,7 +112,7 @@ network_handler::ErrorCallback())); } else { std::string proxy_config_str; - base::JSONWriter::Write(&proxy_config.GetDictionary(), &proxy_config_str); + base::JSONWriter::Write(proxy_config.GetDictionary(), &proxy_config_str); shill_service_client->SetProperty( dbus::ObjectPath(network.path()), shill::kProxyConfigProperty,
diff --git a/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.cc b/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.cc index 8e1cff3d..6058ba9 100644 --- a/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.cc +++ b/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.cc
@@ -28,6 +28,7 @@ #include "chrome/browser/chromeos/policy/device_network_configuration_updater.h" #include "chrome/browser/chromeos/policy/enrollment_config.h" #include "chrome/browser/chromeos/policy/enterprise_install_attributes.h" +#include "chrome/browser/chromeos/policy/remote_commands/affiliated_remote_commands_invalidator.h" #include "chrome/browser/chromeos/policy/server_backed_state_keys_broker.h" #include "chrome/browser/chromeos/settings/cros_settings.h" #include "chrome/browser/chromeos/settings/device_settings_service.h" @@ -198,6 +199,10 @@ enterprise_management::DeviceRegisterRequest::DEVICE, device_cloud_policy_manager_->core(), affiliated_invalidation_service_provider_.get())); + device_remote_commands_invalidator_.reset( + new AffiliatedRemoteCommandsInvalidator( + device_cloud_policy_manager_->core(), + affiliated_invalidation_service_provider_.get())); } SetTimezoneIfPolicyAvailable();
diff --git a/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h b/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h index 347a4e3..fe342d8c 100644 --- a/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h +++ b/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h
@@ -24,10 +24,11 @@ namespace policy { +class AffiliatedCloudPolicyInvalidator; class AffiliatedInvalidationServiceProvider; +class AffiliatedRemoteCommandsInvalidator; class ConsumerManagementService; class DeviceCloudPolicyInitializer; -class AffiliatedCloudPolicyInvalidator; class DeviceLocalAccountPolicyService; class DeviceManagementService; struct EnrollmentConfig; @@ -164,6 +165,8 @@ scoped_ptr<DeviceLocalAccountPolicyService> device_local_account_policy_service_; scoped_ptr<AffiliatedCloudPolicyInvalidator> device_cloud_policy_invalidator_; + scoped_ptr<AffiliatedRemoteCommandsInvalidator> + device_remote_commands_invalidator_; // This policy provider is used on Chrome OS to feed user policy into the // global PolicyService instance. This works by installing the cloud policy
diff --git a/chrome/browser/chromeos/policy/cloud_external_data_policy_observer_unittest.cc b/chrome/browser/chromeos/policy/cloud_external_data_policy_observer_unittest.cc index 292507f5..aa26956 100644 --- a/chrome/browser/chromeos/policy/cloud_external_data_policy_observer_unittest.cc +++ b/chrome/browser/chromeos/policy/cloud_external_data_policy_observer_unittest.cc
@@ -82,8 +82,7 @@ test_data_dir.Append("chromeos").Append(file_name), policy_data)); base::JSONWriter::Write( - test::ConstructExternalDataReference(url, *policy_data).get(), - policy); + *test::ConstructExternalDataReference(url, *policy_data), policy); } } // namespace
diff --git a/chrome/browser/chromeos/policy/configuration_policy_handler_chromeos.cc b/chrome/browser/chromeos/policy/configuration_policy_handler_chromeos.cc index 6530914c..f62b6c3 100644 --- a/chrome/browser/chromeos/policy/configuration_policy_handler_chromeos.cc +++ b/chrome/browser/chromeos/policy/configuration_policy_handler_chromeos.cc
@@ -298,9 +298,8 @@ *toplevel_dict, kPlaceholder); - base::JSONWriter::WriteWithOptions(toplevel_dict.get(), - base::JSONWriter::OPTIONS_PRETTY_PRINT, - &json_string); + base::JSONWriter::WriteWithOptions( + *toplevel_dict, base::JSONWriter::OPTIONS_PRETTY_PRINT, &json_string); return new base::StringValue(json_string); }
diff --git a/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.h b/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.h index 2035c5e..33f11a84 100644 --- a/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.h +++ b/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.h
@@ -105,7 +105,9 @@ return device_store_.get(); } - bool HasStatusUploaderForTest() { return status_uploader_; } + // Return the StatusUploader used to communicate device status to the + // policy server. + StatusUploader* GetStatusUploader() const { return status_uploader_.get(); } private: // Saves the state keys received from |session_manager_client_|.
diff --git a/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos_unittest.cc b/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos_unittest.cc index dae7074dd..b3f626eb 100644 --- a/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos_unittest.cc +++ b/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos_unittest.cc
@@ -262,7 +262,7 @@ Mock::VerifyAndClearExpectations(&device_management_service_); ASSERT_TRUE(policy_fetch_job); // Should create a status uploader for reporting on enrolled devices. - EXPECT_TRUE(manager_->HasStatusUploaderForTest()); + EXPECT_TRUE(manager_->GetStatusUploader()); VerifyPolicyPopulated(); manager_->Shutdown(); @@ -301,7 +301,7 @@ ASSERT_TRUE(policy_fetch_job); // Should create a status provider for reporting on enrolled devices, even // those that aren't managed. - EXPECT_TRUE(manager_->HasStatusUploaderForTest()); + EXPECT_TRUE(manager_->GetStatusUploader()); // Switch back to ACTIVE, service the policy fetch and let it propagate. device_policy_.policy_data().set_state(em::PolicyData::ACTIVE); @@ -329,7 +329,7 @@ ConnectManager(); EXPECT_TRUE(manager_->policies().Equals(bundle)); // Should not create a status provider for reporting on consumer devices. - EXPECT_FALSE(manager_->HasStatusUploaderForTest()); + EXPECT_FALSE(manager_->GetStatusUploader()); manager_->Shutdown(); EXPECT_TRUE(manager_->policies().Equals(bundle));
diff --git a/chrome/browser/chromeos/policy/device_local_account_browsertest.cc b/chrome/browser/chromeos/policy/device_local_account_browsertest.cc index 108ac77..24509fc 100644 --- a/chrome/browser/chromeos/policy/device_local_account_browsertest.cc +++ b/chrome/browser/chromeos/policy/device_local_account_browsertest.cc
@@ -1279,7 +1279,7 @@ scoped_ptr<base::DictionaryValue> metadata = test::ConstructExternalDataReference(kExternalDataURL, kExternalData); std::string policy; - base::JSONWriter::Write(metadata.get(), &policy); + base::JSONWriter::Write(*metadata, &policy); device_local_account_policy_.payload().mutable_useravatarimage()->set_value( policy); UploadAndInstallDeviceLocalAccountPolicy(); @@ -1362,10 +1362,13 @@ &image_data)); std::string policy; - base::JSONWriter::Write(test::ConstructExternalDataReference( - embedded_test_server()->GetURL(std::string("/") + - chromeos::test::kUserAvatarImage1RelativePath).spec(), - image_data).get(), + base::JSONWriter::Write( + *test::ConstructExternalDataReference( + embedded_test_server() + ->GetURL(std::string("/") + + chromeos::test::kUserAvatarImage1RelativePath) + .spec(), + image_data), &policy); device_local_account_policy_.payload().mutable_useravatarimage()->set_value( policy);
diff --git a/chrome/browser/chromeos/policy/device_status_collector.h b/chrome/browser/chromeos/policy/device_status_collector.h index 4f31b298..47656a9b 100644 --- a/chrome/browser/chromeos/policy/device_status_collector.h +++ b/chrome/browser/chromeos/policy/device_status_collector.h
@@ -95,6 +95,12 @@ static void RegisterPrefs(PrefRegistrySimple* registry); + // Returns the DeviceLocalAccount associated with the currently active + // kiosk session, if the session was auto-launched with zero delay + // (this enables functionality such as network reporting). + // Virtual to allow mocking. + virtual scoped_ptr<DeviceLocalAccount> GetAutoLaunchedKioskSessionInfo(); + // How often, in seconds, to poll to see if the user is idle. static const unsigned int kIdlePollIntervalSeconds = 30; @@ -111,12 +117,6 @@ // Callback which receives the results of the idle state check. void IdleStateCallback(ui::IdleState state); - // Returns the DeviceLocalAccount associated with the currently active - // kiosk session, if the session was auto-launched with zero delay - // (this enables functionality such as network reporting). - // Virtual to allow mocking. - virtual scoped_ptr<DeviceLocalAccount> GetAutoLaunchedKioskSessionInfo(); - // Gets the version of the passed app. Virtual to allow mocking. virtual std::string GetAppVersion(const std::string& app_id);
diff --git a/chrome/browser/chromeos/policy/login_policy_test_base.cc b/chrome/browser/chromeos/policy/login_policy_test_base.cc index 710b0bda..7fb6adac 100644 --- a/chrome/browser/chromeos/policy/login_policy_test_base.cc +++ b/chrome/browser/chromeos/policy/login_policy_test_base.cc
@@ -54,10 +54,10 @@ root_dict.SetString("policy_user", account); root_dict.SetInteger("current_key_index", 0); - std::string jsonPolicy; + std::string json_policy; base::JSONWriter::WriteWithOptions( - &root_dict, base::JSONWriter::OPTIONS_PRETTY_PRINT, &jsonPolicy); - return jsonPolicy; + root_dict, base::JSONWriter::OPTIONS_PRETTY_PRINT, &json_policy); + return json_policy; } } // namespace
diff --git a/chrome/browser/chromeos/policy/proto/chrome_device_policy.proto b/chrome/browser/chromeos/policy/proto/chrome_device_policy.proto index ceee1d05..bb4e8e99 100644 --- a/chrome/browser/chromeos/policy/proto/chrome_device_policy.proto +++ b/chrome/browser/chromeos/policy/proto/chrome_device_policy.proto
@@ -610,7 +610,8 @@ } message ExtensionCacheSizeProto { - // Specifies the maximum extension cache size, in bytes. + // Specifies the maximum extension cache size, in bytes. The default is 256 + // MiB. The minimum allowed value is 1 MiB, smaller values will get ignored. optional int64 extension_cache_size = 1; }
diff --git a/chrome/browser/chromeos/policy/remote_commands/affiliated_remote_commands_invalidator.cc b/chrome/browser/chromeos/policy/remote_commands/affiliated_remote_commands_invalidator.cc new file mode 100644 index 0000000..63bb35a --- /dev/null +++ b/chrome/browser/chromeos/policy/remote_commands/affiliated_remote_commands_invalidator.cc
@@ -0,0 +1,37 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/chromeos/policy/remote_commands/affiliated_remote_commands_invalidator.h" + +#include "chrome/browser/policy/cloud/remote_commands_invalidator_impl.h" + +namespace policy { + +AffiliatedRemoteCommandsInvalidator::AffiliatedRemoteCommandsInvalidator( + CloudPolicyCore* core, + AffiliatedInvalidationServiceProvider* invalidation_service_provider) + : core_(core), + invalidation_service_provider_(invalidation_service_provider) { + invalidation_service_provider_->RegisterConsumer(this); +} + +AffiliatedRemoteCommandsInvalidator::~AffiliatedRemoteCommandsInvalidator() { + invalidation_service_provider_->UnregisterConsumer(this); +} + +void AffiliatedRemoteCommandsInvalidator::OnInvalidationServiceSet( + invalidation::InvalidationService* invalidation_service) { + // Destroy this invalidator if it exists. + if (invalidator_) { + invalidator_->Shutdown(); + invalidator_.reset(); + } + // Create a new one if required. + if (invalidation_service) { + invalidator_.reset(new RemoteCommandsInvalidatorImpl(core_)); + invalidator_->Initialize(invalidation_service); + } +} + +} // namespace policy
diff --git a/chrome/browser/chromeos/policy/remote_commands/affiliated_remote_commands_invalidator.h b/chrome/browser/chromeos/policy/remote_commands/affiliated_remote_commands_invalidator.h new file mode 100644 index 0000000..c981377 --- /dev/null +++ b/chrome/browser/chromeos/policy/remote_commands/affiliated_remote_commands_invalidator.h
@@ -0,0 +1,42 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_CHROMEOS_POLICY_REMOTE_COMMANDS_AFFILIATED_REMOTE_COMMANDS_INVALIDATOR_H_ +#define CHROME_BROWSER_CHROMEOS_POLICY_REMOTE_COMMANDS_AFFILIATED_REMOTE_COMMANDS_INVALIDATOR_H_ + +#include "base/macros.h" +#include "base/memory/scoped_ptr.h" +#include "chrome/browser/chromeos/policy/affiliated_invalidation_service_provider.h" + +namespace policy { + +class CloudPolicyCore; +class RemoteCommandsInvalidatorImpl; + +// This is a wrapper class to be used for device commands and device-local +// account commands. +class AffiliatedRemoteCommandsInvalidator + : public AffiliatedInvalidationServiceProvider::Consumer { + public: + AffiliatedRemoteCommandsInvalidator( + CloudPolicyCore* core, + AffiliatedInvalidationServiceProvider* invalidation_service_provider); + ~AffiliatedRemoteCommandsInvalidator() override; + + // AffiliatedInvalidationServiceProvider::Consumer: + void OnInvalidationServiceSet( + invalidation::InvalidationService* invalidation_service) override; + + private: + CloudPolicyCore* const core_; + AffiliatedInvalidationServiceProvider* const invalidation_service_provider_; + + scoped_ptr<RemoteCommandsInvalidatorImpl> invalidator_; + + DISALLOW_COPY_AND_ASSIGN(AffiliatedRemoteCommandsInvalidator); +}; + +} // namespace policy + +#endif // CHROME_BROWSER_CHROMEOS_POLICY_REMOTE_COMMANDS_AFFILIATED_REMOTE_COMMANDS_INVALIDATOR_H_
diff --git a/chrome/browser/chromeos/policy/remote_commands/device_command_screenshot_job.cc b/chrome/browser/chromeos/policy/remote_commands/device_command_screenshot_job.cc index 3a03d6c..28deddf 100644 --- a/chrome/browser/chromeos/policy/remote_commands/device_command_screenshot_job.cc +++ b/chrome/browser/chromeos/policy/remote_commands/device_command_screenshot_job.cc
@@ -81,8 +81,8 @@ DeviceCommandScreenshotJob::Payload::Payload(ResultCode result_code) { base::DictionaryValue root_dict; if (result_code != SUCCESS) - root_dict.Set(kResultFieldName, new base::FundamentalValue(result_code)); - base::JSONWriter::Write(&root_dict, &payload_); + root_dict.SetInteger(kResultFieldName, result_code); + base::JSONWriter::Write(root_dict, &payload_); } scoped_ptr<std::string> DeviceCommandScreenshotJob::Payload::Serialize() { @@ -189,8 +189,13 @@ succeeded_callback_ = succeeded_callback; failed_callback_ = failed_callback; - upload_job_ = screenshot_delegate_->CreateUploadJob(upload_url_, this); - DCHECK(upload_job_); + // Fail if the delegate says screenshots are not allowed in this session. + if (!screenshot_delegate_->IsScreenshotAllowed()) { + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, + base::Bind(failed_callback_, base::Passed(make_scoped_ptr( + new Payload(FAILURE_USER_INPUT))))); + } aura::Window::Windows root_windows = ash::Shell::GetAllRootWindows(); @@ -213,6 +218,9 @@ return; } + upload_job_ = screenshot_delegate_->CreateUploadJob(upload_url_, this); + DCHECK(upload_job_); + // Post tasks to the sequenced worker pool for taking screenshots on each // attached screen. num_pending_screenshots_ = root_windows.size();
diff --git a/chrome/browser/chromeos/policy/remote_commands/device_command_screenshot_job.h b/chrome/browser/chromeos/policy/remote_commands/device_command_screenshot_job.h index fb8aa79..49032be 100644 --- a/chrome/browser/chromeos/policy/remote_commands/device_command_screenshot_job.h +++ b/chrome/browser/chromeos/policy/remote_commands/device_command_screenshot_job.h
@@ -65,6 +65,12 @@ public: virtual ~Delegate() {} + // Returns true if screenshots are allowed in this session. Returns false + // if the current session is not an auto-launched kiosk session, or there + // have been certain types of user input that may result in leaking private + // information. + virtual bool IsScreenshotAllowed() = 0; + // Acquires a snapshot of |source_rect| in |window| and invokes |callback| // with the PNG data. The passed-in callback will not be invoked after the // delegate has been destroyed. See e.g. ScreenshotDelegate.
diff --git a/chrome/browser/chromeos/policy/remote_commands/device_command_screenshot_job_unittest.cc b/chrome/browser/chromeos/policy/remote_commands/device_command_screenshot_job_unittest.cc index cc4b51b2..8b07687 100644 --- a/chrome/browser/chromeos/policy/remote_commands/device_command_screenshot_job_unittest.cc +++ b/chrome/browser/chromeos/policy/remote_commands/device_command_screenshot_job_unittest.cc
@@ -49,8 +49,8 @@ command_proto.set_age_of_command(age_of_command.InMilliseconds()); std::string payload; base::DictionaryValue root_dict; - root_dict.Set(kUploadUrlFieldName, new base::StringValue(upload_url)); - base::JSONWriter::Write(&root_dict, &payload); + root_dict.SetString(kUploadUrlFieldName, upload_url); + base::JSONWriter::Write(root_dict, &payload); command_proto.set_payload(payload); return command_proto; } @@ -137,10 +137,11 @@ class MockScreenshotDelegate : public DeviceCommandScreenshotJob::Delegate { public: - MockScreenshotDelegate( - scoped_ptr<UploadJob::ErrorCode> upload_job_error_code); + MockScreenshotDelegate(scoped_ptr<UploadJob::ErrorCode> upload_job_error_code, + bool screenshot_allowed); ~MockScreenshotDelegate() override; + bool IsScreenshotAllowed() override; void TakeSnapshot( gfx::NativeWindow window, const gfx::Rect& source_rect, @@ -150,16 +151,23 @@ private: scoped_ptr<UploadJob::ErrorCode> upload_job_error_code_; + bool screenshot_allowed_; }; MockScreenshotDelegate::MockScreenshotDelegate( - scoped_ptr<UploadJob::ErrorCode> upload_job_error_code) - : upload_job_error_code_(upload_job_error_code.Pass()) { + scoped_ptr<UploadJob::ErrorCode> upload_job_error_code, + bool screenshot_allowed) + : upload_job_error_code_(upload_job_error_code.Pass()), + screenshot_allowed_(screenshot_allowed) { } MockScreenshotDelegate::~MockScreenshotDelegate() { } +bool MockScreenshotDelegate::IsScreenshotAllowed() { + return screenshot_allowed_; +} + void MockScreenshotDelegate::TakeSnapshot( gfx::NativeWindow window, const gfx::Rect& source_rect, @@ -238,7 +246,7 @@ base::DictionaryValue root_dict; if (result_code != DeviceCommandScreenshotJob::SUCCESS) root_dict.Set(kResultFieldName, new base::FundamentalValue(result_code)); - base::JSONWriter::Write(&root_dict, &payload); + base::JSONWriter::Write(root_dict, &payload); return payload; } @@ -257,7 +265,7 @@ TEST_F(DeviceCommandScreenshotTest, Success) { scoped_ptr<RemoteCommandJob> job(new DeviceCommandScreenshotJob( - make_scoped_ptr(new MockScreenshotDelegate(nullptr)))); + make_scoped_ptr(new MockScreenshotDelegate(nullptr, true)))); InitializeScreenshotJob(job.get(), kUniqueID, test_start_time_, kMockUploadUrl); bool success = job->Run( @@ -270,12 +278,28 @@ run_loop_.Run(); } +TEST_F(DeviceCommandScreenshotTest, FailureUserInput) { + scoped_ptr<RemoteCommandJob> job(new DeviceCommandScreenshotJob( + make_scoped_ptr(new MockScreenshotDelegate(nullptr, false)))); + InitializeScreenshotJob(job.get(), kUniqueID, test_start_time_, + kMockUploadUrl); + bool success = + job->Run(base::TimeTicks::Now(), + base::Bind(&DeviceCommandScreenshotTest::VerifyResults, + base::Unretained(this), base::Unretained(job.get()), + RemoteCommandJob::FAILED, + CreatePayloadFromResultCode( + DeviceCommandScreenshotJob::FAILURE_USER_INPUT))); + EXPECT_TRUE(success); + run_loop_.Run(); +} + TEST_F(DeviceCommandScreenshotTest, Failure) { using ErrorCode = UploadJob::ErrorCode; scoped_ptr<ErrorCode> error_code( new ErrorCode(UploadJob::AUTHENTICATION_ERROR)); scoped_ptr<RemoteCommandJob> job(new DeviceCommandScreenshotJob( - make_scoped_ptr(new MockScreenshotDelegate(error_code.Pass())))); + make_scoped_ptr(new MockScreenshotDelegate(error_code.Pass(), true)))); InitializeScreenshotJob(job.get(), kUniqueID, test_start_time_, kMockUploadUrl); bool success = job->Run(
diff --git a/chrome/browser/chromeos/policy/remote_commands/screenshot_delegate.cc b/chrome/browser/chromeos/policy/remote_commands/screenshot_delegate.cc index b850a59..c431d68 100644 --- a/chrome/browser/chromeos/policy/remote_commands/screenshot_delegate.cc +++ b/chrome/browser/chromeos/policy/remote_commands/screenshot_delegate.cc
@@ -5,6 +5,9 @@ #include "chrome/browser/chromeos/policy/remote_commands/screenshot_delegate.h" #include "chrome/browser/browser_process.h" +#include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h" +#include "chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.h" +#include "chrome/browser/chromeos/policy/status_uploader.h" #include "chrome/browser/chromeos/policy/upload_job_impl.h" #include "chrome/browser/chromeos/settings/device_oauth2_token_service.h" #include "chrome/browser/chromeos/settings/device_oauth2_token_service_factory.h" @@ -20,6 +23,18 @@ ScreenshotDelegate::~ScreenshotDelegate() { } +bool ScreenshotDelegate::IsScreenshotAllowed() { + BrowserPolicyConnectorChromeOS* connector = + g_browser_process->platform_part()->browser_policy_connector_chromeos(); + DeviceCloudPolicyManagerChromeOS* manager = + connector->GetDeviceCloudPolicyManager(); + // DeviceCloudPolicyManagerChromeOS and StatusUploader can be null during + // shutdown (and unit tests) - don't allow screenshots unless we have a + // StatusUploader that can confirm that screenshots are allowed. + return manager && manager->GetStatusUploader() && + manager->GetStatusUploader()->IsSessionDataUploadAllowed(); +} + void ScreenshotDelegate::TakeSnapshot( gfx::NativeWindow window, const gfx::Rect& source_rect,
diff --git a/chrome/browser/chromeos/policy/remote_commands/screenshot_delegate.h b/chrome/browser/chromeos/policy/remote_commands/screenshot_delegate.h index d809b91..fd15c7e7f 100644 --- a/chrome/browser/chromeos/policy/remote_commands/screenshot_delegate.h +++ b/chrome/browser/chromeos/policy/remote_commands/screenshot_delegate.h
@@ -28,6 +28,7 @@ ~ScreenshotDelegate() override; // DeviceCommandScreenshotJob::Delegate: + bool IsScreenshotAllowed() override; void TakeSnapshot( gfx::NativeWindow window, const gfx::Rect& source_rect,
diff --git a/chrome/browser/chromeos/policy/status_uploader.cc b/chrome/browser/chromeos/policy/status_uploader.cc index 5bf4202..fd95fca 100644 --- a/chrome/browser/chromeos/policy/status_uploader.cc +++ b/chrome/browser/chromeos/policy/status_uploader.cc
@@ -10,11 +10,13 @@ #include "base/bind_helpers.h" #include "base/location.h" #include "base/sequenced_task_runner.h" +#include "chrome/browser/chromeos/policy/device_local_account.h" #include "chrome/browser/chromeos/policy/device_status_collector.h" #include "chromeos/settings/cros_settings_names.h" #include "chromeos/settings/cros_settings_provider.h" #include "components/policy/core/common/cloud/cloud_policy_client.h" #include "components/policy/core/common/cloud/device_management_service.h" +#include "ui/base/user_activity/user_activity_detector.h" namespace { const int kMinUploadDelayMs = 60 * 1000; // 60 seconds @@ -103,6 +105,22 @@ ScheduleNextStatusUpload(); } +bool StatusUploader::IsSessionDataUploadAllowed() { + // Check if we're in an auto-launched kiosk session. + scoped_ptr<DeviceLocalAccount> account = + collector_->GetAutoLaunchedKioskSessionInfo(); + if (!account) + return false; + + // Check if there has been any user input. + if (!ui::UserActivityDetector::Get()->last_activity_time().is_null()) + return false; + + // TODO(atwilson): Check if we've captured any audio/video data + // (http://crbug.com/487261). + return true; +} + void StatusUploader::UploadStatus() { enterprise_management::DeviceStatusReportRequest device_status; bool have_device_status = collector_->GetDeviceStatus(&device_status);
diff --git a/chrome/browser/chromeos/policy/status_uploader.h b/chrome/browser/chromeos/policy/status_uploader.h index 2eead18..6fa48203 100644 --- a/chrome/browser/chromeos/policy/status_uploader.h +++ b/chrome/browser/chromeos/policy/status_uploader.h
@@ -44,6 +44,11 @@ // has ever happened. base::Time last_upload() const { return last_upload_; } + // Returns true if session data upload (screenshots, logs, etc) is allowed. + // This checks to ensure that the current session is a kiosk session, and + // that no user input (keyboard, mouse, touch, audio/video) has been received. + bool IsSessionDataUploadAllowed(); + private: // Callback invoked periodically to upload the device status from the // DeviceStatusCollector.
diff --git a/chrome/browser/chromeos/proxy_config_service_impl_unittest.cc b/chrome/browser/chromeos/proxy_config_service_impl_unittest.cc index 785c48a..121ef02e 100644 --- a/chrome/browser/chromeos/proxy_config_service_impl_unittest.cc +++ b/chrome/browser/chromeos/proxy_config_service_impl_unittest.cc
@@ -333,7 +333,7 @@ void SetUserConfigInShill(base::DictionaryValue* pref_proxy_config_dict) { std::string proxy_config; if (pref_proxy_config_dict) - base::JSONWriter::Write(pref_proxy_config_dict, &proxy_config); + base::JSONWriter::Write(*pref_proxy_config_dict, &proxy_config); NetworkStateHandler* network_state_handler = NetworkHandler::Get()->network_state_handler();
diff --git a/chrome/browser/component_updater/supervised_user_whitelist_installer_unittest.cc b/chrome/browser/component_updater/supervised_user_whitelist_installer_unittest.cc index c6266a2..c5e897f0 100644 --- a/chrome/browser/component_updater/supervised_user_whitelist_installer_unittest.cc +++ b/chrome/browser/component_updater/supervised_user_whitelist_installer_unittest.cc
@@ -51,7 +51,7 @@ return GetCrxComponentID(component); } -std::string JsonToString(const base::DictionaryValue* dict) { +std::string JsonToString(const base::DictionaryValue& dict) { std::string json; base::JSONWriter::Write(dict, &json); return json; @@ -310,8 +310,8 @@ ASSERT_TRUE(base::ReadFileToString(whitelist_path_, &whitelist_contents)); EXPECT_EQ(kWhitelistContents, whitelist_contents); - EXPECT_EQ(JsonToString(&pref_), - JsonToString(local_state_.GetDictionary( + EXPECT_EQ(JsonToString(pref_), + JsonToString(*local_state_.GetDictionary( prefs::kRegisteredSupervisedUserWhitelists))); }
diff --git a/chrome/browser/content_settings/host_content_settings_map_unittest.cc b/chrome/browser/content_settings/host_content_settings_map_unittest.cc index 6247af2..0cf740f 100644 --- a/chrome/browser/content_settings/host_content_settings_map_unittest.cc +++ b/chrome/browser/content_settings/host_content_settings_map_unittest.cc
@@ -720,8 +720,8 @@ // Initialize the content map. profile.GetHostContentSettingsMap(); - const base::DictionaryValue* content_setting_prefs = - profile.GetPrefs()->GetDictionary( + const base::DictionaryValue& content_setting_prefs = + *profile.GetPrefs()->GetDictionary( prefs::kContentSettingsImagesPatternPairs); std::string prefs_as_json; base::JSONWriter::Write(content_setting_prefs, &prefs_as_json);
diff --git a/chrome/browser/content_settings/permission_context_base.cc b/chrome/browser/content_settings/permission_context_base.cc index 60b7438e..9cd5d126 100644 --- a/chrome/browser/content_settings/permission_context_base.cc +++ b/chrome/browser/content_settings/permission_context_base.cc
@@ -181,7 +181,7 @@ if (persist) { DCHECK(content_setting == CONTENT_SETTING_ALLOW || content_setting == CONTENT_SETTING_BLOCK); - if (CONTENT_SETTING_ALLOW) + if (content_setting == CONTENT_SETTING_ALLOW) PermissionContextUmaUtil::PermissionGranted(permission_type_, requesting_origin); else
diff --git a/chrome/browser/devtools/device/webrtc/send_command_request.cc b/chrome/browser/devtools/device/webrtc/send_command_request.cc index d09be25..7bfe5f4 100644 --- a/chrome/browser/devtools/device/webrtc/send_command_request.cc +++ b/chrome/browser/devtools/device/webrtc/send_command_request.cc
@@ -22,7 +22,7 @@ SendCommandRequest::SendCommandRequest(const base::DictionaryValue* request, Delegate* delegate) : delegate_(delegate) { - base::JSONWriter::Write(request, &upload_data_); + base::JSONWriter::Write(*request, &upload_data_); DCHECK(delegate_); }
diff --git a/chrome/browser/devtools/devtools_protocol.cc b/chrome/browser/devtools/devtools_protocol.cc index 8df0557..5687220 100644 --- a/chrome/browser/devtools/devtools_protocol.cc +++ b/chrome/browser/devtools/devtools_protocol.cc
@@ -37,7 +37,7 @@ command.Set(kParamsParam, params.release()); std::string json_command; - base::JSONWriter::Write(&command, &json_command); + base::JSONWriter::Write(command, &json_command); return json_command; }
diff --git a/chrome/browser/devtools/devtools_ui_bindings.cc b/chrome/browser/devtools/devtools_ui_bindings.cc index 3a5d3ca..69ab19f 100644 --- a/chrome/browser/devtools/devtools_ui_bindings.cc +++ b/chrome/browser/devtools/devtools_ui_bindings.cc
@@ -1016,13 +1016,13 @@ std::string javascript = function_name + "("; if (arg1) { std::string json; - base::JSONWriter::Write(arg1, &json); + base::JSONWriter::Write(*arg1, &json); javascript.append(json); if (arg2) { - base::JSONWriter::Write(arg2, &json); + base::JSONWriter::Write(*arg2, &json); javascript.append(", ").append(json); if (arg3) { - base::JSONWriter::Write(arg3, &json); + base::JSONWriter::Write(*arg3, &json); javascript.append(", ").append(json); } }
diff --git a/chrome/browser/extensions/BUILD.gn b/chrome/browser/extensions/BUILD.gn index ab3ce940..8a541b1 100644 --- a/chrome/browser/extensions/BUILD.gn +++ b/chrome/browser/extensions/BUILD.gn
@@ -202,7 +202,4 @@ if (!use_ozone) { sources -= [ "global_shortcut_listener_ozone.cc" ] } - if (enable_media_router) { - defines += [ "ENABLE_MEDIA_ROUTER=1" ] - } }
diff --git a/chrome/browser/extensions/api/automation/automation_apitest.cc b/chrome/browser/extensions/api/automation/automation_apitest.cc index 4310f03..e94ad6cc 100644 --- a/chrome/browser/extensions/api/automation/automation_apitest.cc +++ b/chrome/browser/extensions/api/automation/automation_apitest.cc
@@ -206,7 +206,7 @@ #else #define MAYBE_Mixins Mixins #endif -IN_PROC_BROWSER_TEST_F(AutomationApiTest, Mixins) { +IN_PROC_BROWSER_TEST_F(AutomationApiTest, MAYBE_Mixins) { StartEmbeddedTestServer(); ASSERT_TRUE(RunExtensionSubtest("automation/tests/tabs", "mixins.html")) << message_;
diff --git a/chrome/browser/extensions/api/debugger/debugger_api.cc b/chrome/browser/extensions/api/debugger/debugger_api.cc index 14638efb..27623d9 100644 --- a/chrome/browser/extensions/api/debugger/debugger_api.cc +++ b/chrome/browser/extensions/api/debugger/debugger_api.cc
@@ -385,7 +385,7 @@ } std::string json_args; - base::JSONWriter::Write(&protocol_request, &json_args); + base::JSONWriter::Write(protocol_request, &json_args); agent_host_->DispatchProtocolMessage(json_args); } @@ -666,7 +666,7 @@ base::DictionaryValue* response) { base::Value* error_body; if (response->Get("error", &error_body)) { - base::JSONWriter::Write(error_body, &error_); + base::JSONWriter::Write(*error_body, &error_); SendResponse(false); return; }
diff --git a/chrome/browser/extensions/api/developer_private/extension_info_generator_unittest.cc b/chrome/browser/extensions/api/developer_private/extension_info_generator_unittest.cc index 3b7d50d9..65e3aec6 100644 --- a/chrome/browser/extensions/api/developer_private/extension_info_generator_unittest.cc +++ b/chrome/browser/extensions/api/developer_private/extension_info_generator_unittest.cc
@@ -146,15 +146,15 @@ std::string actual_string; for (base::DictionaryValue::Iterator field(*expected_output_data); !field.IsAtEnd(); field.Advance()) { - const base::Value* expected_value = &field.value(); + const base::Value& expected_value = field.value(); base::Value* actual_value = nullptr; EXPECT_TRUE(actual_output_data->Get(field.key(), &actual_value)) << field.key() + " is missing" + paths_details; if (!actual_value) continue; - if (!actual_value->Equals(expected_value)) { + if (!actual_value->Equals(&expected_value)) { base::JSONWriter::Write(expected_value, &expected_string); - base::JSONWriter::Write(actual_value, &actual_string); + base::JSONWriter::Write(*actual_value, &actual_string); EXPECT_EQ(expected_string, actual_string) << field.key() << paths_details; }
diff --git a/chrome/browser/extensions/api/downloads/downloads_api.cc b/chrome/browser/extensions/api/downloads/downloads_api.cc index 268043e..0d614aa 100644 --- a/chrome/browser/extensions/api/downloads/downloads_api.cc +++ b/chrome/browser/extensions/api/downloads/downloads_api.cc
@@ -1860,7 +1860,7 @@ scoped_ptr<base::ListValue> args(new base::ListValue()); args->Append(arg); std::string json_args; - base::JSONWriter::Write(args.get(), &json_args); + base::JSONWriter::Write(*args, &json_args); scoped_ptr<Event> event(new Event(event_name, args.Pass())); // The downloads system wants to share on-record events with off-record // extension renderers even in incognito_split_mode because that's how
diff --git a/chrome/browser/extensions/api/file_system/file_system_api.cc b/chrome/browser/extensions/api/file_system/file_system_api.cc index fbf6a83..fce5277 100644 --- a/chrome/browser/extensions/api/file_system/file_system_api.cc +++ b/chrome/browser/extensions/api/file_system/file_system_api.cc
@@ -318,8 +318,8 @@ if (!registry) // Possible on shutdown. return; - ConsentProvider consent_provider( - new ConsentProviderDelegate(profile, nullptr)); + ConsentProviderDelegate consent_provider_delegate(profile, nullptr); + ConsentProvider consent_provider(&consent_provider_delegate); extensions::api::file_system::VolumeListChangedEvent event_args; FillVolumeList(profile, &event_args.volumes); for (const auto& extension : registry->enabled_extensions()) {
diff --git a/chrome/browser/extensions/api/instance_id/instance_id_apitest.cc b/chrome/browser/extensions/api/instance_id/instance_id_apitest.cc index a8c00fb..54f07576 100644 --- a/chrome/browser/extensions/api/instance_id/instance_id_apitest.cc +++ b/chrome/browser/extensions/api/instance_id/instance_id_apitest.cc
@@ -10,7 +10,7 @@ #include "chrome/browser/services/gcm/fake_gcm_profile_service.h" #include "chrome/browser/services/gcm/gcm_profile_service_factory.h" #include "chrome/browser/services/gcm/instance_id/instance_id_profile_service_factory.h" -#include "chrome/common/chrome_switches.h" +#include "chrome/common/extensions/features/feature_channel.h" #include "chrome/test/base/ui_test_utils.h" #include "components/gcm_driver/instance_id/fake_gcm_driver_for_instance_id.h" #include "extensions/test/result_catcher.h" @@ -36,7 +36,6 @@ protected: void SetUpOnMainThread() override; - void SetUpCommandLine(base::CommandLine* command_line) override; private: DISALLOW_COPY_AND_ASSIGN(InstanceIDApiTest); @@ -49,35 +48,40 @@ ExtensionApiTest::SetUpOnMainThread(); } -void InstanceIDApiTest::SetUpCommandLine(base::CommandLine* command_line) { - ExtensionApiTest::SetUpCommandLine(command_line); - - // Makes sure InstanceID is enabled for testing. - command_line->AppendSwitchASCII( - switches::kForceFieldTrials, "InstanceID/Enabled/"); -} - IN_PROC_BROWSER_TEST_F(InstanceIDApiTest, GetID) { + extensions::ScopedCurrentChannel current_channel( + chrome::VersionInfo::CHANNEL_DEV); ASSERT_TRUE(RunExtensionTest("instance_id/get_id")); } IN_PROC_BROWSER_TEST_F(InstanceIDApiTest, GetCreationTime) { + extensions::ScopedCurrentChannel current_channel( + chrome::VersionInfo::CHANNEL_DEV); ASSERT_TRUE(RunExtensionTest("instance_id/get_creation_time")); } IN_PROC_BROWSER_TEST_F(InstanceIDApiTest, DeleteID) { + extensions::ScopedCurrentChannel current_channel( + chrome::VersionInfo::CHANNEL_DEV); ASSERT_TRUE(RunExtensionTest("instance_id/delete_id")); } IN_PROC_BROWSER_TEST_F(InstanceIDApiTest, GetToken) { + extensions::ScopedCurrentChannel current_channel( + chrome::VersionInfo::CHANNEL_DEV); ASSERT_TRUE(RunExtensionTest("instance_id/get_token")); } IN_PROC_BROWSER_TEST_F(InstanceIDApiTest, DeleteToken) { + extensions::ScopedCurrentChannel current_channel( + chrome::VersionInfo::CHANNEL_DEV); ASSERT_TRUE(RunExtensionTest("instance_id/delete_token")); } IN_PROC_BROWSER_TEST_F(InstanceIDApiTest, Incognito) { + extensions::ScopedCurrentChannel current_channel( + chrome::VersionInfo::CHANNEL_DEV); + ResultCatcher catcher; catcher.RestrictToBrowserContext(profile()); ResultCatcher incognito_catcher; @@ -90,4 +94,16 @@ EXPECT_TRUE(incognito_catcher.GetNextResult()) << incognito_catcher.message(); } +IN_PROC_BROWSER_TEST_F(InstanceIDApiTest, BetaChannel) { + extensions::ScopedCurrentChannel current_channel( + chrome::VersionInfo::CHANNEL_BETA); + ASSERT_TRUE(RunExtensionTest("instance_id/channel")); +} + +IN_PROC_BROWSER_TEST_F(InstanceIDApiTest, StableChannel) { + extensions::ScopedCurrentChannel current_channel( + chrome::VersionInfo::CHANNEL_STABLE); + ASSERT_TRUE(RunExtensionTest("instance_id/channel")); +} + } // namespace extensions
diff --git a/chrome/browser/extensions/api/launcher_page/launcher_page_api.cc b/chrome/browser/extensions/api/launcher_page/launcher_page_api.cc index ae0669d7..07bb351 100644 --- a/chrome/browser/extensions/api/launcher_page/launcher_page_api.cc +++ b/chrome/browser/extensions/api/launcher_page/launcher_page_api.cc
@@ -65,6 +65,19 @@ return RespondNow(NoArguments()); } +LauncherPageHideFunction::LauncherPageHideFunction() { +} + +ExtensionFunction::ResponseAction LauncherPageHideFunction::Run() { + chrome::HostDesktopType host_desktop = + chrome::GetHostDesktopTypeForNativeWindow( + GetAssociatedWebContents()->GetTopLevelNativeWindow()); + + AppListService::Get(host_desktop)->HideCustomLauncherPage(); + + return RespondNow(NoArguments()); +} + LauncherPageSetEnabledFunction::LauncherPageSetEnabledFunction() { }
diff --git a/chrome/browser/extensions/api/launcher_page/launcher_page_api.h b/chrome/browser/extensions/api/launcher_page/launcher_page_api.h index 8f3b915b..bd39314 100644 --- a/chrome/browser/extensions/api/launcher_page/launcher_page_api.h +++ b/chrome/browser/extensions/api/launcher_page/launcher_page_api.h
@@ -65,6 +65,21 @@ DISALLOW_COPY_AND_ASSIGN(LauncherPageShowFunction); }; +class LauncherPageHideFunction : public UIThreadExtensionFunction { + public: + DECLARE_EXTENSION_FUNCTION("launcherPage.hide", LAUNCHERPAGE_HIDE); + + LauncherPageHideFunction(); + + protected: + ~LauncherPageHideFunction() override {} + + ResponseAction Run() override; + + private: + DISALLOW_COPY_AND_ASSIGN(LauncherPageHideFunction); +}; + class LauncherPageSetEnabledFunction : public UIThreadExtensionFunction { public: DECLARE_EXTENSION_FUNCTION("launcherPage.setEnabled",
diff --git a/chrome/browser/extensions/api/media_galleries/media_galleries_apitest.cc b/chrome/browser/extensions/api/media_galleries/media_galleries_apitest.cc index 1cffad6..67740e1 100644 --- a/chrome/browser/extensions/api/media_galleries/media_galleries_apitest.cc +++ b/chrome/browser/extensions/api/media_galleries/media_galleries_apitest.cc
@@ -164,7 +164,7 @@ const char* custom_arg = NULL; std::string json_string; if (!custom_arg_value.empty()) { - base::JSONWriter::Write(&custom_arg_value, &json_string); + base::JSONWriter::Write(custom_arg_value, &json_string); custom_arg = json_string.c_str(); }
diff --git a/chrome/browser/extensions/api/messaging/message_property_provider.cc b/chrome/browser/extensions/api/messaging/message_property_provider.cc index cee56d7..a1eb7acf 100644 --- a/chrome/browser/extensions/api/messaging/message_property_provider.cc +++ b/chrome/browser/extensions/api/messaging/message_property_provider.cc
@@ -100,7 +100,7 @@ return; } std::string jwk_str; - base::JSONWriter::Write(&jwk_value, &jwk_str); + base::JSONWriter::Write(jwk_value, &jwk_str); original_task_runner->PostTask(FROM_HERE, base::Bind(reply, jwk_str)); }
diff --git a/chrome/browser/extensions/api/messaging/native_message_host_chromeos.cc b/chrome/browser/extensions/api/messaging/native_message_host_chromeos.cc index 4977908..0fbc770 100644 --- a/chrome/browser/extensions/api/messaging/native_message_host_chromeos.cc +++ b/chrome/browser/extensions/api/messaging/native_message_host_chromeos.cc
@@ -70,12 +70,12 @@ private: void ProcessEcho(const base::DictionaryValue& request) { - scoped_ptr<base::DictionaryValue> response(new base::DictionaryValue()); - response->SetInteger("id", ++message_number_); - response->Set("echo", request.DeepCopy()); - response->SetString("caller_url", kEchoHostOrigins[0]); + base::DictionaryValue response; + response.SetInteger("id", ++message_number_); + response.Set("echo", request.CreateDeepCopy()); + response.SetString("caller_url", kEchoHostOrigins[0]); std::string response_string; - base::JSONWriter::Write(response.get(), &response_string); + base::JSONWriter::Write(response, &response_string); client_->PostMessageFromNativeHost(response_string); }
diff --git a/chrome/browser/extensions/api/permissions/permissions_api_helpers.cc b/chrome/browser/extensions/api/permissions/permissions_api_helpers.cc index 19aa3e14..13ce9b1 100644 --- a/chrome/browser/extensions/api/permissions/permissions_api_helpers.cc +++ b/chrome/browser/extensions/api/permissions/permissions_api_helpers.cc
@@ -51,7 +51,7 @@ } else { std::string name(i->name()); std::string json; - base::JSONWriter::Write(value.get(), &json); + base::JSONWriter::Write(*value, &json); permissions->permissions->push_back(name + kDelimiter + json); } }
diff --git a/chrome/browser/extensions/api/socket/tls_socket_unittest.cc b/chrome/browser/extensions/api/socket/tls_socket_unittest.cc index 49edd64..858d06d 100644 --- a/chrome/browser/extensions/api/socket/tls_socket_unittest.cc +++ b/chrome/browser/extensions/api/socket/tls_socket_unittest.cc
@@ -69,6 +69,7 @@ MOCK_CONST_METHOD0(GetUnverifiedServerCertificateChain, scoped_refptr<net::X509Certificate>()); MOCK_CONST_METHOD0(GetChannelIDService, net::ChannelIDService*()); + MOCK_CONST_METHOD0(GetSSLFailureState, net::SSLFailureState()); bool IsConnected() const override { return true; } private:
diff --git a/chrome/browser/extensions/api/storage/settings_apitest.cc b/chrome/browser/extensions/api/storage/settings_apitest.cc index eaa5ea1..50f0383 100644 --- a/chrome/browser/extensions/api/storage/settings_apitest.cc +++ b/chrome/browser/extensions/api/storage/settings_apitest.cc
@@ -174,12 +174,12 @@ Namespace settings_namespace, const std::string& action, bool is_final_action) { - scoped_ptr<base::DictionaryValue> message(new base::DictionaryValue()); - message->SetString("namespace", ToString(settings_namespace)); - message->SetString("action", action); - message->SetBoolean("isFinalAction", is_final_action); + base::DictionaryValue message; + message.SetString("namespace", ToString(settings_namespace)); + message.SetString("action", action); + message.SetBoolean("isFinalAction", is_final_action); std::string message_json; - base::JSONWriter::Write(message.get(), &message_json); + base::JSONWriter::Write(message, &message_json); return message_json; }
diff --git a/chrome/browser/extensions/api/storage/settings_sync_unittest.cc b/chrome/browser/extensions/api/storage/settings_sync_unittest.cc index 9ed1922f..ab4f521a 100644 --- a/chrome/browser/extensions/api/storage/settings_sync_unittest.cc +++ b/chrome/browser/extensions/api/storage/settings_sync_unittest.cc
@@ -45,9 +45,8 @@ // Gets the pretty-printed JSON for a value. static std::string GetJson(const base::Value& value) { std::string json; - base::JSONWriter::WriteWithOptions(&value, - base::JSONWriter::OPTIONS_PRETTY_PRINT, - &json); + base::JSONWriter::WriteWithOptions( + value, base::JSONWriter::OPTIONS_PRETTY_PRINT, &json); return json; }
diff --git a/chrome/browser/extensions/api/storage/settings_sync_util.cc b/chrome/browser/extensions/api/storage/settings_sync_util.cc index c187c52d..ccd9a44 100644 --- a/chrome/browser/extensions/api/storage/settings_sync_util.cc +++ b/chrome/browser/extensions/api/storage/settings_sync_util.cc
@@ -30,7 +30,7 @@ specifics->set_key(key); { std::string value_as_json; - base::JSONWriter::Write(&value, &value_as_json); + base::JSONWriter::Write(value, &value_as_json); specifics->set_value(value_as_json); } }
diff --git a/chrome/browser/extensions/api/web_navigation/frame_navigation_state.cc b/chrome/browser/extensions/api/web_navigation/frame_navigation_state.cc index 37764cb..635653748 100644 --- a/chrome/browser/extensions/api/web_navigation/frame_navigation_state.cc +++ b/chrome/browser/extensions/api/web_navigation/frame_navigation_state.cc
@@ -37,17 +37,8 @@ FrameNavigationState::~FrameNavigationState() {} -bool FrameNavigationState::CanSendEvents( - content::RenderFrameHost* frame_host) const { - FrameHostToStateMap::const_iterator it = - frame_host_state_map_.find(frame_host); - if (it == frame_host_state_map_.end() || it->second.error_occurred) { - return false; - } - return IsValidUrl(it->second.url); -} - -bool FrameNavigationState::IsValidUrl(const GURL& url) const { +// static +bool FrameNavigationState::IsValidUrl(const GURL& url) { for (unsigned i = 0; i < arraysize(kValidSchemes); ++i) { if (url.scheme() == kValidSchemes[i]) return true; @@ -60,6 +51,16 @@ return allow_extension_scheme_ && url.scheme() == kExtensionScheme; } +bool FrameNavigationState::CanSendEvents( + content::RenderFrameHost* frame_host) const { + FrameHostToStateMap::const_iterator it = + frame_host_state_map_.find(frame_host); + if (it == frame_host_state_map_.end() || it->second.error_occurred) { + return false; + } + return IsValidUrl(it->second.url); +} + void FrameNavigationState::StartTrackingNavigation( content::RenderFrameHost* frame_host, const GURL& url,
diff --git a/chrome/browser/extensions/api/web_navigation/frame_navigation_state.h b/chrome/browser/extensions/api/web_navigation/frame_navigation_state.h index 2e4a300..3751870 100644 --- a/chrome/browser/extensions/api/web_navigation/frame_navigation_state.h +++ b/chrome/browser/extensions/api/web_navigation/frame_navigation_state.h
@@ -28,6 +28,9 @@ FrameNavigationState(); ~FrameNavigationState(); + // True if in general webNavigation events may be sent for the given URL. + static bool IsValidUrl(const GURL& url); + // Use these to iterate over all frame hosts known by this object. const_iterator begin() const { return frame_hosts_.begin(); } const_iterator end() const { return frame_hosts_.end(); } @@ -35,10 +38,6 @@ // True if navigation events for the given frame can be sent. bool CanSendEvents(content::RenderFrameHost* frame_host) const; - // TODO(dcheng): This should be static. - // True if in general webNavigation events may be sent for the given URL. - bool IsValidUrl(const GURL& url) const; - // Starts to track a navigation in |frame_host| to |url|. void StartTrackingNavigation(content::RenderFrameHost* frame_host, const GURL& url,
diff --git a/chrome/browser/extensions/api/web_navigation/web_navigation_api.cc b/chrome/browser/extensions/api/web_navigation/web_navigation_api.cc index aa6c568..d5a9dda 100644 --- a/chrome/browser/extensions/api/web_navigation/web_navigation_api.cc +++ b/chrome/browser/extensions/api/web_navigation/web_navigation_api.cc
@@ -122,11 +122,8 @@ DCHECK(GetViewType(old_contents) != VIEW_TYPE_TAB_CONTENTS); return; } - const FrameNavigationState& frame_navigation_state = - tab_observer->frame_navigation_state(); - - if (!frame_navigation_state.IsValidUrl(old_contents->GetURL()) || - !frame_navigation_state.IsValidUrl(new_contents->GetURL())) + if (!FrameNavigationState::IsValidUrl(old_contents->GetURL()) || + !FrameNavigationState::IsValidUrl(new_contents->GetURL())) return; helpers::DispatchOnTabReplaced(old_contents, profile_, new_contents); @@ -322,31 +319,21 @@ if (!navigation_state_.CanSendEvents(render_frame_host)) return; + std::string event_name; if (is_reference_fragment_navigation) { - helpers::DispatchOnCommitted( - web_navigation::OnReferenceFragmentUpdated::kEventName, - web_contents(), - render_frame_host, - navigation_state_.GetUrl(render_frame_host), - transition_type); + event_name = web_navigation::OnReferenceFragmentUpdated::kEventName; } else if (is_history_state_modification) { - helpers::DispatchOnCommitted( - web_navigation::OnHistoryStateUpdated::kEventName, - web_contents(), - render_frame_host, - navigation_state_.GetUrl(render_frame_host), - transition_type); + event_name = web_navigation::OnHistoryStateUpdated::kEventName; } else { if (navigation_state_.GetIsServerRedirected(render_frame_host)) { transition_type = ui::PageTransitionFromInt( transition_type | ui::PAGE_TRANSITION_SERVER_REDIRECT); } - helpers::DispatchOnCommitted(web_navigation::OnCommitted::kEventName, - web_contents(), - render_frame_host, - navigation_state_.GetUrl(render_frame_host), - transition_type); + event_name = web_navigation::OnCommitted::kEventName; } + helpers::DispatchOnCommitted(event_name, web_contents(), render_frame_host, + navigation_state_.GetUrl(render_frame_host), + transition_type); } void WebNavigationTabObserver::DidFailProvisionalLoad(
diff --git a/chrome/browser/extensions/api/webrtc_audio_private/webrtc_audio_private_browsertest.cc b/chrome/browser/extensions/api/webrtc_audio_private/webrtc_audio_private_browsertest.cc index 95bcf2e..289aeec 100644 --- a/chrome/browser/extensions/api/webrtc_audio_private/webrtc_audio_private_browsertest.cc +++ b/chrome/browser/extensions/api/webrtc_audio_private/webrtc_audio_private_browsertest.cc
@@ -94,7 +94,7 @@ base::ListValue parameters; AppendTabIdToRequestInfo(¶meters, tab_id); std::string parameter_string; - JSONWriter::Write(¶meters, ¶meter_string); + JSONWriter::Write(parameters, ¶meter_string); scoped_refptr<WebrtcAudioPrivateGetActiveSinkFunction> function = new WebrtcAudioPrivateGetActiveSinkFunction(); @@ -180,7 +180,7 @@ scoped_ptr<base::Value> result = InvokeGetSinks(&sink_list); std::string result_string; - JSONWriter::Write(result.get(), &result_string); + JSONWriter::Write(*result, &result_string); VLOG(2) << result_string; EXPECT_EQ(devices.size(), sink_list->GetSize()); @@ -229,7 +229,7 @@ base::ListValue parameters; AppendTabIdToRequestInfo(¶meters, tab_id); std::string parameter_string; - JSONWriter::Write(¶meters, ¶meter_string); + JSONWriter::Write(parameters, ¶meter_string); scoped_refptr<WebrtcAudioPrivateGetActiveSinkFunction> function = new WebrtcAudioPrivateGetActiveSinkFunction(); @@ -240,7 +240,7 @@ browser())); std::string result_string; - JSONWriter::Write(result.get(), &result_string); + JSONWriter::Write(*result, &result_string); EXPECT_EQ("\"\"", result_string); } @@ -253,7 +253,7 @@ AppendTabIdToRequestInfo(¶meters, tab_id); parameters.AppendString("no such id"); std::string parameter_string; - JSONWriter::Write(¶meters, ¶meter_string); + JSONWriter::Write(parameters, ¶meter_string); scoped_refptr<WebrtcAudioPrivateSetActiveSinkFunction> function = new WebrtcAudioPrivateSetActiveSinkFunction(); @@ -299,7 +299,7 @@ AppendTabIdToRequestInfo(¶meters, tab_id); parameters.AppendString(target_device); std::string parameter_string; - JSONWriter::Write(¶meters, ¶meter_string); + JSONWriter::Write(parameters, ¶meter_string); scoped_refptr<WebrtcAudioPrivateSetActiveSinkFunction> function = new WebrtcAudioPrivateSetActiveSinkFunction(); @@ -345,14 +345,14 @@ parameters.AppendString(origin.spec()); parameters.AppendString(source_id_in_origin); std::string parameter_string; - JSONWriter::Write(¶meters, ¶meter_string); + JSONWriter::Write(parameters, ¶meter_string); scoped_ptr<base::Value> result( RunFunctionAndReturnSingleResult(function.get(), parameter_string, browser())); std::string result_string; - JSONWriter::Write(result.get(), &result_string); + JSONWriter::Write(*result, &result_string); VLOG(2) << "Results: " << result_string; } }
diff --git a/chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_apitest.cc b/chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_apitest.cc index fc80b08..cb5ab5e9 100644 --- a/chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_apitest.cc +++ b/chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_apitest.cc
@@ -35,7 +35,7 @@ std::string ParamsToString(const base::ListValue& parameters) { std::string parameter_string; - EXPECT_TRUE(base::JSONWriter::Write(¶meters, ¶meter_string)); + EXPECT_TRUE(base::JSONWriter::Write(parameters, ¶meter_string)); return parameter_string; }
diff --git a/chrome/browser/extensions/dev_mode_bubble_controller.cc b/chrome/browser/extensions/dev_mode_bubble_controller.cc index e02ffc9..7f4a3e7 100644 --- a/chrome/browser/extensions/dev_mode_bubble_controller.cc +++ b/chrome/browser/extensions/dev_mode_bubble_controller.cc
@@ -41,7 +41,8 @@ ExtensionMessageBubbleController::BubbleAction user_action) override; void PerformAction(const ExtensionIdList& list) override; base::string16 GetTitle() const override; - base::string16 GetMessageBody(bool anchored_to_browser_action) const override; + base::string16 GetMessageBody(bool anchored_to_browser_action, + int extension_count) const override; base::string16 GetOverflowText( const base::string16& overflow_count) const override; GURL GetLearnMoreUrl() const override; @@ -92,7 +93,8 @@ } base::string16 DevModeBubbleDelegate::GetMessageBody( - bool anchored_to_browser_action) const { + bool anchored_to_browser_action, + int extension_count) const { return l10n_util::GetStringUTF16(IDS_EXTENSIONS_DISABLE_DEVELOPER_MODE_BODY); }
diff --git a/chrome/browser/extensions/extension_fullscreen_apitest.cc b/chrome/browser/extensions/extension_fullscreen_apitest.cc index 9abe3c3..198fd71f 100644 --- a/chrome/browser/extensions/extension_fullscreen_apitest.cc +++ b/chrome/browser/extensions/extension_fullscreen_apitest.cc
@@ -7,13 +7,19 @@ IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ExtensionFullscreenAccessFail) { - // Test that fullscreen can be accessed from an extension without permission. + // Test that fullscreen cannot be accessed from an extension without + // permission. ASSERT_TRUE(RunPlatformAppTest("fullscreen/no_permission")) << message_; } -// Disabled, a user gesture is required for fullscreen. http://crbug.com/174178 -IN_PROC_BROWSER_TEST_F(ExtensionApiTest, - DISABLED_ExtensionFullscreenAccessPass) { +#if defined(OS_MACOSX) +// Fails on MAC: http://crbug.com/480370 +#define MAYBE_ExtensionFullscreenAccessPass \ + DISABLED_ExtensionFullscreenAccessPass +#else +#define MAYBE_ExtensionFullscreenAccessPass ExtensionFullscreenAccessPass +#endif // defined(OS_MACOSX) +IN_PROC_BROWSER_TEST_F(ExtensionApiTest, MAYBE_ExtensionFullscreenAccessPass) { // Test that fullscreen can be accessed from an extension with permission. ASSERT_TRUE(RunPlatformAppTest("fullscreen/has_permission")) << message_; }
diff --git a/chrome/browser/extensions/extension_message_bubble_controller.h b/chrome/browser/extensions/extension_message_bubble_controller.h index 5e3d878..6d6e803f 100644 --- a/chrome/browser/extensions/extension_message_bubble_controller.h +++ b/chrome/browser/extensions/extension_message_bubble_controller.h
@@ -46,8 +46,10 @@ // icon, allowing the bubble to show a different message than when it is // anchored against something else (e.g. show "This extension has..." // instead of "An extension has..."). + // |extension_count| is the number of extensions being referenced. virtual base::string16 GetMessageBody( - bool anchored_to_browser_action) const = 0; + bool anchored_to_browser_action, + int extension_count) const = 0; virtual base::string16 GetOverflowText( const base::string16& overflow_count) const = 0; virtual base::string16 GetLearnMoreLabel() const;
diff --git a/chrome/browser/extensions/extension_messages_apitest.cc b/chrome/browser/extensions/extension_messages_apitest.cc index 1c4305257..9edda30 100644 --- a/chrome/browser/extensions/extension_messages_apitest.cc +++ b/chrome/browser/extensions/extension_messages_apitest.cc
@@ -994,7 +994,7 @@ base::DictionaryValue jwk_value; net::JwkSerializer::ConvertSpkiFromDerToJwk(spki, &jwk_value); std::string tls_channel_id_value; - base::JSONWriter::Write(&jwk_value, &tls_channel_id_value); + base::JSONWriter::Write(jwk_value, &tls_channel_id_value); return tls_channel_id_value; }
diff --git a/chrome/browser/extensions/extension_uninstall_dialog.cc b/chrome/browser/extensions/extension_uninstall_dialog.cc index 1e39567..0f9b728 100644 --- a/chrome/browser/extensions/extension_uninstall_dialog.cc +++ b/chrome/browser/extensions/extension_uninstall_dialog.cc
@@ -48,8 +48,6 @@ ExtensionUninstallDialog::Delegate* delegate) : profile_(profile), delegate_(delegate), - extension_(NULL), - triggering_extension_(NULL), ui_loop_(base::MessageLoop::current()) { } @@ -71,7 +69,7 @@ ? extension_misc::EXTENSION_ICON_SMALL * 2 : extension_misc::EXTENSION_ICON_LARGE; ExtensionResource image = IconsInfo::GetIconResource( - extension_, icon_size, ExtensionIconSet::MATCH_BIGGER); + extension_.get(), icon_size, ExtensionIconSet::MATCH_BIGGER); // Load the image asynchronously. The response will be sent to OnImageLoaded. ImageLoader* loader = ImageLoader::Get(profile_); @@ -83,7 +81,7 @@ ImageLoader::ImageRepresentation::NEVER_RESIZE, gfx::Size(), ui::SCALE_FACTOR_100P)); - loader->LoadImagesAsync(extension_, + loader->LoadImagesAsync(extension_.get(), images_list, base::Bind(&ExtensionUninstallDialog::OnImageLoaded, AsWeakPtr(), @@ -130,7 +128,7 @@ } bool ExtensionUninstallDialog::ShouldShowReportAbuseCheckbox() const { - return ManifestURL::UpdatesFromGallery(extension_); + return ManifestURL::UpdatesFromGallery(extension_.get()); } void ExtensionUninstallDialog::OnDialogClosed(CloseAction action) {
diff --git a/chrome/browser/extensions/extension_uninstall_dialog.h b/chrome/browser/extensions/extension_uninstall_dialog.h index 4a3a32f2..3f750281 100644 --- a/chrome/browser/extensions/extension_uninstall_dialog.h +++ b/chrome/browser/extensions/extension_uninstall_dialog.h
@@ -91,11 +91,11 @@ Delegate* delegate_; // The extension we are showing the dialog for. - const Extension* extension_; + scoped_refptr<const Extension> extension_; // The extension triggering the dialog if the dialog was shown by // chrome.management.uninstall. - const Extension* triggering_extension_; + scoped_refptr<const Extension> triggering_extension_; // The extensions icon. gfx::ImageSkia icon_;
diff --git a/chrome/browser/extensions/install_signer.cc b/chrome/browser/extensions/install_signer.cc index 1fca16a..afb88cc 100644 --- a/chrome/browser/extensions/install_signer.cc +++ b/chrome/browser/extensions/install_signer.cc
@@ -388,7 +388,7 @@ } dictionary.Set(kIdsKey, id_list.release()); std::string json; - base::JSONWriter::Write(&dictionary, &json); + base::JSONWriter::Write(dictionary, &json); if (json.empty()) { ReportErrorViaCallback(); return;
diff --git a/chrome/browser/extensions/ntp_overridden_bubble_controller.cc b/chrome/browser/extensions/ntp_overridden_bubble_controller.cc index 317b7bae..86e437d 100644 --- a/chrome/browser/extensions/ntp_overridden_bubble_controller.cc +++ b/chrome/browser/extensions/ntp_overridden_bubble_controller.cc
@@ -40,7 +40,8 @@ override; void PerformAction(const extensions::ExtensionIdList& list) override; base::string16 GetTitle() const override; - base::string16 GetMessageBody(bool anchored_to_browser_action) const override; + base::string16 GetMessageBody(bool anchored_to_browser_action, + int extension_count) const override; base::string16 GetOverflowText( const base::string16& overflow_count) const override; GURL GetLearnMoreUrl() const override; @@ -112,7 +113,8 @@ } base::string16 NtpOverriddenBubbleDelegate::GetMessageBody( - bool anchored_to_browser_action) const { + bool anchored_to_browser_action, + int extension_count) const { base::string16 body = l10n_util::GetStringUTF16(IDS_EXTENSIONS_NTP_CONTROLLED_FIRST_LINE); body += l10n_util::GetStringUTF16(
diff --git a/chrome/browser/extensions/proxy_overridden_bubble_controller.cc b/chrome/browser/extensions/proxy_overridden_bubble_controller.cc index 3d81d16b..0a40141 100644 --- a/chrome/browser/extensions/proxy_overridden_bubble_controller.cc +++ b/chrome/browser/extensions/proxy_overridden_bubble_controller.cc
@@ -44,7 +44,8 @@ ExtensionMessageBubbleController::BubbleAction user_action) override; void PerformAction(const ExtensionIdList& list) override; base::string16 GetTitle() const override; - base::string16 GetMessageBody(bool anchored_to_browser_action) const override; + base::string16 GetMessageBody(bool anchored_to_browser_action, + int extension_count) const override; base::string16 GetOverflowText( const base::string16& overflow_count) const override; GURL GetLearnMoreUrl() const override; @@ -122,7 +123,8 @@ } base::string16 ProxyOverriddenBubbleDelegate::GetMessageBody( - bool anchored_to_browser_action) const { + bool anchored_to_browser_action, + int extension_count) const { if (anchored_to_browser_action) { return l10n_util::GetStringUTF16( IDS_EXTENSIONS_PROXY_CONTROLLED_FIRST_LINE_EXTENSION_SPECIFIC);
diff --git a/chrome/browser/extensions/settings_api_bubble_controller.cc b/chrome/browser/extensions/settings_api_bubble_controller.cc index c13239f..7a4f65d 100644 --- a/chrome/browser/extensions/settings_api_bubble_controller.cc +++ b/chrome/browser/extensions/settings_api_bubble_controller.cc
@@ -46,7 +46,8 @@ ExtensionMessageBubbleController::BubbleAction user_action) override; void PerformAction(const ExtensionIdList& list) override; base::string16 GetTitle() const override; - base::string16 GetMessageBody(bool anchored_to_browser_action) const override; + base::string16 GetMessageBody(bool anchored_to_browser_action, + int extension_count) const override; base::string16 GetOverflowText( const base::string16& overflow_count) const override; GURL GetLearnMoreUrl() const override; @@ -149,7 +150,8 @@ } base::string16 SettingsApiBubbleDelegate::GetMessageBody( - bool anchored_to_browser_action) const { + bool anchored_to_browser_action, + int extension_count) const { ExtensionRegistry* registry = ExtensionRegistry::Get(profile()); const Extension* extension = registry->GetExtensionById(extension_id_, ExtensionRegistry::ENABLED);
diff --git a/chrome/browser/extensions/suspicious_extension_bubble_controller.cc b/chrome/browser/extensions/suspicious_extension_bubble_controller.cc index 94d189f..3f045e3d 100644 --- a/chrome/browser/extensions/suspicious_extension_bubble_controller.cc +++ b/chrome/browser/extensions/suspicious_extension_bubble_controller.cc
@@ -46,7 +46,8 @@ ExtensionMessageBubbleController::BubbleAction user_action) override; void PerformAction(const extensions::ExtensionIdList& list) override; base::string16 GetTitle() const override; - base::string16 GetMessageBody(bool anchored_to_browser_action) const override; + base::string16 GetMessageBody(bool anchored_to_browser_action, + int extension_count) const override; base::string16 GetOverflowText( const base::string16& overflow_count) const override; GURL GetLearnMoreUrl() const override; @@ -101,9 +102,13 @@ } base::string16 SuspiciousExtensionBubbleDelegate::GetMessageBody( - bool anchored_to_browser_action) const { - return l10n_util::GetStringFUTF16(IDS_EXTENSIONS_UNSUPPORTED_DISABLED_BODY, - l10n_util::GetStringUTF16(IDS_EXTENSION_WEB_STORE_TITLE)); + bool anchored_to_browser_action, + int extension_count) const { + int message_id = extension_count == 1 ? + IDS_EXTENSIONS_SINGLE_UNSUPPORTED_DISABLED_BODY : + IDS_EXTENSIONS_MULTIPLE_UNSUPPORTED_DISABLED_BODY; + return l10n_util::GetStringFUTF16( + message_id, l10n_util::GetStringUTF16(IDS_EXTENSION_WEB_STORE_TITLE)); } base::string16 SuspiciousExtensionBubbleDelegate::GetOverflowText(
diff --git a/chrome/browser/extensions/test_extension_environment.cc b/chrome/browser/extensions/test_extension_environment.cc index f8478fcb..6914ab0 100644 --- a/chrome/browser/extensions/test_extension_environment.cc +++ b/chrome/browser/extensions/test_extension_environment.cc
@@ -41,7 +41,7 @@ manifest->MergeDictionary(manifest_extra_dict); } else { std::string manifest_json; - base::JSONWriter::Write(&manifest_extra, &manifest_json); + base::JSONWriter::Write(manifest_extra, &manifest_json); ADD_FAILURE() << "Expected dictionary; got \"" << manifest_json << "\""; } return manifest;
diff --git a/chrome/browser/file_select_helper.cc b/chrome/browser/file_select_helper.cc index 22a8fb4a..92f3b967 100644 --- a/chrome/browser/file_select_helper.cc +++ b/chrome/browser/file_select_helper.cc
@@ -292,6 +292,16 @@ temporary_files_.clear(); } +void FileSelectHelper::CleanUpOnRenderViewHostChange() { + if (!temporary_files_.empty()) { + DeleteTemporaryFiles(); + + // Now that the temporary files have been scheduled for deletion, there + // is no longer any reason to keep this instance around. + Release(); + } +} + scoped_ptr<ui::SelectFileDialog::FileTypeInfo> FileSelectHelper::GetFileTypesFromAcceptType( const std::vector<base::string16>& accept_types) { @@ -390,16 +400,11 @@ render_view_host_ = render_view_host; web_contents_ = web_contents; notification_registrar_.RemoveAll(); - notification_registrar_.Add(this, - content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED, - content::Source<WebContents>(web_contents_)); + content::WebContentsObserver::Observe(web_contents_); notification_registrar_.Add( this, content::NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED, content::Source<RenderWidgetHost>(render_view_host_)); - notification_registrar_.Add( - this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED, - content::Source<WebContents>(web_contents_)); BrowserThread::PostTask( BrowserThread::FILE, FROM_HERE, @@ -534,29 +539,21 @@ render_view_host_ = NULL; break; } - - case content::NOTIFICATION_WEB_CONTENTS_DESTROYED: { - DCHECK(content::Source<WebContents>(source).ptr() == web_contents_); - web_contents_ = NULL; - } - - // Intentional fall through. - case content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED: - if (!temporary_files_.empty()) { - DeleteTemporaryFiles(); - - // Now that the temporary files have been scheduled for deletion, there - // is no longer any reason to keep this instance around. - Release(); - } - - break; - default: NOTREACHED(); } } +void FileSelectHelper::RenderViewHostChanged(RenderViewHost* old_host, + RenderViewHost* new_host) { + CleanUpOnRenderViewHostChange(); +} + +void FileSelectHelper::WebContentsDestroyed() { + web_contents_ = nullptr; + CleanUpOnRenderViewHostChange(); +} + // static bool FileSelectHelper::IsAcceptTypeValid(const std::string& accept_type) { // TODO(raymes): This only does some basic checks, extend to test more cases.
diff --git a/chrome/browser/file_select_helper.h b/chrome/browser/file_select_helper.h index 06672ba8..0067b8a 100644 --- a/chrome/browser/file_select_helper.h +++ b/chrome/browser/file_select_helper.h
@@ -12,6 +12,7 @@ #include "base/gtest_prod_util.h" #include "content/public/browser/notification_observer.h" #include "content/public/browser/notification_registrar.h" +#include "content/public/browser/web_contents_observer.h" #include "content/public/common/file_chooser_params.h" #include "net/base/directory_lister.h" #include "ui/shell_dialogs/select_file_dialog.h" @@ -31,10 +32,10 @@ // This class handles file-selection requests coming from WebUI elements // (via the extensions::ExtensionHost class). It implements both the // initialisation and listener functions for file-selection dialogs. -class FileSelectHelper - : public base::RefCountedThreadSafe<FileSelectHelper>, - public ui::SelectFileDialog::Listener, - public content::NotificationObserver { +class FileSelectHelper : public base::RefCountedThreadSafe<FileSelectHelper>, + public ui::SelectFileDialog::Listener, + public content::WebContentsObserver, + public content::NotificationObserver { public: // Show the file chooser dialog. @@ -105,6 +106,11 @@ const content::NotificationSource& source, const content::NotificationDetails& details) override; + // content::WebContentsObserver overrides. + void RenderViewHostChanged(content::RenderViewHost* old_host, + content::RenderViewHost* new_host) override; + void WebContentsDestroyed() override; + void EnumerateDirectory(int request_id, content::RenderViewHost* render_view_host, const base::FilePath& path); @@ -155,6 +161,9 @@ // vector. void DeleteTemporaryFiles(); + // Cleans up when the RenderViewHost of our WebContents changes. + void CleanUpOnRenderViewHostChange(); + // Helper method to get allowed extensions for select file dialog from // the specified accept types as defined in the spec: // http://whatwg.org/html/number-state.html#attr-input-accept
diff --git a/chrome/browser/guest_view/web_view/chrome_web_view_guest_delegate.cc b/chrome/browser/guest_view/web_view/chrome_web_view_guest_delegate.cc index 170a561..d2570020 100644 --- a/chrome/browser/guest_view/web_view/chrome_web_view_guest_delegate.cc +++ b/chrome/browser/guest_view/web_view/chrome_web_view_guest_delegate.cc
@@ -35,7 +35,6 @@ ChromeWebViewGuestDelegate::ChromeWebViewGuestDelegate( WebViewGuest* web_view_guest) : pending_context_menu_request_id_(0), - chromevox_injected_(false), web_view_guest_(web_view_guest), weak_ptr_factory_(this) { } @@ -83,29 +82,6 @@ new ChromePDFWebContentsHelperClient())); } -void ChromeWebViewGuestDelegate::OnDidCommitProvisionalLoadForFrame( - bool is_main_frame) { - if (is_main_frame) - chromevox_injected_ = false; -} - -void ChromeWebViewGuestDelegate::OnDidInitialize() { -#if defined(OS_CHROMEOS) - chromeos::AccessibilityManager* accessibility_manager = - chromeos::AccessibilityManager::Get(); - CHECK(accessibility_manager); - accessibility_subscription_ = accessibility_manager->RegisterCallback( - base::Bind(&ChromeWebViewGuestDelegate::OnAccessibilityStatusChanged, - weak_ptr_factory_.GetWeakPtr())); -#endif -} - -void ChromeWebViewGuestDelegate::OnDocumentLoadedInFrame( - content::RenderFrameHost* render_frame_host) { - if (!render_frame_host->GetParent()) - InjectChromeVoxIfNeeded(render_frame_host->GetRenderViewHost()); -} - void ChromeWebViewGuestDelegate::OnGuestDestroyed() { // Clean up custom context menu items for this guest. MenuManager* menu_manager = MenuManager::Get( @@ -149,33 +125,4 @@ menu_delegate->ShowMenu(pending_menu_.Pass()); } -void ChromeWebViewGuestDelegate::InjectChromeVoxIfNeeded( - content::RenderViewHost* render_view_host) { -#if defined(OS_CHROMEOS) - if (!chromevox_injected_) { - chromeos::AccessibilityManager* manager = - chromeos::AccessibilityManager::Get(); - if (manager && manager->IsSpokenFeedbackEnabled()) { - manager->InjectChromeVox(render_view_host); - chromevox_injected_ = true; - } - } -#endif -} - -#if defined(OS_CHROMEOS) -void ChromeWebViewGuestDelegate::OnAccessibilityStatusChanged( - const chromeos::AccessibilityStatusEventDetails& details) { - if (details.notification_type == chromeos::ACCESSIBILITY_MANAGER_SHUTDOWN) { - accessibility_subscription_.reset(); - } else if (details.notification_type == - chromeos::ACCESSIBILITY_TOGGLE_SPOKEN_FEEDBACK) { - if (details.enabled) - InjectChromeVoxIfNeeded(guest_web_contents()->GetRenderViewHost()); - else - chromevox_injected_ = false; - } -} -#endif - } // namespace extensions
diff --git a/chrome/browser/guest_view/web_view/chrome_web_view_guest_delegate.h b/chrome/browser/guest_view/web_view/chrome_web_view_guest_delegate.h index aae364a..d21d8a47 100644 --- a/chrome/browser/guest_view/web_view/chrome_web_view_guest_delegate.h +++ b/chrome/browser/guest_view/web_view/chrome_web_view_guest_delegate.h
@@ -29,10 +29,6 @@ // WebViewGuestDelegate implementation. bool HandleContextMenu(const content::ContextMenuParams& params) override; void OnAttachWebViewHelpers(content::WebContents* contents) override; - void OnDidCommitProvisionalLoadForFrame(bool is_main_frame) override; - void OnDidInitialize() override; - void OnDocumentLoadedInFrame( - content::RenderFrameHost* render_frame_host) override; void OnGuestDestroyed() override; void OnShowContextMenu(int request_id, const MenuItemVector* items) override; @@ -47,31 +43,14 @@ static scoped_ptr<base::ListValue> MenuModelToValue( const ui::SimpleMenuModel& menu_model); - void InjectChromeVoxIfNeeded(content::RenderViewHost* render_view_host); - -#if defined(OS_CHROMEOS) - // Notification of a change in the state of an accessibility setting. - void OnAccessibilityStatusChanged( - const chromeos::AccessibilityStatusEventDetails& details); -#endif - // A counter to generate a unique request id for a context menu request. // We only need the ids to be unique for a given WebViewGuest. int pending_context_menu_request_id_; - // Set to |true| if ChromeVox was already injected in main frame. - bool chromevox_injected_; - // Holds the RenderViewContextMenuBase that has been built but yet to be // shown. This is .reset() after ShowContextMenu(). scoped_ptr<RenderViewContextMenuBase> pending_menu_; -#if defined(OS_CHROMEOS) - // Subscription to receive notifications on changes to a11y settings. - scoped_ptr<chromeos::AccessibilityStatusSubscription> - accessibility_subscription_; -#endif - WebViewGuest* const web_view_guest_; // This is used to ensure pending tasks will not fire after this object is @@ -84,4 +63,3 @@ } // namespace extensions #endif // CHROME_BROWSER_GUEST_VIEW_WEB_VIEW_CHROME_WEB_VIEW_GUEST_DELEGATE_H_ -
diff --git a/chrome/browser/io_thread.cc b/chrome/browser/io_thread.cc index 55767a7..46d0e3e8 100644 --- a/chrome/browser/io_thread.cc +++ b/chrome/browser/io_thread.cc
@@ -1342,9 +1342,6 @@ ShouldEnableQuicPortSelection(command_line)); globals->quic_connection_options = GetQuicConnectionOptions(command_line, quic_trial_params); - if (ShouldEnableQuicPacing(command_line, quic_trial_params)) { - globals->quic_connection_options.push_back(net::kPACE); - } } size_t max_packet_length = GetQuicMaxPacketLength(command_line, @@ -1439,20 +1436,6 @@ return false; // Default to disabling port selection on all channels. } -bool IOThread::ShouldEnableQuicPacing( - const base::CommandLine& command_line, - const VariationParameters& quic_trial_params) { - if (command_line.HasSwitch(switches::kEnableQuicPacing)) - return true; - - if (command_line.HasSwitch(switches::kDisableQuicPacing)) - return false; - - return LowerCaseEqualsASCII( - GetVariationParam(quic_trial_params, "enable_pacing"), - "true"); -} - net::QuicTagVector IOThread::GetQuicConnectionOptions( const base::CommandLine& command_line, const VariationParameters& quic_trial_params) {
diff --git a/chrome/browser/io_thread.h b/chrome/browser/io_thread.h index ca55e19c..0b94438 100644 --- a/chrome/browser/io_thread.h +++ b/chrome/browser/io_thread.h
@@ -346,12 +346,6 @@ static bool ShouldEnableQuicPortSelection( const base::CommandLine& command_line); - // Returns true if QUIC packet pacing should be negotiated during the - // QUIC handshake. - static bool ShouldEnableQuicPacing( - const base::CommandLine& command_line, - const VariationParameters& quic_trial_params); - // Returns true if QUIC should always require handshake confirmation during // the QUIC handshake. static bool ShouldQuicAlwaysRequireHandshakeConfirmation(
diff --git a/chrome/browser/io_thread_unittest.cc b/chrome/browser/io_thread_unittest.cc index 13b21fc6..03e3dc4 100644 --- a/chrome/browser/io_thread_unittest.cc +++ b/chrome/browser/io_thread_unittest.cc
@@ -80,7 +80,6 @@ }; TEST_F(IOThreadTest, InitializeNetworkSessionParamsFromGlobals) { - globals_.quic_connection_options.push_back(net::kPACE); globals_.quic_connection_options.push_back(net::kTBBR); globals_.quic_connection_options.push_back(net::kTIME); @@ -220,17 +219,6 @@ EXPECT_FALSE(IOThread::ShouldEnableQuicForDataReductionProxy()); } -TEST_F(IOThreadTest, EnablePacingFromCommandLine) { - command_line_.AppendSwitch("enable-quic"); - command_line_.AppendSwitch("enable-quic-pacing"); - - ConfigureQuicGlobals(); - net::HttpNetworkSession::Params params; - InitializeNetworkSessionParams(¶ms); - net::QuicTagVector options; - options.push_back(net::kPACE); - EXPECT_EQ(options, params.quic_connection_options); -} TEST_F(IOThreadTest, DisableInsecureQuicFromFieldTrialParams) { field_trial_group_ = "Enabled"; field_trial_params_["disable_insecure_quic"] = "true"; @@ -241,18 +229,6 @@ EXPECT_TRUE(params.disable_insecure_quic); } -TEST_F(IOThreadTest, EnablePacingFromFieldTrialParams) { - field_trial_group_ = "Enabled"; - field_trial_params_["enable_pacing"] = "true"; - - ConfigureQuicGlobals(); - net::HttpNetworkSession::Params params; - InitializeNetworkSessionParams(¶ms); - net::QuicTagVector options; - options.push_back(net::kPACE); - EXPECT_EQ(options, params.quic_connection_options); -} - TEST_F(IOThreadTest, PacketLengthFromCommandLine) { command_line_.AppendSwitch("enable-quic"); command_line_.AppendSwitchASCII("quic-max-packet-length", "1450"); @@ -303,14 +279,13 @@ TEST_F(IOThreadTest, QuicConnectionOptionsFromCommandLine) { command_line_.AppendSwitch("enable-quic"); command_line_.AppendSwitchASCII("quic-connection-options", - "PACE,TIME,TBBR,REJ"); + "TIME,TBBR,REJ"); ConfigureQuicGlobals(); net::HttpNetworkSession::Params params; InitializeNetworkSessionParams(¶ms); net::QuicTagVector options; - options.push_back(net::kPACE); options.push_back(net::kTIME); options.push_back(net::kTBBR); options.push_back(net::kREJ); @@ -319,14 +294,13 @@ TEST_F(IOThreadTest, QuicConnectionOptionsFromFieldTrialParams) { field_trial_group_ = "Enabled"; - field_trial_params_["connection_options"] = "PACE,TIME,TBBR,REJ"; + field_trial_params_["connection_options"] = "TIME,TBBR,REJ"; ConfigureQuicGlobals(); net::HttpNetworkSession::Params params; InitializeNetworkSessionParams(¶ms); net::QuicTagVector options; - options.push_back(net::kPACE); options.push_back(net::kTIME); options.push_back(net::kTBBR); options.push_back(net::kREJ);
diff --git a/chrome/browser/lifetime/application_lifetime.cc b/chrome/browser/lifetime/application_lifetime.cc index 0d80bd11..261e00e0 100644 --- a/chrome/browser/lifetime/application_lifetime.cc +++ b/chrome/browser/lifetime/application_lifetime.cc
@@ -33,7 +33,6 @@ #include "chrome/common/chrome_constants.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/pref_names.h" -#include "content/public/browser/browser_shutdown.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/navigation_details.h" #include "content/public/browser/notification_service.h"
diff --git a/chrome/browser/local_discovery/privet_http_unittest.cc b/chrome/browser/local_discovery/privet_http_unittest.cc index f8d5dbe..9fe8500d 100644 --- a/chrome/browser/local_discovery/privet_http_unittest.cc +++ b/chrome/browser/local_discovery/privet_http_unittest.cc
@@ -222,7 +222,7 @@ std::string result = json; scoped_ptr<base::Value> value(base::JSONReader::Read(result)); DCHECK(value); - base::JSONWriter::Write(value.get(), &result); + base::JSONWriter::Write(*value, &result); return result; }
diff --git a/chrome/browser/local_discovery/privetv3_session.cc b/chrome/browser/local_discovery/privetv3_session.cc index 85a9a42..b278279 100644 --- a/chrome/browser/local_discovery/privetv3_session.cc +++ b/chrome/browser/local_discovery/privetv3_session.cc
@@ -410,7 +410,7 @@ on_post_data_.Run(input); std::string json; base::JSONWriter::WriteWithOptions( - &input, base::JSONWriter::OPTIONS_PRETTY_PRINT, &json); + input, base::JSONWriter::OPTIONS_PRETTY_PRINT, &json); PrivetURLFetcher* fetcher = CreateFetcher(api, net::URLFetcher::RequestType::POST, callback); fetcher->SetUploadData(cloud_print::kContentTypeJSON, json);
diff --git a/chrome/browser/media/router/BUILD.gn b/chrome/browser/media/router/BUILD.gn index 6ee9a6f..62caec6 100644 --- a/chrome/browser/media/router/BUILD.gn +++ b/chrome/browser/media/router/BUILD.gn
@@ -5,85 +5,25 @@ import("//testing/test.gni") import("//third_party/mojo/src/mojo/public/tools/bindings/mojom.gni") -source_set("router") { - deps = [ - ":router_core", - ] -} +gypi_values = exec_script("//build/gypi_to_gn.py", + [ rebase_path("media_router.gypi") ], + "scope", + [ "media_router.gypi" ]) -source_set("router_core") { +# TODO(mfoltz): Fix problem that requires explicitly listing //skia +source_set("router") { deps = [ ":mojo_bindings", "//base", + "//extensions/browser", "//components/keyed_service/core", "//third_party/mojo/src/mojo/public/cpp/bindings", + "//skia", "//url", ] - sources = [ - "create_session_request.cc", - "create_session_request.h", - "issue.cc", - "issue.h", - "issue_manager.cc", - "issue_manager.h", - "issues_observer.h", - "media_route.cc", - "media_route.h", - "media_route_id.h", - "media_router.h", - "media_router_type_converters.cc", - "media_router_type_converters.h", - "media_routes_observer.cc", - "media_routes_observer.h", - "media_sink.cc", - "media_sink.h", - "media_sinks_observer.cc", - "media_sinks_observer.h", - "media_source.cc", - "media_source.h", - "media_source_helper.cc", - "media_source_helper.h", - "presentation_media_sinks_observer.cc", - "presentation_media_sinks_observer.h", - "route_id_manager.cc", - "route_id_manager.h", - ] -} - -source_set("unit_tests") { - testonly = true - deps = [ - ":router_core", - ":unit_tests_support", - "//base/test:test_support", - "//chrome/test:test_support", - "//testing/gmock", - "//testing/gtest", - "//third_party/cld_2:cld2_static", - "//third_party/mojo/src/mojo/public/cpp/bindings", - ] - sources = [ - "media_route_unittest.cc", - "media_router_type_converters_unittest.cc", - "media_sink_unittest.cc", - "media_source_unittest.cc", - "presentation_media_sinks_observer_unittest.cc", - "route_id_manager_unittest.cc", - ] -} - -source_set("unit_tests_support") { - testonly = true - deps = [ - ":router_core", - "//testing/gmock", - ] - sources = [ - "mock_media_router.cc", - "mock_media_router.h", - "mock_screen_availability_listener.cc", - "mock_screen_availability_listener.h", - ] + sources = rebase_path(gypi_values.media_router_sources, + ".", + "//chrome/browser/media/router") } mojom("mojo_bindings") { @@ -92,13 +32,15 @@ ] } -# Optional standalone test binary, for faster isolated builds. -test("unit_tests_main") { +source_set("test_support") { + testonly = true deps = [ - ":unit_tests", - "//testing/gmock:gmock_main", + ":mojo_bindings", + ":router", + "//chrome/test:test_support", + "//testing/gmock", ] - sources = [ - ":unittest_files", - ] + sources = rebase_path(gypi_values.media_router_test_support_sources, + ".", + "//chrome/browser/media/router") }
diff --git a/chrome/browser/media/router/media_router.gyp b/chrome/browser/media/router/media_router.gyp index 33e8bc8..7f83664 100644 --- a/chrome/browser/media/router/media_router.gyp +++ b/chrome/browser/media/router/media_router.gyp
@@ -3,8 +3,12 @@ # found in the LICENSE file. { + 'includes': [ + 'media_router.gypi', + ], 'targets': [ { + # GN version: //chrome/browser/media/router:router 'target_name': 'media_router', 'type': 'static_library', 'include_dirs': [ @@ -13,43 +17,20 @@ ], 'dependencies': [ # media_router_type_converters.h needs the generated file. - ':media_router_mojo_gen', - ':media_router_mojo', + 'media_router_mojo_gen', + 'media_router_mojo', '<(DEPTH)/base/base.gyp:base', + '<(DEPTH)/components/components.gyp:keyed_service_core', + '<(DEPTH)/extensions/extensions.gyp:extensions_browser', + '<(DEPTH)/skia/skia.gyp:skia', '<(DEPTH)/url/url.gyp:url_lib', ], 'sources': [ - 'create_session_request.cc', - 'create_session_request.h', - 'issue.cc', - 'issue.h', - 'issue_manager.cc', - 'issue_manager.h', - 'issue_observer.h', - 'media_route.cc', - 'media_route.h', - 'media_route_id.h', - 'media_router.h', - 'media_router_type_converters.cc', - 'media_router_type_converters.h', - 'media_routes_observer.cc', - 'media_routes_observer.h', - 'media_sink.cc', - 'media_sink.h', - 'media_sinks_observer.cc', - 'media_sinks_observer.h', - 'media_source.cc', - 'media_source.h', - 'media_source_helper.cc', - 'media_source_helper.h', - 'presentation_media_sinks_observer.cc', - 'presentation_media_sinks_observer.h', - 'route_id_manager.cc', - 'route_id_manager.h', + '<@(media_router_sources)', ], }, { - # Mojo bindings for the Media Router internal API. + # Mojo compiler for the Media Router internal API. 'target_name': 'media_router_mojo_gen', 'type': 'none', 'sources': [ @@ -67,9 +48,6 @@ ], 'dependencies': [ 'media_router_mojo_gen', - '<(DEPTH)/mojo/mojo_base.gyp:mojo_common_lib', - '<(DEPTH)/mojo/mojo_base.gyp:mojo_environment_chromium', - '<(DEPTH)/third_party/mojo/mojo_public.gyp:mojo_cpp_bindings', ], 'sources': [ '<(SHARED_INTERMEDIATE_DIR)/chrome/browser/media/router/media_router.mojom.cc', @@ -77,23 +55,21 @@ ], }, { + # GN version: //chrome/browser/media/router:test_support 'target_name': 'media_router_test_support', 'type': 'static_library', 'include_dirs': [ '<(DEPTH)', ], 'dependencies': [ - ':media_router', + 'media_router', + 'media_router_mojo', '<(DEPTH)/base/base.gyp:base', '<(DEPTH)/testing/gmock.gyp:gmock', ], 'sources': [ - 'mock_media_router.cc', - 'mock_media_router.h', - 'mock_screen_availability_listener.cc', - 'mock_screen_availability_listener.h', + '<@(media_router_test_support_sources)', ], }, - ], }
diff --git a/chrome/browser/media/router/media_router.gypi b/chrome/browser/media/router/media_router.gypi new file mode 100644 index 0000000..702b04a --- /dev/null +++ b/chrome/browser/media/router/media_router.gypi
@@ -0,0 +1,42 @@ +# Copyright (c) 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +{ + 'variables': { + # File lists shared with GN build. + 'media_router_sources': [ + 'create_session_request.cc', + 'create_session_request.h', + 'issue.cc', + 'issue.h', + 'issue_manager.cc', + 'issue_manager.h', + 'issues_observer.h', + 'media_route.cc', + 'media_route.h', + 'media_route_id.h', + 'media_router.h', + 'media_router_type_converters.cc', + 'media_router_type_converters.h', + 'media_routes_observer.cc', + 'media_routes_observer.h', + 'media_sink.cc', + 'media_sink.h', + 'media_sinks_observer.cc', + 'media_sinks_observer.h', + 'media_source.cc', + 'media_source.h', + 'media_source_helper.cc', + 'media_source_helper.h', + 'presentation_media_sinks_observer.cc', + 'presentation_media_sinks_observer.h', + ], + 'media_router_test_support_sources': [ + 'mock_media_router.cc', + 'mock_media_router.h', + 'mock_screen_availability_listener.cc', + 'mock_screen_availability_listener.h', + ], + }, +}
diff --git a/chrome/browser/media/router/media_router_tests.gypi b/chrome/browser/media/router/media_router_tests.gypi deleted file mode 100644 index 3ef86c75..0000000 --- a/chrome/browser/media/router/media_router_tests.gypi +++ /dev/null
@@ -1,24 +0,0 @@ -# Copyright 2015 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -{ - 'sources': [ - '../../ui/webui/media_router/media_cast_mode_unittest.cc', - '../../ui/webui/media_router/media_router_test.cc', - '../../ui/webui/media_router/media_router_test.h', - '../../ui/webui/media_router/media_router_dialog_controller_unittest.cc', - 'issue_manager_unittest.cc', - 'issue_unittest.cc', - 'media_route_unittest.cc', - 'media_router_type_converters_unittest.cc', - 'media_sink_unittest.cc', - 'media_source_helper_unittest.cc', - 'media_source_unittest.cc', - "presentation_media_sinks_observer_unittest.cc", - 'route_id_manager_unittest.cc', - ], - 'dependencies': [ - 'browser/media/router/media_router.gyp:media_router_test_support', - ], -}
diff --git a/chrome/browser/media/router/route_id_manager.cc b/chrome/browser/media/router/route_id_manager.cc deleted file mode 100644 index 9735257..0000000 --- a/chrome/browser/media/router/route_id_manager.cc +++ /dev/null
@@ -1,27 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/media/router/route_id_manager.h" - -#include "base/memory/singleton.h" -#include "base/strings/string_number_conversions.h" -#include "chrome/browser/media/router/media_route.h" - -namespace media_router { - -const char kLocalRoutePrefix[] = "route-local-"; - -RouteIDManager::RouteIDManager() : next_local_id_(0) {} - -std::string RouteIDManager::ForLocalRoute() { - DCHECK(CalledOnValidThread()); - return kLocalRoutePrefix + base::Uint64ToString(next_local_id_++); -} - -// static -RouteIDManager* RouteIDManager::GetInstance() { - return Singleton<RouteIDManager>::get(); -} - -} // namespace media_router
diff --git a/chrome/browser/media/router/route_id_manager.h b/chrome/browser/media/router/route_id_manager.h deleted file mode 100644 index 8497bd1..0000000 --- a/chrome/browser/media/router/route_id_manager.h +++ /dev/null
@@ -1,42 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_MEDIA_ROUTER_ROUTE_ID_MANAGER_H_ -#define CHROME_BROWSER_MEDIA_ROUTER_ROUTE_ID_MANAGER_H_ - -#include <string> - -#include "base/basictypes.h" -#include "base/gtest_prod_util.h" -#include "base/memory/singleton.h" -#include "base/threading/non_thread_safe.h" - -namespace media_router { - -class MediaRoute; - -// Shared singleton which coordinates the assignment of unique IDs to -// MediaRoute objects. -// Class is not threadsafe; IDs should be created on the same thread. -class RouteIDManager : public base::NonThreadSafe { - public: - static RouteIDManager* GetInstance(); - - std::string ForLocalRoute(); - - private: - FRIEND_TEST_ALL_PREFIXES(RouteIDManagerTest, ForLocalRoute); - friend struct DefaultSingletonTraits<RouteIDManager>; - - RouteIDManager(); - - // Monotonically increasing ID number. - uint64 next_local_id_; - - DISALLOW_COPY_AND_ASSIGN(RouteIDManager); -}; - -} // namespace media_router - -#endif // CHROME_BROWSER_MEDIA_ROUTER_ROUTE_ID_MANAGER_H_
diff --git a/chrome/browser/media/router/route_id_manager_unittest.cc b/chrome/browser/media/router/route_id_manager_unittest.cc deleted file mode 100644 index 46da03e..0000000 --- a/chrome/browser/media/router/route_id_manager_unittest.cc +++ /dev/null
@@ -1,20 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/media/router/route_id_manager.h" -#include "testing/gmock/include/gmock/gmock.h" - -namespace media_router { - -TEST(RouteIDManagerTest, ForLocalRoute) { - // Singleton instance is left unused for better test isolation. - RouteIDManager manager1; - EXPECT_EQ("route-local-0", manager1.ForLocalRoute()); - EXPECT_EQ("route-local-1", manager1.ForLocalRoute()); - - RouteIDManager manager2; - EXPECT_EQ("route-local-0", manager2.ForLocalRoute()); -} - -} // namespace media_router
diff --git a/chrome/browser/net/pref_proxy_config_tracker_impl.cc b/chrome/browser/net/pref_proxy_config_tracker_impl.cc index 49161ba..f839949 100644 --- a/chrome/browser/net/pref_proxy_config_tracker_impl.cc +++ b/chrome/browser/net/pref_proxy_config_tracker_impl.cc
@@ -5,6 +5,7 @@ #include "chrome/browser/net/pref_proxy_config_tracker_impl.h" #include "base/bind.h" +#include "base/metrics/histogram_macros.h" #include "base/prefs/pref_registry_simple.h" #include "base/prefs/pref_service.h" #include "base/strings/string_util.h" @@ -30,10 +31,8 @@ } // Removes any Data Reduction Proxies like *.googlezip.net from |proxy_list|. -void RemoveGooglezipDataReductionProxiesFromList(net::ProxyList* proxy_list) { - if (proxy_list->IsEmpty()) - return; - +// Returns the number of proxies that were removed from |proxy_list|. +size_t RemoveGooglezipDataReductionProxiesFromList(net::ProxyList* proxy_list) { bool found_googlezip_proxy = false; for (const net::ProxyServer& proxy : proxy_list->GetAll()) { if (IsGooglezipDataReductionProxy(proxy)) { @@ -42,17 +41,21 @@ } } if (!found_googlezip_proxy) - return; + return 0; + size_t num_removed_proxies = 0; net::ProxyList replacement_list; for (const net::ProxyServer& proxy : proxy_list->GetAll()) { if (!IsGooglezipDataReductionProxy(proxy)) replacement_list.AddProxyServer(proxy); + else + ++num_removed_proxies; } if (replacement_list.IsEmpty()) replacement_list.AddProxyServer(net::ProxyServer::Direct()); *proxy_list = replacement_list; + return num_removed_proxies; } // Remove any Data Reduction Proxies like *.googlezip.net from |proxy_rules|. @@ -61,17 +64,23 @@ // the Data Reduction Proxy without adding any of the necessary authentication // headers or applying the Data Reduction Proxy bypass logic. See // http://crbug.com/476610. -// TODO(sclittle): Add UMA to record how often this method is called, and how -// often it actually removes a *.googlezip.net proxy. This method should be -// removed once it stops actually finding and removing *.googlezip.net proxies -// from the proxy rules. +// TODO(sclittle): This method should be removed once the UMA indicates that +// *.googlezip.net proxies are no longer present in the |proxy_rules|. void RemoveGooglezipDataReductionProxies( net::ProxyConfig::ProxyRules* proxy_rules) { - RemoveGooglezipDataReductionProxiesFromList(&proxy_rules->fallback_proxies); - RemoveGooglezipDataReductionProxiesFromList(&proxy_rules->proxies_for_ftp); - RemoveGooglezipDataReductionProxiesFromList(&proxy_rules->proxies_for_http); - RemoveGooglezipDataReductionProxiesFromList(&proxy_rules->proxies_for_https); - RemoveGooglezipDataReductionProxiesFromList(&proxy_rules->single_proxies); + size_t num_removed_proxies = + RemoveGooglezipDataReductionProxiesFromList( + &proxy_rules->fallback_proxies) + + RemoveGooglezipDataReductionProxiesFromList( + &proxy_rules->proxies_for_ftp) + + RemoveGooglezipDataReductionProxiesFromList( + &proxy_rules->proxies_for_http) + + RemoveGooglezipDataReductionProxiesFromList( + &proxy_rules->proxies_for_https) + + RemoveGooglezipDataReductionProxiesFromList(&proxy_rules->single_proxies); + + UMA_HISTOGRAM_COUNTS_100("Net.PrefProxyConfig.GooglezipProxyRemovalCount", + num_removed_proxies); } } // namespace
diff --git a/chrome/browser/net/pref_proxy_config_tracker_impl_unittest.cc b/chrome/browser/net/pref_proxy_config_tracker_impl_unittest.cc index 44a3c005b..793e9e7c 100644 --- a/chrome/browser/net/pref_proxy_config_tracker_impl_unittest.cc +++ b/chrome/browser/net/pref_proxy_config_tracker_impl_unittest.cc
@@ -11,6 +11,7 @@ #include "base/message_loop/message_loop.h" #include "base/prefs/pref_registry_simple.h" #include "base/prefs/testing_pref_service.h" +#include "base/test/histogram_tester.h" #include "chrome/browser/prefs/pref_service_mock_factory.h" #include "chrome/browser/prefs/proxy_config_dictionary.h" #include "chrome/common/chrome_switches.h" @@ -310,39 +311,58 @@ "https://proxy.googlezip.net:443,compress.googlezip.net," "https://proxy-dev.googlezip.net:443,proxy-dev.googlezip.net," "quic://proxy.googlezip.net"; + const int kNumDataReductionProxies = 5; struct { std::string initial_proxy_rules; const char* http_proxy_info; const char* https_proxy_info; const char* ftp_proxy_info; + int expected_num_removed_proxies; } test_cases[] = { {"http=foopyhttp," + kDataReductionProxies + ",direct://;https=foopyhttps," + kDataReductionProxies + ",direct://;ftp=foopyftp," + kDataReductionProxies + ",direct://", "foopyhttp;direct://", "foopyhttps;direct://", - "foopyftp;direct://"}, + "foopyftp;direct://", + kNumDataReductionProxies * 3}, {"foopy," + kDataReductionProxies + ",direct://", "foopy;direct://", "foopy;direct://", - "foopy;direct://"}, + "foopy;direct://", + kNumDataReductionProxies}, {"http=" + kDataReductionProxies + ";https=" + kDataReductionProxies + ";ftp=" + kDataReductionProxies, "direct://", "direct://", - "direct://"}, + "direct://", + kNumDataReductionProxies * 3}, {"http=" + kDataReductionProxies + ",foopy,direct://", "foopy;direct://", "direct://", - "direct://"}, + "direct://", + kNumDataReductionProxies}, + + {"foopy,direct://", + "foopy;direct://", + "foopy;direct://", + "foopy;direct://", + 0}, + + {"direct://", + "direct://", + "direct://", + "direct://", + 0}, }; // Test setting the proxy from a user pref. for (const auto& test : test_cases) { + base::HistogramTester histogram_tester; pref_service_->SetUserPref(prefs::kProxy, ProxyConfigDictionary::CreateFixedServers( test.initial_proxy_rules, std::string())); @@ -351,6 +371,9 @@ net::ProxyConfig config; EXPECT_EQ(net::ProxyConfigService::CONFIG_VALID, proxy_config_service_->GetLatestProxyConfig(&config)); + histogram_tester.ExpectUniqueSample( + "Net.PrefProxyConfig.GooglezipProxyRemovalCount", + test.expected_num_removed_proxies, 1); CheckResolvedProxyMatches(&config, GURL("http://google.com"), test.http_proxy_info);
diff --git a/chrome/browser/net/proxy_service_factory.cc b/chrome/browser/net/proxy_service_factory.cc index 96293f8a..7ec1ac3 100644 --- a/chrome/browser/net/proxy_service_factory.cc +++ b/chrome/browser/net/proxy_service_factory.cc
@@ -7,6 +7,7 @@ #include <string> #include "base/command_line.h" +#include "base/metrics/field_trial.h" #include "base/strings/string_number_conversions.h" #include "base/threading/thread.h" #include "chrome/browser/browser_process.h" @@ -38,6 +39,23 @@ using content::BrowserThread; +namespace { + +#if !defined(OS_ANDROID) +bool EnableOutOfProcessV8Pac(const base::CommandLine& command_line) { + const std::string group_name = + base::FieldTrialList::FindFullName("OutOfProcessPac"); + + if (command_line.HasSwitch(switches::kDisableOutOfProcessPac)) + return false; + if (command_line.HasSwitch(switches::kV8PacMojoOutOfProcess)) + return true; + return group_name == "Enabled"; +} +#endif // !defined(OS_ANDROID) + +} // namespace + // static net::ProxyConfigService* ProxyServiceFactory::CreateProxyConfigService( PrefProxyConfigTracker* tracker) { @@ -144,14 +162,16 @@ #endif #if !defined(OS_ANDROID) - if (command_line.HasSwitch(switches::kV8PacMojoOutOfProcess)) { - proxy_service = net::CreateProxyServiceUsingMojoFactory( - UtilityProcessMojoProxyResolverFactory::GetInstance(), + // In-process Mojo PAC can only be set on the command line, so its presence + // should override other options. + if (command_line.HasSwitch(switches::kV8PacMojoInProcess)) { + proxy_service = net::CreateProxyServiceUsingMojoInProcess( proxy_config_service, new net::ProxyScriptFetcherImpl(context), dhcp_proxy_script_fetcher, context->host_resolver(), net_log, network_delegate); - } else if (command_line.HasSwitch(switches::kV8PacMojoInProcess)) { - proxy_service = net::CreateProxyServiceUsingMojoInProcess( + } else if (EnableOutOfProcessV8Pac(command_line)) { + proxy_service = net::CreateProxyServiceUsingMojoFactory( + UtilityProcessMojoProxyResolverFactory::GetInstance(), proxy_config_service, new net::ProxyScriptFetcherImpl(context), dhcp_proxy_script_fetcher, context->host_resolver(), net_log, network_delegate);
diff --git a/chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_io_data.cc b/chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_io_data.cc index c70e581..08a6344 100644 --- a/chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_io_data.cc +++ b/chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_io_data.cc
@@ -7,6 +7,8 @@ #include "base/prefs/pref_service.h" #include "chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_settings.h" #include "chrome/common/chrome_content_client.h" +#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_config_retrieval_params.h" +#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_experiments_stats.h" #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.h" #include "components/data_reduction_proxy/core/common/data_reduction_proxy_params.h" #include "components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h" @@ -61,6 +63,9 @@ DataReductionProxyChromeSettings::GetClient(), flags, net_log, io_task_runner, ui_task_runner, enabled, enable_quic, GetUserAgent())); + data_reduction_proxy_io_data->experiments_stats()->InitializeOnUIThread( + data_reduction_proxy::DataReductionProxyConfigRetrievalParams::Create( + prefs)); #if defined(ENABLE_DATA_REDUCTION_PROXY_DEBUGGING) scoped_ptr<data_reduction_proxy::ContentDataReductionProxyDebugUIService>
diff --git a/chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_settings.cc b/chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_settings.cc index 43188184..db900de 100644 --- a/chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_settings.cc +++ b/chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_settings.cc
@@ -138,7 +138,7 @@ profile_prefs, ui_task_runner, commit_delay)); scoped_ptr<data_reduction_proxy::DataReductionProxyService> service = make_scoped_ptr(new data_reduction_proxy::DataReductionProxyService( - compression_stats.Pass(), this, request_context_getter, + compression_stats.Pass(), this, profile_prefs, request_context_getter, io_data->io_task_runner())); data_reduction_proxy::DataReductionProxySettings:: InitDataReductionProxySettings(profile_prefs, io_data, service.Pass());
diff --git a/chrome/browser/net/utility_process_mojo_proxy_resolver_factory.cc b/chrome/browser/net/utility_process_mojo_proxy_resolver_factory.cc index 0be9eef..73ffff9 100644 --- a/chrome/browser/net/utility_process_mojo_proxy_resolver_factory.cc +++ b/chrome/browser/net/utility_process_mojo_proxy_resolver_factory.cc
@@ -64,6 +64,7 @@ const mojo::String& pac_script, mojo::InterfaceRequest<net::interfaces::ProxyResolver> req, net::interfaces::HostResolverPtr host_resolver, + net::interfaces::ProxyResolverErrorObserverPtr error_observer, net::interfaces::ProxyResolverFactoryRequestClientPtr client) { DCHECK(thread_checker_.CalledOnValidThread()); if (!resolver_factory_) @@ -78,7 +79,8 @@ idle_timer_.Stop(); num_proxy_resolvers_++; resolver_factory_->CreateResolver(pac_script, req.Pass(), - host_resolver.Pass(), client.Pass()); + host_resolver.Pass(), error_observer.Pass(), + client.Pass()); return make_scoped_ptr(new base::ScopedClosureRunner( base::Bind(&UtilityProcessMojoProxyResolverFactory::OnResolverDestroyed, base::Unretained(this))));
diff --git a/chrome/browser/net/utility_process_mojo_proxy_resolver_factory.h b/chrome/browser/net/utility_process_mojo_proxy_resolver_factory.h index 2b796a2c..f6e9e21 100644 --- a/chrome/browser/net/utility_process_mojo_proxy_resolver_factory.h +++ b/chrome/browser/net/utility_process_mojo_proxy_resolver_factory.h
@@ -33,6 +33,7 @@ const mojo::String& pac_script, mojo::InterfaceRequest<net::interfaces::ProxyResolver> req, net::interfaces::HostResolverPtr host_resolver, + net::interfaces::ProxyResolverErrorObserverPtr error_observer, net::interfaces::ProxyResolverFactoryRequestClientPtr client) override; private:
diff --git a/chrome/browser/password_manager/generated_password_saved_infobar_delegate_android.cc b/chrome/browser/password_manager/generated_password_saved_infobar_delegate_android.cc index f6dd43c..59df849 100644 --- a/chrome/browser/password_manager/generated_password_saved_infobar_delegate_android.cc +++ b/chrome/browser/password_manager/generated_password_saved_infobar_delegate_android.cc
@@ -22,7 +22,7 @@ GeneratedPasswordSavedInfoBarDelegateAndroid() : button_label_(l10n_util::GetStringUTF16(IDS_OK)) { base::string16 link = l10n_util::GetStringUTF16( - IDS_MANAGE_PASSWORDS_CONFIRM_GENERATED_LINK); + IDS_MANAGE_PASSWORDS_LINK); size_t offset; message_text_ = l10n_util::GetStringFUTF16( IDS_MANAGE_PASSWORDS_CONFIRM_GENERATED_TEXT_INFOBAR, link, &offset);
diff --git a/chrome/browser/password_manager/password_store_factory.cc b/chrome/browser/password_manager/password_store_factory.cc index 8e640816..13d0e74d 100644 --- a/chrome/browser/password_manager/password_store_factory.cc +++ b/chrome/browser/password_manager/password_store_factory.cc
@@ -193,6 +193,21 @@ } } +// static +void PasswordStoreFactory::TrimOrDeleteAffiliationCache(Profile* profile) { + scoped_refptr<PasswordStore> password_store = + GetForProfile(profile, ServiceAccessType::EXPLICIT_ACCESS); + if (password_store && password_store->HasAffiliatedMatchHelper()) { + password_store->TrimAffiliationCache(); + } else { + scoped_refptr<base::SingleThreadTaskRunner> db_thread_runner( + content::BrowserThread::GetMessageLoopProxyForThread( + content::BrowserThread::DB)); + password_manager::AffiliationService::DeleteCache( + GetAffiliationDatabasePath(profile), db_thread_runner.get()); + } +} + PasswordStoreFactory::PasswordStoreFactory() : BrowserContextKeyedServiceFactory( "PasswordStore",
diff --git a/chrome/browser/password_manager/password_store_factory.h b/chrome/browser/password_manager/password_store_factory.h index 25bd747..5fab46e 100644 --- a/chrome/browser/password_manager/password_store_factory.h +++ b/chrome/browser/password_manager/password_store_factory.h
@@ -62,6 +62,10 @@ // that syncing passwords has just started or ended for |profile|. static void OnPasswordsSyncedStatePotentiallyChanged(Profile* profile); + // Trims the affiliation cache for |profile| if affiliation-based matching is + // enabled, and completely deletes it otherwise. + static void TrimOrDeleteAffiliationCache(Profile* profile); + private: friend struct DefaultSingletonTraits<PasswordStoreFactory>;
diff --git a/chrome/browser/password_manager/save_password_infobar_delegate.cc b/chrome/browser/password_manager/save_password_infobar_delegate.cc index 7e2f2d8..299b246 100644 --- a/chrome/browser/password_manager/save_password_infobar_delegate.cc +++ b/chrome/browser/password_manager/save_password_infobar_delegate.cc
@@ -44,7 +44,7 @@ SavePasswordInfoBarDelegate* infobar_delegate = new SavePasswordInfoBarDelegate( form_to_save.Pass(), uma_histogram_suffix, source_type, - password_bubble_experiment::IsEnabledSmartLockBranding(profile)); + password_bubble_experiment::IsSmartLockBrandingEnabled(profile)); #if defined(OS_ANDROID) // For Android in case of smart lock we need different appearance of infobar. scoped_ptr<infobars::InfoBar> infobar =
diff --git a/chrome/browser/policy/cloud/DEPS b/chrome/browser/policy/cloud/DEPS index 422fa2a..07ecd7c9 100644 --- a/chrome/browser/policy/cloud/DEPS +++ b/chrome/browser/policy/cloud/DEPS
@@ -38,7 +38,9 @@ "+content/public/test", ], - r"cloud_policy_invalidator_unittest\.cc": [ + r"(cloud_policy_invalidator_unittest|" + r"remote_commands_invalidator_unittest)" + r"\.cc": [ "+chrome/browser/invalidation/fake_invalidation_service.h", ], }
diff --git a/chrome/browser/policy/cloud/remote_commands_invalidator.cc b/chrome/browser/policy/cloud/remote_commands_invalidator.cc new file mode 100644 index 0000000..f0af3cc --- /dev/null +++ b/chrome/browser/policy/cloud/remote_commands_invalidator.cc
@@ -0,0 +1,158 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/policy/cloud/remote_commands_invalidator.h" + +#include <string> + +#include "base/logging.h" +#include "components/invalidation/invalidation.h" +#include "components/invalidation/invalidation_service.h" +#include "components/invalidation/invalidation_util.h" +#include "components/invalidation/invalidator_state.h" +#include "components/invalidation/object_id_invalidation_map.h" +#include "components/invalidation/single_object_invalidation_set.h" + +namespace policy { + +RemoteCommandsInvalidator::RemoteCommandsInvalidator() { +} + +RemoteCommandsInvalidator::~RemoteCommandsInvalidator() { + DCHECK_EQ(SHUT_DOWN, state_); +} + +void RemoteCommandsInvalidator::Initialize( + invalidation::InvalidationService* invalidation_service) { + DCHECK_EQ(SHUT_DOWN, state_); + DCHECK(thread_checker_.CalledOnValidThread()); + + DCHECK(invalidation_service); + invalidation_service_ = invalidation_service; + + state_ = STOPPED; + OnInitialize(); +} + +void RemoteCommandsInvalidator::Shutdown() { + DCHECK_NE(SHUT_DOWN, state_); + DCHECK(thread_checker_.CalledOnValidThread()); + + Stop(); + + state_ = SHUT_DOWN; + OnShutdown(); +} + +void RemoteCommandsInvalidator::Start() { + DCHECK_EQ(STOPPED, state_); + DCHECK(thread_checker_.CalledOnValidThread()); + state_ = STARTED; + + OnStart(); +} + +void RemoteCommandsInvalidator::Stop() { + DCHECK_NE(SHUT_DOWN, state_); + DCHECK(thread_checker_.CalledOnValidThread()); + + if (state_ == STARTED) { + Unregister(); + state_ = STOPPED; + + OnStop(); + } +} + +void RemoteCommandsInvalidator::OnInvalidatorStateChange( + syncer::InvalidatorState state) { + DCHECK_EQ(STARTED, state_); + DCHECK(thread_checker_.CalledOnValidThread()); + + invalidation_service_enabled_ = state == syncer::INVALIDATIONS_ENABLED; + UpdateInvalidationsEnabled(); +} + +void RemoteCommandsInvalidator::OnIncomingInvalidation( + const syncer::ObjectIdInvalidationMap& invalidation_map) { + DCHECK_EQ(STARTED, state_); + DCHECK(thread_checker_.CalledOnValidThread()); + + if (!invalidation_service_enabled_) + LOG(WARNING) << "Unexpected invalidation received."; + + const syncer::SingleObjectInvalidationSet& list = + invalidation_map.ForObject(object_id_); + if (list.IsEmpty()) { + NOTREACHED(); + return; + } + + // Acknowledge all invalidations. + for (const auto& it : list) + it.Acknowledge(); + + DoRemoteCommandsFetch(); +} + +std::string RemoteCommandsInvalidator::GetOwnerName() const { + return "RemoteCommands"; +} + +void RemoteCommandsInvalidator::ReloadPolicyData( + const enterprise_management::PolicyData* policy) { + DCHECK(thread_checker_.CalledOnValidThread()); + + if (state_ != STARTED) + return; + + // Create the ObjectId based on the policy data. + // If the policy does not specify an the ObjectId, then unregister. + if (!policy || !policy->has_command_invalidation_source() || + !policy->has_command_invalidation_name()) { + Unregister(); + return; + } + const invalidation::ObjectId object_id(policy->command_invalidation_source(), + policy->command_invalidation_name()); + + // If the policy object id in the policy data is different from the currently + // registered object id, update the object registration. + if (!is_registered_ || !(object_id == object_id_)) + Register(object_id); +} + +void RemoteCommandsInvalidator::Register( + const invalidation::ObjectId& object_id) { + // Register this handler with the invalidation service if needed. + if (!is_registered_) { + OnInvalidatorStateChange(invalidation_service_->GetInvalidatorState()); + invalidation_service_->RegisterInvalidationHandler(this); + is_registered_ = true; + } + + object_id_ = object_id; + UpdateInvalidationsEnabled(); + + // Update registration with the invalidation service. + syncer::ObjectIdSet ids; + ids.insert(object_id); + invalidation_service_->UpdateRegisteredInvalidationIds(this, ids); +} + +void RemoteCommandsInvalidator::Unregister() { + if (is_registered_) { + invalidation_service_->UpdateRegisteredInvalidationIds( + this, syncer::ObjectIdSet()); + invalidation_service_->UnregisterInvalidationHandler(this); + is_registered_ = false; + UpdateInvalidationsEnabled(); + } +} + +void RemoteCommandsInvalidator::UpdateInvalidationsEnabled() { + invalidations_enabled_ = invalidation_service_enabled_ && is_registered_; +} + +} // namespace policy
diff --git a/chrome/browser/policy/cloud/remote_commands_invalidator.h b/chrome/browser/policy/cloud/remote_commands_invalidator.h new file mode 100644 index 0000000..07d0194a --- /dev/null +++ b/chrome/browser/policy/cloud/remote_commands_invalidator.h
@@ -0,0 +1,115 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_POLICY_CLOUD_REMOTE_COMMANDS_INVALIDATOR_H_ +#define CHROME_BROWSER_POLICY_CLOUD_REMOTE_COMMANDS_INVALIDATOR_H_ + +#include "base/macros.h" +#include "base/threading/thread_checker.h" +#include "components/invalidation/invalidation_handler.h" +#include "google/cacheinvalidation/include/types.h" +#include "policy/proto/device_management_backend.pb.h" + +namespace invalidation { +class InvalidationService; +} // namespace invalidation + +namespace policy { + +// This class provides basic intefaces for an invalidator for remote commands +// services. It's not interacting with CloudPolicyClient/CloudPolicyCore +// directly, instead, it handles the interacting with invalidation service +// only and leaves interfaces to integrate with subclasses. +class RemoteCommandsInvalidator : public syncer::InvalidationHandler { + public: + RemoteCommandsInvalidator(); + ~RemoteCommandsInvalidator() override; + + // Initialize this invalidator to pair with |invalidation_service|. Must be + // called before Start(). + void Initialize(invalidation::InvalidationService* invalidation_service); + + // Shutdown this invalidator. Will stop the invalidator first, and after + // shutting down, the invalidator can't be started anymore unless it's + // initialized again. + void Shutdown(); + + // Starts to process invalidations. + void Start(); + + // Stops to process invalidation. May only be called after Start() has been + // called. + void Stop(); + + // Helpful accessors. + invalidation::InvalidationService* invalidation_service() { + return invalidation_service_; + } + bool invalidations_enabled() { return invalidations_enabled_; } + + // syncer::InvalidationHandler: + void OnInvalidatorStateChange(syncer::InvalidatorState state) override; + void OnIncomingInvalidation( + const syncer::ObjectIdInvalidationMap& invalidation_map) override; + std::string GetOwnerName() const override; + + protected: + virtual void OnInitialize() = 0; + virtual void OnShutdown() = 0; + virtual void OnStart() = 0; + virtual void OnStop() = 0; + + // Subclasses must override this method to implement the actual remote + // commands fetch. + virtual void DoRemoteCommandsFetch() = 0; + + // Subclasses must call this function to set the object id for remote command + // invalidations. + void ReloadPolicyData(const enterprise_management::PolicyData* policy); + + private: + // Registers the given object with the invalidation service. + void Register(const invalidation::ObjectId& object_id); + + // Unregisters the current object with the invalidation service. + void Unregister(); + + // Updates invalidations_enabled_. + void UpdateInvalidationsEnabled(); + + // The state of the object. + enum State { + SHUT_DOWN, + STOPPED, + STARTED, + }; + State state_ = SHUT_DOWN; + + // The invalidation service. + invalidation::InvalidationService* invalidation_service_ = nullptr; + + // Whether the invalidator currently has the ability to receive invalidations. + // This is true if the invalidation service is enabled and the invalidator + // has registered for a remote commands object. + bool invalidations_enabled_ = false; + + // Whether the invalidation service is currently enabled. + bool invalidation_service_enabled_ = false; + + // Whether this object has registered for remote commands invalidations. + bool is_registered_ = false; + + // The object id representing the remote commands in the invalidation service. + invalidation::ObjectId object_id_; + + // A thread checker to make sure that callbacks are invoked on the correct + // thread. + base::ThreadChecker thread_checker_; + + DISALLOW_COPY_AND_ASSIGN(RemoteCommandsInvalidator); +}; + +} // namespace policy + +#endif // CHROME_BROWSER_POLICY_CLOUD_REMOTE_COMMANDS_INVALIDATOR_H_
diff --git a/chrome/browser/policy/cloud/remote_commands_invalidator_impl.cc b/chrome/browser/policy/cloud/remote_commands_invalidator_impl.cc new file mode 100644 index 0000000..51fbc5c --- /dev/null +++ b/chrome/browser/policy/cloud/remote_commands_invalidator_impl.cc
@@ -0,0 +1,65 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/policy/cloud/remote_commands_invalidator_impl.h" + +#include "base/logging.h" +#include "components/policy/core/common/remote_commands/remote_commands_service.h" + +namespace policy { + +RemoteCommandsInvalidatorImpl::RemoteCommandsInvalidatorImpl( + CloudPolicyCore* core) + : core_(core) { + DCHECK(core_); +} + +void RemoteCommandsInvalidatorImpl::OnInitialize() { + core_->AddObserver(this); + if (core_->remote_commands_service()) + OnRemoteCommandsServiceStarted(core_); +} + +void RemoteCommandsInvalidatorImpl::OnShutdown() { + core_->RemoveObserver(this); +} + +void RemoteCommandsInvalidatorImpl::OnStart() { + core_->store()->AddObserver(this); + OnStoreLoaded(core_->store()); +} + +void RemoteCommandsInvalidatorImpl::OnStop() { + core_->store()->RemoveObserver(this); +} + +void RemoteCommandsInvalidatorImpl::DoRemoteCommandsFetch() { + DCHECK(core_->remote_commands_service()); + core_->remote_commands_service()->FetchRemoteCommands(); +} + +void RemoteCommandsInvalidatorImpl::OnCoreConnected(CloudPolicyCore* core) { +} + +void RemoteCommandsInvalidatorImpl::OnRefreshSchedulerStarted( + CloudPolicyCore* core) { +} + +void RemoteCommandsInvalidatorImpl::OnCoreDisconnecting(CloudPolicyCore* core) { + Stop(); +} + +void RemoteCommandsInvalidatorImpl::OnRemoteCommandsServiceStarted( + CloudPolicyCore* core) { + Start(); +} + +void RemoteCommandsInvalidatorImpl::OnStoreLoaded(CloudPolicyStore* core) { + ReloadPolicyData(core_->store()->policy()); +} + +void RemoteCommandsInvalidatorImpl::OnStoreError(CloudPolicyStore* core) { +} + +} // namespace policy
diff --git a/chrome/browser/policy/cloud/remote_commands_invalidator_impl.h b/chrome/browser/policy/cloud/remote_commands_invalidator_impl.h new file mode 100644 index 0000000..aca0aef --- /dev/null +++ b/chrome/browser/policy/cloud/remote_commands_invalidator_impl.h
@@ -0,0 +1,49 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_POLICY_CLOUD_REMOTE_COMMANDS_INVALIDATOR_IMPL_H_ +#define CHROME_BROWSER_POLICY_CLOUD_REMOTE_COMMANDS_INVALIDATOR_IMPL_H_ + +#include "base/macros.h" +#include "chrome/browser/policy/cloud/remote_commands_invalidator.h" +#include "components/policy/core/common/cloud/cloud_policy_core.h" +#include "components/policy/core/common/cloud/cloud_policy_store.h" + +namespace policy { + +// Implementation of invalidator for remote commands services. This class +// listens to events from CloudPolicyCore and CloudPolicyStore and builds +// with RemoteCommandsInvalidator to complete the tasks. +class RemoteCommandsInvalidatorImpl : public RemoteCommandsInvalidator, + public CloudPolicyCore::Observer, + public CloudPolicyStore::Observer { + public: + explicit RemoteCommandsInvalidatorImpl(CloudPolicyCore* core); + + // RemoteCommandsInvalidator: + void OnInitialize() override; + void OnShutdown() override; + void OnStart() override; + void OnStop() override; + void DoRemoteCommandsFetch() override; + + // CloudPolicyCore::Observer: + void OnCoreConnected(CloudPolicyCore* core) override; + void OnRefreshSchedulerStarted(CloudPolicyCore* core) override; + void OnCoreDisconnecting(CloudPolicyCore* core) override; + void OnRemoteCommandsServiceStarted(CloudPolicyCore* core) override; + + // CloudPolicyStore::Observer: + void OnStoreLoaded(CloudPolicyStore* store) override; + void OnStoreError(CloudPolicyStore* store) override; + + private: + CloudPolicyCore* const core_; + + DISALLOW_COPY_AND_ASSIGN(RemoteCommandsInvalidatorImpl); +}; + +} // namespace policy + +#endif // CHROME_BROWSER_POLICY_CLOUD_REMOTE_COMMANDS_INVALIDATOR_IMPL_H_
diff --git a/chrome/browser/policy/cloud/remote_commands_invalidator_unittest.cc b/chrome/browser/policy/cloud/remote_commands_invalidator_unittest.cc new file mode 100644 index 0000000..d33a919c --- /dev/null +++ b/chrome/browser/policy/cloud/remote_commands_invalidator_unittest.cc
@@ -0,0 +1,293 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/policy/cloud/remote_commands_invalidator.h" + +#include "base/message_loop/message_loop.h" +#include "base/run_loop.h" +#include "chrome/browser/invalidation/fake_invalidation_service.h" +#include "components/invalidation/invalidation.h" +#include "components/invalidation/invalidation_util.h" +#include "components/invalidation/invalidator_registrar.h" +#include "components/invalidation/invalidator_state.h" +#include "components/invalidation/mock_ack_handler.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace em = enterprise_management; + +using ::testing::Mock; +using ::testing::StrictMock; + +namespace policy { + +class MockRemoteCommandInvalidator : public RemoteCommandsInvalidator { + public: + MockRemoteCommandInvalidator() {} + + MOCK_METHOD0(OnInitialize, void()); + MOCK_METHOD0(OnShutdown, void()); + MOCK_METHOD0(OnStart, void()); + MOCK_METHOD0(OnStop, void()); + MOCK_METHOD0(DoRemoteCommandsFetch, void()); + + void SetInvalidationObjectID(const invalidation::ObjectId& object_id) { + em::PolicyData policy_data; + policy_data.set_command_invalidation_source(object_id.source()); + policy_data.set_command_invalidation_name(object_id.name()); + ReloadPolicyData(&policy_data); + } + + void ClearInvalidationObjectID() { + const em::PolicyData policy_data; + ReloadPolicyData(&policy_data); + } + + private: + DISALLOW_COPY_AND_ASSIGN(MockRemoteCommandInvalidator); +}; + +class RemoteCommandsInvalidatorTest : public testing::Test { + public: + RemoteCommandsInvalidatorTest() + : kTestingObjectId1(123456, "abcdef"), + kTestingObjectId2(654321, "defabc") { + } + + void EnableInvalidationService() { + invalidation_service_.SetInvalidatorState(syncer::INVALIDATIONS_ENABLED); + } + + void DisableInvalidationService() { + invalidation_service_.SetInvalidatorState( + syncer::TRANSIENT_INVALIDATION_ERROR); + } + + syncer::Invalidation FireInvalidation( + const invalidation::ObjectId& object_id) { + const syncer::Invalidation invalidation = + syncer::Invalidation::InitUnknownVersion(object_id); + invalidation_service_.EmitInvalidationForTest(invalidation); + return invalidation; + } + + bool IsInvalidationSent(const syncer::Invalidation& invalidation) { + return !invalidation_service_.GetMockAckHandler()->IsUnsent(invalidation); + } + + bool IsInvalidationAcknowledged(const syncer::Invalidation& invalidation) { + return invalidation_service_.GetMockAckHandler()->IsAcknowledged( + invalidation); + } + + bool IsInvalidatorRegistered() { + return !invalidation_service_.invalidator_registrar() + .GetRegisteredIds(&invalidator_) + .empty(); + } + + void VerifyExpectations() { + Mock::VerifyAndClearExpectations(&invalidator_); + } + + protected: + // Initialize and start the invalidator. + void InitializeAndStart() { + EXPECT_CALL(invalidator_, OnInitialize()).Times(1); + invalidator_.Initialize(&invalidation_service_); + VerifyExpectations(); + + EXPECT_CALL(invalidator_, OnStart()).Times(1); + invalidator_.Start(); + + VerifyExpectations(); + } + + // Stop and shutdown the invalidator. + void StopAndShutdown() { + EXPECT_CALL(invalidator_, OnStop()).Times(1); + EXPECT_CALL(invalidator_, OnShutdown()).Times(1); + invalidator_.Shutdown(); + + VerifyExpectations(); + } + + // Fire an invalidation to verify that invalidation is not working. + void VerifyInvalidationDisabled(const invalidation::ObjectId& object_id) { + const syncer::Invalidation invalidation = FireInvalidation(object_id); + + base::RunLoop().RunUntilIdle(); + EXPECT_FALSE(IsInvalidationSent(invalidation)); + } + + // Fire an invalidation to verify that invalidation works. + void VerifyInvalidationEnabled(const invalidation::ObjectId& object_id) { + EXPECT_TRUE(invalidator_.invalidations_enabled()); + + EXPECT_CALL(invalidator_, DoRemoteCommandsFetch()).Times(1); + const syncer::Invalidation invalidation = FireInvalidation(object_id); + + base::RunLoop().RunUntilIdle(); + EXPECT_TRUE(IsInvalidationSent(invalidation)); + EXPECT_TRUE(IsInvalidationAcknowledged(invalidation)); + VerifyExpectations(); + } + + const invalidation::ObjectId kTestingObjectId1; + const invalidation::ObjectId kTestingObjectId2; + + base::MessageLoop loop_; + + invalidation::FakeInvalidationService invalidation_service_; + StrictMock<MockRemoteCommandInvalidator> invalidator_; + + private: + DISALLOW_COPY_AND_ASSIGN(RemoteCommandsInvalidatorTest); +}; + +// Verifies that only the fired invalidations will be received. +TEST_F(RemoteCommandsInvalidatorTest, FiredInvalidation) { + InitializeAndStart(); + + // Invalidator won't work at this point. + EXPECT_FALSE(invalidator_.invalidations_enabled()); + + // Load the policy data, it should work now. + invalidator_.SetInvalidationObjectID(kTestingObjectId1); + EXPECT_TRUE(invalidator_.invalidations_enabled()); + + base::RunLoop().RunUntilIdle(); + // No invalidation will be received if no invalidation is fired. + VerifyExpectations(); + + // Fire an invalidation with different object id, no invalidation will be + // received. + const syncer::Invalidation invalidation1 = + FireInvalidation(kTestingObjectId2); + + base::RunLoop().RunUntilIdle(); + EXPECT_FALSE(IsInvalidationSent(invalidation1)); + VerifyExpectations(); + + // Fire the invalidation, it should be acknowledged and trigger a remote + // commands fetch. + EXPECT_CALL(invalidator_, DoRemoteCommandsFetch()).Times(1); + const syncer::Invalidation invalidation2 = + FireInvalidation(kTestingObjectId1); + + base::RunLoop().RunUntilIdle(); + EXPECT_TRUE(IsInvalidationSent(invalidation2)); + EXPECT_TRUE(IsInvalidationAcknowledged(invalidation2)); + VerifyExpectations(); + + StopAndShutdown(); +} + +// Verifies that no invalidation will be received when invalidator is shutdown. +TEST_F(RemoteCommandsInvalidatorTest, ShutDown) { + EXPECT_FALSE(invalidator_.invalidations_enabled()); + FireInvalidation(kTestingObjectId1); + + base::RunLoop().RunUntilIdle(); + EXPECT_FALSE(invalidator_.invalidations_enabled()); +} + +// Verifies that no invalidation will be received when invalidator is stopped. +TEST_F(RemoteCommandsInvalidatorTest, Stopped) { + EXPECT_CALL(invalidator_, OnInitialize()).Times(1); + invalidator_.Initialize(&invalidation_service_); + VerifyExpectations(); + + EXPECT_FALSE(invalidator_.invalidations_enabled()); + FireInvalidation(kTestingObjectId2); + + base::RunLoop().RunUntilIdle(); + EXPECT_FALSE(invalidator_.invalidations_enabled()); + + EXPECT_CALL(invalidator_, OnShutdown()).Times(1); + invalidator_.Shutdown(); +} + +// Verifies that stated/stopped state changes work as expected. +TEST_F(RemoteCommandsInvalidatorTest, StartedStateChange) { + InitializeAndStart(); + + // Invalidator requires object id to work. + VerifyInvalidationDisabled(kTestingObjectId1); + EXPECT_FALSE(invalidator_.invalidations_enabled()); + invalidator_.SetInvalidationObjectID(kTestingObjectId1); + VerifyInvalidationEnabled(kTestingObjectId1); + + // Stop and restart invalidator. + EXPECT_CALL(invalidator_, OnStop()).Times(1); + invalidator_.Stop(); + VerifyExpectations(); + + VerifyInvalidationDisabled(kTestingObjectId1); + EXPECT_FALSE(invalidator_.invalidations_enabled()); + + EXPECT_CALL(invalidator_, OnStart()).Times(1); + invalidator_.Start(); + VerifyExpectations(); + + // Invalidator requires object id to work. + invalidator_.SetInvalidationObjectID(kTestingObjectId1); + VerifyInvalidationEnabled(kTestingObjectId1); + + StopAndShutdown(); +} + +// Verifies that registered state changes work as expected. +TEST_F(RemoteCommandsInvalidatorTest, RegistedStateChange) { + InitializeAndStart(); + + invalidator_.SetInvalidationObjectID(kTestingObjectId1); + VerifyInvalidationEnabled(kTestingObjectId1); + + invalidator_.SetInvalidationObjectID(kTestingObjectId2); + VerifyInvalidationEnabled(kTestingObjectId2); + VerifyInvalidationDisabled(kTestingObjectId1); + + invalidator_.SetInvalidationObjectID(kTestingObjectId1); + VerifyInvalidationEnabled(kTestingObjectId1); + VerifyInvalidationDisabled(kTestingObjectId2); + + invalidator_.ClearInvalidationObjectID(); + VerifyInvalidationDisabled(kTestingObjectId1); + VerifyInvalidationDisabled(kTestingObjectId2); + EXPECT_FALSE(invalidator_.invalidations_enabled()); + + invalidator_.SetInvalidationObjectID(kTestingObjectId2); + VerifyInvalidationEnabled(kTestingObjectId2); + VerifyInvalidationDisabled(kTestingObjectId1); + + StopAndShutdown(); +} + +// Verifies that invalidation service enabled state changes work as expected. +TEST_F(RemoteCommandsInvalidatorTest, InvalidationServiceEnabledStateChanged) { + InitializeAndStart(); + + invalidator_.SetInvalidationObjectID(kTestingObjectId1); + VerifyInvalidationEnabled(kTestingObjectId1); + + DisableInvalidationService(); + EXPECT_FALSE(invalidator_.invalidations_enabled()); + + EnableInvalidationService(); + VerifyInvalidationEnabled(kTestingObjectId1); + + EnableInvalidationService(); + VerifyInvalidationEnabled(kTestingObjectId1); + + DisableInvalidationService(); + EXPECT_FALSE(invalidator_.invalidations_enabled()); + + DisableInvalidationService(); + EXPECT_FALSE(invalidator_.invalidations_enabled()); + + StopAndShutdown(); +} + +} // namespace policy
diff --git a/chrome/browser/policy/test/local_policy_test_server.cc b/chrome/browser/policy/test/local_policy_test_server.cc index d4bb6c7..439067f 100644 --- a/chrome/browser/policy/test/local_policy_test_server.cc +++ b/chrome/browser/policy/test/local_policy_test_server.cc
@@ -240,7 +240,7 @@ if (!clients_.empty()) { std::string json; - base::JSONWriter::Write(&clients_, &json); + base::JSONWriter::Write(clients_, &json); base::FilePath client_state_file = server_data_dir_.path().Append(kClientStateFileName); if (base::WriteFile(client_state_file, json.c_str(), json.size()) !=
diff --git a/chrome/browser/profile_resetter/resettable_settings_snapshot.cc b/chrome/browser/profile_resetter/resettable_settings_snapshot.cc index d7d00017..da82550 100644 --- a/chrome/browser/profile_resetter/resettable_settings_snapshot.cc +++ b/chrome/browser/profile_resetter/resettable_settings_snapshot.cc
@@ -215,7 +215,7 @@ "new field needs to be serialized here"); std::string json; - base::JSONWriter::Write(&dict, &json); + base::JSONWriter::Write(dict, &json); return json; }
diff --git a/chrome/browser/renderer_context_menu/render_view_context_menu.cc b/chrome/browser/renderer_context_menu/render_view_context_menu.cc index be5d6ef..3c5e9a0 100644 --- a/chrome/browser/renderer_context_menu/render_view_context_menu.cc +++ b/chrome/browser/renderer_context_menu/render_view_context_menu.cc
@@ -62,6 +62,7 @@ #include "chrome/common/spellcheck_messages.h" #include "chrome/common/url_constants.h" #include "chrome/grit/generated_resources.h" +#include "components/data_reduction_proxy/core/common/data_reduction_proxy_headers.h" #include "components/google/core/browser/google_util.h" #include "components/metrics/proto/omnibox_input_type.pb.h" #include "components/omnibox/autocomplete_match.h" @@ -220,8 +221,10 @@ {63, IDC_WRITING_DIRECTION_DEFAULT}, {64, IDC_WRITING_DIRECTION_LTR}, {65, IDC_WRITING_DIRECTION_RTL}, + {66, IDC_CONTENT_CONTEXT_SHOW_ORIGINAL_IMAGE}, // Add new items here and use |enum_id| from the next line. - {66, 0}, // Must be the last. Increment |enum_id| when new IDC was added. + // Also, add new items to RenderViewContextMenuItem enum in histograms.xml. + {67, 0}, // Must be the last. Increment |enum_id| when new IDC was added. }; // Collapses large ranges of ids before looking for UMA enum. @@ -741,6 +744,14 @@ IDS_CONTENT_CONTEXT_COPYIMAGELOCATION); menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPYIMAGE, IDS_CONTENT_CONTEXT_COPYIMAGE); + std::map<std::string, std::string>::const_iterator it = + params_.properties.find(data_reduction_proxy::chrome_proxy_header()); + if (it != params_.properties.end() && it->second == + data_reduction_proxy::chrome_proxy_lo_fi_directive()) { + menu_model_.AddItemWithStringId( + IDC_CONTENT_CONTEXT_SHOW_ORIGINAL_IMAGE, + IDS_CONTENT_CONTEXT_SHOW_ORIGINAL_IMAGE); + } DataReductionProxyChromeSettings* settings = DataReductionProxyChromeSettingsFactory::GetForBrowserContext( browser_context_); @@ -1161,6 +1172,7 @@ // The images shown in the most visited thumbnails can't be opened or // searched for conventionally. case IDC_CONTENT_CONTEXT_OPEN_ORIGINAL_IMAGE_NEW_TAB: + case IDC_CONTENT_CONTEXT_SHOW_ORIGINAL_IMAGE: case IDC_CONTENT_CONTEXT_OPENIMAGENEWTAB: case IDC_CONTENT_CONTEXT_SEARCHWEBFORIMAGE: return params_.src_url.is_valid() && @@ -1476,6 +1488,10 @@ data_reduction_proxy::kDataReductionPassThroughHeader); break; + case IDC_CONTENT_CONTEXT_SHOW_ORIGINAL_IMAGE: + ShowOriginalImage(); + break; + case IDC_CONTENT_CONTEXT_OPENIMAGENEWTAB: case IDC_CONTENT_CONTEXT_OPENAVNEWTAB: OpenURL(params_.src_url, @@ -1830,6 +1846,14 @@ source_web_contents_->GetRenderViewHost()->CopyImageAt(x, y); } +void RenderViewContextMenu::ShowOriginalImage() { + RenderFrameHost* render_frame_host = GetRenderFrameHost(); + if (!render_frame_host) + return; + render_frame_host->Send(new ChromeViewMsg_RequestReloadImageForContextNode( + render_frame_host->GetRoutingID())); +} + void RenderViewContextMenu::GetImageThumbnailForSearch() { RenderFrameHost* render_frame_host = GetRenderFrameHost(); if (!render_frame_host)
diff --git a/chrome/browser/renderer_context_menu/render_view_context_menu.h b/chrome/browser/renderer_context_menu/render_view_context_menu.h index e492994..c033698 100644 --- a/chrome/browser/renderer_context_menu/render_view_context_menu.h +++ b/chrome/browser/renderer_context_menu/render_view_context_menu.h
@@ -134,6 +134,9 @@ // Copy to the clipboard an image located at a point in the RenderView void CopyImageAt(int x, int y); + // Show the original image located at a point in the RenderView. + void ShowOriginalImage(); + // Get an image located at a point in the RenderView for search. void GetImageThumbnailForSearch();
diff --git a/chrome/browser/renderer_context_menu/render_view_context_menu_browsertest.cc b/chrome/browser/renderer_context_menu/render_view_context_menu_browsertest.cc index 0498a2c..823dbafd 100644 --- a/chrome/browser/renderer_context_menu/render_view_context_menu_browsertest.cc +++ b/chrome/browser/renderer_context_menu/render_view_context_menu_browsertest.cc
@@ -4,6 +4,7 @@ #include <string> +#include "base/bind.h" #include "base/command_line.h" #include "base/macros.h" #include "base/memory/ref_counted.h" @@ -34,6 +35,10 @@ #include "content/public/browser/web_contents.h" #include "content/public/test/browser_test_utils.h" #include "content/public/test/test_utils.h" +#include "net/base/load_flags.h" +#include "net/url_request/url_request.h" +#include "net/url_request/url_request_filter.h" +#include "net/url_request/url_request_interceptor.h" #include "third_party/WebKit/public/web/WebContextMenuData.h" #include "third_party/WebKit/public/web/WebInputEvent.h" @@ -525,4 +530,125 @@ EXPECT_EQ(ThumbnailResponseWatcher::THUMBNAIL_RECEIVED, watcher.Wait()); } +class ShowImageRequestInterceptor : public net::URLRequestInterceptor { + public: + ShowImageRequestInterceptor() : num_requests_(0), + requests_to_wait_for_(-1), + weak_factory_(this) { + } + + ~ShowImageRequestInterceptor() override {} + + // net::URLRequestInterceptor implementation + net::URLRequestJob* MaybeInterceptRequest( + net::URLRequest* request, + net::NetworkDelegate* network_delegate) const override { + DCHECK_CURRENTLY_ON(content::BrowserThread::IO); + EXPECT_TRUE(request->load_flags() & net::LOAD_BYPASS_CACHE); + content::BrowserThread::PostTask( + content::BrowserThread::UI, FROM_HERE, + base::Bind(&ShowImageRequestInterceptor::RequestCreated, + weak_factory_.GetWeakPtr())); + return nullptr; + } + + void WaitForRequests(int requests_to_wait_for) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + DCHECK_EQ(-1, requests_to_wait_for_); + DCHECK(!run_loop_); + + if (num_requests_ >= requests_to_wait_for) + return; + + requests_to_wait_for_ = requests_to_wait_for; + run_loop_.reset(new base::RunLoop()); + run_loop_->Run(); + run_loop_.reset(); + requests_to_wait_for_ = -1; + EXPECT_EQ(num_requests_, requests_to_wait_for); + } + + // It is up to the caller to wait until all relevant requests has been + // created, either through calling WaitForRequests or some other manner, + // before calling this method. + int num_requests() const { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + return num_requests_; + } + + private: + void RequestCreated() { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + + num_requests_++; + if (num_requests_ == requests_to_wait_for_) + run_loop_->Quit(); + } + + // These are only used on the UI thread. + int num_requests_; + int requests_to_wait_for_; + scoped_ptr<base::RunLoop> run_loop_; + + // This prevents any risk of flake if any test doesn't wait for a request + // it sent. Mutable so it can be accessed from a const function. + mutable base::WeakPtrFactory<ShowImageRequestInterceptor> weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(ShowImageRequestInterceptor); +}; + +class ShowImageBrowserTest : public InProcessBrowserTest { + protected: + void SetupAndLoadImagePage(const std::string& image_path) { + // Go to a page with an image in it. The test server doesn't serve the image + // with the right MIME type, so use a data URL to make a page containing it. + GURL image_url(test_server()->GetURL(image_path)); + GURL page("data:text/html,<img src='" + image_url.spec() + "'>"); + ui_test_utils::NavigateToURL(browser(), page); + } + + void AddShowImageInterceptor(const std::string& image_path) { + interceptor_ = new ShowImageRequestInterceptor(); + scoped_ptr<net::URLRequestInterceptor> owned_interceptor(interceptor_); + content::BrowserThread::PostTask( + content::BrowserThread::IO, FROM_HERE, + base::Bind(&ShowImageBrowserTest::AddInterceptorForURL, + base::Unretained(this), + GURL(test_server()->GetURL(image_path).spec()), + base::Passed(&owned_interceptor))); + } + + void AttemptShowImage() { + // Right-click where the image should be. + // |menu_observer_| will cause the show-image menu item to be clicked. + menu_observer_.reset(new ContextMenuNotificationObserver( + IDC_CONTENT_CONTEXT_SHOW_ORIGINAL_IMAGE)); + content::WebContents* tab = + browser()->tab_strip_model()->GetActiveWebContents(); + content::SimulateMouseClickAt(tab, 0, blink::WebMouseEvent::ButtonRight, + gfx::Point(15, 15)); + } + + void AddInterceptorForURL( + const GURL& url, scoped_ptr<net::URLRequestInterceptor> handler) { + DCHECK_CURRENTLY_ON(content::BrowserThread::IO); + net::URLRequestFilter::GetInstance()->AddUrlInterceptor( + url, handler.Pass()); + } + + ShowImageRequestInterceptor* interceptor_; + + private: + scoped_ptr<ContextMenuNotificationObserver> menu_observer_; +}; + +IN_PROC_BROWSER_TEST_F(ShowImageBrowserTest, ShowImage) { + static const char kValidImage[] = "files/show_image/image.png"; + SetupAndLoadImagePage(kValidImage); + AddShowImageInterceptor(kValidImage); + AttemptShowImage(); + interceptor_->WaitForRequests(1); + EXPECT_EQ(1, interceptor_->num_requests()); +} + } // namespace
diff --git a/chrome/browser/renderer_context_menu/render_view_context_menu_unittest.cc b/chrome/browser/renderer_context_menu/render_view_context_menu_unittest.cc index c55c0ce9..66c8b7c 100644 --- a/chrome/browser/renderer_context_menu/render_view_context_menu_unittest.cc +++ b/chrome/browser/renderer_context_menu/render_view_context_menu_unittest.cc
@@ -23,6 +23,7 @@ #include "chrome/test/base/chrome_render_view_host_test_harness.h" #include "chrome/test/base/testing_profile.h" #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h" +#include "components/data_reduction_proxy/core/common/data_reduction_proxy_headers.h" #include "components/data_reduction_proxy/core/common/data_reduction_proxy_params.h" #include "components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h" #include "content/public/browser/web_contents.h" @@ -356,6 +357,10 @@ return menu; } + void AppendImageItems(TestRenderViewContextMenu* menu) { + menu->AppendImageItems(); + } + void SetupDataReductionProxy(bool enable_data_reduction_proxy) { drp_test_context_ = data_reduction_proxy::DataReductionProxyTestContext::Builder() @@ -467,3 +472,19 @@ std::string::npos && headers.find("Cache-Control: no-cache") == std::string::npos); } + +// Verify that the Chrome-Proxy Lo-Fi directive causes the context menu to +// display the "Show Image" menu item. +TEST_F(RenderViewContextMenuPrefsTest, DataSaverShowImage) { + SetupDataReductionProxy(true); + content::ContextMenuParams params = CreateParams(MenuItem::IMAGE); + params.properties[data_reduction_proxy::chrome_proxy_header()] = + data_reduction_proxy::chrome_proxy_lo_fi_directive(); + params.unfiltered_link_url = params.link_url; + content::WebContents* wc = web_contents(); + scoped_ptr<TestRenderViewContextMenu> menu( + new TestRenderViewContextMenu(wc->GetMainFrame(), params)); + AppendImageItems(menu.get()); + + ASSERT_TRUE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_SHOW_ORIGINAL_IMAGE)); +}
diff --git a/chrome/browser/resources/chromeos/chromevox/manifest.json.jinja2 b/chrome/browser/resources/chromeos/chromevox/manifest.json.jinja2 index 68b27ad..88ee980 100644 --- a/chrome/browser/resources/chromeos/chromevox/manifest.json.jinja2 +++ b/chrome/browser/resources/chromeos/chromevox/manifest.json.jinja2
@@ -55,8 +55,8 @@ "automation": { "desktop": true }, -{% if is_chromevox_classic == '0' %} "commands": { +{% if is_chromevox_classic == '0' %} "nextElement": { "description": "__MSG_CHROMEVOX_NEXT_OBJECT__", "suggested_key": { @@ -279,8 +279,8 @@ "chromeos": "Search+Shift+R" } } - }, {% endif %} + }, "options_page": "chromevox/background/options.html", "default_locale": "en" }
diff --git a/chrome/browser/resources/chromeos/login/gaia_password_changed.html b/chrome/browser/resources/chromeos/login/gaia_password_changed.html index 82d8fd1..be137ac 100644 --- a/chrome/browser/resources/chromeos/login/gaia_password_changed.html +++ b/chrome/browser/resources/chromeos/login/gaia_password_changed.html
@@ -45,11 +45,12 @@ <p i18n-content="passwordChangedTitle"> </p> </div> - <gaia-input-form class="footer" id="oldPasswordInput" - inputtype="password" - i18n-values="errorMsg:oldPasswordIncorrect; - inputLabel:oldPasswordHint; - buttonText:nextButtonText"> + <gaia-input-form class="footer" id="oldPasswordInputForm" + i18n-values="buttonText:nextButtonText"> + <gaia-input id="oldPasswordInput" type="password" + i18n-values="error:oldPasswordIncorrect; + label:oldPasswordHint"> + </gaia-input> <gaia-paper-button noink i18n-content="forgotOldPasswordButtonText" class="link-button" on-tap="{{onForgotPasswordClicked}}">
diff --git a/chrome/browser/resources/chromeos/login/gaia_password_changed.js b/chrome/browser/resources/chromeos/login/gaia_password_changed.js index a004678..9887a4b 100644 --- a/chrome/browser/resources/chromeos/login/gaia_password_changed.js +++ b/chrome/browser/resources/chromeos/login/gaia_password_changed.js
@@ -5,21 +5,21 @@ Polymer('gaia-password-changed', { invalidate: function() { - this.$.oldPasswordInput.setValid(false); + this.$.oldPasswordInput.isInvalid = true; }, reset: function() { this.$.animatedPages.selected = 0; this.clearPassword(); - this.$.oldPasswordInput.setValid(true); + this.$.oldPasswordInput.isInvalid = false; this.disabled = false; this.$.closeButton.hidden = false; this.$.oldPasswordCard.classList.remove('disabled'); }, ready: function() { - this.$.oldPasswordInput.addEventListener('buttonClick', function() { - var inputPassword = this.$.oldPasswordInput.inputValue; + this.$.oldPasswordInputForm.addEventListener('submit', function() { + var inputPassword = this.$.oldPasswordInput.value; if (!inputPassword) this.invalidate(); else { @@ -36,7 +36,7 @@ }, set disabled(value) { - this.$.oldPasswordInput.disabled = value; + this.$.oldPasswordInputForm.disabled = value; }, onForgotPasswordClicked: function() { @@ -45,7 +45,7 @@ }, onTryAgainClicked: function() { - this.$.oldPasswordInput.setValid(true); + this.$.oldPasswordInput.isInvalid = false; this.$.animatedPages.selected -= 1; }, @@ -54,7 +54,7 @@ }, clearPassword: function() { - this.$.oldPasswordInput.inputValue = ''; + this.$.oldPasswordInput.value = ''; }, onProceedClicked: function() {
diff --git a/chrome/browser/resources/chromeos/login/header_bar.css b/chrome/browser/resources/chromeos/login/header_bar.css index a1fd095..3e8a1e8 100644 --- a/chrome/browser/resources/chromeos/login/header_bar.css +++ b/chrome/browser/resources/chromeos/login/header_bar.css
@@ -77,8 +77,10 @@ color: black !important; display: block; font-size: 13px; + height: auto; left: 15px; margin: 0 0 -10px -10px; + min-height: 34px; position: absolute; text-align: center; width: 180px;
diff --git a/chrome/browser/resources/chromeos/login/header_bar.js b/chrome/browser/resources/chromeos/login/header_bar.js index 9cf78ad..20c551e 100644 --- a/chrome/browser/resources/chromeos/login/header_bar.js +++ b/chrome/browser/resources/chromeos/login/header_bar.js
@@ -352,7 +352,8 @@ accountPickerIsActive || !this.allowCancel_ || wrongHWIDWarningIsActive || - isMultiProfilesUI; + isMultiProfilesUI || + supervisedUserCreationDialogIsActive; $('guest-user-header-bar-item').hidden = (gaiaIsActive && !this.isNewGaiaFlow_) || supervisedUserCreationDialogIsActiveAndNotIntro ||
diff --git a/chrome/browser/resources/chromeos/login/oobe_screen_eula.js b/chrome/browser/resources/chromeos/login/oobe_screen_eula.js index b43d666..f6c85cc 100644 --- a/chrome/browser/resources/chromeos/login/oobe_screen_eula.js +++ b/chrome/browser/resources/chromeos/login/oobe_screen_eula.js
@@ -96,6 +96,7 @@ acceptButton.textContent = loadTimeData.getString('acceptAgreement'); acceptButton.addEventListener('click', function(e) { $('eula').classList.add('loading'); // Mark EULA screen busy. + Oobe.clearErrors(); e.stopPropagation(); }); buttons.push(acceptButton);
diff --git a/chrome/browser/resources/chromeos/login/screen_gaia_signin.js b/chrome/browser/resources/chromeos/login/screen_gaia_signin.js index 0fc43f40..388a8a5 100644 --- a/chrome/browser/resources/chromeos/login/screen_gaia_signin.js +++ b/chrome/browser/resources/chromeos/login/screen_gaia_signin.js
@@ -33,7 +33,6 @@ 'onFrameError', 'updateCancelButtonState', 'showWhitelistCheckFailedError', - 'updateDeviceId', ], /** @@ -153,8 +152,6 @@ 'backButton', this.onBackButton_.bind(this)); this.gaiaAuthHost_.addEventListener( 'showView', this.onShowView_.bind(this)); - this.gaiaAuthHost_.addEventListener('attemptLogin', - this.onAttemptLogin_.bind(this)); this.gaiaAuthHost_.confirmPasswordCallback = this.onAuthConfirmPassword_.bind(this); this.gaiaAuthHost_.noPasswordCallback = @@ -630,16 +627,6 @@ }, /** - * Invoked when the auth host emits 'attemptLogin' event. - * @param {Object} Message object with |detail| field keeping email: - * like {detail: 'user@gmail.com'} . - * @private - */ - onAttemptLogin_: function(e) { - chrome.send('attemptLogin', [e.detail]); - }, - - /** * Invoked when the user has successfully authenticated via SAML, the * principals API was not used and the auth host needs the user to confirm * the scraped password. @@ -747,8 +734,7 @@ credentials.email, credentials.password, credentials.authCode, - credentials.usingSAML, - credentials.deviceId + credentials.usingSAML ]); } } else { @@ -953,18 +939,6 @@ if (!show) Oobe.showSigninUI(); - }, - - /** - * Inform Gaia of new deviceId. - * @param {data} Object like {'deviceId': 'test-device-id'} - */ - updateDeviceId: function(data) { - if (!this.isNewGaiaFlow) - return; - - if (data && data.deviceId) - this.gaiaAuthHost_.updateDeviceId(data.deviceId); - }, + } }; });
diff --git a/chrome/browser/resources/chromeos/login/screen_supervised_user_creation.css b/chrome/browser/resources/chromeos/login/screen_supervised_user_creation.css index 0db1542..30416a6 100644 --- a/chrome/browser/resources/chromeos/login/screen_supervised_user_creation.css +++ b/chrome/browser/resources/chromeos/login/screen_supervised_user_creation.css
@@ -549,3 +549,16 @@ .camera.live:not(.online) .supervised-user-creation-image-stream-area .spinner { display: block; } + +#supervised-user-creation-close-button-item { + color: rgba(0, 0, 0, .54); + position: absolute; + right: 10px; + top: 10px; + z-index: 1; +} + +html[dir=rtl] #supervised-user-creation-close-button-item { + left: 10px; + right: auto; +}
diff --git a/chrome/browser/resources/chromeos/login/screen_supervised_user_creation.html b/chrome/browser/resources/chromeos/login/screen_supervised_user_creation.html index 170b473..8be6fc77 100644 --- a/chrome/browser/resources/chromeos/login/screen_supervised_user_creation.html +++ b/chrome/browser/resources/chromeos/login/screen_supervised_user_creation.html
@@ -1,3 +1,4 @@ +<link rel="import" href="chrome://oobe/custom_elements.html"> <div class="step hidden" id="supervised-user-creation" hidden> <div class="step-contents"> <div id="supervised-user-creation-intro" class="step-no-logo"> @@ -157,4 +158,7 @@ <img class="import-pod-image"></img> <div class="import-pod-name"></div> </div> + <button id="supervised-user-creation-close-button-item" is="gaia-icon-button" + icon="close" i18n-values="aria-label:closeButton" tabindex="0"> + </button> </div>
diff --git a/chrome/browser/resources/chromeos/login/screen_supervised_user_creation.js b/chrome/browser/resources/chromeos/login/screen_supervised_user_creation.js index be8f355..c7d44f8 100644 --- a/chrome/browser/resources/chromeos/login/screen_supervised_user_creation.js +++ b/chrome/browser/resources/chromeos/login/screen_supervised_user_creation.js
@@ -616,6 +616,12 @@ 'webkitTransitionEnd', function(e) { previewElement.classList.remove('animation'); }); + + $('supervised-user-creation-close-button-item').addEventListener( + 'click', function(e) { + this.cancel(); + e.preventDefault(); + }.bind(this)); }, buttonIds: [], @@ -1193,6 +1199,9 @@ !this.importList_.selectedPod_ || this.importList_.selectedPod_.user.exists; } + $('supervised-user-creation-close-button-item').hidden = + (visiblePage == 'created'); + chrome.send('currentSupervisedUserPage', [this.currentPage_]); },
diff --git a/chrome/browser/resources/gaia_auth_host/authenticator.js b/chrome/browser/resources/gaia_auth_host/authenticator.js index 020493cd..87580d9 100644 --- a/chrome/browser/resources/gaia_auth_host/authenticator.js +++ b/chrome/browser/resources/gaia_auth_host/authenticator.js
@@ -29,8 +29,6 @@ var OAUTH_CODE_COOKIE = 'oauth_code'; var SERVICE_ID = 'chromeoslogin'; var EMBEDDED_SETUP_CHROMEOS_ENDPOINT = 'embedded/setup/chromeos'; - var X_DEVICE_ID_HEADER = 'X-Device-ID'; - var EPHEMERAL_DEVICE_ID_PREFIX = 't_'; /** * The source URL parameter for the constrained signin flow. @@ -85,8 +83,6 @@ 'enterpriseDomain', // Domain in which hosting device is (or should be) // enrolled. 'emailDomain', // Value used to prefill domain for email. - 'deviceId', // User device ID (sync Id). - 'sessionIsEphemeral', // User session would be ephemeral. 'clientVersion', // Version of the Chrome build. 'platformVersion', // Version of the OS build. 'releaseChannel', // Installation channel. @@ -119,9 +115,6 @@ this.reloadUrl_ = null; this.trusted_ = true; this.oauth_code_ = null; - this.deviceId_ = null; - this.sessionIsEphemeral_ = null; - this.onBeforeSetHeadersSet_ = false; this.useEafe_ = false; this.clientId_ = null; @@ -216,14 +209,6 @@ this.webview_.contextMenus.onShow.addListener(function(e) { e.preventDefault(); }); - if (!this.onBeforeSetHeadersSet_) { - this.onBeforeSetHeadersSet_ = true; - var filterPrefix = this.idpOrigin_ + EMBEDDED_SETUP_CHROMEOS_ENDPOINT; - this.webview_.request.onBeforeSendHeaders.addListener( - this.onBeforeSendHeaders_.bind(this), - {urls: [filterPrefix + '?*', filterPrefix + '/*']}, - ['requestHeaders', 'blocking']); - } } this.webview_.src = this.reloadUrl_; @@ -261,8 +246,6 @@ url = appendParam(url, 'release_channel', data.releaseChannel); if (data.endpointGen) url = appendParam(url, 'endpoint_gen', data.endpointGen); - this.deviceId_ = data.deviceId; - this.sessionIsEphemeral_ = data.sessionIsEphemeral; } else { url = appendParam(url, 'continue', this.continueUrl_); url = appendParam(url, 'service', data.service || SERVICE_ID); @@ -397,36 +380,6 @@ }; /** - * Handler for webView.request.onBeforeSendHeaders . - * @return {!Object} Modified request headers. - * @private - */ - Authenticator.prototype.onBeforeSendHeaders_ = function(details) { - // deviceId_ is empty when we do not need to send it. For example, - // in case of device enrollment. - if (this.isNewGaiaFlowChromeOS && this.deviceId_) { - var headers = details.requestHeaders; - var found = false; - var deviceId = this.getGAIADeviceId_(); - - for (var i = 0, l = headers.length; i < l; ++i) { - if (headers[i].name == X_DEVICE_ID_HEADER) { - headers[i].value = deviceId; - found = true; - break; - } - } - if (!found) { - details.requestHeaders.push( - {name: X_DEVICE_ID_HEADER, value: deviceId}); - } - } - return { - requestHeaders: details.requestHeaders - }; - }; - - /** * Returns true if given HTML5 message is received from the webview element. * @param {object} e Payload of the received HTML5 message. */ @@ -582,8 +535,7 @@ chooseWhatToSync: this.chooseWhatToSync_, skipForNow: this.skipForNow_, sessionIndex: this.sessionIndex_ || '', - trusted: this.trusted_, - deviceId: this.deviceId_ || '' + trusted: this.trusted_ } })); this.clearCredentials_(); @@ -647,7 +599,6 @@ if (currentUrl.lastIndexOf(this.idpOrigin_) == 0) { var msg = { 'method': 'handshake', - 'deviceId': this.getGAIADeviceId_(), }; this.webview_.contentWindow.postMessage(msg, currentUrl); @@ -716,37 +667,6 @@ }; /** - * Format deviceId for GAIA . - * @return {string} deviceId. - * @private - */ - Authenticator.prototype.getGAIADeviceId_ = function() { - // deviceId_ is empty when we do not need to send it. For example, - // in case of device enrollment. - if (!(this.isNewGaiaFlowChromeOS && this.deviceId_)) - return; - - if (this.sessionIsEphemeral_) - return EPHEMERAL_DEVICE_ID_PREFIX + this.deviceId_; - else - return this.deviceId_; - }; - - /** - * Informs Gaia of new deviceId to be used. - */ - Authenticator.prototype.updateDeviceId = function(deviceId) { - this.deviceId_ = deviceId; - var msg = { - 'method': 'updateDeviceId', - 'deviceId': this.getGAIADeviceId_(), - }; - - var currentUrl = this.webview_.src; - this.webview_.contentWindow.postMessage(msg, currentUrl); - }; - - /** * The current auth flow of the hosted auth page. * @type {AuthFlow} */
diff --git a/chrome/browser/resources/google_now/background.js b/chrome/browser/resources/google_now/background.js index 2db2d1e..aebf1be 100644 --- a/chrome/browser/resources/google_now/background.js +++ b/chrome/browser/resources/google_now/background.js
@@ -1028,8 +1028,6 @@ */ function initialize() { recordEvent(GoogleNowEvent.EXTENSION_START); - // TODO(skare): Reenable, after signin. - unregisterFromGcm(); onStateChange(); } @@ -1054,7 +1052,8 @@ } /** - * Starts or stops the optin check. + * Starts or stops the optin check and GCM channel to receive optin + * notifications. * @param {boolean} shouldPollOptInStatus true to start and false to stop * polling the optin status. */ @@ -1073,6 +1072,12 @@ 'Action Ignored setShouldPollOptInStatus=' + shouldPollOptInStatus); } }); + + if (shouldPollOptInStatus) { + registerForGcm(); + } else { + unregisterFromGcm(); + } } /**
diff --git a/chrome/browser/resources/local_ntp/most_visited_single.js b/chrome/browser/resources/local_ntp/most_visited_single.js index ce9fb810..46d2897 100644 --- a/chrome/browser/resources/local_ntp/most_visited_single.js +++ b/chrome/browser/resources/local_ntp/most_visited_single.js
@@ -338,11 +338,16 @@ tile.href = data.url; tile.title = data.title; - tile.addEventListener('keypress', function(ev) { - if (ev.keyCode == 127) { // DELETE + tile.addEventListener('keydown', function(event) { + if (event.keyCode == 46 /* DELETE */ || + event.keyCode == 8 /* BACKSPACE */) { + event.preventDefault(); + event.stopPropagation(); blacklistTile(tile); - ev.stopPropagation(); - return false; + } else if (event.keyCode == 13 /* ENTER */ || + event.keyCode == 32 /* SPACE */) { + event.preventDefault(); + tile.click(); } }); // TODO(fserb): remove this or at least change to mouseenter.
diff --git a/chrome/browser/resources/media_router/media_router_common.css b/chrome/browser/resources/media_router/media_router_common.css index 47d72ae..4add52ebc 100644 --- a/chrome/browser/resources/media_router/media_router_common.css +++ b/chrome/browser/resources/media_router/media_router_common.css
@@ -9,6 +9,7 @@ cursor: pointer; font-size: 1em; font-weight: bold; + margin: 0; overflow: hidden; text-align: center; width: 100%;
diff --git a/chrome/browser/resources/ntp4/compiled_resources.gyp b/chrome/browser/resources/ntp4/compiled_resources.gyp index 8316d78..ed02952 100644 --- a/chrome/browser/resources/ntp4/compiled_resources.gyp +++ b/chrome/browser/resources/ntp4/compiled_resources.gyp
@@ -39,7 +39,6 @@ 'page_list_view.js', 'nav_dot.js', 'other_sessions.js', - 'suggestions_page.js', 'new_tab.js', ], 'externs': ['<(CLOSURE_DIR)/externs/chrome_send_externs.js'],
diff --git a/chrome/browser/resources/ntp4/new_tab.html b/chrome/browser/resources/ntp4/new_tab.html index 3694ba00..4cac17a1 100644 --- a/chrome/browser/resources/ntp4/new_tab.html +++ b/chrome/browser/resources/ntp4/new_tab.html
@@ -27,7 +27,6 @@ <link rel="stylesheet" href="../../../../ui/webui/resources/css/trash.css"> <link rel="stylesheet" href="../../../../ui/webui/resources/css/widgets.css"> <link rel="stylesheet" href="apps_page.css"> -<link rel="stylesheet" href="chrome://newtab/suggestions_page.css"> <link rel="stylesheet" href="most_visited_page.css"> <link rel="stylesheet" href="nav_dot.css"> <link rel="stylesheet" href="new_tab.css">
diff --git a/chrome/browser/resources/ntp4/new_tab.js b/chrome/browser/resources/ntp4/new_tab.js index 007bd039..4c1ac76 100644 --- a/chrome/browser/resources/ntp4/new_tab.js +++ b/chrome/browser/resources/ntp4/new_tab.js
@@ -137,8 +137,6 @@ function() { chrome.send('onLearnMore'); }); } } - if (loadTimeData.getBoolean('isDiscoveryInNTPEnabled')) - sectionsToWaitFor++; measureNavDots(); // Load the current theme colors. @@ -171,21 +169,6 @@ chrome.send('getMostVisited'); } - if (loadTimeData.getBoolean('isDiscoveryInNTPEnabled')) { - var suggestionsScript = document.createElement('script'); - suggestionsScript.src = 'suggestions_page.js'; - suggestionsScript.onload = function() { - newTabView.appendTilePage(new ntp.SuggestionsPage(), - loadTimeData.getString('suggestions'), - false, - (newTabView.appsPages.length > 0) ? - newTabView.appsPages[0] : null); - chrome.send('getSuggestions'); - cr.dispatchSimpleEvent(document, 'sectionready', true, true); - }; - document.querySelector('head').appendChild(suggestionsScript); - } - if (!loadTimeData.getBoolean('showWebStoreIcon')) { var webStoreIcon = $('chrome-web-store-link'); // Not all versions of the NTP have a footer, so this may not exist. @@ -547,10 +530,6 @@ cr.dispatchSimpleEvent(document, 'sectionready', true, true); } - function setSuggestionsPages(data, hasBlacklistedUrls) { - newTabView.suggestionsPage.data = data; - } - /** * Set the dominant color for a node. This will be called in response to * getFaviconDominantColor. The node represented by |id| better have a setter @@ -759,7 +738,6 @@ setBookmarkBarAttached: setBookmarkBarAttached, setForeignSessions: setForeignSessions, setMostVisitedPages: setMostVisitedPages, - setSuggestionsPages: setSuggestionsPages, setFaviconDominantColor: setFaviconDominantColor, showNotification: showNotification, themeChanged: themeChanged,
diff --git a/chrome/browser/resources/ntp4/page_list_view.js b/chrome/browser/resources/ntp4/page_list_view.js index 14c613b..fa1513b9 100644 --- a/chrome/browser/resources/ntp4/page_list_view.js +++ b/chrome/browser/resources/ntp4/page_list_view.js
@@ -86,12 +86,6 @@ appsPages: undefined, /** - * The Suggestions page. - * @type {!Element|undefined} - */ - suggestionsPage: undefined, - - /** * The Most Visited page. * @type {!Element|undefined} */ @@ -273,11 +267,6 @@ this.mostVisitedPage = page; } - if (typeof ntp.SuggestionsPage != 'undefined' && - page instanceof ntp.SuggestionsPage) { - this.suggestionsPage = page; - } - // If we're appending an AppsPage and it's a temporary page, animate it. var animate = page instanceof ntp.AppsPage && page.classList.contains('temporary'); @@ -536,19 +525,6 @@ this.tilePages.length - 1)); this.cardSlider.setCards(Array.prototype.slice.call(this.tilePages), pageNo); - // The shownPage property was potentially saved from a previous webui that - // didn't have the same set of pages as the current one. So we cascade - // from suggestions, to most visited and then to apps because we can have - // an page with apps only (e.g., chrome://apps) or one with only the most - // visited, but not one with only suggestions. And we alwayd default to - // most visited first when previously shown page is not availabel anymore. - // If most visited isn't there either, we go to apps. - if (this.shownPage == loadTimeData.getInteger('suggestions_page_id')) { - if (this.suggestionsPage) - this.cardSlider.selectCardByValue(this.suggestionsPage); - else - this.shownPage = loadTimeData.getInteger('most_visited_page_id'); - } if (this.shownPage == loadTimeData.getInteger('most_visited_page_id')) { if (this.mostVisitedPage) this.cardSlider.selectCardByValue(this.mostVisitedPage); @@ -692,8 +668,6 @@ } else if (page.classList.contains('most-visited-page')) { this.setShownPage_( loadTimeData.getInteger('most_visited_page_id'), 0); - } else if (page.classList.contains('suggestions-page')) { - this.setShownPage_(loadTimeData.getInteger('suggestions_page_id'), 0); } else { console.error('unknown page selected'); }
diff --git a/chrome/browser/resources/ntp4/suggestions_page.css b/chrome/browser/resources/ntp4/suggestions_page.css deleted file mode 100644 index 8fd1109..0000000 --- a/chrome/browser/resources/ntp4/suggestions_page.css +++ /dev/null
@@ -1,109 +0,0 @@ -/* Copyright (c) 2012 The Chromium Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. */ - -.suggestions { - position: absolute; - z-index: 0; -} - -.suggestions { - -webkit-box-orient: vertical; - display: -webkit-box; - position: absolute; - text-decoration: none; -} - -.suggestions:focus { - outline: none; -} - -.suggestions .close-button { - -webkit-transition: opacity 150ms; - opacity: 0; - position: absolute; - right: 0; - top: 0; - z-index: 5; -} - -html[dir=rtl] .suggestions .close-button { - left: 0; - right: auto; -} - -.suggestions:hover .close-button { - -webkit-transition-delay: 500ms; - opacity: 1; -} - -.suggestions .close-button:hover { - -webkit-transition: none; -} - -.suggestions .favicon { - -webkit-margin-start: 5px; - background: no-repeat left 50%; - bottom: 7px; - box-sizing: border-box; - display: block; - height: 16px; - position: absolute; - width: 16px; -} - -html[dir='rtl'] .suggestions .favicon { - background-position-x: right; -} - -.suggestions .color-stripe { - border-bottom-left-radius: 3px 3px; - border-bottom-right-radius: 3px 3px; - /* Matches height of title plus height of score. */ - bottom: 36px; - height: 3px; - position: absolute; - width: 100%; - z-index: 10; -} - -.suggestions .title { - display: block; - height: 18px; - overflow: hidden; - text-align: center; - text-overflow: ellipsis; - white-space: nowrap; -} - -.suggestions .score { - display: block; - height: 18px; - overflow: hidden; - text-align: center; -} - -.suggestions:focus .thumbnail, -.suggestions:hover .thumbnail { - opacity: 0.95; -} - -.suggestions:focus .thumbnail-shield, -.suggestions:hover .thumbnail-shield, -.suggestions:active .thumbnail-shield { - background: -webkit-linear-gradient(rgba(255, 255, 255, 0), - rgba(255, 255, 255, 0) 80%, - rgba(255, 255, 255, 0.9)); -} - -/* The thumbnail gets lighter when clicked, but not when the click is on the - * close button. */ -.suggestions:active .close-button:not(:active) + .thumbnail { - opacity: 0.9; -} - -/* The thumbnail gets a shadow when clicked, but not when the click is on the - * close button. */ -.suggestions:active .close-button:not(:active) + .thumbnail .thumbnail-shield { - box-shadow: inset 0 1px 10px rgba(0, 0, 0, 0.2); -}
diff --git a/chrome/browser/resources/ntp4/suggestions_page.js b/chrome/browser/resources/ntp4/suggestions_page.js deleted file mode 100644 index 6dc5ecd..0000000 --- a/chrome/browser/resources/ntp4/suggestions_page.js +++ /dev/null
@@ -1,478 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -cr.define('ntp', function() { - 'use strict'; - - var TilePage = ntp.TilePage; - - /** - * A counter for generating unique tile IDs. - */ - var tileID = 0; - - /** - * Creates a new Suggestions page object for tiling. - * @constructor - * @extends {HTMLAnchorElement} - */ - function Suggestion() { - var el = cr.doc.createElement('a'); - el.__proto__ = Suggestion.prototype; - el.initialize(); - - return el; - } - - Suggestion.prototype = { - __proto__: HTMLAnchorElement.prototype, - - initialize: function() { - this.reset(); - - this.addEventListener('click', this.handleClick_); - this.addEventListener('keydown', this.handleKeyDown_); - }, - - get index() { - assert(this.tile); - return this.tile.index; - }, - - get data() { - return this.data_; - }, - - /** - * Clears the DOM hierarchy for this node, setting it back to the default - * for a blank thumbnail. TODO(georgey) make it a template. - */ - reset: function() { - this.className = 'suggestions filler real'; - this.innerHTML = - '<span class="thumbnail-wrapper fills-parent">' + - '<div class="close-button"></div>' + - '<span class="thumbnail fills-parent">' + - // thumbnail-shield provides a gradient fade effect. - '<div class="thumbnail-shield fills-parent"></div>' + - '</span>' + - '<span class="favicon"></span>' + - '</span>' + - '<div class="color-stripe"></div>' + - '<span class="title"></span>' + - '<span class="score"></span>'; - - this.querySelector('.close-button').title = - loadTimeData.getString('removethumbnailtooltip'); - - this.tabIndex = -1; - this.data_ = null; - this.removeAttribute('id'); - this.title = ''; - }, - - /** - * Update the appearance of this tile according to |data|. - * @param {{score: number, url: string, title: string, direction: string, - * filler: boolean}} data A dictionary of relevant data for the page. - * @see chrome/browser/ui/webui/ntp/suggestions_source_top_sites.cc - * @see chrome/browser/ui/webui/ntp/most_visited_handler.cc - */ - updateForData: function(data) { - if (this.classList.contains('blacklisted') && data) { - // Animate appearance of new tile. - this.classList.add('new-tile-contents'); - } - this.classList.remove('blacklisted'); - - if (!data || data.filler) { - if (this.data_) - this.reset(); - return; - } - - var id = tileID++; - this.id = 'suggestions-tile-' + id; - this.data_ = data; - this.classList.add('focusable'); - - var faviconDiv = this.querySelector('.favicon'); - var faviconUrl = 'chrome://favicon/size/16@1x/' + data.url; - faviconDiv.style.backgroundImage = url(faviconUrl); - chrome.send('getFaviconDominantColor', [faviconUrl, this.id]); - - var title = this.querySelector('.title'); - title.textContent = data.title; - title.dir = data.direction; - - var score = this.querySelector('.score'); - score.textContent = data.score; - - // Sets the tooltip. - this.title = data.title; - - var thumbnailUrl; - thumbnailUrl = data.urlImage ? data.urlImage : - 'chrome://thumb/' + data.url; - - this.querySelector('.thumbnail').style.backgroundImage = - url(thumbnailUrl); - - this.href = data.url; - - this.classList.remove('filler'); - }, - - /** - * Sets the color of the favicon dominant color bar. - * @param {string} color The css-parsable value for the color. - */ - set stripeColor(color) { - this.querySelector('.color-stripe').style.backgroundColor = color; - }, - - /** - * Handles a click on the tile. - * @param {Event} e The click event. - */ - handleClick_: function(e) { - if (e.target.classList.contains('close-button')) { - this.blacklist_(); - e.preventDefault(); - } else { - // Records the index of this tile. - chrome.send('metricsHandler:recordInHistogram', - ['NewTabPage.SuggestedSite', this.index, 8]); - chrome.send('suggestedSitesAction', - [ntp.NtpFollowAction.CLICKED_TILE]); - } - }, - - /** - * Allow blacklisting suggestions site using the keyboard. - * @param {Event} e The keydown event. - */ - handleKeyDown_: function(e) { - if (!cr.isMac && e.keyCode == 46 || // Del - cr.isMac && e.metaKey && e.keyCode == 8) { // Cmd + Backspace - this.blacklist_(); - } - }, - - /** - * Permanently removes a page from Suggestions. - */ - blacklist_: function() { - this.showUndoNotification_(); - chrome.send('blacklistURLFromSuggestions', [this.data_.url]); - this.reset(); - chrome.send('getSuggestions'); - this.classList.add('blacklisted'); - }, - - /** - * Shows notification that you can undo blacklisting. - */ - showUndoNotification_: function() { - var data = this.data_; - var self = this; - var doUndo = function() { - chrome.send('removeURLsFromSuggestionsBlacklist', [data.url]); - self.updateForData(data); - }; - - var undo = { - action: doUndo, - text: loadTimeData.getString('undothumbnailremove'), - }; - - var undoAll = { - action: function() { - chrome.send('clearSuggestionsURLsBlacklist'); - }, - text: loadTimeData.getString('restoreThumbnailsShort'), - }; - - ntp.showNotification( - loadTimeData.getString('thumbnailremovednotification'), - [undo, undoAll]); - }, - - /** - * Set the size and position of the suggestions tile. - * @param {number} size The total size of |this|. - * @param {number} x The x-position. - * @param {number} y The y-position. - */ - setBounds: function(size, x, y) { - this.style.width = size + 'px'; - this.style.height = heightForWidth(size) + 'px'; - - this.style.left = x + 'px'; - this.style.right = x + 'px'; - this.style.top = y + 'px'; - }, - - /** - * Returns whether this element can be 'removed' from chrome (i.e. whether - * the user can drag it onto the trash and expect something to happen). - * @return {boolean} True, since suggestions pages can always be - * blacklisted. - */ - canBeRemoved: function() { - return true; - }, - - /** - * Removes this element from chrome, i.e. blacklists it. - */ - removeFromChrome: function() { - this.blacklist_(); - this.parentNode.classList.add('finishing-drag'); - }, - - /** - * Called when a drag of this tile has ended (after all animations have - * finished). - */ - finalizeDrag: function() { - this.parentNode.classList.remove('finishing-drag'); - }, - - /** - * Called when a drag is starting on the tile. Updates dataTransfer with - * data for this tile (for dragging outside of the NTP). - * @param {DataTransfer} dataTransfer The drag event data store. - */ - setDragData: function(dataTransfer) { - dataTransfer.setData('Text', this.data_.title); - dataTransfer.setData('URL', this.data_.url); - }, - }; - - var suggestionsPageGridValues = { - // The fewest tiles we will show in a row. - minColCount: 2, - // The suggestions we will show in a row. - maxColCount: 4, - - // The smallest a tile can be. - minTileWidth: 122, - // The biggest a tile can be. 212 (max thumbnail width) + 2. - maxTileWidth: 214, - - // The padding between tiles, as a fraction of the tile width. - tileSpacingFraction: 1 / 8, - }; - TilePage.initGridValues(suggestionsPageGridValues); - - /** - * Calculates the height for a Suggestion tile for a given width. The size - * is based on the thumbnail, which should have a 212:132 ratio. - * @return {number} The height. - */ - function heightForWidth(width) { - // The 2s are for borders, the 36 is for the title and score. - return (width - 2) * 132 / 212 + 2 + 36; - } - - var THUMBNAIL_COUNT = 8; - - /** - * Creates a new SuggestionsPage object. - * @constructor - * @extends {TilePage} - */ - function SuggestionsPage() { - var el = new TilePage(suggestionsPageGridValues); - el.__proto__ = SuggestionsPage.prototype; - el.initialize(); - - return el; - } - - SuggestionsPage.prototype = { - __proto__: TilePage.prototype, - - initialize: function() { - this.classList.add('suggestions-page'); - this.data_ = null; - this.suggestionsTiles_ = this.getElementsByClassName('suggestions real'); - - this.addEventListener('carddeselected', this.handleCardDeselected_); - this.addEventListener('cardselected', this.handleCardSelected_); - }, - - /** - * Create blank (filler) tiles. - * @private - */ - createTiles_: function() { - for (var i = 0; i < THUMBNAIL_COUNT; i++) { - this.appendTile(new Suggestion(), false); - } - }, - - /** - * Update the tiles after a change to |this.data_|. - */ - updateTiles_: function() { - for (var i = 0; i < THUMBNAIL_COUNT; i++) { - var page = this.data_[i]; - var tile = this.suggestionsTiles_[i]; - - if (i >= this.data_.length) - tile.reset(); - else - tile.updateForData(page); - } - }, - - /** - * Handles the 'card deselected' event (i.e. the user clicked to another - * pane). - * @param {Event} e The CardChanged event. - */ - handleCardDeselected_: function(e) { - if (!document.documentElement.classList.contains('starting-up')) { - chrome.send('suggestedSitesAction', - [ntp.NtpFollowAction.CLICKED_OTHER_NTP_PANE]); - } - }, - - /** - * Handles the 'card selected' event (i.e. the user clicked to select the - * Suggested pane). - * @param {Event} e The CardChanged event. - */ - handleCardSelected_: function(e) { - if (!document.documentElement.classList.contains('starting-up')) - chrome.send('suggestedSitesSelected'); - }, - - /** - * Array of suggestions data objects. - * @type {Array} - */ - get data() { - return this.data_; - }, - set data(data) { - var startTime = Date.now(); - - // The first time data is set, create the tiles. - if (!this.data_) { - this.createTiles_(); - this.data_ = data.slice(0, THUMBNAIL_COUNT); - } else { - this.data_ = refreshData(this.data_, data); - } - - this.updateTiles_(); - this.updateFocusableElement(); - logEvent('suggestions.layout: ' + (Date.now() - startTime)); - }, - - /** @override */ - shouldAcceptDrag: function(e) { - return false; - }, - - /** @override */ - heightForWidth: heightForWidth, - }; - - /** - * Executed once the NTP has loaded. Checks if the Suggested pane is - * shown or not. If it is shown, the 'suggestedSitesSelected' message is sent - * to the C++ code, to record the fact that the user has seen this pane. - */ - SuggestionsPage.onLoaded = function() { - if (ntp.getCardSlider() && - ntp.getCardSlider().currentCardValue && - ntp.getCardSlider().currentCardValue.classList - .contains('suggestions-page')) { - chrome.send('suggestedSitesSelected'); - } - }; - - /** - * We've gotten additional data for Suggestions page. Update our old data with - * the new data. The ordering of the new data is not important, except when a - * page is pinned. Thus we try to minimize re-ordering. - * @param {Array} oldData The current Suggestions page list. - * @param {Array} newData The new Suggestions page list. - * @return {Array} The merged page list that should replace the current page - * list. - */ - function refreshData(oldData, newData) { - oldData = oldData.slice(0, THUMBNAIL_COUNT); - newData = newData.slice(0, THUMBNAIL_COUNT); - - // Copy over pinned sites directly. - for (var i = 0; i < newData.length; i++) { - if (newData[i].pinned) { - oldData[i] = newData[i]; - // Mark the entry as 'updated' so we don't try to update again. - oldData[i].updated = true; - // Mark the newData page as 'used' so we don't try to re-use it. - newData[i].used = true; - } - } - - // Look through old pages; if they exist in the newData list, keep them - // where they are. - for (var i = 0; i < oldData.length; i++) { - if (!oldData[i] || oldData[i].updated) - continue; - - for (var j = 0; j < newData.length; j++) { - if (newData[j].used) - continue; - - if (newData[j].url == oldData[i].url) { - // The background image and other data may have changed. - oldData[i] = newData[j]; - oldData[i].updated = true; - newData[j].used = true; - break; - } - } - } - - // Look through old pages that haven't been updated yet; replace them. - for (var i = 0; i < oldData.length; i++) { - if (oldData[i] && oldData[i].updated) - continue; - - for (var j = 0; j < newData.length; j++) { - if (newData[j].used) - continue; - - oldData[i] = newData[j]; - oldData[i].updated = true; - newData[j].used = true; - break; - } - - if (oldData[i] && !oldData[i].updated) - oldData[i] = null; - } - - // Clear 'updated' flags so this function will work next time it's called. - for (var i = 0; i < THUMBNAIL_COUNT; i++) { - if (oldData[i]) - oldData[i].updated = false; - } - - return oldData; - } - - return { - SuggestionsPage: SuggestionsPage, - refreshData: refreshData, - }; -}); - -document.addEventListener('ntpLoaded', ntp.SuggestionsPage.onLoaded);
diff --git a/chrome/browser/resources/suggestions_internals/suggestions_internals.css b/chrome/browser/resources/suggestions_internals/suggestions_internals.css deleted file mode 100644 index 1996edcd..0000000 --- a/chrome/browser/resources/suggestions_internals/suggestions_internals.css +++ /dev/null
@@ -1,37 +0,0 @@ -/* Copyright (c) 2012 The Chromium Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. */ - -.suggestions-debug-table { - border: 1px solid grey; - margin-bottom: 1.5em; -} - -.suggestions-debug-table th { - border: 1px solid grey; -} - -.suggestions-debug-table td { - border: 1px solid grey; -} - -p { - margin: 0; -} - -.input-section { - margin-bottom: 1em; -} - -.boolean-property-true { - background-color: rgb(146, 205, 0); -} - -.boolean-property-false { - background-color: rgb(205, 74, 0); -} - -.boolean-property-true, -.boolean-property-false { - text-align: center; -}
diff --git a/chrome/browser/resources/suggestions_internals/suggestions_internals.html b/chrome/browser/resources/suggestions_internals/suggestions_internals.html deleted file mode 100644 index 8ed75ca..0000000 --- a/chrome/browser/resources/suggestions_internals/suggestions_internals.html +++ /dev/null
@@ -1,26 +0,0 @@ -<!doctype html> -<html> -<head> - <meta charset="utf-8"> - <title>Suggestions Internals</title> - <link rel="stylesheet" href="chrome://resources/css/text_defaults.css"> - <link rel="stylesheet" href="suggestions_internals.css"> - <script src="chrome://resources/js/cr.js"></script> - <script src="chrome://resources/js/util.js"></script> - <script src="suggestions_internals.js"></script> -</head> -<body> - <div class="input-section"> - <form id="suggestions-form" action=""> - <p> - <input id="refresh-data" type="submit" value="Refresh data"> - </p> - <p> - <input id="show-discarded" type="checkbox"> - <label for="show-discarded">Show discarded items</label> - </p> - </form> - </div> - <div id="suggestions-debug-text"></div> -</body> -</html>
diff --git a/chrome/browser/resources/suggestions_internals/suggestions_internals.js b/chrome/browser/resources/suggestions_internals/suggestions_internals.js deleted file mode 100644 index 63a9ace..0000000 --- a/chrome/browser/resources/suggestions_internals/suggestions_internals.js +++ /dev/null
@@ -1,186 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -/** - * Javascript for suggestions_internals.html, served from - * chrome://suggestions-internals/. This is used to debug suggestions ranking. - * When loaded, the page will show the current set of suggestions, along with a - * large set of information (e.g. all the signals that were taken into - * consideration for deciding which pages were selected to be shown to the user) - * that will aid in debugging and optimizing the algorithms. - */ -cr.define('suggestionsInternals', function() { - 'use strict'; - - /** - * Register our event handlers. - */ - function initialize() { - $('suggestions-form').addEventListener('submit', onRefreshClicked); - $('show-discarded').addEventListener('change', refresh); - refresh(); - } - - /** - * Called when the 'Refresh' button is clicked. Reloads the suggestions data. - */ - function onRefreshClicked(event) { - refresh(); - event.preventDefault(); - } - - /** - * Reloads the suggestions data by sending a 'getSuggestions' message to - * Chrome. The C++ code is then expected to call 'setSuggestions' when there - * are suggestions ready. - */ - function refresh() { - chrome.send('getSuggestions'); - } - - /** - * A list of columns that we do not want to display. - * @type {Array<string>} - * @const - */ - var IGNORED_COLUMNS = [ - 'direction' - ]; - - /** - * A list specifying the name of the first columns to be displayed. If - * present, they will be displayed in this order, followed by the remaining - * columns. - * @type {Array<string>} - * @const - */ - var PREFERRED_COLUMN_ORDER = [ - 'title', - 'url', - 'score' - ]; - - function setBooleanColumn(column, value) { - if (value) { - column.innerText = 'Y'; - column.classList.add('boolean-property-true'); - } else { - column.innerText = 'N'; - column.classList.add('boolean-property-false'); - } - } - - /** - * Called by Chrome code, with a ranked list of suggestions. The columns - * to be displayed are calculated automatically from the properties of the - * elements in the list, such that all properties have a column. - */ - function setSuggestions(list) { - // Build a list of all the columns that will be displayed. - var columns = []; - list.forEach(function(entry) { - for (var column in entry) { - if (typeof entry[column] == 'object') { - // Expand one level deep - for (var subColumn in entry[column]) { - var path = column + '.' + subColumn; - if (columns.indexOf(path) < 0) - columns.push(path); - } - } else if (columns.indexOf(column) < 0) { - columns.push(column); - } - } - }); - - // Remove columns that we don't want to display. - columns = columns.filter(function(column) { - return IGNORED_COLUMNS.indexOf(column) < 0; - }); - - // Move the preferred columns to the start of the column list. - for (var i = PREFERRED_COLUMN_ORDER.length - 1; i >= 0; i--) { - var index = columns.indexOf(PREFERRED_COLUMN_ORDER[i]); - if (index >= 0) - columns.unshift(columns.splice(index, 1)[0]); - } - - // Special columns. - columns.unshift('favicon'); - columns.unshift('screenshot'); - columns.unshift('rank'); - - // Erase whatever is currently being displayed. - var output = $('suggestions-debug-text'); - output.innerHTML = ''; - - // Create the container table and add the header row. - var table = document.createElement('table'); - table.className = 'suggestions-debug-table'; - var header = document.createElement('tr'); - columns.forEach(function(entry) { - var column = document.createElement('th'); - column.innerText = entry; - header.appendChild(column); - }); - table.appendChild(header); - - // Add all the suggestions to the table. - var rank = 1; - list.forEach(function(entry) { - var row = document.createElement('tr'); - columns.forEach(function(columnName) { - var column = document.createElement('td'); - // Expand the path and find the data if it's there. - var path = columnName.split('.'); - var data = entry; - for (var i = 0; i < path.length; ++i) { - if (data && data.hasOwnProperty(path[i])) - data = data[path[i]]; - else - data = undefined; - } - // Only add the column if the current suggestion has this property - // (otherwise, leave the cell empty). - if (typeof(data) != 'undefined') { - if (typeof(data) == 'boolean') { - setBooleanColumn(column, data); - } else if (/^https?:\/\/.+$/.test(data)) { - // If the text is a URL, make it an anchor element. - var anchor = document.createElement('a'); - anchor.href = data; - anchor.innerText = data; - column.appendChild(anchor); - } else { - column.innerText = data; - } - } else if (columnName == 'rank') { - column.innerText = rank++; - } else if (columnName == 'screenshot') { - var thumbnailUrl = 'chrome://thumb/' + entry.url; - var img = document.createElement('img'); - img.onload = function() { setBooleanColumn(column, true); }; - img.onerror = function() { setBooleanColumn(column, false); }; - img.src = thumbnailUrl; - } else if (columnName == 'favicon') { - var faviconUrl = 'chrome://favicon/size/16@1x/' + entry.url; - column.style.backgroundImage = url(faviconUrl); - column.style.backgroundRepeat = 'no-repeat'; - column.style.backgroundPosition = 'center center'; - } - row.appendChild(column); - }); - table.appendChild(row); - }); - - output.appendChild(table); - } - - return { - initialize: initialize, - setSuggestions: setSuggestions - }; -}); - -document.addEventListener('DOMContentLoaded', suggestionsInternals.initialize);
diff --git a/chrome/browser/safe_browsing/incident_reporting/preference_validation_delegate.cc b/chrome/browser/safe_browsing/incident_reporting/preference_validation_delegate.cc index 6ac435dc..60b460ad 100644 --- a/chrome/browser/safe_browsing/incident_reporting/preference_validation_delegate.cc +++ b/chrome/browser/safe_browsing/incident_reporting/preference_validation_delegate.cc
@@ -62,7 +62,7 @@ incident->set_path(pref_path); if (!value || (!value->GetAsString(incident->mutable_atomic_value()) && - !base::JSONWriter::Write(value, incident->mutable_atomic_value()))) { + !base::JSONWriter::Write(*value, incident->mutable_atomic_value()))) { incident->clear_atomic_value(); } incident->set_value_state(proto_value_state);
diff --git a/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc b/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc index 472dc51..a11bee0d 100644 --- a/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc +++ b/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc
@@ -159,7 +159,7 @@ // This must be done after calculating |interstitial_reason_| above. // Use same prefix for UMA as for Rappor. set_metrics_helper(new SecurityInterstitialMetricsHelper( - web_contents, request_url(), GetMetricPrefix(), GetMetricPrefix(), + web_contents, request_url(), GetMetricPrefix(), GetRapporPrefix(), SecurityInterstitialMetricsHelper::REPORT_RAPPOR, GetSamplingEventName())); metrics_helper()->RecordUserDecision(SecurityInterstitialMetricsHelper::SHOW); @@ -493,6 +493,20 @@ } std::string SafeBrowsingBlockingPage::GetMetricPrefix() const { + bool primary_subresource = unsafe_resources_[0].is_subresource; + switch (interstitial_reason_) { + case SB_REASON_MALWARE: + return primary_subresource ? "malware_subresource" : "malware"; + case SB_REASON_HARMFUL: + return primary_subresource ? "harmful_subresource" : "harmful"; + case SB_REASON_PHISHING: + return primary_subresource ? "phishing_subresource" : "phishing"; + } + NOTREACHED(); + return std::string(); +} + +std::string SafeBrowsingBlockingPage::GetRapporPrefix() const { switch (interstitial_reason_) { case SB_REASON_MALWARE: return "malware";
diff --git a/chrome/browser/safe_browsing/safe_browsing_blocking_page.h b/chrome/browser/safe_browsing/safe_browsing_blocking_page.h index a42b022..80e0642 100644 --- a/chrome/browser/safe_browsing/safe_browsing_blocking_page.h +++ b/chrome/browser/safe_browsing/safe_browsing_blocking_page.h
@@ -186,6 +186,7 @@ void PopulatePhishingLoadTimeData(base::DictionaryValue* load_time_data); std::string GetMetricPrefix() const; + std::string GetRapporPrefix() const; std::string GetSamplingEventName() const; DISALLOW_COPY_AND_ASSIGN(SafeBrowsingBlockingPage);
diff --git a/chrome/browser/safe_json_parser_browsertest.cc b/chrome/browser/safe_json_parser_browsertest.cc index 5d7f5a10..f67e513d 100644 --- a/chrome/browser/safe_json_parser_browsertest.cc +++ b/chrome/browser/safe_json_parser_browsertest.cc
@@ -19,7 +19,7 @@ return "(null)"; std::string json; - if (!base::JSONWriter::Write(value, &json)) + if (!base::JSONWriter::Write(*value, &json)) return "(invalid value)"; return json;
diff --git a/chrome/browser/services/gcm/instance_id/instance_id_profile_service.cc b/chrome/browser/services/gcm/instance_id/instance_id_profile_service.cc index 47a6f3a0..dc80f36 100644 --- a/chrome/browser/services/gcm/instance_id/instance_id_profile_service.cc +++ b/chrome/browser/services/gcm/instance_id/instance_id_profile_service.cc
@@ -19,10 +19,12 @@ if (!gcm::GCMProfileService::IsGCMEnabled(profile)) return false; - // Enabled for trunk build. + // Enabled only for trunk/canary/dev builds. chrome::VersionInfo::Channel channel = chrome::VersionInfo::GetChannel(); - if (channel == chrome::VersionInfo::CHANNEL_UNKNOWN) - return true; + if (channel == chrome::VersionInfo::CHANNEL_BETA || + channel == chrome::VersionInfo::CHANNEL_STABLE) { + return false; + } return InstanceIDDriver::IsInstanceIDEnabled(); }
diff --git a/chrome/browser/sessions/tab_loader.cc b/chrome/browser/sessions/tab_loader.cc index bf1b00a..98226b7 100644 --- a/chrome/browser/sessions/tab_loader.cc +++ b/chrome/browser/sessions/tab_loader.cc
@@ -117,7 +117,7 @@ delegate_ = TabLoaderDelegate::Create(this); // There is already at least one tab loading (the active tab). As such we // only have to start the timeout timer here. - StartTimer(); + StartFirstTimer(); } } @@ -152,6 +152,13 @@ StartTimer(); } +void TabLoader::StartFirstTimer() { + force_load_timer_.Stop(); + force_load_timer_.Start(FROM_HERE, + delegate_->GetFirstTabLoadingTimeout(), + this, &TabLoader::ForceLoadTimerFired); +} + void TabLoader::StartTimer() { force_load_timer_.Stop(); force_load_timer_.Start(FROM_HERE,
diff --git a/chrome/browser/sessions/tab_loader.h b/chrome/browser/sessions/tab_loader.h index 519d024..d40987d5 100644 --- a/chrome/browser/sessions/tab_loader.h +++ b/chrome/browser/sessions/tab_loader.h
@@ -68,8 +68,14 @@ // otherwise |force_load_timer_| is restarted. void LoadNextTab(); - // Starts a timer to load load the next tab once expired before the current - // tab loading is finished. + // Starts |force_load_timer_| to load the first non-visible tab if the timer + // expires before a visible tab has finished loading. This uses the same + // timer but a different timeout value than StartTimer. + void StartFirstTimer(); + + // Starts |force_load_timer_| to load the next tab if the timer expires + // before the current tab loading is finished. This uses the same timer but a + // different timeout value than StartFirstTimer. void StartTimer(); // Removes the listeners from the specified tab and removes the tab from
diff --git a/chrome/browser/sessions/tab_loader_delegate.cc b/chrome/browser/sessions/tab_loader_delegate.cc index 640495e..251096c 100644 --- a/chrome/browser/sessions/tab_loader_delegate.cc +++ b/chrome/browser/sessions/tab_loader_delegate.cc
@@ -4,6 +4,8 @@ #include "chrome/browser/sessions/tab_loader_delegate.h" +#include "base/strings/string_number_conversions.h" +#include "components/variations/variations_associated_data.h" #include "net/base/network_change_notifier.h" namespace { @@ -22,8 +24,13 @@ ~TabLoaderDelegateImpl() override; // TabLoaderDelegate: + base::TimeDelta GetFirstTabLoadingTimeout() const override { + return first_timeout_; + } + + // TabLoaderDelegate: base::TimeDelta GetTimeoutBeforeLoadingNextTab() const override { - return base::TimeDelta::FromMilliseconds(kInitialDelayTimerMS); + return timeout_; } // net::NetworkChangeNotifier::ConnectionTypeObserver: @@ -34,6 +41,10 @@ // The function to call when the connection type changes. TabLoaderCallback* callback_; + // The timeouts to use in tab loading. + base::TimeDelta first_timeout_; + base::TimeDelta timeout_; + DISALLOW_COPY_AND_ASSIGN(TabLoaderDelegateImpl); }; @@ -47,6 +58,28 @@ // distributes network access, we can remove this. callback->SetTabLoadingEnabled(false); } + + // Initialize the timeouts to use from the session restore field trial. + // Default to the usual value if none is specified. + + static const char kIntelligentSessionRestore[] = "IntelligentSessionRestore"; + std::string timeout = variations::GetVariationParamValue( + kIntelligentSessionRestore, "FirstTabLoadTimeoutMs"); + int timeout_ms = 0; + if (timeout.empty() || !base::StringToInt(timeout, &timeout_ms) || + timeout_ms <= 0) { + timeout_ms = kInitialDelayTimerMS; + } + first_timeout_ = base::TimeDelta::FromMilliseconds(timeout_ms); + + timeout = variations::GetVariationParamValue( + kIntelligentSessionRestore, "TabLoadTimeoutMs"); + timeout_ms = 0; + if (timeout.empty() || !base::StringToInt(timeout, &timeout_ms) || + timeout_ms <= 0) { + timeout_ms = kInitialDelayTimerMS; + } + timeout_ = base::TimeDelta::FromMilliseconds(timeout_ms); } TabLoaderDelegateImpl::~TabLoaderDelegateImpl() {
diff --git a/chrome/browser/sessions/tab_loader_delegate.h b/chrome/browser/sessions/tab_loader_delegate.h index f545354..e396ac5 100644 --- a/chrome/browser/sessions/tab_loader_delegate.h +++ b/chrome/browser/sessions/tab_loader_delegate.h
@@ -27,8 +27,12 @@ // The callback object is valid as long as this object exists. static scoped_ptr<TabLoaderDelegate> Create(TabLoaderCallback* callback); + // Returns the default timeout time after which the first non-visible tab + // gets loaded if the first (visible) tab did not finish loading. + virtual base::TimeDelta GetFirstTabLoadingTimeout() const = 0; + // Returns the default timeout time after which the next tab gets loaded if - // the previous tab did not finish to load. + // the previous tab did not finish loading. virtual base::TimeDelta GetTimeoutBeforeLoadingNextTab() const = 0; };
diff --git a/chrome/browser/signin/chrome_signin_client.cc b/chrome/browser/signin/chrome_signin_client.cc index a98dd89..cc4aed9 100644 --- a/chrome/browser/signin/chrome_signin_client.cc +++ b/chrome/browser/signin/chrome_signin_client.cc
@@ -33,6 +33,7 @@ #if defined(OS_CHROMEOS) #include "chrome/browser/chromeos/net/delay_network_call.h" +#include "chrome/browser/chromeos/profiles/profile_helper.h" #include "components/user_manager/user_manager.h" #endif @@ -40,6 +41,10 @@ #include "chrome/browser/first_run/first_run.h" #endif +namespace { +const char kEphemeralUserDeviceIDPrefix[] = "t_"; +} + ChromeSigninClient::ChromeSigninClient( Profile* profile, SigninErrorController* signin_error_controller) : profile_(profile), @@ -47,6 +52,33 @@ signin_error_controller_->AddObserver(this); #if !defined(OS_CHROMEOS) net::NetworkChangeNotifier::AddNetworkChangeObserver(this); +#else + // UserManager may not exist in unit_tests. + if (!user_manager::UserManager::IsInitialized()) + return; + + const user_manager::User* user = + chromeos::ProfileHelper::Get()->GetUserByProfile(profile_); + if (!user) + return; + auto* user_manager = user_manager::UserManager::Get(); + const std::string& user_id = user->GetUserID(); + if (user_manager->GetKnownUserDeviceId(user_id).empty()) { + const std::string legacy_device_id = + GetPrefs()->GetString(prefs::kGoogleServicesSigninScopedDeviceId); + if (!legacy_device_id.empty()) { + // Need to move device ID from the old location to the new one, if it has + // not been done yet. + user_manager->SetKnownUserDeviceId(user_id, legacy_device_id); + } else { + user_manager->SetKnownUserDeviceId( + user_id, + GenerateSigninScopedDeviceID( + user_manager->IsUserNonCryptohomeDataEphemeral(user_id))); + } + } + GetPrefs()->SetString(prefs::kGoogleServicesSigninScopedDeviceId, + std::string()); #endif } @@ -77,6 +109,13 @@ cookie_settings->IsSettingCookieAllowed(google_url, google_url); } +// static +std::string ChromeSigninClient::GenerateSigninScopedDeviceID( + bool for_ephemeral) { + std::string guid = base::GenerateGUID(); + return for_ephemeral ? kEphemeralUserDeviceIDPrefix + guid : guid; +} + PrefService* ChromeSigninClient::GetPrefs() { return profile_->GetPrefs(); } scoped_refptr<TokenWebData> ChromeSigninClient::GetDatabase() { @@ -113,16 +152,33 @@ return std::string(); } +#if !defined(OS_CHROMEOS) std::string signin_scoped_device_id = GetPrefs()->GetString(prefs::kGoogleServicesSigninScopedDeviceId); if (signin_scoped_device_id.empty()) { // If device_id doesn't exist then generate new and save in prefs. - signin_scoped_device_id = base::GenerateGUID(); + signin_scoped_device_id = GenerateSigninScopedDeviceID(false); DCHECK(!signin_scoped_device_id.empty()); GetPrefs()->SetString(prefs::kGoogleServicesSigninScopedDeviceId, signin_scoped_device_id); } return signin_scoped_device_id; +#else + // UserManager may not exist in unit_tests. + if (!user_manager::UserManager::IsInitialized()) + return std::string(); + + const user_manager::User* user = + chromeos::ProfileHelper::Get()->GetUserByProfile(profile_); + if (!user) + return std::string(); + + const std::string signin_scoped_device_id = + user_manager::UserManager::Get()->GetKnownUserDeviceId(user->GetUserID()); + LOG_IF(ERROR, signin_scoped_device_id.empty()) + << "Device ID is not set for user."; + return signin_scoped_device_id; +#endif } void ChromeSigninClient::OnSignedOut() {
diff --git a/chrome/browser/signin/chrome_signin_client.h b/chrome/browser/signin/chrome_signin_client.h index 016bf5b..34003178 100644 --- a/chrome/browser/signin/chrome_signin_client.h +++ b/chrome/browser/signin/chrome_signin_client.h
@@ -33,6 +33,10 @@ static bool ProfileAllowsSigninCookies(Profile* profile); static bool SettingsAllowSigninCookies(CookieSettings* cookie_settings); + // If |for_ephemeral| is true, special kind of device ID for ephemeral users + // is generated. + static std::string GenerateSigninScopedDeviceID(bool for_ephemeral); + // SigninClient implementation. PrefService* GetPrefs() override; scoped_refptr<TokenWebData> GetDatabase() override;
diff --git a/chrome/browser/signin/fake_account_tracker_service.cc b/chrome/browser/signin/fake_account_tracker_service.cc index c592b1a..173acd10 100644 --- a/chrome/browser/signin/fake_account_tracker_service.cc +++ b/chrome/browser/signin/fake_account_tracker_service.cc
@@ -39,7 +39,8 @@ user_info.SetString("id", gaia); user_info.SetString("email", email); user_info.SetString("hd", hosted_domain); - SetAccountStateFromUserInfo(account_id, &user_info); + std::vector<std::string> service_flags; + SetAccountStateFromUserInfo(account_id, &user_info, &service_flags); } void FakeAccountTrackerService::SendRefreshTokenAnnotationRequest(
diff --git a/chrome/browser/speech/chrome_speech_recognition_manager_delegate.cc b/chrome/browser/speech/chrome_speech_recognition_manager_delegate.cc index 47a8707..dc894638 100644 --- a/chrome/browser/speech/chrome_speech_recognition_manager_delegate.cc +++ b/chrome/browser/speech/chrome_speech_recognition_manager_delegate.cc
@@ -18,9 +18,6 @@ #include "chrome/common/pref_names.h" #include "chrome/common/url_constants.h" #include "content/public/browser/browser_thread.h" -#include "content/public/browser/notification_registrar.h" -#include "content/public/browser/notification_source.h" -#include "content/public/browser/notification_types.h" #include "content/public/browser/render_process_host.h" #include "content/public/browser/render_view_host.h" #include "content/public/browser/resource_context.h" @@ -28,6 +25,7 @@ #include "content/public/browser/speech_recognition_session_config.h" #include "content/public/browser/speech_recognition_session_context.h" #include "content/public/browser/web_contents.h" +#include "content/public/browser/web_contents_observer.h" #include "content/public/common/speech_recognition_error.h" #include "content/public/common/speech_recognition_result.h" #include "net/url_request/url_request_context_getter.h" @@ -137,8 +135,7 @@ // There is no restriction on the constructor, however this class must be // destroyed on the UI thread, due to the NotificationRegistrar dependency. class ChromeSpeechRecognitionManagerDelegate::TabWatcher - : public base::RefCountedThreadSafe<TabWatcher>, - public content::NotificationObserver { + : public base::RefCountedThreadSafe<TabWatcher> { public: typedef base::Callback<void(int render_process_id, int render_view_id)> TabClosedCallback; @@ -168,96 +165,91 @@ if (!web_contents) return; - // Avoid multiple registrations on |registrar_| for the same |web_contents|. + // Avoid multiple registrations for the same |web_contents|. if (FindWebContents(web_contents) != registered_web_contents_.end()) { return; } - registered_web_contents_.push_back( - WebContentsInfo(web_contents, render_process_id, render_view_id)); - - // Lazy initialize the registrar. - if (!registrar_.get()) - registrar_.reset(new content::NotificationRegistrar()); - - registrar_->Add(this, - content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED, - content::Source<WebContents>(web_contents)); - registrar_->Add(this, - content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED, - content::Source<WebContents>(web_contents)); + registered_web_contents_.push_back(new WebContentsTracker( + web_contents, base::Bind(&TabWatcher::OnTabClosed, + // |this| outlives WebContentsTracker. + base::Unretained(this), web_contents), + render_process_id, render_view_id)); } - // content::NotificationObserver implementation. - void Observe(int type, - const content::NotificationSource& source, - const content::NotificationDetails& details) override { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - DCHECK(type == content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED || - type == content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED); - - WebContents* web_contents = content::Source<WebContents>(source).ptr(); - std::vector<WebContentsInfo>::iterator iter = FindWebContents(web_contents); + void OnTabClosed(content::WebContents* web_contents) { + ScopedVector<WebContentsTracker>::iterator iter = + FindWebContents(web_contents); DCHECK(iter != registered_web_contents_.end()); - int render_process_id = iter->render_process_id; - int render_view_id = iter->render_view_id; + int render_process_id = (*iter)->render_process_id(); + int render_view_id = (*iter)->render_view_id(); registered_web_contents_.erase(iter); - registrar_->Remove(this, - content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED, - content::Source<WebContents>(web_contents)); - registrar_->Remove(this, - content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED, - content::Source<WebContents>(web_contents)); - tab_closed_callback_.Run(render_process_id, render_view_id); } private: - struct WebContentsInfo { - WebContentsInfo(content::WebContents* web_contents, - int render_process_id, - int render_view_id) - : web_contents(web_contents), - render_process_id(render_process_id), - render_view_id(render_view_id) {} + class WebContentsTracker : public content::WebContentsObserver { + public: + WebContentsTracker(content::WebContents* web_contents, + const base::Closure& finished_callback, + int render_process_id, + int render_view_id) + : content::WebContentsObserver(web_contents), + finished_callback_(finished_callback), + render_process_id_(render_process_id), + render_view_id_(render_view_id) {} - ~WebContentsInfo() {} + ~WebContentsTracker() override {} - content::WebContents* web_contents; - int render_process_id; - int render_view_id; + int render_process_id() const { return render_process_id_; } + int render_view_id() const { return render_view_id_; } + + private: + // content::WebContentsObserver overrides. + void WebContentsDestroyed() override { + Observe(nullptr); + finished_callback_.Run(); + // NOTE: We are deleted now. + } + void RenderViewHostChanged(content::RenderViewHost* old_host, + content::RenderViewHost* new_host) override { + Observe(nullptr); + finished_callback_.Run(); + // NOTE: We are deleted now. + } + + const base::Closure finished_callback_; + const int render_process_id_; + const int render_view_id_; }; friend class base::RefCountedThreadSafe<TabWatcher>; - ~TabWatcher() override { + ~TabWatcher() { // Must be destroyed on the UI thread due to |registrar_| non thread-safety. + // TODO(lazyboy): Do we still need this? DCHECK_CURRENTLY_ON(BrowserThread::UI); } // Helper function to find the iterator in |registered_web_contents_| which // contains |web_contents|. - std::vector<WebContentsInfo>::iterator FindWebContents( + ScopedVector<WebContentsTracker>::iterator FindWebContents( content::WebContents* web_contents) { - for (std::vector<WebContentsInfo>::iterator i( - registered_web_contents_.begin()); + for (ScopedVector<WebContentsTracker>::iterator i( + registered_web_contents_.begin()); i != registered_web_contents_.end(); ++i) { - if (i->web_contents == web_contents) + if ((*i)->web_contents() == web_contents) return i; } return registered_web_contents_.end(); } - // Lazy-initialized and used on the UI thread to handle web contents - // notifications (tab closing). - scoped_ptr<content::NotificationRegistrar> registrar_; - // Keeps track of which WebContent(s) have been registered, in order to avoid - // double registrations on |registrar_| and to pass the correct render + // double registrations on WebContentsObserver and to pass the correct render // process id and render view id to |tab_closed_callback_| after the process // has gone away. - std::vector<WebContentsInfo> registered_web_contents_; + ScopedVector<WebContentsTracker> registered_web_contents_; // Callback used to notify, on the thread specified by |callback_thread_| the // closure of a registered tab.
diff --git a/chrome/browser/speech/extension_api/tts_engine_extension_api.cc b/chrome/browser/speech/extension_api/tts_engine_extension_api.cc index bc050e17..7e4071f 100644 --- a/chrome/browser/speech/extension_api/tts_engine_extension_api.cc +++ b/chrome/browser/speech/extension_api/tts_engine_extension_api.cc
@@ -191,7 +191,7 @@ args->AppendInteger(utterance->id()); std::string json; - base::JSONWriter::Write(args.get(), &json); + base::JSONWriter::Write(*args, &json); scoped_ptr<extensions::Event> event(new extensions::Event( tts_engine_events::kOnSpeak, args.Pass()));
diff --git a/chrome/browser/spellchecker/feedback_sender.cc b/chrome/browser/spellchecker/feedback_sender.cc index 5ed97bb..bce2b810 100644 --- a/chrome/browser/spellchecker/feedback_sender.cc +++ b/chrome/browser/spellchecker/feedback_sender.cc
@@ -403,7 +403,7 @@ country_), api_version_)); std::string feedback; - base::JSONWriter::Write(feedback_value.get(), &feedback); + base::JSONWriter::Write(*feedback_value, &feedback); // The tests use this identifier to mock the URL fetcher. static const int kUrlFetcherId = 0;
diff --git a/chrome/browser/supervised_user/child_accounts/family_info_fetcher_unittest.cc b/chrome/browser/supervised_user/child_accounts/family_info_fetcher_unittest.cc index 47f7af4..b855b7d5 100644 --- a/chrome/browser/supervised_user/child_accounts/family_info_fetcher_unittest.cc +++ b/chrome/browser/supervised_user/child_accounts/family_info_fetcher_unittest.cc
@@ -49,7 +49,7 @@ family_dict->SetWithoutPathExpansion("profile", profile_dict); dict.SetWithoutPathExpansion("family", family_dict); std::string result; - base::JSONWriter::Write(&dict, &result); + base::JSONWriter::Write(dict, &result); return result; } @@ -58,7 +58,7 @@ base::DictionaryValue* family_dict = new base::DictionaryValue; dict.SetWithoutPathExpansion("family", family_dict); std::string result; - base::JSONWriter::Write(&dict, &result); + base::JSONWriter::Write(dict, &result); return result; } @@ -97,7 +97,7 @@ } dict.SetWithoutPathExpansion("members", list); std::string result; - base::JSONWriter::Write(&dict, &result); + base::JSONWriter::Write(dict, &result); return result; }
diff --git a/chrome/browser/supervised_user/child_accounts/permission_request_creator_apiary.cc b/chrome/browser/supervised_user/child_accounts/permission_request_creator_apiary.cc index 0f868f453..e14bbff6 100644 --- a/chrome/browser/supervised_user/child_accounts/permission_request_creator_apiary.cc +++ b/chrome/browser/supervised_user/child_accounts/permission_request_creator_apiary.cc
@@ -190,7 +190,7 @@ dict.SetStringWithoutPathExpansion(kStateKey, kState); std::string body; - base::JSONWriter::Write(&dict, &body); + base::JSONWriter::Write(dict, &body); (*it)->url_fetcher->SetUploadData("application/json", body); (*it)->url_fetcher->Start();
diff --git a/chrome/browser/supervised_user/child_accounts/permission_request_creator_apiary_unittest.cc b/chrome/browser/supervised_user/child_accounts/permission_request_creator_apiary_unittest.cc index f78e9afa..b0926117 100644 --- a/chrome/browser/supervised_user/child_accounts/permission_request_creator_apiary_unittest.cc +++ b/chrome/browser/supervised_user/child_accounts/permission_request_creator_apiary_unittest.cc
@@ -24,7 +24,7 @@ permission_dict->SetStringWithoutPathExpansion("id", "requestid"); dict.SetWithoutPathExpansion("permissionRequest", permission_dict); std::string result; - base::JSONWriter::Write(&dict, &result); + base::JSONWriter::Write(dict, &result); return result; }
diff --git a/chrome/browser/supervised_user/experimental/supervised_user_async_url_checker_unittest.cc b/chrome/browser/supervised_user/experimental/supervised_user_async_url_checker_unittest.cc index 0099af6..bc3dfd1 100644 --- a/chrome/browser/supervised_user/experimental/supervised_user_async_url_checker_unittest.cc +++ b/chrome/browser/supervised_user/experimental/supervised_user_async_url_checker_unittest.cc
@@ -53,7 +53,7 @@ dict.SetWithoutPathExpansion("items", results_list); } std::string result; - base::JSONWriter::Write(&dict, &result); + base::JSONWriter::Write(dict, &result); return result; }
diff --git a/chrome/browser/supervised_user/legacy/supervised_user_shared_settings_service.cc b/chrome/browser/supervised_user/legacy/supervised_user_shared_settings_service.cc index 94480d8..17fc6758 100644 --- a/chrome/browser/supervised_user/legacy/supervised_user_shared_settings_service.cc +++ b/chrome/browser/supervised_user/legacy/supervised_user_shared_settings_service.cc
@@ -174,7 +174,7 @@ const Value& value, bool acknowledged) { std::string json_value; - base::JSONWriter::Write(&value, &json_value); + base::JSONWriter::Write(value, &json_value); ::sync_pb::EntitySpecifics specifics; specifics.mutable_managed_user_shared_setting()->set_mu_id(su_id); specifics.mutable_managed_user_shared_setting()->set_key(key);
diff --git a/chrome/browser/supervised_user/legacy/supervised_user_shared_settings_service_unittest.cc b/chrome/browser/supervised_user/legacy/supervised_user_shared_settings_service_unittest.cc index eed022ae..ffa3940 100644 --- a/chrome/browser/supervised_user/legacy/supervised_user_shared_settings_service_unittest.cc +++ b/chrome/browser/supervised_user/legacy/supervised_user_shared_settings_service_unittest.cc
@@ -69,7 +69,7 @@ return std::string(); std::string json_value; - base::JSONWriter::Write(value, &json_value); + base::JSONWriter::Write(*value, &json_value); return json_value; }
diff --git a/chrome/browser/supervised_user/supervised_user_settings_service.cc b/chrome/browser/supervised_user/supervised_user_settings_service.cc index 421a2b4..41b4aa2d 100644 --- a/chrome/browser/supervised_user/supervised_user_settings_service.cc +++ b/chrome/browser/supervised_user/supervised_user_settings_service.cc
@@ -163,7 +163,7 @@ const std::string& name, const base::Value& value) { std::string json_value; - base::JSONWriter::Write(&value, &json_value); + base::JSONWriter::Write(value, &json_value); ::sync_pb::EntitySpecifics specifics; specifics.mutable_managed_user_setting()->set_name(name); specifics.mutable_managed_user_setting()->set_value(json_value);
diff --git a/chrome/browser/sync/profile_sync_service.cc b/chrome/browser/sync/profile_sync_service.cc index 2ac3dee..5f0bffdf 100644 --- a/chrome/browser/sync/profile_sync_service.cc +++ b/chrome/browser/sync/profile_sync_service.cc
@@ -365,6 +365,8 @@ DCHECK(!running_rollback); #endif + memory_pressure_listener_.reset(new base::MemoryPressureListener(base::Bind( + &ProfileSyncService::OnMemoryPressure, weak_factory_.GetWeakPtr()))); startup_controller_->Reset(GetRegisteredDataTypes()); startup_controller_->TryStart(); } @@ -702,6 +704,8 @@ InitializeBackend(ShouldDeleteSyncFolder()); UpdateFirstSyncTimePref(); + + ReportPreviousSessionMemoryWarningCount(); } void ProfileSyncService::OnGetTokenSuccess( @@ -912,6 +916,9 @@ UpdateAuthErrorState(GoogleServiceAuthError::AuthErrorNone()); NotifyObservers(); + + // Mark this as a clean shutdown(without crash). + sync_prefs_.SetCleanShutdown(true); } void ProfileSyncService::DisableForUser() { @@ -2720,3 +2727,31 @@ access_token_, cache_guid, birthday); } } + +void ProfileSyncService::OnMemoryPressure( + base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level) { + if (memory_pressure_level == + base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL) { + sync_prefs_.SetMemoryPressureWarningCount( + sync_prefs_.GetMemoryPressureWarningCount() + 1); + } +} + +void ProfileSyncService::ReportPreviousSessionMemoryWarningCount() { + int warning_received = sync_prefs_.GetMemoryPressureWarningCount(); + + if (-1 != warning_received) { + // -1 means it is new client. + if (!sync_prefs_.DidSyncShutdownCleanly()) { + UMA_HISTOGRAM_COUNTS("Sync.MemoryPressureWarningBeforeUncleanShutdown", + warning_received); + } else { + UMA_HISTOGRAM_COUNTS("Sync.MemoryPressureWarningBeforeCleanShutdown", + warning_received); + } + } + sync_prefs_.SetMemoryPressureWarningCount(0); + // Will set to true during a clean shutdown, so crash or something else will + // remain this as false. + sync_prefs_.SetCleanShutdown(false); +}
diff --git a/chrome/browser/sync/profile_sync_service.h b/chrome/browser/sync/profile_sync_service.h index 1ad2cb7..ff2e2b01 100644 --- a/chrome/browser/sync/profile_sync_service.h +++ b/chrome/browser/sync/profile_sync_service.h
@@ -14,6 +14,7 @@ #include "base/files/file_path.h" #include "base/gtest_prod_util.h" #include "base/location.h" +#include "base/memory/memory_pressure_listener.h" #include "base/memory/scoped_ptr.h" #include "base/memory/scoped_vector.h" #include "base/memory/weak_ptr.h" @@ -891,6 +892,13 @@ // Tell the sync server that this client has disabled sync. void RemoveClientFromServer() const; + // Called when the system is under memory pressure. + void OnMemoryPressure( + base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level); + + // Check if previous shutdown is shutdown cleanly. + void ReportPreviousSessionMemoryWarningCount(); + // Factory used to create various dependent objects. scoped_ptr<ProfileSyncComponentsFactory> factory_; @@ -1070,6 +1078,9 @@ scoped_ptr<browser_sync::SyncStoppedReporter> sync_stopped_reporter_; + // Listens for the system being under memory pressure. + scoped_ptr<base::MemoryPressureListener> memory_pressure_listener_; + base::WeakPtrFactory<ProfileSyncService> weak_factory_; // We don't use |weak_factory_| for the StartupController because the weak
diff --git a/chrome/browser/sync/profile_sync_service_android.cc b/chrome/browser/sync/profile_sync_service_android.cc index 59d44f7..d8e536e 100644 --- a/chrome/browser/sync/profile_sync_service_android.cc +++ b/chrome/browser/sync/profile_sync_service_android.cc
@@ -441,7 +441,7 @@ scoped_ptr<base::DictionaryValue> about_info = sync_ui_util::ConstructAboutInformation(sync_service_); std::string about_info_json; - base::JSONWriter::Write(about_info.get(), &about_info_json); + base::JSONWriter::Write(*about_info, &about_info_json); return ConvertUTF8ToJavaString(env, about_info_json); }
diff --git a/chrome/browser/sync/profile_sync_service_unittest.cc b/chrome/browser/sync/profile_sync_service_unittest.cc index cba1633..f4cb23a 100644 --- a/chrome/browser/sync/profile_sync_service_unittest.cc +++ b/chrome/browser/sync/profile_sync_service_unittest.cc
@@ -659,5 +659,50 @@ EXPECT_TRUE(ProfileSyncService::IsSyncEnabled()); } +// Test Sync will stop after receive memory pressure +TEST_F(ProfileSyncServiceTest, MemoryPressureRecording) { + CreateService(browser_sync::AUTO_START); + IssueTestTokens(); + ExpectDataTypeManagerCreation(1); + ExpectSyncBackendHostCreation(1); + InitializeForNthSync(); + + EXPECT_TRUE(service()->SyncActive()); + EXPECT_FALSE(profile()->GetPrefs()->GetBoolean( + sync_driver::prefs::kSyncSuppressStart)); + + testing::Mock::VerifyAndClearExpectations(components_factory()); + + sync_driver::SyncPrefs sync_prefs(service()->profile()->GetPrefs()); + + EXPECT_EQ(profile()->GetPrefs()->GetInteger( + sync_driver::prefs::kSyncMemoryPressureWarningCount), + 0); + EXPECT_FALSE(sync_prefs.DidSyncShutdownCleanly()); + + // Simulate memory pressure notification. + base::MemoryPressureListener::NotifyMemoryPressure( + base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL); + base::RunLoop().RunUntilIdle(); + + // Verify memory pressure recorded. + EXPECT_EQ(profile()->GetPrefs()->GetInteger( + sync_driver::prefs::kSyncMemoryPressureWarningCount), + 1); + EXPECT_FALSE(sync_prefs.DidSyncShutdownCleanly()); + + // Simulate memory pressure notification. + base::MemoryPressureListener::NotifyMemoryPressure( + base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL); + base::RunLoop().RunUntilIdle(); + ShutdownAndDeleteService(); + + // Verify memory pressure and shutdown recorded. + EXPECT_EQ(profile()->GetPrefs()->GetInteger( + sync_driver::prefs::kSyncMemoryPressureWarningCount), + 2); + EXPECT_TRUE(sync_prefs.DidSyncShutdownCleanly()); +} + } // namespace } // namespace browser_sync
diff --git a/chrome/browser/sync/test/integration/extension_settings_helper.cc b/chrome/browser/sync/test/integration/extension_settings_helper.cc index 73a88533..e9414af1 100644 --- a/chrome/browser/sync/test/integration/extension_settings_helper.cc +++ b/chrome/browser/sync/test/integration/extension_settings_helper.cc
@@ -31,9 +31,8 @@ std::string ToJson(const base::Value& value) { std::string json; - base::JSONWriter::WriteWithOptions(&value, - base::JSONWriter::OPTIONS_PRETTY_PRINT, - &json); + base::JSONWriter::WriteWithOptions( + value, base::JSONWriter::OPTIONS_PRETTY_PRINT, &json); return json; }
diff --git a/chrome/browser/sync/test/integration/profile_sync_service_harness.cc b/chrome/browser/sync/test/integration/profile_sync_service_harness.cc index bb71e353..fca7be5 100644 --- a/chrome/browser/sync/test/integration/profile_sync_service_harness.cc +++ b/chrome/browser/sync/test/integration/profile_sync_service_harness.cc
@@ -469,8 +469,7 @@ scoped_ptr<base::DictionaryValue> value( sync_ui_util::ConstructAboutInformation(service())); std::string service_status; - base::JSONWriter::WriteWithOptions(value.get(), - base::JSONWriter::OPTIONS_PRETTY_PRINT, - &service_status); + base::JSONWriter::WriteWithOptions( + *value, base::JSONWriter::OPTIONS_PRETTY_PRINT, &service_status); return service_status; }
diff --git a/chrome/browser/task_profiler/task_profiler_data_serializer_unittest.cc b/chrome/browser/task_profiler/task_profiler_data_serializer_unittest.cc index da040b7..5567eec6 100644 --- a/chrome/browser/task_profiler/task_profiler_data_serializer_unittest.cc +++ b/chrome/browser/task_profiler/task_profiler_data_serializer_unittest.cc
@@ -26,7 +26,7 @@ process_data_phase, process_id, process_type, &serialized_value); std::string serialized_json; - base::JSONWriter::Write(&serialized_value, &serialized_json); + base::JSONWriter::Write(serialized_value, &serialized_json); EXPECT_EQ(expected_json, serialized_json); }
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn index ea7487c9..3a16f27 100644 --- a/chrome/browser/ui/BUILD.gn +++ b/chrome/browser/ui/BUILD.gn
@@ -427,8 +427,7 @@ sources += rebase_path(gypi_values.chrome_browser_ui_media_router_sources, ".", "//chrome") - deps += [ "//chrome/browser/media/router:router_core" ] - defines += [ "ENABLE_MEDIA_ROUTER=1" ] + deps += [ "//chrome/browser/media/router" ] } if (enable_webrtc) { sources += rebase_path(gypi_values.chrome_browser_ui_webrtc_sources,
diff --git a/chrome/browser/ui/android/context_menu_helper.cc b/chrome/browser/ui/android/context_menu_helper.cc index d41f0c8a..37519e1e 100644 --- a/chrome/browser/ui/android/context_menu_helper.cc +++ b/chrome/browser/ui/android/context_menu_helper.cc
@@ -6,6 +6,7 @@ #include "base/android/jni_android.h" #include "base/android/jni_string.h" +#include "components/data_reduction_proxy/core/common/data_reduction_proxy_headers.h" #include "content/public/browser/android/content_view_core.h" #include "content/public/browser/android/download_controller_android.h" #include "content/public/common/context_menu_params.h" @@ -75,6 +76,12 @@ GURL sanitizedReferrer = (params.frame_url.is_empty() ? params.page_url : params.frame_url).GetAsReferrer(); + std::map<std::string, std::string>::const_iterator it = + params.properties.find(data_reduction_proxy::chrome_proxy_header()); + bool image_was_fetched_lo_fi = + it != params.properties.end() && + it->second == data_reduction_proxy::chrome_proxy_lo_fi_directive(); + JNIEnv* env = base::android::AttachCurrentThread(); base::android::ScopedJavaLocalRef<jobject> jmenu_info = ContextMenuParamsAndroid::Java_ContextMenuParams_create( @@ -86,6 +93,8 @@ ConvertUTF8ToJavaString(env, params.unfiltered_link_url.spec()).obj(), ConvertUTF8ToJavaString(env, params.src_url.spec()).obj(), ConvertUTF16ToJavaString(env, params.selection_text).obj(), + ConvertUTF16ToJavaString(env, params.title_text).obj(), + image_was_fetched_lo_fi, params.is_editable, ConvertUTF8ToJavaString(env, sanitizedReferrer.spec()).obj(), params.referrer_policy);
diff --git a/chrome/browser/ui/app_list/app_list_service.h b/chrome/browser/ui/app_list/app_list_service.h index b8dafd3..99fbd65 100644 --- a/chrome/browser/ui/app_list/app_list_service.h +++ b/chrome/browser/ui/app_list/app_list_service.h
@@ -100,6 +100,10 @@ // Shows the app list, and switches to the custom launcher page. virtual void ShowForCustomLauncherPage(Profile* profile) = 0; + // Hides the custom launcher page if it is currently being shown. Does nothing + // otherwise. + virtual void HideCustomLauncherPage() = 0; + // Dismiss the app list. virtual void DismissAppList() = 0;
diff --git a/chrome/browser/ui/app_list/app_list_service_disabled.cc b/chrome/browser/ui/app_list/app_list_service_disabled.cc index 31a0cbc1..25293ae 100644 --- a/chrome/browser/ui/app_list/app_list_service_disabled.cc +++ b/chrome/browser/ui/app_list/app_list_service_disabled.cc
@@ -35,6 +35,7 @@ Profile* profile, const scoped_refptr<content::SpeechRecognitionSessionPreamble>& preamble) override {} + void HideCustomLauncherPage() override {} void ShowForAppInstall(Profile* profile, const std::string& extension_id, bool start_discovery_tracking) override {}
diff --git a/chrome/browser/ui/app_list/app_list_service_mac.h b/chrome/browser/ui/app_list/app_list_service_mac.h index c97e2d3..f8211ca3 100644 --- a/chrome/browser/ui/app_list/app_list_service_mac.h +++ b/chrome/browser/ui/app_list/app_list_service_mac.h
@@ -51,6 +51,7 @@ void Init(Profile* initial_profile) override; void DismissAppList() override; void ShowForCustomLauncherPage(Profile* profile) override; + void HideCustomLauncherPage() override; bool IsAppListVisible() const override; void EnableAppList(Profile* initial_profile, AppListEnableSource enable_source) override;
diff --git a/chrome/browser/ui/app_list/app_list_service_mac.mm b/chrome/browser/ui/app_list/app_list_service_mac.mm index f337879..35cdec9 100644 --- a/chrome/browser/ui/app_list/app_list_service_mac.mm +++ b/chrome/browser/ui/app_list/app_list_service_mac.mm
@@ -425,6 +425,10 @@ NOTIMPLEMENTED(); } +void AppListServiceMac::HideCustomLauncherPage() { + NOTIMPLEMENTED(); +} + bool AppListServiceMac::IsAppListVisible() const { return [GetNativeWindow() isVisible] && ![animation_controller_ isClosing];
diff --git a/chrome/browser/ui/app_list/app_list_service_unittest.cc b/chrome/browser/ui/app_list/app_list_service_unittest.cc index 812d638..c7d3107 100644 --- a/chrome/browser/ui/app_list/app_list_service_unittest.cc +++ b/chrome/browser/ui/app_list/app_list_service_unittest.cc
@@ -56,6 +56,7 @@ } void ShowForCustomLauncherPage(Profile* profile) override {} + void HideCustomLauncherPage() override {} void DismissAppList() override { showing_for_profile_ = NULL; }
diff --git a/chrome/browser/ui/app_list/app_list_service_views.cc b/chrome/browser/ui/app_list/app_list_service_views.cc index 7f1cd4a..6f1a4b8 100644 --- a/chrome/browser/ui/app_list/app_list_service_views.cc +++ b/chrome/browser/ui/app_list/app_list_service_views.cc
@@ -49,6 +49,19 @@ app_list::AppListModel::STATE_CUSTOM_LAUNCHER_PAGE); } +void AppListServiceViews::HideCustomLauncherPage() { + if (!shower_.IsAppListVisible()) + return; + + app_list::ContentsView* contents_view = + shower_.app_list()->app_list_main_view()->contents_view(); + + if (contents_view->IsStateActive( + app_list::AppListModel::STATE_CUSTOM_LAUNCHER_PAGE)) { + contents_view->SetActiveState(app_list::AppListModel::STATE_START, true); + } +} + void AppListServiceViews::DismissAppList() { if (!can_dismiss_) return;
diff --git a/chrome/browser/ui/app_list/app_list_service_views.h b/chrome/browser/ui/app_list/app_list_service_views.h index 60cd10a..7ba7417 100644 --- a/chrome/browser/ui/app_list/app_list_service_views.h +++ b/chrome/browser/ui/app_list/app_list_service_views.h
@@ -38,6 +38,7 @@ const std::string& extension_id, bool start_discovery_tracking) override; void ShowForCustomLauncherPage(Profile* profile) override; + void HideCustomLauncherPage() override; void DismissAppList() override; bool IsAppListVisible() const override; gfx::NativeWindow GetAppListWindow() override;
diff --git a/chrome/browser/ui/ash/app_list/app_list_controller_ash.cc b/chrome/browser/ui/ash/app_list/app_list_controller_ash.cc index ce65a13..969f776 100644 --- a/chrome/browser/ui/ash/app_list/app_list_controller_ash.cc +++ b/chrome/browser/ui/ash/app_list/app_list_controller_ash.cc
@@ -4,6 +4,7 @@ #include "chrome/browser/ui/ash/app_list/app_list_controller_ash.h" +#include "ash/metrics/task_switch_metrics_recorder.h" #include "ash/shell.h" #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h" #include "chrome/browser/ui/browser_navigator.h" @@ -101,6 +102,11 @@ const extensions::Extension* extension, AppListSource source, int event_flags) { + ash::Shell::GetInstance() + ->metrics() + ->task_switch_metrics_recorder() + .OnTaskSwitch(ash::TaskSwitchMetricsRecorder::kAppList); + // Platform apps treat activations as a launch. The app can decide whether to // show a new window or focus an existing window as it sees fit. if (extension->is_platform_app()) {
diff --git a/chrome/browser/ui/ash/app_list/app_list_service_ash.cc b/chrome/browser/ui/ash/app_list/app_list_service_ash.cc index 2fb7881d..d46fe3e 100644 --- a/chrome/browser/ui/ash/app_list/app_list_service_ash.cc +++ b/chrome/browser/ui/ash/app_list/app_list_service_ash.cc
@@ -91,6 +91,20 @@ ShowAndSwitchToState(app_list::AppListModel::STATE_CUSTOM_LAUNCHER_PAGE); } +void AppListServiceAsh::HideCustomLauncherPage() { + app_list::AppListView* app_list_view = + ash::Shell::GetInstance()->GetAppListView(); + if (!app_list_view) + return; + + app_list::ContentsView* contents_view = + app_list_view->app_list_main_view()->contents_view(); + if (contents_view->IsStateActive( + app_list::AppListModel::STATE_CUSTOM_LAUNCHER_PAGE)) { + contents_view->SetActiveState(app_list::AppListModel::STATE_START, true); + } +} + bool AppListServiceAsh::IsAppListVisible() const { return ash::Shell::GetInstance()->GetAppListTargetVisibility(); }
diff --git a/chrome/browser/ui/ash/app_list/app_list_service_ash.h b/chrome/browser/ui/ash/app_list/app_list_service_ash.h index 6dcc302..62e3ae6 100644 --- a/chrome/browser/ui/ash/app_list/app_list_service_ash.h +++ b/chrome/browser/ui/ash/app_list/app_list_service_ash.h
@@ -44,6 +44,7 @@ const std::string& extension_id, bool start_discovery_tracking) override; void ShowForCustomLauncherPage(Profile* profile) override; + void HideCustomLauncherPage() override; bool IsAppListVisible() const override; void DismissAppList() override; void EnableAppList(Profile* initial_profile,
diff --git a/chrome/browser/ui/ash/ash_keyboard_controller_proxy.cc b/chrome/browser/ui/ash/ash_keyboard_controller_proxy.cc index d999706b..0b79244 100644 --- a/chrome/browser/ui/ash/ash_keyboard_controller_proxy.cc +++ b/chrome/browser/ui/ash/ash_keyboard_controller_proxy.cc
@@ -26,6 +26,7 @@ #include "ui/aura/window_event_dispatcher.h" #include "ui/compositor/scoped_layer_animation_settings.h" #include "ui/keyboard/keyboard_controller.h" +#include "ui/keyboard/keyboard_controller_observer.h" namespace virtual_keyboard_private = extensions::core_api::virtual_keyboard_private; @@ -69,6 +70,43 @@ return virtual_keyboard_private::ON_TEXT_INPUT_BOX_FOCUSED_TYPE_NONE; } +class AshKeyboardControllerObserver + : public keyboard::KeyboardControllerObserver { + public: + explicit AshKeyboardControllerObserver(content::BrowserContext* context) + : context_(context) {} + ~AshKeyboardControllerObserver() override {} + + // KeyboardControllerObserver overrides: + void OnKeyboardBoundsChanging(const gfx::Rect& bounds) override { + extensions::EventRouter* router = extensions::EventRouter::Get(context_); + + if (!router->HasEventListener( + virtual_keyboard_private::OnBoundsChanged::kEventName)) { + return; + } + + scoped_ptr<base::ListValue> event_args(new base::ListValue()); + scoped_ptr<base::DictionaryValue> new_bounds(new base::DictionaryValue()); + new_bounds->SetInteger("left", bounds.x()); + new_bounds->SetInteger("top", bounds.y()); + new_bounds->SetInteger("width", bounds.width()); + new_bounds->SetInteger("height", bounds.height()); + event_args->Append(new_bounds.release()); + + scoped_ptr<extensions::Event> event(new extensions::Event( + virtual_keyboard_private::OnBoundsChanged::kEventName, + event_args.Pass())); + event->restrict_to_browser_context = context_; + router->BroadcastEvent(event.Pass()); + } + + private: + content::BrowserContext* context_; + + DISALLOW_COPY_AND_ASSIGN(AshKeyboardControllerObserver); +}; + } // namespace AshKeyboardControllerProxy::AshKeyboardControllerProxy( @@ -76,7 +114,9 @@ : keyboard::KeyboardControllerProxy(context) { } -AshKeyboardControllerProxy::~AshKeyboardControllerProxy() {} +AshKeyboardControllerProxy::~AshKeyboardControllerProxy() { + DCHECK(!keyboard_controller_); +} void AshKeyboardControllerProxy::OnRequest( const ExtensionHostMsg_Request_Params& params) { @@ -123,6 +163,20 @@ return NULL; } +void AshKeyboardControllerProxy::SetController( + keyboard::KeyboardController* controller) { + // During KeyboardController destruction, controller can be set to null. + if (!controller) { + DCHECK(keyboard_controller_); + keyboard_controller_->RemoveObserver(observer_.get()); + keyboard_controller_ = nullptr; + return; + } + keyboard_controller_ = controller; + observer_.reset(new AshKeyboardControllerObserver(browser_context())); + keyboard_controller_->AddObserver(observer_.get()); +} + content::WebContents* AshKeyboardControllerProxy::GetAssociatedWebContents() const { return web_contents();
diff --git a/chrome/browser/ui/ash/ash_keyboard_controller_proxy.h b/chrome/browser/ui/ash/ash_keyboard_controller_proxy.h index 40b4777..64c042ce8 100644 --- a/chrome/browser/ui/ash/ash_keyboard_controller_proxy.h +++ b/chrome/browser/ui/ash/ash_keyboard_controller_proxy.h
@@ -22,6 +22,10 @@ namespace gfx { class Rect; } +namespace keyboard { +class KeyboardController; +class KeyboardControllerObserver; +} namespace ui { class InputMethod; } @@ -46,6 +50,7 @@ const content::MediaStreamRequest& request, const content::MediaResponseCallback& callback) override; void SetupWebContents(content::WebContents* contents) override; + void SetController(keyboard::KeyboardController* controller) override; void ShowKeyboardContainer(aura::Window* container) override; // The overridden implementation dispatches @@ -65,8 +70,11 @@ bool OnMessageReceived(const IPC::Message& message) override; void RenderViewCreated(content::RenderViewHost* render_view_host) override; + keyboard::KeyboardController* keyboard_controller_; + scoped_ptr<extensions::ExtensionFunctionDispatcher> extension_function_dispatcher_; + scoped_ptr<keyboard::KeyboardControllerObserver> observer_; DISALLOW_COPY_AND_ASSIGN(AshKeyboardControllerProxy); };
diff --git a/chrome/browser/ui/ash/cast_config_delegate_chromeos.cc b/chrome/browser/ui/ash/cast_config_delegate_chromeos.cc new file mode 100644 index 0000000..3f0b87b --- /dev/null +++ b/chrome/browser/ui/ash/cast_config_delegate_chromeos.cc
@@ -0,0 +1,155 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/ash/cast_config_delegate_chromeos.h" + +#include <string> + +#include "base/memory/scoped_ptr.h" +#include "base/strings/utf_string_conversions.h" +#include "chrome/browser/extensions/api/tab_capture/tab_capture_api.h" +#include "chrome/browser/profiles/profile_manager.h" +#include "chrome/browser/ui/browser_navigator.h" +#include "content/public/browser/browser_context.h" +#include "content/public/browser/render_frame_host.h" +#include "content/public/browser/render_view_host.h" +#include "extensions/browser/extension_host.h" +#include "extensions/browser/extension_registry.h" +#include "extensions/browser/process_manager.h" +#include "extensions/common/extension.h" + +namespace chromeos { +namespace { + +using JavaScriptResultCallback = + content::RenderFrameHost::JavaScriptResultCallback; + +// Returns the cast extension if it exists. +const extensions::Extension* FindCastExtension() { + // TODO(jdufault): Figure out how to correctly handle multiprofile mode. + // See crbug.com/488751 + Profile* profile = ProfileManager::GetActiveUserProfile(); + const extensions::ExtensionRegistry* extension_registry = + extensions::ExtensionRegistry::Get(profile); + const extensions::ExtensionSet& enabled_extensions = + extension_registry->enabled_extensions(); + + for (size_t i = 0; i < arraysize(extensions::kChromecastExtensionIds); ++i) { + const std::string extension_id(extensions::kChromecastExtensionIds[i]); + if (enabled_extensions.Contains(extension_id)) { + return extension_registry->GetExtensionById( + extension_id, extensions::ExtensionRegistry::ENABLED); + } + } + return nullptr; +} + +// Utility method that returns the currently active RenderViewHost. +content::RenderViewHost* GetRenderViewHost() { + const extensions::Extension* extension = FindCastExtension(); + if (!extension) + return nullptr; + // TODO(jdufault): Figure out how to correctly handle multiprofile mode. + // See crbug.com/488751 + Profile* profile = ProfileManager::GetActiveUserProfile(); + if (!profile) + return nullptr; + extensions::ProcessManager* pm = extensions::ProcessManager::Get(profile); + return pm->GetBackgroundHostForExtension(extension->id())->render_view_host(); +} + +// Executes JavaScript in the context of the cast extension's background page. +void ExecuteJavaScript(const std::string& javascript) { + auto rvh = GetRenderViewHost(); + if (!rvh) + return; + rvh->GetMainFrame()->ExecuteJavaScript(base::UTF8ToUTF16(javascript)); +} + +// Executes JavaScript in the context of the cast extension's background page. +// Invokes |callback| with the return value of the invoked javascript. +void ExecuteJavaScriptWithCallback(const std::string& javascript, + const JavaScriptResultCallback& callback) { + auto rvh = GetRenderViewHost(); + if (!rvh) + return; + rvh->GetMainFrame()->ExecuteJavaScript(base::UTF8ToUTF16(javascript), + callback); +} + +// Handler for GetReceiversAndActivities. +void GetReceiversAndActivitiesCallback( + const ash::CastConfigDelegate::ReceiversAndActivitesCallback& callback, + const base::Value* value) { + ash::CastConfigDelegate::ReceiversAndActivites receiver_activites; + const base::ListValue* ra_list = nullptr; + if (value->GetAsList(&ra_list)) { + for (auto i = ra_list->begin(); i != ra_list->end(); ++i) { + const base::DictionaryValue* ra_dict = nullptr; + if ((*i)->GetAsDictionary(&ra_dict)) { + const base::DictionaryValue* receiver_dict(nullptr), + *activity_dict(nullptr); + ash::CastConfigDelegate::ReceiverAndActivity receiver_activity; + if (ra_dict->GetDictionary("receiver", &receiver_dict)) { + receiver_dict->GetString("name", &receiver_activity.receiver.name); + receiver_dict->GetString("id", &receiver_activity.receiver.id); + } + if (ra_dict->GetDictionary("activity", &activity_dict) && + !activity_dict->empty()) { + activity_dict->GetString("id", &receiver_activity.activity.id); + activity_dict->GetString("title", &receiver_activity.activity.title); + activity_dict->GetString("activityType", + &receiver_activity.activity.activity_type); + activity_dict->GetBoolean("allowStop", + &receiver_activity.activity.allow_stop); + activity_dict->GetInteger("tabId", + &receiver_activity.activity.tab_id); + } + receiver_activites[receiver_activity.receiver.id] = receiver_activity; + } + } + } + callback.Run(receiver_activites); +} + +} // namespace + +CastConfigDelegateChromeos::CastConfigDelegateChromeos() { +} + +CastConfigDelegateChromeos::~CastConfigDelegateChromeos() { +} + +bool CastConfigDelegateChromeos::HasCastExtension() const { + return FindCastExtension() != nullptr; +} + +void CastConfigDelegateChromeos::GetReceiversAndActivities( + const ReceiversAndActivitesCallback& callback) { + ExecuteJavaScriptWithCallback( + "backgroundSetup.getMirrorCapableReceiversAndActivities();", + base::Bind(&GetReceiversAndActivitiesCallback, callback)); +} + +void CastConfigDelegateChromeos::CastToReceiver( + const std::string& receiver_id) { + ExecuteJavaScript("backgroundSetup.launchDesktopMirroring('" + receiver_id + + "');"); +} + +void CastConfigDelegateChromeos::StopCasting(const std::string& activity_id) { + ExecuteJavaScript("backgroundSetup.stopCastMirroring('user-stop');"); +} + +void CastConfigDelegateChromeos::LaunchCastOptions() { + chrome::NavigateParams params( + ProfileManager::GetActiveUserProfile(), + FindCastExtension()->GetResourceURL("options.html"), + ui::PAGE_TRANSITION_LINK); + params.disposition = NEW_FOREGROUND_TAB; + params.window_action = chrome::NavigateParams::SHOW_WINDOW; + chrome::Navigate(¶ms); +} + +} // namespace chromeos
diff --git a/chrome/browser/ui/ash/cast_config_delegate_chromeos.h b/chrome/browser/ui/ash/cast_config_delegate_chromeos.h new file mode 100644 index 0000000..f0c1b58 --- /dev/null +++ b/chrome/browser/ui/ash/cast_config_delegate_chromeos.h
@@ -0,0 +1,38 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_ASH_CAST_CONFIG_DELEGATE_CHROMEOS_H_ +#define CHROME_BROWSER_UI_ASH_CAST_CONFIG_DELEGATE_CHROMEOS_H_ + +#include <string> + +#include "ash/cast_config_delegate.h" +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "base/values.h" + +namespace chromeos { + +// A class which allows the ash tray to communicate with the cast extension. +class CastConfigDelegateChromeos : public ash::CastConfigDelegate { + public: + CastConfigDelegateChromeos(); + + private: + ~CastConfigDelegateChromeos() override; + + // CastConfigDelegate: + bool HasCastExtension() const override; + void GetReceiversAndActivities( + const ReceiversAndActivitesCallback& callback) override; + void CastToReceiver(const std::string& receiver_id) override; + void StopCasting(const std::string& activity_id) override; + void LaunchCastOptions() override; + + DISALLOW_COPY_AND_ASSIGN(CastConfigDelegateChromeos); +}; + +} // namespace chromeos + +#endif // CHROME_BROWSER_UI_ASH_CAST_CONFIG_DELEGATE_CHROMEOS_H_
diff --git a/chrome/browser/ui/ash/chrome_shell_delegate.h b/chrome/browser/ui/ash/chrome_shell_delegate.h index a467a6e..ae87ac1 100644 --- a/chrome/browser/ui/ash/chrome_shell_delegate.h +++ b/chrome/browser/ui/ash/chrome_shell_delegate.h
@@ -13,6 +13,7 @@ #include "base/compiler_specific.h" #include "base/memory/scoped_ptr.h" #include "base/observer_list.h" +#include "chrome/browser/ui/ash/metrics/chrome_user_metrics_recorder.h" #include "content/public/browser/notification_observer.h" #include "content/public/browser/notification_registrar.h" @@ -93,6 +94,9 @@ ObserverList<ash::VirtualKeyboardStateObserver> keyboard_state_observer_list_; + // Proxies events from chrome/browser to ash::UserMetricsRecorder. + scoped_ptr<ChromeUserMetricsRecorder> chrome_user_metrics_recorder_; + #if defined(OS_CHROMEOS) scoped_ptr<chromeos::DisplayConfigurationObserver> display_configuration_observer_;
diff --git a/chrome/browser/ui/ash/chrome_shell_delegate_chromeos.cc b/chrome/browser/ui/ash/chrome_shell_delegate_chromeos.cc index 1b617147..7eb8da5b 100644 --- a/chrome/browser/ui/ash/chrome_shell_delegate_chromeos.cc +++ b/chrome/browser/ui/ash/chrome_shell_delegate_chromeos.cc
@@ -217,10 +217,13 @@ // in Shell::Init. display_configuration_observer_.reset( new chromeos::DisplayConfigurationObserver()); + + chrome_user_metrics_recorder_.reset(new ChromeUserMetricsRecorder); } void ChromeShellDelegate::PreShutdown() { display_configuration_observer_.reset(); + chrome_user_metrics_recorder_.reset(); } ash::SessionStateDelegate* ChromeShellDelegate::CreateSessionStateDelegate() {
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_browser.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_browser.cc index 26a75a8..be2cbe0 100644 --- a/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_browser.cc +++ b/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_browser.cc
@@ -6,6 +6,7 @@ #include "ash/wm/window_util.h" #include "chrome/browser/chrome_notification_types.h" +#include "chrome/browser/ui/ash/multi_user/multi_user_util.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_finder.h" #include "chrome/browser/ui/browser_window.h" @@ -42,6 +43,10 @@ TabStripModel* tab_strip = browser_->tab_strip_model(); tab_strip->CloseAllTabs(); } else { + // In ChromeOS multiprofile scenario we might need to teleport the window + // back to the current user desktop. + multi_user_util::MoveWindowToCurrentDesktop( + browser_->window()->GetNativeWindow()); browser_->window()->Show(); ash::wm::ActivateWindow(browser_->window()->GetNativeWindow()); }
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_tab.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_tab.cc index b1ce6d6..0c263b8 100644 --- a/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_tab.cc +++ b/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_tab.cc
@@ -5,6 +5,7 @@ #include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_tab.h" #include "ash/wm/window_util.h" +#include "chrome/browser/ui/ash/multi_user/multi_user_util.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_finder.h" #include "chrome/browser/ui/browser_window.h" @@ -43,6 +44,10 @@ if (event_flags & (ui::EF_SHIFT_DOWN | ui::EF_MIDDLE_MOUSE_BUTTON)) { tab_strip->CloseWebContentsAt(index, TabStripModel::CLOSE_USER_GESTURE); } else { + // In ChromeOS multiprofile scenario we might need to teleport the window + // back to the current user desktop. + multi_user_util::MoveWindowToCurrentDesktop( + browser->window()->GetNativeWindow()); tab_strip->ActivateTabAt(index, false); browser->window()->Show(); // Need this check to prevent unit tests from crashing.
diff --git a/chrome/browser/ui/ash/metrics/chrome_user_metrics_recorder.cc b/chrome/browser/ui/ash/metrics/chrome_user_metrics_recorder.cc new file mode 100644 index 0000000..81e9108 --- /dev/null +++ b/chrome/browser/ui/ash/metrics/chrome_user_metrics_recorder.cc
@@ -0,0 +1,47 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/ash/metrics/chrome_user_metrics_recorder.h" + +#include "ash/metrics/task_switch_metrics_recorder.h" +#include "ash/metrics/user_metrics_recorder.h" +#include "ash/shell.h" +#include "base/logging.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/browser_list.h" +#include "chrome/browser/ui/host_desktop.h" +#include "chrome/browser/ui/tabs/tab_strip_model.h" + +ChromeUserMetricsRecorder::ChromeUserMetricsRecorder() { + BrowserList::AddObserver(this); +} + +ChromeUserMetricsRecorder::~ChromeUserMetricsRecorder() { + DCHECK(BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH)->empty()); + BrowserList::RemoveObserver(this); +} + +void ChromeUserMetricsRecorder::OnBrowserAdded(Browser* browser) { + browser->tab_strip_model()->AddObserver(this); +} + +void ChromeUserMetricsRecorder::OnBrowserRemoved(Browser* browser) { + browser->tab_strip_model()->RemoveObserver(this); +} + +void ChromeUserMetricsRecorder::ActiveTabChanged( + content::WebContents* old_contents, + content::WebContents* new_contents, + int index, + int reason) { + if (reason & CHANGE_REASON_USER_GESTURE) + OnTabSwitchedByUserGesture(); +} + +void ChromeUserMetricsRecorder::OnTabSwitchedByUserGesture() { + ash::Shell::GetInstance() + ->metrics() + ->task_switch_metrics_recorder() + .OnTaskSwitch(ash::TaskSwitchMetricsRecorder::kTabStrip); +}
diff --git a/chrome/browser/ui/ash/metrics/chrome_user_metrics_recorder.h b/chrome/browser/ui/ash/metrics/chrome_user_metrics_recorder.h new file mode 100644 index 0000000..81236e9 --- /dev/null +++ b/chrome/browser/ui/ash/metrics/chrome_user_metrics_recorder.h
@@ -0,0 +1,40 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_ASH_METRICS_CHROME_USER_METRICS_RECORDER_H_ +#define CHROME_BROWSER_UI_ASH_METRICS_CHROME_USER_METRICS_RECORDER_H_ + +#include "base/macros.h" +#include "chrome/browser/ui/browser_list_observer.h" +#include "chrome/browser/ui/tabs/tab_strip_model_observer.h" + +namespace content { +class WebContents; +} // namespace content + +// A bridge proxy between chrome/browser events and ash::UserMetricsRecorder. +class ChromeUserMetricsRecorder : public chrome::BrowserListObserver, + public TabStripModelObserver { + public: + ChromeUserMetricsRecorder(); + ~ChromeUserMetricsRecorder() override; + + // chrome::BroswerListObserver: + void OnBrowserAdded(Browser* browser) override; + void OnBrowserRemoved(Browser* browser) override; + + // TabStripModelObserver: + void ActiveTabChanged(content::WebContents* old_contents, + content::WebContents* new_contents, + int index, + int reason) override; + + private: + // Called when a different tab becomes active due to a user gesture. + void OnTabSwitchedByUserGesture(); + + DISALLOW_COPY_AND_ASSIGN(ChromeUserMetricsRecorder); +}; + +#endif // CHROME_BROWSER_UI_ASH_METRICS_CHROME_USER_METRICS_RECORDER_H_
diff --git a/chrome/browser/ui/ash/system_tray_delegate_chromeos.cc b/chrome/browser/ui/ash/system_tray_delegate_chromeos.cc index 28c6c48..f4e1284 100644 --- a/chrome/browser/ui/ash/system_tray_delegate_chromeos.cc +++ b/chrome/browser/ui/ash/system_tray_delegate_chromeos.cc
@@ -71,6 +71,7 @@ #include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/supervised_user/supervised_user_service.h" #include "chrome/browser/supervised_user/supervised_user_service_factory.h" +#include "chrome/browser/ui/ash/cast_config_delegate_chromeos.h" #include "chrome/browser/ui/ash/multi_user/multi_user_util.h" #include "chrome/browser/ui/ash/networking_config_delegate_chromeos.h" #include "chrome/browser/ui/ash/system_tray_delegate_utils.h" @@ -195,6 +196,7 @@ have_session_length_limit_(false), should_run_bluetooth_discovery_(false), session_started_(false), + cast_config_delegate_(new CastConfigDelegateChromeos()), networking_config_delegate_(new NetworkingConfigDelegateChromeos()), volume_control_delegate_(new VolumeController()), device_settings_observer_(CrosSettings::Get()->AddSettingsObserver( @@ -788,6 +790,11 @@ LoginDisplayHostImpl::default_host()->OpenProxySettings(); } +ash::CastConfigDelegate* SystemTrayDelegateChromeOS::GetCastConfigDelegate() + const { + return cast_config_delegate_.get(); +} + ash::NetworkingConfigDelegate* SystemTrayDelegateChromeOS::GetNetworkingConfigDelegate() const { return networking_config_delegate_.get();
diff --git a/chrome/browser/ui/ash/system_tray_delegate_chromeos.h b/chrome/browser/ui/ash/system_tray_delegate_chromeos.h index cf9bcee..cbb48829 100644 --- a/chrome/browser/ui/ash/system_tray_delegate_chromeos.h +++ b/chrome/browser/ui/ash/system_tray_delegate_chromeos.h
@@ -125,6 +125,7 @@ bool GetBluetoothEnabled() override; bool GetBluetoothDiscovering() override; void ChangeProxySettings() override; + ash::CastConfigDelegate* GetCastConfigDelegate() const override; ash::NetworkingConfigDelegate* GetNetworkingConfigDelegate() const override; ash::VolumeControlDelegate* GetVolumeControlDelegate() const override; void SetVolumeControlDelegate( @@ -292,6 +293,7 @@ scoped_refptr<device::BluetoothAdapter> bluetooth_adapter_; scoped_ptr<device::BluetoothDiscoverySession> bluetooth_discovery_session_; + scoped_ptr<ash::CastConfigDelegate> cast_config_delegate_; scoped_ptr<ash::NetworkingConfigDelegate> networking_config_delegate_; scoped_ptr<ash::VolumeControlDelegate> volume_control_delegate_; scoped_ptr<CrosSettingsObserverSubscription> device_settings_observer_;
diff --git a/chrome/browser/ui/autofill/card_unmask_prompt_controller_impl.cc b/chrome/browser/ui/autofill/card_unmask_prompt_controller_impl.cc index 6de0858..fadae3a 100644 --- a/chrome/browser/ui/autofill/card_unmask_prompt_controller_impl.cc +++ b/chrome/browser/ui/autofill/card_unmask_prompt_controller_impl.cc
@@ -48,6 +48,7 @@ if (card_unmask_view_) card_unmask_view_->ControllerGone(); + new_card_link_clicked_ = false; shown_timestamp_ = base::Time::Now(); pending_response_ = CardUnmaskDelegate::UnmaskResponse(); LoadRiskFingerprint();
diff --git a/chrome/browser/ui/autofill/password_generation_popup_controller_impl.cc b/chrome/browser/ui/autofill/password_generation_popup_controller_impl.cc index 26a3649..5ee343e6 100644 --- a/chrome/browser/ui/autofill/password_generation_popup_controller_impl.cc +++ b/chrome/browser/ui/autofill/password_generation_popup_controller_impl.cc
@@ -11,11 +11,13 @@ #include "base/strings/string_util.h" #include "base/strings/utf_string_conversion_utils.h" #include "base/strings/utf_string_conversions.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/autofill/password_generation_popup_observer.h" #include "chrome/browser/ui/autofill/password_generation_popup_view.h" #include "chrome/browser/ui/autofill/popup_constants.h" #include "chrome/browser/ui/browser_finder.h" #include "chrome/browser/ui/chrome_pages.h" +#include "chrome/browser/ui/passwords/password_bubble_experiment.h" #include "chrome/common/url_constants.h" #include "chrome/grit/chromium_strings.h" #include "chrome/grit/generated_resources.h" @@ -87,15 +89,18 @@ base::Bind(&PasswordGenerationPopupControllerImpl::HandleKeyPressEvent, base::Unretained(this))); - std::vector<base::string16> pieces; - base::SplitStringDontTrim( - l10n_util::GetStringUTF16(IDS_PASSWORD_GENERATION_PROMPT), - '|', // separator - &pieces); - DCHECK_EQ(3u, pieces.size()); - link_range_ = gfx::Range(pieces[0].size(), - pieces[0].size() + pieces[1].size()); - help_text_ = JoinString(pieces, base::string16()); + int link_id = IDS_MANAGE_PASSWORDS_LINK; + int help_text_id = IDS_PASSWORD_GENERATION_PROMPT; + if (password_bubble_experiment::IsSmartLockBrandingEnabled( + Profile::FromBrowserContext(web_contents->GetBrowserContext()))) { + help_text_id = IDS_PASSWORD_GENERATION_SMART_LOCK_PROMPT; + link_id = IDS_PASSWORD_MANAGER_SMART_LOCK_FOR_PASSWORDS; + } + + base::string16 link = l10n_util::GetStringUTF16(link_id); + size_t offset; + help_text_ = l10n_util::GetStringFUTF16(help_text_id, link, &offset); + link_range_ = gfx::Range(offset, offset + link.length()); } PasswordGenerationPopupControllerImpl::~PasswordGenerationPopupControllerImpl()
diff --git a/chrome/browser/ui/blocked_content/popup_blocker_browsertest.cc b/chrome/browser/ui/blocked_content/popup_blocker_browsertest.cc index 963aa2a..e4264d4 100644 --- a/chrome/browser/ui/blocked_content/popup_blocker_browsertest.cc +++ b/chrome/browser/ui/blocked_content/popup_blocker_browsertest.cc
@@ -45,6 +45,7 @@ #include "net/dns/mock_host_resolver.h" #include "net/test/embedded_test_server/embedded_test_server.h" #include "testing/gtest/include/gtest/gtest.h" +#include "ui/events/keycodes/dom/dom_code.h" #include "ui/events/keycodes/dom/keycode_converter.h" using content::WebContents; @@ -637,35 +638,38 @@ #if defined(OS_MACOSX) int modifiers = blink::WebInputEvent::MetaKey; - InjectRawKeyEvent(tab, blink::WebInputEvent::RawKeyDown, ui::VKEY_COMMAND, - ui::KeycodeConverter::CodeToNativeKeycode("OSLeft"), - modifiers); + InjectRawKeyEvent( + tab, blink::WebInputEvent::RawKeyDown, ui::VKEY_COMMAND, + ui::KeycodeConverter::DomCodeToNativeKeycode(ui::DomCode::OS_LEFT), + modifiers); #else int modifiers = blink::WebInputEvent::ControlKey; - InjectRawKeyEvent(tab, blink::WebInputEvent::RawKeyDown, ui::VKEY_CONTROL, - ui::KeycodeConverter::CodeToNativeKeycode("ControlLeft"), - modifiers); + InjectRawKeyEvent( + tab, blink::WebInputEvent::RawKeyDown, ui::VKEY_CONTROL, + ui::KeycodeConverter::DomCodeToNativeKeycode(ui::DomCode::CONTROL_LEFT), + modifiers); #endif InjectRawKeyEvent(tab, blink::WebInputEvent::RawKeyDown, ui::VKEY_RETURN, - ui::KeycodeConverter::CodeToNativeKeycode(NULL), modifiers); + ui::KeycodeConverter::InvalidNativeKeycode(), modifiers); InjectRawKeyEvent(tab, blink::WebInputEvent::Char, ui::VKEY_RETURN, - ui::KeycodeConverter::CodeToNativeKeycode(NULL), modifiers); + ui::KeycodeConverter::InvalidNativeKeycode(), modifiers); InjectRawKeyEvent(tab, blink::WebInputEvent::KeyUp, ui::VKEY_RETURN, - ui::KeycodeConverter::CodeToNativeKeycode(NULL), modifiers); + ui::KeycodeConverter::InvalidNativeKeycode(), modifiers); #if defined(OS_MACOSX) - InjectRawKeyEvent(tab, blink::WebInputEvent::KeyUp, ui::VKEY_COMMAND, - ui::KeycodeConverter::CodeToNativeKeycode("OSLeft"), - modifiers); + InjectRawKeyEvent( + tab, blink::WebInputEvent::KeyUp, ui::VKEY_COMMAND, + ui::KeycodeConverter::DomCodeToNativeKeycode(ui::DomCode::OS_LEFT), + modifiers); #else - InjectRawKeyEvent(tab, blink::WebInputEvent::KeyUp, ui::VKEY_CONTROL, - ui::KeycodeConverter::CodeToNativeKeycode("ControlLeft"), - modifiers); + InjectRawKeyEvent( + tab, blink::WebInputEvent::KeyUp, ui::VKEY_CONTROL, + ui::KeycodeConverter::DomCodeToNativeKeycode(ui::DomCode::CONTROL_LEFT), + modifiers); #endif - wait_for_new_tab.Wait(); ASSERT_EQ(1u, chrome::GetBrowserCount(browser()->profile(),
diff --git a/chrome/browser/ui/cocoa/browser_window_cocoa.mm b/chrome/browser/ui/cocoa/browser_window_cocoa.mm index 5a70b39..dab05bbc 100644 --- a/chrome/browser/ui/cocoa/browser_window_cocoa.mm +++ b/chrome/browser/ui/cocoa/browser_window_cocoa.mm
@@ -330,11 +330,13 @@ content::WebContents* new_contents, int index, int reason) { + [controller_ onActiveTabChanged:old_contents to:new_contents]; // TODO(pkasting): Perhaps the code in // TabStripController::activateTabWithContents should move here? Or this // should call that (instead of TabStripModelObserverBridge doing so)? It's // not obvious to me why Mac doesn't handle tab changes in BrowserWindow the // way views and GTK do. + // See http://crbug.com/340720 for discussion. } void BrowserWindowCocoa::ZoomChangedForActiveTab(bool can_show_bubble) {
diff --git a/chrome/browser/ui/cocoa/browser_window_controller.h b/chrome/browser/ui/cocoa/browser_window_controller.h index b9676e1..1597b0f 100644 --- a/chrome/browser/ui/cocoa/browser_window_controller.h +++ b/chrome/browser/ui/cocoa/browser_window_controller.h
@@ -253,6 +253,11 @@ // Sets whether or not the current page is translated. - (void)setCurrentPageIsTranslated:(BOOL)on; +// Invoked via BrowserWindowCocoa::OnActiveTabChanged, happens whenever a +// new tab becomes active. +- (void)onActiveTabChanged:(content::WebContents*)oldContents + to:(content::WebContents*)newContents; + // Happens when the zoom level is changed in the active tab, the active tab is // changed, or a new browser window or tab is created. |canShowBubble| denotes // whether it would be appropriate to show a zoom bubble or not.
diff --git a/chrome/browser/ui/cocoa/browser_window_controller.mm b/chrome/browser/ui/cocoa/browser_window_controller.mm index b176b64..b33ec48 100644 --- a/chrome/browser/ui/cocoa/browser_window_controller.mm +++ b/chrome/browser/ui/cocoa/browser_window_controller.mm
@@ -395,9 +395,6 @@ // Create the bridge for the status bubble. statusBubble_ = new StatusBubbleMac([self window], self); - // Create the permissions bubble. - permissionBubbleCocoa_.reset(new PermissionBubbleCocoa([self window])); - // Register for application hide/unhide notifications. [[NSNotificationCenter defaultCenter] addObserver:self @@ -1269,6 +1266,26 @@ [toolbarController_ setTranslateIconLit:on]; } +- (void)onActiveTabChanged:(content::WebContents*)oldContents + to:(content::WebContents*)newContents { + // No need to remove previous bubble. It will close itself. + PermissionBubbleManager* manager(nullptr); + if (oldContents) { + manager = PermissionBubbleManager::FromWebContents(oldContents); + if (manager) + manager->SetView(nullptr); + } + + if (newContents) { + if (!permissionBubbleCocoa_.get()) { + permissionBubbleCocoa_.reset(new PermissionBubbleCocoa([self window])); + } + manager = PermissionBubbleManager::FromWebContents(newContents); + if (manager) + manager->SetView(permissionBubbleCocoa_.get()); + } +} + - (void)zoomChangedForActiveTab:(BOOL)canShowBubble { [toolbarController_ zoomChangedForActiveTab:canShowBubble]; } @@ -1651,14 +1668,6 @@ [infoBarContainerController_ changeWebContents:contents]; - // No need to remove previous bubble. It will close itself. - // TODO(leng): The PermissionBubbleManager for the previous contents should - // have SetView(NULL) called. Fix this when the previous contents are - // available here or move to BrowserWindowCocoa::OnActiveTabChanged(). - // crbug.com/340720 - PermissionBubbleManager::FromWebContents(contents)->SetView( - permissionBubbleCocoa_.get()); - // Must do this after bookmark and infobar updates to avoid // unnecesary resize in contents. [devToolsController_ updateDevToolsForWebContents:contents
diff --git a/chrome/browser/ui/cocoa/download/download_item_button.h b/chrome/browser/ui/cocoa/download/download_item_button.h index e012491..33646d7 100644 --- a/chrome/browser/ui/cocoa/download/download_item_button.h +++ b/chrome/browser/ui/cocoa/download/download_item_button.h
@@ -1,4 +1,4 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Copyright 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -17,11 +17,15 @@ @private base::FilePath downloadPath_; DownloadItemController* controller_; // weak + base::scoped_nsobject<NSMenu> contextMenu_; } @property(assign, nonatomic) base::FilePath download; @property(assign, nonatomic) DownloadItemController* controller; +// Shows the DownloadItemButton's context menu. +- (void)showContextMenu; + // Overridden from DraggableButton. - (void)beginDrag:(NSEvent*)event;
diff --git a/chrome/browser/ui/cocoa/download/download_item_button.mm b/chrome/browser/ui/cocoa/download/download_item_button.mm index 141976df..b2b6ae9 100644 --- a/chrome/browser/ui/cocoa/download/download_item_button.mm +++ b/chrome/browser/ui/cocoa/download/download_item_button.mm
@@ -1,4 +1,4 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Copyright 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -25,6 +25,18 @@ } } +- (void)showContextMenu { + base::scoped_nsobject<DownloadShelfContextMenuController> menuController( + [[DownloadShelfContextMenuController alloc] + initWithItemController:controller_ + withDelegate:self]); + contextMenu_.reset([[menuController menu] retain]); + [NSMenu popUpContextMenu:contextMenu_.get() + withEvent:[NSApp currentEvent] + forView:self]; + contextMenu_.reset(); +} + // Override to show a context menu on mouse down if clicked over the context // menu area. - (void)mouseDown:(NSEvent*)event { @@ -35,15 +47,8 @@ if ([reinterpret_cast<DownloadItemCell*>(cell) isMouseOverButtonPart]) { [self.draggableButton mouseDownImpl:event]; } else { - base::scoped_nsobject<DownloadShelfContextMenuController> menuController( - [[DownloadShelfContextMenuController alloc] - initWithItemController:controller_ - withDelegate:self]); - [cell setHighlighted:YES]; - [NSMenu popUpContextMenu:[menuController menu] - withEvent:[NSApp currentEvent] - forView:self]; + [self showContextMenu]; } } @@ -84,4 +89,16 @@ [self setNeedsDisplay:YES]; } +- (BOOL)showingContextMenu +{ + return contextMenu_.get() != nil; +} + +- (void)viewWillMoveToWindow:(NSWindow *)newWindow { + // If the DownloadItemButton's context menu is still visible, dismiss it. + if (!newWindow) { + [contextMenu_.get() cancelTrackingWithoutAnimation]; + } +} + @end
diff --git a/chrome/browser/ui/cocoa/download/download_item_controller.mm b/chrome/browser/ui/cocoa/download/download_item_controller.mm index 801e739b..7ffaf4e0 100644 --- a/chrome/browser/ui/cocoa/download/download_item_controller.mm +++ b/chrome/browser/ui/cocoa/download/download_item_controller.mm
@@ -1,4 +1,4 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Copyright 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -370,13 +370,7 @@ } - (IBAction)showContextMenu:(id)sender { - base::scoped_nsobject<DownloadShelfContextMenuController> menuController( - [[DownloadShelfContextMenuController alloc] - initWithItemController:self - withDelegate:nil]); - [NSMenu popUpContextMenu:[menuController menu] - withEvent:[NSApp currentEvent] - forView:[self view]]; + [progressView_ showContextMenu]; } @end
diff --git a/chrome/browser/ui/cocoa/download/download_item_controller_unittest.mm b/chrome/browser/ui/cocoa/download/download_item_controller_unittest.mm index cf7a98c..b800b99 100644 --- a/chrome/browser/ui/cocoa/download/download_item_controller_unittest.mm +++ b/chrome/browser/ui/cocoa/download/download_item_controller_unittest.mm
@@ -8,6 +8,7 @@ #include "base/memory/scoped_ptr.h" #include "base/run_loop.h" #include "chrome/browser/ui/cocoa/cocoa_profile_test.h" +#import "chrome/browser/ui/cocoa/download/download_item_button.h" #import "chrome/browser/ui/cocoa/download/download_item_controller.h" #import "chrome/browser/ui/cocoa/download/download_shelf_controller.h" #include "content/public/test/mock_download_item.h" @@ -44,6 +45,13 @@ - (void)awakeFromNib; @end +@interface DownloadItemButton(DownloadItemButtonTest) + +- (BOOL)showingContextMenu; + +@end + + @implementation DownloadItemControllerWithInitCallback - (id)initWithDownload:(content::DownloadItem*)downloadItem @@ -179,4 +187,31 @@ [(id)shelf_ verify]; } +TEST_F(DownloadItemControllerTest, DismissesContextMenuWhenRemovedFromWindow) { + base::scoped_nsobject<DownloadItemController> item(CreateItemController()); + DownloadItemButton* downloadItemButton = nil; + for (NSView *nextSubview in [[item view] subviews]) { + if ([nextSubview isKindOfClass:[DownloadItemButton class]]) { + downloadItemButton = static_cast<DownloadItemButton *>(nextSubview); + break; + } + } + + // showContextMenu: calls [NSMenu popUpContextMenu:...], which blocks until + // the menu is dismissed. Use a block to cancel the menu while waiting for + // [NSMenu popUpContextMenu:...] to return (this block will execute on the + // main thread, on the next pass through the run loop). + [[NSOperationQueue mainQueue] addOperationWithBlock:^{ + EXPECT_TRUE([downloadItemButton showingContextMenu]); + // Simulate the item's removal from the shelf. Ideally we would call an + // actual shelf removal method like [item remove] but the shelf and + // download item are mock objects. + [downloadItemButton removeFromSuperview]; + }]; + // The unit test will stop here until the block causes the DownloadItemButton + // to dismiss the menu. + [item showContextMenu:nil]; +} + + } // namespace
diff --git a/chrome/browser/ui/cocoa/download/download_show_all_button.mm b/chrome/browser/ui/cocoa/download/download_show_all_button.mm index 6a91543..df7ab45 100644 --- a/chrome/browser/ui/cocoa/download/download_show_all_button.mm +++ b/chrome/browser/ui/cocoa/download/download_show_all_button.mm
@@ -44,7 +44,18 @@ - (void)drawRect:(NSRect)rect { NSView* downloadShelfView = [self ancestorWithViewID:VIEW_ID_DOWNLOAD_SHELF]; - [self cr_drawUsingAncestor:downloadShelfView inRect:rect]; + // Previously the show all button used cr_drawUsingAncestor:inRect: to use + // the download shelf to draw its background. However when the download + // shelf has zero height, the shelf's drawing methods don't work as expected + // because they constrain their drawing to the shelf's bounds rect. This + // situation occurs sometimes when the shelf is about to become visible, + // and the result is a very dark show all button + // + // To work around this problem, we'll call a variant of that method which + // does restrict drawing to the ancestor view's bounds. + [self cr_drawUsingAncestor:downloadShelfView + inRect:rect + clippedToAncestorBounds:NO]; [super drawRect:rect]; }
diff --git a/chrome/browser/ui/cocoa/extensions/extension_message_bubble_bridge.mm b/chrome/browser/ui/cocoa/extensions/extension_message_bubble_bridge.mm index cc9832f..137a5f7c 100644 --- a/chrome/browser/ui/cocoa/extensions/extension_message_bubble_bridge.mm +++ b/chrome/browser/ui/cocoa/extensions/extension_message_bubble_bridge.mm
@@ -34,7 +34,9 @@ } base::string16 ExtensionMessageBubbleBridge::GetBodyText() { - return controller_->delegate()->GetMessageBody(anchored_to_extension_); + return controller_->delegate()->GetMessageBody( + anchored_to_extension_, + controller_->GetExtensionIdList().size()); } base::string16 ExtensionMessageBubbleBridge::GetItemListText() {
diff --git a/chrome/browser/ui/libgtk2ui/gtk2_ui.cc b/chrome/browser/ui/libgtk2ui/gtk2_ui.cc index 1925e13..29d8e1c3 100644 --- a/chrome/browser/ui/libgtk2ui/gtk2_ui.cc +++ b/chrome/browser/ui/libgtk2ui/gtk2_ui.cc
@@ -8,6 +8,7 @@ #include <set> #include <pango/pango.h> +#include <X11/Xlib.h> #include "base/command_line.h" #include "base/debug/leak_annotations.h" @@ -49,6 +50,7 @@ #include "ui/gfx/image/image.h" #include "ui/gfx/skbitmap_operations.h" #include "ui/gfx/skia_util.h" +#include "ui/gfx/x/x11_types.h" #include "ui/resources/grit/ui_resources.h" #include "ui/views/controls/button/label_button.h" #include "ui/views/controls/button/label_button_border.h" @@ -378,20 +380,27 @@ return params; } -double GetDPI() { +double GetBaseDPI() { + XDisplay* xdisplay = gfx::GetXDisplay(); + int xscreen = DefaultScreen(xdisplay); + return (DisplayHeight(xdisplay, xscreen) * 25.4) / + DisplayHeightMM(xdisplay, xscreen); +} + +double GetFontDPI() { GtkSettings* gtk_settings = gtk_settings_get_default(); CHECK(gtk_settings); gint gtk_dpi = -1; g_object_get(gtk_settings, "gtk-xft-dpi", >k_dpi, NULL); // GTK multiplies the DPI by 1024 before storing it. - return (gtk_dpi > 0) ? gtk_dpi / 1024.0 : 96.0; + return (gtk_dpi > 0) ? gtk_dpi / 1024.0 : GetBaseDPI(); } // Queries GTK for its font DPI setting and returns the number of pixels in a // point. double GetPixelsInPoint(float device_scale_factor) { - double dpi = GetDPI(); + double dpi = GetFontDPI(); // Take device_scale_factor into account — if Chrome already scales the // entire UI up by 2x, we should not also scale up. @@ -1424,10 +1433,9 @@ } float Gtk2UI::GetDeviceScaleFactor() const { - const int kCSSDefaultDPI = 96; - float scale = GetDPI() / kCSSDefaultDPI; - // Round to 2 decimals, e.g. to 1.33. - return roundf(scale * 100) / 100; + float scale = GetFontDPI() / GetBaseDPI(); + // Round to 1 decimal, e.g. to 1.4. + return roundf(scale * 10) / 10; } } // namespace libgtk2ui
diff --git a/chrome/browser/ui/panels/panel.cc b/chrome/browser/ui/panels/panel.cc index 949c612a..7c98b7d6 100644 --- a/chrome/browser/ui/panels/panel.cc +++ b/chrome/browser/ui/panels/panel.cc
@@ -437,9 +437,6 @@ const content::NotificationSource& source, const content::NotificationDetails& details) { switch (type) { - case content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED: - ConfigureAutoResize(content::Source<content::WebContents>(source).ptr()); - break; case chrome::NOTIFICATION_APP_TERMINATING: Close(); break; @@ -448,6 +445,11 @@ } } +void Panel::RenderViewHostChanged(content::RenderViewHost* old_host, + content::RenderViewHost* new_host) { + ConfigureAutoResize(web_contents()); +} + void Panel::OnExtensionUnloaded( content::BrowserContext* browser_context, const extensions::Extension* extension, @@ -593,8 +595,7 @@ EnableWebContentsAutoResize(web_contents); } else { if (web_contents) { - registrar_.Remove(this, content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED, - content::Source<content::WebContents>(web_contents)); + content::WebContentsObserver::Observe(nullptr); // NULL might be returned if the tab has not been added. RenderViewHost* render_view_host = web_contents->GetRenderViewHost(); @@ -610,14 +611,7 @@ // We also need to know when the render view host changes in order // to turn on auto-resize notifications in the new render view host. - if (!registrar_.IsRegistered( - this, content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED, - content::Source<content::WebContents>(web_contents))) { - registrar_.Add( - this, - content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED, - content::Source<content::WebContents>(web_contents)); - } + content::WebContentsObserver::Observe(web_contents); } void Panel::OnContentsAutoResized(const gfx::Size& new_content_size) {
diff --git a/chrome/browser/ui/panels/panel.h b/chrome/browser/ui/panels/panel.h index fa511d7..877b08c 100644 --- a/chrome/browser/ui/panels/panel.h +++ b/chrome/browser/ui/panels/panel.h
@@ -17,6 +17,7 @@ #include "components/sessions/session_id.h" #include "content/public/browser/notification_observer.h" #include "content/public/browser/notification_registrar.h" +#include "content/public/browser/web_contents_observer.h" #include "extensions/browser/extension_registry_observer.h" #include "ui/base/base_window.h" #include "ui/gfx/geometry/rect.h" @@ -53,6 +54,7 @@ class Panel : public ui::BaseWindow, public CommandUpdaterDelegate, public content::NotificationObserver, + public content::WebContentsObserver, public extensions::ExtensionRegistryObserver { public: enum ExpansionState { @@ -147,6 +149,10 @@ const content::NotificationSource& source, const content::NotificationDetails& details) override; + // content::WebContentsObserver overrides. + void RenderViewHostChanged(content::RenderViewHost* old_host, + content::RenderViewHost* new_host) override; + // extensions::ExtensionRegistryObserver. void OnExtensionUnloaded( content::BrowserContext* browser_context,
diff --git a/chrome/browser/ui/passwords/manage_passwords_bubble_model.cc b/chrome/browser/ui/passwords/manage_passwords_bubble_model.cc index dd9ed49..2b832256 100644 --- a/chrome/browser/ui/passwords/manage_passwords_bubble_model.cc +++ b/chrome/browser/ui/passwords/manage_passwords_bubble_model.cc
@@ -13,6 +13,7 @@ #include "chrome/browser/ui/browser_finder.h" #include "chrome/browser/ui/passwords/manage_passwords_ui_controller.h" #include "chrome/browser/ui/passwords/password_bubble_experiment.h" +#include "chrome/common/url_constants.h" #include "chrome/grit/chromium_strings.h" #include "chrome/grit/generated_resources.h" #include "components/feedback/feedback_data.h" @@ -118,11 +119,20 @@ if (state_ == password_manager::ui::CONFIRMATION_STATE) { base::string16 save_confirmation_link = - l10n_util::GetStringUTF16(IDS_MANAGE_PASSWORDS_CONFIRM_GENERATED_LINK); + l10n_util::GetStringUTF16(IDS_MANAGE_PASSWORDS_LINK); + int confirmation_text_id = IDS_MANAGE_PASSWORDS_CONFIRM_GENERATED_TEXT; + if (password_bubble_experiment::IsSmartLockBrandingEnabled(GetProfile())) { + std::string management_hostname = + GURL(chrome::kPasswordManagerAccountDashboardURL).host(); + save_confirmation_link = base::UTF8ToUTF16(management_hostname); + confirmation_text_id = + IDS_MANAGE_PASSWORDS_CONFIRM_GENERATED_SMART_LOCK_TEXT; + } + size_t offset; save_confirmation_text_ = - l10n_util::GetStringFUTF16(IDS_MANAGE_PASSWORDS_CONFIRM_GENERATED_TEXT, - save_confirmation_link, &offset); + l10n_util::GetStringFUTF16( + confirmation_text_id, save_confirmation_link, &offset); save_confirmation_link_range_ = gfx::Range(offset, offset + save_confirmation_link.length()); } @@ -239,8 +249,13 @@ void ManagePasswordsBubbleModel::OnManageLinkClicked() { dismissal_reason_ = metrics_util::CLICKED_MANAGE; - ManagePasswordsUIController::FromWebContents(web_contents()) - ->NavigateToPasswordManagerSettingsPage(); + if (password_bubble_experiment::IsSmartLockBrandingEnabled(GetProfile())) { + ManagePasswordsUIController::FromWebContents(web_contents()) + ->NavigateToExternalPasswordManager(); + } else { + ManagePasswordsUIController::FromWebContents(web_contents()) + ->NavigateToPasswordManagerSettingsPage(); + } } void ManagePasswordsBubbleModel::OnBrandLinkClicked() { @@ -313,8 +328,8 @@ if (never_save_passwords_) { title_ = l10n_util::GetStringUTF16( IDS_MANAGE_PASSWORDS_BLACKLIST_CONFIRMATION_TITLE); - } else if (password_bubble_experiment::IsEnabledSmartLockBranding( - GetProfile())) { + } else if (password_bubble_experiment::IsSmartLockBrandingEnabled( + GetProfile())) { // "Google Smart Lock" should be a hyperlink. base::string16 brand_link = l10n_util::GetStringUTF16(IDS_PASSWORD_MANAGER_SMART_LOCK);
diff --git a/chrome/browser/ui/passwords/manage_passwords_ui_controller.cc b/chrome/browser/ui/passwords/manage_passwords_ui_controller.cc index 4007400..02fa300e 100644 --- a/chrome/browser/ui/passwords/manage_passwords_ui_controller.cc +++ b/chrome/browser/ui/passwords/manage_passwords_ui_controller.cc
@@ -159,8 +159,7 @@ UpdateBubbleAndIconVisibility(); } -void ManagePasswordsUIController:: - NavigateToPasswordManagerSettingsPage() { +void ManagePasswordsUIController::NavigateToPasswordManagerSettingsPage() { #if defined(OS_ANDROID) chrome::android::ChromiumApplication::ShowPasswordSettings(); #else @@ -170,6 +169,19 @@ #endif } +void ManagePasswordsUIController::NavigateToExternalPasswordManager() { +#if defined(OS_ANDROID) + NOTREACHED(); +#else + chrome::NavigateParams params( + chrome::FindBrowserWithWebContents(web_contents()), + GURL(chrome::kPasswordManagerAccountDashboardURL), + ui::PAGE_TRANSITION_LINK); + params.disposition = NEW_FOREGROUND_TAB; + chrome::Navigate(¶ms); +#endif +} + void ManagePasswordsUIController::NavigateToSmartLockHelpArticle() { #if defined(OS_ANDROID) NOTREACHED();
diff --git a/chrome/browser/ui/passwords/manage_passwords_ui_controller.h b/chrome/browser/ui/passwords/manage_passwords_ui_controller.h index 9abec5c..10debdb 100644 --- a/chrome/browser/ui/passwords/manage_passwords_ui_controller.h +++ b/chrome/browser/ui/passwords/manage_passwords_ui_controller.h
@@ -104,6 +104,9 @@ // Open a new tab, pointing to the password manager settings page. virtual void NavigateToPasswordManagerSettingsPage(); + // Open a new tab, pointing to passwords.google.com. + void NavigateToExternalPasswordManager(); + // Open a new tab, pointing to the Smart Lock help article. void NavigateToSmartLockHelpArticle();
diff --git a/chrome/browser/ui/passwords/password_bubble_experiment.cc b/chrome/browser/ui/passwords/password_bubble_experiment.cc index 4402e801..aca8198 100644 --- a/chrome/browser/ui/passwords/password_bubble_experiment.cc +++ b/chrome/browser/ui/passwords/password_bubble_experiment.cc
@@ -12,7 +12,7 @@ namespace password_bubble_experiment { namespace { -const char kBrandingExperimentName[] = "PasswordBubbleBranding"; +const char kBrandingExperimentName[] = "PasswordBranding"; const char kSmartLockBrandingGroupName[] = "SmartLockBranding"; } // namespace @@ -23,13 +23,13 @@ // TODO(vasilii): store the statistics. } -bool IsEnabledSmartLockBranding(Profile* profile) { +bool IsSmartLockBrandingEnabled(Profile* profile) { const ProfileSyncService* sync_service = ProfileSyncServiceFactory::GetForProfile(profile); - return password_manager_util::GetPasswordSyncState(sync_service) && + return password_manager_util::GetPasswordSyncState(sync_service) == + password_manager::SYNCING_NORMAL_ENCRYPTION && base::FieldTrialList::FindFullName(kBrandingExperimentName) == kSmartLockBrandingGroupName; } - } // namespace password_bubble_experiment
diff --git a/chrome/browser/ui/passwords/password_bubble_experiment.h b/chrome/browser/ui/passwords/password_bubble_experiment.h index cf38e82..f20ac7f 100644 --- a/chrome/browser/ui/passwords/password_bubble_experiment.h +++ b/chrome/browser/ui/passwords/password_bubble_experiment.h
@@ -18,9 +18,9 @@ PrefService* prefs, password_manager::metrics_util::UIDismissalReason reason); -// Returns true if the Save bubble should mention Smart Lock instead of Chrome. +// Returns true if the password manager should be referred to as Smart Lock. // This is only true for signed-in users. -bool IsEnabledSmartLockBranding(Profile* profile); +bool IsSmartLockBrandingEnabled(Profile* profile); } // namespace password_bubble_experiment
diff --git a/chrome/browser/ui/views/extensions/extension_message_bubble_view.cc b/chrome/browser/ui/views/extensions/extension_message_bubble_view.cc index bc0619f8..2959f9a9 100644 --- a/chrome/browser/ui/views/extensions/extension_message_bubble_view.cc +++ b/chrome/browser/ui/views/extensions/extension_message_bubble_view.cc
@@ -123,7 +123,8 @@ message->SetMultiLine(true); message->SetHorizontalAlignment(gfx::ALIGN_LEFT); message->SetText(delegate->GetMessageBody( - anchor_view_->id() == VIEW_ID_BROWSER_ACTION)); + anchor_view_->id() == VIEW_ID_BROWSER_ACTION, + controller_->GetExtensionIdList().size())); message->SizeToFit(views::Widget::GetLocalizedContentsWidth( IDS_EXTENSION_WIPEOUT_BUBBLE_WIDTH_CHARS)); layout->AddView(message);
diff --git a/chrome/browser/ui/views/extensions/extension_uninstall_dialog_view.cc b/chrome/browser/ui/views/extensions/extension_uninstall_dialog_view.cc index d211a53..c402e8b 100644 --- a/chrome/browser/ui/views/extensions/extension_uninstall_dialog_view.cc +++ b/chrome/browser/ui/views/extensions/extension_uninstall_dialog_view.cc
@@ -69,8 +69,7 @@ public: ExtensionUninstallDialogDelegateView( ExtensionUninstallDialogViews* dialog_view, - const extensions::Extension* extension, - const extensions::Extension* triggering_extension, + bool triggered_by_extension, gfx::ImageSkia* image); ~ExtensionUninstallDialogDelegateView() override; @@ -135,7 +134,7 @@ } view_ = new ExtensionUninstallDialogDelegateView( - this, extension_, triggering_extension_, &icon_); + this, triggering_extension_.get() != nullptr, &icon_); constrained_window::CreateBrowserModalDialogViews(view_, parent_)->Show(); } @@ -162,11 +161,10 @@ ExtensionUninstallDialogDelegateView::ExtensionUninstallDialogDelegateView( ExtensionUninstallDialogViews* dialog_view, - const extensions::Extension* extension, - const extensions::Extension* triggering_extension, + bool triggered_by_extension, gfx::ImageSkia* image) : dialog_(dialog_view), - triggered_by_extension_(triggering_extension != NULL), + triggered_by_extension_(triggered_by_extension), report_abuse_checkbox_(nullptr) { // Scale down to icon size, but allow smaller icons (don't scale up). gfx::Size size(image->width(), image->height());
diff --git a/chrome/browser/ui/views/frame/system_menu_model_builder.cc b/chrome/browser/ui/views/frame/system_menu_model_builder.cc index e877f97..0e5d48fb 100644 --- a/chrome/browser/ui/views/frame/system_menu_model_builder.cc +++ b/chrome/browser/ui/views/frame/system_menu_model_builder.cc
@@ -9,8 +9,10 @@ #include "chrome/app/chrome_command_ids.h" #include "chrome/browser/ui/browser_commands.h" #include "chrome/browser/ui/host_desktop.h" +#include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/browser/ui/toolbar/wrench_menu_model.h" #include "chrome/common/chrome_switches.h" +#include "chrome/common/url_constants.h" #include "chrome/grit/generated_resources.h" #include "ui/base/accelerators/accelerator.h" #include "ui/base/models/simple_menu_model.h" @@ -25,6 +27,24 @@ #include "ui/base/l10n/l10n_util.h" #endif +namespace { + +// Given a |browser| that's an app or popup window, checks if it's hosting the +// settings page. +bool IsChromeSettingsAppOrPopupWindow(Browser* browser) { + DCHECK(browser); + TabStripModel* tab_strip = browser->tab_strip_model(); + DCHECK_EQ(1, tab_strip->count()); + const GURL gurl(tab_strip->GetWebContentsAt(0)->GetURL()); + if (gurl.SchemeIs(content::kChromeUIScheme) && + gurl.host().find(chrome::kChromeUISettingsHost) != std::string::npos) { + return true; + } + return false; +} + +} // namespace + SystemMenuModelBuilder::SystemMenuModelBuilder( ui::AcceleratorProvider* provider, Browser* browser) @@ -108,7 +128,13 @@ model->AddItemWithStringId(IDC_CLOSE_WINDOW, IDS_CLOSE); #endif - AppendTeleportMenu(model); + // Avoid appending the teleport menu for the settings window. This window's + // presentation is unique: it's a normal browser window with an app-like + // frame, which doesn't have a user icon badge. Thus if teleported it's not + // clear what user it applies to. Rather than bother to implement badging just + // for this rare case, simply prevent the user from teleporting the window. + if (!IsChromeSettingsAppOrPopupWindow(browser())) + AppendTeleportMenu(model); } void SystemMenuModelBuilder::AddFrameToggleItems(ui::SimpleMenuModel* model) {
diff --git a/chrome/browser/ui/webui/certificate_viewer_webui.cc b/chrome/browser/ui/webui/certificate_viewer_webui.cc index 8bbbfdca..7f9c668fc 100644 --- a/chrome/browser/ui/webui/certificate_viewer_webui.cc +++ b/chrome/browser/ui/webui/certificate_viewer_webui.cc
@@ -187,7 +187,7 @@ // Set the last node as the top of the certificate hierarchy. cert_info.Set("hierarchy", children); - base::JSONWriter::Write(&cert_info, &data); + base::JSONWriter::Write(cert_info, &data); return data; }
diff --git a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc index fc43f0d..1ef2156d 100644 --- a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc +++ b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
@@ -96,7 +96,6 @@ #if !defined(OS_ANDROID) #include "chrome/browser/ui/webui/ntp/new_tab_ui.h" #include "chrome/browser/ui/webui/quota_internals/quota_internals_ui.h" -#include "chrome/browser/ui/webui/suggestions_internals/suggestions_internals_ui.h" #include "chrome/browser/ui/webui/sync_file_system_internals/sync_file_system_internals_ui.h" #include "chrome/browser/ui/webui/system_info_ui.h" #include "chrome/browser/ui/webui/uber/uber_ui.h" @@ -406,8 +405,6 @@ ::switches::AboutInSettingsEnabled())) { return &NewWebUI<options::OptionsUI>; } - if (url.host() == chrome::kChromeUISuggestionsInternalsHost) - return &NewWebUI<SuggestionsInternalsUI>; if (url.host() == chrome::kChromeUISyncFileSystemInternalsHost) return &NewWebUI<SyncFileSystemInternalsUI>; if (url.host() == chrome::kChromeUISystemInfoHost)
diff --git a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc index ce43512..e71da5a 100644 --- a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc +++ b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
@@ -153,8 +153,7 @@ password_changed(false), show_users(false), use_offline(false), - has_users(false), - session_is_ephemeral(false) { + has_users(false) { } GaiaScreenHandler::GaiaScreenHandler( @@ -218,10 +217,6 @@ params.SetString("email", context.email); params.SetBoolean("isEnrollingConsumerManagement", is_enrolling_consumer_management); - if (StartupUtils::IsWebviewSigninEnabled()) { - params.SetString("deviceId", context.device_id); - params.SetBoolean("sessionIsEphemeral", context.session_is_ephemeral); - } UpdateAuthParams(¶ms, context.has_users, @@ -338,9 +333,6 @@ void GaiaScreenHandler::UpdateGaia(const GaiaContext& context) { base::DictionaryValue params; - if (StartupUtils::IsWebviewSigninEnabled()) { - params.SetString("deviceId", context.device_id); - } UpdateAuthParams(¶ms, context.has_users, context.is_enrolling_consumer_management); CallJS("updateAuthExtension", params); @@ -438,7 +430,6 @@ &GaiaScreenHandler::HandleToggleWebviewSignin); AddCallback("toggleEasyBootstrap", &GaiaScreenHandler::HandleToggleEasyBootstrap); - AddCallback("attemptLogin", &GaiaScreenHandler::HandleAttemptLogin); } void GaiaScreenHandler::HandleFrameLoadingCompleted(int status) { @@ -503,8 +494,7 @@ const std::string& email, const std::string& password, const std::string& auth_code, - bool using_saml, - const std::string& device_id) { + bool using_saml) { if (!Delegate()) return; @@ -521,7 +511,6 @@ user_context.SetAuthFlow(using_saml ? UserContext::AUTH_FLOW_GAIA_WITH_SAML : UserContext::AUTH_FLOW_GAIA_WITHOUT_SAML); - user_context.SetDeviceId(device_id); Delegate()->CompleteLogin(user_context); } @@ -601,21 +590,6 @@ LoadAuthExtension(kForceReload, kSilentLoad, kNoOfflineUI); } -void GaiaScreenHandler::HandleAttemptLogin(const std::string& email) { - std::string device_id = - user_manager::UserManager::Get()->GetKnownUserDeviceId( - gaia::CanonicalizeEmail(gaia::SanitizeEmail(email))); - - if (!device_id.empty() && StartupUtils::IsWebviewSigninEnabled()) { - base::DictionaryValue params; - params.SetString("deviceId", device_id); - CallJS("updateDeviceId", params); - } else { - // Mark current temporary device Id as used. - temporary_device_id_ = std::string(); - } -} - void GaiaScreenHandler::HandleGaiaUIReady() { if (focus_stolen_) { // Set focus to the Gaia page. @@ -958,17 +932,6 @@ context.has_users = !Delegate()->GetUsers().empty(); } - if (!context.email.empty()) { - context.device_id = user_manager::UserManager::Get()->GetKnownUserDeviceId( - gaia::CanonicalizeEmail(context.email)); - } - - if (context.device_id.empty()) - context.device_id = GetTemporaryDeviceId(); - - context.session_is_ephemeral = - ChromeUserManager::Get()->AreEphemeralUsersEnabled(); - populated_email_.clear(); LoadGaia(context); @@ -988,12 +951,4 @@ signin_screen_handler_ = handler; } -std::string GaiaScreenHandler::GetTemporaryDeviceId() { - if (temporary_device_id_.empty()) - temporary_device_id_ = base::GenerateGUID(); - - DCHECK(!temporary_device_id_.empty()); - return temporary_device_id_; -} - } // namespace chromeos
diff --git a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h index abc6b3d..7a7575c1 100644 --- a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h +++ b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h
@@ -53,14 +53,8 @@ // GAIA ID of the current user. std::string gaia_id; - // Device Id of the current user. - std::string device_id; - // Whether consumer management enrollment is in progress. bool is_enrolling_consumer_management; - - // If user session would be ephemeral. - bool session_is_ephemeral; }; // A class that handles WebUI hooks in Gaia screen. @@ -121,8 +115,7 @@ const std::string& email, const std::string& password, const std::string& auth_code, - bool using_saml, - const std::string& device_id); + bool using_saml); void HandleCompleteAuthenticationAuthCodeOnly(const std::string& auth_code); void HandleCompleteLogin(const std::string& gaia_id, const std::string& typed_email, @@ -137,8 +130,6 @@ void HandleToggleEasyBootstrap(); - void HandleAttemptLogin(const std::string& email); - void HandleToggleWebviewSignin(); // This is called when ConsumerManagementService::SetOwner() returns. @@ -277,10 +268,6 @@ // GAIA extension loader. scoped_ptr<ScopedGaiaAuthExtension> auth_extension_; - // Temporary DeviceId to be used for new users. - // If it's empty, new deviceId should be generated. - std::string temporary_device_id_; - base::WeakPtrFactory<GaiaScreenHandler> weak_factory_; DISALLOW_COPY_AND_ASSIGN(GaiaScreenHandler);
diff --git a/chrome/browser/ui/webui/help/version_updater_win.cc b/chrome/browser/ui/webui/help/version_updater_win.cc index 2c59ece8..9e47d47e 100644 --- a/chrome/browser/ui/webui/help/version_updater_win.cc +++ b/chrome/browser/ui/webui/help/version_updater_win.cc
@@ -4,10 +4,11 @@ #include "base/memory/weak_ptr.h" #include "base/strings/string16.h" +#include "base/task_runner_util.h" #include "base/win/win_util.h" #include "base/win/windows_version.h" #include "chrome/browser/browser_process.h" -#include "chrome/browser/first_run/upgrade_util_win.h" +#include "chrome/browser/first_run/upgrade_util.h" #include "chrome/browser/google/google_update_win.h" #include "chrome/browser/lifetime/application_lifetime.h" #include "chrome/browser/ui/webui/help/version_updater.h" @@ -49,6 +50,10 @@ void BeginUpdateCheckOnFileThread(bool install_update_if_possible); #endif // GOOGLE_CHROME_BUILD + // A task run on the UI thread with the result of checking for a pending + // restart. + void OnPendingRestartCheck(bool is_update_pending_restart); + // The widget owning the UI for the update check. gfx::AcceleratedWidget owner_widget_; @@ -99,7 +104,19 @@ if (new_version.empty()) { // Google Update says that no new version is available. Check to see if a // restart is needed for a previously-applied update to take effect. - status = upgrade_util::IsRunningOldChrome() ? NEARLY_UPDATED : UPDATED; + if (base::PostTaskAndReplyWithResult( + content::BrowserThread::GetBlockingPool(), + FROM_HERE, + base::Bind(&upgrade_util::IsUpdatePendingRestart), + base::Bind(&VersionUpdaterWin::OnPendingRestartCheck, + weak_factory_.GetWeakPtr()))) { + // Early exit since callback_ will be Run in OnPendingRestartCheck. + return; + } + // Failure to post the task means that Chrome is shutting down. A pending + // update (if there is one) will be applied as Chrome exits, so tell the + // caller that it is up to date in either case. + status = UPDATED; } else { // Notify the caller that the update is now beginning and initiate it. status = UPDATING; @@ -156,6 +173,11 @@ } #endif // GOOGLE_CHROME_BUILD +void VersionUpdaterWin::OnPendingRestartCheck(bool is_update_pending_restart) { + callback_.Run(is_update_pending_restart ? NEARLY_UPDATED : UPDATED, 0, + base::string16()); +} + } // namespace VersionUpdater* VersionUpdater::Create(content::WebContents* web_contents) {
diff --git a/chrome/browser/ui/webui/ntp/new_tab_page_handler.cc b/chrome/browser/ui/webui/ntp/new_tab_page_handler.cc index de548df..d908496 100644 --- a/chrome/browser/ui/webui/ntp/new_tab_page_handler.cc +++ b/chrome/browser/ui/webui/ntp/new_tab_page_handler.cc
@@ -175,7 +175,6 @@ base::DictionaryValue* values) { values->SetInteger("most_visited_page_id", MOST_VISITED_PAGE_ID); values->SetInteger("apps_page_id", APPS_PAGE_ID); - values->SetInteger("suggestions_page_id", SUGGESTIONS_PAGE_ID); PrefService* prefs = profile->GetPrefs(); int shown_page = prefs->GetInteger(prefs::kNtpShownPage);
diff --git a/chrome/browser/ui/webui/ntp/new_tab_page_handler.h b/chrome/browser/ui/webui/ntp/new_tab_page_handler.h index 7e4e99b..d822354 100644 --- a/chrome/browser/ui/webui/ntp/new_tab_page_handler.h +++ b/chrome/browser/ui/webui/ntp/new_tab_page_handler.h
@@ -73,9 +73,7 @@ INDEX_MASK = (1 << kPageIdOffset) - 1, MOST_VISITED_PAGE_ID = 1 << kPageIdOffset, APPS_PAGE_ID = 2 << kPageIdOffset, - BOOKMARKS_PAGE_ID = 3 << kPageIdOffset, - SUGGESTIONS_PAGE_ID = 4 << kPageIdOffset, - LAST_PAGE_ID = SUGGESTIONS_PAGE_ID + LAST_PAGE_ID = APPS_PAGE_ID, }; static const int kHistogramEnumerationMax = (LAST_PAGE_ID >> kPageIdOffset) + 1;
diff --git a/chrome/browser/ui/webui/ntp/new_tab_ui.cc b/chrome/browser/ui/webui/ntp/new_tab_ui.cc index e91fe6b..d43f22f 100644 --- a/chrome/browser/ui/webui/ntp/new_tab_ui.cc +++ b/chrome/browser/ui/webui/ntp/new_tab_ui.cc
@@ -26,7 +26,6 @@ #include "chrome/browser/ui/webui/ntp/ntp_resource_cache.h" #include "chrome/browser/ui/webui/ntp/ntp_resource_cache_factory.h" #include "chrome/browser/ui/webui/ntp/ntp_user_data_logger.h" -#include "chrome/browser/ui/webui/ntp/suggestions_page_handler.h" #include "chrome/common/pref_names.h" #include "chrome/common/url_constants.h" #include "chrome/grit/generated_resources.h" @@ -99,8 +98,6 @@ web_ui->AddMessageHandler(new FaviconWebUIHandler()); web_ui->AddMessageHandler(new NewTabPageHandler()); web_ui->AddMessageHandler(new CoreAppLauncherHandler()); - if (NewTabUI::IsDiscoveryInNTPEnabled()) - web_ui->AddMessageHandler(new SuggestionsHandler()); web_ui->AddMessageHandler(new NewTabPageSyncHandler()); ExtensionService* service = @@ -124,13 +121,6 @@ scoped_ptr<NewTabHTMLSource> html_source( new NewTabHTMLSource(profile->GetOriginalProfile())); - // These two resources should be loaded only if suggestions NTP is enabled. - html_source->AddResource("suggestions_page.css", "text/css", - NewTabUI::IsDiscoveryInNTPEnabled() ? IDR_SUGGESTIONS_PAGE_CSS : 0); - if (NewTabUI::IsDiscoveryInNTPEnabled()) { - html_source->AddResource("suggestions_page.js", "application/javascript", - IDR_SUGGESTIONS_PAGE_JS); - } // content::URLDataSource assumes the ownership of the html_source. content::URLDataSource::Add(profile, html_source.release()); @@ -224,8 +214,6 @@ user_prefs::PrefRegistrySyncable* registry) { CoreAppLauncherHandler::RegisterProfilePrefs(registry); NewTabPageHandler::RegisterProfilePrefs(registry); - if (NewTabUI::IsDiscoveryInNTPEnabled()) - SuggestionsHandler::RegisterProfilePrefs(registry); MostVisitedHandler::RegisterProfilePrefs(registry); browser_sync::ForeignSessionHandler::RegisterProfilePrefs(registry); } @@ -241,13 +229,6 @@ } // static -bool NewTabUI::IsDiscoveryInNTPEnabled() { - // TODO(beaudoin): The flag was removed during a clean-up pass. We leave that - // here to easily enable it back when we will explore this option again. - return false; -} - -// static void NewTabUI::SetUrlTitleAndDirection(base::DictionaryValue* dictionary, const base::string16& title, const GURL& gurl) {
diff --git a/chrome/browser/ui/webui/ntp/new_tab_ui.h b/chrome/browser/ui/webui/ntp/new_tab_ui.h index 4fdee9fe..a6eae7a 100644 --- a/chrome/browser/ui/webui/ntp/new_tab_ui.h +++ b/chrome/browser/ui/webui/ntp/new_tab_ui.h
@@ -42,9 +42,6 @@ // Returns whether or not to show apps pages. static bool ShouldShowApps(); - // Returns whether or not "Discovery" in the NTP is Enabled. - static bool IsDiscoveryInNTPEnabled(); - // Adds "url", "title", and "direction" keys on incoming dictionary, setting // title as the url as a fallback on empty title. static void SetUrlTitleAndDirection(base::DictionaryValue* dictionary,
diff --git a/chrome/browser/ui/webui/ntp/ntp_resource_cache.cc b/chrome/browser/ui/webui/ntp/ntp_resource_cache.cc index 22cfbe9..73f49e1 100644 --- a/chrome/browser/ui/webui/ntp/ntp_resource_cache.cc +++ b/chrome/browser/ui/webui/ntp/ntp_resource_cache.cc
@@ -421,8 +421,6 @@ l10n_util::GetStringUTF16(IDS_NEW_TAB_TITLE)); load_time_data.SetString("mostvisited", l10n_util::GetStringUTF16(IDS_NEW_TAB_MOST_VISITED)); - load_time_data.SetString("suggestions", - l10n_util::GetStringUTF16(IDS_NEW_TAB_SUGGESTIONS)); load_time_data.SetString("restoreThumbnailsShort", l10n_util::GetStringUTF16(IDS_NEW_TAB_RESTORE_THUMBNAILS_SHORT_LINK)); load_time_data.SetString("webStoreTitle", @@ -477,8 +475,6 @@ GURL(extension_urls::GetWebstoreLaunchURL()), app_locale).spec()); load_time_data.SetString("appInstallHintText", l10n_util::GetStringUTF16(IDS_NEW_TAB_APP_INSTALL_HINT_LABEL)); - load_time_data.SetBoolean("isDiscoveryInNTPEnabled", - NewTabUI::IsDiscoveryInNTPEnabled()); load_time_data.SetString("collapseSessionMenuItemText", l10n_util::GetStringUTF16(IDS_NEW_TAB_OTHER_SESSIONS_COLLAPSE_SESSION)); load_time_data.SetString("expandSessionMenuItemText",
diff --git a/chrome/browser/ui/webui/ntp/suggestions_combiner.cc b/chrome/browser/ui/webui/ntp/suggestions_combiner.cc deleted file mode 100644 index bf99814..0000000 --- a/chrome/browser/ui/webui/ntp/suggestions_combiner.cc +++ /dev/null
@@ -1,152 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/ui/webui/ntp/suggestions_combiner.h" - -#include <algorithm> - -#include "base/values.h" -#include "chrome/browser/profiles/profile.h" -#include "chrome/browser/ui/browser.h" -#include "chrome/browser/ui/browser_iterator.h" -#include "chrome/browser/ui/tabs/tab_strip_model.h" -#include "chrome/browser/ui/webui/ntp/suggestions_page_handler.h" -#include "chrome/browser/ui/webui/ntp/suggestions_source.h" -#include "content/public/browser/web_contents.h" - -namespace { - -static const size_t kSuggestionsCount = 8; - -} // namespace - -SuggestionsCombiner::SuggestionsCombiner( - SuggestionsCombiner::Delegate* delegate, - Profile* profile) - : sources_fetching_count_(0), - delegate_(delegate), - suggestions_count_(kSuggestionsCount), - page_values_(new base::ListValue()), - debug_enabled_(false), - profile_(profile) { -} - -SuggestionsCombiner::~SuggestionsCombiner() { -} - -void SuggestionsCombiner::AddSource(SuggestionsSource* source) { - source->SetCombiner(this); - source->SetDebug(debug_enabled_); - sources_.push_back(source); -} - -void SuggestionsCombiner::EnableDebug(bool enable) { - debug_enabled_ = enable; - for (size_t i = 0; i < sources_.size(); ++i) { - sources_[i]->SetDebug(enable); - } -} - -void SuggestionsCombiner::FetchItems(Profile* profile) { - sources_fetching_count_ = sources_.size(); - for (size_t i = 0; i < sources_.size(); ++i) { - sources_[i]->FetchItems(profile); - } -} - -base::ListValue* SuggestionsCombiner::GetPageValues() { - return page_values_.get(); -} - -void SuggestionsCombiner::OnItemsReady() { - DCHECK_GT(sources_fetching_count_, 0); - sources_fetching_count_--; - if (sources_fetching_count_ == 0) { - FillPageValues(); - delegate_->OnSuggestionsReady(); - } -} - -void SuggestionsCombiner::SetSuggestionsCount(size_t suggestions_count) { - suggestions_count_ = suggestions_count; -} - -void SuggestionsCombiner::FillPageValues() { - int total_weight = 0; - for (size_t i = 0; i < sources_.size(); ++i) - total_weight += sources_[i]->GetWeight(); - DCHECK_GT(total_weight, 0); - - page_values_.reset(new base::ListValue()); - - // Evaluate how many items to obtain from each source. We use error diffusion - // to ensure that we get the total desired number of items. - int error = 0; - - // Holds the index at which the next item should be added for each source. - std::vector<size_t> next_item_index_for_source; - next_item_index_for_source.reserve(sources_.size()); - for (size_t i = 0; i < sources_.size(); ++i) { - int numerator = sources_[i]->GetWeight() * suggestions_count_ + error; - error = numerator % total_weight; - int item_count = std::min(numerator / total_weight, - sources_[i]->GetItemCount()); - - for (int j = 0; j < item_count; ++j) - page_values_->Append(sources_[i]->PopItem()); - next_item_index_for_source.push_back(page_values_->GetSize()); - } - - // Fill in extra items, prioritizing the first source. - // Rather than updating |next_item_index_for_source| we keep track of the - // number of extra items that were added and offset indices by that much. - size_t extra_items_added = 0; - for (size_t i = 0; i < sources_.size() && - page_values_->GetSize() < suggestions_count_; ++i) { - - size_t index = next_item_index_for_source[i] + extra_items_added; - while (page_values_->GetSize() < suggestions_count_) { - base::DictionaryValue* item = sources_[i]->PopItem(); - if (!item) - break; - page_values_->Insert(index++, item); - extra_items_added++; - } - } - - // Add page value information common to all sources. - for (size_t i = 0; i < page_values_->GetSize(); i++) { - base::DictionaryValue* page_value; - if (page_values_->GetDictionary(i, &page_value)) - AddExtendedInformation(page_value); - } -} - -void SuggestionsCombiner::AddExtendedInformation( - base::DictionaryValue* page_value) { - if (debug_enabled_) { - std::string url_string; - if (page_value->GetString("url", &url_string)) { - GURL url(url_string); - page_value->SetBoolean("already_open", IsUrlAlreadyOpen(url)); - } - } -} - -bool SuggestionsCombiner::IsUrlAlreadyOpen(const GURL &url) { - for (chrome::BrowserIterator it; !it.done(); it.Next()) { - const Browser* browser = *it; - if (browser->profile()->IsOffTheRecord() || - !browser->profile()->IsSameProfile(profile_)) - continue; - - for (int i = 0; i < browser->tab_strip_model()->count(); i++) { - const content::WebContents* tab = - browser->tab_strip_model()->GetWebContentsAt(i); - if (tab->GetURL() == url) - return true; - } - } - return false; -}
diff --git a/chrome/browser/ui/webui/ntp/suggestions_combiner.h b/chrome/browser/ui/webui/ntp/suggestions_combiner.h deleted file mode 100644 index ca5041a0..0000000 --- a/chrome/browser/ui/webui/ntp/suggestions_combiner.h +++ /dev/null
@@ -1,108 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_UI_WEBUI_NTP_SUGGESTIONS_COMBINER_H_ -#define CHROME_BROWSER_UI_WEBUI_NTP_SUGGESTIONS_COMBINER_H_ - -#include <vector> - -#include "base/basictypes.h" -#include "base/memory/scoped_ptr.h" -#include "base/memory/scoped_vector.h" - -class GURL; -class SuggestionsHandler; -class SuggestionsSource; -class Profile; - -namespace base { -class DictionaryValue; -class ListValue; -} - -// Combines many different sources of suggestions and generates data from it. -class SuggestionsCombiner { - public: - // Interface to be implemented by classes that will be notified of events from - // the SuggestionsCombiner. - class Delegate { - public: - virtual ~Delegate() {} - - // Method that is called when new suggestions are ready from the - // SuggestionsCombiner. - virtual void OnSuggestionsReady() = 0; - }; - - virtual ~SuggestionsCombiner(); - - explicit SuggestionsCombiner(SuggestionsCombiner::Delegate* delegate, - Profile* profile); - - // Add a new source. The SuggestionsCombiner takes ownership of |source|. - void AddSource(SuggestionsSource* source); - - // Enables or disables debug mode. If debug mode is enabled, the sources are - // expected to provide additional data, which could be displayed, for example, - // in the chrome://suggestions-internals/ page. - void EnableDebug(bool enable); - - // Fetch a new set of items from the various suggestion sources. - void FetchItems(Profile* profile); - - base::ListValue* GetPageValues(); - - // Called by a source when its items are ready. Make sure suggestion sources - // call this method exactly once for each call to - // SuggestionsSource::FetchItems. - void OnItemsReady(); - - void SetSuggestionsCount(size_t suggestions_count); - - private: - friend class SuggestionsCombinerTest; - - // Fill the page values from the suggestion sources so they can be sent to - // the JavaScript side. This should only be called when all the suggestion - // sources have items ready. - void FillPageValues(); - - // Add extra information to page values that should be common across all - // suggestion sources. - void AddExtendedInformation(base::DictionaryValue* page_value); - - // Checks if a URL is already open for the current profile. URLs open in an - // incognito window are not reported. - bool IsUrlAlreadyOpen(const GURL& url); - - typedef ScopedVector<SuggestionsSource> SuggestionsSources; - - // List of all the suggestions sources that will be combined to generate a - // single list of suggestions. - SuggestionsSources sources_; - - // Counter tracking the number of sources that are currently asynchronously - // fetching their data. - int sources_fetching_count_; - - // The delegate to notify once items are ready. - SuggestionsCombiner::Delegate* delegate_; - - // Number of suggestions to generate. Used to distribute the suggestions - // between the various sources. - size_t suggestions_count_; - - // Informations to send to the javascript side. - scoped_ptr<base::ListValue> page_values_; - - // Whether debug mode is enabled or not (debug mode provides more data in the - // results). - bool debug_enabled_; - - Profile* profile_; - - DISALLOW_COPY_AND_ASSIGN(SuggestionsCombiner); -}; - -#endif // CHROME_BROWSER_UI_WEBUI_NTP_SUGGESTIONS_COMBINER_H_
diff --git a/chrome/browser/ui/webui/ntp/suggestions_combiner_unittest.cc b/chrome/browser/ui/webui/ntp/suggestions_combiner_unittest.cc deleted file mode 100644 index d6bc880..0000000 --- a/chrome/browser/ui/webui/ntp/suggestions_combiner_unittest.cc +++ /dev/null
@@ -1,298 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// TODO(beaudoin): What is really needed here? - -#include <deque> -#include <string> - -#include "base/memory/scoped_ptr.h" -#include "base/stl_util.h" -#include "base/strings/string_util.h" -#include "base/values.h" -#include "chrome/browser/ui/webui/ntp/suggestions_combiner.h" -#include "chrome/browser/ui/webui/ntp/suggestions_page_handler.h" -#include "chrome/browser/ui/webui/ntp/suggestions_source.h" -#include "chrome/test/base/testing_profile.h" -#include "content/public/test/test_browser_thread_bundle.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace { - -struct SourceInfo { - int weight; - const char* source_name; - int number_of_suggestions; -}; - -struct TestDescription { - SourceInfo sources[3]; - const char* results[8]; -} test_suite[] = { - // One source, more than 8 items. - { - {{1, "A", 10}}, - {"A 0", "A 1", "A 2", "A 3", "A 4", "A 5", "A 6", "A 7"} - }, - // One source, exactly 8 items. - { - {{1, "A", 8}}, - {"A 0", "A 1", "A 2", "A 3", "A 4", "A 5", "A 6", "A 7"} - }, - // One source, not enough items. - { - {{1, "A", 3}}, - {"A 0", "A 1", "A 2"} - }, - // One source, no items. - { - {{1, "A", 0}}, - {} - }, - // Two sources, equal weight, more than 8 items. - { - {{1, "A", 10}, {1, "B", 10}}, - {"A 0", "A 1", "A 2", "A 3", "B 0", "B 1", "B 2", "B 3"} - }, - // Two sources, equal weight, exactly 8 items. - { - {{1, "A", 4}, {1, "B", 4}}, - {"A 0", "A 1", "A 2", "A 3", "B 0", "B 1", "B 2", "B 3"} - }, - // Two sources, equal weight, exactly 8 items but source A has more. - { - {{1, "A", 5}, {1, "B", 3}}, - {"A 0", "A 1", "A 2", "A 3", "A 4", "B 0", "B 1", "B 2"} - }, - // Two sources, equal weight, exactly 8 items but source B has more. - { - {{1, "A", 2}, {1, "B", 6}}, - {"A 0", "A 1", "B 0", "B 1", "B 2", "B 3", "B 4", "B 5"} - }, - // Two sources, equal weight, exactly 8 items but source A has none. - { - {{1, "A", 0}, {1, "B", 8}}, - {"B 0", "B 1", "B 2", "B 3", "B 4", "B 5", "B 6", "B 7"} - }, - // Two sources, equal weight, exactly 8 items but source B has none. - { - {{1, "A", 8}, {1, "B", 0}}, - {"A 0", "A 1", "A 2", "A 3", "A 4", "A 5", "A 6", "A 7"} - }, - // Two sources, equal weight, less than 8 items. - { - {{1, "A", 3}, {1, "B", 3}}, - {"A 0", "A 1", "A 2", "B 0", "B 1", "B 2"} - }, - // Two sources, equal weight, less than 8 items but source A has more. - { - {{1, "A", 4}, {1, "B", 3}}, - {"A 0", "A 1", "A 2", "A 3", "B 0", "B 1", "B 2"} - }, - // Two sources, equal weight, less than 8 items but source B has more. - { - {{1, "A", 1}, {1, "B", 3}}, - {"A 0", "B 0", "B 1", "B 2"} - }, - // Two sources, weights 3/4 A 1/4 B, more than 8 items. - { - {{3, "A", 10}, {1, "B", 10}}, - {"A 0", "A 1", "A 2", "A 3", "A 4", "A 5", "B 0", "B 1"} - }, - // Two sources, weights 1/8 A 7/8 B, more than 8 items. - { - {{1, "A", 10}, {7, "B", 10}}, - {"A 0", "B 0", "B 1", "B 2", "B 3", "B 4", "B 5", "B 6"} - }, - // Two sources, weights 1/3 A 2/3 B, more than 8 items. - { - {{1, "A", 10}, {2, "B", 10}}, - {"A 0", "A 1", "B 0", "B 1", "B 2", "B 3", "B 4", "B 5"} - }, - // Three sources, weights 1/2 A 1/4 B 1/4 C, more than 8 items. - { - {{2, "A", 10}, {1, "B", 10}, {1, "C", 10}}, - {"A 0", "A 1", "A 2", "A 3", "B 0", "B 1", "C 0", "C 1"} - }, - // Three sources, weights 1/3 A 1/3 B 1/3 C, more than 8 items. - { - {{1, "A", 10}, {1, "B", 10}, {1, "C", 10}}, - {"A 0", "A 1", "B 0", "B 1", "B 2", "C 0", "C 1", "C 2"} - }, - // Extra items should be grouped together. - { - {{1, "A", 3}, {1, "B", 4}, {10, "C", 1}}, - {"A 0", "A 1", "A 2", "B 0", "B 1", "B 2", "B 3", "C 0"} - } -}; - -} // namespace - -// Stub for a SuggestionsSource that can provide a number of fake suggestions. -// Fake suggestions are DictionaryValue with a single "title" string field -// containing the |source_name| followed by the index of the suggestion. -// Not in the empty namespace since it's a friend of SuggestionsCombiner. -class SuggestionsSourceStub : public SuggestionsSource { - public: - explicit SuggestionsSourceStub(int weight, - const std::string& source_name, int number_of_suggestions) - : combiner_(NULL), - weight_(weight), - source_name_(source_name), - number_of_suggestions_(number_of_suggestions), - debug_(false) { - } - ~SuggestionsSourceStub() override { STLDeleteElements(&items_); } - - // Call this method to simulate that the SuggestionsSource has received all - // its suggestions. - void Done() { - combiner_->OnItemsReady(); - } - - private: - // SuggestionsSource Override and implementation. - void SetDebug(bool enable) override { debug_ = enable; } - int GetWeight() override { return weight_; } - int GetItemCount() override { return items_.size(); } - base::DictionaryValue* PopItem() override { - if (items_.empty()) - return NULL; - base::DictionaryValue* item = items_.front(); - items_.pop_front(); - return item; - } - - void FetchItems(Profile* profile) override { - char num_str[21]; // Enough to hold all numbers up to 64-bits. - for (int i = 0; i < number_of_suggestions_; ++i) { - base::snprintf(num_str, sizeof(num_str), "%d", i); - AddSuggestion(source_name_ + ' ' + num_str); - } - } - - // Adds a fake suggestion. This suggestion is a DictionaryValue with a single - // "title" field containing |title|. - void AddSuggestion(const std::string& title) { - base::DictionaryValue* item = new base::DictionaryValue(); - item->SetString("title", title); - items_.push_back(item); - } - - void SetCombiner(SuggestionsCombiner* combiner) override { - DCHECK(!combiner_); - combiner_ = combiner; - } - - // Our combiner. - SuggestionsCombiner* combiner_; - - int weight_; - std::string source_name_; - int number_of_suggestions_; - bool debug_; - - // Keep the results of the db query here. - std::deque<base::DictionaryValue*> items_; - - DISALLOW_COPY_AND_ASSIGN(SuggestionsSourceStub); -}; - -class SuggestionsCombinerTest : public testing::Test { - public: - SuggestionsCombinerTest() { - } - - protected: - content::TestBrowserThreadBundle thread_bundle_; - Profile* profile_; - SuggestionsHandler* suggestions_handler_; - SuggestionsCombiner* combiner_; - - void Reset() { - delete combiner_; - combiner_ = new SuggestionsCombiner(suggestions_handler_, profile_); - } - - private: - void SetUp() override { - profile_ = new TestingProfile(); - suggestions_handler_ = new SuggestionsHandler(); - combiner_ = new SuggestionsCombiner(suggestions_handler_, profile_); - } - - void TearDown() override { - delete combiner_; - delete suggestions_handler_; - delete profile_; - } - - DISALLOW_COPY_AND_ASSIGN(SuggestionsCombinerTest); -}; - -TEST_F(SuggestionsCombinerTest, NoSource) { - combiner_->FetchItems(NULL); - EXPECT_EQ(0UL, combiner_->GetPageValues()->GetSize()); -} - -TEST_F(SuggestionsCombinerTest, SourcesAreNotDoneFetching) { - combiner_->AddSource(new SuggestionsSourceStub(1, "sourceA", 10)); - combiner_->AddSource(new SuggestionsSourceStub(1, "sourceB", 10)); - combiner_->FetchItems(NULL); - EXPECT_EQ(0UL, combiner_->GetPageValues()->GetSize()); -} - -TEST_F(SuggestionsCombinerTest, TestSuite) { - size_t test_count = arraysize(test_suite); - for (size_t i = 0; i < test_count; ++i) { - const TestDescription& description = test_suite[i]; - size_t source_count = arraysize(description.sources); - - scoped_ptr<SuggestionsSourceStub*[]> sources( - new SuggestionsSourceStub*[source_count]); - - // Setup sources. - for (size_t j = 0; j < source_count; ++j) { - const SourceInfo& source_info = description.sources[j]; - // A NULL |source_name| means we shouldn't add this source. - if (source_info.source_name) { - sources[j] = new SuggestionsSourceStub(source_info.weight, - source_info.source_name, source_info.number_of_suggestions); - combiner_->AddSource(sources[j]); - } else { - sources[j] = NULL; - } - } - - // Start fetching. - combiner_->FetchItems(NULL); - - // Sources complete. - for (size_t j = 0; j < source_count; ++j) { - if (sources[j]) - sources[j]->Done(); - } - - // Verify expectations. - base::ListValue* results = combiner_->GetPageValues(); - size_t result_count = results->GetSize(); - EXPECT_LE(result_count, 8UL); - for (size_t j = 0; j < 8; ++j) { - if (j < result_count) { - std::string value; - base::DictionaryValue* dictionary; - results->GetDictionary(j, &dictionary); - dictionary->GetString("title", &value); - EXPECT_STREQ(description.results[j], value.c_str()) << - " test index:" << i; - } else { - EXPECT_EQ(description.results[j], static_cast<const char*>(NULL)) << - " test index:" << i; - } - } - - Reset(); - } -} -
diff --git a/chrome/browser/ui/webui/ntp/suggestions_page_handler.cc b/chrome/browser/ui/webui/ntp/suggestions_page_handler.cc deleted file mode 100644 index d8b97451..0000000 --- a/chrome/browser/ui/webui/ntp/suggestions_page_handler.cc +++ /dev/null
@@ -1,198 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/ui/webui/ntp/suggestions_page_handler.h" - -#include <math.h> -#include <vector> - -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/md5.h" -#include "base/metrics/histogram.h" -#include "base/strings/string16.h" -#include "base/strings/utf_string_conversions.h" -#include "base/threading/thread.h" -#include "base/values.h" -#include "chrome/browser/history/top_sites_factory.h" -#include "chrome/browser/profiles/profile.h" -#include "chrome/browser/ui/webui/favicon_source.h" -#include "chrome/browser/ui/webui/ntp/ntp_stats.h" -#include "chrome/browser/ui/webui/ntp/suggestions_combiner.h" -#include "chrome/browser/ui/webui/ntp/suggestions_source_top_sites.h" -#include "chrome/browser/ui/webui/ntp/thumbnail_source.h" -#include "chrome/common/url_constants.h" -#include "components/history/core/browser/page_usage_data.h" -#include "components/history/core/browser/top_sites.h" -#include "components/pref_registry/pref_registry_syncable.h" -#include "content/public/browser/navigation_controller.h" -#include "content/public/browser/navigation_entry.h" -#include "content/public/browser/url_data_source.h" -#include "content/public/browser/user_metrics.h" -#include "content/public/browser/web_contents.h" -#include "content/public/browser/web_ui.h" -#include "ui/base/page_transition_types.h" -#include "url/gurl.h" - -using base::UserMetricsAction; - -SuggestionsHandler::SuggestionsHandler() - : scoped_observer_(this), - got_first_suggestions_request_(false), - suggestions_viewed_(false), - user_action_logged_(false) { -} - -SuggestionsHandler::~SuggestionsHandler() { - if (!user_action_logged_ && suggestions_viewed_) { - const GURL ntp_url = GURL(chrome::kChromeUINewTabURL); - int action_id = NTP_FOLLOW_ACTION_OTHER; - content::NavigationEntry* entry = - web_ui()->GetWebContents()->GetController().GetLastCommittedEntry(); - if (entry && (entry->GetURL() != ntp_url)) { - action_id = - ui::PageTransitionStripQualifier(entry->GetTransitionType()); - } - - UMA_HISTOGRAM_ENUMERATION("NewTabPage.SuggestedSitesAction", action_id, - NUM_NTP_FOLLOW_ACTIONS); - } -} - -void SuggestionsHandler::RegisterMessages() { - Profile* profile = Profile::FromWebUI(web_ui()); - // Set up our sources for thumbnail and favicon data. - content::URLDataSource::Add(profile, new ThumbnailSource(profile, false)); - content::URLDataSource::Add( - profile, new FaviconSource(profile, FaviconSource::FAVICON)); - - // TODO(georgey) change the source of the web-sites to provide our data. - // Initial commit uses top sites as a data source. - scoped_refptr<history::TopSites> top_sites = - TopSitesFactory::GetForProfile(profile); - if (top_sites) { - // TopSites updates itself after a delay. This is especially noticable when - // your profile is empty. Ask TopSites to update itself when we're about to - // show the new tab page. - top_sites->SyncWithHistory(); - - // Register as TopSitesObserver so that we can update ourselves when the - // TopSites changes. - scoped_observer_.Add(top_sites.get()); - } - - // Setup the suggestions sources. - SuggestionsCombiner* combiner = new SuggestionsCombiner(this, profile); - combiner->AddSource(new SuggestionsSourceTopSites()); - suggestions_combiner_.reset(combiner); - - // We pre-emptively make a fetch for suggestions so we have the results - // sooner. - suggestions_combiner_->FetchItems(profile); - - web_ui()->RegisterMessageCallback("getSuggestions", - base::Bind(&SuggestionsHandler::HandleGetSuggestions, - base::Unretained(this))); - // Register ourselves for any suggestions item blacklisting. - web_ui()->RegisterMessageCallback("blacklistURLFromSuggestions", - base::Bind(&SuggestionsHandler::HandleBlacklistURL, - base::Unretained(this))); - web_ui()->RegisterMessageCallback("removeURLsFromSuggestionsBlacklist", - base::Bind(&SuggestionsHandler::HandleRemoveURLsFromBlacklist, - base::Unretained(this))); - web_ui()->RegisterMessageCallback("clearSuggestionsURLsBlacklist", - base::Bind(&SuggestionsHandler::HandleClearBlacklist, - base::Unretained(this))); - web_ui()->RegisterMessageCallback("suggestedSitesAction", - base::Bind(&SuggestionsHandler::HandleSuggestedSitesAction, - base::Unretained(this))); - web_ui()->RegisterMessageCallback("suggestedSitesSelected", - base::Bind(&SuggestionsHandler::HandleSuggestedSitesSelected, - base::Unretained(this))); -} - -void SuggestionsHandler::HandleGetSuggestions(const base::ListValue* args) { - if (!got_first_suggestions_request_) { - // If it's the first request we get, return the prefetched data. - SendPagesValue(); - got_first_suggestions_request_ = true; - } else { - suggestions_combiner_->FetchItems(Profile::FromWebUI(web_ui())); - } -} - -void SuggestionsHandler::OnSuggestionsReady() { - // If we got the results as a result of a suggestions request initiated by the - // JavaScript then we send back the page values. - if (got_first_suggestions_request_) - SendPagesValue(); -} - -void SuggestionsHandler::SendPagesValue() { - if (suggestions_combiner_->GetPageValues()) { - // TODO(georgey) add actual blacklist. - bool has_blacklisted_urls = false; - base::FundamentalValue has_blacklisted_urls_value(has_blacklisted_urls); - web_ui()->CallJavascriptFunction("ntp.setSuggestionsPages", - *suggestions_combiner_->GetPageValues(), - has_blacklisted_urls_value); - } -} - -void SuggestionsHandler::HandleBlacklistURL(const base::ListValue* args) { - std::string url = base::UTF16ToUTF8(ExtractStringValue(args)); - BlacklistURL(GURL(url)); -} - -void SuggestionsHandler::HandleRemoveURLsFromBlacklist( - const base::ListValue* args) { - DCHECK_GT(args->GetSize(), 0U); - // TODO(georgey) remove URLs from blacklist. -} - -void SuggestionsHandler::HandleClearBlacklist(const base::ListValue* args) { - // TODO(georgey) clear blacklist. -} - -void SuggestionsHandler::HandleSuggestedSitesAction( - const base::ListValue* args) { - DCHECK(args); - - double action_id; - if (!args->GetDouble(0, &action_id)) - NOTREACHED(); - - UMA_HISTOGRAM_ENUMERATION("NewTabPage.SuggestedSitesAction", - static_cast<int>(action_id), - NUM_NTP_FOLLOW_ACTIONS); - suggestions_viewed_ = true; - user_action_logged_ = true; -} - -void SuggestionsHandler::HandleSuggestedSitesSelected( - const base::ListValue* args) { - suggestions_viewed_ = true; -} - -void SuggestionsHandler::TopSitesLoaded(history::TopSites* top_sites) { -} - -void SuggestionsHandler::TopSitesChanged(history::TopSites* top_sites) { - // Suggestions urls changed, query again. - suggestions_combiner_->FetchItems(Profile::FromWebUI(web_ui())); -} - -void SuggestionsHandler::BlacklistURL(const GURL& url) { - // TODO(georgey) blacklist an URL. -} - -std::string SuggestionsHandler::GetDictionaryKeyForURL(const std::string& url) { - return base::MD5String(url); -} - -// static -void SuggestionsHandler::RegisterProfilePrefs( - user_prefs::PrefRegistrySyncable* registry) { - // TODO(georgey) add user preferences (such as own blacklist) as needed. -}
diff --git a/chrome/browser/ui/webui/ntp/suggestions_page_handler.h b/chrome/browser/ui/webui/ntp/suggestions_page_handler.h deleted file mode 100644 index de7712fc..0000000 --- a/chrome/browser/ui/webui/ntp/suggestions_page_handler.h +++ /dev/null
@@ -1,99 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_UI_WEBUI_NTP_SUGGESTIONS_PAGE_HANDLER_H_ -#define CHROME_BROWSER_UI_WEBUI_NTP_SUGGESTIONS_PAGE_HANDLER_H_ - -#include <string> - -#include "base/scoped_observer.h" -#include "chrome/browser/ui/webui/ntp/suggestions_combiner.h" -#include "components/history/core/browser/history_types.h" -#include "components/history/core/browser/top_sites_observer.h" -#include "content/public/browser/web_ui_message_handler.h" - -class GURL; - -namespace base { -class ListValue; -class Value; -} - -namespace user_prefs { -class PrefRegistrySyncable; -} - -// The handler for Javascript messages related to the "suggestions" view. -// -// This class manages one preference: -// - The URL blacklist: URLs we do not want to show in the thumbnails list. It -// is a dictionary for quick access (it associates a dummy boolean to the URL -// string). -class SuggestionsHandler : public content::WebUIMessageHandler, - public SuggestionsCombiner::Delegate, - public history::TopSitesObserver { - public: - SuggestionsHandler(); - ~SuggestionsHandler() override; - - // WebUIMessageHandler override and implementation. - void RegisterMessages() override; - - // Callback for the "getSuggestions" message. - void HandleGetSuggestions(const base::ListValue* args); - - // Callback for the "blacklistURLFromSuggestions" message. - void HandleBlacklistURL(const base::ListValue* args); - - // Callback for the "removeURLsFromSuggestionsBlacklist" message. - void HandleRemoveURLsFromBlacklist(const base::ListValue* args); - - // Callback for the "clearSuggestionsURLsBlacklist" message. - void HandleClearBlacklist(const base::ListValue* args); - - // Callback for the "suggestedSitesAction" message. - void HandleSuggestedSitesAction(const base::ListValue* args); - - // Callback for the "suggestedSitesSelected" message. - void HandleSuggestedSitesSelected(const base::ListValue* args); - - // history::TopSitesObserver implementation. - void TopSitesLoaded(history::TopSites* top_sites) override; - void TopSitesChanged(history::TopSites* top_sites) override; - - // SuggestionsCombiner::Delegate implementation. - void OnSuggestionsReady() override; - - static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry); - - private: - // Puts the passed URL in the blacklist (so it does not show as a thumbnail). - void BlacklistURL(const GURL& url); - - // Returns the key used in url_blacklist_ for the passed |url|. - std::string GetDictionaryKeyForURL(const std::string& url); - - // Sends pages_value_ to the javascript side to and resets page_value_. - void SendPagesValue(); - - // Scoped observer to help with TopSitesObserver registration. - ScopedObserver<history::TopSites, history::TopSitesObserver> scoped_observer_; - - // We pre-fetch the first set of result pages. This variable is false until - // we get the first getSuggestions() call. - bool got_first_suggestions_request_; - - // Used to combine suggestions from various sources. - scoped_ptr<SuggestionsCombiner> suggestions_combiner_; - - // Whether the user has viewed the 'suggested' pane. - bool suggestions_viewed_; - - // Whether the user has performed a "tracked" action to leave the page or not. - bool user_action_logged_; - - DISALLOW_COPY_AND_ASSIGN(SuggestionsHandler); -}; - -#endif // CHROME_BROWSER_UI_WEBUI_NTP_SUGGESTIONS_PAGE_HANDLER_H_
diff --git a/chrome/browser/ui/webui/ntp/suggestions_source.h b/chrome/browser/ui/webui/ntp/suggestions_source.h deleted file mode 100644 index fd174d50..0000000 --- a/chrome/browser/ui/webui/ntp/suggestions_source.h +++ /dev/null
@@ -1,60 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_UI_WEBUI_NTP_SUGGESTIONS_SOURCE_H_ -#define CHROME_BROWSER_UI_WEBUI_NTP_SUGGESTIONS_SOURCE_H_ - -#include "base/basictypes.h" - -class Profile; -class SuggestionsCombiner; - -namespace base { -class DictionaryValue; -} - -// Interface for a source of suggested pages. The various sources will be -// combined by the SuggestionsCombiner. -class SuggestionsSource { - - public: - virtual ~SuggestionsSource() {} - - protected: - SuggestionsSource() {} - - friend class SuggestionsCombiner; - - // Enables or disables debug mode for the current source. The source is - // expected to provide additional data when debug mode is enabled. - virtual void SetDebug(bool enable) = 0; - - // The source's weight indicates how many items from this source will be - // selected by the combiner. If a source weight is x and the total weight of - // all the sources is y, then the combiner will select x/y items from it. - virtual int GetWeight() = 0; - - // Returns the number of items this source can produce. - virtual int GetItemCount() = 0; - - // Removes the most important item from this source and returns it. The - // returned item must be in the right format to be sent to the javascript, - // which you typically get by calling NewTabUI::SetUrlTitleAndDirection. If - // the source is empty this method returns null. - // The caller takes ownership of the returned item. - virtual base::DictionaryValue* PopItem() = 0; - - // Requests that the source fetch its items. If the source is already fetching - // it does not have to reset and can continue fetching. - virtual void FetchItems(Profile* profile) = 0; - - // Sets the combiner holding this suggestion source. This method can only - // be called once. - virtual void SetCombiner(SuggestionsCombiner* combiner) = 0; - - private: - DISALLOW_COPY_AND_ASSIGN(SuggestionsSource); -}; - -#endif // CHROME_BROWSER_UI_WEBUI_NTP_SUGGESTIONS_SOURCE_H_
diff --git a/chrome/browser/ui/webui/ntp/suggestions_source_top_sites.cc b/chrome/browser/ui/webui/ntp/suggestions_source_top_sites.cc deleted file mode 100644 index cdac4b5..0000000 --- a/chrome/browser/ui/webui/ntp/suggestions_source_top_sites.cc +++ /dev/null
@@ -1,139 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/ui/webui/ntp/suggestions_source_top_sites.h" - -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/command_line.h" -#include "base/stl_util.h" -#include "base/strings/string_number_conversions.h" -#include "base/values.h" -#include "chrome/browser/history/history_service_factory.h" -#include "chrome/browser/profiles/profile.h" -#include "chrome/browser/ui/webui/ntp/new_tab_ui.h" -#include "chrome/browser/ui/webui/ntp/suggestions_combiner.h" -#include "chrome/common/chrome_switches.h" -#include "components/history/core/browser/history_service.h" -#include "components/history/core/browser/top_sites.h" -#include "components/history/core/browser/visit_filter.h" - - -namespace { - -// The weight used by the combiner to determine which ratio of suggestions -// should be obtained from this source. -const int kSuggestionsTopListWeight = 1; - -} // namespace - -SuggestionsSourceTopSites::SuggestionsSourceTopSites() - : combiner_(NULL), - debug_(false) { -} - -SuggestionsSourceTopSites::~SuggestionsSourceTopSites() { - STLDeleteElements(&items_); -} - -void SuggestionsSourceTopSites::SetDebug(bool enable) { - debug_ = enable; -} - -inline int SuggestionsSourceTopSites::GetWeight() { - return kSuggestionsTopListWeight; -} - -int SuggestionsSourceTopSites::GetItemCount() { - return items_.size(); -} - -base::DictionaryValue* SuggestionsSourceTopSites::PopItem() { - if (items_.empty()) - return NULL; - - base::DictionaryValue* item = items_.front(); - items_.pop_front(); - return item; -} - -void SuggestionsSourceTopSites::FetchItems(Profile* profile) { - DCHECK(combiner_); - STLDeleteElements(&items_); - - history_tracker_.TryCancelAll(); - history::HistoryService* history = HistoryServiceFactory::GetForProfile( - profile, ServiceAccessType::EXPLICIT_ACCESS); - // |history| may be null during unit tests. - if (history) { - history::VisitFilter time_filter; - time_filter.SetFilterTime(base::Time::Now()); - time_filter.SetFilterWidth(GetFilterWidth()); - time_filter.set_sorting_order(GetSortingOrder()); - - history->QueryFilteredURLs( - 0, - time_filter, - debug_, - base::Bind(&SuggestionsSourceTopSites::OnSuggestionsUrlsAvailable, - base::Unretained(this)), - &history_tracker_); - } -} - -void SuggestionsSourceTopSites::SetCombiner(SuggestionsCombiner* combiner) { - DCHECK(!combiner_); - combiner_ = combiner; -} - -void SuggestionsSourceTopSites::OnSuggestionsUrlsAvailable( - const history::FilteredURLList* data) { - DCHECK(data); - DCHECK(combiner_); - for (size_t i = 0; i < data->size(); i++) { - const history::FilteredURL& suggested_url = (*data)[i]; - if (suggested_url.url.is_empty()) - continue; - - base::DictionaryValue* page_value = new base::DictionaryValue(); - NewTabUI::SetUrlTitleAndDirection(page_value, - suggested_url.title, - suggested_url.url); - page_value->SetDouble("score", suggested_url.score); - if (debug_) { - if (suggested_url.extended_info.total_visits) { - page_value->SetInteger("extended_info.total visits", - suggested_url.extended_info.total_visits); - } - if (suggested_url.extended_info.visits) { - page_value->SetInteger("extended_info.visits", - suggested_url.extended_info.visits); - } - if (suggested_url.extended_info.duration_opened) { - page_value->SetInteger("extended_info.duration opened", - suggested_url.extended_info.duration_opened); - } - if (!suggested_url.extended_info.last_visit_time.is_null()) { - base::TimeDelta deltaTime = - base::Time::Now() - suggested_url.extended_info.last_visit_time; - page_value->SetInteger("extended_info.seconds since last visit", - deltaTime.InSeconds()); - } - } - items_.push_back(page_value); - } - - combiner_->OnItemsReady(); -} - -// static -base::TimeDelta SuggestionsSourceTopSites::GetFilterWidth() { - return base::TimeDelta::FromHours(1); -} - -// static -history::VisitFilter::SortingOrder -SuggestionsSourceTopSites::GetSortingOrder() { - return history::VisitFilter::ORDER_BY_RECENCY; -}
diff --git a/chrome/browser/ui/webui/ntp/suggestions_source_top_sites.h b/chrome/browser/ui/webui/ntp/suggestions_source_top_sites.h deleted file mode 100644 index 3d22043..0000000 --- a/chrome/browser/ui/webui/ntp/suggestions_source_top_sites.h +++ /dev/null
@@ -1,66 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_UI_WEBUI_NTP_SUGGESTIONS_SOURCE_TOP_SITES_H_ -#define CHROME_BROWSER_UI_WEBUI_NTP_SUGGESTIONS_SOURCE_TOP_SITES_H_ - -#include <deque> - -#include "base/basictypes.h" -#include "base/task/cancelable_task_tracker.h" -#include "chrome/browser/ui/webui/ntp/suggestions_source.h" -#include "components/history/core/browser/history_types.h" -#include "components/history/core/browser/visit_filter.h" - -class SuggestionsCombiner; -class Profile; - -namespace base { -class DictionaryValue; -} - -// A SuggestionsSource that uses the local TopSites database to provide -// suggestions. -class SuggestionsSourceTopSites : public SuggestionsSource { - public: - SuggestionsSourceTopSites(); - ~SuggestionsSourceTopSites() override; - - protected: - // SuggestionsSource overrides: - void SetDebug(bool enable) override; - int GetWeight() override; - int GetItemCount() override; - base::DictionaryValue* PopItem() override; - void FetchItems(Profile* profile) override; - void SetCombiner(SuggestionsCombiner* combiner) override; - - void OnSuggestionsUrlsAvailable(const history::FilteredURLList* data); - - private: - - // Gets the sorting order from the command-line arguments. Defaults to - // |ORDER_BY_RECENCY| if there are no command-line argument specifying a - // sorting order. - static history::VisitFilter::SortingOrder GetSortingOrder(); - - // Gets the filter width from the command-line arguments. Defaults to one - // hour if there are no command-line argument setting the filter width. - static base::TimeDelta GetFilterWidth(); - - // Our combiner. - SuggestionsCombiner* combiner_; - - // Keep the results of the db query here. - std::deque<base::DictionaryValue*> items_; - - // Whether the source should provide additional debug information or not. - bool debug_; - - base::CancelableTaskTracker history_tracker_; - - DISALLOW_COPY_AND_ASSIGN(SuggestionsSourceTopSites); -}; - -#endif // CHROME_BROWSER_UI_WEBUI_NTP_SUGGESTIONS_SOURCE_TOP_SITES_H_
diff --git a/chrome/browser/ui/webui/options/browser_options_handler.cc b/chrome/browser/ui/webui/options/browser_options_handler.cc index 13dfafa..ce01268 100644 --- a/chrome/browser/ui/webui/options/browser_options_handler.cc +++ b/chrome/browser/ui/webui/options/browser_options_handler.cc
@@ -58,6 +58,7 @@ #include "chrome/browser/ui/browser_finder.h" #include "chrome/browser/ui/chrome_select_file_policy.h" #include "chrome/browser/ui/host_desktop.h" +#include "chrome/browser/ui/passwords/password_bubble_experiment.h" #include "chrome/browser/ui/webui/favicon_source.h" #include "chrome/browser/ui/webui/options/options_handlers_helper.h" #include "chrome/common/chrome_constants.h" @@ -307,7 +308,11 @@ { "metricsReportingResetRestart", IDS_OPTIONS_ENABLE_LOGGING_RESTART }, { "networkPredictionEnabledDescription", IDS_NETWORK_PREDICTION_ENABLED_DESCRIPTION }, - { "passwordManagerEnabled", IDS_OPTIONS_PASSWORD_MANAGER_ENABLE }, + { "passwordManagerEnabled", + password_bubble_experiment::IsSmartLockBrandingEnabled( + Profile::FromWebUI(web_ui())) ? + IDS_OPTIONS_PASSWORD_MANAGER_SMART_LOCK_ENABLE : + IDS_OPTIONS_PASSWORD_MANAGER_ENABLE }, { "passwordsAndAutofillGroupName", IDS_OPTIONS_PASSWORDS_AND_FORMS_GROUP_NAME }, { "privacyClearDataButton", IDS_OPTIONS_PRIVACY_CLEAR_DATA_BUTTON },
diff --git a/chrome/browser/ui/webui/options/password_manager_handler.cc b/chrome/browser/ui/webui/options/password_manager_handler.cc index 4957e149..ec0f9c3 100644 --- a/chrome/browser/ui/webui/options/password_manager_handler.cc +++ b/chrome/browser/ui/webui/options/password_manager_handler.cc
@@ -17,6 +17,7 @@ #include "chrome/browser/ui/ash/ash_util.h" #endif #include "chrome/browser/ui/passwords/manage_passwords_view_utils.h" +#include "chrome/browser/ui/passwords/password_bubble_experiment.h" #include "chrome/common/pref_names.h" #include "chrome/common/url_constants.h" #include "chrome/grit/generated_resources.h" @@ -74,25 +75,32 @@ }; RegisterStrings(localized_strings, resources, arraysize(resources)); - RegisterTitle(localized_strings, "passwordsPage", - IDS_PASSWORDS_EXCEPTIONS_WINDOW_TITLE); + + int title_id = + password_bubble_experiment::IsSmartLockBrandingEnabled(GetProfile()) ? + IDS_PASSWORDS_EXCEPTIONS_SMART_LOCK_WINDOW_TITLE : + IDS_PASSWORDS_EXCEPTIONS_WINDOW_TITLE; + RegisterTitle(localized_strings, "passwordsPage", title_id); localized_strings->SetString("passwordManagerLearnMoreURL", chrome::kPasswordManagerLearnMoreURL); localized_strings->SetString("passwordsManagePasswordsLink", chrome::kPasswordManagerAccountDashboardURL); - std::vector<base::string16> pieces; - base::SplitStringDontTrim( - l10n_util::GetStringUTF16(IDS_MANAGE_PASSWORDS_REMOTE_TEXT), - '|', // separator - &pieces); - DCHECK_EQ(3U, pieces.size()); + std::string management_hostname = + GURL(chrome::kPasswordManagerAccountDashboardURL).host(); + base::string16 link_text = base::UTF8ToUTF16(management_hostname); + size_t offset; + base::string16 full_text = l10n_util::GetStringFUTF16( + IDS_MANAGE_PASSWORDS_REMOTE_TEXT, link_text, &offset); + localized_strings->SetString("passwordsManagePasswordsBeforeLinkText", - pieces[0]); - localized_strings->SetString("passwordsManagePasswordsLinkText", pieces[1]); + full_text.substr(0, offset)); + localized_strings->SetString("passwordsManagePasswordsLinkText", + full_text.substr(offset, + offset + link_text.size())); localized_strings->SetString("passwordsManagePasswordsAfterLinkText", - pieces[2]); + full_text.substr(offset + link_text.size())); bool disable_show_passwords = false;
diff --git a/chrome/browser/ui/webui/options/preferences_browsertest.cc b/chrome/browser/ui/webui/options/preferences_browsertest.cc index 4a6511e..99805dc 100644 --- a/chrome/browser/ui/webui/options/preferences_browsertest.cc +++ b/chrome/browser/ui/webui/options/preferences_browsertest.cc
@@ -68,7 +68,7 @@ // Helper for pretty-printing the contents of base::Value in case of failures. void PrintTo(const base::Value& value, std::ostream* stream) { std::string json; - JSONWriter::Write(&value, &json); + JSONWriter::Write(value, &json); *stream << json; } @@ -192,7 +192,7 @@ .WillRepeatedly(Return(true)); policy::BrowserPolicyConnector::SetPolicyProviderForTesting( &policy_provider_); -}; +} void PreferencesBrowserTest::SetUserPolicies( const std::vector<std::string>& names, @@ -376,9 +376,8 @@ ExpectClearCommit(name); else ExpectNoCommit(name); - scoped_ptr<base::Value> commit_ptr(new base::FundamentalValue(commit)); std::string commit_json; - base::JSONWriter::Write(commit_ptr.get(), &commit_json); + base::JSONWriter::Write(base::FundamentalValue(commit), &commit_json); std::stringstream javascript; javascript << "testEnv.runAndReply(function() {" << " Preferences.clearPref("
diff --git a/chrome/browser/ui/webui/options/sync_setup_handler_unittest.cc b/chrome/browser/ui/webui/options/sync_setup_handler_unittest.cc index ef6108e4..a0c5de4 100644 --- a/chrome/browser/ui/webui/options/sync_setup_handler_unittest.cc +++ b/chrome/browser/ui/webui/options/sync_setup_handler_unittest.cc
@@ -93,7 +93,7 @@ result.SetBoolean("wifiCredentialsSynced", types.Has(syncer::WIFI_CREDENTIALS)); std::string args; - base::JSONWriter::Write(&result, &args); + base::JSONWriter::Write(result, &args); return args; }
diff --git a/chrome/browser/ui/webui/policy_ui.cc b/chrome/browser/ui/webui/policy_ui.cc index d2e73e7..03d4348 100644 --- a/chrome/browser/ui/webui/policy_ui.cc +++ b/chrome/browser/ui/webui/policy_ui.cc
@@ -36,6 +36,7 @@ #include "components/policy/core/common/policy_namespace.h" #include "components/policy/core/common/policy_service.h" #include "components/policy/core/common/policy_types.h" +#include "components/policy/core/common/remote_commands/remote_commands_service.h" #include "components/policy/core/common/schema.h" #include "components/policy/core/common/schema_map.h" #include "components/policy/core/common/schema_registry.h" @@ -52,6 +53,7 @@ #include "ui/base/l10n/time_format.h" #if defined(OS_CHROMEOS) +#include "chrome/browser/browser_process_platform_part.h" #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h" #include "chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.h" #include "chrome/browser/chromeos/policy/device_local_account_policy_service.h" @@ -215,7 +217,7 @@ // Utility function that returns a JSON serialization of the given |dict|. scoped_ptr<base::StringValue> DictionaryToJSONString( - const base::DictionaryValue* dict) { + const base::DictionaryValue& dict) { std::string json_string; base::JSONWriter::WriteWithOptions(dict, base::JSONWriter::OPTIONS_PRETTY_PRINT, @@ -228,14 +230,14 @@ scoped_ptr<base::Value> CopyAndConvert(const base::Value* value) { const base::DictionaryValue* dict = NULL; if (value->GetAsDictionary(&dict)) - return DictionaryToJSONString(dict); + return DictionaryToJSONString(*dict); scoped_ptr<base::Value> copy(value->DeepCopy()); base::ListValue* list = NULL; if (copy->GetAsList(&list)) { for (size_t i = 0; i < list->GetSize(); ++i) { if (list->GetDictionary(i, &dict)) - list->Set(i, DictionaryToJSONString(dict).release()); + list->Set(i, DictionaryToJSONString(*dict).release()); } } @@ -807,9 +809,22 @@ } void PolicyUIHandler::HandleReloadPolicies(const base::ListValue* args) { - GetPolicyService()->RefreshPolicies( - base::Bind(&PolicyUIHandler::OnRefreshPoliciesDone, - weak_factory_.GetWeakPtr())); +#if defined(OS_CHROMEOS) + // Allow user to manually fetch remote commands, in case invalidation + // service is not working properly. + // TODO(binjin): evaluate and possibly remove this after invalidation + // service is landed and tested. http://crbug.com/480982 + policy::BrowserPolicyConnectorChromeOS* connector = + g_browser_process->platform_part()->browser_policy_connector_chromeos(); + policy::RemoteCommandsService* remote_commands_service = + connector->GetDeviceCloudPolicyManager() + ->core() + ->remote_commands_service(); + if (remote_commands_service) + remote_commands_service->FetchRemoteCommands(); +#endif + GetPolicyService()->RefreshPolicies(base::Bind( + &PolicyUIHandler::OnRefreshPoliciesDone, weak_factory_.GetWeakPtr())); } void PolicyUIHandler::OnRefreshPoliciesDone() const {
diff --git a/chrome/browser/ui/webui/signin/profile_signin_confirmation_dialog.cc b/chrome/browser/ui/webui/signin/profile_signin_confirmation_dialog.cc index 1c688bb..5ad9d87 100644 --- a/chrome/browser/ui/webui/signin/profile_signin_confirmation_dialog.cc +++ b/chrome/browser/ui/webui/signin/profile_signin_confirmation_dialog.cc
@@ -173,7 +173,7 @@ #if defined(OS_WIN) dict.SetBoolean("hideTitle", true); #endif - base::JSONWriter::Write(&dict, &data); + base::JSONWriter::Write(dict, &data); return data; }
diff --git a/chrome/browser/ui/webui/suggestions_internals/suggestions_internals_ui.cc b/chrome/browser/ui/webui/suggestions_internals/suggestions_internals_ui.cc deleted file mode 100644 index d55e8a76..0000000 --- a/chrome/browser/ui/webui/suggestions_internals/suggestions_internals_ui.cc +++ /dev/null
@@ -1,37 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/ui/webui/suggestions_internals/suggestions_internals_ui.h" - -#include "chrome/browser/profiles/profile.h" -#include "chrome/browser/ui/webui/favicon_source.h" -#include "chrome/browser/ui/webui/suggestions_internals/suggestions_internals_ui_handler.h" -#include "chrome/common/url_constants.h" -#include "content/public/browser/url_data_source.h" -#include "content/public/browser/web_ui.h" -#include "content/public/browser/web_ui_controller.h" -#include "content/public/browser/web_ui_data_source.h" -#include "grit/browser_resources.h" - -SuggestionsInternalsUI::SuggestionsInternalsUI(content::WebUI* web_ui) - : content::WebUIController(web_ui) { - // Set up the chrome://suggestions-internals/ source. - content::WebUIDataSource* html_source = content::WebUIDataSource::Create( - chrome::kChromeUISuggestionsInternalsHost); - html_source->AddResourcePath("suggestions_internals.css", - IDR_SUGGESTIONS_INTERNALS_CSS); - html_source->AddResourcePath("suggestions_internals.js", - IDR_SUGGESTIONS_INTERNALS_JS); - html_source->SetDefaultResource(IDR_SUGGESTIONS_INTERNALS_HTML); - - Profile* profile = Profile::FromWebUI(web_ui); - content::WebUIDataSource::Add(profile, html_source); - content::URLDataSource::Add( - profile, new FaviconSource(profile, FaviconSource::FAVICON)); - - // AddMessageHandler takes ownership of SuggestionsInternalsUIHandler - web_ui->AddMessageHandler(new SuggestionsInternalsUIHandler(profile)); -} - -SuggestionsInternalsUI::~SuggestionsInternalsUI() { }
diff --git a/chrome/browser/ui/webui/suggestions_internals/suggestions_internals_ui.h b/chrome/browser/ui/webui/suggestions_internals/suggestions_internals_ui.h deleted file mode 100644 index f80fd85..0000000 --- a/chrome/browser/ui/webui/suggestions_internals/suggestions_internals_ui.h +++ /dev/null
@@ -1,21 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_UI_WEBUI_SUGGESTIONS_INTERNALS_SUGGESTIONS_INTERNALS_UI_H_ -#define CHROME_BROWSER_UI_WEBUI_SUGGESTIONS_INTERNALS_SUGGESTIONS_INTERNALS_UI_H_ - -#include "base/basictypes.h" -#include "content/public/browser/web_ui_controller.h" - -// The UI for chrome://suggestions-internals/ -class SuggestionsInternalsUI : public content::WebUIController { - public: - explicit SuggestionsInternalsUI(content::WebUI* contents); - ~SuggestionsInternalsUI() override; - - private: - DISALLOW_COPY_AND_ASSIGN(SuggestionsInternalsUI); -}; - -#endif // CHROME_BROWSER_UI_WEBUI_SUGGESTIONS_INTERNALS_SUGGESTIONS_INTERNALS_UI_H_
diff --git a/chrome/browser/ui/webui/suggestions_internals/suggestions_internals_ui_handler.cc b/chrome/browser/ui/webui/suggestions_internals/suggestions_internals_ui_handler.cc deleted file mode 100644 index 020d441..0000000 --- a/chrome/browser/ui/webui/suggestions_internals/suggestions_internals_ui_handler.cc +++ /dev/null
@@ -1,45 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/ui/webui/suggestions_internals/suggestions_internals_ui_handler.h" - -#include "base/bind.h" -#include "base/values.h" -#include "chrome/browser/profiles/profile.h" -#include "chrome/browser/ui/webui/ntp/suggestions_combiner.h" -#include "content/public/browser/web_ui.h" - -namespace { - -const size_t kSuggestionsCount = 100; - -} // namespace - -SuggestionsInternalsUIHandler::SuggestionsInternalsUIHandler(Profile* profile) - : profile_(profile) {} - -SuggestionsInternalsUIHandler::~SuggestionsInternalsUIHandler() {} - -void SuggestionsInternalsUIHandler::OnSuggestionsReady() { - if (suggestions_combiner_->GetPageValues()) { - web_ui()->CallJavascriptFunction("suggestionsInternals.setSuggestions", - *suggestions_combiner_->GetPageValues()); - } -} - -void SuggestionsInternalsUIHandler::RegisterMessages() { - // Setup the suggestions sources. - suggestions_combiner_.reset(new SuggestionsCombiner(this, profile_)); - suggestions_combiner_->SetSuggestionsCount(kSuggestionsCount); - suggestions_combiner_->EnableDebug(true); - - web_ui()->RegisterMessageCallback("getSuggestions", - base::Bind(&SuggestionsInternalsUIHandler::HandleGetSuggestions, - base::Unretained(this))); -} - -void SuggestionsInternalsUIHandler::HandleGetSuggestions( - const base::ListValue* one_element_input_string) { - suggestions_combiner_->FetchItems(Profile::FromWebUI(web_ui())); -}
diff --git a/chrome/browser/ui/webui/suggestions_internals/suggestions_internals_ui_handler.h b/chrome/browser/ui/webui/suggestions_internals/suggestions_internals_ui_handler.h deleted file mode 100644 index f20b32fd..0000000 --- a/chrome/browser/ui/webui/suggestions_internals/suggestions_internals_ui_handler.h +++ /dev/null
@@ -1,43 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_UI_WEBUI_SUGGESTIONS_INTERNALS_SUGGESTIONS_INTERNALS_UI_HANDLER_H_ -#define CHROME_BROWSER_UI_WEBUI_SUGGESTIONS_INTERNALS_SUGGESTIONS_INTERNALS_UI_HANDLER_H_ - -#include "base/memory/scoped_ptr.h" -#include "chrome/browser/ui/webui/ntp/suggestions_combiner.h" -#include "content/public/browser/web_ui_message_handler.h" - -class Profile; - -namespace base { -class ListValue; -} - -// UI Handler for chrome://suggestions-internals/ -class SuggestionsInternalsUIHandler : public content::WebUIMessageHandler, - public SuggestionsCombiner::Delegate { - public: - explicit SuggestionsInternalsUIHandler(Profile* profile); - ~SuggestionsInternalsUIHandler() override; - - // SuggestionsCombiner::Delegate implementation. - void OnSuggestionsReady() override; - - protected: - // WebUIMessageHandler implementation. - // Register our handler to get callbacks from javascript. - void RegisterMessages() override; - - void HandleGetSuggestions(const base::ListValue* one_element_input_string); - - // Used to combine suggestions from various sources. - scoped_ptr<SuggestionsCombiner> suggestions_combiner_; - - Profile* profile_; - - DISALLOW_COPY_AND_ASSIGN(SuggestionsInternalsUIHandler); -}; - -#endif // CHROME_BROWSER_UI_WEBUI_SUGGESTIONS_INTERNALS_SUGGESTIONS_INTERNALS_UI_HANDLER_H_
diff --git a/chrome/browser/unload_browsertest.cc b/chrome/browser/unload_browsertest.cc index c19dc05..98d5097 100644 --- a/chrome/browser/unload_browsertest.cc +++ b/chrome/browser/unload_browsertest.cc
@@ -238,15 +238,8 @@ // Navigate to a page with an infinite beforeunload handler. // Then two two sync crosssite requests to ensure // we correctly nav to each one. -// Flaky on Win and Linux; http://crbug.com/462671. -#if defined(OS_WIN) || defined(OS_LINUX) -#define MAYBE_CrossSiteInfiniteBeforeUnloadSync \ - DISABLED_CrossSiteInfiniteBeforeUnloadSync -#else -#define MAYBE_CrossSiteInfiniteBeforeUnloadSync \ - CrossSiteInfiniteBeforeUnloadSync -#endif -IN_PROC_BROWSER_TEST_F(UnloadTest, MAYBE_CrossSiteInfiniteBeforeUnloadSync) { +// Flaky on Win, Linux, and Mac; http://crbug.com/462671. +IN_PROC_BROWSER_TEST_F(UnloadTest, DISABLED_CrossSiteInfiniteBeforeUnloadSync) { // Tests makes no sense in single-process mode since the renderer is hung. if (base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kSingleProcess))
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index 3f20e2d..acc96c7 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi
@@ -2076,6 +2076,10 @@ 'browser/policy/cloud/cloud_policy_invalidator.h', 'browser/policy/cloud/policy_header_service_factory.cc', 'browser/policy/cloud/policy_header_service_factory.h', + 'browser/policy/cloud/remote_commands_invalidator.cc', + 'browser/policy/cloud/remote_commands_invalidator.h', + 'browser/policy/cloud/remote_commands_invalidator_impl.cc', + 'browser/policy/cloud/remote_commands_invalidator_impl.h', 'browser/policy/cloud/user_cloud_policy_invalidator.cc', 'browser/policy/cloud/user_cloud_policy_invalidator.h', 'browser/policy/cloud/user_cloud_policy_invalidator_factory.cc',
diff --git a/chrome/chrome_browser_chromeos.gypi b/chrome/chrome_browser_chromeos.gypi index aa01ca0..0c028c80 100644 --- a/chrome/chrome_browser_chromeos.gypi +++ b/chrome/chrome_browser_chromeos.gypi
@@ -855,6 +855,8 @@ 'browser/chromeos/policy/remote_commands/device_command_screenshot_job.h', 'browser/chromeos/policy/remote_commands/device_commands_factory_chromeos.cc', 'browser/chromeos/policy/remote_commands/device_commands_factory_chromeos.h', + 'browser/chromeos/policy/remote_commands/affiliated_remote_commands_invalidator.cc', + 'browser/chromeos/policy/remote_commands/affiliated_remote_commands_invalidator.h', 'browser/chromeos/policy/remote_commands/screenshot_delegate.cc', 'browser/chromeos/policy/remote_commands/screenshot_delegate.h', 'browser/chromeos/policy/server_backed_device_state.cc',
diff --git a/chrome/chrome_browser_ui.gypi b/chrome/chrome_browser_ui.gypi index 9509ee2..c66e42af 100644 --- a/chrome/chrome_browser_ui.gypi +++ b/chrome/chrome_browser_ui.gypi
@@ -548,6 +548,8 @@ 'browser/ui/ash/ash_keyboard_controller_proxy.h', 'browser/ui/ash/ash_util.cc', 'browser/ui/ash/ash_util.h', + 'browser/ui/ash/cast_config_delegate_chromeos.cc', + 'browser/ui/ash/cast_config_delegate_chromeos.h', 'browser/ui/ash/chrome_launcher_prefs.cc', 'browser/ui/ash/chrome_launcher_prefs.h', 'browser/ui/ash/chrome_new_window_delegate.cc', @@ -599,6 +601,8 @@ 'browser/ui/ash/launcher/multi_profile_browser_status_monitor.h', 'browser/ui/ash/media_delegate_chromeos.cc', 'browser/ui/ash/media_delegate_chromeos.h', + 'browser/ui/ash/metrics/chrome_user_metrics_recorder.cc', + 'browser/ui/ash/metrics/chrome_user_metrics_recorder.h', 'browser/ui/ash/multi_user/multi_user_context_menu_chromeos.cc', 'browser/ui/ash/multi_user/multi_user_notification_blocker_chromeos.cc', 'browser/ui/ash/multi_user/multi_user_notification_blocker_chromeos.h', @@ -1793,13 +1797,6 @@ 'browser/ui/webui/ntp/ntp_resource_cache_factory.cc', 'browser/ui/webui/ntp/ntp_resource_cache_factory.h', 'browser/ui/webui/ntp/ntp_stats.h', - 'browser/ui/webui/ntp/suggestions_combiner.cc', - 'browser/ui/webui/ntp/suggestions_combiner.h', - 'browser/ui/webui/ntp/suggestions_page_handler.cc', - 'browser/ui/webui/ntp/suggestions_page_handler.h', - 'browser/ui/webui/ntp/suggestions_source.h', - 'browser/ui/webui/ntp/suggestions_source_top_sites.cc', - 'browser/ui/webui/ntp/suggestions_source_top_sites.h', 'browser/ui/webui/ntp/thumbnail_source.cc', 'browser/ui/webui/ntp/thumbnail_source.h', 'browser/ui/webui/options/advanced_options_utils.h', @@ -1932,10 +1929,6 @@ 'browser/ui/webui/signin/profile_signin_confirmation_dialog.h', 'browser/ui/webui/signin/profile_signin_confirmation_ui.cc', 'browser/ui/webui/signin/profile_signin_confirmation_ui.h', - 'browser/ui/webui/suggestions_internals/suggestions_internals_ui.cc', - 'browser/ui/webui/suggestions_internals/suggestions_internals_ui.h', - 'browser/ui/webui/suggestions_internals/suggestions_internals_ui_handler.cc', - 'browser/ui/webui/suggestions_internals/suggestions_internals_ui_handler.h', 'browser/ui/webui/sync_file_system_internals/dump_database_handler.cc', 'browser/ui/webui/sync_file_system_internals/dump_database_handler.h', 'browser/ui/webui/sync_file_system_internals/extension_statuses_handler.cc', @@ -3156,7 +3149,7 @@ }], ['enable_media_router==1', { 'dependencies': [ - 'browser/media/router/media_router.gyp:media_router', + 'browser/media/router/media_router.gyp:media_router', ], 'sources': [ '<@(chrome_browser_ui_media_router_sources)' ], }],
diff --git a/chrome/chrome_renderer.gypi b/chrome/chrome_renderer.gypi index 9609443..9f618ca 100644 --- a/chrome/chrome_renderer.gypi +++ b/chrome/chrome_renderer.gypi
@@ -252,6 +252,7 @@ '../components/components.gyp:content_settings_content_common', '../components/components.gyp:cdm_renderer', '../components/components.gyp:data_reduction_proxy_content_common', + '../components/components.gyp:data_reduction_proxy_core_common', '../components/components.gyp:network_hints_renderer', '../components/components.gyp:error_page_renderer', '../components/components.gyp:startup_metric_utils',
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index fc8c4a5..0291a8f 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi
@@ -843,7 +843,7 @@ 'browser/ui/app_list/search/webstore/webstore_provider_browsertest.cc', 'browser/ui/app_list/speech_recognizer_browsertest.cc', ], - 'chrome_browser_tests_media_router_webui_sources': [ + 'chrome_browser_tests_media_router_sources': [ 'browser/ui/webui/media_router/media_router_dialog_controller_browsertest.cc', ], # Javascript sources. These are combined with the .cc files in the GYP build @@ -2246,7 +2246,8 @@ ], }], ['enable_media_router==1', { - 'sources': [ '<@(chrome_browser_tests_media_router_webui_sources)' ], + 'sources': [ '<@(chrome_browser_tests_media_router_sources)' ], + 'dependencies': [ 'browser/media/router/media_router.gyp:media_router_test_support' ], }], ['OS=="win"', { 'sources': [
diff --git a/chrome/chrome_tests_unit.gypi b/chrome/chrome_tests_unit.gypi index e800ea2..2e5c92a2 100644 --- a/chrome/chrome_tests_unit.gypi +++ b/chrome/chrome_tests_unit.gypi
@@ -970,6 +970,7 @@ 'chrome_unit_tests_configuration_policy_sources': [ 'browser/net/proxy_policy_handler_unittest.cc', 'browser/policy/cloud/cloud_policy_invalidator_unittest.cc', + 'browser/policy/cloud/remote_commands_invalidator_unittest.cc', 'browser/policy/cloud/user_policy_signin_service_unittest.cc', 'browser/policy/file_selection_dialogs_policy_handler_unittest.cc', 'browser/policy/javascript_policy_handler_unittest.cc', @@ -1419,6 +1420,21 @@ 'browser/supervised_user/supervised_user_url_filter_unittest.cc', 'browser/supervised_user/supervised_user_whitelist_service_unittest.cc', ], + 'chrome_unit_tests_media_router_sources': [ + 'browser/media/router/issue_manager_unittest.cc', + 'browser/media/router/issue_unittest.cc', + 'browser/media/router/media_router_type_converters_unittest.cc', + 'browser/media/router/media_route_unittest.cc', + 'browser/media/router/media_sink_unittest.cc', + 'browser/media/router/media_source_helper_unittest.cc', + 'browser/media/router/media_source_unittest.cc', + 'browser/media/router/presentation_media_sinks_observer_unittest.cc', + 'browser/ui/webui/media_router/media_cast_mode_unittest.cc', + 'browser/ui/webui/media_router/media_router_dialog_controller_unittest.cc', + 'browser/ui/webui/media_router/media_router_test.cc', + 'browser/ui/webui/media_router/media_router_test.h', + 'browser/ui/webui/media_router/query_result_manager_unittest.cc', + ], # Everything but Android and iOS (iOS is handled separately). 'chrome_unit_tests_non_android_sources': [ # Bookmark export/import are handled via the BookmarkColumns @@ -1522,10 +1538,7 @@ 'browser/ui/toolbar/wrench_menu_model_unittest.cc', 'browser/ui/website_settings/permission_menu_model_unittest.cc', 'browser/ui/webui/help/version_updater_chromeos_unittest.cc', - 'browser/ui/webui/media_router/media_cast_mode_unittest.cc', - 'browser/ui/webui/media_router/query_result_manager_unittest.cc', 'browser/ui/webui/ntp/ntp_user_data_logger_unittest.cc', - 'browser/ui/webui/ntp/suggestions_combiner_unittest.cc', 'browser/ui/webui/options/autofill_options_handler_unittest.cc', 'browser/ui/webui/options/language_options_handler_unittest.cc', 'browser/ui/webui/options/pepper_flash_content_settings_utils_unittest.cc', @@ -2349,9 +2362,8 @@ 'sources': [ '<@(chrome_unit_tests_print_preview_sources)' ], }], ['enable_media_router==1', { - 'includes': [ - 'browser/media/router/media_router_tests.gypi', - ], + 'sources': [ '<@(chrome_unit_tests_media_router_sources)' ], + 'dependencies': [ 'browser/media/router/media_router.gyp:media_router_test_support' ], }], ['enable_captive_portal_detection==1', { 'sources': [ '<@(chrome_unit_tests_captive_portal_sources)' ],
diff --git a/chrome/common/BUILD.gn b/chrome/common/BUILD.gn index b3726f9..4378b37a 100644 --- a/chrome/common/BUILD.gn +++ b/chrome/common/BUILD.gn
@@ -110,9 +110,6 @@ "//extensions/strings", "//media/cast:net", ] - if (enable_media_router) { - defines += [ "ENABLE_MEDIA_ROUTER=1" ] - } if (is_chromeos) { sources += rebase_path(gypi_values.chrome_common_extensions_chromeos_sources, @@ -243,9 +240,6 @@ ".", "//chrome") } - if (enable_media_router) { - defines += [ "ENABLE_MEDIA_ROUTER=1" ] - } } import("//chrome/version.gni")
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc index e8d60b3..86f222f 100644 --- a/chrome/common/chrome_switches.cc +++ b/chrome/common/chrome_switches.cc
@@ -291,6 +291,9 @@ const char kDisableOfflineAutoReloadVisibleOnly[] = "disable-offline-auto-reload-visible-only"; +// Disable out-of-process V8 proxy resolver. +const char kDisableOutOfProcessPac[] = "disable-out-of-process-pac"; + // Disable the setting to prompt the user for their OS account password before // revealing plaintext passwords in the password manager. const char kDisablePasswordManagerReauthentication[] = @@ -319,10 +322,6 @@ // Disables support for the QUIC protocol. const char kDisableQuic[] = "disable-quic"; -// Disable use of pacing of QUIC packets. -// This only has an effect if QUIC protocol is enabled. -const char kDisableQuicPacing[] = "disable-quic-pacing"; - // Disable use of Chromium's port selection for the ephemeral port via bind(). // This only has an effect if QUIC protocol is enabled. const char kDisableQuicPortSelection[] = "disable-quic-port-selection"; @@ -511,10 +510,6 @@ // Enables support for the QUIC protocol. This is a temporary testing flag. const char kEnableQuic[] = "enable-quic"; -// Disable use of pacing of QUIC packets. -// This only has an effect if QUIC protocol is enabled. -const char kEnableQuicPacing[] = "enable-quic-pacing"; - // Enable use of Chromium's port selection for the ephemeral port via bind(). // This only has an effect if QUIC protocol is enabled. const char kEnableQuicPortSelection[] = "enable-quic-port-selection";
diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h index 709f6da6..0af2b1b09 100644 --- a/chrome/common/chrome_switches.h +++ b/chrome/common/chrome_switches.h
@@ -86,6 +86,7 @@ extern const char kDisableNTPOtherSessionsMenu[]; extern const char kDisableOfflineAutoReload[]; extern const char kDisableOfflineAutoReloadVisibleOnly[]; +extern const char kDisableOutOfProcessPac[]; extern const char kDisablePasswordManagerReauthentication[]; extern const char kDisablePdfMaterialUI[]; extern const char kDisablePermissionsBubbles[]; @@ -94,7 +95,6 @@ extern const char kDisablePrintPreview[]; extern const char kDisablePromptOnRepost[]; extern const char kDisableQuic[]; -extern const char kDisableQuicPacing[]; extern const char kDisableQuicPortSelection[]; extern const char kDisableSavePasswordBubble[]; extern const char kDisableSdchPersistence[]; @@ -148,7 +148,6 @@ extern const char kEnableProfiling[]; extern const char kEnableQueryExtraction[]; extern const char kEnableQuic[]; -extern const char kEnableQuicPacing[]; extern const char kEnableQuicPortSelection[]; extern const char kEnableSavePasswordBubble[]; extern const char kEnableSdchPersistence[];
diff --git a/chrome/common/extensions/api/_api_features.json b/chrome/common/extensions/api/_api_features.json index 883b32de..e24ff6d 100644 --- a/chrome/common/extensions/api/_api_features.json +++ b/chrome/common/extensions/api/_api_features.json
@@ -508,6 +508,7 @@ "contexts": ["blessed_extension"] }, "instanceID": { + "channel": "dev", "dependencies": ["permission:gcm"], "contexts": ["blessed_extension"] },
diff --git a/chrome/common/extensions/api/file_manager_private.idl b/chrome/common/extensions/api/file_manager_private.idl index 64295c78..683f56d 100644 --- a/chrome/common/extensions/api/file_manager_private.idl +++ b/chrome/common/extensions/api/file_manager_private.idl
@@ -174,6 +174,14 @@ public }; +// Source of the volume data. +enum Source { + file, + device, + network, + system +}; + // A file task represents an action that the file manager can perform over the // currently selected files. See // chrome/browser/chromeos/extensions/file_manager/file_tasks.h for details @@ -290,6 +298,9 @@ // Extension providing this volume (for provided file systems). DOMString? extensionId; + // Source of the volume's data. + Source source; + // Label of the volume (if available). DOMString? volumeLabel; @@ -320,6 +331,9 @@ // Flag that specifies whether the volume contains media. boolean hasMedia; + // Flag that specifies whether the volume is configurable. + boolean configurable; + // Additional data about mount, for example, that the filesystem is not // supported. MountCondition? mountCondition; @@ -905,10 +919,9 @@ static void addProvidedFileSystem(DOMString extension_id, SimpleCallback callback); - // Requests configuring an existing file system. If not possible, then returns + // Requests configuring an existing volume. If not possible, then returns // an error via chrome.runtime.lastError. - static void configureProvidedFileSystem(DOMString volumeId, - SimpleCallback callback); + static void configureVolume(DOMString volumeId, SimpleCallback callback); }; interface Events {
diff --git a/chrome/common/extensions/api/launcher_page.idl b/chrome/common/extensions/api/launcher_page.idl index a6a1943d..7e7896a8 100644 --- a/chrome/common/extensions/api/launcher_page.idl +++ b/chrome/common/extensions/api/launcher_page.idl
@@ -7,6 +7,7 @@ namespace launcherPage { callback PushSubpageCallback = void(); callback ShowCallback = void(); + callback HideCallback = void(); callback SetEnabledCallback = void(); interface Functions { @@ -24,6 +25,9 @@ // page. static void show(optional ShowCallback callback); + // Returns the launcher to the start page if the launcher page is showing. + static void hide(optional HideCallback callback); + // Sets whether the launcher page is enabled in the launcher. If disabled, // the launcher page will not be shown when the area at the bottom of the // launcher is pressed.
diff --git a/chrome/common/logging_chrome.cc b/chrome/common/logging_chrome.cc index 7d26587..c8458ef9 100644 --- a/chrome/common/logging_chrome.cc +++ b/chrome/common/logging_chrome.cc
@@ -333,14 +333,19 @@ command_line.HasSwitch(switches::kNoErrorDialogs)) SuppressDialogs(); - // Use a minimum log level if the command line asks for one, - // otherwise leave it at the default level (INFO). - if (command_line.HasSwitch(switches::kLoggingLevel)) { - std::string log_level = command_line.GetSwitchValueASCII( - switches::kLoggingLevel); + // Use a minimum log level if the command line asks for one. Ignore this + // switch if there's vlog level switch present too (as both of these switches + // refer to the same underlying log level, and the vlog level switch has + // already been processed inside logging::InitLogging). If there is neither + // log level nor vlog level specified, then just leave the default level + // (INFO). + if (command_line.HasSwitch(switches::kLoggingLevel) && + logging::GetMinLogLevel() >= 0) { + std::string log_level = + command_line.GetSwitchValueASCII(switches::kLoggingLevel); int level = 0; - if (base::StringToInt(log_level, &level) && - level >= 0 && level < LOG_NUM_SEVERITIES) { + if (base::StringToInt(log_level, &level) && level >= 0 && + level < LOG_NUM_SEVERITIES) { logging::SetMinLogLevel(level); } else { DLOG(WARNING) << "Bad log level: " << log_level;
diff --git a/chrome/common/render_messages.h b/chrome/common/render_messages.h index 287b47e..fc9eb17 100644 --- a/chrome/common/render_messages.h +++ b/chrome/common/render_messages.h
@@ -292,6 +292,10 @@ IPC_MESSAGE_ROUTED1(ChromeViewMsg_SetClientSidePhishingDetection, bool /* enable_phishing_detection */) +// Reloads the image selected by the most recently opened context menu +// (if there indeed is an image at that location). +IPC_MESSAGE_ROUTED0(ChromeViewMsg_RequestReloadImageForContextNode) + // Asks the renderer for a thumbnail of the image selected by the most // recently opened context menu, if there is one. If the image's area // is greater than thumbnail_min_area it will be downscaled to
diff --git a/chrome/common/url_constants.cc b/chrome/common/url_constants.cc index 72c4d66..01e5949 100644 --- a/chrome/common/url_constants.cc +++ b/chrome/common/url_constants.cc
@@ -76,8 +76,6 @@ const char kChromeUIContentSettingsURL[] = "chrome://settings/content"; const char kChromeUISettingsFrameURL[] = "chrome://settings-frame/"; const char kChromeUISuggestionsURL[] = "chrome://suggestions/"; -const char kChromeUISuggestionsInternalsURL[] = - "chrome://suggestions-internals/"; const char kChromeUISupervisedUserPassphrasePageURL[] = "chrome://managed-user-passphrase/"; const char kChromeUITermsURL[] = "chrome://terms/"; @@ -229,7 +227,6 @@ const char kChromeUIShorthangHost[] = "shorthang"; const char kChromeUISignInInternalsHost[] = "signin-internals"; const char kChromeUISuggestionsHost[] = "suggestions"; -const char kChromeUISuggestionsInternalsHost[] = "suggestions-internals"; const char kChromeUISupervisedUserPassphrasePageHost[] = "managed-user-passphrase"; const char kChromeUISyncHost[] = "sync"; @@ -573,8 +570,7 @@ #endif const char kRemoveNonCWSExtensionURL[] = - "https://support.google.com/chrome/answer/2811969?" - "p=ui_remove_non_cws_extensions&rd=1"; + "https://support.google.com/chrome/?p=ui_remove_non_cws_extensions"; #if defined(OS_WIN) const char kNotificationsHelpURL[] =
diff --git a/chrome/common/url_constants.h b/chrome/common/url_constants.h index 36163c2..90960f5 100644 --- a/chrome/common/url_constants.h +++ b/chrome/common/url_constants.h
@@ -72,7 +72,6 @@ extern const char kChromeUIContentSettingsURL[]; extern const char kChromeUISettingsFrameURL[]; extern const char kChromeUISuggestionsURL[]; -extern const char kChromeUISuggestionsInternalsURL[]; extern const char kChromeUISupervisedUserPassphrasePageURL[]; extern const char kChromeUITermsURL[]; extern const char kChromeUIThemeURL[]; @@ -216,7 +215,6 @@ extern const char kChromeUIShorthangHost[]; extern const char kChromeUISignInInternalsHost[]; extern const char kChromeUISuggestionsHost[]; -extern const char kChromeUISuggestionsInternalsHost[]; extern const char kChromeUISupervisedUserPassphrasePageHost[]; extern const char kChromeUISyncHost[]; extern const char kChromeUISyncFileSystemInternalsHost[];
diff --git a/chrome/installer/linux/rpm/expected_deps_x86_64 b/chrome/installer/linux/rpm/expected_deps_x86_64 index 1b5cd370..f7085e2 100644 --- a/chrome/installer/linux/rpm/expected_deps_x86_64 +++ b/chrome/installer/linux/rpm/expected_deps_x86_64
@@ -20,6 +20,7 @@ libfontconfig.so.1()(64bit) libfreetype.so.6()(64bit) libgcc_s.so.1()(64bit) +libgcc_s.so.1(GCC_3.0)(64bit) libgcc_s.so.1(GCC_4.0.0)(64bit) libgconf-2.so.4()(64bit) libgdk_pixbuf-2.0.so.0()(64bit)
diff --git a/chrome/renderer/BUILD.gn b/chrome/renderer/BUILD.gn index cd1cb304..e5857448 100644 --- a/chrome/renderer/BUILD.gn +++ b/chrome/renderer/BUILD.gn
@@ -39,6 +39,7 @@ "//components/content_settings/content/common", "//components/cdm/renderer", "//components/data_reduction_proxy/content/common", + "//components/data_reduction_proxy/core/common", "//components/network_hints/renderer", "//components/error_page/renderer", "//components/password_manager/content/renderer",
diff --git a/chrome/renderer/DEPS b/chrome/renderer/DEPS index 2dbacc1..cd2cd8e3 100644 --- a/chrome/renderer/DEPS +++ b/chrome/renderer/DEPS
@@ -9,6 +9,7 @@ "+components/content_settings/core/common", "+components/crx_file", "+components/data_reduction_proxy/content/common", + "+components/data_reduction_proxy/core/common", "+components/dom_distiller/core", "+components/nacl/common", "+components/nacl/renderer",
diff --git a/chrome/renderer/autofill/autofill_renderer_browsertest.cc b/chrome/renderer/autofill/autofill_renderer_browsertest.cc index e6f4ec1..a8a8301 100644 --- a/chrome/renderer/autofill/autofill_renderer_browsertest.cc +++ b/chrome/renderer/autofill/autofill_renderer_browsertest.cc
@@ -258,6 +258,7 @@ GetMainFrame()->view()->advanceFocus(false); // Not a user gesture, so no IPC message to browser. + DisableUserGestureSimulationForAutofill(); full_name.setValue("Alice", true); GetMainFrame()->toWebLocalFrame()->autofillClient()->textFieldDidChange( full_name); @@ -266,6 +267,7 @@ AutofillHostMsg_TextFieldDidChange::ID)); // A user gesture will send a message to the browser. + EnableUserGestureSimulationForAutofill(); SimulateUserInputChangeForElement(&full_name, "Alice"); ASSERT_NE(nullptr, render_thread_->sink().GetFirstMessageMatching( AutofillHostMsg_TextFieldDidChange::ID));
diff --git a/chrome/renderer/chrome_content_renderer_client.cc b/chrome/renderer/chrome_content_renderer_client.cc index 8e92dfc..7613f47 100644 --- a/chrome/renderer/chrome_content_renderer_client.cc +++ b/chrome/renderer/chrome_content_renderer_client.cc
@@ -59,6 +59,7 @@ #include "components/autofill/content/renderer/password_autofill_agent.h" #include "components/autofill/content/renderer/password_generation_agent.h" #include "components/content_settings/core/common/content_settings_pattern.h" +#include "components/data_reduction_proxy/core/common/data_reduction_proxy_headers.h" #include "components/dom_distiller/core/url_constants.h" #include "components/nacl/renderer/ppb_nacl_private.h" #include "components/nacl/renderer/ppb_nacl_private_impl.h" @@ -83,6 +84,7 @@ #include "third_party/WebKit/public/platform/WebURL.h" #include "third_party/WebKit/public/platform/WebURLError.h" #include "third_party/WebKit/public/platform/WebURLRequest.h" +#include "third_party/WebKit/public/platform/WebURLResponse.h" #include "third_party/WebKit/public/web/WebCache.h" #include "third_party/WebKit/public/web/WebDataSource.h" #include "third_party/WebKit/public/web/WebDocument.h" @@ -1653,3 +1655,18 @@ return scoped_ptr<blink::WebAppBannerClient>( new AppBannerClient(render_frame)); } + +void ChromeContentRendererClient::AddImageContextMenuProperties( + const blink::WebURLResponse& response, + std::map<std::string, std::string>* properties) { + DCHECK(properties); + WebString header_key(ASCIIToUTF16( + data_reduction_proxy::chrome_proxy_header())); + if (!response.httpHeaderField(header_key).isNull() && + response.httpHeaderField(header_key).utf8().find( + data_reduction_proxy::chrome_proxy_lo_fi_directive()) != + std::string::npos) { + (*properties)[data_reduction_proxy::chrome_proxy_header()] = + data_reduction_proxy::chrome_proxy_lo_fi_directive(); + } +}
diff --git a/chrome/renderer/chrome_content_renderer_client.h b/chrome/renderer/chrome_content_renderer_client.h index ca206a1f..764edae9 100644 --- a/chrome/renderer/chrome_content_renderer_client.h +++ b/chrome/renderer/chrome_content_renderer_client.h
@@ -5,6 +5,7 @@ #ifndef CHROME_RENDERER_CHROME_CONTENT_RENDERER_CLIENT_H_ #define CHROME_RENDERER_CHROME_CONTENT_RENDERER_CLIENT_H_ +#include <map> #include <set> #include <string> #include <vector> @@ -150,6 +151,9 @@ void RecordRapporURL(const std::string& metric, const GURL& url) override; scoped_ptr<blink::WebAppBannerClient> CreateAppBannerClient( content::RenderFrame* render_frame) override; + void AddImageContextMenuProperties( + const blink::WebURLResponse& response, + std::map<std::string, std::string>* properties) override; #if defined(ENABLE_EXTENSIONS) // Takes ownership.
diff --git a/chrome/renderer/chrome_render_frame_observer.cc b/chrome/renderer/chrome_render_frame_observer.cc index 1518bf6..9921dcc 100644 --- a/chrome/renderer/chrome_render_frame_observer.cc +++ b/chrome/renderer/chrome_render_frame_observer.cc
@@ -94,6 +94,8 @@ return false; IPC_BEGIN_MESSAGE_MAP(ChromeRenderFrameObserver, message) + IPC_MESSAGE_HANDLER(ChromeViewMsg_RequestReloadImageForContextNode, + OnRequestReloadImageForContextNode) IPC_MESSAGE_HANDLER(ChromeViewMsg_RequestThumbnailForContextNode, OnRequestThumbnailForContextNode) IPC_MESSAGE_HANDLER(PrintMsg_PrintNodeUnderContextMenu, @@ -123,6 +125,14 @@ } } +void ChromeRenderFrameObserver::OnRequestReloadImageForContextNode() { + WebNode context_node = render_frame()->GetContextMenuNode(); + if (!context_node.isNull() && context_node.isElementNode() && + render_frame()->GetWebFrame()) { + render_frame()->GetWebFrame()->reloadImage(context_node); + } +} + void ChromeRenderFrameObserver::OnRequestThumbnailForContextNode( int thumbnail_min_area_pixels, const gfx::Size& thumbnail_max_size_pixels) {
diff --git a/chrome/renderer/chrome_render_frame_observer.h b/chrome/renderer/chrome_render_frame_observer.h index 83cce6a..1534895 100644 --- a/chrome/renderer/chrome_render_frame_observer.h +++ b/chrome/renderer/chrome_render_frame_observer.h
@@ -26,6 +26,7 @@ // IPC handlers void OnSetIsPrerendering(bool is_prerendering); + void OnRequestReloadImageForContextNode(); void OnRequestThumbnailForContextNode( int thumbnail_min_area_pixels, const gfx::Size& thumbnail_max_size_pixels);
diff --git a/chrome/renderer/extensions/renderer_permissions_policy_delegate.cc b/chrome/renderer/extensions/renderer_permissions_policy_delegate.cc index dabf649..58b1ed1 100644 --- a/chrome/renderer/extensions/renderer_permissions_policy_delegate.cc +++ b/chrome/renderer/extensions/renderer_permissions_policy_delegate.cc
@@ -30,12 +30,8 @@ int tab_id, int process_id, std::string* error) { - const ExtensionsClient::ScriptingWhitelist& whitelist = - ExtensionsClient::Get()->GetScriptingWhitelist(); - if (std::find(whitelist.begin(), whitelist.end(), extension->id()) != - whitelist.end()) { + if (PermissionsData::CanExecuteScriptEverywhere(extension)) return true; - } if (dispatcher_->IsExtensionActive(kWebStoreAppId)) { if (error)
diff --git a/chrome/renderer/net/net_error_helper.cc b/chrome/renderer/net/net_error_helper.cc index 00c2964..a3ab4e55 100644 --- a/chrome/renderer/net/net_error_helper.cc +++ b/chrome/renderer/net/net_error_helper.cc
@@ -230,7 +230,7 @@ &error_strings); std::string json; - JSONWriter::Write(&error_strings, &json); + JSONWriter::Write(error_strings, &json); std::string js = "if (window.updateForDnsProbe) " "updateForDnsProbe(" + json + ");";
diff --git a/chrome/service/cloud_print/print_system_win.cc b/chrome/service/cloud_print/print_system_win.cc index ac090c2..550a5633 100644 --- a/chrome/service/cloud_print/print_system_win.cc +++ b/chrome/service/cloud_print/print_system_win.cc
@@ -545,7 +545,7 @@ PrinterSemanticCapsAndDefaultsToCdd(semantic_info)); if (description) { base::JSONWriter::WriteWithOptions( - description.get(), base::JSONWriter::OPTIONS_PRETTY_PRINT, + *description, base::JSONWriter::OPTIONS_PRETTY_PRINT, &printer_info.printer_capabilities); } }
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index 65cf46cf..83e07bb9 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -854,9 +854,10 @@ } if (enable_media_router) { sources += rebase_path( - chrome_tests_gypi_values.chrome_browser_tests_media_router_webui_sources, + chrome_tests_gypi_values.chrome_browser_tests_media_router_sources, ".", "//chrome") + deps += [ "//chrome/browser/media/router:test_support" ] } if (is_win) { deps += [ @@ -1283,7 +1284,6 @@ ".", "//chrome") } - if (is_ios || is_chromeos) { sources -= [ "../browser/metrics/signin_status_metrics_provider_unittest.cc" ] @@ -1490,14 +1490,18 @@ ".", "//chrome") } + if (enable_media_router) { + sources += + rebase_path(unit_gypi_values.chrome_unit_tests_media_router_sources, + ".", + "//chrome") + deps += [ "//chrome/browser/media/router:test_support" ] + } if (enable_webrtc) { sources += rebase_path(unit_gypi_values.chrome_unit_tests_webrtc_sources, ".", "//chrome") } - if (enable_media_router) { - deps += [ "//chrome/browser/media/router:unit_tests" ] - } if (is_chromeos) { sources += rebase_path(unit_gypi_values.chrome_unit_tests_chromeos_sources, @@ -1739,6 +1743,7 @@ "//chrome/browser", "//chrome/renderer", "//media/cast:test_support", + "//testing/gmock", "//testing/gtest", "//testing/perf", ]
diff --git a/chrome/test/base/chrome_render_view_test.cc b/chrome/test/base/chrome_render_view_test.cc index 4f47f69..d968e0c6 100644 --- a/chrome/test/base/chrome_render_view_test.cc +++ b/chrome/test/base/chrome_render_view_test.cc
@@ -18,6 +18,7 @@ #include "content/public/browser/native_web_keyboard_event.h" #include "content/public/common/renderer_preferences.h" #include "content/public/renderer/render_view.h" +#include "testing/gmock/include/gmock/gmock.h" #include "third_party/WebKit/public/platform/WebURLRequest.h" #include "third_party/WebKit/public/web/WebFrame.h" #include "third_party/WebKit/public/web/WebInputEvent.h" @@ -44,6 +45,34 @@ using blink::WebScriptSource; using blink::WebString; using blink::WebURLRequest; +using content::RenderFrame; +using testing::NiceMock; +using testing::Return; +using testing::_; + +namespace { + +// An autofill agent that treats all typing as user gesture. +class MockAutofillAgent : public AutofillAgent { + public: + MockAutofillAgent(RenderFrame* render_frame, + PasswordAutofillAgent* password_autofill_agent, + PasswordGenerationAgent* password_generation_agent) + : AutofillAgent(render_frame, + password_autofill_agent, + password_generation_agent) { + ON_CALL(*this, IsUserGesture()).WillByDefault(Return(true)); + } + + ~MockAutofillAgent() override {} + + MOCK_CONST_METHOD0(IsUserGesture, bool()); + + private: + DISALLOW_COPY_AND_ASSIGN(MockAutofillAgent); +}; + +} // namespace ChromeRenderViewTest::ChromeRenderViewTest() : password_autofill_agent_(NULL), @@ -71,9 +100,9 @@ new autofill::TestPasswordAutofillAgent(view_->GetMainRenderFrame()); password_generation_ = new autofill::TestPasswordGenerationAgent(view_->GetMainRenderFrame()); - autofill_agent_ = - new AutofillAgent(view_->GetMainRenderFrame(), password_autofill_agent_, - password_generation_); + autofill_agent_ = new NiceMock<MockAutofillAgent>(view_->GetMainRenderFrame(), + password_autofill_agent_, + password_generation_); } void ChromeRenderViewTest::TearDown() { @@ -96,12 +125,12 @@ } content::ContentBrowserClient* - ChromeRenderViewTest::CreateContentBrowserClient() { +ChromeRenderViewTest::CreateContentBrowserClient() { return new chrome::ChromeContentBrowserClient(); } content::ContentRendererClient* - ChromeRenderViewTest::CreateContentRendererClient() { +ChromeRenderViewTest::CreateContentRendererClient() { ChromeContentRendererClient* client = new ChromeContentRendererClient(); #if defined(ENABLE_EXTENSIONS) extension_dispatcher_delegate_.reset( @@ -114,3 +143,13 @@ #endif return client; } + +void ChromeRenderViewTest::EnableUserGestureSimulationForAutofill() { + EXPECT_CALL(*(static_cast<MockAutofillAgent*>(autofill_agent_)), + IsUserGesture()).WillRepeatedly(Return(true)); +} + +void ChromeRenderViewTest::DisableUserGestureSimulationForAutofill() { + EXPECT_CALL(*(static_cast<MockAutofillAgent*>(autofill_agent_)), + IsUserGesture()).WillRepeatedly(Return(false)); +}
diff --git a/chrome/test/base/chrome_render_view_test.h b/chrome/test/base/chrome_render_view_test.h index c2e06a7c..154a9fd 100644 --- a/chrome/test/base/chrome_render_view_test.h +++ b/chrome/test/base/chrome_render_view_test.h
@@ -34,6 +34,9 @@ content::ContentBrowserClient* CreateContentBrowserClient() override; content::ContentRendererClient* CreateContentRendererClient() override; + void EnableUserGestureSimulationForAutofill(); + void DisableUserGestureSimulationForAutofill(); + #if defined(ENABLE_EXTENSIONS) scoped_ptr<extensions::DispatcherDelegate> extension_dispatcher_delegate_; #endif
diff --git a/chrome/test/chromedriver/chrome/console_logger.cc b/chrome/test/chromedriver/chrome/console_logger.cc index 9300e63..d5557024 100644 --- a/chrome/test/chromedriver/chrome/console_logger.cc +++ b/chrome/test/chromedriver/chrome/console_logger.cc
@@ -93,7 +93,7 @@ // Don't know how to format, log full JSON. std::string message_json; - base::JSONWriter::Write(¶ms, &message_json); + base::JSONWriter::Write(params, &message_json); log_->AddEntry(Log::kWarning, message_json); return Status(kOk); }
diff --git a/chrome/test/chromedriver/chrome/devtools_client_impl.cc b/chrome/test/chromedriver/chrome/devtools_client_impl.cc index 4992c80..56da77b36 100644 --- a/chrome/test/chromedriver/chrome/devtools_client_impl.cc +++ b/chrome/test/chromedriver/chrome/devtools_client_impl.cc
@@ -496,7 +496,7 @@ if (message_dict->GetDictionary("result", &unscoped_result)) command_response->result.reset(unscoped_result->DeepCopy()); else if (message_dict->GetDictionary("error", &unscoped_error)) - base::JSONWriter::Write(unscoped_error, &command_response->error); + base::JSONWriter::Write(*unscoped_error, &command_response->error); else command_response->result.reset(new base::DictionaryValue()); return true;
diff --git a/chrome/test/chromedriver/chrome/devtools_client_impl_unittest.cc b/chrome/test/chromedriver/chrome/devtools_client_impl_unittest.cc index 158caf3..4a0a4b00 100644 --- a/chrome/test/chromedriver/chrome/devtools_client_impl_unittest.cc +++ b/chrome/test/chromedriver/chrome/devtools_client_impl_unittest.cc
@@ -70,7 +70,7 @@ base::DictionaryValue result; result.SetInteger("param", 1); response.Set("result", result.DeepCopy()); - base::JSONWriter::Write(&response, message); + base::JSONWriter::Write(response, message); --queued_messages_; return SyncWebSocket::kOk; } @@ -120,7 +120,7 @@ Status status = client.SendCommandAndGetResult("method", params, &result); ASSERT_EQ(kOk, status.code()); std::string json; - base::JSONWriter::Write(result.get(), &json); + base::JSONWriter::Write(*result, &json); ASSERT_STREQ("{\"param\":1}", json.c_str()); } @@ -725,7 +725,7 @@ response.SetInteger("id", id); response.Set("result", new base::DictionaryValue()); std::string json_response; - base::JSONWriter::Write(&response, &json_response); + base::JSONWriter::Write(response, &json_response); queued_response_.push_back(json_response); // Push one event. @@ -733,7 +733,7 @@ event.SetString("method", "updateEvent"); event.Set("params", new base::DictionaryValue()); std::string json_event; - base::JSONWriter::Write(&event, &json_event); + base::JSONWriter::Write(event, &json_event); queued_response_.push_back(json_event); return true;
diff --git a/chrome/test/chromedriver/chrome/dom_tracker.cc b/chrome/test/chromedriver/chrome/dom_tracker.cc index 40f2f88..5f5fbcb 100644 --- a/chrome/test/chromedriver/chrome/dom_tracker.cc +++ b/chrome/test/chromedriver/chrome/dom_tracker.cc
@@ -43,7 +43,7 @@ if (!ProcessNodeList(nodes)) { std::string json; - base::JSONWriter::Write(nodes, &json); + base::JSONWriter::Write(*nodes, &json); return Status(kUnknownError, "DOM.setChildNodes has invalid 'nodes': " + json); } @@ -54,7 +54,7 @@ if (!ProcessNode(node)) { std::string json; - base::JSONWriter::Write(node, &json); + base::JSONWriter::Write(*node, &json); return Status(kUnknownError, "DOM.childNodeInserted has invalid 'node': " + json); }
diff --git a/chrome/test/chromedriver/chrome/frame_tracker.cc b/chrome/test/chromedriver/chrome/frame_tracker.cc index c18b948e..c87e0d8 100644 --- a/chrome/test/chromedriver/chrome/frame_tracker.cc +++ b/chrome/test/chromedriver/chrome/frame_tracker.cc
@@ -52,7 +52,7 @@ if (!context->GetInteger("id", &context_id) || !context->GetString("frameId", &frame_id)) { std::string json; - base::JSONWriter::Write(context, &json); + base::JSONWriter::Write(*context, &json); return Status( kUnknownError, "Runtime.executionContextCreated has invalid 'context': " + json);
diff --git a/chrome/test/chromedriver/chrome/log.cc b/chrome/test/chromedriver/chrome/log.cc index a40f9b2..ed1190a 100644 --- a/chrome/test/chromedriver/chrome/log.cc +++ b/chrome/test/chromedriver/chrome/log.cc
@@ -85,7 +85,7 @@ std::string PrettyPrintValue(const base::Value& value) { std::string json; base::JSONWriter::WriteWithOptions( - &value, base::JSONWriter::OPTIONS_PRETTY_PRINT, &json); + value, base::JSONWriter::OPTIONS_PRETTY_PRINT, &json); #if defined(OS_WIN) base::RemoveChars(json, "\r", &json); #endif
diff --git a/chrome/test/chromedriver/chrome/util.cc b/chrome/test/chromedriver/chrome/util.cc index b7f1a5cd..02206f3 100644 --- a/chrome/test/chromedriver/chrome/util.cc +++ b/chrome/test/chromedriver/chrome/util.cc
@@ -9,6 +9,6 @@ std::string SerializeValue(const base::Value* value) { std::string json; - base::JSONWriter::Write(value, &json); + base::JSONWriter::Write(*value, &json); return json; }
diff --git a/chrome/test/chromedriver/chrome/web_view_impl.cc b/chrome/test/chromedriver/chrome/web_view_impl.cc index c9cce52..9febe2b7 100644 --- a/chrome/test/chromedriver/chrome/web_view_impl.cc +++ b/chrome/test/chromedriver/chrome/web_view_impl.cc
@@ -237,7 +237,7 @@ const base::ListValue& args, scoped_ptr<base::Value>* result) { std::string json; - base::JSONWriter::Write(&args, &json); + base::JSONWriter::Write(args, &json); // TODO(zachconrad): Second null should be array of shadow host ids. std::string expression = base::StringPrintf( "(%s).apply(null, [null, %s, %s])", @@ -763,7 +763,7 @@ bool* found_node, int* node_id) { std::string json; - base::JSONWriter::Write(&args, &json); + base::JSONWriter::Write(args, &json); // TODO(zachconrad): Second null should be array of shadow host ids. std::string expression = base::StringPrintf( "(%s).apply(null, [null, %s, %s, true])",
diff --git a/chrome/test/chromedriver/chrome_launcher.cc b/chrome/test/chromedriver/chrome_launcher.cc index dcf44d5..6326e14d 100644 --- a/chrome/test/chromedriver/chrome_launcher.cc +++ b/chrome/test/chromedriver/chrome_launcher.cc
@@ -692,7 +692,7 @@ } } else { manifest->SetString("key", public_key_base64); - base::JSONWriter::Write(manifest, &manifest_data); + base::JSONWriter::Write(*manifest, &manifest_data); if (base::WriteFile( manifest_path, manifest_data.c_str(), manifest_data.size()) != static_cast<int>(manifest_data.size())) { @@ -788,7 +788,7 @@ } std::string prefs_str; - base::JSONWriter::Write(prefs, &prefs_str); + base::JSONWriter::Write(*prefs, &prefs_str); VLOG(0) << "Populating " << path.BaseName().value() << " file: " << PrettyPrintValue(*prefs); if (static_cast<int>(prefs_str.length()) != base::WriteFile(
diff --git a/chrome/test/chromedriver/performance_logger.cc b/chrome/test/chromedriver/performance_logger.cc index ea38f77..800e8ec94 100644 --- a/chrome/test/chromedriver/performance_logger.cc +++ b/chrome/test/chromedriver/performance_logger.cc
@@ -123,7 +123,7 @@ log_message_dict.SetString("message.method", method); log_message_dict.Set("message.params", params.DeepCopy()); std::string log_message_json; - base::JSONWriter::Write(&log_message_dict, &log_message_json); + base::JSONWriter::Write(log_message_dict, &log_message_json); // TODO(klm): extract timestamp from params? // Look at where it is for Page, Network, Timeline, and trace events.
diff --git a/chrome/test/chromedriver/server/http_handler.cc b/chrome/test/chromedriver/server/http_handler.cc index 279858c..157b94a 100644 --- a/chrome/test/chromedriver/server/http_handler.cc +++ b/chrome/test/chromedriver/server/http_handler.cc
@@ -709,7 +709,7 @@ body_params.SetString("sessionId", session_id); std::string body; base::JSONWriter::WriteWithOptions( - &body_params, base::JSONWriter::OPTIONS_OMIT_DOUBLE_TYPE_PRESERVATION, + body_params, base::JSONWriter::OPTIONS_OMIT_DOUBLE_TYPE_PRESERVATION, &body); scoped_ptr<net::HttpServerResponseInfo> response( new net::HttpServerResponseInfo(net::HTTP_OK));
diff --git a/chrome/test/chromedriver/server/http_handler_unittest.cc b/chrome/test/chromedriver/server/http_handler_unittest.cc index 55eaeb7..59c191f 100644 --- a/chrome/test/chromedriver/server/http_handler_unittest.cc +++ b/chrome/test/chromedriver/server/http_handler_unittest.cc
@@ -74,7 +74,7 @@ body.SetInteger("value", 1); body.SetString("sessionId", "session_id"); std::string json; - base::JSONWriter::Write(&body, &json); + base::JSONWriter::Write(body, &json); ASSERT_EQ(json, response.body()); } @@ -119,7 +119,7 @@ body.SetInteger("value", 1); body.SetString("sessionId", "session_id"); std::string json; - base::JSONWriter::Write(&body, &json); + base::JSONWriter::Write(body, &json); ASSERT_EQ(json, response.body()); }
diff --git a/chrome/test/data/extensions/api_test/bluetooth_low_energy/register_advertisement/manifest.json b/chrome/test/data/extensions/api_test/bluetooth_low_energy/register_advertisement/manifest.json new file mode 100644 index 0000000..5d4b11f --- /dev/null +++ b/chrome/test/data/extensions/api_test/bluetooth_low_energy/register_advertisement/manifest.json
@@ -0,0 +1,16 @@ +{ + "manifest_version": 2, + "name": "Test the Bluetooth Low Energy registerAdvertisement API", + "version": "1.0", + "app": { + "background": { + "scripts": ["runtest.js"] + } + }, + "bluetooth": { + "low_energy": true, + "peripheral": true, + "uuids": ["1234"] + }, + "key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqbc71rRrqz+62pGVmZGDzTK8P4IHTTyN4jBLBJasDTrRllQp4Pb6INnSr08HQM3aaZMYKWkAJTm4gbCDNzvHfIZMAMY6OZfnm0eqiZnxFFgKgIzdr4Z/EyAXVd1Rm1JKhncde2S/U3zWStDb5iYfWZJBIiWVT98q7cW6sstsMOmrHAIAKCzK+mzycFptlRWzAf+8NR9bq1jNZe+h1kJBgY0xnVlGZm+NIhZd/Ke8Y+G2vM4rtuDvp5971HVV294HD28hWbsoOqBf85gPa6tKE57FhLomi/aJVBVBiCfHExXjK1hB2QeM/r7e8P//ZZPoYszSzHJVBw/heRLFOMezIwIDAQAB" +}
diff --git a/chrome/test/data/extensions/api_test/bluetooth_low_energy/register_advertisement/runtest.js b/chrome/test/data/extensions/api_test/bluetooth_low_energy/register_advertisement/runtest.js new file mode 100644 index 0000000..6ead665e --- /dev/null +++ b/chrome/test/data/extensions/api_test/bluetooth_low_energy/register_advertisement/runtest.js
@@ -0,0 +1,38 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +var registerAdvertisement = + chrome.bluetoothLowEnergy.registerAdvertisement; +var unregisterAdvertisement = + chrome.bluetoothLowEnergy.unregisterAdvertisement; + +var serviceUuidsValue = ['value1', 'value2']; +var manufacturerDataValue = [{id: 321, data: [1, 2, 3]}, + {id: 567, data: [8, 2, 3]}] +var solicitUuidsValue = ['value3', 'value4']; +var serviceDataValue = [{uuid: 'uuid8', data: [1, 2, 3]}, + {uuid: 'uuid36', data: [8, 2, 3]}] + +var advertisement = { + type: 'broadcast', + serviceUuids: serviceUuidsValue, + manufacturerData: manufacturerDataValue, + solicitUuids: solicitUuidsValue, + serviceData: serviceDataValue +}; + +registerAdvertisement(advertisement, function (advertisementId) { + if (chrome.runtime.lastError || !advertisementId) { + chrome.test.fail(chrome.runtime.lastError.message); + return; + } + + unregisterAdvertisement(advertisementId, function () { + if (chrome.runtime.lastError) { + chrome.test.fail(chrome.runtime.lastError.message); + return; + } + chrome.test.succeed(); + }); +});
diff --git a/chrome/test/data/extensions/api_test/file_browser/mount_test/test.js b/chrome/test/data/extensions/api_test/file_browser/mount_test/test.js index ff09363..e288fd5 100644 --- a/chrome/test/data/extensions/api_test/file_browser/mount_test/test.js +++ b/chrome/test/data/extensions/api_test/file_browser/mount_test/test.js
@@ -13,7 +13,9 @@ isParentDevice: false, isReadOnly: false, hasMedia: false, - profile: {profileId: "", displayName: "", isCurrentProfile: true} + configurable: false, + source: 'device', + profile: {profileId: '', displayName: '', isCurrentProfile: true}, }; var expectedVolume2 = { @@ -26,7 +28,9 @@ isParentDevice: true, isReadOnly: true, hasMedia: true, - profile: {profileId: "", displayName: "", isCurrentProfile: true} + configurable: false, + source: 'device', + profile: {profileId: '', displayName: '', isCurrentProfile: true} }; var expectedVolume3 = { @@ -39,7 +43,9 @@ isParentDevice: true, isReadOnly: false, hasMedia: false, - profile: {profileId: "", displayName: "", isCurrentProfile: true} + configurable: false, + source: 'device', + profile: {profileId: '', displayName: '', isCurrentProfile: true} }; var expectedDownloadsVolume = { @@ -48,7 +54,9 @@ volumeType: 'downloads', isReadOnly: false, hasMedia: false, - profile: {profileId: "", displayName: "", isCurrentProfile: true} + configurable: false, + source: 'system', + profile: {profileId: '', displayName: '', isCurrentProfile: true} }; var expectedDriveVolume = { @@ -58,7 +66,9 @@ volumeType: 'drive', isReadOnly: false, hasMedia: false, - profile: {profileId: "", displayName: "", isCurrentProfile: true} + configurable: false, + source: 'network', + profile: {profileId: '', displayName: '', isCurrentProfile: true} }; var expectedArchiveVolume = { @@ -68,7 +78,23 @@ volumeType: 'archive', isReadOnly: true, hasMedia: false, - profile: {profileId: "", displayName: "", isCurrentProfile: true} + configurable: false, + source: 'file', + profile: {profileId: '', displayName: '', isCurrentProfile: true} +}; + +var expectedProvidedVolume = { + volumeId: 'provided:', + volumeLabel: '', + volumeType: 'provided', + isReadOnly: true, + hasMedia: false, + configurable: true, + extensionId: 'testing-extension-id', + source: 'network', + mountContext: 'auto', + fileSystemId: '', + profile: {profileId: '', displayName: '', isCurrentProfile: true} }; // List of expected mount points. @@ -78,9 +104,10 @@ expectedArchiveVolume, expectedDownloadsVolume, expectedDriveVolume, + expectedProvidedVolume, expectedVolume1, expectedVolume2, - expectedVolume3, + expectedVolume3 ]; function validateObject(received, expected, name) {
diff --git a/chrome/test/data/extensions/api_test/file_system_provider/configure/test.js b/chrome/test/data/extensions/api_test/file_system_provider/configure/test.js index 5518d90..4053d11 100644 --- a/chrome/test/data/extensions/api_test/file_system_provider/configure/test.js +++ b/chrome/test/data/extensions/api_test/file_system_provider/configure/test.js
@@ -41,11 +41,11 @@ chrome.test.assertEq('device', extensions[0].source); })); - chrome.fileManagerPrivate.configureProvidedFileSystem(test_util.volumeId, + chrome.fileManagerPrivate.configureVolume(test_util.volumeId, chrome.test.callbackPass(function() {})); }, - // Verify that chrome.fileManager.configureProvidedFileSystem is well wired + // Verify that chrome.fileManager.configureVolume is well wired // to onConfigureRequested(). function configureSuccess() { var configured = false; @@ -59,7 +59,7 @@ chrome.fileSystemProvider.onConfigureRequested.addListener( onConfigureRequested); - chrome.fileManagerPrivate.configureProvidedFileSystem(test_util.volumeId, + chrome.fileManagerPrivate.configureVolume(test_util.volumeId, chrome.test.callbackPass(function() { chrome.test.assertTrue(configured); })); @@ -77,7 +77,7 @@ chrome.fileSystemProvider.onConfigureRequested.addListener( onConfigureRequested); - chrome.fileManagerPrivate.configureProvidedFileSystem(test_util.volumeId, + chrome.fileManagerPrivate.configureVolume(test_util.volumeId, chrome.test.callbackFail('Failed to complete configuration.')); },
diff --git a/chrome/test/data/extensions/api_test/fullscreen/has_permission/window.js b/chrome/test/data/extensions/api_test/fullscreen/has_permission/window.js index fc0876d..dfcbba3 100644 --- a/chrome/test/data/extensions/api_test/fullscreen/has_permission/window.js +++ b/chrome/test/data/extensions/api_test/fullscreen/has_permission/window.js
@@ -6,7 +6,9 @@ function requestFullscreen() { document.onwebkitfullscreenchange = chrome.test.succeed; document.onwebkitfullscreenerror = chrome.test.fail; - document.body.webkitRequestFullscreen(); + chrome.test.runWithUserGesture(function() { + document.body.webkitRequestFullscreen(); + }); }; document.body.onclick = requestFullscreen; // enables manual testing. chrome.test.runTests([requestFullscreen]);
diff --git a/chrome/test/data/extensions/api_test/instance_id/channel/manifest.json b/chrome/test/data/extensions/api_test/instance_id/channel/manifest.json new file mode 100644 index 0000000..36268c2 --- /dev/null +++ b/chrome/test/data/extensions/api_test/instance_id/channel/manifest.json
@@ -0,0 +1,10 @@ +{ + "manifest_version": 2, + "name": "Test InstanceID App", + "version": "1.0", + "description": "Tests InstanceID API", + "background": { + "scripts": ["test.js"] + }, + "permissions": ["gcm"] +}
diff --git a/chrome/test/data/extensions/api_test/instance_id/channel/test.js b/chrome/test/data/extensions/api_test/instance_id/channel/test.js new file mode 100644 index 0000000..298fa2c --- /dev/null +++ b/chrome/test/data/extensions/api_test/instance_id/channel/test.js
@@ -0,0 +1,12 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +chrome.test.runTests([ + function test() { + if (chrome.instanceID) + chrome.test.fail(); + else + chrome.test.succeed(); + } +]);
diff --git a/chrome/test/data/extensions/platform_apps/custom_launcher_page/main.js b/chrome/test/data/extensions/platform_apps/custom_launcher_page/main.js index ce4fdc07..4ccc500 100644 --- a/chrome/test/data/extensions/platform_apps/custom_launcher_page/main.js +++ b/chrome/test/data/extensions/platform_apps/custom_launcher_page/main.js
@@ -31,6 +31,12 @@ }); } +function hideCustomLauncherPage() { + chrome.launcherPage.hide(function() { + chrome.test.sendMessage('launcherPageHidden'); + }); +} + document.addEventListener('DOMContentLoaded', function() { chrome.test.sendMessage('Launched'); });
diff --git a/chromecast/browser/cast_browser_main_parts.cc b/chromecast/browser/cast_browser_main_parts.cc index cab3c615..91b13ce 100644 --- a/chromecast/browser/cast_browser_main_parts.cc +++ b/chromecast/browser/cast_browser_main_parts.cc
@@ -55,6 +55,7 @@ #endif #if defined(USE_AURA) +#include "ui/aura/env.h" #include "ui/aura/test/test_screen.h" #include "ui/gfx/screen.h" #endif @@ -373,6 +374,11 @@ cast_browser_process_->cast_service()->Finalize(); cast_browser_process_->metrics_service_client()->Finalize(); cast_browser_process_.reset(); + +#if defined(USE_AURA) + aura::Env::DeleteInstance(); +#endif + DeregisterKillOnAlarm(); #endif
diff --git a/chromecast/browser/cast_browser_process.cc b/chromecast/browser/cast_browser_process.cc index ccd04ae9..25fcd44 100644 --- a/chromecast/browser/cast_browser_process.cc +++ b/chromecast/browser/cast_browser_process.cc
@@ -18,10 +18,6 @@ #include "components/crash/browser/crash_dump_manager_android.h" #endif // defined(OS_ANDROID) -#if defined(USE_AURA) -#include "ui/aura/env.h" -#endif - namespace chromecast { namespace shell { @@ -44,9 +40,6 @@ DCHECK_EQ(g_instance, this); if (pref_service_) pref_service_->CommitPendingWrite(); -#if defined(USE_AURA) - aura::Env::DeleteInstance(); -#endif g_instance = NULL; }
diff --git a/chromecast/chromecast_tests.gypi b/chromecast/chromecast_tests.gypi index 95ade70..a5a7204f 100644 --- a/chromecast/chromecast_tests.gypi +++ b/chromecast/chromecast_tests.gypi
@@ -12,8 +12,8 @@ 'type': '<(gtest_target_type)', 'dependencies': [ 'chromecast.gyp:cast_base', + '../base/base.gyp:run_all_unittests', '../testing/gtest.gyp:gtest', - '../testing/gtest.gyp:gtest_main', ], 'sources': [ 'base/serializers_unittest.cc',
diff --git a/chromecast/media/cdm/browser_cdm_cast.cc b/chromecast/media/cdm/browser_cdm_cast.cc index 07c3c3e..b62df02 100644 --- a/chromecast/media/cdm/browser_cdm_cast.cc +++ b/chromecast/media/cdm/browser_cdm_cast.cc
@@ -39,6 +39,8 @@ legacy_session_error_cb_ = legacy_session_error_cb; session_keys_change_cb_ = session_keys_change_cb; session_expiration_update_cb_ = session_expiration_update_cb; + + InitializeInternal(); } int BrowserCdmCast::RegisterPlayer(const base::Closure& new_key_cb, @@ -198,5 +200,10 @@ return nullptr; } +// A default empty implementation for subclasses that don't need to provide +// any key system specific initialization. +void BrowserCdmCast::InitializeInternal() { +} + } // namespace media } // namespace chromecast
diff --git a/chromecast/media/cdm/browser_cdm_cast.h b/chromecast/media/cdm/browser_cdm_cast.h index 1f2d8e7..7a83a08d 100644 --- a/chromecast/media/cdm/browser_cdm_cast.h +++ b/chromecast/media/cdm/browser_cdm_cast.h
@@ -77,6 +77,10 @@ private: friend class BrowserCdmCastUi; + // Allow subclasses to override to provide key sysytem specific + // initialization. + virtual void InitializeInternal(); + ::media::SessionMessageCB session_message_cb_; ::media::SessionClosedCB session_closed_cb_; ::media::LegacySessionErrorCB legacy_session_error_cb_;
diff --git a/chromecast/media/cma/backend/audio_video_pipeline_device_unittest.cc b/chromecast/media/cma/backend/audio_video_pipeline_device_unittest.cc index 7374261e..972d20a 100644 --- a/chromecast/media/cma/backend/audio_video_pipeline_device_unittest.cc +++ b/chromecast/media/cma/backend/audio_video_pipeline_device_unittest.cc
@@ -6,6 +6,7 @@ #include "base/basictypes.h" #include "base/bind.h" +#include "base/command_line.h" #include "base/files/file_path.h" #include "base/files/memory_mapped_file.h" #include "base/logging.h" @@ -28,6 +29,7 @@ #include "chromecast/media/cma/base/decoder_config_adapter.h" #include "chromecast/media/cma/test/frame_segmenter_for_test.h" #include "chromecast/media/cma/test/media_component_device_feeder_for_test.h" +#include "chromecast/public/cast_media_shlib.h" #include "chromecast/public/media/decoder_config.h" #include "media/base/audio_decoder_config.h" #include "media/base/buffers.h" @@ -71,6 +73,15 @@ AudioVideoPipelineDeviceTest(); ~AudioVideoPipelineDeviceTest() override; + void SetUp() override { + CastMediaShlib::Initialize( + base::CommandLine::ForCurrentProcess()->argv()); + } + + void TearDown() override { + CastMediaShlib::Finalize(); + } + void ConfigureForFile(std::string filename); void ConfigureForAudioOnly(std::string filename); void ConfigureForVideoOnly(std::string filename, bool raw_h264);
diff --git a/chromecast/public/cast_media_shlib.h b/chromecast/public/cast_media_shlib.h index 8429ca1..6f2d60d 100644 --- a/chromecast/public/cast_media_shlib.h +++ b/chromecast/public/cast_media_shlib.h
@@ -13,15 +13,24 @@ namespace chromecast { namespace media { +// Provides access to platform-specific media systems and hardware resources. +// In cast_shell, all usage is from the browser process. An implementation is +// assumed to be in an uninitialized state initially. When uninitialized, no +// API calls will be made except for Initialize, which brings the implementation +// into an initialized state. A call to Finalize returns the implementation to +// its uninitialized state. The implementation must support multiple +// transitions between these states, to support resource grant/revoke events and +// also to allow multiple unit tests to bring up the media systems in isolation +// from other tests. class CHROMECAST_EXPORT CastMediaShlib { public: - // Performs platform-specific one-time initialization for media systems and - // hardware resources. Called at startup in browser process before main - // message loop begins. + // Initializes platform-specific media systems. Only called when in an + // uninitialized state. static void Initialize(const std::vector<std::string>& argv); - // Performs platform-specific one-time teardown of media systems and hardware - // resources. Called at browser process exit. + // Tears down platform-specific media systems and returns to the uninitialized + // state. The implementation must release all media-related hardware + // resources. static void Finalize(); };
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM index 0cd395f..615513f 100644 --- a/chromeos/CHROMEOS_LKGM +++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@ -7068.0.0 \ No newline at end of file +7072.0.0 \ No newline at end of file
diff --git a/chromeos/dbus/shill_client_unittest_base.cc b/chromeos/dbus/shill_client_unittest_base.cc index 184851a..de82bf0 100644 --- a/chromeos/dbus/shill_client_unittest_base.cc +++ b/chromeos/dbus/shill_client_unittest_base.cc
@@ -54,7 +54,7 @@ void ValueMatcher::DescribeTo(::std::ostream* os) const { std::string expected_value_str; - base::JSONWriter::WriteWithOptions(expected_value_.get(), + base::JSONWriter::WriteWithOptions(*expected_value_, base::JSONWriter::OPTIONS_PRETTY_PRINT, &expected_value_str); *os << "value equals " << expected_value_str; @@ -62,7 +62,7 @@ void ValueMatcher::DescribeNegationTo(::std::ostream* os) const { std::string expected_value_str; - base::JSONWriter::WriteWithOptions(expected_value_.get(), + base::JSONWriter::WriteWithOptions(*expected_value_, base::JSONWriter::OPTIONS_PRETTY_PRINT, &expected_value_str); *os << "value does not equal " << expected_value_str; @@ -393,9 +393,9 @@ const base::DictionaryValue* expected_result, const base::DictionaryValue& result) { std::string expected_result_string; - base::JSONWriter::Write(expected_result, &expected_result_string); + base::JSONWriter::Write(*expected_result, &expected_result_string); std::string result_string; - base::JSONWriter::Write(&result, &result_string); + base::JSONWriter::Write(result, &result_string); EXPECT_EQ(expected_result_string, result_string); }
diff --git a/chromeos/login/auth/user_context.cc b/chromeos/login/auth/user_context.cc index 4f51b34..e5b3fe0 100644 --- a/chromeos/login/auth/user_context.cc +++ b/chromeos/login/auth/user_context.cc
@@ -25,7 +25,8 @@ auth_flow_(other.auth_flow_), user_type_(other.user_type_), public_session_locale_(other.public_session_locale_), - public_session_input_method_(other.public_session_input_method_) { + public_session_input_method_(other.public_session_input_method_), + device_id_(other.device_id_) { } UserContext::UserContext(const std::string& user_id)
diff --git a/chromeos/network/network_configuration_handler.cc b/chromeos/network/network_configuration_handler.cc index d095e57..ac7ea8b 100644 --- a/chromeos/network/network_configuration_handler.cc +++ b/chromeos/network/network_configuration_handler.cc
@@ -65,7 +65,7 @@ iter.Advance()) { std::string v = "******"; if (shill_property_util::IsLoggableShillProperty(iter.key())) - base::JSONWriter::Write(&iter.value(), &v); + base::JSONWriter::Write(iter.value(), &v); NET_LOG(USER) << desc << ": " << path + "." + iter.key() + "=" + v; } }
diff --git a/chromeos/network/network_configuration_handler_unittest.cc b/chromeos/network/network_configuration_handler_unittest.cc index 2772fc9..2b79c4c 100644 --- a/chromeos/network/network_configuration_handler_unittest.cc +++ b/chromeos/network/network_configuration_handler_unittest.cc
@@ -46,7 +46,7 @@ static std::string PrettyJson(const base::DictionaryValue& value) { std::string pretty; base::JSONWriter::WriteWithOptions( - &value, base::JSONWriter::OPTIONS_PRETTY_PRINT, &pretty); + value, base::JSONWriter::OPTIONS_PRETTY_PRINT, &pretty); return pretty; }
diff --git a/chromeos/network/network_state_handler.cc b/chromeos/network/network_state_handler.cc index a8a9ebf9..e7ddbcf 100644 --- a/chromeos/network/network_state_handler.cc +++ b/chromeos/network/network_state_handler.cc
@@ -56,7 +56,7 @@ std::string ValueAsString(const base::Value& value) { std::string vstr; base::JSONWriter::WriteWithOptions( - &value, base::JSONWriter::OPTIONS_OMIT_BINARY_VALUES, &vstr); + value, base::JSONWriter::OPTIONS_OMIT_BINARY_VALUES, &vstr); return vstr.empty() ? "''" : vstr; }
diff --git a/chromeos/network/onc/onc_translator_onc_to_shill.cc b/chromeos/network/onc/onc_translator_onc_to_shill.cc index 9cea033..33b9e8d5 100644 --- a/chromeos/network/onc/onc_translator_onc_to_shill.cc +++ b/chromeos/network/onc/onc_translator_onc_to_shill.cc
@@ -31,7 +31,7 @@ scoped_ptr<base::StringValue> ConvertValueToString(const base::Value& value) { std::string str; if (!value.GetAsString(&str)) - base::JSONWriter::Write(&value, &str); + base::JSONWriter::Write(value, &str); return make_scoped_ptr(new base::StringValue(str)); }
diff --git a/chromeos/network/shill_property_util.cc b/chromeos/network/shill_property_util.cc index a53487b..30a6925 100644 --- a/chromeos/network/shill_property_util.cc +++ b/chromeos/network/shill_property_util.cc
@@ -221,7 +221,7 @@ base::DictionaryValue ui_data_dict; ui_data.FillDictionary(&ui_data_dict); std::string ui_data_blob; - base::JSONWriter::Write(&ui_data_dict, &ui_data_blob); + base::JSONWriter::Write(ui_data_dict, &ui_data_blob); shill_dictionary->SetStringWithoutPathExpansion(shill::kUIDataProperty, ui_data_blob); }
diff --git a/cloud_print/gcp20/prototype/cloud_print_requester.cc b/cloud_print/gcp20/prototype/cloud_print_requester.cc index d46fdf4..cbfdae44 100644 --- a/cloud_print/gcp20/prototype/cloud_print_requester.cc +++ b/cloud_print/gcp20/prototype/cloud_print_requester.cc
@@ -86,10 +86,10 @@ current->SetBoolean("printer/local_printing_enabled", settings.local_printing_enabled); current->SetInteger("xmpp_timeout_value", settings.xmpp_timeout_value); - dictionary.Set("current", current.release()); + dictionary.Set("current", current.Pass()); std::string local_settings; - base::JSONWriter::Write(&dictionary, &local_settings); + base::JSONWriter::Write(dictionary, &local_settings); return local_settings; }
diff --git a/cloud_print/gcp20/prototype/printer.cc b/cloud_print/gcp20/prototype/printer.cc index 9820ace..4309002 100644 --- a/cloud_print/gcp20/prototype/printer.cc +++ b/cloud_print/gcp20/prototype/printer.cc
@@ -193,7 +193,7 @@ std::string Printer::GetRawCdd() { std::string json_str; - base::JSONWriter::WriteWithOptions(&GetCapabilities(), + base::JSONWriter::WriteWithOptions(GetCapabilities(), base::JSONWriter::OPTIONS_PRETTY_PRINT, &json_str); return json_str;
diff --git a/cloud_print/gcp20/prototype/printer_state.cc b/cloud_print/gcp20/prototype/printer_state.cc index 9dedf1d..0d8fead 100644 --- a/cloud_print/gcp20/prototype/printer_state.cc +++ b/cloud_print/gcp20/prototype/printer_state.cc
@@ -71,7 +71,7 @@ json.Set(kCdd, state.cdd->DeepCopy()); std::string json_str; - base::JSONWriter::WriteWithOptions(&json, + base::JSONWriter::WriteWithOptions(json, base::JSONWriter::OPTIONS_PRETTY_PRINT, &json_str); int size = base::checked_cast<int>(json_str.size());
diff --git a/cloud_print/gcp20/prototype/privet_http_server.cc b/cloud_print/gcp20/prototype/privet_http_server.cc index c0334395..90b45a8 100644 --- a/cloud_print/gcp20/prototype/privet_http_server.cc +++ b/cloud_print/gcp20/prototype/privet_http_server.cc
@@ -234,7 +234,7 @@ return status_code; } - base::JSONWriter::WriteWithOptions(json_response.get(), + base::JSONWriter::WriteWithOptions(*json_response, base::JSONWriter::OPTIONS_PRETTY_PRINT, response); return status_code;
diff --git a/cloud_print/service/service_state.cc b/cloud_print/service/service_state.cc index f98c513..789d229 100644 --- a/cloud_print/service/service_state.cc +++ b/cloud_print/service/service_state.cc
@@ -134,8 +134,6 @@ } std::string ServiceState::ToString() { - scoped_ptr<base::DictionaryValue> services(new base::DictionaryValue()); - scoped_ptr<base::DictionaryValue> cloud_print(new base::DictionaryValue()); cloud_print->SetBoolean(kEnabledOptionName, true); @@ -147,12 +145,12 @@ SetNotEmptyJsonString(cloud_print.get(), kXmppAuthTokenOptionName, xmpp_auth_token_); - services->Set(kCloudPrintJsonName, cloud_print.release()); + base::DictionaryValue services; + services.Set(kCloudPrintJsonName, cloud_print.Pass()); std::string json; - base::JSONWriter::WriteWithOptions(services.get(), - base::JSONWriter::OPTIONS_PRETTY_PRINT, - &json); + base::JSONWriter::WriteWithOptions( + services, base::JSONWriter::OPTIONS_PRETTY_PRINT, &json); return json; }
diff --git a/cloud_print/service/win/chrome_launcher.cc b/cloud_print/service/win/chrome_launcher.cc index adf9c24..e9bcee1 100644 --- a/cloud_print/service/win/chrome_launcher.cc +++ b/cloud_print/service/win/chrome_launcher.cc
@@ -133,7 +133,7 @@ if (!proxy_id.empty()) // Reuse proxy id if we already had one. dictionary->SetString(prefs::kCloudPrintProxyId, proxy_id); std::string result; - base::JSONWriter::WriteWithOptions(dictionary, + base::JSONWriter::WriteWithOptions(*dictionary, base::JSONWriter::OPTIONS_PRETTY_PRINT, &result); return result; @@ -276,7 +276,7 @@ base::ListValue printer_list; printer_list.AppendStrings(printers); std::string printers_json; - base::JSONWriter::Write(&printer_list, &printers_json); + base::JSONWriter::Write(printer_list, &printers_json); size_t written = base::WriteFile(printers_file, printers_json.c_str(), printers_json.size());
diff --git a/cloud_print/service/win/service_listener.cc b/cloud_print/service/win/service_listener.cc index f4af6ddc..497aff76 100644 --- a/cloud_print/service/win/service_listener.cc +++ b/cloud_print/service/win/service_listener.cc
@@ -49,7 +49,7 @@ } std::string result; - base::JSONWriter::Write(&environment, &result); + base::JSONWriter::Write(environment, &result); return result; }
diff --git a/components/OWNERS b/components/OWNERS index 6ed83b5..4f7ba090 100644 --- a/components/OWNERS +++ b/components/OWNERS
@@ -63,9 +63,6 @@ per-file data_reduction_proxy*=sclittle@chromium.org per-file data_reduction_proxy*=jeremyim@chromium.org -per-file devtools_bridge.gyp=mnaganov@chromium.org -per-file devtools_bridge.gyp=serya@chromium.org - per-file devtools_discovery.gyp*=dgozman@chromium.org per-file devtools_discovery.gyp*=pfeldman@chromium.org
diff --git a/components/autofill/content/browser/wallet/wallet_client.cc b/components/autofill/content/browser/wallet/wallet_client.cc index b5cd15e..e599b2e 100644 --- a/components/autofill/content/browser/wallet/wallet_client.cc +++ b/components/autofill/content/browser/wallet/wallet_client.cc
@@ -295,7 +295,7 @@ request_dict.SetString(kInstrumentIdKey, instrument_id); std::string json_payload; - base::JSONWriter::Write(&request_dict, &json_payload); + base::JSONWriter::Write(request_dict, &json_payload); std::string escaped_card_verification_number = net::EscapeUrlEncodedData( card_verification_number, true); @@ -339,7 +339,7 @@ request_dict.Set(kRiskCapabilitiesKey, risk_capabilities_list.release()); std::string json_payload; - base::JSONWriter::Write(&request_dict, &json_payload); + base::JSONWriter::Write(request_dict, &json_payload); crypto::RandBytes(&(one_time_pad_[0]), one_time_pad_.size()); @@ -431,7 +431,7 @@ } std::string json_payload; - base::JSONWriter::Write(&request_dict, &json_payload); + base::JSONWriter::Write(request_dict, &json_payload); if (!card_verification_number.empty()) { std::string post_body; @@ -476,7 +476,7 @@ request_dict.SetString(kTransactionCurrencyKey, currency); std::string post_body; - base::JSONWriter::Write(&request_dict, &post_body); + base::JSONWriter::Write(request_dict, &post_body); MakeWalletRequest(GetGetWalletItemsUrl(user_index_), post_body, @@ -515,7 +515,7 @@ request_dict.Set(kAcceptedLegalDocumentKey, docs_list.release()); std::string post_body; - base::JSONWriter::Write(&request_dict, &post_body); + base::JSONWriter::Write(request_dict, &post_body); MakeWalletRequest(GetAcceptLegalDocumentsUrl(user_index_), post_body,
diff --git a/components/autofill/content/browser/wallet/wallet_client_unittest.cc b/components/autofill/content/browser/wallet/wallet_client_unittest.cc index 230776f6..a57bbf5 100644 --- a/components/autofill/content/browser/wallet/wallet_client_unittest.cc +++ b/components/autofill/content/browser/wallet/wallet_client_unittest.cc
@@ -876,7 +876,7 @@ static_cast<base::DictionaryValue*>(root.get()); dict->Remove("api_key", NULL); std::string clean_upload_data; - base::JSONWriter::Write(dict, &clean_upload_data); + base::JSONWriter::Write(*dict, &clean_upload_data); return clean_upload_data; }
diff --git a/components/autofill/content/renderer/autofill_agent.cc b/components/autofill/content/renderer/autofill_agent.cc index b994e4d..bf1f54a 100644 --- a/components/autofill/content/renderer/autofill_agent.cc +++ b/components/autofill/content/renderer/autofill_agent.cc
@@ -388,7 +388,7 @@ if (ignore_text_changes_) return; - if (!WebUserGestureIndicator::isProcessingUserGesture()) + if (!IsUserGesture()) return; // We post a task for doing the Autofill as the caret position is not set @@ -752,6 +752,10 @@ Send(new AutofillHostMsg_HidePopup(routing_id())); } +bool AutofillAgent::IsUserGesture() const { + return WebUserGestureIndicator::isProcessingUserGesture(); +} + void AutofillAgent::didAssociateFormControls(const WebVector<WebNode>& nodes) { for (size_t i = 0; i < nodes.size(); ++i) { WebLocalFrame* frame = nodes[i].document().frame();
diff --git a/components/autofill/content/renderer/autofill_agent.h b/components/autofill/content/renderer/autofill_agent.h index 39d6573..c75d5d6 100644 --- a/components/autofill/content/renderer/autofill_agent.h +++ b/components/autofill/content/renderer/autofill_agent.h
@@ -221,6 +221,10 @@ // Hides any currently showing Autofill popup. void HidePopup(); + // Returns true if the text field change is due to a user gesture. Can be + // overriden in tests. + virtual bool IsUserGesture() const; + // Formerly cached forms for all frames, now only caches forms for the current // frame. FormCache form_cache_;
diff --git a/components/autofill/content/renderer/password_form_conversion_utils.cc b/components/autofill/content/renderer/password_form_conversion_utils.cc index 44fc323..b737f1a 100644 --- a/components/autofill/content/renderer/password_form_conversion_utils.cc +++ b/components/autofill/content/renderer/password_form_conversion_utils.cc
@@ -8,6 +8,7 @@ #include "base/lazy_instance.h" #include "base/memory/scoped_ptr.h" +#include "base/metrics/histogram_macros.h" #include "base/strings/string_util.h" #include "components/autofill/content/renderer/form_autofill_util.h" #include "components/autofill/core/common/form_data_predictions.h" @@ -404,6 +405,14 @@ password_form->new_password_marked_by_site = true; } + if (username_element.isNull()) { + // To get a better idea on how password forms without a username field + // look like, report the total number of text and password fields. + UMA_HISTOGRAM_COUNTS_100( + "PasswordManager.EmptyUsernames.TextAndPasswordFieldCount", + layout_sequence.size()); + } + password_form->scheme = PasswordForm::SCHEME_HTML; password_form->ssl_valid = false; password_form->preferred = false;
diff --git a/components/autofill/core/browser/wallet/real_pan_wallet_client.cc b/components/autofill/core/browser/wallet/real_pan_wallet_client.cc index 9d41ab4..ec7adb5c 100644 --- a/components/autofill/core/browser/wallet/real_pan_wallet_client.cc +++ b/components/autofill/core/browser/wallet/real_pan_wallet_client.cc
@@ -244,7 +244,7 @@ request_dict.SetInteger("expiration_year", value); std::string json_request; - base::JSONWriter::Write(&request_dict, &json_request); + base::JSONWriter::Write(request_dict, &json_request); std::string post_body = base::StringPrintf(kUnmaskCardRequestFormat, net::EscapeUrlEncodedData(json_request, true).c_str(),
diff --git a/components/autofill/core/common/password_form.cc b/components/autofill/core/common/password_form.cc index 41ca1fc..e5edaca9 100644 --- a/components/autofill/core/common/password_form.cc +++ b/components/autofill/core/common/password_form.cc
@@ -160,7 +160,7 @@ std::string form_as_string; base::JSONWriter::WriteWithOptions( - &form_json, base::JSONWriter::OPTIONS_PRETTY_PRINT, &form_as_string); + form_json, base::JSONWriter::OPTIONS_PRETTY_PRINT, &form_as_string); base::TrimWhitespaceASCII(form_as_string, base::TRIM_ALL, &form_as_string); return os << "PasswordForm(" << form_as_string << ")"; }
diff --git a/components/autofill/core/common/save_password_progress_logger.cc b/components/autofill/core/common/save_password_progress_logger.cc index 2fe68c9..f6da10c 100644 --- a/components/autofill/core/common/save_password_progress_logger.cc +++ b/components/autofill/core/common/save_password_progress_logger.cc
@@ -143,7 +143,7 @@ void SavePasswordProgressLogger::LogValue(StringID label, const Value& log) { std::string log_string; bool conversion_to_string_successful = base::JSONWriter::WriteWithOptions( - &log, base::JSONWriter::OPTIONS_PRETTY_PRINT, &log_string); + log, base::JSONWriter::OPTIONS_PRETTY_PRINT, &log_string); DCHECK(conversion_to_string_successful); SendLog(GetStringFromID(label) + ": " + log_string); }
diff --git a/components/bookmarks/browser/bookmark_model_unittest.cc b/components/bookmarks/browser/bookmark_model_unittest.cc index 1f71f01..bf4f917 100644 --- a/components/bookmarks/browser/bookmark_model_unittest.cc +++ b/components/bookmarks/browser/bookmark_model_unittest.cc
@@ -103,6 +103,110 @@ n2->set_date_added(tmp); } +// See comment in PopulateNodeFromString. +using TestNode = ui::TreeNodeWithValue<BookmarkNode::Type>; + +// Does the work of PopulateNodeFromString. index gives the index of the current +// element in description to process. +void PopulateNodeImpl(const std::vector<std::string>& description, + size_t* index, + TestNode* parent) { + while (*index < description.size()) { + const std::string& element = description[*index]; + (*index)++; + if (element == "[") { + // Create a new folder and recurse to add all the children. + // Folders are given a unique named by way of an ever increasing integer + // value. The folders need not have a name, but one is assigned to help + // in debugging. + static int next_folder_id = 1; + TestNode* new_node = new TestNode(base::IntToString16(next_folder_id++), + BookmarkNode::FOLDER); + parent->Add(new_node, parent->child_count()); + PopulateNodeImpl(description, index, new_node); + } else if (element == "]") { + // End the current folder. + return; + } else { + // Add a new URL. + + // All tokens must be space separated. If there is a [ or ] in the name it + // likely means a space was forgotten. + DCHECK(element.find('[') == std::string::npos); + DCHECK(element.find(']') == std::string::npos); + parent->Add(new TestNode(base::UTF8ToUTF16(element), BookmarkNode::URL), + parent->child_count()); + } + } +} + +// Creates and adds nodes to parent based on description. description consists +// of the following tokens (all space separated): +// [ : creates a new USER_FOLDER node. All elements following the [ until the +// next balanced ] is encountered are added as children to the node. +// ] : closes the last folder created by [ so that any further nodes are added +// to the current folders parent. +// text: creates a new URL node. +// For example, "a [b] c" creates the following nodes: +// a 1 c +// | +// b +// In words: a node of type URL with the title a, followed by a folder node with +// the title 1 having the single child of type url with name b, followed by +// the url node with the title c. +// +// NOTE: each name must be unique, and folders are assigned a unique title by +// way of an increasing integer. +void PopulateNodeFromString(const std::string& description, TestNode* parent) { + std::vector<std::string> elements; + base::SplitStringAlongWhitespace(description, &elements); + size_t index = 0; + PopulateNodeImpl(elements, &index, parent); +} + +// Populates the BookmarkNode with the children of parent. +void PopulateBookmarkNode(TestNode* parent, + BookmarkModel* model, + const BookmarkNode* bb_node) { + for (int i = 0; i < parent->child_count(); ++i) { + TestNode* child = parent->GetChild(i); + if (child->value == BookmarkNode::FOLDER) { + const BookmarkNode* new_bb_node = + model->AddFolder(bb_node, i, child->GetTitle()); + PopulateBookmarkNode(child, model, new_bb_node); + } else { + model->AddURL(bb_node, i, child->GetTitle(), + GURL("http://" + base::UTF16ToASCII(child->GetTitle()))); + } + } +} + +// Verifies the contents of the bookmark bar node match the contents of the +// TestNode. +void VerifyModelMatchesNode(TestNode* expected, const BookmarkNode* actual) { + ASSERT_EQ(expected->child_count(), actual->child_count()); + for (int i = 0; i < expected->child_count(); ++i) { + TestNode* expected_child = expected->GetChild(i); + const BookmarkNode* actual_child = actual->GetChild(i); + ASSERT_EQ(expected_child->GetTitle(), actual_child->GetTitle()); + if (expected_child->value == BookmarkNode::FOLDER) { + ASSERT_TRUE(actual_child->type() == BookmarkNode::FOLDER); + // Recurse throught children. + VerifyModelMatchesNode(expected_child, actual_child); + } else { + // No need to check the URL, just the title is enough. + ASSERT_TRUE(actual_child->is_url()); + } + } +} + +void VerifyNoDuplicateIDs(BookmarkModel* model) { + ui::TreeNodeIterator<const BookmarkNode> it(model->root_node()); + base::hash_set<int64> ids; + while (it.has_next()) + ASSERT_TRUE(ids.insert(it.Next()->id()).second); +} + class BookmarkModelTest : public testing::Test, public BookmarkModelObserver { public: @@ -826,165 +930,6 @@ EXPECT_TRUE(model_->HasBookmarks()); } -// See comment in PopulateNodeFromString. -typedef ui::TreeNodeWithValue<BookmarkNode::Type> TestNode; - -// Does the work of PopulateNodeFromString. index gives the index of the current -// element in description to process. -void PopulateNodeImpl(const std::vector<std::string>& description, - size_t* index, - TestNode* parent) { - while (*index < description.size()) { - const std::string& element = description[*index]; - (*index)++; - if (element == "[") { - // Create a new folder and recurse to add all the children. - // Folders are given a unique named by way of an ever increasing integer - // value. The folders need not have a name, but one is assigned to help - // in debugging. - static int next_folder_id = 1; - TestNode* new_node = - new TestNode(base::IntToString16(next_folder_id++), - BookmarkNode::FOLDER); - parent->Add(new_node, parent->child_count()); - PopulateNodeImpl(description, index, new_node); - } else if (element == "]") { - // End the current folder. - return; - } else { - // Add a new URL. - - // All tokens must be space separated. If there is a [ or ] in the name it - // likely means a space was forgotten. - DCHECK(element.find('[') == std::string::npos); - DCHECK(element.find(']') == std::string::npos); - parent->Add(new TestNode(base::UTF8ToUTF16(element), BookmarkNode::URL), - parent->child_count()); - } - } -} - -// Creates and adds nodes to parent based on description. description consists -// of the following tokens (all space separated): -// [ : creates a new USER_FOLDER node. All elements following the [ until the -// next balanced ] is encountered are added as children to the node. -// ] : closes the last folder created by [ so that any further nodes are added -// to the current folders parent. -// text: creates a new URL node. -// For example, "a [b] c" creates the following nodes: -// a 1 c -// | -// b -// In words: a node of type URL with the title a, followed by a folder node with -// the title 1 having the single child of type url with name b, followed by -// the url node with the title c. -// -// NOTE: each name must be unique, and folders are assigned a unique title by -// way of an increasing integer. -void PopulateNodeFromString(const std::string& description, TestNode* parent) { - std::vector<std::string> elements; - base::SplitStringAlongWhitespace(description, &elements); - size_t index = 0; - PopulateNodeImpl(elements, &index, parent); -} - -// Populates the BookmarkNode with the children of parent. -void PopulateBookmarkNode(TestNode* parent, - BookmarkModel* model, - const BookmarkNode* bb_node) { - for (int i = 0; i < parent->child_count(); ++i) { - TestNode* child = parent->GetChild(i); - if (child->value == BookmarkNode::FOLDER) { - const BookmarkNode* new_bb_node = - model->AddFolder(bb_node, i, child->GetTitle()); - PopulateBookmarkNode(child, model, new_bb_node); - } else { - model->AddURL(bb_node, i, child->GetTitle(), - GURL("http://" + base::UTF16ToASCII(child->GetTitle()))); - } - } -} - -// Test class that creates a BookmarkModel with a real history backend. -class BookmarkModelTestWithProfile : public testing::Test { - public: - BookmarkModelTestWithProfile() {} - - protected: - // Verifies the contents of the bookmark bar node match the contents of the - // TestNode. - void VerifyModelMatchesNode(TestNode* expected, const BookmarkNode* actual) { - ASSERT_EQ(expected->child_count(), actual->child_count()); - for (int i = 0; i < expected->child_count(); ++i) { - TestNode* expected_child = expected->GetChild(i); - const BookmarkNode* actual_child = actual->GetChild(i); - ASSERT_EQ(expected_child->GetTitle(), actual_child->GetTitle()); - if (expected_child->value == BookmarkNode::FOLDER) { - ASSERT_TRUE(actual_child->type() == BookmarkNode::FOLDER); - // Recurse throught children. - VerifyModelMatchesNode(expected_child, actual_child); - if (HasFatalFailure()) - return; - } else { - // No need to check the URL, just the title is enough. - ASSERT_TRUE(actual_child->is_url()); - } - } - } - - void VerifyNoDuplicateIDs(BookmarkModel* model) { - ui::TreeNodeIterator<const BookmarkNode> it(model->root_node()); - base::hash_set<int64> ids; - while (it.has_next()) - ASSERT_TRUE(ids.insert(it.Next()->id()).second); - } - - TestBookmarkClient client_; - scoped_ptr<BookmarkModel> model_; -}; - -// Creates a set of nodes in the bookmark bar model, then recreates the -// bookmark bar model which triggers loading from the db and checks the loaded -// structure to make sure it is what we first created. -TEST_F(BookmarkModelTestWithProfile, CreateAndRestore) { - struct TestData { - // Structure of the children of the bookmark bar model node. - const std::string bbn_contents; - // Structure of the children of the other node. - const std::string other_contents; - // Structure of the children of the synced node. - const std::string mobile_contents; - } data[] = { - // See PopulateNodeFromString for a description of these strings. - { "", "" }, - { "a", "b" }, - { "a [ b ]", "" }, - { "", "[ b ] a [ c [ d e [ f ] ] ]" }, - { "a [ b ]", "" }, - { "a b c [ d e [ f ] ]", "g h i [ j k [ l ] ]"}, - }; - for (size_t i = 0; i < arraysize(data); ++i) { - model_ = client_.CreateModel(); - - TestNode bbn; - PopulateNodeFromString(data[i].bbn_contents, &bbn); - PopulateBookmarkNode(&bbn, model_.get(), model_->bookmark_bar_node()); - - TestNode other; - PopulateNodeFromString(data[i].other_contents, &other); - PopulateBookmarkNode(&other, model_.get(), model_->other_node()); - - TestNode mobile; - PopulateNodeFromString(data[i].mobile_contents, &mobile); - PopulateBookmarkNode(&mobile, model_.get(), model_->mobile_node()); - - VerifyModelMatchesNode(&bbn, model_->bookmark_bar_node()); - VerifyModelMatchesNode(&other, model_->other_node()); - VerifyModelMatchesNode(&mobile, model_->mobile_node()); - VerifyNoDuplicateIDs(model_.get()); - } -} - // http://crbug.com/450464 TEST_F(BookmarkModelTest, DISABLED_Sort) { // Populate the bookmark bar node with nodes for 'B', 'a', 'd' and 'C'. @@ -1193,5 +1138,48 @@ EXPECT_FALSE(node.GetMetaInfoMap()); } +// Creates a set of nodes in the bookmark model, and checks that the loaded +// structure is what we first created. +TEST(BookmarkModelTest2, CreateAndRestore) { + struct TestData { + // Structure of the children of the bookmark model node. + const std::string bbn_contents; + // Structure of the children of the other node. + const std::string other_contents; + // Structure of the children of the synced node. + const std::string mobile_contents; + } data[] = { + // See PopulateNodeFromString for a description of these strings. + { "", "" }, + { "a", "b" }, + { "a [ b ]", "" }, + { "", "[ b ] a [ c [ d e [ f ] ] ]" }, + { "a [ b ]", "" }, + { "a b c [ d e [ f ] ]", "g h i [ j k [ l ] ]"}, + }; + TestBookmarkClient client; + scoped_ptr<BookmarkModel> model; + for (size_t i = 0; i < arraysize(data); ++i) { + model = client.CreateModel(); + + TestNode bbn; + PopulateNodeFromString(data[i].bbn_contents, &bbn); + PopulateBookmarkNode(&bbn, model.get(), model->bookmark_bar_node()); + + TestNode other; + PopulateNodeFromString(data[i].other_contents, &other); + PopulateBookmarkNode(&other, model.get(), model->other_node()); + + TestNode mobile; + PopulateNodeFromString(data[i].mobile_contents, &mobile); + PopulateBookmarkNode(&mobile, model.get(), model->mobile_node()); + + VerifyModelMatchesNode(&bbn, model->bookmark_bar_node()); + VerifyModelMatchesNode(&other, model->other_node()); + VerifyModelMatchesNode(&mobile, model->mobile_node()); + VerifyNoDuplicateIDs(model.get()); + } +} + } // namespace } // namespace bookmarks
diff --git a/components/chrome_apps/webstore_widget/app/main.js b/components/chrome_apps/webstore_widget/app/main.js index aca72b3d..2495c5e 100644 --- a/components/chrome_apps/webstore_widget/app/main.js +++ b/components/chrome_apps/webstore_widget/app/main.js
@@ -40,7 +40,8 @@ 'LINK_TO_WEBSTORE': '[LOCALIZE ME] Learn more...', 'INSTALLATION_FAILED_MESSAGE': '[LOCALIZE ME] Installation failed!', 'OK_BUTTON': '[LOCALIZE ME] OK', - 'TITLE_PRINTER_PROVIDERS': '[LOCALIZE ME] Select app for your printer' + 'TITLE_PRINTER_PROVIDERS': '[LOCALIZE ME] Select app for your printer', + 'DEFAULT_ERROR_MESSAGE': '[LOCALIZE ME] Failure' }; /** @@ -121,7 +122,7 @@ function initializeTopbarButtons() { $('close-button').addEventListener('click', function(e) { e.preventDefault(); - chrome.app.window.current().close(); + closeAppWindow(); }); $('close-button').addEventListener('mousedown', function(e) { @@ -138,6 +139,27 @@ }); } +/** + * @param {!CWSWidgetContainer.Result} result The result reported by the widget. + */ +function showWidgetResult(result) { + // TODO(tbarzic): Add some UI to show on success. + if (result != CWSWidgetContainer.Result.FAILED) { + closeAppWindow(); + return; + } + + var dialog = new CWSWidgetContainerErrorDialog($('widget-container-root')); + dialog.show(getString('DEFAULT_ERROR_MESSAGE'), + closeAppWindow, + closeAppWindow); +} + +/** Closes the current app window. */ +function closeAppWindow() { + chrome.app.window.current().close(); +} + window.addEventListener('DOMContentLoaded', function() { initializeTopbarButtons(); @@ -176,12 +198,15 @@ }) /** @param {!CWSWidgetContainer.ResolveReason} reason */ .then(function(reason) { - chrome.app.window.current().close(); + if (reason != CWSWidgetContainer.ResolveReason.DONE) + return; + + var result = widgetContainer.finalizeAndGetResult(); + showWidgetResult(result.result); }) /** @param {*} error */ .catch(function(error) { - // TODO(tbarzic): Add error UI. - console.error(error); + showWidgetResult(CWSWidgetContainer.Result.FAILED); }); }); });
diff --git a/components/chrome_apps/webstore_widget/cws_widget/cws_widget_container.js b/components/chrome_apps/webstore_widget/cws_widget/cws_widget_container.js index 7cffe7a..55640997 100644 --- a/components/chrome_apps/webstore_widget/cws_widget/cws_widget_container.js +++ b/components/chrome_apps/webstore_widget/cws_widget/cws_widget_container.js
@@ -369,6 +369,8 @@ return; } + this.spinnerLayerController_.setVisible(true); + this.metricsRecorder_.recordShowDialog(); this.metricsRecorder_.startLoad(); @@ -379,6 +381,7 @@ this.accessToken_ = accessToken; resolve(); }.bind(this), function(error) { + this.spinnerLayerController_.setVisible(false); this.state_ = CWSWidgetContainer.State.UNINITIALIZED; reject('Failed to get Web Store access token: ' + error); }.bind(this)); @@ -823,8 +826,7 @@ this.visible_ = visible; // Spinner should be shown during transition. - if (!this.spinnerLayer_.classList.contains('cws-widget-show-spinner')) - this.spinnerLayer_.classList.add('cws-widget-show-spinner'); + this.spinnerLayer_.classList.toggle('cws-widget-show-spinner', true); if (this.visible_) { this.spinnerLayer_.focus();
diff --git a/components/cloud_devices/common/cloud_device_description.cc b/components/cloud_devices/common/cloud_device_description.cc index d1cb5041..ba29908 100644 --- a/components/cloud_devices/common/cloud_device_description.cc +++ b/components/cloud_devices/common/cloud_device_description.cc
@@ -47,7 +47,7 @@ std::string CloudDeviceDescription::ToString() const { std::string json; base::JSONWriter::WriteWithOptions( - root_.get(), base::JSONWriter::OPTIONS_PRETTY_PRINT, &json); + *root_, base::JSONWriter::OPTIONS_PRETTY_PRINT, &json); return json; }
diff --git a/components/cloud_devices/common/printer_description_unittest.cc b/components/cloud_devices/common/printer_description_unittest.cc index c1fb455..5c8b182f 100644 --- a/components/cloud_devices/common/printer_description_unittest.cc +++ b/components/cloud_devices/common/printer_description_unittest.cc
@@ -22,7 +22,7 @@ base::ReplaceChars(result, "'", "\"", &result); scoped_ptr<base::Value> value(base::JSONReader::Read(result)); DCHECK(value); - base::JSONWriter::Write(value.get(), &result); + base::JSONWriter::Write(*value, &result); return result; }
diff --git a/components/components_tests.gyp b/components/components_tests.gyp index 1578e704..c5ca9d30 100644 --- a/components/components_tests.gyp +++ b/components/components_tests.gyp
@@ -110,9 +110,11 @@ 'data_reduction_proxy/core/browser/data_reduction_proxy_bypass_protocol_unittest.cc', 'data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats_unittest.cc', 'data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats_unittest.cc', + 'data_reduction_proxy/core/browser/data_reduction_proxy_config_retrieval_params_unittest.cc', 'data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client_unittest.cc', 'data_reduction_proxy/core/browser/data_reduction_proxy_config_unittest.cc', 'data_reduction_proxy/core/browser/data_reduction_proxy_configurator_unittest.cc', + 'data_reduction_proxy/core/browser/data_reduction_proxy_experiments_stats_unittest.cc', 'data_reduction_proxy/core/browser/data_reduction_proxy_interceptor_unittest.cc', 'data_reduction_proxy/core/browser/data_reduction_proxy_io_data_unittest.cc', 'data_reduction_proxy/core/browser/data_reduction_proxy_metrics_unittest.cc',
diff --git a/components/cronet/android/cronet_data_reduction_proxy.cc b/components/cronet/android/cronet_data_reduction_proxy.cc index 1a052346d..f6f47ef3 100644 --- a/components/cronet/android/cronet_data_reduction_proxy.cc +++ b/components/cronet/android/cronet_data_reduction_proxy.cc
@@ -116,7 +116,7 @@ scoped_ptr<data_reduction_proxy::DataReductionProxyService> data_reduction_proxy_service( new data_reduction_proxy::DataReductionProxyService( - compression_stats.Pass(), settings_.get(), + compression_stats.Pass(), settings_.get(), prefs_.get(), url_request_context_getter_.get(), task_runner_)); io_data_->SetDataReductionProxyService( data_reduction_proxy_service->GetWeakPtr());
diff --git a/components/cronet/android/java/src/org/chromium/net/ChromiumUrlRequest.java b/components/cronet/android/java/src/org/chromium/net/ChromiumUrlRequest.java index afccf84..f369e06 100644 --- a/components/cronet/android/java/src/org/chromium/net/ChromiumUrlRequest.java +++ b/components/cronet/android/java/src/org/chromium/net/ChromiumUrlRequest.java
@@ -6,13 +6,13 @@ import android.util.Log; -import org.apache.http.conn.ConnectTimeoutException; import org.chromium.base.CalledByNative; import org.chromium.base.JNINamespace; import org.chromium.base.annotations.SuppressFBWarnings; import java.io.IOException; import java.net.MalformedURLException; +import java.net.SocketTimeoutException; import java.net.URL; import java.net.UnknownHostException; import java.nio.ByteBuffer; @@ -186,7 +186,7 @@ case ChromiumUrlRequestError.MALFORMED_URL: return new MalformedURLException("Malformed URL: " + mUrl); case ChromiumUrlRequestError.CONNECTION_TIMED_OUT: - return new ConnectTimeoutException("Connection timed out"); + return new SocketTimeoutException("Connection timed out"); case ChromiumUrlRequestError.UNKNOWN_HOST: String host; try {
diff --git a/components/cronet/android/java/src/org/chromium/net/HttpUrlConnectionUrlRequest.java b/components/cronet/android/java/src/org/chromium/net/HttpUrlConnectionUrlRequest.java index 88e97ea3..21a2e35 100644 --- a/components/cronet/android/java/src/org/chromium/net/HttpUrlConnectionUrlRequest.java +++ b/components/cronet/android/java/src/org/chromium/net/HttpUrlConnectionUrlRequest.java
@@ -7,8 +7,6 @@ import android.content.Context; import android.text.TextUtils; -import org.apache.http.HttpStatus; - import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; @@ -283,7 +281,7 @@ if (mOffset != 0) { // The server may ignore the request for a byte range. - if (mHttpStatusCode == HttpStatus.SC_OK) { + if (mHttpStatusCode == HttpURLConnection.HTTP_OK) { if (mContentLength != -1) { mContentLength -= mOffset; } @@ -447,8 +445,8 @@ // the status code will be 206, not 200. Since the rest of the // application is // expecting 200 to indicate success, we need to fake it. - if (httpStatusCode == HttpStatus.SC_PARTIAL_CONTENT) { - httpStatusCode = HttpStatus.SC_OK; + if (httpStatusCode == HttpURLConnection.HTTP_PARTIAL) { + httpStatusCode = HttpURLConnection.HTTP_OK; } return httpStatusCode; }
diff --git a/components/data_reduction_proxy.gypi b/components/data_reduction_proxy.gypi index 2fa94c2..4742760e 100644 --- a/components/data_reduction_proxy.gypi +++ b/components/data_reduction_proxy.gypi
@@ -17,12 +17,16 @@ 'data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.h', 'data_reduction_proxy/core/browser/data_reduction_proxy_config.cc', 'data_reduction_proxy/core/browser/data_reduction_proxy_config.h', + 'data_reduction_proxy/core/browser/data_reduction_proxy_config_retrieval_params.cc', + 'data_reduction_proxy/core/browser/data_reduction_proxy_config_retrieval_params.h', 'data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.cc', 'data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.h', 'data_reduction_proxy/core/browser/data_reduction_proxy_configurator.cc', 'data_reduction_proxy/core/browser/data_reduction_proxy_configurator.h', 'data_reduction_proxy/core/browser/data_reduction_proxy_delegate.cc', 'data_reduction_proxy/core/browser/data_reduction_proxy_delegate.h', + 'data_reduction_proxy/core/browser/data_reduction_proxy_experiments_stats.cc', + 'data_reduction_proxy/core/browser/data_reduction_proxy_experiments_stats.h', 'data_reduction_proxy/core/browser/data_reduction_proxy_interceptor.cc', 'data_reduction_proxy/core/browser/data_reduction_proxy_interceptor.h', 'data_reduction_proxy/core/browser/data_reduction_proxy_io_data.cc',
diff --git a/components/data_reduction_proxy/DEPS b/components/data_reduction_proxy/DEPS index 54740c7b..596361d 100644 --- a/components/data_reduction_proxy/DEPS +++ b/components/data_reduction_proxy/DEPS
@@ -1,5 +1,6 @@ include_rules = [ "+components/pref_registry", + "+components/variations", "+crypto", "+google_apis", "+net",
diff --git a/components/data_reduction_proxy/core/browser/BUILD.gn b/components/data_reduction_proxy/core/browser/BUILD.gn index a292f6b..22e939a 100644 --- a/components/data_reduction_proxy/core/browser/BUILD.gn +++ b/components/data_reduction_proxy/core/browser/BUILD.gn
@@ -12,6 +12,8 @@ "data_reduction_proxy_compression_stats.h", "data_reduction_proxy_config.cc", "data_reduction_proxy_config.h", + "data_reduction_proxy_config_retrieval_params.cc", + "data_reduction_proxy_config_retrieval_params.h", "data_reduction_proxy_config_service_client.cc", "data_reduction_proxy_config_service_client.h", "data_reduction_proxy_configurator.cc", @@ -19,6 +21,8 @@ "data_reduction_proxy_debug_ui_service.h", "data_reduction_proxy_delegate.cc", "data_reduction_proxy_delegate.h", + "data_reduction_proxy_experiments_stats.cc", + "data_reduction_proxy_experiments_stats.h", "data_reduction_proxy_interceptor.cc", "data_reduction_proxy_interceptor.h", "data_reduction_proxy_io_data.cc", @@ -93,9 +97,11 @@ "data_reduction_proxy_bypass_protocol_unittest.cc", "data_reduction_proxy_bypass_stats_unittest.cc", "data_reduction_proxy_compression_stats_unittest.cc", + "data_reduction_proxy_config_retrieval_params_unittest.cc", "data_reduction_proxy_config_service_client_unittest.cc", "data_reduction_proxy_config_unittest.cc", "data_reduction_proxy_configurator_unittest.cc", + "data_reduction_proxy_experiments_stats_unittest.cc", "data_reduction_proxy_interceptor_unittest.cc", "data_reduction_proxy_io_data_unittest.cc", "data_reduction_proxy_metrics_unittest.cc",
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats.cc index d1796571..1664cc1 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats.cc +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats.cc
@@ -223,6 +223,21 @@ } } +void DataReductionProxyBypassStats::ClearRequestCounts() { + successful_requests_through_proxy_count_ = 0; + proxy_net_errors_count_ = 0; +} + +void DataReductionProxyBypassStats::NotifyUnavailabilityIfChanged() { + bool prev_unavailable = unavailable_; + unavailable_ = + (proxy_net_errors_count_ >= kMinFailedRequestsWhenUnavailable && + successful_requests_through_proxy_count_ <= + kMaxSuccessfulRequestsWhenUnavailable); + if (prev_unavailable != unavailable_) + unreachable_callback_.Run(unavailable_); +} + void DataReductionProxyBypassStats::RecordBypassedBytesHistograms( const net::URLRequest& request, bool data_reduction_proxy_enabled, @@ -365,21 +380,6 @@ ClearRequestCounts(); } -void DataReductionProxyBypassStats::ClearRequestCounts() { - successful_requests_through_proxy_count_ = 0; - proxy_net_errors_count_ = 0; -} - -void DataReductionProxyBypassStats::NotifyUnavailabilityIfChanged() { - bool prev_unavailable = unavailable_; - unavailable_ = - (proxy_net_errors_count_ >= kMinFailedRequestsWhenUnavailable && - successful_requests_through_proxy_count_ <= - kMaxSuccessfulRequestsWhenUnavailable); - if (prev_unavailable != unavailable_) - unreachable_callback_.Run(unavailable_); -} - void DataReductionProxyBypassStats::RecordBypassedBytes( DataReductionProxyBypassType bypass_type, DataReductionProxyBypassStats::BypassedBytesType bypassed_bytes_type,
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats.h index dcec95e..b13dc949 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats.h +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats.h
@@ -80,6 +80,14 @@ void OnConnectComplete(const net::HostPortPair& proxy_server, int net_error); + // Unconditionally clears counts of successful requests and net errors when + // using the Data Reduction Proxy. + void ClearRequestCounts(); + + // Checks if the availability status of the Data Reduction Proxy has changed, + // and calls |unreachable_callback_| if so. + void NotifyUnavailabilityIfChanged(); + private: friend class DataReductionProxyBypassStatsTest; FRIEND_TEST_ALL_PREFIXES(DataReductionProxyBypassStatsTest, @@ -115,17 +123,6 @@ void OnNetworkChanged( net::NetworkChangeNotifier::ConnectionType type) override; - // Clears request counts unconditionally. - void ClearRequestCounts(); - - // Checks if the availability status of the data reduction proxy has changed, - // and notifies the UIThread via NotifyUnavailabilityOnUIThread if so. The - // data reduction proxy is considered unavailable if and only if no requests - // went through the proxy but some eligible requests were service by other - // routes. - void NotifyUnavailabilityIfChanged(); - void NotifyUnavailabilityOnUIThread(bool unavailable); - void RecordBypassedBytes( DataReductionProxyBypassType bypass_type, BypassedBytesType bypassed_bytes_type,
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_retrieval_params.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_retrieval_params.cc new file mode 100644 index 0000000..9379f67 --- /dev/null +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_retrieval_params.cc
@@ -0,0 +1,270 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_config_retrieval_params.h" + +#include "base/metrics/field_trial.h" +#include "base/metrics/histogram.h" +#include "base/prefs/pref_service.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/string_piece.h" +#include "components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h" +#include "components/variations/variations_associated_data.h" + +namespace { + +// The trial group prefix for which an experiment is considered enabled. +const char kEnabled[] = "Enabled"; + +// The minimum interval (in seconds) at which the config retrieval can occur. +const int kConfigFetchMinimumIntervalSeconds = 300; + +// The default latency base for retrieving the config. +const int kConfigFetchDefaultRoundtripMillisecondsBase = 100; + +// The default latency base for retrieving the config. +const double kConfigFetchDefaultRoundtripMultiplier = 1.0; + +// The default latency base for retrieving the config. +const int kConfigFetchDefaultRoundtripMillisecondsIncrement = 100; + +// The minimum Data Reduction Proxy configuration expiration. +const int kConfigFetchMinimumExpirationSeconds = 5 * 60; + +// The default Data Reduction Proxy configuration expiration. +const int kConfigFetchDefaultExpirationSeconds = 24 * 60 * 60; + +// Based on a histogram prefix |histogram| and |suffix|, retrieves the +// histogram for the expanded histogram name. The histogram is identical to +// the used in UMA_HISTOGRAM_COUNTS. +base::HistogramBase* GetHistogramWithSuffix(const char* histogram, int suffix) { + std::string full_histogram_name = histogram + base::IntToString(suffix); + return base::Histogram::FactoryGet( + full_histogram_name, 1, 1000000, 50, + base::HistogramBase::kUmaTargetedHistogramFlag); +} + +// Retrieves the boolean stored in |variation| from the field trial group +// |group|. If the value is not present or cannot be parsed, returns +// |default_value|. +bool GetVariationBoolWithDefault(const char* group, + const char* variation, + bool default_value) { + std::string variation_value = + variations::GetVariationParamValue(group, variation); + int64 variation_numeric; + if (variation_value.empty() || + !base::StringToInt64(variation_value, &variation_numeric)) { + return default_value; + } + + return variation_numeric != 0; +} + +// Retrieves the int64 stored in |variation| from the field trial group +// |group|. If the value is not present, cannot be parsed, or is less than +// |min_value|, returns |default_value|. +int64 GetVariationInt64WithDefault(const char* group, + const char* variation, + int64 default_value, + int64 min_value) { + DCHECK(default_value >= min_value); + std::string variation_value = + variations::GetVariationParamValue(group, variation); + int64 variation_numeric; + if (variation_value.empty() || + !base::StringToInt64(variation_value, &variation_numeric) || + variation_numeric < min_value) { + return default_value; + } + + return variation_numeric; +} + +// Retrieves the double stored in |variation| from the field trial group +// |group|. If the value is not present, cannot be parsed, or is less than +// |min_value|, returns |default_value|. +double GetVariationDoubleWithDefault(const char* group, + const char* variation, + double default_value, + double min_value) { + DCHECK(default_value >= min_value); + std::string variation_value = + variations::GetVariationParamValue(group, variation); + double variation_numeric; + if (variation_value.empty() || + !base::StringToDouble(variation_value, &variation_numeric) || + variation_numeric < min_value) { + return default_value; + } + + return variation_numeric; +} + +} // namespace + +namespace data_reduction_proxy { + +const int kConfigFetchGroups = 10; + +const char kConfigFetchTrialGroup[] = "DataReductionProxyConfigFetchBytes"; + +const char kConfigRoundtripMillisecondsBaseParam[] = + "config_roundtrip_milliseconds_base"; + +const char kConfigRoundtripMultiplierParam[] = "config_roundtrip_multiplier"; + +const char kConfigRoundtripMillisecondsIncrementParam[] = + "config_roundtrip_milliseconds_increment"; + +const char kConfigExpirationSecondsParam[] = "config_expiration_seconds"; + +const char kConfigAlwaysStaleParam[] = "always_stale"; + +const int kConfigFetchBufferSeconds = 300; + +// static +scoped_ptr<DataReductionProxyConfigRetrievalParams> +DataReductionProxyConfigRetrievalParams::Create(PrefService* pref_service) { + std::string group_value = + base::FieldTrialList::FindFullName(kConfigFetchTrialGroup); + base::StringPiece group = group_value; + if (!group.starts_with(kEnabled)) + return scoped_ptr<DataReductionProxyConfigRetrievalParams>(); + + base::Time now = base::Time::Now(); + base::Time config_retrieve; + bool config_always_stale = GetVariationBoolWithDefault( + kConfigFetchTrialGroup, kConfigAlwaysStaleParam, false); + if (config_always_stale) { + config_retrieve = base::Time(); + } else { + int64 config_retrieve_value = + pref_service->GetInt64(prefs::kSimulatedConfigRetrieveTime); + config_retrieve = base::Time::FromInternalValue(config_retrieve_value); + if (config_retrieve > now) + config_retrieve = base::Time(); + } + + int64 config_expiration_interval_seconds = GetVariationInt64WithDefault( + kConfigFetchTrialGroup, kConfigExpirationSecondsParam, + kConfigFetchDefaultExpirationSeconds, + kConfigFetchMinimumExpirationSeconds); + base::TimeDelta config_expiration_interval = + base::TimeDelta::FromSeconds(config_expiration_interval_seconds); + base::Time config_expiration = config_retrieve + config_expiration_interval; + std::vector<Variation> variations; + bool expired_config = (now > config_expiration); + if (expired_config) { + config_expiration = now + config_expiration_interval; + + int64 config_roundtrip_milliseconds = GetVariationInt64WithDefault( + kConfigFetchTrialGroup, kConfigRoundtripMillisecondsBaseParam, + kConfigFetchDefaultRoundtripMillisecondsBase, 0); + double config_roundtrip_multiplier = GetVariationDoubleWithDefault( + kConfigFetchTrialGroup, kConfigRoundtripMultiplierParam, + kConfigFetchDefaultRoundtripMultiplier, 1.0); + int64 roundtrip_milliseconds_increment = GetVariationInt64WithDefault( + kConfigFetchTrialGroup, kConfigRoundtripMillisecondsIncrementParam, + kConfigFetchDefaultRoundtripMillisecondsIncrement, 0); + + for (int params_index = 0; params_index < kConfigFetchGroups; + ++params_index) { + base::Time config_retrieved = now + base::TimeDelta::FromMilliseconds( + config_roundtrip_milliseconds); + variations.push_back(Variation(params_index, config_retrieved)); + config_roundtrip_milliseconds *= config_roundtrip_multiplier; + config_roundtrip_milliseconds += roundtrip_milliseconds_increment; + } + } + + return scoped_ptr<DataReductionProxyConfigRetrievalParams>( + new DataReductionProxyConfigRetrievalParams(expired_config, variations, + config_expiration, + config_expiration_interval)); +} + +DataReductionProxyConfigRetrievalParams::Variation::Variation( + int index, + const base::Time& simulated_config_retrieved) + : simulated_config_retrieved_(simulated_config_retrieved) { + lost_bytes_ocl_ = GetHistogramWithSuffix( + "DataReductionProxy.ConfigFetchLostBytesOCL_", index); + lost_bytes_rcl_ = GetHistogramWithSuffix( + "DataReductionProxy.ConfigFetchLostBytesCL_", index); + lost_bytes_diff_ = GetHistogramWithSuffix( + "DataReductionProxy.ConfigFetchLostBytesDiff_", index); +} + +DataReductionProxyConfigRetrievalParams::ConfigState +DataReductionProxyConfigRetrievalParams::Variation::GetState( + const base::Time& request_time, + const base::Time& config_expiration) const { + if (!simulated_config_retrieved_.is_null() && + request_time < simulated_config_retrieved_) { + return DataReductionProxyConfigRetrievalParams::RETRIEVING; + } else if (request_time < config_expiration) { + return DataReductionProxyConfigRetrievalParams::VALID; + } + + return DataReductionProxyConfigRetrievalParams::EXPIRED; +} + +void DataReductionProxyConfigRetrievalParams::Variation::RecordStats( + int64 received_content_length, + int64 original_content_length) const { + lost_bytes_rcl_->Add(received_content_length); + lost_bytes_ocl_->Add(original_content_length); + int64 content_length_diff = original_content_length - received_content_length; + if (content_length_diff > 0) + lost_bytes_diff_->Add(content_length_diff); +} + +DataReductionProxyConfigRetrievalParams:: + DataReductionProxyConfigRetrievalParams( + bool loaded_expired_config, + const std::vector<Variation>& variations, + const base::Time& config_expiration, + const base::TimeDelta& config_expiration_interval) + : loaded_expired_config_(loaded_expired_config), + config_expiration_(config_expiration), + config_expiration_interval_(config_expiration_interval), + variations_(variations) { + config_refresh_interval_ = + config_expiration_interval_ - + base::TimeDelta::FromSeconds(kConfigFetchBufferSeconds); + if (config_refresh_interval_.InSeconds() < + kConfigFetchMinimumIntervalSeconds) { + config_refresh_interval_ = + base::TimeDelta::FromSeconds(kConfigFetchMinimumIntervalSeconds); + } +} + +DataReductionProxyConfigRetrievalParams:: + ~DataReductionProxyConfigRetrievalParams() { +} + +void DataReductionProxyConfigRetrievalParams::RecordStats( + const base::Time& request_time, + int64 received_content_length, + int64 original_content_length) const { + for (const auto& variation : variations_) { + switch (variation.GetState(request_time, config_expiration_)) { + case VALID: + break; + case RETRIEVING: + case EXPIRED: + variation.RecordStats(received_content_length, original_content_length); + break; + default: + NOTREACHED(); + } + } +} + +void DataReductionProxyConfigRetrievalParams::RefreshConfig() { + config_expiration_ = base::Time::Now() + config_expiration_interval_; +} + +} // namespace data_reduction_proxy
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_retrieval_params.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_retrieval_params.h new file mode 100644 index 0000000..53aa10a --- /dev/null +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_retrieval_params.h
@@ -0,0 +1,154 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_DATA_REDUCTION_PROXY_CORE_BROWSER_DATA_REDUCTION_PROXY_CONFIG_RETRIEVAL_PARAMS_H_ +#define COMPONENTS_DATA_REDUCTION_PROXY_CORE_BROWSER_DATA_REDUCTION_PROXY_CONFIG_RETRIEVAL_PARAMS_H_ + +#include <vector> + +#include "base/basictypes.h" +#include "base/memory/scoped_ptr.h" +#include "base/time/time.h" + +class PrefService; + +namespace base { +class HistogramBase; +} + +namespace data_reduction_proxy { + +// The number of config fetch variations supported. Must match the number of +// suffixes in histograms.xml. +extern const int kConfigFetchGroups; + +// The name of the trial group for measuring lost bytes during fetching the +// configuration. +extern const char kConfigFetchTrialGroup[]; + +// The config retrieval round trip time is calculated as: +// (previous base) * (multiplier) + increment. +// Multipler is >= 1. Increment is >= 0. +// The name of the param prefix for determining the base round trip time in +// milliseconds for simulating a configuration fetch. +extern const char kConfigRoundtripMillisecondsBaseParam[]; + +// The name of the param prefix for determining the base round trip time in +// milliseconds for simulating a configuration fetch. +extern const char kConfigRoundtripMultiplierParam[]; + +// The name of the param prefix for determining the base round trip time in +// milliseconds for simulating a configuration fetch. +extern const char kConfigRoundtripMillisecondsIncrementParam[]; + +// The name of the param for determining the expiration interval of the +// configuration in seconds. +extern const char kConfigExpirationSecondsParam[]; + +// The name of the param for determining if the config should be considered +// stale on startup (regardless of whether it is stale or not). +extern const char kConfigAlwaysStaleParam[]; + +// The number of seconds by which the expiration interval exceeds the refresh +// interval so that we maintain a valid configuration. +extern const int kConfigFetchBufferSeconds; + +// Parameters for setting up an experiment to measure potentially uncompressed +// bytes during the retrieval of the Data Reduction Proxy configuration. +class DataReductionProxyConfigRetrievalParams { + public: + enum ConfigState { + VALID = 0, + RETRIEVING = 1, + EXPIRED = 2, + }; + + // A variation of the simulated configuration retrieval time, permitting the + // experiment to measure multiple values. + class Variation { + public: + Variation(int index, const base::Time& simulated_config_retrieved); + + // Returns the current state of the Data Reduction Proxy configuration. + // Virtual for testing. + virtual ConfigState GetState(const base::Time& request_time, + const base::Time& config_expiration) const; + + // Records content length statistics if potentially uncompressed bytes have + // been detected for this variation. + void RecordStats(int64 received_content_length, + int64 original_content_length) const; + + // Visible for testing. + const base::Time& simulated_config_retrieved() const { + return simulated_config_retrieved_; + } + + private: + // The time at which the simulated Data Reduction Proxy configuration is + // considered to have been received. + base::Time simulated_config_retrieved_; + + // Histograms for recording stats. + base::HistogramBase* lost_bytes_ocl_; + base::HistogramBase* lost_bytes_rcl_; + base::HistogramBase* lost_bytes_diff_; + }; + + static scoped_ptr<DataReductionProxyConfigRetrievalParams> Create( + PrefService* pref_service); + + virtual ~DataReductionProxyConfigRetrievalParams(); + + // Records content length statistics against any variations for which + // potentially uncompressed bytes have been detected. + void RecordStats(const base::Time& request_time, + int64 received_content_length, + int64 original_content_length) const; + + // Simulates retrieving a new configuration. + void RefreshConfig(); + + bool loaded_expired_config() const { return loaded_expired_config_; } + + // Returns the expiration time of the current configuration. + const base::Time& config_expiration() const { return config_expiration_; } + + // Returns how often the configuration should be retrieved. + const base::TimeDelta& refresh_interval() const { + return config_refresh_interval_; + } + + // Visible for testing. + const std::vector<Variation>& variations() const { return variations_; } + + private: + DataReductionProxyConfigRetrievalParams( + bool loaded_expired_config, + const std::vector<Variation>& variations, + const base::Time& config_expiration, + const base::TimeDelta& config_refresh_interval); + + // Indicates that the Data Reduction Proxy configuration when loaded has + // expired. + bool loaded_expired_config_; + + // The time at which the simulated Data Reduction Proxy configuration + // expires. + base::Time config_expiration_; + + // The duration for which a Data Reduction Proxy configuration is considered + // valid. + base::TimeDelta config_expiration_interval_; + + // The duration after which a simulated retrieval of a new Data Reduction + // Proxy configuration should be performed. + base::TimeDelta config_refresh_interval_; + + // The different variations on roundtrip time that can take place. + std::vector<Variation> variations_; +}; + +} // namespace data_reduction_proxy +#endif // COMPONENTS_DATA_REDUCTION_PROXY_CORE_BROWSER_DATA_REDUCTION_PROXY_CONFIG_RETRIEVAL_PARAMS_H_
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_retrieval_params_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_retrieval_params_unittest.cc new file mode 100644 index 0000000..02f82cb --- /dev/null +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_retrieval_params_unittest.cc
@@ -0,0 +1,228 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_config_retrieval_params.h" + +#include <map> + +#include "base/message_loop/message_loop.h" +#include "base/prefs/pref_service.h" +#include "base/strings/string_number_conversions.h" +#include "base/time/time.h" +#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h" +#include "components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h" +#include "components/variations/variations_associated_data.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace { + +// Test value for how long a Data Reduction Proxy configuration should be valid. +const int64 kConfigExpirationSeconds = 60 * 60 * 24; + +// Checks that |actual| falls in the range of |min| + |delta| and +// |max| + |delta|. +void ExpectInTimeRange(const base::Time& min, + const base::Time& max, + const base::TimeDelta& delta, + const base::Time& actual) { + EXPECT_GE(actual, min + delta); + EXPECT_LE(actual, max + delta); +} + +} // namespace + +namespace data_reduction_proxy { + +class DataReductionProxyConfigRetrievalParamsTest : public testing::Test { + protected: + void SetUp() override { + test_context_ = DataReductionProxyTestContext::Builder().Build(); + } + + void SetConfigExperimentValues( + bool enabled, + const base::TimeDelta& retrieve_offset_from_now, + int64 roundtrip_milliseconds_base, + double roundtrip_multiplier, + int64 roundtrip_milliseconds_increment, + int64 expiration_seconds, + bool always_stale) { + variations::testing::ClearAllVariationParams(); + std::map<std::string, std::string> variation_params; + variation_params[kConfigRoundtripMillisecondsBaseParam] = + base::Int64ToString(roundtrip_milliseconds_base); + variation_params[kConfigRoundtripMultiplierParam] = + base::DoubleToString(roundtrip_multiplier); + variation_params[kConfigRoundtripMillisecondsIncrementParam] = + base::Int64ToString(roundtrip_milliseconds_increment); + variation_params[kConfigExpirationSecondsParam] = + base::Int64ToString(expiration_seconds); + variation_params[kConfigAlwaysStaleParam] = always_stale ? "1" : "0:"; + if (enabled) { + ASSERT_TRUE(variations::AssociateVariationParams( + kConfigFetchTrialGroup, "Enabled", variation_params)); + } + pref_service()->SetInt64( + prefs::kSimulatedConfigRetrieveTime, + (base::Time::Now() + retrieve_offset_from_now).ToInternalValue()); + } + + PrefService* pref_service() { return test_context_->pref_service(); } + + private: + base::MessageLoopForIO message_loop_; + scoped_ptr<DataReductionProxyTestContext> test_context_; +}; + +TEST_F(DataReductionProxyConfigRetrievalParamsTest, ExpectedVariations) { + struct { + bool experiment_enabled; + base::TimeDelta retrieve_offset_from_now; + int64 expiration_seconds; + int64 roundtrip_milliseconds_base; + double roundtrip_multiplier; + int64 roundtrip_milliseconds_increment; + bool always_stale; + bool expected_has_variations; + base::TimeDelta expected_config_expiration_from_now; + base::TimeDelta expected_delta_0; + base::TimeDelta expected_delta_2; + base::TimeDelta expected_delta_5; + } test_cases[] = { + // Experiment is disabled. + {false, + base::TimeDelta::FromHours(-2), + kConfigExpirationSeconds, + 100, + 2.0, + 100, + false, + false, + base::TimeDelta(), + base::TimeDelta(), + base::TimeDelta(), + base::TimeDelta()}, + // Experiment is enabled, but not marked always stale and the last + // retrieval is such that the configuration is still valid. + {true, + base::TimeDelta::FromHours(-2), + kConfigExpirationSeconds, + 100, + 2.0, + 100, + false, + false, + base::TimeDelta::FromHours(22), + base::TimeDelta(), + base::TimeDelta(), + base::TimeDelta()}, + // Experiment is enabled, but not marked always stale with a retrieval + // time sufficiently in the past such that the configuration is expired. + { + true, + base::TimeDelta::FromHours(-26), + kConfigExpirationSeconds, + 100, + 2.0, + 100, + true, + true, + base::TimeDelta::FromSeconds(kConfigExpirationSeconds), + base::TimeDelta::FromMilliseconds(100), + base::TimeDelta::FromMilliseconds(700), + base::TimeDelta::FromMilliseconds(6300), + }, + // Experiment is enabled, marked always stale and the retrieval time is + // recent enough that a configuration would be still valid. + { + true, + base::TimeDelta::FromHours(-2), + kConfigExpirationSeconds, + 100, + 2.0, + 100, + true, + true, + base::TimeDelta::FromSeconds(kConfigExpirationSeconds), + base::TimeDelta::FromMilliseconds(100), + base::TimeDelta::FromMilliseconds(700), + base::TimeDelta::FromMilliseconds(6300), + }, + // Experiment is enabled but values are invalid. + { + true, + base::TimeDelta::FromHours(-2), + -400, + -500, + 0.5, + -300, + true, + true, + base::TimeDelta::FromSeconds(kConfigExpirationSeconds), + base::TimeDelta::FromMilliseconds(100), + base::TimeDelta::FromMilliseconds(300), + base::TimeDelta::FromMilliseconds(600), + }, + // Experiment is enabled, but the last config retrieval time is in the + // future and thus ignored. + { + true, + base::TimeDelta::FromHours(26), + kConfigExpirationSeconds, + 100, + 2.0, + 100, + true, + true, + base::TimeDelta::FromSeconds(kConfigExpirationSeconds), + base::TimeDelta::FromMilliseconds(100), + base::TimeDelta::FromMilliseconds(700), + base::TimeDelta::FromMilliseconds(6300), + }, + }; + + for (const auto& test_case : test_cases) { + base::FieldTrialList field_trial_list(nullptr); + base::FieldTrialList::CreateFieldTrial( + kConfigFetchTrialGroup, + test_case.experiment_enabled ? "Enabled" : "Disabled"); + base::Time min_now = base::Time::Now(); + SetConfigExperimentValues( + test_case.experiment_enabled, test_case.retrieve_offset_from_now, + test_case.roundtrip_milliseconds_base, test_case.roundtrip_multiplier, + test_case.roundtrip_milliseconds_increment, kConfigExpirationSeconds, + test_case.always_stale); + scoped_ptr<DataReductionProxyConfigRetrievalParams> config_params = + DataReductionProxyConfigRetrievalParams::Create(pref_service()); + base::Time max_now = base::Time::Now(); + if (!test_case.experiment_enabled) { + EXPECT_EQ(nullptr, config_params.get()); + continue; + } + + EXPECT_NE(nullptr, config_params.get()); + ExpectInTimeRange(min_now, max_now, + test_case.expected_config_expiration_from_now, + config_params->config_expiration()); + EXPECT_EQ(config_params->refresh_interval(), + base::TimeDelta::FromSeconds(kConfigExpirationSeconds) - + base::TimeDelta::FromSeconds(kConfigFetchBufferSeconds)); + if (test_case.expected_has_variations) { + EXPECT_EQ(kConfigFetchGroups, (int)config_params->variations().size()); + ExpectInTimeRange( + min_now, max_now, test_case.expected_delta_0, + config_params->variations()[0].simulated_config_retrieved()); + ExpectInTimeRange( + min_now, max_now, test_case.expected_delta_2, + config_params->variations()[2].simulated_config_retrieved()); + ExpectInTimeRange( + min_now, max_now, test_case.expected_delta_5, + config_params->variations()[5].simulated_config_retrieved()); + } else { + EXPECT_EQ(0u, config_params->variations().size()); + } + } +} + +} // namespace data_reduction_proxy
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.cc index d6895cd7..b805682 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.cc +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.cc
@@ -198,7 +198,7 @@ scoped_ptr<base::DictionaryValue> values(new base::DictionaryValue()); params_->PopulateConfigResponse(values.get()); request_options_->PopulateConfigResponse(values.get()); - base::JSONWriter::Write(values.get(), &response); + base::JSONWriter::Write(*values, &response); return response; }
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_experiments_stats.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_experiments_stats.cc new file mode 100644 index 0000000..ddf3de1 --- /dev/null +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_experiments_stats.cc
@@ -0,0 +1,67 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_experiments_stats.h" + +#include "base/logging.h" +#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_config_retrieval_params.h" +#include "components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h" + +namespace data_reduction_proxy { + +DataReductionProxyExperimentsStats::DataReductionProxyExperimentsStats( + const Int64ValueSetter& value_setter) + : value_setter_(value_setter), initialized_(false) { + // Constructed on the UI thread, but should be checked on the IO thread. + thread_checker_.DetachFromThread(); +} + +DataReductionProxyExperimentsStats::~DataReductionProxyExperimentsStats() { +} + +void DataReductionProxyExperimentsStats::InitializeOnUIThread(scoped_ptr< + DataReductionProxyConfigRetrievalParams> config_retrieval_params) { + DCHECK(!initialized_); + config_retrieval_params_ = config_retrieval_params.Pass(); + + // This method may be called from the UI thread, but should be checked on the + // IO thread. + thread_checker_.DetachFromThread(); +} + +void DataReductionProxyExperimentsStats::InitializeOnIOThread() { + DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK(!initialized_); + initialized_ = true; + if (config_retrieval_params_) { + if (config_retrieval_params_->loaded_expired_config()) + UpdateSimulatedConfig(); + config_refresh_time_.Start( + FROM_HERE, config_retrieval_params_->refresh_interval(), this, + &DataReductionProxyExperimentsStats::UpdateSimulatedConfig); + } +} + +void DataReductionProxyExperimentsStats::RecordBytes( + const base::Time& request_time, + DataReductionProxyRequestType request_type, + int64 received_content_length, + int64 original_content_length) { + DCHECK(thread_checker_.CalledOnValidThread()); + if (config_retrieval_params_) { + // Only measure requests which flowed through the Data Reduction Proxy. + if (request_type == VIA_DATA_REDUCTION_PROXY) { + config_retrieval_params_->RecordStats( + request_time, received_content_length, original_content_length); + } + } +} + +void DataReductionProxyExperimentsStats::UpdateSimulatedConfig() { + DCHECK(config_retrieval_params_); + value_setter_.Run(prefs::kSimulatedConfigRetrieveTime, + base::Time::Now().ToInternalValue()); +} + +} // namespace data_reduction_proxy
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_experiments_stats.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_experiments_stats.h new file mode 100644 index 0000000..1806d51 --- /dev/null +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_experiments_stats.h
@@ -0,0 +1,80 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_DATA_REDUCTION_PROXY_CORE_BROWSER_DATA_REDUCTION_PROXY_EXPERIMENTS_STATS_H_ +#define COMPONENTS_DATA_REDUCTION_PROXY_CORE_BROWSER_DATA_REDUCTION_PROXY_EXPERIMENTS_STATS_H_ + +#include <string> + +#include "base/basictypes.h" +#include "base/callback.h" +#include "base/macros.h" +#include "base/memory/scoped_ptr.h" +#include "base/threading/thread_checker.h" +#include "base/timer/timer.h" +#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_metrics.h" + +namespace base { +class Time; +} + +namespace data_reduction_proxy { + +class DataReductionProxyConfigRetrievalParams; + +typedef base::Callback<void(const std::string&, int64)> Int64ValueSetter; + +// Collects statistics specific to experiments of which a client may be part. +// Any calls into this class should be as lightweight as possible such that if +// no experiments are being performed, there should be minimal code being +// executed. +// Currently supported experiments are: +// - Measuring potentially uncompressed bytes during simulated config retrieval. +class DataReductionProxyExperimentsStats { + public: + DataReductionProxyExperimentsStats(const Int64ValueSetter& value_setter); + virtual ~DataReductionProxyExperimentsStats(); + + // Initializes |this| on the UI thread. If called, must be called prior to + // InitializeOnIOThread. + void InitializeOnUIThread(scoped_ptr<DataReductionProxyConfigRetrievalParams> + config_retrieval_params); + + // Initializes |this| on the IO thread. + void InitializeOnIOThread(); + + // Collect received bytes for the experiment. + void RecordBytes(const base::Time& request_time, + DataReductionProxyRequestType request_type, + int64 received_content_length, + int64 original_content_length); + + private: + // Updates the simulated expiration of the Data Reduction Proxy configuration + // if |config_retrieval_| is set. + void UpdateSimulatedConfig(); + + // Allows an experiment to persist data to preferences. + Int64ValueSetter value_setter_; + + // Enables measuring of potentially uncompressed bytes during a simulated Data + // Reduction Proxy configuration retrieval. + scoped_ptr<DataReductionProxyConfigRetrievalParams> config_retrieval_params_; + + // If set, periodically updates the simulated expiration of the Data Reduction + // Proxy configuration. + base::RepeatingTimer<DataReductionProxyExperimentsStats> config_refresh_time_; + + // Enforce initialization order. + bool initialized_; + + // Enforce usage on the IO thread. + base::ThreadChecker thread_checker_; + + DISALLOW_COPY_AND_ASSIGN(DataReductionProxyExperimentsStats); +}; + +} // namespace data_reduction_proxy + +#endif // COMPONENTS_DATA_REDUCTION_PROXY_CORE_BROWSER_DATA_REDUCTION_PROXY_EXPERIMENTS_STATS_H_
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_experiments_stats_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_experiments_stats_unittest.cc new file mode 100644 index 0000000..6b1d2d3 --- /dev/null +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_experiments_stats_unittest.cc
@@ -0,0 +1,163 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_experiments_stats.h" + +#include <map> + +#include "base/metrics/field_trial.h" +#include "base/prefs/pref_service.h" +#include "base/strings/string_number_conversions.h" +#include "base/test/histogram_tester.h" +#include "base/time/time.h" +#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_config_retrieval_params.h" +#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h" +#include "components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h" +#include "components/variations/variations_associated_data.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace { + +// Test value for how long a Data Reduction Proxy configuration should be valid. +const int64 kConfigExpirationSeconds = 60 * 60 * 24; + +} // namespace + +namespace data_reduction_proxy { + +class DataReductionProxyExperimentsStatsTest : public testing::Test { + public: + void SetPrefValue(const std::string& path, int64 value) {} + + protected: + void SetUp() override { + test_context_ = DataReductionProxyTestContext::Builder().Build(); + } + + void SetConfigExperimentValues( + bool enabled, + const base::TimeDelta& retrieve_offset_from_now, + int64 roundtrip_milliseconds_base, + double roundtrip_multiplier, + int64 roundtrip_milliseconds_increment, + int64 expiration_seconds, + bool always_stale) { + variations::testing::ClearAllVariationParams(); + std::map<std::string, std::string> variation_params; + variation_params[kConfigRoundtripMillisecondsBaseParam] = + base::Int64ToString(roundtrip_milliseconds_base); + variation_params[kConfigRoundtripMultiplierParam] = + base::DoubleToString(roundtrip_multiplier); + variation_params[kConfigRoundtripMillisecondsIncrementParam] = + base::Int64ToString(roundtrip_milliseconds_increment); + variation_params[kConfigExpirationSecondsParam] = + base::Int64ToString(expiration_seconds); + variation_params[kConfigAlwaysStaleParam] = always_stale ? "1" : "0:"; + if (enabled) { + ASSERT_TRUE(variations::AssociateVariationParams( + kConfigFetchTrialGroup, "Enabled", variation_params)); + } + pref_service()->SetInt64( + prefs::kSimulatedConfigRetrieveTime, + (base::Time::Now() + retrieve_offset_from_now).ToInternalValue()); + } + + PrefService* pref_service() { return test_context_->pref_service(); } + + private: + base::MessageLoopForIO message_loop_; + scoped_ptr<DataReductionProxyTestContext> test_context_; +}; + +TEST_F(DataReductionProxyExperimentsStatsTest, CheckHistogramsNoExperiments) { + scoped_ptr<DataReductionProxyExperimentsStats> experiments_stats( + new DataReductionProxyExperimentsStats( + base::Bind(&DataReductionProxyExperimentsStatsTest::SetPrefValue, + base::Unretained(this)))); + experiments_stats->InitializeOnUIThread( + scoped_ptr<DataReductionProxyConfigRetrievalParams>()); + base::HistogramTester histogram_tester; + experiments_stats->RecordBytes(base::Time::Now(), VIA_DATA_REDUCTION_PROXY, + 500, 1000); + histogram_tester.ExpectTotalCount( + "DataReductionProxy.ConfigFetchLostBytesOCL_0", 0); + histogram_tester.ExpectTotalCount( + "DataReductionProxy.ConfigFetchLostBytesCL_0", 0); + histogram_tester.ExpectTotalCount( + "DataReductionProxy.ConfigFetchLostBytesDiff_0", 0); +} + +TEST_F(DataReductionProxyExperimentsStatsTest, CheckConfigHistograms) { + struct { + DataReductionProxyRequestType request_type; + base::Time request_time; + int64 received_content_length; + int64 original_content_length; + int64 expected_received_content_length; + int64 expected_original_content_length; + int64 expected_diff; + } test_cases[] = { + { + VIA_DATA_REDUCTION_PROXY, + base::Time::Now() + base::TimeDelta::FromMinutes(5), + 500, + 1000, + -1, + -1, + -1, + }, + { + VIA_DATA_REDUCTION_PROXY, base::Time::Now(), 500, 1000, 500, 1000, 500, + }, + { + HTTPS, base::Time::Now(), 500, 1000, -1, -1, -1, + }, + }; + + base::FieldTrialList field_trial_list(nullptr); + base::FieldTrialList::CreateFieldTrial(kConfigFetchTrialGroup, "Enabled"); + SetConfigExperimentValues(true, base::TimeDelta::FromHours(-2), 100, 2.0, + 1000, kConfigExpirationSeconds, true); + scoped_ptr<DataReductionProxyConfigRetrievalParams> config_params = + DataReductionProxyConfigRetrievalParams::Create(pref_service()); + scoped_ptr<DataReductionProxyExperimentsStats> experiments_stats( + new DataReductionProxyExperimentsStats( + base::Bind(&DataReductionProxyExperimentsStatsTest::SetPrefValue, + base::Unretained(this)))); + experiments_stats->InitializeOnUIThread(config_params.Pass()); + for (const auto& test_case : test_cases) { + base::HistogramTester histogram_tester; + experiments_stats->RecordBytes( + test_case.request_time, test_case.request_type, + test_case.received_content_length, test_case.original_content_length); + if (test_case.expected_received_content_length == -1) { + histogram_tester.ExpectTotalCount( + "DataReductionProxy.ConfigFetchLostBytesCL_0", 0); + } else { + histogram_tester.ExpectUniqueSample( + "DataReductionProxy.ConfigFetchLostBytesCL_0", + test_case.expected_received_content_length, 1); + } + + if (test_case.expected_original_content_length == -1) { + histogram_tester.ExpectTotalCount( + "DataReductionProxy.ConfigFetchLostBytesOCL_0", 0); + } else { + histogram_tester.ExpectUniqueSample( + "DataReductionProxy.ConfigFetchLostBytesOCL_0", + test_case.expected_original_content_length, 1); + } + + if (test_case.expected_diff == -1) { + histogram_tester.ExpectTotalCount( + "DataReductionProxy.ConfigFetchLostBytesDiff_0", 0); + } else { + histogram_tester.ExpectUniqueSample( + "DataReductionProxy.ConfigFetchLostBytesDiff_0", + test_case.expected_diff, 1); + } + } +} + +} // namespace data_reduction_proxy
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.cc index 50a303c..9c12d24 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.cc +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.cc
@@ -14,6 +14,7 @@ #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.h" #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_configurator.h" #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate.h" +#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_experiments_stats.h" #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_interceptor.h" #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_mutable_config_values.h" #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.h" @@ -142,6 +143,11 @@ proxy_delegate_.reset( new DataReductionProxyDelegate(request_options_.get(), config_.get())); + // It is safe to use base::Unretained here, since it gets executed + // synchronously on the IO thread, and |this| outlives the caller (since the + // caller is owned by |this|. + experiments_stats_.reset(new DataReductionProxyExperimentsStats(base::Bind( + &DataReductionProxyIOData::SetInt64Pref, base::Unretained(this)))); } DataReductionProxyIOData::DataReductionProxyIOData() @@ -177,6 +183,7 @@ config_->InitializeOnIOThread(basic_url_request_context_getter_.get()); if (config_client_.get()) config_client_->InitializeOnIOThread(url_request_context_getter_); + experiments_stats_->InitializeOnIOThread(); ui_task_runner_->PostTask( FROM_HERE, base::Bind(&DataReductionProxyService::SetIOData, @@ -209,18 +216,31 @@ scoped_ptr<DataReductionProxyNetworkDelegate> network_delegate( new DataReductionProxyNetworkDelegate( wrapped_network_delegate.Pass(), config_.get(), - request_options_.get(), configurator_.get())); + request_options_.get(), configurator_.get(), + experiments_stats_.get())); if (track_proxy_bypass_statistics) network_delegate->InitIODataAndUMA(this, bypass_stats_.get()); return network_delegate.Pass(); } +// TODO(kundaji): Rename this method to something more descriptive. +// Bug http://crbug/488190. void DataReductionProxyIOData::SetProxyPrefs(bool enabled, bool alternative_enabled, bool at_startup) { DCHECK(io_task_runner_->BelongsToCurrentThread()); + DCHECK(url_request_context_getter_->GetURLRequestContext()->proxy_service()); enabled_ = enabled; config_->SetProxyConfig(enabled, alternative_enabled, at_startup); + + // If Data Saver is disabled, reset data reduction proxy state. + if (!enabled) { + net::ProxyService* proxy_service = + url_request_context_getter_->GetURLRequestContext()->proxy_service(); + proxy_service->ClearBadProxiesCache(); + bypass_stats_->ClearRequestCounts(); + bypass_stats_->NotifyUnavailabilityIfChanged(); + } } void DataReductionProxyIOData::UpdateContentLengths( @@ -279,4 +299,12 @@ service_, unreachable)); } +void DataReductionProxyIOData::SetInt64Pref(const std::string& pref_path, + int64 value) { + DCHECK(io_task_runner_->BelongsToCurrentThread()); + ui_task_runner_->PostTask( + FROM_HERE, base::Bind(&DataReductionProxyService::SetInt64Pref, service_, + pref_path, value)); +} + } // namespace data_reduction_proxy
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.h index d68001f6..73a2840 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.h +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.h
@@ -34,6 +34,7 @@ class DataReductionProxyConfigServiceClient; class DataReductionProxyConfigurator; class DataReductionProxyEventCreator; +class DataReductionProxyExperimentsStats; class DataReductionProxyService; // Contains and initializes all Data Reduction Proxy objects that operate on @@ -60,7 +61,8 @@ void ShutdownOnUIThread(); // Sets the Data Reduction Proxy service after it has been created. - void SetDataReductionProxyService( + // Virtual for testing. + virtual void SetDataReductionProxyService( base::WeakPtr<DataReductionProxyService> data_reduction_proxy_service); void RetrieveConfig(); @@ -81,9 +83,7 @@ // configuration should be set. Use the alternative configuration only if // |enabled| and |alternative_enabled| are true. |at_startup| is true only // when DataReductionProxySettings is initialized. - void SetProxyPrefs(bool enabled, - bool alternative_enabled, - bool at_startup); + void SetProxyPrefs(bool enabled, bool alternative_enabled, bool at_startup); // Bridge methods to safely call to the UI thread objects. void UpdateContentLengths(int64 received_content_length, @@ -124,6 +124,10 @@ return config_client_.get(); } + DataReductionProxyExperimentsStats* experiments_stats() const { + return experiments_stats_.get(); + } + net::ProxyDelegate* proxy_delegate() const { return proxy_delegate_.get(); } @@ -153,6 +157,8 @@ private: friend class TestDataReductionProxyIOData; FRIEND_TEST_ALL_PREFIXES(DataReductionProxyIODataTest, TestConstruction); + FRIEND_TEST_ALL_PREFIXES(DataReductionProxyIODataTest, + TestResetBadProxyListOnDisableDataSaver); // Used for testing. DataReductionProxyIOData(); @@ -165,6 +171,9 @@ // Records that the data reduction proxy is unreachable or not. void SetUnreachable(bool unreachable); + // Stores an int64 value in preferences storage. + void SetInt64Pref(const std::string& pref_path, int64 value); + // The type of Data Reduction Proxy client. Client client_; @@ -197,6 +206,9 @@ // Requests new Data Reduction Proxy configurations from a remote service. scoped_ptr<DataReductionProxyConfigServiceClient> config_client_; + // Used to track stats for experiments. + scoped_ptr<DataReductionProxyExperimentsStats> experiments_stats_; + // A net log. net::NetLog* net_log_;
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data_unittest.cc index 24fc634a..80a255b 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data_unittest.cc +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data_unittest.cc
@@ -8,14 +8,21 @@ #include "base/memory/scoped_ptr.h" #include "base/message_loop/message_loop.h" #include "base/message_loop/message_loop_proxy.h" +#include "base/prefs/pref_service.h" #include "base/prefs/testing_pref_service.h" +#include "base/run_loop.h" #include "base/strings/string_number_conversions.h" #include "base/time/time.h" #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_prefs.h" #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options.h" +#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h" #include "components/data_reduction_proxy/core/common/data_reduction_proxy_params.h" +#include "components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h" + #include "net/http/http_network_session.h" #include "net/log/net_log.h" +#include "net/proxy/proxy_info.h" +#include "net/proxy/proxy_service.h" #include "net/socket/next_proto.h" #include "net/url_request/url_request_context.h" #include "net/url_request/url_request_context_getter.h" @@ -144,4 +151,48 @@ io_data->ShutdownOnUIThread(); } +TEST_F(DataReductionProxyIODataTest, TestResetBadProxyListOnDisableDataSaver) { + net::TestURLRequestContext context(false); + scoped_ptr<DataReductionProxyTestContext> drp_test_context = + DataReductionProxyTestContext::Builder() + .WithParamsFlags(DataReductionProxyParams::kAllowed | + DataReductionProxyParams::kFallbackAllowed | + DataReductionProxyParams::kPromoAllowed) + .WithURLRequestContext(&context) + .WithTestConfigurator() + .SkipSettingsInitialization() + .Build(); + + drp_test_context->pref_service()->SetBoolean( + prefs::kDataReductionProxyEnabled, true); + drp_test_context->InitSettings(); + DataReductionProxyIOData* io_data = drp_test_context->io_data(); + std::vector<net::ProxyServer> proxies; + proxies.push_back(net::ProxyServer::FromURI("http://foo1.com", + net::ProxyServer::SCHEME_HTTP)); + net::ProxyService* proxy_service = + io_data->url_request_context_getter_->GetURLRequestContext() + ->proxy_service(); + net::ProxyInfo proxy_info; + proxy_info.UseNamedProxy("http://foo2.com"); + net::BoundNetLog bound_net_log; + const net::ProxyRetryInfoMap& bad_proxy_list = + proxy_service->proxy_retry_info(); + + // Simulate network error to add proxies to the bad proxy list. + proxy_service->MarkProxiesAsBadUntil(proxy_info, base::TimeDelta::FromDays(1), + proxies, bound_net_log); + base::RunLoop().RunUntilIdle(); + + // Verify that there are 2 proxies in the bad proxies list. + EXPECT_EQ(2UL, bad_proxy_list.size()); + + // Turn Data Saver off. + drp_test_context->settings()->SetDataReductionProxyEnabled(false); + base::RunLoop().RunUntilIdle(); + + // Verify that bad proxy list is empty. + EXPECT_EQ(0UL, bad_proxy_list.size()); +} + } // namespace data_reduction_proxy
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.cc index 9a66acdf..706f1729 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.cc +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.cc
@@ -12,6 +12,7 @@ #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats.h" #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_config.h" #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_configurator.h" +#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_experiments_stats.h" #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.h" #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options.h" #include "components/data_reduction_proxy/core/common/data_reduction_proxy_params.h" @@ -76,7 +77,8 @@ scoped_ptr<net::NetworkDelegate> network_delegate, DataReductionProxyConfig* config, DataReductionProxyRequestOptions* request_options, - const DataReductionProxyConfigurator* configurator) + const DataReductionProxyConfigurator* configurator, + DataReductionProxyExperimentsStats* experiments_stats) : LayeredNetworkDelegate(network_delegate.Pass()), received_content_length_(0), original_content_length_(0), @@ -84,9 +86,11 @@ data_reduction_proxy_bypass_stats_(nullptr), data_reduction_proxy_request_options_(request_options), data_reduction_proxy_io_data_(nullptr), - configurator_(configurator) { + configurator_(configurator), + experiments_stats_(experiments_stats) { DCHECK(data_reduction_proxy_config_); DCHECK(data_reduction_proxy_request_options_); + DCHECK(experiments_stats_); } DataReductionProxyNetworkDelegate::~DataReductionProxyNetworkDelegate() { @@ -185,6 +189,9 @@ RecordContentLengthHistograms(received_content_length, original_content_length, freshness_lifetime); + experiments_stats_->RecordBytes(request->request_time(), request_type, + received_content_length, + original_content_length); if (data_reduction_proxy_io_data_ && data_reduction_proxy_bypass_stats_) { data_reduction_proxy_bypass_stats_->RecordBytesHistograms(
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.h index 0290d6e..da13b28 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.h +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.h
@@ -31,6 +31,7 @@ class DataReductionProxyBypassStats; class DataReductionProxyConfig; class DataReductionProxyConfigurator; +class DataReductionProxyExperimentsStats; class DataReductionProxyIOData; class DataReductionProxyRequestOptions; @@ -52,7 +53,8 @@ scoped_ptr<net::NetworkDelegate> network_delegate, DataReductionProxyConfig* config, DataReductionProxyRequestOptions* handler, - const DataReductionProxyConfigurator* configurator); + const DataReductionProxyConfigurator* configurator, + DataReductionProxyExperimentsStats* experiments_stats); ~DataReductionProxyNetworkDelegate() override; // Initializes member variables to record data reduction proxy prefs and @@ -122,6 +124,8 @@ const DataReductionProxyConfigurator* configurator_; + DataReductionProxyExperimentsStats* experiments_stats_; + DISALLOW_COPY_AND_ASSIGN(DataReductionProxyNetworkDelegate); };
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc index b7402b0..897162c1 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc
@@ -82,7 +82,8 @@ new DataReductionProxyNetworkDelegate( scoped_ptr<net::NetworkDelegate>(new TestNetworkDelegate()), config(), test_context_->io_data()->request_options(), - test_context_->configurator())); + test_context_->configurator(), + test_context_->io_data()->experiments_stats())); } const net::ProxyConfig& GetProxyConfig() const {
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_prefs.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_prefs.cc index 2b59e3a..ac95358 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_prefs.cc +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_prefs.cc
@@ -59,6 +59,7 @@ prefs::kDailyOriginalContentLengthViaDataReductionProxy); registry->RegisterListPref(prefs::kDailyContentLengthViaDataReductionProxy); registry->RegisterInt64Pref(prefs::kDailyHttpContentLengthLastUpdateDate, 0L); + registry->RegisterInt64Pref(prefs::kSimulatedConfigRetrieveTime, 0L); } void RegisterSimpleProfilePrefs(PrefRegistrySimple* registry) { @@ -105,6 +106,7 @@ prefs::kDailyContentLengthViaDataReductionProxy); registry->RegisterInt64Pref( prefs::kDailyHttpContentLengthLastUpdateDate, 0L); + registry->RegisterInt64Pref(prefs::kSimulatedConfigRetrieveTime, 0L); } void MigrateStatisticsPrefs(PrefService* local_state_prefs,
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options.cc index 12b67856..f418c98 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options.cc +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options.cc
@@ -25,6 +25,7 @@ #include "components/data_reduction_proxy/core/common/version.h" #include "crypto/random.h" #include "net/base/host_port_pair.h" +#include "net/base/load_flags.h" #include "net/proxy/proxy_server.h" #include "net/url_request/url_request.h" @@ -33,12 +34,19 @@ #endif namespace data_reduction_proxy { - namespace { + std::string FormatOption(const std::string& name, const std::string& value) { return name + "=" + value; } -} //namespace + +bool ShouldForceDisableLoFi(const net::URLRequest* request) { + if (!request) + return false; + return (request->load_flags() & net::LOAD_BYPASS_CACHE) != 0; +} + +} // namespace const char kSessionHeaderOption[] = "ps"; const char kCredentialsHeaderOption[] = "sid"; @@ -126,7 +134,7 @@ void DataReductionProxyRequestOptions::Init() { key_ = GetDefaultKey(), UpdateCredentials(); - UpdateLoFi(); + UpdateLoFi(false); UpdateVersion(); UpdateExperiments(); } @@ -156,10 +164,16 @@ RegenerateRequestHeaderValue(); } -void DataReductionProxyRequestOptions::UpdateLoFi() { +void DataReductionProxyRequestOptions::UpdateLoFi(bool force_disable_lo_fi) { + if (force_disable_lo_fi) { + if (lofi_.empty()) + return; + lofi_ = std::string(); + RegenerateRequestHeaderValue(); + return; + } // LoFi was not enabled, but now is. Add the header option. - if (lofi_.empty() && - DataReductionProxyParams::IsLoFiEnabled()) { + if (lofi_.empty() && DataReductionProxyParams::IsLoFiEnabled()) { lofi_ = "low"; RegenerateRequestHeaderValue(); return; @@ -216,25 +230,25 @@ return; if (proxy_server.is_direct()) return; - MaybeAddRequestHeaderImpl(proxy_server.host_port_pair(), - false, - request_headers); + MaybeAddRequestHeaderImpl(proxy_server.host_port_pair(), false, + request_headers, ShouldForceDisableLoFi(request)); } void DataReductionProxyRequestOptions::MaybeAddProxyTunnelRequestHandler( const net::HostPortPair& proxy_server, net::HttpRequestHeaders* request_headers) { DCHECK(thread_checker_.CalledOnValidThread()); - MaybeAddRequestHeaderImpl(proxy_server, true, request_headers); + MaybeAddRequestHeaderImpl(proxy_server, true, request_headers, false); } void DataReductionProxyRequestOptions::SetHeader( - net::HttpRequestHeaders* headers) { + net::HttpRequestHeaders* headers, + bool force_disable_lo_fi) { base::Time now = Now(); // Authorization credentials must be regenerated if they are expired. if (!use_assigned_credentials_ && (now > credentials_expiration_time_)) UpdateCredentials(); - UpdateLoFi(); + UpdateLoFi(force_disable_lo_fi); const char kChromeProxyHeader[] = "Chrome-Proxy"; std::string header_value; if (headers->HasHeader(kChromeProxyHeader)) { @@ -349,14 +363,15 @@ void DataReductionProxyRequestOptions::MaybeAddRequestHeaderImpl( const net::HostPortPair& proxy_server, bool expect_ssl, - net::HttpRequestHeaders* request_headers) { + net::HttpRequestHeaders* request_headers, + bool force_disable_lo_fi) { if (proxy_server.IsEmpty()) return; if (data_reduction_proxy_config_ && data_reduction_proxy_config_->IsDataReductionProxy(proxy_server, NULL) && data_reduction_proxy_config_->UsingHTTPTunnel(proxy_server) == expect_ssl) { - SetHeader(request_headers); + SetHeader(request_headers, force_disable_lo_fi); } }
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options.h index 82cdf1e..7316ef62 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options.h +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options.h
@@ -132,7 +132,7 @@ void SetSecureSession(const std::string& secure_session); protected: - void SetHeader(net::HttpRequestHeaders* headers); + void SetHeader(net::HttpRequestHeaders* headers, bool force_disable_lo_fi); // Returns a UTF16 string that's the hash of the configured authentication // |key| and |salt|. Returns an empty UTF16 string if no key is configured or @@ -170,8 +170,9 @@ // Updates client type, build, and patch. void UpdateVersion(); - // Updates the value of LoFi and regenerates the header if necessary. - void UpdateLoFi(); + // Updates the value of LoFi and regenerates the header if necessary. The LoFi + // header is not added if the request bypasses the cache. + void UpdateLoFi(bool force_disable_lo_fi); // Update the value of the experiments to be run and regenerate the header if // necessary. @@ -192,7 +193,8 @@ // reduction proxy for HTTP traffic. void MaybeAddRequestHeaderImpl(const net::HostPortPair& proxy_server, bool expect_ssl, - net::HttpRequestHeaders* request_headers); + net::HttpRequestHeaders* request_headers, + bool force_disable_lo_fi); // Regenerates the |header_value_| string which is concatenated to the // Chrome-proxy header.
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options_unittest.cc index 53741a9..ab271aa2 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options_unittest.cc +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options_unittest.cc
@@ -4,6 +4,9 @@ #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options.h" +#include <string> +#include <vector> + #include "base/command_line.h" #include "base/md5.h" #include "base/memory/scoped_ptr.h" @@ -16,9 +19,13 @@ #include "components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h" #include "net/base/auth.h" #include "net/base/host_port_pair.h" +#include "net/base/load_flags.h" #include "net/proxy/proxy_server.h" +#include "net/url_request/url_request.h" +#include "net/url_request/url_request_context.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" +#include "url/gurl.h" namespace { const char kChromeProxyHeader[] = "chrome-proxy"; @@ -138,6 +145,13 @@ request_options_->Init(); } + void CreateRequest(int load_flags) { + net::URLRequestContext* context = + test_context_->request_context_getter()->GetURLRequestContext(); + request_ = context->CreateRequest(GURL(), net::DEFAULT_PRIORITY, nullptr); + request_->SetLoadFlags(load_flags); + } + TestDataReductionProxyParams* params() { return test_context_->config()->test_params(); } @@ -151,9 +165,10 @@ test_context_->RunUntilIdle(); net::HttpRequestHeaders headers; request_options_->MaybeAddRequestHeader( - NULL, - proxy_uri.empty() ? net::ProxyServer() : - net::ProxyServer::FromURI(proxy_uri, net::ProxyServer::SCHEME_HTTP), + request_.get(), + proxy_uri.empty() ? net::ProxyServer() + : net::ProxyServer::FromURI( + proxy_uri, net::ProxyServer::SCHEME_HTTP), &headers); if (expected_header.empty()) { EXPECT_FALSE(headers.HasHeader(kChromeProxyHeader)); @@ -168,6 +183,7 @@ base::MessageLoopForIO message_loop_; scoped_ptr<TestDataReductionProxyRequestOptions> request_options_; scoped_ptr<DataReductionProxyTestContext> test_context_; + scoped_ptr<net::URLRequest> request_; }; TEST_F(DataReductionProxyRequestOptionsTest, AuthHashForSalt) { @@ -287,6 +303,30 @@ VerifyExpectedHeader(params()->DefaultOrigin(), expected_header); } +TEST_F(DataReductionProxyRequestOptionsTest, LoFiReloadSingleImage) { + // Add the LoFi command line switch. + base::CommandLine::ForCurrentProcess()->AppendSwitch( + data_reduction_proxy::switches::kEnableDataReductionProxyLoFi); + + std::string expected_header; + SetHeaderExpectations(kExpectedSession, kExpectedCredentials, std::string(), + kClientStr, std::string(), std::string(), std::string(), + std::vector<std::string>(), &expected_header); + + CreateRequest(net::LOAD_BYPASS_CACHE); + CreateRequestOptions(kBogusVersion); + VerifyExpectedHeader(params()->DefaultOrigin(), expected_header); + + // Check that LoFi turns back on. + SetHeaderExpectations(kExpectedSession, kExpectedCredentials, std::string(), + kClientStr, std::string(), std::string(), "low", + std::vector<std::string>(), &expected_header); + + CreateRequest(net::LOAD_NORMAL); + CreateRequestOptions(kBogusVersion); + VerifyExpectedHeader(params()->DefaultOrigin(), expected_header); +} + TEST_F(DataReductionProxyRequestOptionsTest, SecureSession) { std::string expected_header; SetHeaderExpectations(std::string(), std::string(), kSecureSession,
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.cc index 374489e..9f6b4b0e 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.cc +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.cc
@@ -6,6 +6,7 @@ #include "base/bind.h" #include "base/location.h" +#include "base/prefs/pref_service.h" #include "base/sequenced_task_runner.h" #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.h" #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.h" @@ -18,10 +19,12 @@ DataReductionProxyService::DataReductionProxyService( scoped_ptr<DataReductionProxyCompressionStats> compression_stats, DataReductionProxySettings* settings, + PrefService* prefs, net::URLRequestContextGetter* request_context_getter, scoped_refptr<base::SingleThreadTaskRunner> io_task_runner) : url_request_context_getter_(request_context_getter), settings_(settings), + prefs_(prefs), io_task_runner_(io_task_runner), initialized_(false), weak_factory_(this) { @@ -53,8 +56,10 @@ const base::TimeDelta& commit_delay) { DCHECK(CalledOnValidThread()); DCHECK(!compression_stats_); + DCHECK(!prefs_); + prefs_ = prefs; compression_stats_.reset(new DataReductionProxyCompressionStats( - prefs, ui_task_runner, commit_delay)); + prefs_, ui_task_runner, commit_delay)); } void DataReductionProxyService::UpdateContentLengths( @@ -100,6 +105,12 @@ settings_->SetUnreachable(unreachable); } +void DataReductionProxyService::SetInt64Pref(const std::string& pref_path, + int64 value) { + if (prefs_) + prefs_->SetInt64(pref_path, value); +} + void DataReductionProxyService::SetProxyPrefs(bool enabled, bool alternative_enabled, bool at_startup) {
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.h index 2fbc18d..df2b38b 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.h +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.h
@@ -43,14 +43,16 @@ : public base::NonThreadSafe, public DataReductionProxyEventStorageDelegate { public: - // The caller must ensure that |settings| and |request_context| remain alive - // for the lifetime of the |DataReductionProxyService| instance. This instance + // The caller must ensure that |settings|, |prefs|, |request_context|, and + // |io_task_runner| remain alive for the lifetime of the + // |DataReductionProxyService| instance. |prefs| may be null. This instance // will take ownership of |compression_stats|. // TODO(jeremyim): DataReductionProxyService should own // DataReductionProxySettings and not vice versa. DataReductionProxyService( scoped_ptr<DataReductionProxyCompressionStats> compression_stats, DataReductionProxySettings* settings, + PrefService* prefs, net::URLRequestContextGetter* request_context_getter, scoped_refptr<base::SingleThreadTaskRunner> io_task_runner); @@ -89,6 +91,9 @@ // Records whether the Data Reduction Proxy is unreachable or not. void SetUnreachable(bool unreachable); + // Stores an int64 value in |prefs_|. + void SetInt64Pref(const std::string& pref_path, int64 value); + // Bridge methods to safely call to the UI thread objects. // Virtual for testing. virtual void SetProxyPrefs(bool enabled, @@ -129,6 +134,9 @@ DataReductionProxySettings* settings_; + // A prefs service for storing data. + PrefService* prefs_; + // Used to post tasks to |io_data_|. scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.cc index a9d620d..706648f3d 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.cc +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.cc
@@ -9,6 +9,7 @@ #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.h" #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.h" #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_configurator_test_utils.h" +#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_experiments_stats.h" #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_interceptor.h" #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_mutable_config_values.h" #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.h" @@ -166,10 +167,14 @@ MockDataReductionProxyService::MockDataReductionProxyService( scoped_ptr<DataReductionProxyCompressionStats> compression_stats, DataReductionProxySettings* settings, + PrefService* prefs, net::URLRequestContextGetter* request_context, scoped_refptr<base::SingleThreadTaskRunner> io_task_runner) - : DataReductionProxyService( - compression_stats.Pass(), settings, request_context, io_task_runner) { + : DataReductionProxyService(compression_stats.Pass(), + settings, + prefs, + request_context, + io_task_runner) { } MockDataReductionProxyService::~MockDataReductionProxyService() { @@ -182,8 +187,9 @@ scoped_ptr<DataReductionProxyRequestOptions> request_options, scoped_ptr<DataReductionProxyConfigurator> configurator, scoped_ptr<DataReductionProxyConfigServiceClient> config_client, + scoped_ptr<DataReductionProxyExperimentsStats> experiments_stats, bool enabled) - : DataReductionProxyIOData() { + : DataReductionProxyIOData(), service_set_(false) { io_task_runner_ = task_runner; ui_task_runner_ = task_runner; config_ = config.Pass(); @@ -191,6 +197,7 @@ request_options_ = request_options.Pass(); configurator_ = configurator.Pass(); config_client_ = config_client.Pass(); + experiments_stats_ = experiments_stats.Pass(); bypass_stats_.reset(new DataReductionProxyBypassStats( config_.get(), base::Bind(&DataReductionProxyIOData::SetUnreachable, base::Unretained(this)))); @@ -202,6 +209,15 @@ TestDataReductionProxyIOData::~TestDataReductionProxyIOData() { } +void TestDataReductionProxyIOData::SetDataReductionProxyService( + base::WeakPtr<DataReductionProxyService> data_reduction_proxy_service) { + if (!service_set_) + DataReductionProxyIOData::SetDataReductionProxyService( + data_reduction_proxy_service); + + service_set_ = true; +} + DataReductionProxyTestContext::Builder::Builder() : params_flags_(DataReductionProxyParams::kAllowed | DataReductionProxyParams::kFallbackAllowed | @@ -391,11 +407,14 @@ RegisterSimpleProfilePrefs(pref_service->registry()); + scoped_ptr<DataReductionProxyExperimentsStats> experiments_stats( + new DataReductionProxyExperimentsStats(base::Bind( + &PrefService::SetInt64, base::Unretained(pref_service.get())))); scoped_ptr<TestDataReductionProxyIOData> io_data( new TestDataReductionProxyIOData( task_runner, config.Pass(), event_creator.Pass(), request_options.Pass(), configurator.Pass(), config_client.Pass(), - true /* enabled */)); + experiments_stats.Pass(), true /* enabled */)); io_data->SetSimpleURLRequestContextGetter(request_context_getter); scoped_ptr<DataReductionProxyTestContext> test_context( @@ -476,11 +495,11 @@ if (test_context_flags_ & DataReductionProxyTestContext::USE_MOCK_SERVICE) { return make_scoped_ptr(new MockDataReductionProxyService( - compression_stats.Pass(), settings_.get(), + compression_stats.Pass(), settings_.get(), simple_pref_service_.get(), request_context_getter_.get(), task_runner_)); } else { return make_scoped_ptr(new DataReductionProxyService( - compression_stats.Pass(), settings_.get(), + compression_stats.Pass(), settings_.get(), simple_pref_service_.get(), request_context_getter_.get(), task_runner_)); } }
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h index 004a3a5..5898569 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h
@@ -43,6 +43,7 @@ class DataReductionProxyConfigurator; class DataReductionProxyEventCreator; +class DataReductionProxyExperimentsStats; class DataReductionProxyMutableConfigValues; class DataReductionProxyRequestOptions; class DataReductionProxySettings; @@ -150,6 +151,7 @@ MockDataReductionProxyService( scoped_ptr<DataReductionProxyCompressionStats> compression_stats, DataReductionProxySettings* settings, + PrefService* prefs, net::URLRequestContextGetter* request_context, scoped_refptr<base::SingleThreadTaskRunner> io_task_runner); ~MockDataReductionProxyService() override; @@ -170,9 +172,13 @@ scoped_ptr<DataReductionProxyRequestOptions> request_options, scoped_ptr<DataReductionProxyConfigurator> configurator, scoped_ptr<DataReductionProxyConfigServiceClient> config_client, + scoped_ptr<DataReductionProxyExperimentsStats> experiments_stats, bool enabled); ~TestDataReductionProxyIOData() override; + void SetDataReductionProxyService(base::WeakPtr<DataReductionProxyService> + data_reduction_proxy_service) override; + DataReductionProxyConfigurator* configurator() const { return configurator_.get(); } @@ -189,6 +195,10 @@ base::WeakPtr<DataReductionProxyIOData> GetWeakPtr() { return weak_factory_.GetWeakPtr(); } + + private: + // Allowed SetDataReductionProxyService to be re-entrant. + bool service_set_; }; // Builds a test version of the Data Reduction Proxy stack for use in tests.
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.cc b/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.cc index 50c5e963..35c93f51 100644 --- a/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.cc +++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.cc
@@ -22,8 +22,11 @@ namespace { const char kChromeProxyHeader[] = "chrome-proxy"; + const char kActionValueDelimiter = '='; +const char kChromeProxyLoFiDirective[] = "q=low"; + const char kChromeProxyActionBlockOnce[] = "block-once"; const char kChromeProxyActionBlock[] = "block"; const char kChromeProxyActionBypass[] = "bypass"; @@ -49,6 +52,14 @@ namespace data_reduction_proxy { +const char* chrome_proxy_header() { + return kChromeProxyHeader; +} + +const char* chrome_proxy_lo_fi_directive() { + return kChromeProxyLoFiDirective; +} + bool GetDataReductionProxyActionValue( const net::HttpResponseHeaders* headers, const std::string& action_prefix,
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.h b/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.h index ab94b0f..4505d58 100644 --- a/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.h +++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.h
@@ -64,6 +64,13 @@ DataReductionProxyBypassAction bypass_action; }; +// Gets the header used for data reduction proxy requests and responses. +const char* chrome_proxy_header(); + +// Gets the Chrome-Proxy directive used by data reduction proxy Lo-Fi requests +// and responses. +const char* chrome_proxy_lo_fi_directive(); + // Returns true if the Chrome-Proxy header is present and contains a bypass // delay. Sets |proxy_info->bypass_duration| to the specified delay if greater // than 0, and to 0 otherwise to indicate that the default proxy delay
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_params.cc b/components/data_reduction_proxy/core/common/data_reduction_proxy_params.cc index c47a06d56..3951d09 100644 --- a/components/data_reduction_proxy/core/common/data_reduction_proxy_params.cc +++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_params.cc
@@ -148,6 +148,10 @@ kDataReductionProxyStartSecureDisabled)) return false; + if (FieldTrialList::FindFullName("DataReductionProxySecureProxyAfterCheck") == + kEnabled) + return false; + return true; }
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_params_unittest.cc b/components/data_reduction_proxy/core/common/data_reduction_proxy_params_unittest.cc index aa507412..77c9e4ee 100644 --- a/components/data_reduction_proxy/core/common/data_reduction_proxy_params_unittest.cc +++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_params_unittest.cc
@@ -7,6 +7,7 @@ #include <map> #include "base/command_line.h" +#include "base/metrics/field_trial.h" #include "base/values.h" #include "components/data_reduction_proxy/core/common/data_reduction_proxy_params_test_utils.h" #include "components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h" @@ -767,6 +768,57 @@ "google/hammerhead/hammerhead:5.0/LRX210/1570415:user/release-keys")); } +TEST_F(DataReductionProxyParamsTest, SecureProxyCheckDefault) { + struct { + bool command_line_set; + bool experiment_enabled; + bool in_trial_group; + bool expected_use_by_default; + } test_cases[]{ + { + false, false, false, true, + }, + { + true, false, false, false, + }, + { + true, true, false, false, + }, + { + true, true, true, false, + }, + { + false, true, true, false, + }, + { + false, true, false, true, + }, + }; + + int test_index = 0; + for (const auto& test_case : test_cases) { + // Reset all flags. + base::CommandLine::ForCurrentProcess()->InitFromArgv(0, NULL); + + base::FieldTrialList trial_list(nullptr); + if (test_case.command_line_set) { + base::CommandLine::ForCurrentProcess()->AppendSwitchASCII( + switches::kDataReductionProxyStartSecureDisabled, ""); + } + + if (test_case.experiment_enabled) { + base::FieldTrialList::CreateFieldTrial( + "DataReductionProxySecureProxyAfterCheck", + test_case.in_trial_group ? "Enabled" : "Disabled"); + } + + EXPECT_EQ(test_case.expected_use_by_default, + DataReductionProxyParams::ShouldUseSecureProxyByDefault()) + << test_index; + test_index++; + } +} + TEST_F(DataReductionProxyParamsTest, PopulateConfigResponse) { DataReductionProxyParams params( DataReductionProxyParams::kAllowed |
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.cc b/components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.cc index a086117..9979f38 100644 --- a/components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.cc +++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.cc
@@ -88,6 +88,13 @@ // received over the network. const char kHttpOriginalContentLength[] = "http_original_content_length"; +// Pref to store the retrieval time of the last simulated Data Reduction Proxy +// configuration. This is part of an experiment to see how many bytes are lost +// if the Data Reduction Proxy is not used due to configuration being expired +// or not available. +const char kSimulatedConfigRetrieveTime[] = + "data_reduction.simulated_config_retrieve_time"; + // A boolean specifying whether the data reduction proxy statistics preferences // have migrated from local state to the profile. const char kStatisticsPrefsMigrated[] =
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h b/components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h index 9a9b36a..17660463 100644 --- a/components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h +++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h
@@ -28,6 +28,7 @@ extern const char kDataReductionProxyWasEnabledBefore[]; extern const char kHttpOriginalContentLength[]; extern const char kHttpReceivedContentLength[]; +extern const char kSimulatedConfigRetrieveTime[]; extern const char kStatisticsPrefsMigrated[]; extern const char kUpdateDailyReceivedContentLengths[];
diff --git a/components/devtools_bridge.gyp b/components/devtools_bridge.gyp deleted file mode 100644 index 37c5fce5..0000000 --- a/components/devtools_bridge.gyp +++ /dev/null
@@ -1,98 +0,0 @@ -# Copyright 2014 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -{ - 'targets': [ - { - 'target_name': 'devtools_bridge_jni_headers', - 'type': 'none', - 'sources': [ - 'devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/SessionDependencyFactoryNative.java', - 'devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/apiary/ApiaryClientFactory.java', - ], - 'variables': { - 'jni_gen_package': 'devtools_bridge', - }, - 'includes': [ '../build/jni_generator.gypi' ], - }, - { - 'target_name': 'devtools_bridge', - 'type': 'static_library', - 'sources': [ - 'devtools_bridge/android/apiary_client_factory.cc', - 'devtools_bridge/android/apiary_client_factory.h', - 'devtools_bridge/android/session_dependency_factory_android.cc', - 'devtools_bridge/android/session_dependency_factory_android.h', - 'devtools_bridge/session_dependency_factory.cc', - 'devtools_bridge/session_dependency_factory.h', - 'devtools_bridge/socket_tunnel_connection.cc', - 'devtools_bridge/socket_tunnel_connection.h', - 'devtools_bridge/socket_tunnel_packet_handler.cc', - 'devtools_bridge/socket_tunnel_packet_handler.h', - 'devtools_bridge/socket_tunnel_server.cc', - 'devtools_bridge/socket_tunnel_server.h', - ], - 'dependencies': [ - '../base/base.gyp:base', - '../google_apis/google_apis.gyp:google_apis', - '../third_party/libjingle/libjingle.gyp:libjingle_webrtc', - '../third_party/libjingle/libjingle.gyp:libpeerconnection', - '../third_party/webrtc/base/base.gyp:rtc_base', - 'devtools_bridge_jni_headers', - ], - }, - { - 'target_name': 'devtools_bridge_javalib', - 'type': 'none', - 'variables': { - 'java_in_dir': 'devtools_bridge/android/java', - }, - 'includes': [ '../build/java.gypi' ], - 'dependencies': [ - '../base/base.gyp:base_java', - '../sync/sync.gyp:sync_java', - '../third_party/android_tools/android_tools.gyp:android_support_v13_javalib', - ], - }, - { - 'target_name': 'libdevtools_bridge_natives_so', - 'type': 'shared_library', - 'sources': [ - 'devtools_bridge/test/android/javatests/jni/jni_onload.cc', - ], - 'dependencies': [ - '../base/base.gyp:base', - 'devtools_bridge', - ], - }, - { - 'target_name': 'devtools_bridge_testutils', - 'type': 'none', - 'variables': { - 'java_in_dir': 'devtools_bridge/test/android/javatests', - }, - 'includes': [ '../build/java.gypi' ], - 'dependencies': [ - 'devtools_bridge_javalib', - ], - }, - { - 'target_name': 'devtools_bridge_tests_apk', - 'type': 'none', - 'dependencies': [ - 'devtools_bridge_javalib', - 'devtools_bridge_testutils', - 'libdevtools_bridge_natives_so', - ], - 'variables': { - 'apk_name': 'DevToolsBridgeTest', - 'test_suite_name': 'devtools_bridge_tests', - 'java_in_dir': 'devtools_bridge/android/javatests', - 'native_lib_target': 'libdevtools_bridge_natives_so', - 'is_test_apk': 1, - }, - 'includes': [ '../build/java_apk.gypi' ], - }, - ], -}
diff --git a/components/devtools_bridge/DEPS b/components/devtools_bridge/DEPS deleted file mode 100644 index 7112bb2f..0000000 --- a/components/devtools_bridge/DEPS +++ /dev/null
@@ -1,8 +0,0 @@ -include_rules = [ - "+google_apis", - "+net", - "+third_party/libjingle", - "+third_party/webrtc", - "-chrome", - "-content", -]
diff --git a/components/devtools_bridge/OWNERS b/components/devtools_bridge/OWNERS deleted file mode 100644 index 1b209e2d..0000000 --- a/components/devtools_bridge/OWNERS +++ /dev/null
@@ -1,2 +0,0 @@ -mnaganov@chromium.org -serya@chromium.org
diff --git a/components/devtools_bridge/README b/components/devtools_bridge/README deleted file mode 100644 index 40077c9b..0000000 --- a/components/devtools_bridge/README +++ /dev/null
@@ -1,2 +0,0 @@ -The devtools_bridge component contains code for tunneling DevTools connection -over P2P data channel for remote debugging android devices.
diff --git a/components/devtools_bridge/abstract_data_channel.h b/components/devtools_bridge/abstract_data_channel.h deleted file mode 100644 index 473774e..0000000 --- a/components/devtools_bridge/abstract_data_channel.h +++ /dev/null
@@ -1,77 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_DEVTOOLS_BRIDGE_ABSTRACT_DATA_CHANNEL_H_ -#define COMPONENTS_DEVTOOLS_BRIDGE_ABSTRACT_DATA_CHANNEL_H_ - -#include <string> - -#include "base/callback.h" -#include "base/memory/ref_counted.h" -#include "base/memory/scoped_ptr.h" - -namespace devtools_bridge { - -/** - * WebRTC DataChannel adapter for DevTools bridge. Not thread safe. - */ -class AbstractDataChannel { - public: - AbstractDataChannel() {} - virtual ~AbstractDataChannel() {} - - /** - * Called on WebRTC signaling thread. - */ - class Observer { - public: - Observer() {} - virtual ~Observer() {} - - virtual void OnOpen() = 0; - virtual void OnClose() = 0; - - virtual void OnMessage(const void* data, size_t length) = 0; - - private: - DISALLOW_COPY_AND_ASSIGN(Observer); - }; - - /** - * Proxy for accessing data channel from a different thread. - * May outlive data channel (methods will have no effect if DataChannel - * destroyed). - */ - class Proxy : public base::RefCountedThreadSafe<Proxy> { - public: - virtual void SendBinaryMessage(const void* data, size_t length) = 0; - virtual void Close() = 0; - - protected: - Proxy() {} - virtual ~Proxy() {} - - private: - friend class base::RefCountedThreadSafe<Proxy>; - - DISALLOW_COPY_AND_ASSIGN(Proxy); - }; - - virtual void RegisterObserver(scoped_ptr<Observer> observer) = 0; - virtual void UnregisterObserver() = 0; - - virtual void SendBinaryMessage(void* data, size_t length) = 0; - virtual void SendTextMessage(void* data, size_t length) = 0; - - virtual void Close() = 0; - - virtual scoped_refptr<Proxy> proxy() = 0; - - private: - DISALLOW_COPY_AND_ASSIGN(AbstractDataChannel); -}; - -} // namespace devtools_bridge - -#endif // COMPONENTS_DEVTOOLS_BRIDGE_ABSTRACT_DATA_CHANNEL_H_
diff --git a/components/devtools_bridge/abstract_peer_connection.h b/components/devtools_bridge/abstract_peer_connection.h deleted file mode 100644 index 9fd04a8..0000000 --- a/components/devtools_bridge/abstract_peer_connection.h +++ /dev/null
@@ -1,65 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_DEVTOOLS_BRIDGE_ABSTRACT_PEER_CONNECTION_H_ -#define COMPONENTS_DEVTOOLS_BRIDGE_ABSTRACT_PEER_CONNECTION_H_ - -#include <string> - -#include "base/memory/scoped_ptr.h" - -namespace devtools_bridge { - -class AbstractDataChannel; - -/** - * WebRTC PeerConnection adapter for DevTools bridge. - */ -class AbstractPeerConnection { - public: - /** - * Delegate is called on signaling thread. - */ - class Delegate { - public: - Delegate() {} - virtual ~Delegate() {} - - virtual void OnIceConnectionChange(bool connected) = 0; - virtual void OnIceCandidate( - const std::string& sdp_mid, - int sdp_mline_index, - const std::string& sdp) = 0; - virtual void OnLocalOfferCreatedAndSetSet( - const std::string& description) = 0; - virtual void OnLocalAnswerCreatedAndSetSet( - const std::string& description) = 0; - virtual void OnRemoteDescriptionSet() = 0; - virtual void OnFailure(const std::string& description) = 0; - - private: - DISALLOW_COPY_AND_ASSIGN(Delegate); - }; - - AbstractPeerConnection() {} - virtual ~AbstractPeerConnection() {} - - virtual void CreateAndSetLocalOffer() = 0; - virtual void CreateAndSetLocalAnswer() = 0; - virtual void SetRemoteOffer(const std::string& description) = 0; - virtual void SetRemoteAnswer(const std::string& description) = 0; - virtual void AddIceCandidate( - const std::string& sdp_mid, - int sdp_mline_index, - const std::string& sdp) = 0; - - virtual scoped_ptr<AbstractDataChannel> CreateDataChannel(int channelId) = 0; - - private: - DISALLOW_COPY_AND_ASSIGN(AbstractPeerConnection); -}; - -} // namespace devtools_bridge - -#endif // COMPONENTS_DEVTOOLS_BRIDGE_ABSTRACT_PEER_CONNECTION_H_
diff --git a/components/devtools_bridge/android/DEPS b/components/devtools_bridge/android/DEPS deleted file mode 100644 index c80012b5..0000000 --- a/components/devtools_bridge/android/DEPS +++ /dev/null
@@ -1,3 +0,0 @@ -include_rules = [ - "+jni", -]
diff --git a/components/devtools_bridge/android/apiary_client_factory.cc b/components/devtools_bridge/android/apiary_client_factory.cc deleted file mode 100644 index 2224643f..0000000 --- a/components/devtools_bridge/android/apiary_client_factory.cc +++ /dev/null
@@ -1,41 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/devtools_bridge/android/apiary_client_factory.h" - -#include "base/android/jni_string.h" -#include "google_apis/google_api_keys.h" -#include "jni/ApiaryClientFactory_jni.h" - -using base::android::ConvertUTF8ToJavaString; - -namespace devtools_bridge { -namespace android { - -// static -bool ApiaryClientFactory::RegisterNatives(JNIEnv* env) { - return RegisterNativesImpl(env); -} - -// static -jstring GetAPIKey(JNIEnv* env, jobject jcaller) { - return ConvertUTF8ToJavaString(env, google_apis::GetAPIKey()).Release(); -} - -// static -jstring GetOAuthClientId(JNIEnv* env, jobject jcaller) { - return ConvertUTF8ToJavaString( - env, google_apis::GetOAuth2ClientID( - google_apis::OAuth2Client::CLIENT_MAIN)).Release(); -} - -// static -jstring GetOAuthClientSecret(JNIEnv* env, jobject jcaller) { - return ConvertUTF8ToJavaString( - env, google_apis::GetOAuth2ClientSecret( - google_apis::OAuth2Client::CLIENT_MAIN)).Release(); -} - -} // namespace android -} // namespace devtools_bridge
diff --git a/components/devtools_bridge/android/apiary_client_factory.h b/components/devtools_bridge/android/apiary_client_factory.h deleted file mode 100644 index d44909c..0000000 --- a/components/devtools_bridge/android/apiary_client_factory.h +++ /dev/null
@@ -1,26 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_DEVTOOLS_BRIDGE_ANDROID_APIARY_CLIENT_FACTORY_H_ -#define COMPONENTS_DEVTOOLS_BRIDGE_ANDROID_APIARY_CLIENT_FACTORY_H_ - -#include <jni.h> - -namespace devtools_bridge { -namespace android { - -/** - * Native counterpart of Java |ApiaryClientFactory| in DevTools Bridge. - * Provides access to API keys and OAuth credentials needed for GCD - * robotic account. - */ -class ApiaryClientFactory { - public: - static bool RegisterNatives(JNIEnv* env); -}; - -} // namespace android -} // namespace devtools_bridge - -#endif // COMPONENTS_DEVTOOLS_BRIDGE_ANDROID_APIARY_CLIENT_FACTORY_H_
diff --git a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/AbstractDataChannel.java b/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/AbstractDataChannel.java deleted file mode 100644 index e92c6db..0000000 --- a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/AbstractDataChannel.java +++ /dev/null
@@ -1,77 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.components.devtools_bridge; - -import java.nio.ByteBuffer; - -/** - * Limited view on org.webrtc.DataChannel. Abstraction layer helps with: - * 1. Mocking in tests. There is no need to emulate full set of features of the DataChannel. - * 2. Allows both native and Java API implementation for WebRTC data channel. - * 3. Hides unused features. - * Only SCTP data channels supported. - * Data channel is thread safe (except the dispose method). - */ -public abstract class AbstractDataChannel { - /** - * Observer's callbacks are called on WebRTC signaling thread (or it's equivalent in tests). - */ - public interface Observer { - void onStateChange(State state); - - /** - * TEXT and BINARY messages should be handled equally. Size of the message is - * |message|.remaining(). |message| may reference to a native buffer on stack so - * the reference to the buffer must not outlive the invocation. - */ - void onMessage(ByteBuffer message); - } - - /** - * Type is only significant for JavaScript-based counterpart. TEXT messages will - * be observed as strings, BINARY as ByteArray's. - */ - public enum MessageType { - TEXT, BINARY - } - - /** - * State of the data channel. - * Only 2 states of channel are important here: OPEN and everything else. - */ - public enum State { - OPEN, CLOSED - } - - /** - * Registers an observer. - */ - public abstract void registerObserver(Observer observer); - - /** - * Unregisters the previously registered observer. - * Observer unregistration synchronized with signaling thread. If some data modified - * in observer callbacks without additional synchronization it's safe to access - * this data on the current thread after calling this method. - */ - public abstract void unregisterObserver(); - - /** - * Sending message to the data channel. - * Message size is |message|.remaining(). - */ - public abstract void send(ByteBuffer message, MessageType type); - - /** - * Closing data channel. Both channels in the pair will change state to CLOSED. - */ - public abstract void close(); - - /** - * Releases native objects (if any). Closes data channel. No other methods are allowed after it - * (in multithread scenario needs synchronization with access to the data channel). - */ - public abstract void dispose(); -}
diff --git a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/AbstractPeerConnection.java b/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/AbstractPeerConnection.java deleted file mode 100644 index 3e1fb6a..0000000 --- a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/AbstractPeerConnection.java +++ /dev/null
@@ -1,106 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.components.devtools_bridge; - -/** - * Limited view on org.webrtc.PeerConnection. Abstraction layer helps with: - * 1. Allows both native and Java API implementation. - * 2. Hides unused features. - * Should be accessed on a single thread. - */ -public abstract class AbstractPeerConnection { - /** - * All methods are callen on WebRTC signaling thread. - */ - public interface Observer { - /** - * Called when createAndSetLocalDescription or setRemoteDescription failed. - */ - void onFailure(String description); - - /** - * Called when createAndSetLocalDescription succeeded. - */ - void onLocalDescriptionCreatedAndSet(SessionDescriptionType type, String description); - - /** - * Called when setRemoteDescription succeeded. - */ - void onRemoteDescriptionSet(); - - /** - * New ICE candidate available. String representation defined in the IceCandidate class. - * To be sent to the remote peer connection. - */ - void onIceCandidate(String iceCandidate); - - /** - * Called when connected or disconnected. In disconnected state recovery procedure - * should only rely on signaling channel. - */ - void onIceConnectionChange(boolean connected); - } - - /** - * Type of session description. - */ - public enum SessionDescriptionType { - OFFER, ANSWER - } - - /** - * The result of this method will be invocation onLocalDescriptionCreatedAndSet - * or onFailure on the observer. Should not be called when waiting result of - * setRemoteDescription. - */ - public abstract void createAndSetLocalDescription(SessionDescriptionType type); - - /** - * Result of this method will be invocation onRemoteDescriptionSet or onFailure on the observer. - */ - public abstract void setRemoteDescription(SessionDescriptionType type, String description); - - /** - * Adds a remote ICE candidate. - */ - public abstract void addIceCandidate(String candidate); - - /** - * Destroys native objects. Synchronized with the signaling thread - * (no observer method called when the connection disposed) - */ - public abstract void dispose(); - - /** - * Creates prenegotiated SCTP data channel. - */ - public abstract AbstractDataChannel createDataChannel(int channelId); - - /** - * Helper class which enforces string representation of an ICE candidate. - */ - static class IceCandidate { - public final String sdpMid; - public final int sdpMLineIndex; - public final String sdp; - - public IceCandidate(String sdpMid, int sdpMLineIndex, String sdp) { - this.sdpMid = sdpMid; - this.sdpMLineIndex = sdpMLineIndex; - this.sdp = sdp; - } - - public String toString() { - return sdpMid + ":" + sdpMLineIndex + ":" + sdp; - } - - public static IceCandidate fromString(String candidate) throws IllegalArgumentException { - String[] parts = candidate.split(":", 3); - if (parts.length != 3) - throw new IllegalArgumentException("Expected column separated list."); - return new IceCandidate(parts[0], Integer.parseInt(parts[1]), parts[2]); - } - } -}
diff --git a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/DevToolsBridgeServer.java b/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/DevToolsBridgeServer.java deleted file mode 100644 index 076fe50..0000000 --- a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/DevToolsBridgeServer.java +++ /dev/null
@@ -1,181 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.components.devtools_bridge; - -import android.content.Context; -import android.content.Intent; -import android.content.SharedPreferences; - -import org.chromium.components.devtools_bridge.util.LooperExecutor; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * Responsibility of DevToolsBridgeServer consists of handling commands and managing sessions. - * It designed to live in DevToolsBridgeServiceBase but also may live separately (in tests). - */ -public class DevToolsBridgeServer implements SignalingReceiver { - private final LooperExecutor mExecutor; - private final SessionDependencyFactory mFactory = SessionDependencyFactory.newInstance(); - private final Map<String, ServerSession> mSessions = new HashMap<String, ServerSession>(); - private final GCDNotificationHandler mHandler; - private final Delegate mDelegate; - - /** - * Callback for finding DevTools socket asynchronously. Needed in multiprocess - * scenario when socket name is variable. May be called synchronously. - */ - public interface QuerySocketCallback { - void onSuccess(String socketName); - void onFailure(); - } - - /** - * Delegate abstracts Server from service lifetime management and UI. - */ - public interface Delegate { - Context getContext(); - - // When runs in a service this service should not die when |sessionCount| > 0. - void onSessionCountChange(int sessionCount); - - // Lets query a socket name when starting a new session. Result may change - // (in multiprocess scenario: when browser process stops and then starts again). - void querySocketName(QuerySocketCallback callback); - } - - public DevToolsBridgeServer(Delegate delegate) { - assert delegate != null; - - mExecutor = LooperExecutor.newInstanceForMainLooper(delegate.getContext()); - mHandler = new GCDNotificationHandler(this); - mDelegate = delegate; - } - - private void checkCalledOnHostServiceThread() { - assert mExecutor.isCalledOnSessionThread(); - } - - public Context getContext() { - return mDelegate.getContext(); - } - - public SharedPreferences getPreferences() { - return getPreferences(getContext()); - } - - public static SharedPreferences getPreferences(Context context) { - return context.getSharedPreferences( - DevToolsBridgeServer.class.getName(), Context.MODE_PRIVATE); - } - - public void handleCloudMessage(Intent cloudMessage, Runnable completionHandler) { - if (mHandler.isNotification(cloudMessage)) { - mHandler.onNotification(cloudMessage, completionHandler); - } else { - completionHandler.run(); - } - } - - public void updateCloudMessagesId(String channelId, Runnable completionHandler) { - mHandler.updateCloudMessagesId(channelId, completionHandler); - } - - /** - * Should be called in service's onDestroy. - */ - public void dispose() { - checkCalledOnHostServiceThread(); - - for (ServerSession session : mSessions.values()) { - session.dispose(); - } - mFactory.dispose(); - mHandler.dispose(); - } - - @Override - public void startSession( - final String sessionId, - final RTCConfiguration config, - final String offer, - final SessionBase.NegotiationCallback callback) { - checkCalledOnHostServiceThread(); - if (mSessions.containsKey(sessionId)) { - callback.onFailure("Session " + sessionId + " already exists"); - return; - } - - mDelegate.querySocketName(new QuerySocketCallback() { - @Override - public void onSuccess(String socketName) { - ServerSession session = new ServerSession(mFactory, mExecutor, socketName); - session.setEventListener(new SessionEventListener(sessionId)); - mSessions.put(sessionId, session); - session.startSession(config, offer, callback); - mDelegate.onSessionCountChange(mSessions.size()); - } - - @Override - public void onFailure() { - callback.onFailure("Socket not available"); - } - }); - } - - @Override - public void renegotiate( - String sessionId, - String offer, - SessionBase.NegotiationCallback callback) { - checkCalledOnHostServiceThread(); - if (!mSessions.containsKey(sessionId)) { - callback.onFailure("Session does not exist"); - return; - } - ServerSession session = mSessions.get(sessionId); - session.renegotiate(offer, callback); - } - - @Override - public void iceExchange( - String sessionId, - List<String> clientCandidates, - SessionBase.IceExchangeCallback callback) { - checkCalledOnHostServiceThread(); - if (!mSessions.containsKey(sessionId)) { - callback.onFailure("Session does not exist"); - return; - } - ServerSession session = mSessions.get(sessionId); - session.iceExchange(clientCandidates, callback); - } - - private class SessionEventListener implements SessionBase.EventListener { - private final String mSessionId; - - public SessionEventListener(String sessionId) { - mSessionId = sessionId; - } - - public void onCloseSelf() { - checkCalledOnHostServiceThread(); - - mSessions.remove(mSessionId); - mDelegate.onSessionCountChange(mSessions.size()); - } - } - - public void closeAllSessions() { - if (mSessions.isEmpty()) return; - for (ServerSession session : mSessions.values()) { - session.stop(); - } - mSessions.clear(); - mDelegate.onSessionCountChange(mSessions.size()); - } -}
diff --git a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/DevToolsBridgeServiceBase.java b/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/DevToolsBridgeServiceBase.java deleted file mode 100644 index f893592..0000000 --- a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/DevToolsBridgeServiceBase.java +++ /dev/null
@@ -1,151 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.components.devtools_bridge; - -import android.app.Service; -import android.content.Context; -import android.content.Intent; -import android.os.IBinder; -import android.os.Looper; -import android.support.v4.content.WakefulBroadcastReceiver; - -import com.google.ipc.invalidation.external.client.contrib.MultiplexingGcmListener; - -/** - * Base class for a service which hosts DevToolsBridgeServer. It relies on Cloud Messages - * intents rebroadcasted via MultiplexingGcmListener. It intentionally doesn't inherit from - * MultiplexingGcmListener.AbstractListener because this service may not be IntentService - * due to lifetime management restrictions of it. - * - * Service lives while any intent being processed or any client connected. - * TODO(serya): Service lifetime management code should be moved here from DevToolsBridgeServer. - */ -public abstract class DevToolsBridgeServiceBase extends Service { - private static final String WAKELOCK_KEY = "DevToolsBridgeService.WAKELOCK"; - - /** - * Delivers intents from MultiplexingGcmListener to the service making sure - * wakelock is kept during the process. - */ - protected abstract static class ReceiverBase extends WakefulBroadcastReceiver { - private final Class<? extends DevToolsBridgeServiceBase> mConcreteServiceClass; - - protected ReceiverBase(Class<? extends DevToolsBridgeServiceBase> concreteServiceClass) { - mConcreteServiceClass = concreteServiceClass; - } - - @Override - public void onReceive(Context context, Intent intent) { - // Pass all intent extras to the service. - Intent startIntent = new Intent(context, mConcreteServiceClass); - startIntent.setAction(intent.getAction()); - if (intent.getExtras() != null) startIntent.putExtras(intent.getExtras()); - startWakefulService(context, startIntent); - } - } - - private DevToolsBridgeServer mServer; - private ServiceLifetimeManager mLifetimeManager; - - private Runnable mSessionHandlingTask; - - @Override - public IBinder onBind(Intent intent) { - return null; - } - - @Override - public void onCreate() { - super.onCreate(); - mServer = new DevToolsBridgeServer(new ServerDelegate()); - mLifetimeManager = new ServiceLifetimeManager(this, WAKELOCK_KEY); - } - - @Override - public void onDestroy() { - mServer.dispose(); - - super.onDestroy(); - } - - @Override - public final int onStartCommand(Intent intent, int flags, int startId) { - Runnable intentHandlingTask = mLifetimeManager.startTask(startId); - if (MultiplexingGcmListener.Intents.ACTION.equals(intent.getAction())) { - handleGCMIntent(intent); - } else { - onHandleIntent(intent); - } - ReceiverBase.completeWakefulIntent(intent); - intentHandlingTask.run(); // Stops self if no other task started. - return START_NOT_STICKY; - } - - private void handleGCMIntent(Intent intent) { - if (intent.getBooleanExtra(MultiplexingGcmListener.Intents.EXTRA_OP_MESSAGE, false)) { - mServer.handleCloudMessage(intent, mLifetimeManager.startTask()); - } else if (intent.getBooleanExtra( - MultiplexingGcmListener.Intents.EXTRA_OP_REGISTERED, false)) { - mServer.updateCloudMessagesId( - intent.getStringExtra(MultiplexingGcmListener.Intents.EXTRA_DATA_REG_ID), - startTask()); - } else if (intent.getBooleanExtra( - MultiplexingGcmListener.Intents.EXTRA_OP_UNREGISTERED, false)) { - mServer.updateCloudMessagesId("", startTask()); - } - } - - /** - * Unlike similar method in IntentService this one runs on service thread. - * Cloud Messages intents are handled separately. - */ - protected void onHandleIntent(Intent intent) { - assert calledOnServiceThread(); - } - - protected abstract void querySocketName(DevToolsBridgeServer.QuerySocketCallback callback); - protected abstract void onFirstSessionStarted(); - protected abstract void onLastSessionStopped(); - protected void onSessionCountChange(int sessionCount) {} - - protected DevToolsBridgeServer server() { - return mServer; - } - - protected Runnable startTask() { - return mLifetimeManager.startTask(); - } - - protected boolean calledOnServiceThread() { - return Looper.myLooper() == getMainLooper(); - } - - private class ServerDelegate implements DevToolsBridgeServer.Delegate { - @Override - public Context getContext() { - return DevToolsBridgeServiceBase.this; - } - - @Override - public void onSessionCountChange(int sessionCount) { - assert calledOnServiceThread(); - if (sessionCount > 0 && mSessionHandlingTask == null) { - mSessionHandlingTask = startTask(); - DevToolsBridgeServiceBase.this.onFirstSessionStarted(); - } else if (sessionCount == 0 && mSessionHandlingTask != null) { - mSessionHandlingTask.run(); - mSessionHandlingTask = null; - DevToolsBridgeServiceBase.this.onLastSessionStopped(); - } else { - DevToolsBridgeServiceBase.this.onSessionCountChange(sessionCount); - } - } - - @Override - public void querySocketName(DevToolsBridgeServer.QuerySocketCallback callback) { - DevToolsBridgeServiceBase.this.querySocketName(callback); - } - } -}
diff --git a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/GCDNotificationHandler.java b/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/GCDNotificationHandler.java deleted file mode 100644 index fdf5de9b..0000000 --- a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/GCDNotificationHandler.java +++ /dev/null
@@ -1,177 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.components.devtools_bridge; - -import android.content.Intent; -import android.content.SharedPreferences; -import android.util.Log; - -import org.chromium.components.devtools_bridge.apiary.ApiaryClientFactory; -import org.chromium.components.devtools_bridge.apiary.OAuthResult; -import org.chromium.components.devtools_bridge.commands.Command; -import org.chromium.components.devtools_bridge.commands.CommandReceiver; -import org.chromium.components.devtools_bridge.gcd.InstanceCredential; -import org.chromium.components.devtools_bridge.gcd.Notification; - -import java.io.IOException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; - -/** - * Handles notifications from GCD. For command notification it delegates work to - * DevToolsBridgeServer and updates command state when it finish. for unregistration - * notification it updates preferences. - */ -public class GCDNotificationHandler { - private static final String TAG = "GCDNotificationHandler"; - - private static final String EXTRA_FROM = "from"; - private static final String EXTRA_NOTIFICATION = "notification"; - private static final String EXPECTED_SENDER = - "clouddevices-gcm@clouddevices.google.com"; - - private final DevToolsBridgeServer mServer; - private final ApiaryClientFactory mClientFactory; - private final CommandReceiver mCommandReceiver; - - private final ExecutorService mIOExecutor; - private OAuthResult mOAuthResult; - - public GCDNotificationHandler(DevToolsBridgeServer server) { - mServer = server; - mClientFactory = new ApiaryClientFactory(); - mCommandReceiver = new CommandReceiver(server); - mIOExecutor = Executors.newSingleThreadExecutor(); - } - - public void dispose() { - mIOExecutor.shutdown(); - mClientFactory.close(); - } - - public boolean isNotification(Intent intent) { - return EXPECTED_SENDER.equals(intent.getStringExtra(EXTRA_FROM)) - && intent.getStringExtra(EXTRA_NOTIFICATION) != null; - } - - public void onNotification(Intent intent, Runnable completionHandler) { - try { - handle(Notification.read(intent.getStringExtra(EXTRA_NOTIFICATION)), completionHandler); - return; - } catch (Notification.FormatException e) { - Log.e(TAG, "Invalid notification", e); - } - completionHandler.run(); - } - - public void updateCloudMessagesId(final String gcmChannelId, final Runnable completionHandler) { - final InstanceCredential credential = InstanceCredential.get(mServer.getPreferences()); - if (credential == null) return; - - mIOExecutor.submit(new Runnable() { - @Override - public void run() { - try { - mClientFactory.newGCDClient(getAccessToken(credential)) - .patchInstanceGCMChannel(credential.id, gcmChannelId); - } catch (Exception e) { - Log.e(TAG, "Failure when updating GCM channel id", e); - } finally { - completionHandler.run(); - } - } - }); - } - - private void handle(Notification notification, Runnable completionHandler) { - if (notification == null) { - // Unsupported notification type. Ignore. - Log.i(TAG, "Unsupported notification"); - completionHandler.run(); - return; - } - - switch (notification.type) { - case INSTANCE_UNREGISTERED: - onInstanceUnregistered(notification.instanceId, completionHandler); - break; - - case COMMAND_CREATED: - onCommand(notification.instanceId, notification.command, completionHandler); - break; - - default: - completionHandler.run(); - break; - } - } - - private void onInstanceUnregistered(String instanceId, Runnable completionHandler) { - Log.i(TAG, "Received unregistration notification: " + instanceId); - InstanceCredential credential = InstanceCredential.get(mServer.getPreferences()); - if (credential != null && credential.id.equals(instanceId)) { - SharedPreferences.Editor editor = mServer.getPreferences().edit(); - InstanceCredential.remove(editor); - editor.commit(); - } - completionHandler.run(); - } - - private void onCommand(String instanceId, Command command, Runnable completionHandler) { - InstanceCredential credential = InstanceCredential.get(mServer.getPreferences()); - if (credential != null && credential.id.equals(instanceId)) { - mCommandReceiver.receive( - command, new Responder(command, credential, completionHandler)); - } else { - Log.w(TAG, "Ignored command " + command.type + " for " + instanceId); - completionHandler.run(); - } - } - - private String getAccessToken(InstanceCredential credential) throws IOException { - // Called on IO executor. - // TODO(serya): mOAuthResult should be persistent. - if (mOAuthResult == null) { - mOAuthResult = mClientFactory.newOAuthClient().authenticate( - credential.secret); - } - return mOAuthResult.accessToken; - } - - private final class Responder implements Runnable { - private final Command mCommand; - private final InstanceCredential mCredential; - private final Runnable mCompletionHandler; - private boolean mForwardedToIOThread = false; - - public Responder( - Command command, - InstanceCredential credential, - Runnable completionHandler) { - assert command != null; - assert credential != null; - assert completionHandler != null; - - mCommand = command; - mCredential = credential; - mCompletionHandler = completionHandler; - } - - @Override - public void run() { - if (!mForwardedToIOThread) { - mForwardedToIOThread = true; - mIOExecutor.submit(this); - return; - } - try { - mClientFactory.newGCDClient(getAccessToken(mCredential)).patchCommand(mCommand); - } catch (Exception e) { - // TODO(serya): Handle authorization exception. - Log.e(TAG, "Failure when patching command", e); - } - } - } -}
diff --git a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/RTCConfiguration.java b/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/RTCConfiguration.java deleted file mode 100644 index bb2dbb03..0000000 --- a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/RTCConfiguration.java +++ /dev/null
@@ -1,62 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.components.devtools_bridge; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -/** - * Represents RTCConfiguration (http://www.w3.org/TR/webrtc/#rtcconfiguration-type). - * Replacement for List<PeerConnection.IceServer> in Java WebRTC API. - * Transferable through signaling channel. - * Immutable. - */ -public class RTCConfiguration { - /** - * Single ICE server description. - */ - public static class IceServer { - public final String uri; - public final String username; - public final String credential; - - public IceServer(String uri, String username, String credential) { - this.uri = uri; - this.username = username; - this.credential = credential; - } - } - - public final List<IceServer> iceServers; - - private RTCConfiguration(List<IceServer> iceServers) { - this.iceServers = Collections.unmodifiableList(new ArrayList<IceServer>(iceServers)); - } - - public RTCConfiguration() { - this(Collections.<IceServer>emptyList()); - } - - /** - * Builder for RTCConfiguration. - */ - public static class Builder { - private final List<IceServer> mIceServers = new ArrayList<IceServer>(); - - public RTCConfiguration build() { - return new RTCConfiguration(mIceServers); - } - - public Builder addIceServer(String uri, String username, String credential) { - mIceServers.add(new IceServer(uri, username, credential)); - return this; - } - - public Builder addIceServer(String uri) { - return addIceServer(uri, "", ""); - } - } -}
diff --git a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/ServerSession.java b/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/ServerSession.java deleted file mode 100644 index 4dadcb9d..0000000 --- a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/ServerSession.java +++ /dev/null
@@ -1,178 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.components.devtools_bridge; - -import java.util.List; - -/** - * DevTools Bridge server session. Handles connection with a ClientSession. - * See SessionBase description for more detais. - */ -public class ServerSession extends SessionBase implements SessionBase.ServerSessionInterface { - private NegotiationCallback mNegotiationCallback; - private IceExchangeCallback mIceExchangeCallback; - private boolean mIceEchangeRequested = false; - - protected int mGatheringDelayMs = 200; - - public ServerSession(SessionDependencyFactory factory, - Executor executor, - String defaultSocketName) { - super(factory, executor, factory.newSocketTunnelServer(defaultSocketName)); - } - - @Override - public void stop() { - super.stop(); - if (mNegotiationCallback != null) { - mNegotiationCallback.onFailure("Session stopped"); - mNegotiationCallback = null; - } - if (mIceExchangeCallback != null) { - mIceExchangeCallback.onFailure("Session stopped"); - mIceExchangeCallback = null; - } - } - - @Override - public void startSession(RTCConfiguration config, - String offer, - NegotiationCallback callback) { - checkCalledOnSessionThread(); - if (isStarted()) { - callback.onFailure("Session already started"); - return; - } - - ClientMessageHandler handler = new ClientMessageHandler(); - start(config, handler); - - negotiate(offer, callback); - } - - @Override - public void renegotiate(String offer, NegotiationCallback callback) { - checkCalledOnSessionThread(); - if (!isStarted()) { - callback.onFailure("Session is not started"); - return; - } - - callback.onFailure("Not implemented"); - } - - private void negotiate(String offer, NegotiationCallback callback) { - if (mNegotiationCallback != null) { - callback.onFailure("Negotiation already in progress"); - return; - } - - mNegotiationCallback = callback; - // If success will call onRemoteDescriptionSet. - connection().setRemoteDescription( - AbstractPeerConnection.SessionDescriptionType.OFFER, offer); - } - - protected void onRemoteDescriptionSet() { - // If success will call onLocalDescriptionCreatedAndSet. - connection().createAndSetLocalDescription( - AbstractPeerConnection.SessionDescriptionType.ANSWER); - } - - @Override - protected void onLocalDescriptionCreatedAndSet( - AbstractPeerConnection.SessionDescriptionType type, String description) { - assert type == AbstractPeerConnection.SessionDescriptionType.ANSWER; - - mNegotiationCallback.onSuccess(description); - mNegotiationCallback = null; - onSessionNegotiated(); - } - - protected void onSessionNegotiated() { - if (!isControlChannelOpened()) - startAutoCloseTimer(); - } - - @Override - public void iceExchange(List<String> clientCandidates, - IceExchangeCallback callback) { - checkCalledOnSessionThread(); - if (!isStarted()) { - callback.onFailure("Session disposed"); - return; - } - - if (mNegotiationCallback != null || mIceExchangeCallback != null) { - callback.onFailure("Concurrent requests detected"); - return; - } - - mIceExchangeCallback = callback; - addIceCandidates(clientCandidates); - - // Give libjingle some time for gathering ice candidates. - postOnSessionThread(mGatheringDelayMs, new Runnable() { - @Override - public void run() { - if (isStarted()) - sendIceCandidatesBack(); - } - }); - } - - private void sendIceCandidatesBack() { - mIceExchangeCallback.onSuccess(takeIceCandidates()); - mIceExchangeCallback = null; - mIceEchangeRequested = false; - } - - @Override - protected void onControlChannelOpened() { - stopAutoCloseTimer(); - } - - @Override - protected void onFailure(String message) { - if (mNegotiationCallback != null) { - mNegotiationCallback.onFailure(message); - mNegotiationCallback = null; - } - super.onFailure(message); - } - - @Override - protected void onIceCandidate(String candidate) { - super.onIceCandidate(candidate); - if (isControlChannelOpened() && !mIceEchangeRequested) { - // New ICE candidate may improve connection even if control channel operable. - // If control channel closed client will exchange candidates anyway. - sendControlMessage(new SessionControlMessages.IceExchangeMessage()); - mIceEchangeRequested = true; - } - } - - protected SocketTunnel newSocketTunnelServer(String serverSocketName) { - return mFactory.newSocketTunnelServer(serverSocketName); - } - - private final class ClientMessageHandler extends SessionControlMessages.ClientMessageHandler { - @Override - protected void onMessage(SessionControlMessages.ClientMessage message) { - switch (message.type) { - case UNKNOWN_REQUEST: - sendControlMessage(((SessionControlMessages.UnknownRequestMessage) message) - .createResponse()); - break; - } - } - } - - @Override - protected void sendControlMessage(SessionControlMessages.Message<?> message) { - assert message instanceof SessionControlMessages.ServerMessage; - super.sendControlMessage(message); - } -}
diff --git a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/ServiceLifetimeManager.java b/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/ServiceLifetimeManager.java deleted file mode 100644 index 29f0f3b3..0000000 --- a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/ServiceLifetimeManager.java +++ /dev/null
@@ -1,83 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.components.devtools_bridge; - -import android.app.IntentService; -import android.app.Service; -import android.content.Context; -import android.os.Handler; -import android.os.Looper; -import android.os.PowerManager; - -/** - * Tracks count of running tasks and stops the service when all tasks completed. Supposed to be - * a part of a service. - * - * Usage: - * class MyService extends Service { - * public int onStartCommand(Intent intent, int flags, int startId) { - * Runnable intentHandlingTask = mLifetimeManager.startTask(startId); - * ... - * intentHandlingTask.run(); // Stops self if no other task started. - * return START_NOT_STICKY; - * } - * } - */ -class ServiceLifetimeManager { - private final Service mService; - private final String mWakeLockKey; - private int mLastStartId = -1; - private int mActiveTasks = 0; - private PowerManager.WakeLock mWakeLock; - - public ServiceLifetimeManager(Service service, String wakeLockKey) { - // IntentService is incompatible with this class because it manages lifetime on its own. - assert !(service instanceof IntentService); - - mService = service; - mWakeLockKey = wakeLockKey; - } - - public Runnable startTask(int startId) { - mLastStartId = startId; - return startTask(); - } - - public Runnable startTask() { - assert isCalledOnServiceLooper(); - if (mActiveTasks == 0) { - if (mWakeLock == null) { - PowerManager pm = (PowerManager) mService.getSystemService(Context.POWER_SERVICE); - mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, mWakeLockKey); - } - mWakeLock.acquire(); - } - mActiveTasks++; - return new TaskCompletionHandler(); - } - - private boolean isCalledOnServiceLooper() { - return mService.getMainLooper() == Looper.myLooper(); - } - - private class TaskCompletionHandler implements Runnable { - private boolean mCompleted = false; - - @Override - public void run() { - if (!isCalledOnServiceLooper()) { - new Handler(mService.getMainLooper()).post(this); - return; - } - if (mCompleted) return; - - if (--mActiveTasks == 0) { - mWakeLock.release(); - mService.stopSelf(mLastStartId); - } - mCompleted = true; - } - } -}
diff --git a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/SessionBase.java b/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/SessionBase.java deleted file mode 100644 index 11fd9b6f..0000000 --- a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/SessionBase.java +++ /dev/null
@@ -1,435 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.components.devtools_bridge; - -import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * Base class for ServerSession and ClientSession. Both opens a control channel and a default - * tunnel. Control channel designated to exchange messages defined in SessionControlMessages. - * - * Signaling communication between client and server works in request/response manner. It's more - * restrictive than traditional bidirectional signaling channel but give more freedom in - * implementing signaling. Main motivation is that GCD provides API what works in that way. - * - * Session is initiated by a client. It creates an offer and sends it along with RTC configuration. - * Server sends an answer in response. Once session negotiated client starts ICE candidates - * exchange. It periodically sends own candidates and peeks server's ones. Periodic ICE exchange - * stops when control channel opens. It resumes if connections state turns to DISCONNECTED (because - * server may generate ICE candidates to recover connectivity but may not notify through - * control channel). ICE exchange in CONNECTED state designated to let improve connection - * when network configuration changed. - * - * If session is not started (or resumed) after mAutoCloseTimeoutMs it closes itself. - * - * Only default tunnel is supported at the moment. It designated for DevTools UNIX socket. - * Additional tunnels may be useful for: 1) reverse port forwarding and 2) tunneling - * WebView DevTools sockets of other applications. Additional tunnels negotiation should - * be implemented by adding new types of control messages. Dynamic tunnel configuration - * will need support for session renegotiation. - * - * Session is a single threaded object. Until started owner is responsible to synchronizing access - * to it. When started it must be called on the thread of SessionBase.Executor. - * All WebRTC callbacks are forwarded on this thread. - */ -public abstract class SessionBase { - private static final int CONTROL_CHANNEL_ID = 0; - private static final int DEFAULT_TUNNEL_CHANNEL_ID = 1; - - private final Executor mExecutor; - protected final SessionDependencyFactory mFactory; - private AbstractPeerConnection mConnection; - private AbstractDataChannel mControlChannel; - private List<String> mCandidates = new ArrayList<String>(); - private boolean mControlChannelOpened = false; - private boolean mConnected = false; - private Cancellable mAutoCloseTask; - private SessionControlMessages.MessageHandler mControlMessageHandler; - private final Map<Integer, SocketTunnel> mTunnels = - new HashMap<Integer, SocketTunnel>(); - private EventListener mEventListener; - - protected int mAutoCloseTimeoutMs = 30000; - - /** - * Allows to post tasks on the thread where the sessions lives. - */ - public interface Executor { - Cancellable postOnSessionThread(int delayMs, Runnable runnable); - boolean isCalledOnSessionThread(); - } - - /** - * Interface for cancelling scheduled tasks. - */ - public interface Cancellable { - void cancel(); - } - - /** - * Representation of server session. All methods are delivered through - * signaling channel (except test configurations). Server session is accessible - * in request/response manner. - */ - public interface ServerSessionInterface { - /** - * Starts session with specified RTC configuration and offer. - */ - void startSession(RTCConfiguration config, - String offer, - NegotiationCallback callback); - - /** - * Renegoteates session. Needed when tunnels added/removed on the fly. - */ - void renegotiate(String offer, NegotiationCallback callback); - - /** - * Sends client's ICE candidates to the server and peeks server's ICE candidates. - */ - void iceExchange(List<String> clientCandidates, IceExchangeCallback callback); - } - - /** - * Base interface for server callbacks. - */ - public interface ServerCallback { - void onFailure(String errorMessage); - } - - /** - * Server's response to startSession and renegotiate methods. - */ - public interface NegotiationCallback extends ServerCallback { - void onSuccess(String answer); - } - - /** - * Server's response on iceExchange method. - */ - public interface IceExchangeCallback extends ServerCallback { - void onSuccess(List<String> serverCandidates); - } - - /** - * Listener of session's events. - */ - public interface EventListener { - void onCloseSelf(); - } - - protected SessionBase(SessionDependencyFactory factory, - Executor executor, - SocketTunnel defaultTunnel) { - mExecutor = executor; - mFactory = factory; - addTunnel(DEFAULT_TUNNEL_CHANNEL_ID, defaultTunnel); - } - - public final void dispose() { - checkCalledOnSessionThread(); - - if (isStarted()) stop(); - - for (SocketTunnel tunnel : mTunnels.values()) { - tunnel.dispose(); - } - } - - public void setEventListener(EventListener listener) { - checkCalledOnSessionThread(); - - mEventListener = listener; - } - - protected AbstractPeerConnection connection() { - return mConnection; - } - - protected boolean doesTunnelExist(int channelId) { - return mTunnels.containsKey(channelId); - } - - private final void addTunnel(int channelId, SocketTunnel tunnel) { - assert !mTunnels.containsKey(channelId); - assert !tunnel.isBound(); - // Tunnel renegotiation not implemented. - assert channelId == DEFAULT_TUNNEL_CHANNEL_ID && !isStarted(); - - mTunnels.put(channelId, tunnel); - } - - protected void removeTunnel(int channelId) { - assert mTunnels.containsKey(channelId); - mTunnels.get(channelId).unbind().dispose(); - mTunnels.remove(channelId); - } - - protected final boolean isControlChannelOpened() { - return mControlChannelOpened; - } - - protected final boolean isConnected() { - return mConnected; - } - - protected final void postOnSessionThread(Runnable runnable) { - postOnSessionThread(0, runnable); - } - - protected final Cancellable postOnSessionThread(int delayMs, Runnable runnable) { - return mExecutor.postOnSessionThread(delayMs, runnable); - } - - protected final void checkCalledOnSessionThread() { - assert mExecutor.isCalledOnSessionThread(); - } - - public final boolean isStarted() { - return mConnection != null; - } - - /** - * Creates and configures peer connection and sets a control message handler. - */ - protected void start(RTCConfiguration config, - SessionControlMessages.MessageHandler handler) { - assert !isStarted(); - - mConnection = mFactory.createPeerConnection(config, new ConnectionObserver()); - mControlChannel = mConnection.createDataChannel(CONTROL_CHANNEL_ID); - mControlMessageHandler = handler; - mControlChannel.registerObserver(new ControlChannelObserver()); - - for (Map.Entry<Integer, SocketTunnel> entry : mTunnels.entrySet()) { - int channelId = entry.getKey(); - SocketTunnel tunnel = entry.getValue(); - tunnel.bind(connection().createDataChannel(channelId)); - } - } - - /** - * Disposed objects created in |start|. - */ - public void stop() { - checkCalledOnSessionThread(); - - assert isStarted(); - - stopAutoCloseTimer(); - - for (SocketTunnel tunnel : mTunnels.values()) { - tunnel.unbind().dispose(); - } - - AbstractPeerConnection connection = mConnection; - mConnection = null; - assert !isStarted(); - - mControlChannel.unregisterObserver(); - mControlMessageHandler = null; - mControlChannel.dispose(); - mControlChannel = null; - - // Dispose connection after data channels. - connection.dispose(); - } - - protected abstract void onRemoteDescriptionSet(); - protected abstract void onLocalDescriptionCreatedAndSet( - AbstractPeerConnection.SessionDescriptionType type, String description); - protected abstract void onControlChannelOpened(); - - protected void onControlChannelClosed() { - closeSelf(); - } - - protected void onIceConnectionChange() {} - - private void handleFailureOnSignalingThread(final String message) { - postOnSessionThread(new Runnable() { - @Override - public void run() { - if (isStarted()) - onFailure(message); - } - }); - } - - protected final void startAutoCloseTimer() { - assert mAutoCloseTask == null; - assert isStarted(); - mAutoCloseTask = postOnSessionThread(mAutoCloseTimeoutMs, new Runnable() { - @Override - public void run() { - assert isStarted(); - - mAutoCloseTask = null; - closeSelf(); - } - }); - } - - protected final void stopAutoCloseTimer() { - if (mAutoCloseTask != null) { - mAutoCloseTask.cancel(); - mAutoCloseTask = null; - } - } - - protected void closeSelf() { - stop(); - if (mEventListener != null) { - mEventListener.onCloseSelf(); - } - } - - // Returns collected candidates (for sending to the remote session) and removes them. - protected List<String> takeIceCandidates() { - List<String> result = new ArrayList<String>(); - result.addAll(mCandidates); - mCandidates.clear(); - return result; - } - - protected void addIceCandidates(List<String> candidates) { - for (String candidate : candidates) { - mConnection.addIceCandidate(candidate); - } - } - - protected void onFailure(String message) { - closeSelf(); - } - - protected void onIceCandidate(String candidate) { - mCandidates.add(candidate); - } - - /** - * Receives callbacks from the peer connection on the signaling thread. Forwards them - * on the session thread. All session event handling methods assume session started (prevents - * disposed objects). It drops callbacks it closed. - */ - private final class ConnectionObserver implements AbstractPeerConnection.Observer { - @Override - public void onFailure(final String description) { - postOnSessionThread(new Runnable() { - @Override - public void run() { - if (!isStarted()) return; - SessionBase.this.onFailure(description); - } - }); - } - - @Override - public void onLocalDescriptionCreatedAndSet( - final AbstractPeerConnection.SessionDescriptionType type, - final String description) { - postOnSessionThread(new Runnable() { - @Override - public void run() { - if (!isStarted()) return; - SessionBase.this.onLocalDescriptionCreatedAndSet(type, description); - } - }); - } - - @Override - public void onRemoteDescriptionSet() { - postOnSessionThread(new Runnable() { - @Override - public void run() { - if (!isStarted()) return; - SessionBase.this.onRemoteDescriptionSet(); - } - }); - } - - @Override - public void onIceCandidate(final String candidate) { - postOnSessionThread(new Runnable() { - @Override - public void run() { - if (!isStarted()) return; - SessionBase.this.onIceCandidate(candidate); - } - }); - } - - @Override - public void onIceConnectionChange(final boolean connected) { - postOnSessionThread(new Runnable() { - @Override - public void run() { - if (!isStarted()) return; - mConnected = connected; - SessionBase.this.onIceConnectionChange(); - } - }); - } - } - - /** - * Receives callbacks from the control channel. Forwards them on the session thread. - */ - private final class ControlChannelObserver implements AbstractDataChannel.Observer { - @Override - public void onStateChange(final AbstractDataChannel.State state) { - postOnSessionThread(new Runnable() { - @Override - public void run() { - if (!isStarted()) return; - mControlChannelOpened = state == AbstractDataChannel.State.OPEN; - - if (mControlChannelOpened) { - onControlChannelOpened(); - } else { - onControlChannelClosed(); - } - } - }); - } - - @Override - public void onMessage(ByteBuffer message) { - final byte[] bytes = new byte[message.remaining()]; - message.get(bytes); - postOnSessionThread(new Runnable() { - @Override - public void run() { - if (!isStarted() || mControlMessageHandler == null) return; - - try { - mControlMessageHandler.readMessage(bytes); - } catch (SessionControlMessages.InvalidFormatException e) { - // TODO(serya): handle - } - } - }); - } - } - - protected void sendControlMessage(SessionControlMessages.Message<?> message) { - assert mControlChannelOpened; - - byte[] bytes = SessionControlMessages.toByteArray(message); - ByteBuffer rawMessage = ByteBuffer.allocateDirect(bytes.length); - rawMessage.put(bytes); - - sendControlMessage(rawMessage); - } - - private void sendControlMessage(ByteBuffer rawMessage) { - rawMessage.limit(rawMessage.position()); - rawMessage.position(0); - mControlChannel.send(rawMessage, AbstractDataChannel.MessageType.TEXT); - } -}
diff --git a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/SessionControlMessages.java b/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/SessionControlMessages.java deleted file mode 100644 index 4c16520..0000000 --- a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/SessionControlMessages.java +++ /dev/null
@@ -1,251 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.components.devtools_bridge; - -import android.util.JsonReader; -import android.util.JsonWriter; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStreamWriter; - -/** - * Defines protocol of control channel of SessionBase. Messages are JSON serializable - * and transferred through AbstractDataChannel. - */ -public final class SessionControlMessages { - private SessionControlMessages() { - throw new RuntimeException("Class not intended to instantiate"); - } - - /** - * Types of messages that client sends to server. - */ - enum ClientMessageType { - UNKNOWN_REQUEST - } - - /** - * Types of messages that servers sends to client. - */ - enum ServerMessageType { - ICE_EXCHANGE, - UNKNOWN_RESPONSE - } - - /** - * Base class for all messages. - */ - public abstract static class Message<T extends Enum> { - public final T type; - - protected Message(T type) { - this.type = type; - } - - public void write(JsonWriter writer) throws IOException { - writer.name("type"); - writer.value(type.toString()); - } - } - - /** - * Base calss for messages that client sends to server. - */ - public abstract static class ClientMessage extends Message<ClientMessageType> { - protected ClientMessage(ClientMessageType type) { - super(type); - } - } - - /** - * Base class for messages that server sends to client. - */ - public abstract static class ServerMessage extends Message<ServerMessageType> { - protected ServerMessage(ServerMessageType type) { - super(type); - } - } - - /** - * Server sends this message when it has ICE candidates to exchange. Client initiates - * ICE exchange over signaling channel. - */ - public static final class IceExchangeMessage extends ServerMessage { - public IceExchangeMessage() { - super(ServerMessageType.ICE_EXCHANGE); - } - } - - /** - * Server response on unrecognized client message. - */ - public static final class UnknownResponseMessage extends ServerMessage { - public final String rawRequestType; - - public UnknownResponseMessage(String rawRequestType) { - super(ServerMessageType.UNKNOWN_RESPONSE); - this.rawRequestType = rawRequestType; - } - - @Override - public void write(JsonWriter writer) throws IOException { - super.write(writer); - writer.name("rawRequestType"); - writer.value(rawRequestType.toString()); - } - } - - /** - * Helper class to represent message of unknown type. Should not be sent. - */ - public static final class UnknownRequestMessage extends ClientMessage { - public final String rawType; - - public UnknownRequestMessage(String rawType) { - super(ClientMessageType.UNKNOWN_REQUEST); - this.rawType = rawType; - } - - @Override - public void write(JsonWriter writer) throws IOException { - throw new RuntimeException("Should not be serialized"); - } - - public UnknownResponseMessage createResponse() { - return new UnknownResponseMessage(rawType); - } - } - - private static <T extends Enum<T>> T getMessageType( - Class<T> enumType, String rawType, T defaultType) throws IOException { - try { - return Enum.valueOf(enumType, rawType); - } catch (IllegalArgumentException e) { - if (defaultType != null) - return defaultType; - throw new IOException("Invalid message type " + rawType); - } - } - - public static void write(JsonWriter writer, Message<?> message) throws IOException { - writer.beginObject(); - message.write(writer); - writer.endObject(); - } - - public static ClientMessage readClientMessage(JsonReader reader) throws IOException { - String rawType = ""; - boolean success = false; - - reader.beginObject(); - while (reader.hasNext()) { - String name = reader.nextName(); - if ("type".equals(name)) { - rawType = reader.nextString(); - } - } - reader.endObject(); - - switch (getMessageType(ClientMessageType.class, - rawType, - ClientMessageType.UNKNOWN_REQUEST)) { - case UNKNOWN_REQUEST: - return new UnknownRequestMessage(rawType); - } - throw new IOException("Invalid message"); - } - - public static ServerMessage readServerMessage(JsonReader reader) throws IOException { - String rawType = ""; - String rawRequestType = null; - - reader.beginObject(); - while (reader.hasNext()) { - String name = reader.nextName(); - if ("type".equals(name)) { - rawType = reader.nextString(); - } else if ("rawRequestType".equals(name)) { - rawRequestType = reader.nextString(); - } - } - reader.endObject(); - - switch (getMessageType(ServerMessageType.class, rawType, null)) { - case ICE_EXCHANGE: - return new IceExchangeMessage(); - case UNKNOWN_RESPONSE: - return new UnknownResponseMessage(rawRequestType); - } - throw new IOException("Invalid message"); - } - - /** - * Base class for client and server message handlers. - */ - public abstract static class MessageHandler { - protected abstract void readMessage(JsonReader reader) throws IOException; - - public boolean readMessage(byte[] bytes) throws InvalidFormatException { - try { - readMessage(new JsonReader(new InputStreamReader(new ByteArrayInputStream(bytes)))); - return true; - } catch (IOException e) { - throw new InvalidFormatException(e); - } - } - } - - /** - * Exception when parsing or handling message. - */ - public static class InvalidFormatException extends IOException { - public InvalidFormatException(IOException e) { - super(e); - } - - public InvalidFormatException(String message) { - super(message); - } - } - - /** - * Base class for handler of server messages (to be created on client). - */ - public abstract static class ServerMessageHandler extends MessageHandler { - @Override - protected void readMessage(JsonReader reader) throws IOException { - onMessage(readServerMessage(reader)); - } - - protected abstract void onMessage(ServerMessage message); - } - - /** - * Base class for handler of client messages (to be created on server). - */ - public abstract static class ClientMessageHandler extends MessageHandler { - @Override - public void readMessage(JsonReader reader) throws IOException { - onMessage(readClientMessage(reader)); - } - - protected abstract void onMessage(ClientMessage message); - } - - public static byte[] toByteArray(Message<?> message) { - ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); - JsonWriter writer = new JsonWriter(new OutputStreamWriter(byteStream)); - try { - write(writer, message); - writer.close(); - return byteStream.toByteArray(); - } catch (IOException e) { - throw new RuntimeException(e); - } - } -}
diff --git a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/SessionDependencyFactory.java b/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/SessionDependencyFactory.java deleted file mode 100644 index e90e8ce4..0000000 --- a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/SessionDependencyFactory.java +++ /dev/null
@@ -1,44 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.components.devtools_bridge; - -/** - * Implements AbstractDataChannel and AbstractPeerConnection on top of org.webrtc.* API. - * Isolation is needed because some configuration of DevTools bridge may not be based on - * Java API. - * In addition abstraction layer isolates SessionBase from complexity of underlying API - * beside used features. - */ -public abstract class SessionDependencyFactory { - private interface Constructor { - SessionDependencyFactory newInstance(); - } - - private static Constructor sConstructor; - - public static SessionDependencyFactory newInstance() { - return sConstructor.newInstance(); - } - - public static <T extends SessionDependencyFactory> void init(final Class<T> c) { - sConstructor = new Constructor() { - @Override - public SessionDependencyFactory newInstance() { - try { - return c.newInstance(); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - }; - } - - public abstract AbstractPeerConnection createPeerConnection( - RTCConfiguration config, AbstractPeerConnection.Observer observer); - - public abstract SocketTunnel newSocketTunnelServer(String socketName); - - public abstract void dispose(); -}
diff --git a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/SessionDependencyFactoryNative.java b/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/SessionDependencyFactoryNative.java deleted file mode 100644 index cac78a5..0000000 --- a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/SessionDependencyFactoryNative.java +++ /dev/null
@@ -1,283 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.components.devtools_bridge; - -import org.chromium.base.CalledByNative; -import org.chromium.base.JNINamespace; - -import java.nio.ByteBuffer; - -/** - * Native implementation of session dependency factory on top of C++ - * libjingle API. - */ -@JNINamespace("devtools_bridge::android") -public class SessionDependencyFactoryNative extends SessionDependencyFactory { - private final long mFactoryPtr; - - public SessionDependencyFactoryNative() { - mFactoryPtr = nativeCreateFactory(); - assert mFactoryPtr != 0; - } - - @Override - public AbstractPeerConnection createPeerConnection( - RTCConfiguration config, AbstractPeerConnection.Observer observer) { - assert config != null; - assert observer != null; - - long configPtr = nativeCreateConfig(); - for (RTCConfiguration.IceServer server : config.iceServers) { - nativeAddIceServer(configPtr, server.uri, server.username, server.credential); - } - - return new PeerConnectionImpl(mFactoryPtr, configPtr, observer); - } - - @Override - public SocketTunnel newSocketTunnelServer(String socketBase) { - return new SocketTunnelServerImpl(mFactoryPtr, socketBase); - } - - @Override - public void dispose() { - nativeDestroyFactory(mFactoryPtr); - } - - private static final class PeerConnectionImpl extends AbstractPeerConnection { - private final long mConnectionPtr; - - // Takes ownership on |configPtr|. - public PeerConnectionImpl( - long factoryPtr, long configPtr, - AbstractPeerConnection.Observer observer) { - mConnectionPtr = nativeCreatePeerConnection(factoryPtr, configPtr, observer); - assert mConnectionPtr != 0; - } - - @Override - public void createAndSetLocalDescription(SessionDescriptionType type) { - switch (type) { - case OFFER: - nativeCreateAndSetLocalOffer(mConnectionPtr); - break; - - case ANSWER: - nativeCreateAndSetLocalAnswer(mConnectionPtr); - break; - } - } - - @Override - public void setRemoteDescription(SessionDescriptionType type, String description) { - switch (type) { - case OFFER: - nativeSetRemoteOffer(mConnectionPtr, description); - break; - - case ANSWER: - nativeSetRemoteAnswer(mConnectionPtr, description); - break; - } - } - - @Override - public void addIceCandidate(String candidate) { - // TODO(serya): Handle IllegalArgumentException exception. - IceCandidate parsed = IceCandidate.fromString(candidate); - nativeAddIceCandidate(mConnectionPtr, parsed.sdpMid, parsed.sdpMLineIndex, parsed.sdp); - } - - @Override - public void dispose() { - nativeDestroyPeerConnection(mConnectionPtr); - } - - @Override - public AbstractDataChannel createDataChannel(int channelId) { - return new DataChannelImpl(nativeCreateDataChannel(mConnectionPtr, channelId)); - } - } - - private static final class DataChannelImpl extends AbstractDataChannel { - private final long mChannelPtr; - - public DataChannelImpl(long ptr) { - assert ptr != 0; - mChannelPtr = ptr; - } - - long nativePtr() { - return mChannelPtr; - } - - @Override - public void registerObserver(Observer observer) { - nativeRegisterDataChannelObserver(mChannelPtr, observer); - } - - @Override - public void unregisterObserver() { - nativeUnregisterDataChannelObserver(mChannelPtr); - } - - @Override - public void send(ByteBuffer message, MessageType type) { - assert message.position() == 0; - int length = message.limit(); - assert length > 0; - - switch (type) { - case BINARY: - nativeSendBinaryMessage(mChannelPtr, message, length); - break; - - case TEXT: - nativeSendTextMessage(mChannelPtr, message, length); - break; - } - } - - @Override - public void close() { - nativeCloseDataChannel(mChannelPtr); - } - - @Override - public void dispose() { - nativeDestroyDataChannel(mChannelPtr); - } - } - - private static class SocketTunnelServerImpl implements SocketTunnel { - private final String mSocketName; - private final long mFactoryPtr; - private DataChannelImpl mDataChannel; - private long mTunnelPtr; - - public SocketTunnelServerImpl(long factoryPtr, String socketName) { - mFactoryPtr = factoryPtr; - mSocketName = socketName; - } - - @Override - public void bind(AbstractDataChannel dataChannel) { - mDataChannel = (DataChannelImpl) dataChannel; - mTunnelPtr = nativeCreateSocketTunnelServer( - mFactoryPtr, mDataChannel.nativePtr(), mSocketName); - } - - @Override - public AbstractDataChannel unbind() { - AbstractDataChannel result = mDataChannel; - nativeDestroySocketTunnelServer(mTunnelPtr); - mTunnelPtr = 0; - mDataChannel = null; - return result; - } - - @Override - public boolean isBound() { - return mDataChannel != null; - } - - @Override - public void dispose() { - assert !isBound(); - } - } - - // Peer connection callbacks. - - @CalledByNative - private static void notifyLocalOfferCreatedAndSetSet(Object observer, String description) { - ((AbstractPeerConnection.Observer) observer).onLocalDescriptionCreatedAndSet( - AbstractPeerConnection.SessionDescriptionType.OFFER, description); - } - - @CalledByNative - private static void notifyLocalAnswerCreatedAndSetSet(Object observer, String description) { - ((AbstractPeerConnection.Observer) observer).onLocalDescriptionCreatedAndSet( - AbstractPeerConnection.SessionDescriptionType.ANSWER, description); - } - - @CalledByNative - private static void notifyRemoteDescriptionSet(Object observer) { - ((AbstractPeerConnection.Observer) observer).onRemoteDescriptionSet(); - } - - @CalledByNative - private static void notifyConnectionFailure(Object observer, String description) { - ((AbstractPeerConnection.Observer) observer).onFailure(description); - } - - @CalledByNative - private static void notifyIceCandidate( - Object observer, String sdpMid, int sdpMLineIndex, String sdp) { - ((AbstractPeerConnection.Observer) observer) - .onIceCandidate(new AbstractPeerConnection.IceCandidate( - sdpMid, sdpMLineIndex, sdp).toString()); - } - - @CalledByNative - private static void notifyIceConnectionChange(Object observer, boolean connected) { - ((AbstractPeerConnection.Observer) observer) - .onIceConnectionChange(connected); - } - - // Data channel callbacks. - - @CalledByNative - private static void notifyChannelOpen(Object observer) { - ((AbstractDataChannel.Observer) observer) - .onStateChange(AbstractDataChannel.State.OPEN); - } - - @CalledByNative - private static void notifyChannelClose(Object observer) { - ((AbstractDataChannel.Observer) observer) - .onStateChange(AbstractDataChannel.State.CLOSED); - } - - @CalledByNative - private static void notifyMessage(Object observer, ByteBuffer message) { - ((AbstractDataChannel.Observer) observer) - .onMessage(message); - } - - private static native long nativeCreateFactory(); - private static native void nativeDestroyFactory(long factoryPtr); - - private static native long nativeCreateConfig(); - private static native void nativeAddIceServer( - long configPtr, String uri, String username, String credential); - - // Takes ownership on |configPtr|. - private static native long nativeCreatePeerConnection( - long factoryPtr, long configPtr, Object observer); - private static native void nativeDestroyPeerConnection(long connectionPtr); - - private static native void nativeCreateAndSetLocalOffer(long connectionPtr); - private static native void nativeCreateAndSetLocalAnswer(long connectionPtr); - private static native void nativeSetRemoteOffer(long connectionPtr, String description); - private static native void nativeSetRemoteAnswer(long connectionPtr, String description); - private static native void nativeAddIceCandidate( - long peerConnectionPtr, String sdpMid, int sdpMLineIndex, String sdp); - - private static native long nativeCreateDataChannel(long connectionPtr, int channelId); - private static native void nativeDestroyDataChannel(long channelPtr); - - private static native void nativeRegisterDataChannelObserver( - long channelPtr, Object observer); - private static native void nativeUnregisterDataChannelObserver(long channelPtr); - private static native void nativeSendBinaryMessage( - long channelPtr, ByteBuffer message, int size); - private static native void nativeSendTextMessage(long channelPtr, ByteBuffer message, int size); - private static native void nativeCloseDataChannel(long channelPtr); - - private static native long nativeCreateSocketTunnelServer( - long factoryPtr, long channelPtr, String socketName); - private static native void nativeDestroySocketTunnelServer(long tunnelPtr); -}
diff --git a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/SignalingReceiver.java b/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/SignalingReceiver.java deleted file mode 100644 index fb914d8..0000000 --- a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/SignalingReceiver.java +++ /dev/null
@@ -1,44 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.components.devtools_bridge; - -import java.util.List; - -/** - * Signaling channel interface. Methods are marshalled through GCM. - * Direct calling supported for tests. - * - * Primary reason of the signaling channel is supporting debugging sessions (so why - * it looks like SessionBase.ServerSessionInterface with session ids). It also - * may be used for retrieving information when establishing session is not appropriate. - */ -public interface SignalingReceiver { - /** - * Starts new session and assigns sessionId to it. Passes all arguments to - * the ServerSession object. Session ID must be globay unique (like long random) to - * avoid conflicts among clients. - */ - void startSession( - String sessionId, - RTCConfiguration config, - String offer, - SessionBase.NegotiationCallback callback); - - /** - * Passes call to the appropriate ServerSession object (if it still exists). - */ - void renegotiate( - String sessionId, - String offer, - SessionBase.NegotiationCallback callback); - - /** - * Passes call to the appropriate ServerSession object (if it still exists). - */ - void iceExchange( - String sessionId, - List<String> clientCandidates, - SessionBase.IceExchangeCallback callback); -}
diff --git a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/SocketTunnel.java b/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/SocketTunnel.java deleted file mode 100644 index f7670e8..0000000 --- a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/SocketTunnel.java +++ /dev/null
@@ -1,27 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.components.devtools_bridge; - -/** - * Interface for client or server socket tunnel. Tunnels a socket over a data channel. - * Client tunnel should be bound to one side and server tunnel to another. - * - * Data flow schema looks like this: - * - * DevToolsServer - * <-unix socket-> - * SocketTunnelServer - * <-data channel-> - * SocketTunnelClient - * <- unix socket -> - * Client (DevTools frontend) - */ -interface SocketTunnel { - void bind(AbstractDataChannel dataChannel); - AbstractDataChannel unbind(); - boolean isBound(); - - void dispose(); -}
diff --git a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/apiary/ApiaryClientFactory.java b/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/apiary/ApiaryClientFactory.java deleted file mode 100644 index 92df28a..0000000 --- a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/apiary/ApiaryClientFactory.java +++ /dev/null
@@ -1,61 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.components.devtools_bridge.apiary; - -import android.net.http.AndroidHttpClient; - -import org.chromium.base.JNINamespace; - -/** - * Factory for creating clients for external APIs. - */ -@JNINamespace("devtools_bridge::android") -public class ApiaryClientFactory { - private static final String USER_AGENT = "DevTools bridge"; - - public static final String OAUTH_SCOPE = "https://www.googleapis.com/auth/clouddevices"; - - protected final AndroidHttpClient mHttpClient = AndroidHttpClient.newInstance(USER_AGENT); - - /** - * Creates a new GCD client with auth token. - */ - public GCDClient newGCDClient(String oAuthToken) { - return new GCDClient(mHttpClient, getAPIKey(), oAuthToken); - } - - /** - * Creates a new anonymous client. GCD requires client been not authenticated by user or - * device credentials for finalizing registration. - */ - public GCDClient newAnonymousGCDClient() { - return new GCDClient(mHttpClient, nativeGetAPIKey()); - } - - public OAuthClient newOAuthClient() { - return new OAuthClient( - mHttpClient, OAUTH_SCOPE, getOAuthClientId(), nativeGetOAuthClientSecret()); - } - - public BlockingGCMRegistrar newGCMRegistrar() { - return new BlockingGCMRegistrar(); - } - - public void close() { - mHttpClient.close(); - } - - public String getOAuthClientId() { - return nativeGetOAuthClientId(); - } - - protected String getAPIKey() { - return nativeGetAPIKey(); - } - - private native String nativeGetAPIKey(); - private native String nativeGetOAuthClientId(); - private native String nativeGetOAuthClientSecret(); -}
diff --git a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/apiary/BlockingGCMRegistrar.java b/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/apiary/BlockingGCMRegistrar.java deleted file mode 100644 index 3cf5eaf0..0000000 --- a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/apiary/BlockingGCMRegistrar.java +++ /dev/null
@@ -1,82 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.components.devtools_bridge.apiary; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.os.Looper; - -import com.google.ipc.invalidation.external.client.contrib.MultiplexingGcmListener; - -import java.io.IOException; -import java.util.concurrent.CountDownLatch; - -/** - * Helps using MultiplexingGcmListene in blocking manner. If the app has not registered in GCM - * it sends registration request and waits for an intent with registration ID. - * Waiting may be interrupted. Must not be used on UI (or Context's main) looper. - */ -public final class BlockingGCMRegistrar { - public String blockingGetRegistrationId(Context context) - throws InterruptedException, IOException { - assert context != null; - assert context.getMainLooper() != Looper.myLooper(); - - Receiver receiver = new Receiver(); - receiver.register(context); - try { - // MultiplexingGcmListener starts registration if the app has not registered yet. - String result = MultiplexingGcmListener.initializeGcm(context); - if (result != null && !result.isEmpty()) return result; - return receiver.awaitRegistrationId(); - } finally { - receiver.unregister(context); - } - } - - private static class Receiver extends BroadcastReceiver { - private final CountDownLatch mDone = new CountDownLatch(1); - - private String mRegistrationId; - - public void register(Context context) { - IntentFilter filter = new IntentFilter(); - filter.addCategory(context.getPackageName()); - filter.addAction(MultiplexingGcmListener.Intents.ACTION); - context.registerReceiver(this, filter); - } - - public void unregister(Context context) { - context.unregisterReceiver(this); - } - - public String awaitRegistrationId() throws InterruptedException, IOException { - mDone.await(); - if (mRegistrationId != null) { - return mRegistrationId; - } - throw new IOException(); - } - - @Override - public void onReceive(Context context, Intent intent) { - assert intent.getAction().equals(MultiplexingGcmListener.Intents.ACTION); - - if (!intent.getBooleanExtra( - MultiplexingGcmListener.Intents.EXTRA_OP_REGISTERED, false)) { - return; - } - - mRegistrationId = intent.getStringExtra( - MultiplexingGcmListener.Intents.EXTRA_DATA_REG_ID); - - if (mRegistrationId != null) { - mDone.countDown(); - } - } - } -}
diff --git a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/apiary/GCDClient.java b/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/apiary/GCDClient.java deleted file mode 100644 index 7a3f52d..0000000 --- a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/apiary/GCDClient.java +++ /dev/null
@@ -1,193 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.components.devtools_bridge.apiary; - -import android.util.JsonReader; - -import org.apache.http.HttpResponse; -import org.apache.http.client.HttpClient; -import org.apache.http.client.HttpResponseException; -import org.apache.http.client.ResponseHandler; -import org.apache.http.client.methods.HttpDelete; -import org.apache.http.client.methods.HttpEntityEnclosingRequestBase; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.client.methods.HttpRequestBase; -import org.apache.http.entity.StringEntity; - -import org.chromium.components.devtools_bridge.commands.Command; -import org.chromium.components.devtools_bridge.gcd.InstanceCredential; -import org.chromium.components.devtools_bridge.gcd.InstanceDescription; -import org.chromium.components.devtools_bridge.gcd.MessageReader; -import org.chromium.components.devtools_bridge.gcd.MessageWriter; - -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.net.URI; - -/** - * Client for accessing GCD API. - */ -public class GCDClient { - private static final String API_BASE = "https://www.googleapis.com/clouddevices/v1"; - public static final String ENCODING = "UTF-8"; - protected static final String CONTENT_TYPE = "application/json; charset=" + ENCODING; - - protected final HttpClient mHttpClient; - private final String mAPIKey; - private final String mOAuthToken; - - GCDClient(HttpClient httpClient, String apiKey, String oAuthToken) { - mHttpClient = httpClient; - mAPIKey = apiKey; - mOAuthToken = oAuthToken; - } - - GCDClient(HttpClient httpClient, String apiKey) { - this(httpClient, apiKey, null); - } - - /** - * Creation of a registration ticket is the first step in instance registration. Client must - * have user credentials. If the ticket has been registered it will be associated with the - * user. Next step is registration ticket patching. - */ - public final String createRegistrationTicket() throws IOException { - assert mOAuthToken != null; - - return mHttpClient.execute( - newHttpPost("/registrationTickets", "{\"userEmail\":\"me\"}"), - new JsonResponseHandler<String>() { - @Override - public String readResponse(JsonReader reader) throws IOException { - return new MessageReader(reader).readTicketId(); - } - }); - } - - /** - * Patching registration ticket. GCD gets device definition including commands metadata, - * GCM channel description and user-visible instance name. - */ - public final void patchRegistrationTicket(String ticketId, InstanceDescription description) - throws IOException { - String content = new MessageWriter().writeTicketPatch(description).close().toString(); - - mHttpClient.execute( - newHttpPatch("/registrationTickets/" + ticketId, content), - new EmptyResponseHandler()); - } - - /** - * Finalizing registration. Client must be anonymous (GCD requirement). GCD provides - * instance credentials needed for handling commands. - */ - public final InstanceCredential finalizeRegistration(String ticketId) throws IOException { - return mHttpClient.execute( - newHttpPost("/registrationTickets/" + ticketId + "/finalize", ""), - new JsonResponseHandler<InstanceCredential>() { - @Override - public InstanceCredential readResponse(JsonReader reader) throws IOException { - return new MessageReader(reader).readInstanceCredential(); - } - }); - } - - public final void patchInstanceGCMChannel(String instanceId, String gcmChannelId) - throws IOException { - String content = new MessageWriter() - .writeDeviceGCMChannelPatch(gcmChannelId).close().toString(); - - mHttpClient.execute( - newHttpPatch("/devices/" + instanceId, content), - new EmptyResponseHandler()); - } - - /** - * Deletes registered instance (unregisters). If client has instance credentials then - * instanceId must be it's own ID. If client has user credentials then instance must belong - * to the user. - */ - public void deleteInstance(String instanceId) throws IOException { - mHttpClient.execute( - newHttpDelete("/devices/" + instanceId), - new EmptyResponseHandler()); - } - - /** - * Patches the command (previously received with Notification) with out-parameters or - * an error message. - */ - public final void patchCommand(Command command) throws IOException { - String content = new MessageWriter().writeCommandPatch(command).close().toString(); - - mHttpClient.execute( - newHttpPatch("/commands/" + command.id, content), - new EmptyResponseHandler()); - } - - protected final HttpGet newHttpGet(String path) { - return prepare(new HttpGet(buildUrl(path))); - } - - protected final HttpPost newHttpPost(String path, String content) - throws UnsupportedEncodingException { - return prepare(new HttpPost(buildUrl(path)), content); - } - - protected final HttpPost newHttpPost(String path, String query, String content) - throws UnsupportedEncodingException { - return prepare(new HttpPost(buildUrl(path, query)), content); - } - - protected final HttpPatch newHttpPatch(String path, String content) - throws UnsupportedEncodingException { - return prepare(new HttpPatch(buildUrl(path)), content); - } - - protected final HttpDelete newHttpDelete(String path) { - return prepare(new HttpDelete(buildUrl(path))); - } - - private String buildUrl(String path) { - return API_BASE + path + "?key=" + mAPIKey; - } - - private String buildUrl(String path, String query) { - return API_BASE + path + "?" + query + "&key=" + mAPIKey; - } - - private <T extends HttpEntityEnclosingRequestBase> T prepare(T request, String content) - throws UnsupportedEncodingException { - request.setEntity(new StringEntity(content, ENCODING)); - request.addHeader("Content-Type", CONTENT_TYPE); - return prepare(request); - } - - private <T extends HttpRequestBase> T prepare(T request) { - if (mOAuthToken != null) { - request.addHeader("Authorization", "Bearer " + mOAuthToken); - } - return request; - } - - private static final class HttpPatch extends HttpEntityEnclosingRequestBase { - public HttpPatch(String uri) { - setURI(URI.create(uri)); - } - - public String getMethod() { - return "PATCH"; - } - } - - private static class EmptyResponseHandler implements ResponseHandler<Void> { - @Override - public Void handleResponse(HttpResponse response) throws HttpResponseException { - JsonResponseHandler.checkStatus(response); - return null; - } - } -}
diff --git a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/apiary/JsonResponseHandler.java b/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/apiary/JsonResponseHandler.java deleted file mode 100644 index 1700cc5..0000000 --- a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/apiary/JsonResponseHandler.java +++ /dev/null
@@ -1,70 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.components.devtools_bridge.apiary; - -import android.util.JsonReader; - -import org.apache.http.HttpEntity; -import org.apache.http.HttpResponse; -import org.apache.http.StatusLine; -import org.apache.http.client.ClientProtocolException; -import org.apache.http.client.HttpResponseException; -import org.apache.http.client.ResponseHandler; - -import java.io.IOException; -import java.io.InputStreamReader; - -/** - * Base class for a ResponseHandler that reads response with JsonReader. Like BasicResponseHandler - * throws HttpResponseException if response code >= 300. - * - * It catchs JsonReader's runtime exception (IllegalStateException and IllegalArgumentException) - * and wraps them into ResponseFormatException. - */ -abstract class JsonResponseHandler<T> implements ResponseHandler<T> { - public static void checkStatus(HttpResponse response) throws HttpResponseException { - StatusLine statusLine = response.getStatusLine(); - if (response.getStatusLine().getStatusCode() >= 300) { - throw new HttpResponseException( - statusLine.getStatusCode(), statusLine.getReasonPhrase()); - } - } - - @Override - public final T handleResponse(HttpResponse response) - throws IOException, ClientProtocolException { - checkStatus(response); - HttpEntity entity = response.getEntity(); - if (entity == null) { - throw new ClientProtocolException("Missing content"); - } - JsonReader reader = new JsonReader(new InputStreamReader(entity.getContent())); - try { - T result = readResponse(reader); - reader.close(); - - if (result == null) { - throw new ClientProtocolException("Missing result"); - } - - return result; - } catch (IllegalStateException e) { - throw new ResponseFormatException(e); - } catch (IllegalArgumentException e) { - throw new ResponseFormatException(e); - } - } - - public abstract T readResponse(JsonReader reader) - throws IOException, ResponseFormatException; - - public static class ResponseFormatException extends ClientProtocolException { - public ResponseFormatException(RuntimeException readerException) { - super(readerException); - } - - public ResponseFormatException() {} - } -}
diff --git a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/apiary/OAuthClient.java b/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/apiary/OAuthClient.java deleted file mode 100644 index 7ddb381..0000000 --- a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/apiary/OAuthClient.java +++ /dev/null
@@ -1,102 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.components.devtools_bridge.apiary; - -import android.util.JsonReader; - -import org.apache.http.client.HttpClient; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.entity.StringEntity; - -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; - -/** - * Google authentication client. Fetches a pair of refresh/access tokens for a - * secret received while registering the instance in GCD. - */ -public class OAuthClient { - public static final String API_BASE = "https://accounts.google.com/o/oauth2"; - public static final String ENCODING = "UTF-8"; - public static final String CONTENT_TYPE = "application/x-www-form-urlencoded"; - - private final HttpClient mHttpClient; - private final String mScope; - private final String mClientId; - private final String mClientSecret; - - OAuthClient(HttpClient httpClient, String scope, String clientId, String clientSecret) { - assert httpClient != null; - assert scope != null; - assert clientId != null; - assert clientSecret != null; - - mHttpClient = httpClient; - mScope = scope; - mClientId = clientId; - mClientSecret = clientSecret; - } - - public OAuthResult authenticate(String secret) throws IOException { - final long startTimeMs = System.currentTimeMillis(); - - String content = - "client_id=" + urlEncode(mClientId) - + "&client_secret=" + urlEncode(mClientSecret) - + "&scope=" + urlEncode(mScope) - + "&code=" + urlEncode(secret) - + "&redirect_uri=oob" - + "&grant_type=authorization_code"; - - return mHttpClient.execute( - newHttpPost("/token", content), - new JsonResponseHandler<OAuthResult>() { - @Override - public OAuthResult readResponse(JsonReader reader) throws IOException { - return readResponse(reader, startTimeMs); - } - }); - } - - private HttpPost newHttpPost(String path, String content) throws UnsupportedEncodingException { - HttpPost request = new HttpPost(API_BASE + "/token"); - request.setEntity(new StringEntity(content, ENCODING)); - request.addHeader("Content-Type", CONTENT_TYPE); - return request; - } - - private static String urlEncode(String value) { - try { - return URLEncoder.encode(value, ENCODING); - } catch (UnsupportedEncodingException e) { - throw new RuntimeException(e); - } - } - - static OAuthResult readResponse(JsonReader reader, long startTimeMs) throws IOException { - String refreshToken = null; - String accessToken = null; - long expiresInS = 0; // In seconds. - - reader.beginObject(); - while (reader.hasNext()) { - String name = reader.nextName(); - if (name.equals("refresh_token")) { - refreshToken = reader.nextString(); - } else if (name.equals("access_token")) { - accessToken = reader.nextString(); - } else if (name.equals("expires_in")) { - expiresInS = reader.nextLong(); - } else { - reader.skipValue(); - } - } - reader.endObject(); - - return OAuthResult.create( - refreshToken, accessToken, startTimeMs + expiresInS * 1000); - } -}
diff --git a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/apiary/OAuthResult.java b/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/apiary/OAuthResult.java deleted file mode 100644 index 3c9c5ac..0000000 --- a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/apiary/OAuthResult.java +++ /dev/null
@@ -1,28 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.components.devtools_bridge.apiary; - -/** - * Pair of refresh/access tokens fetched with OAuthClient. - */ -public class OAuthResult { - public String refreshToken; - public String accessToken; - public final long expirationTimeMs; // In milliseconds. - - private OAuthResult(String refreshToken, String accessToken, long expirationTimeMs) { - assert refreshToken != null; - - this.refreshToken = refreshToken; - this.accessToken = accessToken; - this.expirationTimeMs = expirationTimeMs; - } - - public static OAuthResult create( - String refreshToken, String accessToken, long expirationTimeMs) { - return refreshToken != null - ? new OAuthResult(refreshToken, accessToken, expirationTimeMs) : null; - } -}
diff --git a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/commands/Command.java b/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/commands/Command.java deleted file mode 100644 index d71eacf..0000000 --- a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/commands/Command.java +++ /dev/null
@@ -1,84 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.components.devtools_bridge.commands; - -import java.util.Map; - -/** - * Base class for a command. Command is an abstracton over GCD's command. Command - * has state, in- and out-parameters. Both parameters are encoded as a hash of strings. - */ -public abstract class Command { - public final Type type; - public final String id; - - private State mState = State.INITIAL; - private String mErrorMessage; - - public enum State { - INITIAL, DONE, ERROR - } - - public enum Type { - START_SESSION(Commands.StartSessionCommand.DEFINITION), - ICE_EXCHANGE(Commands.IceExchangeCommand.DEFINITION), - RENEGOTIATE(Commands.RenegotiateCommand.DEFINITION); - - public final CommandDefinition definition; - - Type(CommandDefinition definition) { - this.definition = definition; - } - } - - /** - * Provides access to parameters values with the Visitor pattern. - */ - public interface ParamVisitor { - void visit(ParamDefinition<?> param, String value); - } - - protected Command(Type type, String id) { - assert type != null; - - this.type = type; - this.id = id; - } - - public State state() { - return mState; - } - - public abstract void visitInParams(ParamVisitor visitor); - - public abstract void visitOutParams(ParamVisitor visitor); - - protected abstract void setOutParams(Map<String, String> actualOutParams) - throws CommandFormatException; - - protected final void setDone() { - assert mState == State.INITIAL; - - mState = State.DONE; - } - - public void setSuccess(Map<String, String> actualOutParams) throws CommandFormatException { - setOutParams(actualOutParams); - setDone(); - } - - public void setFailure(String errorMessage) { - assert mState == State.INITIAL; - - mState = State.ERROR; - mErrorMessage = errorMessage; - } - - public String getErrorMessage() { - assert mState == State.ERROR; - - return mErrorMessage; - } -}
diff --git a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/commands/CommandDefinition.java b/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/commands/CommandDefinition.java deleted file mode 100644 index b7ddaf0..0000000 --- a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/commands/CommandDefinition.java +++ /dev/null
@@ -1,40 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.components.devtools_bridge.commands; - -import java.util.List; -import java.util.Map; - -/** - * Definition for a Command and a command factory. Definition needed when - * registering in GCD. GCD only interested in in-parameters so to CommandDefinition. - */ -public abstract class CommandDefinition { - private final String mName; - private final List<ParamDefinition<?>> mInParams; - - public CommandDefinition(String name, List<ParamDefinition<?>> inParams) { - mName = name; - mInParams = inParams; - } - - public Iterable<ParamDefinition<?>> inParams() { - return mInParams; - } - - public String shortName() { - return "_" + mName; - } - - public String fullName() { - return "base._" + mName; - } - - /** - * Factory method for creaiting a command from serialized state. - */ - public abstract Command newCommand(String id, Map<String, String> actualParameters) - throws CommandFormatException; -}
diff --git a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/commands/CommandFormatException.java b/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/commands/CommandFormatException.java deleted file mode 100644 index 5054a3ad..0000000 --- a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/commands/CommandFormatException.java +++ /dev/null
@@ -1,18 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.components.devtools_bridge.commands; - -/** - * This exception throws then a Command object cannot be reconstructed from serialized state. - */ -public class CommandFormatException extends Exception { - public CommandFormatException(String message) { - super(message); - } - - public CommandFormatException(String message, Exception cause) { - super(message, cause); - } -}
diff --git a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/commands/CommandReceiver.java b/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/commands/CommandReceiver.java deleted file mode 100644 index 96672c7d..0000000 --- a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/commands/CommandReceiver.java +++ /dev/null
@@ -1,97 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.components.devtools_bridge.commands; - -import org.chromium.components.devtools_bridge.SessionBase; -import org.chromium.components.devtools_bridge.SignalingReceiver; - -import java.util.List; - -/** - * Converts commands to SignalingReceiver's calls. - */ -public class CommandReceiver { - private final SignalingReceiver mBase; - - public CommandReceiver(SignalingReceiver base) { - mBase = base; - } - - public void receive(Command command, Runnable completionHandler) { - switch (command.type) { - case START_SESSION: - onCommand((Commands.StartSessionCommand) command, completionHandler); - break; - - case RENEGOTIATE: - onCommand((Commands.RenegotiateCommand) command, completionHandler); - break; - - case ICE_EXCHANGE: - onCommand((Commands.IceExchangeCommand) command, completionHandler); - break; - - default: - assert false; - } - } - - private void onCommand( - final Commands.StartSessionCommand command, final Runnable completionHandler) { - mBase.startSession( - command.sessionId, command.config, command.offer, - new SessionBase.NegotiationCallback() { - @Override - public void onSuccess(String answer) { - command.setResult(answer); - completionHandler.run(); - } - - @Override - public void onFailure(String errorMessage) { - command.setFailure(errorMessage); - completionHandler.run(); - } - }); - } - - private void onCommand( - final Commands.RenegotiateCommand command, final Runnable completionHandler) { - mBase.renegotiate( - command.sessionId, command.offer, - new SessionBase.NegotiationCallback() { - @Override - public void onSuccess(String answer) { - command.setResult(answer); - completionHandler.run(); - } - - @Override - public void onFailure(String errorMessage) { - command.setFailure(errorMessage); - completionHandler.run(); - } - }); - } - - private void onCommand( - final Commands.IceExchangeCommand command, final Runnable completionHandler) { - mBase.iceExchange( - command.sessionId, command.clientCandidates, - new SessionBase.IceExchangeCallback() { - @Override - public void onSuccess(List<String> serverCandidates) { - command.setResult(serverCandidates); - completionHandler.run(); - } - - @Override - public void onFailure(String errorMessage) { - command.setFailure(errorMessage); - completionHandler.run(); - } - }); - } -}
diff --git a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/commands/Commands.java b/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/commands/Commands.java deleted file mode 100644 index 2157078..0000000 --- a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/commands/Commands.java +++ /dev/null
@@ -1,196 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.components.devtools_bridge.commands; - -import org.chromium.components.devtools_bridge.RTCConfiguration; - -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Map; - -/** - * Implementation of all commands. - */ -final class Commands { - public static final String NO_ID = null; - - // In params. - private static final ParamDefinition<String> PARAM_SESSION_ID = - ParamDefinitions.newStringParam("sessionId"); - private static final ParamDefinition<RTCConfiguration> PARAM_CONFIG = - ParamDefinitions.newConfigParam("config"); - private static final ParamDefinition<String> PARAM_OFFER = - ParamDefinitions.newStringParam("offer"); - private static final ParamDefinition<List<String>> PARAM_CLIENT_CANDIDATES = - ParamDefinitions.newStringListParam("clientCandidates"); - - // Out params. - private static final ParamDefinition<String> PARAM_ANSWER = - ParamDefinitions.newStringParam("answer"); - private static final ParamDefinition<List<String>> PARAM_SERVER_CANDIDATES = - ParamDefinitions.newStringListParam("serverCandidates"); - - /** - * Common base class for signaling commands. All commands needed so far have a session ID - * and a single out parameter (result). - */ - abstract static class SignalingCommandBase<R> extends Command { - public final String sessionId; - public R mResult; - - protected SignalingCommandBase(Type type, String id, String sessionId) { - super(type, id); - this.sessionId = sessionId; - } - - @Override - public void visitInParams(ParamVisitor visitor) { - PARAM_SESSION_ID.pass(visitor, sessionId); - } - - @Override - public final void visitOutParams(ParamVisitor visitor) { - resultDefinition().pass(visitor, mResult); - } - - @Override - protected void setOutParams(Map<String, String> actualOutParams) - throws CommandFormatException { - mResult = resultDefinition().checkAndGet(actualOutParams); - } - - public final void setResult(R result) { - mResult = result; - setDone(); - } - - public final R getResult() { - assert state() == State.DONE; - return mResult; - } - - protected abstract ParamDefinition<R> resultDefinition(); - } - - static final class StartSessionCommand extends SignalingCommandBase<String> { - public final RTCConfiguration config; - public final String offer; - - public static final CommandDefinition DEFINITION = new CommandDefinition( - "startSession", params(PARAM_SESSION_ID, PARAM_CONFIG, PARAM_OFFER)) { - @Override - public Command newCommand(String id, Map<String, String> actualParameters) - throws CommandFormatException { - return new StartSessionCommand( - id, - PARAM_SESSION_ID.get(actualParameters), - PARAM_CONFIG.get(actualParameters), - PARAM_OFFER.get(actualParameters)); - } - }; - - private StartSessionCommand( - String id, String sessionId, RTCConfiguration config, String offer) { - super(Type.START_SESSION, id, sessionId); - this.config = config; - this.offer = offer; - } - - public StartSessionCommand(String sessionId, RTCConfiguration config, String offer) { - this(NO_ID, sessionId, config, offer); - } - - @Override - public void visitInParams(ParamVisitor visitor) { - super.visitInParams(visitor); - PARAM_CONFIG.pass(visitor, config); - PARAM_OFFER.pass(visitor, offer); - } - - @Override - protected ParamDefinition<String> resultDefinition() { - return PARAM_ANSWER; - } - } - - static final class IceExchangeCommand extends SignalingCommandBase<List<String>> { - private static final String SERVER_CANDIDATES = "serverCandidates"; - - public final List<String> clientCandidates; - - public static final CommandDefinition DEFINITION = new CommandDefinition( - "iceExchange", params(PARAM_SESSION_ID, PARAM_CLIENT_CANDIDATES)) { - @Override - public Command newCommand(String id, Map<String, String> actualParameters) - throws CommandFormatException { - return new IceExchangeCommand( - id, - PARAM_SESSION_ID.get(actualParameters), - PARAM_CLIENT_CANDIDATES.get(actualParameters)); - } - }; - - private IceExchangeCommand(String id, String sessionId, List<String> clientCandidates) { - super(Type.ICE_EXCHANGE, id, sessionId); - this.clientCandidates = clientCandidates; - } - - public IceExchangeCommand(String sessionId, List<String> clientCandidates) { - this(NO_ID, sessionId, clientCandidates); - } - - @Override - public void visitInParams(ParamVisitor visitor) { - super.visitInParams(visitor); - PARAM_CLIENT_CANDIDATES.pass(visitor, clientCandidates); - } - - @Override - protected ParamDefinition<List<String>> resultDefinition() { - return PARAM_SERVER_CANDIDATES; - } - } - - static final class RenegotiateCommand extends SignalingCommandBase<String> { - public final String offer; - - public static final CommandDefinition DEFINITION = new CommandDefinition( - "renegotiate", params(PARAM_SESSION_ID, PARAM_OFFER)) { - @Override - public Command newCommand(String id, Map<String, String> actualParameters) - throws CommandFormatException { - return new RenegotiateCommand( - id, - PARAM_SESSION_ID.get(actualParameters), - PARAM_OFFER.get(actualParameters)); - } - }; - - private RenegotiateCommand(String id, String sessionId, String offer) { - super(Type.RENEGOTIATE, id, sessionId); - this.offer = offer; - } - - public RenegotiateCommand(String sessionId, String offer) { - this(NO_ID, sessionId, offer); - } - - @Override - public void visitInParams(ParamVisitor visitor) { - super.visitInParams(visitor); - PARAM_OFFER.pass(visitor, offer); - } - - @Override - protected ParamDefinition<String> resultDefinition() { - return PARAM_ANSWER; - } - } - - private static List<ParamDefinition<?>> params(ParamDefinition<?>... values) { - return Collections.unmodifiableList(Arrays.asList(values)); - } -}
diff --git a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/commands/ParamDefinition.java b/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/commands/ParamDefinition.java deleted file mode 100644 index 07fd314..0000000 --- a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/commands/ParamDefinition.java +++ /dev/null
@@ -1,49 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.components.devtools_bridge.commands; - -import java.util.Map; - -/** - * Desribes in- or out-parameter of a Command. - * @param <T> Type of the parameter. - */ -public abstract class ParamDefinition<T> { - public final String mName; - - protected ParamDefinition(String name) { - mName = name; - } - - public String name() { - return "_" + mName; - } - - public String type() { - return "string"; - } - - public void checkPresents(Map<String, String> actualParameters) throws CommandFormatException { - if (!actualParameters.containsKey(name())) { - throw new CommandFormatException("Missing parameter " + mName); - } - } - - public T get(Map<String, String> actualParameters) throws CommandFormatException { - return fromString(actualParameters.get(name())); - } - - public T checkAndGet(Map<String, String> actualParameters) throws CommandFormatException { - checkPresents(actualParameters); - return get(actualParameters); - } - - public final void pass(Command.ParamVisitor visitor, T value) { - visitor.visit(this, toString(value)); - } - - protected abstract T fromString(String value) throws CommandFormatException; - protected abstract String toString(T value); -}
diff --git a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/commands/ParamDefinitions.java b/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/commands/ParamDefinitions.java deleted file mode 100644 index c2b0446..0000000 --- a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/commands/ParamDefinitions.java +++ /dev/null
@@ -1,203 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.components.devtools_bridge.commands; - -import android.util.JsonReader; -import android.util.JsonWriter; - -import org.chromium.components.devtools_bridge.RTCConfiguration; - -import java.io.IOException; -import java.io.StringReader; -import java.io.StringWriter; -import java.util.ArrayList; -import java.util.List; - -/** - * Hepler class with a collection of parameter definitions. - */ -final class ParamDefinitions { - public static ParamDefinition<String> newStringParam(String name) { - return new ParamDefinition<String>(name) { - @Override - protected String fromString(String value) { - return value; - } - - @Override - protected String toString(String value) { - return value; - } - }; - } - - public static ParamDefinition<List<String>> newStringListParam(String name) { - return new ParamDefinition<List<String>>(name) { - @Override - protected List<String> fromString(String value) throws CommandFormatException { - try { - return new ParamReader(value) - .readStringList() - .close() - .stringListResult; - } catch (Exception e) { - throw newException(this, "Expected JSON-serialized string list", e); - } - } - - @Override - protected String toString(List<String> value) { - try { - return new ParamWriter().write(value).close().toString(); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - }; - } - - public static ParamDefinition<RTCConfiguration> newConfigParam(String name) { - return new ParamDefinition<RTCConfiguration>(name) { - @Override - protected RTCConfiguration fromString(String value) throws CommandFormatException { - try { - return new ParamReader(value) - .readConfig() - .close() - .configResult; - } catch (Exception e) { - throw newException(this, "Expected WebRTC configuration", e); - } - } - - @Override - protected String toString(RTCConfiguration value) { - try { - return new ParamWriter().write(value).close().toString(); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - }; - } - - private static CommandFormatException newException( - ParamDefinition<?> param, String message, Exception cause) { - return new CommandFormatException( - "Exception in parameter " + param.name() + ": " + message, cause); - } - - private static class ParamReader { - private final JsonReader mReader; - - public List<String> stringListResult; - public RTCConfiguration configResult; - - public ParamReader(String source) { - mReader = new JsonReader(new StringReader(source)); - } - - public ParamReader readStringList() throws IOException { - stringListResult = new ArrayList<String>(); - mReader.beginArray(); - while (mReader.hasNext()) { - stringListResult.add(mReader.nextString()); - } - mReader.endArray(); - return this; - } - - public ParamReader readConfig() throws IOException { - RTCConfiguration.Builder builder = new RTCConfiguration.Builder(); - mReader.beginObject(); - while (mReader.hasNext()) { - String name = mReader.nextName(); - if ("iceServers".equals(name)) { - readIceServerList(builder); - } else { - mReader.skipValue(); - } - } - configResult = builder.build(); - return this; - } - - public ParamReader close() throws IOException { - mReader.close(); - return this; - } - - private void readIceServerList(RTCConfiguration.Builder builder) throws IOException { - mReader.beginArray(); - while (mReader.hasNext()) { - readIceServer(builder); - } - mReader.endArray(); - } - - private void readIceServer(RTCConfiguration.Builder builder) throws IOException { - String uri = null; - String username = ""; - String credential = ""; - mReader.beginObject(); - while (mReader.hasNext()) { - String name = mReader.nextName(); - if ("uri".equals(name)) { - uri = mReader.nextString(); - } else if ("username".equals(name)) { - username = mReader.nextString(); - } else if ("credential".equals(name)) { - credential = mReader.nextString(); - } else { - mReader.skipValue(); - } - } - mReader.endObject(); - if (uri != null) { - builder.addIceServer(uri, username, credential); - } - } - } - - private static class ParamWriter { - private final StringWriter mStringWriter = new StringWriter(); - private final JsonWriter mWriter = new JsonWriter(mStringWriter); - - public ParamWriter write(List<String> value) throws IOException { - mWriter.beginArray(); - for (String item : value) { - mWriter.value(item); - } - mWriter.endArray(); - return this; - } - - public ParamWriter write(RTCConfiguration config) throws IOException { - mWriter.beginObject(); - mWriter.name("iceServers"); - mWriter.beginArray(); - for (RTCConfiguration.IceServer server : config.iceServers) { - mWriter.beginObject(); - mWriter.name("uri").value(server.uri); - mWriter.name("username").value(server.username); - mWriter.name("credential").value(server.credential); - mWriter.endObject(); - } - mWriter.endArray(); - mWriter.endObject(); - return this; - } - - public ParamWriter close() throws IOException { - mWriter.close(); - return this; - } - - @Override - public String toString() { - return mStringWriter.toString(); - } - } -}
diff --git a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/gcd/InstanceCredential.java b/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/gcd/InstanceCredential.java deleted file mode 100644 index 7edb8077..0000000 --- a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/gcd/InstanceCredential.java +++ /dev/null
@@ -1,49 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.components.devtools_bridge.gcd; - -import android.content.SharedPreferences; - -/** - * Information provided by GCD when instance has registered. Instance id - * can be used for: - * 1. Making sure incoming messages are addressed to the instance. - * 2. It needed when sending command results to GCD. - * 3. For device unregistration. - * - * The Secret supposed to be used to authenticate the instance with OAuthClient - * (it has no user credentials). - */ -public final class InstanceCredential { - public static final String PREF_ID = "gcd.ID"; - public static final String PREF_SECRET = "gcd.SECRET"; - - public final String id; - public final String secret; - - public InstanceCredential(String id, String secret) { - assert id != null; - assert secret != null; - - this.id = id; - this.secret = secret; - } - - public static InstanceCredential get(SharedPreferences preferences) { - String id = preferences.getString(PREF_ID, null); - String secret = preferences.getString(PREF_SECRET, null); - return id != null && secret != null ? new InstanceCredential(id, secret) : null; - } - - public void put(SharedPreferences.Editor editor) { - editor.putString(PREF_ID, id); - editor.putString(PREF_SECRET, secret); - } - - public static void remove(SharedPreferences.Editor editor) { - editor.remove(PREF_ID); - editor.remove(PREF_SECRET); - } -}
diff --git a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/gcd/InstanceDescription.java b/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/gcd/InstanceDescription.java deleted file mode 100644 index 6d740bb7..0000000 --- a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/gcd/InstanceDescription.java +++ /dev/null
@@ -1,55 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.components.devtools_bridge.gcd; - -/** - * Information needed for registration in GCD. - * Instance secret will be bound to oAuthClientId. - * gcmChannelId will be used for delivering commands. - * displayName is a human readable name on the client side. - */ -public final class InstanceDescription { - public final String oAuthClientId; - public final String gcmChannelId; - public final String displayName; - - private InstanceDescription(String oAuthClientId, String gcmChannelId, String displayName) { - assert oAuthClientId != null; - assert gcmChannelId != null; - assert displayName != null; - - this.oAuthClientId = oAuthClientId; - this.gcmChannelId = gcmChannelId; - this.displayName = displayName; - } - - /** - * Builder for InstanceDescription. - */ - public static final class Builder { - private String mOAuthClientId; - private String mGCMChannelId; - private String mDisplayName; - - public Builder setOAuthClientId(String value) { - mOAuthClientId = value; - return this; - } - - public Builder setGCMChannelId(String value) { - mGCMChannelId = value; - return this; - } - - public Builder setDisplayName(String value) { - mDisplayName = value; - return this; - } - - public InstanceDescription build() { - return new InstanceDescription(mOAuthClientId, mGCMChannelId, mDisplayName); - } - } -}
diff --git a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/gcd/MessageReader.java b/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/gcd/MessageReader.java deleted file mode 100644 index 87c61f6d..0000000 --- a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/gcd/MessageReader.java +++ /dev/null
@@ -1,181 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.components.devtools_bridge.gcd; - -import android.util.JsonReader; - -import org.chromium.components.devtools_bridge.commands.Command; -import org.chromium.components.devtools_bridge.commands.CommandFormatException; - -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; - -/** - * Helper class for parsing JSON-encoded GCD messages (HTTP responses and GCM notifications) used - * in the DevTools bridge. - */ -public final class MessageReader { - private final JsonReader mReader; - - public MessageReader(JsonReader reader) { - mReader = reader; - } - - /** - * Reads id from a registration ticket. - */ - public String readTicketId() throws IOException { - return new TicketReader().readId(); - } - - /** - * Reads credentials from finalized registration ticket. - */ - public InstanceCredential readInstanceCredential() throws IOException { - return new TicketReader().readCredential(); - } - - Notification readNotification() throws IOException, CommandFormatException { - return new NotificationReader().read(); - } - - private abstract class ObjectReader { - public final void readObject() throws IOException { - mReader.beginObject(); - while (mReader.hasNext()) { - readItem(mReader.nextName()); - } - mReader.endObject(); - } - - protected void readItem(String name) throws IOException { - mReader.skipValue(); - } - } - - private class TicketReader extends ObjectReader { - private String mId; - private String mDeviceId; - private String mDeviceSecret; - - public String readId() throws IOException { - readObject(); - if (mId == null) { - throw new IllegalArgumentException(); - } - return mId; - } - - public InstanceCredential readCredential() throws IOException { - readObject(); - if (mDeviceId == null || mDeviceSecret == null) { - throw new IllegalArgumentException(); - } - return new InstanceCredential(mDeviceId, mDeviceSecret); - } - - @Override - protected void readItem(String name) throws IOException { - if (name.equals("id")) { - mId = mReader.nextString(); - } else if (name.equals("deviceId")) { - mDeviceId = mReader.nextString(); - } else if (name.equals("robotAccountAuthorizationCode")) { - mDeviceSecret = mReader.nextString(); - } else { - super.readItem(name); - } - } - } - - private class NotificationReader extends ObjectReader { - private String mDeviceId; - private String mType; - private String mCommandId; - private CommandReader mCommandReader; - - public Notification read() throws IOException, CommandFormatException { - readObject(); - if (mDeviceId == null || mType == null) return null; - if (mType.equals("COMMAND_CREATED")) { - if (mCommandReader == null) { - throw new CommandFormatException("Command missing"); - } - if (mCommandId == null) { - throw new CommandFormatException("Command id missing"); - } - return new Notification( - mDeviceId, Notification.Type.COMMAND_CREATED, - mCommandReader.newCommand(mCommandId)); - } else if (mType.equals("DEVICE_DELETED")) { - return new Notification(mDeviceId, Notification.Type.INSTANCE_UNREGISTERED, null); - } else { - return null; - } - } - - @Override - protected void readItem(String name) throws IOException { - if (name.equals("deviceId")) { - mDeviceId = mReader.nextString(); - } else if (name.equals("type")) { - mType = mReader.nextString(); - } else if (name.equals("commandId")) { - mCommandId = mReader.nextString(); - } else if (name.equals("command")) { - mCommandReader = new CommandReader(); - mCommandReader.readObject(); - } else { - super.readItem(name); - } - } - } - - private class CommandReader extends ObjectReader { - private String mType; - private Map<String, String> mParameters; - - public Command newCommand(String id) throws CommandFormatException { - if (mType == null) { - throw new CommandFormatException("Missing command type"); - } - if (mParameters == null) { - throw new CommandFormatException("Missing parameters"); - } - return convertType(mType).definition.newCommand(id, mParameters); - } - - @Override - protected void readItem(String name) throws IOException { - if (name.equals("name")) { - mType = mReader.nextString(); - } else if (name.equals("parameters")) { - mParameters = readStringMap(mReader); - } else { - super.readItem(name); - } - } - - private Command.Type convertType(String name) throws CommandFormatException { - for (Command.Type type : Command.Type.values()) { - if (type.definition.fullName().equals(name)) return type; - } - throw new CommandFormatException("Invalid type: " + name); - } - } - - static Map<String, String> readStringMap(JsonReader reader) throws IOException { - Map<String, String> result = new HashMap<String, String>(); - reader.beginObject(); - while (reader.hasNext()) { - String name = reader.nextName(); - String value = reader.nextString(); - result.put(name, value); - } - reader.endObject(); - return result; - } -}
diff --git a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/gcd/MessageWriter.java b/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/gcd/MessageWriter.java deleted file mode 100644 index 2d7388f..0000000 --- a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/gcd/MessageWriter.java +++ /dev/null
@@ -1,156 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.components.devtools_bridge.gcd; - -import android.util.JsonWriter; - -import org.chromium.components.devtools_bridge.commands.Command; -import org.chromium.components.devtools_bridge.commands.ParamDefinition; - -import java.io.IOException; -import java.io.StringWriter; - -/** - * Helper class for constructing GCD JSON messages (HTTP requests) used in the DevTools bridge. - */ -public final class MessageWriter { - private final StringWriter mStringWriter; - private final JsonWriter mWriter; - boolean mClosed = false; - - public MessageWriter() { - mStringWriter = new StringWriter(); - mWriter = new JsonWriter(mStringWriter); - } - - public MessageWriter close() throws IOException { - assert !mClosed; - mWriter.close(); - mClosed = true; - return this; - } - - @Override - public String toString() { - assert mClosed; - return mStringWriter.toString(); - } - - /** - * Writes body of registrationTicket PATCH request. - */ - public MessageWriter writeTicketPatch(InstanceDescription description) throws IOException { - mWriter.beginObject(); - mWriter.name("deviceDraft"); - writeDeviceDraft(description); - mWriter.name("oauthClientId").value(description.oAuthClientId); - mWriter.endObject(); - return this; - } - - /** - * Writes body of devices/<instanceId> PATCH request. - */ - public MessageWriter writeDeviceGCMChannelPatch(String gcmChannelId) throws IOException { - mWriter.beginObject(); - mWriter.name("channel"); - mWriter.beginObject(); - mWriter.name("gcmRegistrationId").value(gcmChannelId); - mWriter.endObject(); - mWriter.endObject(); - return this; - } - - private void writeDeviceDraft(InstanceDescription description) throws IOException { - mWriter.beginObject(); - mWriter.name("deviceKind").value("vendor"); - mWriter.name("displayName").value(description.displayName); - mWriter.name("systemName").value("Chrome DevTools Bridge"); - mWriter.name("channel"); - writeChannelDefinition(description); - mWriter.name("commandDefs"); - writeCommandsDefinition(); - mWriter.endObject(); - } - - private void writeChannelDefinition(InstanceDescription description) throws IOException { - mWriter.beginObject(); - mWriter.name("supportedType").value("gcm"); - mWriter.name("gcmRegistrationId").value(description.gcmChannelId); - mWriter.endObject(); - } - - private void writeCommandsDefinition() throws IOException { - mWriter.beginObject(); - mWriter.name("base"); - writeCommandsDefinitionBase(); - mWriter.endObject(); - } - - private void writeCommandsDefinitionBase() throws IOException { - mWriter.beginObject(); - for (Command.Type type : Command.Type.values()) { - mWriter.name(type.definition.shortName()); - beginParameters(); - for (ParamDefinition<?> param : type.definition.inParams()) { - writeParameter(param.name(), param.type()); - } - endParameters(); - } - mWriter.endObject(); - } - - private void beginParameters() throws IOException { - mWriter.beginObject(); - mWriter.name("parameters"); - mWriter.beginObject(); - } - - private void endParameters() throws IOException { - mWriter.endObject(); - mWriter.endObject(); - } - - private void writeParameter(String name, String type) throws IOException { - mWriter.name(name); - mWriter.beginObject(); - mWriter.name("type").value(type); - mWriter.endObject(); - } - - /** - * Writes body of command PATCH request. Updates command status and out parametes - * when the command has processed. - */ - public MessageWriter writeCommandPatch(Command command) throws IOException { - mWriter.beginObject(); - if (command.state() == Command.State.DONE) { - mWriter.name("state").value("done"); - mWriter.name("results"); - mWriter.beginObject(); - command.visitOutParams(new ParamWriter()); - mWriter.endObject(); - } else if (command.state() == Command.State.ERROR) { - mWriter.name("state").value("error"); - mWriter.name("error"); - mWriter.beginObject(); - mWriter.name("message").value(command.getErrorMessage()); - mWriter.endObject(); - } - mWriter.endObject(); - return this; - } - - private class ParamWriter implements Command.ParamVisitor { - @Override - public void visit(ParamDefinition<?> param, String value) { - try { - mWriter.name(param.name()).value(value); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - } -}
diff --git a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/gcd/Notification.java b/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/gcd/Notification.java deleted file mode 100644 index e8899f4..0000000 --- a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/gcd/Notification.java +++ /dev/null
@@ -1,63 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.components.devtools_bridge.gcd; - -import android.util.JsonReader; - -import org.chromium.components.devtools_bridge.commands.Command; -import org.chromium.components.devtools_bridge.commands.CommandFormatException; - -import java.io.IOException; -import java.io.StringReader; - -/** - * Notification that GCD sends to an instance. - */ -public final class Notification { - public final String instanceId; - public final Type type; - public final Command command; - - public enum Type { - COMMAND_CREATED, // Command created and needs to be executed. - INSTANCE_UNREGISTERED // Instance unregistered (possibly through external UI). - } - - Notification(String instanceId, Type type, Command command) { - this.instanceId = instanceId; - this.type = type; - this.command = command; - } - - public static Notification read(String source) throws FormatException { - JsonReader reader = new JsonReader(new StringReader(source)); - try { - Notification result = new MessageReader(reader).readNotification(); - reader.close(); - return result; - } catch (CommandFormatException e) { - throw new FormatException(e); - } catch (IllegalStateException e) { - throw new FormatException(e); - } catch (IllegalArgumentException e) { - throw new FormatException(e); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - /** - * Exception when parsing notification. - */ - public static class FormatException extends Exception { - public FormatException(RuntimeException cause) { - super(cause); - } - - public FormatException(CommandFormatException cause) { - super(cause); - } - } -}
diff --git a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/ui/GCDRegistrationFragment.java b/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/ui/GCDRegistrationFragment.java deleted file mode 100644 index 09989b37..0000000 --- a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/ui/GCDRegistrationFragment.java +++ /dev/null
@@ -1,320 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.components.devtools_bridge.ui; - -import android.accounts.Account; -import android.accounts.AccountManager; -import android.accounts.AccountManagerCallback; -import android.accounts.AccountManagerFuture; -import android.app.Activity; -import android.app.Fragment; -import android.app.ProgressDialog; -import android.content.Context; -import android.content.DialogInterface; -import android.content.Intent; -import android.content.SharedPreferences; -import android.os.AsyncTask; -import android.os.Bundle; -import android.util.Log; -import android.widget.Toast; - -import org.chromium.components.devtools_bridge.DevToolsBridgeServer; -import org.chromium.components.devtools_bridge.apiary.ApiaryClientFactory; -import org.chromium.components.devtools_bridge.apiary.OAuthResult; -import org.chromium.components.devtools_bridge.gcd.InstanceCredential; -import org.chromium.components.devtools_bridge.gcd.InstanceDescription; - -import java.io.IOException; - -/** - * Fragment that responsible for: - * 1. Displaying GCD registration status. - * 2. Instance registration. - * 3. Instance unregistration. - * - * Fragment is abstract and does not provide UI controls. Descendant is responsible for it. - * It also should have actionable item for registration/unregistration which invokes - * appropriate methods. - */ -public abstract class GCDRegistrationFragment extends Fragment - implements SharedPreferences.OnSharedPreferenceChangeListener { - private static final String TAG = "GCDRegistrationFragment"; - private static final String PREF_OWNER_EMAIL = "ui.OWNER_EMAIL"; - private static final String PREF_DISPLAY_NAME = "ui.OWNER_EMAIL"; - private static final int CODE_ACCOUNT_SELECTED = 1; - - private ApiaryClientFactory mClientFactory; - private Account mSelectedAccount = null; - - private SharedPreferences mPreferences; - - private InstanceCredential mInstanceCredential; - - @Override - public void onCreate(Bundle savedInstanceState) { - mClientFactory = new ApiaryClientFactory(); - mPreferences = DevToolsBridgeServer.getPreferences(getActivity()); - mPreferences.registerOnSharedPreferenceChangeListener(this); - mInstanceCredential = InstanceCredential.get(mPreferences); - super.onCreate(savedInstanceState); - } - - @Override - public void onDestroy() { - super.onDestroy(); - mPreferences.unregisterOnSharedPreferenceChangeListener(this); - new AsyncTask<Void, Void, Void>() { - @Override - protected final Void doInBackground(Void... args) { - mClientFactory.close(); - return null; - } - }.execute(); - } - - @Override - public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { - if (key.equals(InstanceCredential.PREF_ID)) { - mInstanceCredential = InstanceCredential.get(mPreferences); - onRegistrationStatusChange(); - } - } - - public void register() { - AccountManager manager = AccountManager.get(getActivity()); - - Intent intent = manager.newChooseAccountIntent( - mSelectedAccount, - null /* allowableAccounts */, - new String[] { "com.google" } /* allowableAccountTypes */, - true /* alwaysPromptForAccount */, - "Registration in GCD" /* descriptionOverrideText */, - null /* addAccountAuthTokenType */, - null /* addAccountRequiredFeatures */, - null /* addAccountOptions */); - startActivityForResult(intent, CODE_ACCOUNT_SELECTED); - } - - public void unregister() { - if (mInstanceCredential == null) return; - - new RegistrationTask("Unregistering instance") { - private InstanceCredential mInstranceCredentialCopy = mInstanceCredential; - - @Override - protected void doInBackgroundImpl() throws IOException, InterruptedException { - OAuthResult result = mClientFactory.newOAuthClient() - .authenticate(mInstranceCredentialCopy.secret); - - checkInterrupted(); - - Log.d(TAG, "Access token: " + result.accessToken); - - mClientFactory.newGCDClient(result.accessToken) - .deleteInstance(mInstranceCredentialCopy.id); - } - - @Override - protected void onSuccess() { - saveRegistration(null, null, null); - onRegistrationStatusChange(); - showToast("Unregistered"); - } - - @Override - protected void onFailure(Exception e) { - Log.e(TAG, "Unregistration failed", e); - showToast("Unregistration failed. See log for details."); - } - }.execute(); - } - - public boolean isRegistered() { - return mInstanceCredential != null; - } - - public String getOwner() { - return mPreferences.getString(PREF_OWNER_EMAIL, ""); - } - - public String getDisplayName() { - return mPreferences.getString(PREF_DISPLAY_NAME, ""); - } - - public void queryOAuthToken() { - if (mSelectedAccount == null) return; - - AccountManager manager = AccountManager.get(getActivity()); - - final String ownerEmail = mSelectedAccount.name; - - manager.getAuthToken( - mSelectedAccount, - "oauth2:" + ApiaryClientFactory.OAUTH_SCOPE, null /* options */, getActivity(), - new AccountManagerCallback<Bundle>() { - @Override - public void run(AccountManagerFuture<Bundle> future) { - try { - String token = future.getResult().getString( - AccountManager.KEY_AUTHTOKEN); - register(ownerEmail, token); - } catch (Exception e) { - Log.e(TAG, "Failed to get token: ", e); - } - } - }, null); - } - - private void register(final String ownerEmail, final String oAuthToken) { - new RegistrationTask("Registering instance") { - private Context mContext; - - private String mDisplayName; - private InstanceDescription mDescription; - private InstanceCredential mCredential; - - @Override - protected void onPreExecute() { - mContext = getActivity(); - - mDisplayName = generateDisplayName(); - super.onPreExecute(); - } - - @Override - protected void doInBackgroundImpl() throws IOException, InterruptedException { - String ticketId = mClientFactory.newGCDClient(oAuthToken) - .createRegistrationTicket(); - - checkInterrupted(); - - String gcmChannelId = - mClientFactory.newGCMRegistrar().blockingGetRegistrationId(mContext); - - mDescription = new InstanceDescription.Builder() - .setOAuthClientId(mClientFactory.getOAuthClientId()) - .setGCMChannelId(gcmChannelId) - .setDisplayName(mDisplayName) - .build(); - - mClientFactory.newAnonymousGCDClient().patchRegistrationTicket( - ticketId, mDescription); - - checkInterrupted(); - - mCredential = mClientFactory.newAnonymousGCDClient().finalizeRegistration(ticketId); - } - - @Override - protected void onSuccess() { - saveRegistration(mDescription, mCredential, ownerEmail); - onRegistrationStatusChange(); - showToast("Registered"); - } - - @Override - protected void onFailure(Exception e) { - Log.e(TAG, "Registration failed", e); - showToast("Registration failed. See log for details."); - } - }.execute(); - } - - @Override - public void onActivityResult(final int requestCode, final int resultCode, final Intent data) { - if (requestCode == CODE_ACCOUNT_SELECTED && resultCode == Activity.RESULT_OK) { - mSelectedAccount = new Account( - data.getStringExtra(AccountManager.KEY_ACCOUNT_NAME), - data.getStringExtra(AccountManager.KEY_ACCOUNT_TYPE)); - Log.d(TAG, "Selected account=" + mSelectedAccount); - queryOAuthToken(); - } - } - - private void saveRegistration( - InstanceDescription description, InstanceCredential credential, String ownerEmail) { - // TODO(serya): Make registration persistant. - mInstanceCredential = credential; - - SharedPreferences.Editor editor = mPreferences.edit(); - if (description != null && credential != null && ownerEmail != null) { - credential.put(editor); - editor.putString(PREF_DISPLAY_NAME, description.displayName); - editor.putString(PREF_OWNER_EMAIL, ownerEmail); - } else { - InstanceCredential.remove(editor); - editor.remove(PREF_DISPLAY_NAME); - editor.remove(PREF_OWNER_EMAIL); - } - editor.commit(); - } - - protected abstract void onRegistrationStatusChange(); - protected abstract String generateDisplayName(); - - private abstract class RegistrationTask extends AsyncTask<Void, Void, Boolean> { - private ProgressDialog mDialog; - private Exception mException; - - private final String mProgressMessage; - - protected RegistrationTask(String progressMessage) { - mProgressMessage = progressMessage; - } - - @Override - protected void onPreExecute() { - mDialog = ProgressDialog.show( - getActivity(), - "GCD registration", - mProgressMessage, - true, - false, - new DialogInterface.OnCancelListener() { - @Override - public void onCancel(DialogInterface dialog) { - cancel(true); - } - }); - } - - @Override - protected final Boolean doInBackground(Void... args) { - try { - doInBackgroundImpl(); - return Boolean.TRUE; - } catch (IOException e) { - mException = e; - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - return Boolean.FALSE; - } - - protected final void checkInterrupted() throws InterruptedException { - if (Thread.currentThread().isInterrupted()) { - throw new InterruptedException(); - } - } - - @Override - protected void onPostExecute(Boolean success) { - mDialog.dismiss(); - if (Boolean.TRUE.equals(success)) { - onSuccess(); - } else if (mException != null) { - onFailure(mException); - } - } - - protected void showToast(String message) { - Toast.makeText(getActivity(), message, Toast.LENGTH_SHORT).show(); - } - - protected abstract void doInBackgroundImpl() throws IOException, InterruptedException; - protected abstract void onSuccess(); - protected abstract void onFailure(Exception e); - } -}
diff --git a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/util/LooperExecutor.java b/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/util/LooperExecutor.java deleted file mode 100644 index ce383be..0000000 --- a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/util/LooperExecutor.java +++ /dev/null
@@ -1,56 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.components.devtools_bridge.util; - -import android.content.Context; -import android.os.Handler; - -import org.chromium.components.devtools_bridge.SessionBase; - -/** - * Implementation of SessionBase.Executor on top of android's handler. - */ -public class LooperExecutor implements SessionBase.Executor { - private final Handler mHandler; - - public LooperExecutor(Handler handler) { - mHandler = handler; - } - - public static LooperExecutor newInstanceForMainLooper(Context context) { - return new LooperExecutor(new Handler(context.getMainLooper())); - } - - @Override - public SessionBase.Cancellable postOnSessionThread(int delayMs, Runnable runnable) { - CancellableTask task = new CancellableTask(runnable); - mHandler.postDelayed(task, delayMs); - return task; - } - - @Override - public boolean isCalledOnSessionThread() { - return mHandler.getLooper().getThread() == Thread.currentThread(); - } - - private final class CancellableTask implements SessionBase.Cancellable, Runnable { - private Runnable mTask; - - public CancellableTask(Runnable task) { - mTask = task; - } - - @Override - public void run() { - if (mTask != null) mTask.run(); - } - - @Override - public void cancel() { - mHandler.removeCallbacks(this); - mTask = null; - } - } -}
diff --git a/components/devtools_bridge/android/javatests/AndroidManifest.xml b/components/devtools_bridge/android/javatests/AndroidManifest.xml deleted file mode 100644 index c4671eb..0000000 --- a/components/devtools_bridge/android/javatests/AndroidManifest.xml +++ /dev/null
@@ -1,74 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> - <!-- Copyright 2014 The Chromium Authors. All rights reserved. Use of - this source code is governed by a BSD-style license that can be found - in the LICENSE file. --> - <!-- package name must be unique so suffix with "tests" so package loader - doesn't ignore this. --> - <manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="org.chromium.components.devtools_bridge.tests"> - <application - android:name=".TestApplication"> - <uses-library android:name="android.test.runner" /> - <service - android:name=".DebugService" > - </service> - <activity - android:name=".DebugActivity" - android:label="DevToolsBridge tests" > - <intent-filter> - <action android:name="android.intent.action.MAIN" /> - <category android:name="android.intent.category.LAUNCHER" /> - </intent-filter> - </activity> - - <!-- DevToolsBridgeService multiplexed GCM receiver --> - <service android:name="org.chromium.components.devtools_bridge.TestDevToolsBridgeService" - android:exported="false" /> - <receiver android:exported="false" - android:name="org.chromium.components.devtools_bridge.TestDevToolsBridgeService$Receiver"> - <intent-filter> - <action android:name="com.google.ipc.invalidation.gcmmplex.EVENT" /> - </intent-filter> - </receiver> - - <!-- GCM Broadcast Receiver --> - <receiver android:exported="true" - android:name="com.google.ipc.invalidation.external.client.contrib.MultiplexingGcmListener$GCMReceiver" - android:permission="com.google.android.c2dm.permission.SEND"> - <intent-filter> - <action android:name="com.google.android.c2dm.intent.RECEIVE"/> - <action android:name="com.google.android.c2dm.intent.REGISTRATION"/> - <category android:name="com.google.ipc.invalidation.ticl.android2"/> - </intent-filter> - </receiver> - <!-- GCM multiplexer --> - <service android:exported="false" android:name="com.google.ipc.invalidation.external.client.contrib.MultiplexingGcmListener"> - <!-- MultiplexingGcmListener fails if |sender_ids| looks like an integer. - Make it look like a string by duplicating the ID. --> - <meta-data android:name="sender_ids" android:value="287888336735,287888336735"/> - </service> - </application> - <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="22" /> - <instrumentation android:name="android.test.InstrumentationTestRunner" - android:targetPackage="org.chromium.components.devtools_bridge.tests" - android:label="Tests for org.chromium.components.devtools_bridge"/> - - <permission - android:name="org.chromium.components.devtools_bridge.tests.permission.C2D_MESSAGE" - android:protectionLevel="signature" /> - - <uses-permission android:name="android.permission.RUN_INSTRUMENTATION" /> - <uses-permission android:name="android.permission.INJECT_EVENTS" /> - <uses-permission android:name="android.permission.INTERNET" /> - <uses-permission android:name="android.permission.USE_CREDENTIALS" /> - <uses-permission android:name="android.permission.WAKE_LOCK" /> - <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" /> - <uses-permission - android:name="org.chromium.components.devtools_bridge.tests.permission.C2D_MESSAGE" /> - - <!-- For manual testing with Chrome Shell --> - <uses-permission android:name="org.chromium.chrome.shell.permission.DEBUG" /> - - <!-- For manual testing with Clankium --> - <uses-permission android:name="com.google.android.apps.chrome.permission.DEBUG" /> -</manifest>
diff --git a/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/DevToolsBridgeServerTest.java b/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/DevToolsBridgeServerTest.java deleted file mode 100644 index 9f1910a5..0000000 --- a/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/DevToolsBridgeServerTest.java +++ /dev/null
@@ -1,93 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.components.devtools_bridge; - -import android.content.Context; -import android.net.LocalServerSocket; -import android.net.LocalSocket; -import android.test.InstrumentationTestCase; -import android.test.suitebuilder.annotation.SmallTest; - -import junit.framework.Assert; - -import org.chromium.components.devtools_bridge.util.LooperExecutor; - -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.Future; - -/** - * Tests for {@link DevToolsBridgeServer} - */ -public class DevToolsBridgeServerTest extends InstrumentationTestCase { - private static final String REQUEST = "Request"; - private static final String RESPONSE = "Response"; - private static final String SESSION_ID = "SESSION_ID"; - private static final String CLIENT_SOCKET_NAME = - DevToolsBridgeServerTest.class.getName() + ".CLIENT_SOCKET_NAME"; - private static final String SERVER_SOCKET_NAME = - DevToolsBridgeServerTest.class.getName() + ".SERVER_SOCKET_NAME"; - private SessionDependencyFactory mFactory; - - private LooperExecutor mServerExecutor; - private DevToolsBridgeServer mServer; - - @Override - protected void setUp() throws Exception { - super.setUp(); - mFactory = SessionDependencyFactory.newInstance(); - mServer = new DevToolsBridgeServer(new ServerDelegate()); - mServerExecutor = LooperExecutor.newInstanceForMainLooper( - getInstrumentation().getTargetContext()); - } - - @Override - protected void tearDown() throws Exception { - final CountDownLatch done = new CountDownLatch(1); - mServerExecutor.postOnSessionThread(0, new Runnable() { - @Override - public void run() { - mServer.dispose(); - mServer = null; - done.countDown(); - } - }); - done.await(); - mFactory.dispose(); - super.tearDown(); - } - - @SmallTest - public void testRequestResponse() throws Exception { - LocalServerSocket serverListeningSocket = new LocalServerSocket(SERVER_SOCKET_NAME); - ClientSessionTestingHost clientSession = new ClientSessionTestingHost( - mFactory, mServer, mServerExecutor, SESSION_ID, CLIENT_SOCKET_NAME); - clientSession.start(); - - Future<String> response = TestUtils.asyncRequest(CLIENT_SOCKET_NAME, REQUEST); - LocalSocket serverSocket = serverListeningSocket.accept(); - String request = TestUtils.read(serverSocket, REQUEST.length()); - Assert.assertEquals(REQUEST, request); - TestUtils.write(serverSocket, RESPONSE); - serverSocket.close(); - Assert.assertEquals(RESPONSE, response.get()); - - clientSession.dispose(); - } - - private class ServerDelegate implements DevToolsBridgeServer.Delegate { - @Override - public Context getContext() { - return getInstrumentation().getTargetContext(); - } - - @Override - public void querySocketName(DevToolsBridgeServer.QuerySocketCallback callback) { - callback.onSuccess(SERVER_SOCKET_NAME); - } - - @Override - public void onSessionCountChange(int count) {} - } -}
diff --git a/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/LocalSessionBridgeTest.java b/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/LocalSessionBridgeTest.java deleted file mode 100644 index 358702c28..0000000 --- a/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/LocalSessionBridgeTest.java +++ /dev/null
@@ -1,114 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.components.devtools_bridge; - -import android.net.LocalServerSocket; -import android.net.LocalSocket; -import android.test.InstrumentationTestCase; -import android.test.suitebuilder.annotation.MediumTest; - -import junit.framework.Assert; - -import java.util.concurrent.Future; - -/** - * Tests for both client and server sessions bound with {@link LocalSessionBridge}. - */ -public class LocalSessionBridgeTest extends InstrumentationTestCase { - private static final String SERVER_SOCKET_NAME = - LocalSessionBridgeTest.class.getName() + ".SERVER_SOCKET"; - private static final String CLIENT_SOCKET_NAME = - LocalSessionBridgeTest.class.getName() + ".CLIENT_SOCKET"; - - private static final String REQUEST = "Request"; - private static final String RESPONSE = "Response"; - - private LocalSessionBridge mBridge; - - @Override - public void setUp() throws Exception { - super.setUp(); - mBridge = new LocalSessionBridge(SERVER_SOCKET_NAME, CLIENT_SOCKET_NAME); - } - - @Override - public void tearDown() throws Exception { - mBridge.dispose(); - super.tearDown(); - } - - @MediumTest - public void testDisposeAfeterStart() { - mBridge.start(); - } - - @MediumTest - public void testNegotiating() throws InterruptedException { - mBridge.start(); - mBridge.awaitNegotiated(); - } - - @MediumTest - public void testOpenControlChannel() throws InterruptedException { - mBridge.start(); - mBridge.awaitControlChannelOpened(); - } - - @MediumTest - public void testClientAutocloseTimeout() throws InterruptedException { - mBridge.setMessageDeliveryDelayMs(1000); - mBridge.setClientAutoCloseTimeoutMs(100); - mBridge.start(); - mBridge.awaitClientAutoClosed(); - } - - @MediumTest - public void testServerAutocloseTimeout() throws InterruptedException { - mBridge.setMessageDeliveryDelayMs(1000); - mBridge.setServerAutoCloseTimeoutMs(100); - mBridge.start(); - mBridge.awaitServerAutoClosed(); - } - - @MediumTest - public void testRequestResponse() throws Exception { - mBridge.start(); - - LocalServerSocket serverListeningSocket = new LocalServerSocket(SERVER_SOCKET_NAME); - Future<String> response = TestUtils.asyncRequest(CLIENT_SOCKET_NAME, REQUEST); - LocalSocket serverSocket = serverListeningSocket.accept(); - String request = TestUtils.read(serverSocket, REQUEST.length()); - Assert.assertEquals(REQUEST, request); - TestUtils.write(serverSocket, RESPONSE); - serverSocket.close(); - Assert.assertEquals(RESPONSE, response.get()); - } - - @MediumTest - public void testRequestFailure1() throws Exception { - mBridge.start(); - LocalServerSocket serverListeningSocket = new LocalServerSocket(SERVER_SOCKET_NAME); - Future<String> response = TestUtils.asyncRequest(CLIENT_SOCKET_NAME, REQUEST); - LocalSocket socket = serverListeningSocket.accept(); - int firstByte = socket.getInputStream().read(); - - Assert.assertEquals((int) REQUEST.charAt(0), firstByte); - - socket.close(); - Assert.assertEquals("", response.get()); - } - - @MediumTest - public void testRequestFailure2() throws Exception { - mBridge.dispose(); - // Android system socket will reject connection. - mBridge = new LocalSessionBridge("jdwp-control", CLIENT_SOCKET_NAME); - mBridge.start(); - - Future<String> response = TestUtils.asyncRequest(CLIENT_SOCKET_NAME, REQUEST); - - Assert.assertEquals("", response.get()); - } -}
diff --git a/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/SessionControlMessagesTest.java b/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/SessionControlMessagesTest.java deleted file mode 100644 index a3181686..0000000 --- a/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/SessionControlMessagesTest.java +++ /dev/null
@@ -1,94 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.components.devtools_bridge; - -import android.test.InstrumentationTestCase; -import android.test.suitebuilder.annotation.SmallTest; - -import junit.framework.Assert; - -import org.chromium.components.devtools_bridge.SessionControlMessages.ClientMessage; -import org.chromium.components.devtools_bridge.SessionControlMessages.ClientMessageHandler; -import org.chromium.components.devtools_bridge.SessionControlMessages.IceExchangeMessage; -import org.chromium.components.devtools_bridge.SessionControlMessages.InvalidFormatException; -import org.chromium.components.devtools_bridge.SessionControlMessages.Message; -import org.chromium.components.devtools_bridge.SessionControlMessages.MessageHandler; -import org.chromium.components.devtools_bridge.SessionControlMessages.ServerMessage; -import org.chromium.components.devtools_bridge.SessionControlMessages.ServerMessageHandler; -import org.chromium.components.devtools_bridge.SessionControlMessages.UnknownRequestMessage; -import org.chromium.components.devtools_bridge.SessionControlMessages.UnknownResponseMessage; - -/** - * Tests for {@link SessionControlMessages} - */ -public class SessionControlMessagesTest extends InstrumentationTestCase { - private static final String UNKNOWN_REQUEST_TYPE = "@unknown request@"; - private static final String UNKNOWN_REQUEST = "{\"type\": \"" + UNKNOWN_REQUEST_TYPE + "\"}"; - - @SmallTest - public void testIceExchangeMessage() { - recode(new IceExchangeMessage()); - } - - @SmallTest - public void testUnknownRequest() throws InvalidFormatException { - UnknownRequestMessage request = - (UnknownRequestMessage) ClientMessageReader.readMessage(UNKNOWN_REQUEST); - UnknownResponseMessage response = ServerMessageReader.recode(request.createResponse()); - Assert.assertEquals(UNKNOWN_REQUEST_TYPE, response.rawRequestType); - } - - private <T extends ServerMessage> T recode(T message) { - assert message != null; - return ServerMessageReader.recode(message); - } - - @SuppressWarnings("unchecked") - private static <T> T cast(T prototype, Object object) { - Assert.assertNotNull(object); - if (prototype.getClass() == object.getClass()) - return (T) object; - else - throw new ClassCastException(); - } - - private static void checkedRead(MessageHandler handler, Message<?> message) { - try { - handler.readMessage(SessionControlMessages.toByteArray(message)); - } catch (InvalidFormatException e) { - Assert.fail(e.toString()); - } - } - - private static class ServerMessageReader extends ServerMessageHandler { - private ServerMessage mLastMessage; - - @Override - protected void onMessage(ServerMessage message) { - mLastMessage = message; - } - - public static <T extends ServerMessage> T recode(T message) { - ServerMessageReader handler = new ServerMessageReader(); - checkedRead(handler, message); - return cast(message, handler.mLastMessage); - } - } - - private static class ClientMessageReader extends ClientMessageHandler { - private ClientMessage mLastMessage; - - @Override - protected void onMessage(ClientMessage message) { - mLastMessage = message; - } - - public static ClientMessage readMessage(String json) throws InvalidFormatException { - ClientMessageReader reader = new ClientMessageReader(); - reader.readMessage(json.getBytes()); - return reader.mLastMessage; - } - } -}
diff --git a/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/SessionDependencyFactoryTest.java b/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/SessionDependencyFactoryTest.java deleted file mode 100644 index 90a3a9c..0000000 --- a/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/SessionDependencyFactoryTest.java +++ /dev/null
@@ -1,200 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.components.devtools_bridge; - -import android.test.InstrumentationTestCase; -import android.test.suitebuilder.annotation.MediumTest; -import android.test.suitebuilder.annotation.SmallTest; - -import junit.framework.Assert; - -import java.nio.ByteBuffer; - -/** - * Tests for {@link SessionDependencyFactory} - */ -public class SessionDependencyFactoryTest extends InstrumentationTestCase { - private static final int DATA_CHANNEL_ID = 0; - - private SessionDependencyFactory mInstance; - private AbstractPeerConnection mConnection; - private PeerConnectionObserverMock mObserver; - - @Override - protected void setUp() throws Exception { - super.setUp(); - mObserver = new PeerConnectionObserverMock(); - } - - @SmallTest - public void testCreateFactory() { - mInstance = newFactory(); - mInstance.dispose(); - } - - @SmallTest - public void testCreateConnection() { - mInstance = newFactory(); - RTCConfiguration config = new RTCConfiguration.Builder() - .addIceServer("http://expample.org") - .build(); - mInstance.createPeerConnection(config, mObserver).dispose(); - mInstance.dispose(); - } - - @SmallTest - public void testCreateAndSetLocalOffer() throws Exception { - mInstance = newFactory(); - mConnection = newConnection(); - mConnection.createAndSetLocalDescription( - AbstractPeerConnection.SessionDescriptionType.OFFER); - - mObserver.localDescriptionAvailable.await(); - - Assert.assertEquals( - AbstractPeerConnection.SessionDescriptionType.OFFER, - mObserver.localDescriptionType); - mConnection.dispose(); - mInstance.dispose(); - } - - @SmallTest - public void testTerminateCallback() { - mInstance = newFactory(); - mConnection = newConnection(); - mConnection.createAndSetLocalDescription( - AbstractPeerConnection.SessionDescriptionType.OFFER); - - // Do not wait. - - mConnection.dispose(); - mInstance.dispose(); - } - - @SmallTest - public void testCreateAndSetLocalAnswerFailed() throws Exception { - mInstance = newFactory(); - mConnection = newConnection(); - // Creating answer without offer set must fail. - mConnection.createAndSetLocalDescription( - AbstractPeerConnection.SessionDescriptionType.ANSWER); - - mObserver.failureAvailable.await(); - - mConnection.dispose(); - mInstance.dispose(); - } - - @SmallTest - public void testSetRemoteOffer() throws Exception { - mInstance = newFactory(); - mConnection = newConnection(); - mConnection.createAndSetLocalDescription( - AbstractPeerConnection.SessionDescriptionType.OFFER); - mObserver.localDescriptionAvailable.await(); - String offer = mObserver.localDescription; - mConnection.dispose(); - - mConnection = newConnection(); - mConnection.setRemoteDescription( - AbstractPeerConnection.SessionDescriptionType.OFFER, offer); - mObserver.remoteDescriptionSet.await(); - - mConnection.dispose(); - mInstance.dispose(); - } - - @SmallTest - public void testNegotiation() throws Exception { - mInstance = newFactory(); - DataPipe pipe = new DataPipe(mInstance); - pipe.negotiate(); - pipe.dispose(); - mInstance.dispose(); - } - - @SmallTest - public void testConnection() throws Exception { - mInstance = newFactory(); - DataPipe pipe = new DataPipe(mInstance); - pipe.negotiate(); - pipe.awaitConnected(); - pipe.dispose(); - mInstance.dispose(); - } - - @SmallTest - public void testDataChannel() { - mInstance = newFactory(); - mConnection = newConnection(); - AbstractDataChannel channel = mConnection.createDataChannel(DATA_CHANNEL_ID); - - channel.registerObserver(new DataChannelObserverMock()); - channel.send(ByteBuffer.allocateDirect(1), AbstractDataChannel.MessageType.TEXT); - channel.send(ByteBuffer.allocateDirect(1), AbstractDataChannel.MessageType.BINARY); - channel.unregisterObserver(); - channel.close(); - - channel.dispose(); - mConnection.dispose(); - mInstance.dispose(); - } - - @SmallTest - public void testDataChannelOpens() throws Exception { - mInstance = newFactory(); - DataPipe pipe = new DataPipe(mInstance); - - pipe.registerDatatChannelObservers(); - - pipe.negotiate(); - - pipe.dataChannelObserver(0).opened.await(); - pipe.dataChannelObserver(1).opened.await(); - - pipe.unregisterDatatChannelObservers(); - - pipe.dispose(); - mInstance.dispose(); - } - - @MediumTest - public void testPumpData() throws Exception { - mInstance = newFactory(); - DataPipe pipe = new DataPipe(mInstance); - pipe.registerDatatChannelObservers(); - pipe.negotiate(); - pipe.dataChannelObserver(0).opened.await(); - - // Make sure data channel don't leave local references on stack - // of signaling thread. References causes failure like - // "Failed adding to JNI local ref table (has 512 entries)". - final int count = 1000; - - for (int i = 0; i < count; i++) { - pipe.send(0, "A"); - } - - for (int i = 0; i < count; i++) { - pipe.dataChannelObserver(1).received.take(); - } - - pipe.unregisterDatatChannelObservers(); - pipe.dispose(); - mInstance.dispose(); - } - - private SessionDependencyFactory newFactory() { - return SessionDependencyFactory.newInstance(); - } - - private AbstractPeerConnection newConnection() { - return newConnection(mObserver); - } - - private AbstractPeerConnection newConnection(PeerConnectionObserverMock observer) { - return mInstance.createPeerConnection(new RTCConfiguration(), observer); - } -}
diff --git a/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/SocketTunnelServerTest.java b/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/SocketTunnelServerTest.java deleted file mode 100644 index 53aab71..0000000 --- a/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/SocketTunnelServerTest.java +++ /dev/null
@@ -1,234 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.components.devtools_bridge; - -import android.net.LocalServerSocket; -import android.net.LocalSocket; -import android.test.InstrumentationTestCase; -import android.test.suitebuilder.annotation.MediumTest; - -import junit.framework.Assert; - -import org.chromium.base.annotations.SuppressFBWarnings; - -import java.io.IOException; -import java.io.OutputStream; -import java.nio.ByteBuffer; - -/** - * Tests for {@link SocketTunnelServer} - */ -public class SocketTunnelServerTest extends InstrumentationTestCase { - private static final int CONNECTION_ID = 30; - private static final String SOCKET_NAME = "ksdjhflksjhdflk"; - - private static final int SERVER_CHANNEL = 1; - private static final int CLIENT_CHANNEL = 0; - - private SessionDependencyFactory mFactory; - private DataPipe mPipe; - private SocketTunnel mServer; - private LocalServerSocket mSocket; - private DataChannelObserverMock mObserverMock; - - @Override - public void setUp() throws Exception { - super.setUp(); - mFactory = SessionDependencyFactory.newInstance(); - mPipe = new DataPipe(mFactory); - mServer = mFactory.newSocketTunnelServer(SOCKET_NAME); - mServer.bind(mPipe.dataChannel(SERVER_CHANNEL)); - mSocket = new LocalServerSocket(SOCKET_NAME); - mObserverMock = new DataChannelObserverMock(); - mPipe.dataChannel(CLIENT_CHANNEL).registerObserver(mObserverMock); - mPipe.negotiate(); - mPipe.awaitConnected(); - } - - @Override - public void tearDown() throws Exception { - mPipe.dataChannel(CLIENT_CHANNEL).unregisterObserver(); - mServer.unbind(); - mPipe.dispose(); - mFactory.dispose(); - super.tearDown(); - } - - private void sendPacket(ByteBuffer packet) { - packet.position(0); - mPipe.send(CLIENT_CHANNEL, packet); - } - - @MediumTest - public void testConnectToSocket() throws IOException { - LocalSocket socket = connectToSocket(1); - socket.close(); - } - - private LocalSocket connectToSocket(int connectionId) throws IOException { - sendPacket(SocketTunnelBase.buildControlPacket( - connectionId, SocketTunnelBase.CLIENT_OPEN)); - return mSocket.accept(); - } - - private void sendClose(int connectionId) { - sendPacket(SocketTunnelBase.buildControlPacket( - connectionId, SocketTunnelBase.CLIENT_CLOSE)); - } - - @MediumTest - public void testReceiveOpenAcknowledgement() throws IOException, InterruptedException { - LocalSocket socket = connectToSocket(CONNECTION_ID); - - receiveOpenAck(CONNECTION_ID); - - socket.close(); - } - - private PacketDecoder receivePacket() throws InterruptedException { - byte[] bytes = mObserverMock.received.take(); - ByteBuffer buffer = ByteBuffer.allocate(bytes.length); - buffer.put(bytes); - buffer.position(0); - return PacketDecoder.decode(buffer); - } - - private PacketDecoder receiveControlPacket(int connectionId) throws InterruptedException { - PacketDecoder decoder = receivePacket(); - Assert.assertTrue(decoder.isControlPacket()); - Assert.assertEquals(connectionId, decoder.connectionId()); - return decoder; - } - - private void receiveOpenAck(int connectionId) throws InterruptedException { - PacketDecoder decoder = receiveControlPacket(connectionId); - Assert.assertEquals(SocketTunnelBase.SERVER_OPEN_ACK, decoder.opCode()); - } - - private void receiveClose(int connectionId) throws InterruptedException { - PacketDecoder decoder = receiveControlPacket(connectionId); - Assert.assertEquals(SocketTunnelBase.SERVER_CLOSE, decoder.opCode()); - } - - @MediumTest - public void testClosingSocket() throws IOException, InterruptedException { - LocalSocket socket = connectToSocket(CONNECTION_ID); - receiveOpenAck(CONNECTION_ID); - - socket.close(); - - PacketDecoder decoder = receiveControlPacket(CONNECTION_ID); - - Assert.assertEquals(SocketTunnelBase.SERVER_CLOSE, decoder.opCode()); - } - - @MediumTest - public void testReadData() throws IOException, InterruptedException { - LocalSocket socket = connectToSocket(CONNECTION_ID); - receiveOpenAck(CONNECTION_ID); - - byte[] sample = "Sample".getBytes(); - - socket.getOutputStream().write(sample); - socket.getOutputStream().flush(); - socket.shutdownOutput(); - - ByteBuffer result = receiveData(CONNECTION_ID, sample.length); - Assert.assertEquals(ByteBuffer.wrap(sample), result); - } - - private ByteBuffer receiveData(int connectionId, int length) throws InterruptedException { - ByteBuffer result = ByteBuffer.allocate(length); - - while (true) { - PacketDecoder decoder = receivePacket(); - if (decoder.isDataPacket()) { - Assert.assertEquals(connectionId, decoder.connectionId()); - result.put(decoder.data()); - } else if (decoder.isControlPacket()) { - Assert.assertEquals(SocketTunnelBase.SERVER_CLOSE, decoder.opCode()); - Assert.assertEquals(connectionId, decoder.connectionId()); - break; - } - } - result.limit(result.position()); - result.position(0); - return result; - } - - private int sum(int[] values) { - int result = 0; - for (int v : values) - result += v; - return result; - } - - private static final int[] CHUNK_SIZES = - new int[] { 0, 1, 5, 100, 1000, SocketTunnelBase.READING_BUFFER_SIZE * 2 }; - - @MediumTest - public void testReadLongDataChunk() throws IOException, InterruptedException { - LocalSocket socket = connectToSocket(CONNECTION_ID); - receiveOpenAck(CONNECTION_ID); - - byte[] buffer = new byte[CHUNK_SIZES[CHUNK_SIZES.length - 1]]; - ByteBuffer sentData = ByteBuffer.allocate(sum(CHUNK_SIZES)); - OutputStream stream = socket.getOutputStream(); - byte next = 0; - int prevSize = 0; - for (int size : CHUNK_SIZES) { - while (prevSize < size) - buffer[prevSize++] = next++; - - stream.write(buffer, 0, size); - sentData.put(buffer, 0, size); - } - - socket.shutdownOutput(); - - sentData.limit(sentData.position()); - sentData.position(0); - ByteBuffer readData = receiveData(CONNECTION_ID, sentData.limit()); - - Assert.assertEquals(sentData, readData); - } - - @SuppressFBWarnings("DLS_DEAD_LOCAL_STORE") - @MediumTest - public void testReuseConnectionId() throws IOException, InterruptedException { - LocalSocket socket = connectToSocket(CONNECTION_ID); - receiveOpenAck(CONNECTION_ID); - - socket.close(); - receiveClose(CONNECTION_ID); - sendClose(CONNECTION_ID); - - // Open connection with the same ID - socket = connectToSocket(CONNECTION_ID); - receiveOpenAck(CONNECTION_ID); - } - - private static final byte[] SAMPLE = "Sample".getBytes(); - - @MediumTest - public void testWriteData() throws IOException, InterruptedException { - LocalSocket socket = connectToSocket(CONNECTION_ID); - receiveOpenAck(CONNECTION_ID); - - sendPacket(SocketTunnelBase.buildDataPacket(CONNECTION_ID, SAMPLE, SAMPLE.length)); - - byte[] result = new byte[SAMPLE.length]; - int read = 0; - while (read < SAMPLE.length) { - int count = socket.getInputStream().read(result, 0, SAMPLE.length - read); - Assert.assertTrue(count > 0); - read += count; - } - - Assert.assertEquals(ByteBuffer.wrap(SAMPLE), ByteBuffer.wrap(result)); - - socket.close(); - } -}
diff --git a/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/apiary/JsonResponseHandlerTest.java b/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/apiary/JsonResponseHandlerTest.java deleted file mode 100644 index cb4b95c4..0000000 --- a/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/apiary/JsonResponseHandlerTest.java +++ /dev/null
@@ -1,138 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.components.devtools_bridge.apiary; - -import android.test.InstrumentationTestCase; -import android.test.suitebuilder.annotation.SmallTest; -import android.util.JsonReader; - -import junit.framework.Assert; - -import org.apache.http.ProtocolVersion; -import org.apache.http.client.ClientProtocolException; -import org.apache.http.client.HttpResponseException; -import org.apache.http.entity.StringEntity; -import org.apache.http.message.BasicHttpResponse; - -import java.io.IOException; - -/** - * Tests for {@link JsonResponseHandler}. - */ -public class JsonResponseHandlerTest extends InstrumentationTestCase { - @SmallTest - public void testInvalidResponse() throws IOException { - try { - new JsonResponseHandler<String>() { - @Override - public String readResponse(JsonReader reader) { - return ""; - } - }.handleResponse(newResponse(404, null)); - - Assert.fail(); - } catch (HttpResponseException e) { - // Expected - } - } - - @SmallTest - public void testIOException() { - try { - new JsonResponseHandler<String>() { - @Override - public String readResponse(JsonReader reader) throws IOException { - throw new IOException(); - } - }.handleResponse(newResponse(200, "")); - - Assert.fail(); - } catch (IOException e) { - // Expected - } - } - - @SmallTest - public void testStateException() throws IOException { - try { - new JsonResponseHandler<String>() { - @Override - public String readResponse(JsonReader reader) throws IOException { - reader.beginObject(); - reader.endObject(); - return ""; - } - }.handleResponse(newResponse(200, "[]")); - - Assert.fail(); - } catch (JsonResponseHandler.ResponseFormatException e) { - // Expected - } - } - - @SmallTest - public void testFormatException() throws IOException { - try { - new JsonResponseHandler<String>() { - @Override - public String readResponse(JsonReader reader) throws IOException { - reader.beginArray(); - reader.nextLong(); - reader.endArray(); - return ""; - } - }.handleResponse(newResponse(200, "[\"XXX\"]")); - - Assert.fail(); - } catch (JsonResponseHandler.ResponseFormatException e) { - // Expected - } - } - - @SmallTest - public void testNullResultException() throws IOException { - try { - new JsonResponseHandler<String>() { - @Override - public String readResponse(JsonReader reader) throws IOException { - reader.beginArray(); - reader.endArray(); - return null; - } - }.handleResponse(newResponse(200, "[]")); - - Assert.fail(); - } catch (ClientProtocolException e) { - // Expected - } - } - - @SmallTest - public void testSuccess() throws IOException { - String result = new JsonResponseHandler<String>() { - @Override - public String readResponse(JsonReader reader) throws IOException { - reader.beginArray(); - reader.endArray(); - return "OK"; - } - }.handleResponse(newResponse(200, "[]")); - - Assert.assertEquals("OK", result); - } - - private BasicHttpResponse newResponse(int status, String content) { - BasicHttpResponse response = new BasicHttpResponse( - new ProtocolVersion("HTTP", 1, 1), status, "reason"); - if (content != null) { - try { - response.setEntity(new StringEntity(content, "UTF-8")); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - return response; - } -}
diff --git a/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/apiary/OAuthClientTest.java b/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/apiary/OAuthClientTest.java deleted file mode 100644 index 78c7c54..0000000 --- a/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/apiary/OAuthClientTest.java +++ /dev/null
@@ -1,39 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.components.devtools_bridge.apiary; - -import android.test.InstrumentationTestCase; -import android.test.suitebuilder.annotation.SmallTest; - -import junit.framework.Assert; - -import org.chromium.components.devtools_bridge.util.TestSource; - -/** - * Tests for {@link OAuthClient}. - */ -public class OAuthClientTest extends InstrumentationTestCase { - private static final String ACCESS_TOKEN = - "ya29.rgBgy64Y1MACXNmPDUpPGbwFuAec2NCCDJwaEp8DwLnV8RBk45p9RBqBfEQUYxL6OVB-oyktRqZj0w"; - private static final String REFRESH_TOKEN = - "1/cWihsJmDMujYfhzBVTwgh4ukiFyiiRWLmFwTv4EigzU"; - - @SmallTest - public void testResponse() throws Exception { - TestSource source = new TestSource(); - source.write() - .beginObject() - .name("access_token").value(ACCESS_TOKEN) - .name("token_type").value("Bearer") - .name("expires_in").value(3600) // seconds - .name("refresh_token").value(REFRESH_TOKEN) - .endObject() - .close(); - OAuthResult result = OAuthClient.readResponse(source.read(), 1111); - Assert.assertEquals(ACCESS_TOKEN, result.accessToken); - Assert.assertEquals(REFRESH_TOKEN, result.refreshToken); - Assert.assertEquals(1111 + 3600000, result.expirationTimeMs); - } -}
diff --git a/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/commands/CommandReceiverTest.java b/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/commands/CommandReceiverTest.java deleted file mode 100644 index e5226ff..0000000 --- a/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/commands/CommandReceiverTest.java +++ /dev/null
@@ -1,91 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.components.devtools_bridge.commands; - -import android.test.InstrumentationTestCase; -import android.test.suitebuilder.annotation.SmallTest; - -import junit.framework.Assert; - -import org.chromium.components.devtools_bridge.RTCConfiguration; -import org.chromium.components.devtools_bridge.SignalingReceiverMock; - -import java.util.ArrayList; -import java.util.List; - -/** - * Tests for {@link CommandReceiver} - */ -public class CommandReceiverTest extends InstrumentationTestCase { - private static final RTCConfiguration CONFIG = new RTCConfiguration.Builder() - .build(); - - private final SignalingReceiverMock mMock = new SignalingReceiverMock(); - private final CommandReceiver mReceiver = new CommandReceiver(mMock); - private final CompletionHandler mCompletionHandler = new CompletionHandler(); - - private static class CompletionHandler implements Runnable { - public boolean done = false; - - @Override - public void run() { - done = true; - } - }; - - @SmallTest - public void testStartSessionCommand() { - Commands.StartSessionCommand command = - new Commands.StartSessionCommand("SESSION_ID", CONFIG, "OFFER"); - - mReceiver.receive(command, mCompletionHandler); - Assert.assertEquals("SESSION_ID", mMock.sessionId); - Assert.assertEquals("OFFER", mMock.offer); - - mMock.negotiationCallback.onSuccess("ANSWER"); - Assert.assertTrue(mCompletionHandler.done); - Assert.assertEquals(command.getResult(), "ANSWER"); - } - - @SmallTest - public void testRenegotiateCommand() { - Commands.RenegotiateCommand command = - new Commands.RenegotiateCommand("SESSION_ID", "OFFER"); - - mReceiver.receive(command, mCompletionHandler); - Assert.assertEquals("SESSION_ID", mMock.sessionId); - Assert.assertEquals("OFFER", mMock.offer); - - mMock.negotiationCallback.onSuccess("ANSWER"); - Assert.assertTrue(mCompletionHandler.done); - Assert.assertEquals(command.getResult(), "ANSWER"); - } - - @SmallTest - public void testIceExchangeCommand() { - List<String> candidates = new ArrayList<String>(); - - Commands.IceExchangeCommand command = - new Commands.IceExchangeCommand("SESSION_ID", candidates); - - mReceiver.receive(command, mCompletionHandler); - Assert.assertEquals("SESSION_ID", mMock.sessionId); - - mMock.iceExchangeCallback.onSuccess(candidates); - Assert.assertTrue(mCompletionHandler.done); - } - - @SmallTest - public void testCommandFailure() { - Commands.RenegotiateCommand command = - new Commands.RenegotiateCommand("SESSION_ID", "OFFER"); - - mReceiver.receive(command, mCompletionHandler); - - mMock.negotiationCallback.onFailure("ERROR_MESSAGE"); - Assert.assertTrue(mCompletionHandler.done); - Assert.assertEquals(command.getErrorMessage(), "ERROR_MESSAGE"); - } -}
diff --git a/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/commands/CommandSenderTest.java b/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/commands/CommandSenderTest.java deleted file mode 100644 index 3d03935..0000000 --- a/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/commands/CommandSenderTest.java +++ /dev/null
@@ -1,126 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.components.devtools_bridge.commands; - -import android.test.InstrumentationTestCase; -import android.test.suitebuilder.annotation.SmallTest; - -import junit.framework.Assert; - -import org.chromium.base.annotations.SuppressFBWarnings; -import org.chromium.components.devtools_bridge.RTCConfiguration; -import org.chromium.components.devtools_bridge.SessionBase; - -import java.util.ArrayList; -import java.util.List; - -/** - * Tests for {@link CommandSender} - */ -@SuppressFBWarnings("URF_UNREAD_FIELD") -public class CommandSenderTest extends InstrumentationTestCase { - private static final RTCConfiguration CONFIG = new RTCConfiguration.Builder() - .addIceServer("http://example.org") - .build(); - - private Command mCommand; - private Runnable mCompletionCallback; - private String mAnswer; - private String mErrorMessage; - private List<String> mServerCandidates; - - @SmallTest - public void testStartSessionCommand() { - new SenderMock().startSession("SESSION_ID", CONFIG, "OFFER", new NegotiationCallbackMock()); - - Commands.StartSessionCommand command = (Commands.StartSessionCommand) mCommand; - Assert.assertNotNull(command); - - Assert.assertEquals("SESSION_ID", command.sessionId); - Assert.assertEquals("OFFER", command.offer); - - command.setResult("ANSWER"); - - mCompletionCallback.run(); - Assert.assertEquals("ANSWER", mAnswer); - Assert.assertNull(mErrorMessage); - } - - @SmallTest - public void testRenegotiateCommand() { - new SenderMock().renegotiate("SESSION_ID", "OFFER", new NegotiationCallbackMock()); - Commands.RenegotiateCommand command = (Commands.RenegotiateCommand) mCommand; - Assert.assertNotNull(command); - - Assert.assertEquals("SESSION_ID", command.sessionId); - Assert.assertEquals("OFFER", command.offer); - - command.setResult("ANSWER"); - - mCompletionCallback.run(); - Assert.assertEquals("ANSWER", mAnswer); - Assert.assertNull(mErrorMessage); - } - - @SmallTest - public void testIceExchangeCommand() { - ArrayList<String> candidates = new ArrayList<String>(); - new SenderMock().iceExchange("SESSION_ID", candidates, new IceExchangeCallbackMock()); - Commands.IceExchangeCommand command = (Commands.IceExchangeCommand) mCommand; - Assert.assertNotNull(command); - - Assert.assertEquals("SESSION_ID", command.sessionId); - command.setResult(candidates); - - mCompletionCallback.run(); - Assert.assertNull(mErrorMessage); - } - - @SmallTest - public void testCommandFailure() { - new SenderMock().renegotiate("SESSION_ID", "OFFER", new NegotiationCallbackMock()); - - Commands.RenegotiateCommand command = (Commands.RenegotiateCommand) mCommand; - Assert.assertNotNull(command); - - command.setFailure("TEST_MESSAGE"); - - mCompletionCallback.run(); - Assert.assertNull(mAnswer); - Assert.assertEquals("TEST_MESSAGE", mErrorMessage); - } - - private class SenderMock extends CommandSender { - @Override - protected void send(Command command, Runnable completionCallback) { - mCommand = command; - mCompletionCallback = completionCallback; - } - } - - private class NegotiationCallbackMock implements SessionBase.NegotiationCallback { - @Override - public void onSuccess(String answer) { - mAnswer = answer; - } - - @Override - public void onFailure(String errorMessage) { - mErrorMessage = errorMessage; - } - } - - private class IceExchangeCallbackMock implements SessionBase.IceExchangeCallback { - @Override - public void onSuccess(List<String> serverCandidates) { - mServerCandidates = serverCandidates; - } - - @Override - public void onFailure(String errorMessage) { - mErrorMessage = errorMessage; - } - } -}
diff --git a/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/commands/CommandsTest.java b/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/commands/CommandsTest.java deleted file mode 100644 index 2c7e6d8..0000000 --- a/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/commands/CommandsTest.java +++ /dev/null
@@ -1,124 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.components.devtools_bridge.commands; - -import android.test.InstrumentationTestCase; -import android.test.suitebuilder.annotation.SmallTest; - -import junit.framework.Assert; - -import java.util.HashMap; -import java.util.Map; - -/** - * Tests for {@link Commands} - */ -public class CommandsTest extends InstrumentationTestCase { - @SmallTest - public void testStartSessionCommand() throws Exception { - CommandDefinition def = Command.Type.START_SESSION.definition; - - Assert.assertEquals("_startSession", def.shortName()); - Assert.assertEquals("base._startSession", def.fullName()); - - Assert.assertEquals(3, getParamCount(def)); - Assert.assertEquals("_sessionId", getParam(def, 0).name()); - Assert.assertEquals("_config", getParam(def, 1).name()); - Assert.assertEquals("_offer", getParam(def, 2).name()); - - Map<String, String> values = new HashMap<String, String>(); - values.put("_sessionId", "SESSION_ID"); - values.put("_config", "{}"); - values.put("_offer", "OFFER"); - - Commands.StartSessionCommand command = - (Commands.StartSessionCommand) def.newCommand("ID", values); - - Assert.assertEquals(Command.Type.START_SESSION, command.type); - Assert.assertEquals("ID", command.id); - Assert.assertEquals("SESSION_ID", command.sessionId); - Assert.assertEquals("OFFER", command.offer); - - visitInParams(command, values); - } - - @SmallTest - public void testRenegotiateCommand() throws Exception { - CommandDefinition def = Command.Type.RENEGOTIATE.definition; - - Assert.assertEquals("_renegotiate", def.shortName()); - Assert.assertEquals("base._renegotiate", def.fullName()); - - Assert.assertEquals(2, getParamCount(def)); - Assert.assertEquals("_sessionId", getParam(def, 0).name()); - Assert.assertEquals("_offer", getParam(def, 1).name()); - - Map<String, String> values = new HashMap<String, String>(); - values.put("_sessionId", "SESSION_ID"); - values.put("_offer", "OFFER"); - - Commands.RenegotiateCommand command = - (Commands.RenegotiateCommand) def.newCommand("ID", values); - - Assert.assertEquals(Command.Type.RENEGOTIATE, command.type); - Assert.assertEquals("ID", command.id); - Assert.assertEquals("OFFER", command.offer); - - visitInParams(command, values); - } - - @SmallTest - public void testIceExchangeCommand() throws Exception { - CommandDefinition def = Command.Type.ICE_EXCHANGE.definition; - - Assert.assertEquals("_iceExchange", def.shortName()); - Assert.assertEquals("base._iceExchange", def.fullName()); - - Assert.assertEquals(2, getParamCount(def)); - Assert.assertEquals("_sessionId", getParam(def, 0).name()); - Assert.assertEquals("_clientCandidates", getParam(def, 1).name()); - - Map<String, String> values = new HashMap<String, String>(); - values.put("_sessionId", "SESSION_ID"); - values.put("_clientCandidates", "[\"candidate\"]"); - - Commands.IceExchangeCommand command = - (Commands.IceExchangeCommand) def.newCommand("ID", values); - - Assert.assertEquals(Command.Type.ICE_EXCHANGE, command.type); - Assert.assertEquals("ID", command.id); - - visitInParams(command, values); - } - - private void visitInParams(Command command, final Map<String, String> expectedValues) { - final Map<String, String> actualValues = new HashMap<String, String>(); - command.visitInParams(new Command.ParamVisitor() { - @Override - public void visit(ParamDefinition param, String value) { - String name = param.name(); - Assert.assertTrue(expectedValues.containsKey(name)); - actualValues.put(name, value); - } - }); - Assert.assertEquals(expectedValues.size(), actualValues.size()); - } - - private int getParamCount(CommandDefinition def) { - int count = 0; - for (ParamDefinition param : def.inParams()) { - count++; - } - return count; - } - - private ParamDefinition getParam(CommandDefinition def, int index) { - for (ParamDefinition param : def.inParams()) { - if (index == 0) return param; - index--; - } - return null; - } -}
diff --git a/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/commands/ParamDefinitionsTest.java b/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/commands/ParamDefinitionsTest.java deleted file mode 100644 index 3bf72c8..0000000 --- a/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/commands/ParamDefinitionsTest.java +++ /dev/null
@@ -1,81 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.components.devtools_bridge.commands; - -import android.test.InstrumentationTestCase; -import android.test.suitebuilder.annotation.SmallTest; - -import junit.framework.Assert; - -import org.chromium.components.devtools_bridge.RTCConfiguration; - -import java.util.List; - -/** - * Tests for {@link ParamDefinitions} - */ -public class ParamDefinitionsTest extends InstrumentationTestCase { - @SmallTest - public void testStringParam() throws Exception { - ParamDefinition<String> param = ParamDefinitions.newStringParam("NAME"); - Assert.assertEquals("_NAME", param.name()); - Assert.assertEquals("string", param.type()); - Assert.assertEquals("STRING", param.fromString("STRING")); - Assert.assertEquals("STRING", param.toString("STRING")); - } - - @SmallTest - public void testStringListParam() throws Exception { - ParamDefinition<List<String>> param = ParamDefinitions.newStringListParam("NAME"); - Assert.assertEquals("_NAME", param.name()); - Assert.assertEquals("string", param.type()); - - List<String> value = param.fromString("[\"ITEM1\",\"ITEM2\"]"); - Assert.assertEquals(2, value.size()); - Assert.assertEquals("ITEM1", value.get(0)); - Assert.assertEquals("ITEM2", value.get(1)); - - try { - param.fromString("{\"ITEM1\",\"ITEM2\"}"); - Assert.fail("Exception expected"); - } catch (CommandFormatException e) { - // Expected. - } - - List<String> clone = param.fromString(param.toString(value)); - Assert.assertEquals(value.size(), clone.size()); - Assert.assertEquals(value.get(0), clone.get(0)); - Assert.assertEquals(value.get(1), clone.get(1)); - } - - @SmallTest - public void testConfigParam() throws Exception { - ParamDefinition<RTCConfiguration> param = ParamDefinitions.newConfigParam("NAME"); - Assert.assertEquals("_NAME", param.name()); - Assert.assertEquals("string", param.type()); - - RTCConfiguration value = param.fromString( - "{\"iceServers\": [{\"uri\": \"http://example.org\"}]}"); - Assert.assertNotNull(value); - Assert.assertEquals(1, value.iceServers.size()); - Assert.assertEquals("http://example.org", value.iceServers.get(0).uri); - - try { - param.fromString("["); - Assert.fail("Exception expected"); - } catch (CommandFormatException e) { - // Expected. - } - - value = new RTCConfiguration.Builder() - .addIceServer("http://example.org/1", "USERNAME", "CREDENTIAL") - .addIceServer("http://example.org/2", "USERNAME", "CREDENTIAL") - .build(); - RTCConfiguration clone = param.fromString(param.toString(value)); - Assert.assertEquals(value.iceServers.size(), clone.iceServers.size()); - Assert.assertEquals(value.iceServers.get(0).username, clone.iceServers.get(0).username); - Assert.assertEquals(value.iceServers.get(1).credential, clone.iceServers.get(1).credential); - } -}
diff --git a/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/gcd/MessageReaderTest.java b/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/gcd/MessageReaderTest.java deleted file mode 100644 index 72b5254..0000000 --- a/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/gcd/MessageReaderTest.java +++ /dev/null
@@ -1,119 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.components.devtools_bridge.gcd; - -import android.test.InstrumentationTestCase; -import android.test.suitebuilder.annotation.SmallTest; - -import junit.framework.Assert; - -import org.chromium.components.devtools_bridge.commands.Command; -import org.chromium.components.devtools_bridge.util.TestSource; - -/** - * Tests for {@link MessageReader}. - */ -public class MessageReaderTest extends InstrumentationTestCase { - private static final String DEVICE_ID = "4ac8a0f8-??????????????-192e2727710d"; - private static final String ROBOT_ACCOUNT_EMAIL = - "2a3???????????????????????????87@clouddevices.gserviceaccount.com"; - private static final String AUTHORIZATION_CODE = - "4/6V0jpup-????????????????????????????????????????????_e85kQI"; - private static final String COMMAND_ID = - "a0217abb-????-????-????-?????????????????????????-????-2725-b2332fe99829"; - - @SmallTest - public void testReadTicket() throws Exception { - TestSource source = new TestSource(); - source.write().beginObject() - .name("kind").value("clouddevices#registrationTicket") - .name("id").value("p8hI4") - .name("deviceId").value(DEVICE_ID) - .name("creationTimeMs").value("1411029429794") - .name("expirationTimeMs").value("1411029669794") - .endObject().close(); - String result = new MessageReader(source.read()).readTicketId(); - Assert.assertEquals("p8hI4", result); - } - - @SmallTest - public void testReadCredential() throws Exception { - TestSource source = new TestSource(); - source.write().beginObject() - .name("kind").value("clouddevices#registrationTicket") - .name("id").value("p8hI4") - .name("deviceId").value(DEVICE_ID) - .name("userEmail").value("...@chromium.org") - .name("creationTimeMs").value("1411029429794") - .name("expirationTimeMs").value("1411029669794") - .name("robotAccountEmail").value(ROBOT_ACCOUNT_EMAIL) - .name("robotAccountAuthorizationCode").value(AUTHORIZATION_CODE) - .endObject().close(); - InstanceCredential result = new MessageReader(source.read()).readInstanceCredential(); - Assert.assertEquals(DEVICE_ID, result.id); - Assert.assertEquals(AUTHORIZATION_CODE, result.secret); - } - - @SmallTest - public void testReadNotificationCommandCreated() throws Exception { - TestSource source = new TestSource(); - source.write().beginObject() - .name("type").value("COMMAND_CREATED") - .name("commandId").value(COMMAND_ID) - .name("deviceId").value(DEVICE_ID) - .name("command").beginObject() - .name("kind").value("clouddevices#command") - .name("id").value(COMMAND_ID) - .name("deviceId").value(DEVICE_ID) - .name("name").value("base._startSession") - .name("parameters").beginObject() - .name("_sessionId").value("SESSION_ID") - .name("_config").value("{}") - .name("_offer").value("INVALID_OFFER") - .endObject() // parameters - .name("state").value("queued") - .name("error").beginObject() - .name("arguments").beginArray().endArray() - .name("creationTimeMs").value("1411137527329") - .name("expirationTimeMs").value("1411137547329") - .endObject() // error - .endObject() // command - .name("expirationTimeMs").value("1411029669794") - .endObject().close(); - Notification result = new MessageReader(source.read()).readNotification(); - - Assert.assertEquals(Notification.Type.COMMAND_CREATED, result.type); - Assert.assertEquals(DEVICE_ID, result.instanceId); - Assert.assertNotNull(result.command); - Assert.assertEquals(COMMAND_ID, result.command.id); - Assert.assertEquals(Command.Type.START_SESSION, result.command.type); - } - - @SmallTest - public void testReadNotificationCommandExpired() throws Exception { - TestSource source = new TestSource(); - source.write().beginObject() - .name("type").value("COMMAND_EXPIRED") - .name("commandId").value(COMMAND_ID) - .name("deviceId").value(DEVICE_ID) - .endObject().close(); - Notification result = new MessageReader(source.read()).readNotification(); - Assert.assertNull(result); - } - - @SmallTest - public void testReadNotificationInstanceUNregistered() throws Exception { - TestSource source = new TestSource(); - source.write().beginObject() - .name("type").value("DEVICE_DELETED") - .name("deviceId").value(DEVICE_ID) - .endObject().close(); - Notification result = new MessageReader(source.read()).readNotification(); - - Assert.assertEquals(Notification.Type.INSTANCE_UNREGISTERED, result.type); - Assert.assertEquals(DEVICE_ID, result.instanceId); - Assert.assertNull(result.command); - } -}
diff --git a/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/tests/DebugActivity.java b/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/tests/DebugActivity.java deleted file mode 100644 index 3fab9d3f..0000000 --- a/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/tests/DebugActivity.java +++ /dev/null
@@ -1,136 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.components.devtools_bridge.tests; - -import android.app.Activity; -import android.content.Intent; -import android.os.Build; -import android.os.Bundle; -import android.text.Html; -import android.text.method.LinkMovementMethod; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.Button; -import android.widget.LinearLayout; -import android.widget.LinearLayout.LayoutParams; -import android.widget.TextView; - -import org.chromium.components.devtools_bridge.ui.GCDRegistrationFragment; -import org.chromium.components.devtools_bridge.ui.RemoteInstanceListFragment; - -/** - * Activity for testing devtools bridge. - */ -public class DebugActivity extends Activity { - private static final int LAYOUT_ID = 1000; - private static final String DOC_HREF = - "https://docs.google.com/a/chromium.org/document/d/" - + "188V6TWV8ivbjAPIp6aqwffWrY78xN2an5REajZHpunk/edit?usp=sharing"; - - private LinearLayout mLayout; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - mLayout = new LinearLayout(this); - mLayout.setId(LAYOUT_ID); - mLayout.setOrientation(LinearLayout.VERTICAL); - - TextView textView = new TextView(this); - textView.setText(Html.fromHtml( - "See <a href=\"" + DOC_HREF + "\">testing instructions</a>.")); - textView.setMovementMethod(LinkMovementMethod.getInstance()); - mLayout.addView(textView); - - addActionButton("Start LocalSessionBridge", DebugService.START_SESSION_BRIDGE_ACTION); - addActionButton("Start DevToolsBridgeServer", DebugService.START_SERVER_ACTION); - addActionButton("Stop", DebugService.STOP_ACTION); - - LayoutParams layoutParam = new LayoutParams(LayoutParams.MATCH_PARENT, - LayoutParams.MATCH_PARENT); - - getFragmentManager() - .beginTransaction() - .add(LAYOUT_ID, new TestGCDRegistrationFragment()) - .add(LAYOUT_ID, new RemoteInstanceListFragmentImpl()) - .commit(); - - setContentView(mLayout, layoutParam); - } - - private void addActionButton(String text, String action) { - Button button = new Button(this); - button.setText(text); - button.setOnClickListener(new SendActionOnClickListener(action)); - mLayout.addView(button); - } - - private class SendActionOnClickListener implements View.OnClickListener { - private final String mAction; - - SendActionOnClickListener(String action) { - mAction = action; - } - - @Override - public void onClick(View v) { - Intent intent = new Intent(DebugActivity.this, DebugService.class); - intent.setAction(mAction); - startService(intent); - } - } - - private static class TestGCDRegistrationFragment - extends GCDRegistrationFragment implements View.OnClickListener { - private Button mButton; - - @Override - public View onCreateView( - LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - mButton = new Button(getActivity()); - mButton.setOnClickListener(this); - updateText(); - return mButton; - } - - public void updateText() { - mButton.setText(isRegistered() - ? "Unregister (registered for " + getOwner() + ")" - : "Register in GCD"); - } - - @Override - protected void onRegistrationStatusChange() { - updateText(); - } - - @Override - protected String generateDisplayName() { - return Build.MODEL + " Test app"; - } - - @Override - public void onClick(View v) { - if (!isRegistered()) { - register(); - } else { - unregister(); - } - } - } - - private final class RemoteInstanceListFragmentImpl extends RemoteInstanceListFragment { - @Override - protected void connect(String oAuthToken, String remoteInstanceId) { - startService(new Intent(DebugActivity.this, DebugService.class) - .setAction(DebugService.START_GCD_CLIENT_ACTION) - .putExtra(DebugService.EXTRA_OAUTH_TOKEN, oAuthToken) - .putExtra(DebugService.EXTRA_REMOTE_INSTANCE_ID, remoteInstanceId)); - } - } -} -
diff --git a/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/tests/DebugService.java b/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/tests/DebugService.java deleted file mode 100644 index b009555..0000000 --- a/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/tests/DebugService.java +++ /dev/null
@@ -1,243 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.components.devtools_bridge.tests; - -import android.app.Notification; -import android.app.PendingIntent; -import android.app.Service; -import android.content.Intent; -import android.os.Binder; -import android.os.IBinder; -import android.os.Process; -import android.widget.Toast; - -import org.chromium.components.devtools_bridge.DevToolsBridgeServerSandbox; -import org.chromium.components.devtools_bridge.GCDClientSessionTestingHost; -import org.chromium.components.devtools_bridge.LocalSessionBridge; - -import java.io.IOException; - -/** - * Service for testing devtools bridge. - */ -public class DebugService extends Service { - public static final String START_SESSION_BRIDGE_ACTION = "action.START_SESSION_BRIDGE"; - public static final String START_SERVER_ACTION = "action.START_SERVER"; - public static final String START_GCD_CLIENT_ACTION = "action.START_GCD_CLIENT"; - public static final String STOP_ACTION = "action.STOP"; - - public static final String EXTRA_OAUTH_TOKEN = "extra.OAUTH_TOKEN"; - public static final String EXTRA_REMOTE_INSTANCE_ID = "extra.REMOTE_INSTANCE_ID"; - - private static final int NOTIFICATION_ID = 1; - - private Controller mRunningController; - - private interface Controller { - void create() throws IOException; - void start() throws Exception; - void stop(); - void dispose(); - } - - private String replicatingSocketName() { - return "chrome_shell_devtools_remote"; - } - - private String exposingSocketName() { - return "webview_devtools_remote_" + Integer.valueOf(Process.myPid()); - } - - private class LocalSessionBridgeController implements Controller { - private LocalSessionBridge mBridge; - - @Override - public void create() throws IOException { - mBridge = new LocalSessionBridge(replicatingSocketName(), exposingSocketName()); - } - - @Override - public void start() { - mBridge.start(); - } - - @Override - public void stop() { - mBridge.stop(); - } - - @Override - public void dispose() { - mBridge.dispose(); - } - - @Override - public String toString() { - return "LocalSessionBridge"; - } - } - - private class DevToolsBridgeServerSandboxController implements Controller { - private DevToolsBridgeServerSandbox mSandbox; - - @Override - public void create() { - mSandbox = new DevToolsBridgeServerSandbox(); - } - - @Override - public void start() throws Exception { - mSandbox.start(DebugService.this); - } - - @Override - public void stop() { - mSandbox.stop(); - } - - @Override - public void dispose() {} - - @Override - public String toString() { - return "DevToolsBridgeServerSandbox"; - } - } - - private class GCDClientController implements Controller { - private final String mOAuthToken; - private final String mRemoteInstanceId; - - private GCDClientSessionTestingHost mHost; - - public GCDClientController(String oAuthToken, String remoteInstanceId) { - mOAuthToken = oAuthToken; - mRemoteInstanceId = remoteInstanceId; - } - - @Override - public void create() { - } - - @Override - public void start() throws Exception { - final GCDClientSessionTestingHost host = new GCDClientSessionTestingHost( - mOAuthToken, exposingSocketName(), mRemoteInstanceId); - host.start(new Runnable() { - @Override - public void run() { - String text; - if (!host.isStarted()) { - text = "Session not started. See log for details"; - } else { - text = "Session started"; - } - Toast.makeText(DebugService.this, text, Toast.LENGTH_SHORT).show(); - } - }); - mHost = host; - } - - @Override - public void stop() { - } - - @Override - public void dispose() { - mHost.dispose(); - } - - @Override - public String toString() { - return "GCDClientSessionTestingHost"; - } - } - - @Override - public int onStartCommand(Intent intent, int flags, int startId) { - if (intent == null) return START_NOT_STICKY; - - String action = intent.getAction(); - if (START_SESSION_BRIDGE_ACTION.equals(action)) { - return start(new LocalSessionBridgeController()); - } else if (START_SERVER_ACTION.equals(action)) { - return start(new DevToolsBridgeServerSandboxController()); - } else if (START_GCD_CLIENT_ACTION.equals(action)) { - String oAuthToken = intent.getStringExtra(EXTRA_OAUTH_TOKEN); - String remoteInstanceId = intent.getStringExtra(EXTRA_REMOTE_INSTANCE_ID); - return start(new GCDClientController(oAuthToken, remoteInstanceId)); - } else if (STOP_ACTION.equals(action)) { - return stop(); - } - return START_NOT_STICKY; - } - - private int start(Controller controller) { - if (mRunningController != null) { - Toast.makeText(this, "Already started", Toast.LENGTH_SHORT).show(); - return START_NOT_STICKY; - } - - try { - controller.create(); - controller.start(); - } catch (Exception e) { - e.printStackTrace(); - Toast.makeText(this, "Failed to start", Toast.LENGTH_SHORT).show(); - controller.dispose(); - return START_NOT_STICKY; - } - mRunningController = controller; - - startForeground(NOTIFICATION_ID, makeForegroundServiceNotification()); - Toast.makeText(this, controller.toString() + " started", Toast.LENGTH_SHORT).show(); - return START_STICKY; - } - - private int stop() { - if (mRunningController == null) - return START_NOT_STICKY; - - String name = mRunningController.toString(); - mRunningController.stop(); - mRunningController.dispose(); - mRunningController = null; - stopSelf(); - Toast.makeText(this, name + " stopped", Toast.LENGTH_SHORT).show(); - return START_NOT_STICKY; - } - - @Override - public IBinder onBind(Intent intent) { - return new Binder(); - } - - private Notification makeForegroundServiceNotification() { - Intent showInfoIntent = new Intent(this, DebugActivity.class); - showInfoIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP); - PendingIntent showInfoPendingIntent = - PendingIntent.getActivity(DebugService.this, 0, showInfoIntent, 0); - - Intent stopIntent = new Intent(this, DebugService.class); - stopIntent.setAction(STOP_ACTION); - PendingIntent stopPendingIntent = - PendingIntent.getService(DebugService.this, 0, stopIntent, 0); - - return new Notification.Builder(this) - // Mandatory fiends - .setSmallIcon(android.R.drawable.alert_dark_frame) - .setContentTitle("DevTools Bridge") - .setContentText("DevTools socket local test tunnel works") - - // Optional - .setContentIntent(showInfoPendingIntent) - .addAction(android.R.drawable.ic_delete, - "Stop", stopPendingIntent) - .setOngoing(true) - .setWhen(System.currentTimeMillis()) - .build(); - } -} -
diff --git a/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/tests/TestApplication.java b/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/tests/TestApplication.java deleted file mode 100644 index d6b16ba..0000000 --- a/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/tests/TestApplication.java +++ /dev/null
@@ -1,28 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.components.devtools_bridge.tests; - -import android.app.Application; - -import org.chromium.base.library_loader.LibraryLoader; -import org.chromium.base.library_loader.LibraryProcessType; -import org.chromium.base.library_loader.ProcessInitException; -import org.chromium.components.devtools_bridge.SessionDependencyFactory; -import org.chromium.components.devtools_bridge.SessionDependencyFactoryNative; - -/** - * Performs initialization for DevTools Bridge test APK. - */ -public class TestApplication extends Application { - static { - System.loadLibrary("devtools_bridge_natives_so"); - SessionDependencyFactory.init(SessionDependencyFactoryNative.class); - try { - LibraryLoader.get(LibraryProcessType.PROCESS_BROWSER).ensureInitialized(); - } catch (ProcessInitException e) { - throw new RuntimeException(e); - } - } -}
diff --git a/components/devtools_bridge/android/session_dependency_factory_android.cc b/components/devtools_bridge/android/session_dependency_factory_android.cc deleted file mode 100644 index 50c81c5..0000000 --- a/components/devtools_bridge/android/session_dependency_factory_android.cc +++ /dev/null
@@ -1,302 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/devtools_bridge/android/session_dependency_factory_android.h" - -#include "base/android/jni_string.h" -#include "base/android/scoped_java_ref.h" -#include "base/bind.h" -#include "components/devtools_bridge/abstract_data_channel.h" -#include "components/devtools_bridge/abstract_peer_connection.h" -#include "components/devtools_bridge/rtc_configuration.h" -#include "components/devtools_bridge/socket_tunnel_server.h" -#include "jni/SessionDependencyFactoryNative_jni.h" - -using base::android::AttachCurrentThread; -using base::android::ConvertJavaStringToUTF8; -using base::android::ConvertUTF8ToJavaString; - -namespace devtools_bridge { -namespace android { - -namespace { - -/** - * Wraps Java observer and adapts it to native delegate. Chromium code normally - * leaves local java references for automatic disposing. It doesn't happen here - * (because calls originated from native thread). For instance, instead of - * - * ConvertUTF8ToJavaString(env, ...).Release() - * - * please use ConvertUTF8ToJavaString(env, ...).obj() or ScopedJavaLocalFrame. - */ -class PeerConnectionDelegateImpl - : public AbstractPeerConnection::Delegate { - public: - PeerConnectionDelegateImpl(JNIEnv* env, jobject java_object) { - java_object_.Reset(env, java_object); - connected_ = false; - } - - void OnIceConnectionChange(bool connected) override { - JNIEnv* env = AttachCurrentThread(); - Java_SessionDependencyFactoryNative_notifyIceConnectionChange( - env, java_object_.obj(), connected); - } - - void OnIceCandidate(const std::string& sdp_mid, - int sdp_mline_index, - const std::string& sdp) override { - JNIEnv* env = AttachCurrentThread(); - Java_SessionDependencyFactoryNative_notifyIceCandidate( - env, java_object_.obj(), - ConvertUTF8ToJavaString(env, sdp_mid).obj(), - sdp_mline_index, ConvertUTF8ToJavaString(env, sdp).obj()); - } - - void NotifyLocalOfferCreatedAndSetSet(const std::string& description) { - JNIEnv* env = AttachCurrentThread(); - Java_SessionDependencyFactoryNative_notifyLocalOfferCreatedAndSetSet( - env, java_object_.obj(), - ConvertUTF8ToJavaString(env, description).obj()); - } - - void OnLocalOfferCreatedAndSetSet(const std::string& description) override { - JNIEnv* env = AttachCurrentThread(); - Java_SessionDependencyFactoryNative_notifyLocalOfferCreatedAndSetSet( - env, java_object_.obj(), - ConvertUTF8ToJavaString(env, description).obj()); - } - - void OnLocalAnswerCreatedAndSetSet(const std::string& description) override { - JNIEnv* env = AttachCurrentThread(); - Java_SessionDependencyFactoryNative_notifyLocalAnswerCreatedAndSetSet( - env, java_object_.obj(), - ConvertUTF8ToJavaString(env, description).obj()); - } - - void OnRemoteDescriptionSet() override { - JNIEnv* env = AttachCurrentThread(); - Java_SessionDependencyFactoryNative_notifyRemoteDescriptionSet( - env, java_object_.obj()); - } - - void OnFailure(const std::string& description) override { - JNIEnv* env = AttachCurrentThread(); - Java_SessionDependencyFactoryNative_notifyConnectionFailure( - env, java_object_.obj(), - ConvertUTF8ToJavaString(env, description).obj()); - } - - private: - base::android::ScopedJavaGlobalRef<jobject> java_object_; - bool connected_; -}; - -class DataChannelObserverImpl : public AbstractDataChannel::Observer { - public: - DataChannelObserverImpl(JNIEnv* env, jobject java_object) { - java_object_.Reset(env, java_object); - } - - void OnOpen() override { - JNIEnv* env = AttachCurrentThread(); - Java_SessionDependencyFactoryNative_notifyChannelOpen( - env, java_object_.obj()); - } - - void OnClose() override { - JNIEnv* env = AttachCurrentThread(); - Java_SessionDependencyFactoryNative_notifyChannelClose( - env, java_object_.obj()); - } - - void OnMessage(const void* data, size_t length) override { - JNIEnv* env = AttachCurrentThread(); - - ScopedJavaLocalRef<jobject> byte_buffer( - env, env->NewDirectByteBuffer(const_cast<void*>(data), length)); - - Java_SessionDependencyFactoryNative_notifyMessage( - env, java_object_.obj(), byte_buffer.obj()); - } - - private: - base::android::ScopedJavaGlobalRef<jobject> java_object_; -}; - -static void CleanupOnSignalingThread() { - // Called on signaling thread when SessionDependencyFactory is destroying. - base::android::DetachFromVM(); -} - -} // namespace - -// SessionDependencyFactoryNative - -SessionDependencyFactoryAndroid::SessionDependencyFactoryAndroid() - : impl_(SessionDependencyFactory::CreateInstance( - base::Bind(&CleanupOnSignalingThread))) { -} - -SessionDependencyFactoryAndroid::~SessionDependencyFactoryAndroid() { -} - -// static -bool SessionDependencyFactoryAndroid::RegisterNatives(JNIEnv* env) { - return RegisterNativesImpl(env); -} - -scoped_ptr<AbstractPeerConnection> -SessionDependencyFactoryAndroid::CreatePeerConnection( - scoped_ptr<RTCConfiguration> config, - scoped_ptr<AbstractPeerConnection::Delegate> delegate) { - return impl_->CreatePeerConnection(config.Pass(), delegate.Pass()); -} - -scoped_refptr<base::TaskRunner> -SessionDependencyFactoryAndroid::signaling_thread_task_runner() { - return impl_->signaling_thread_task_runner(); -} - -scoped_refptr<base::TaskRunner> -SessionDependencyFactoryAndroid::io_thread_task_runner() { - return impl_->io_thread_task_runner(); -} - -// JNI generated methods - -static jlong CreateFactory(JNIEnv* env, jclass jcaller) { - return reinterpret_cast<jlong>(new SessionDependencyFactoryAndroid()); -} - -static void DestroyFactory(JNIEnv* env, jclass jcaller, jlong factory_ptr) { - delete reinterpret_cast<SessionDependencyFactoryAndroid*>(factory_ptr); -} - -static jlong CreateConfig(JNIEnv* env, jclass jcaller) { - return reinterpret_cast<jlong>( - RTCConfiguration::CreateInstance().release()); -} - -static void AddIceServer( - JNIEnv* env, jclass jcaller, jlong config_ptr, - jstring uri, jstring username, jstring credential) { - reinterpret_cast<RTCConfiguration*>(config_ptr)->AddIceServer( - ConvertJavaStringToUTF8(env, uri), - ConvertJavaStringToUTF8(env, username), - ConvertJavaStringToUTF8(env, credential)); -} - -static jlong CreatePeerConnection( - JNIEnv* env, jclass jcaller, - jlong factory_ptr, jlong config_ptr, jobject observer) { - auto factory = - reinterpret_cast<SessionDependencyFactoryAndroid*>(factory_ptr); - auto config = reinterpret_cast<RTCConfiguration*>(config_ptr); - - auto delegate = new PeerConnectionDelegateImpl(env, observer); - - return reinterpret_cast<jlong>(factory->CreatePeerConnection( - make_scoped_ptr(config), make_scoped_ptr(delegate)).release()); -} - -static void DestroyPeerConnection( - JNIEnv* env, jclass jcaller, jlong connection_ptr) { - delete reinterpret_cast<AbstractPeerConnection*>(connection_ptr); -} - -static void CreateAndSetLocalOffer( - JNIEnv* env, jclass jcaller, jlong connection_ptr) { - reinterpret_cast<AbstractPeerConnection*>( - connection_ptr)->CreateAndSetLocalOffer(); -} - -static void CreateAndSetLocalAnswer( - JNIEnv* env, jclass jcaller, jlong connection_ptr) { - reinterpret_cast<AbstractPeerConnection*>( - connection_ptr)->CreateAndSetLocalAnswer(); -} - -static void SetRemoteOffer( - JNIEnv* env, jclass jcaller, jlong connection_ptr, jstring description) { - reinterpret_cast<AbstractPeerConnection*>(connection_ptr)->SetRemoteOffer( - ConvertJavaStringToUTF8(env, description)); -} - -static void SetRemoteAnswer( - JNIEnv* env, jclass jcaller, jlong connection_ptr, jstring description) { - reinterpret_cast<AbstractPeerConnection*>(connection_ptr)->SetRemoteAnswer( - ConvertJavaStringToUTF8(env, description)); -} - -static void AddIceCandidate( - JNIEnv* env, jclass jcaller, - jlong connection_ptr, jstring sdp_mid, jint sdp_mline_index, jstring sdp) { - reinterpret_cast<AbstractPeerConnection*>(connection_ptr)->AddIceCandidate( - ConvertJavaStringToUTF8(env, sdp_mid), - sdp_mline_index, - ConvertJavaStringToUTF8(env, sdp)); -} - -static jlong CreateDataChannel( - JNIEnv* env, jclass jcaller, jlong connection_ptr, jint channel_id) { - return reinterpret_cast<jlong>( - reinterpret_cast<AbstractPeerConnection*>( - connection_ptr)->CreateDataChannel(channel_id).release()); -} - -static void DestroyDataChannel( - JNIEnv* env, jclass jcaller, jlong channel_ptr) { - delete reinterpret_cast<AbstractDataChannel*>(channel_ptr); -} - -static void RegisterDataChannelObserver( - JNIEnv* env, jclass jcaller, jlong channel_ptr, jobject observer) { - reinterpret_cast<AbstractDataChannel*>(channel_ptr)->RegisterObserver( - make_scoped_ptr(new DataChannelObserverImpl(env, observer))); -} - -static void UnregisterDataChannelObserver( - JNIEnv* env, jclass jcaller, jlong channel_ptr) { - reinterpret_cast<AbstractDataChannel*>(channel_ptr)->UnregisterObserver(); -} - -static void SendBinaryMessage( - JNIEnv* env, jclass jcaller, jlong channel_ptr, jobject message, - jint size) { - DCHECK(size > 0); - reinterpret_cast<AbstractDataChannel*>(channel_ptr)->SendBinaryMessage( - env->GetDirectBufferAddress(message), size); -} - -static void SendTextMessage( - JNIEnv* env, jclass jcaller, jlong channel_ptr, jobject message, - jint size) { - DCHECK(size > 0); - reinterpret_cast<AbstractDataChannel*>(channel_ptr)->SendTextMessage( - env->GetDirectBufferAddress(message), size); -} - -static void CloseDataChannel(JNIEnv* env, jclass jcaller, jlong channel_ptr) { - reinterpret_cast<AbstractDataChannel*>(channel_ptr)->Close(); -} - -static jlong CreateSocketTunnelServer( - JNIEnv* env, jclass jcaller, jlong factory_ptr, jlong channel_ptr, - jstring socket_name) { - return reinterpret_cast<jlong>( - new SocketTunnelServer( - reinterpret_cast<SessionDependencyFactory*>(factory_ptr), - reinterpret_cast<AbstractDataChannel*>(channel_ptr), - ConvertJavaStringToUTF8(env, socket_name))); -} - -static void DestroySocketTunnelServer( - JNIEnv* env, jclass jcaller, jlong tunnel_ptr) { - delete reinterpret_cast<SocketTunnelServer*>(tunnel_ptr); -} - -} // namespace android -} // namespace devtools_bridge
diff --git a/components/devtools_bridge/android/session_dependency_factory_android.h b/components/devtools_bridge/android/session_dependency_factory_android.h deleted file mode 100644 index 24496de1..0000000 --- a/components/devtools_bridge/android/session_dependency_factory_android.h +++ /dev/null
@@ -1,37 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_DEVTOOLS_BRIDGE_ANDROID_SESSION_DEPENDENCY_FACTORY_ANDROID_H_ -#define COMPONENTS_DEVTOOLS_BRIDGE_ANDROID_SESSION_DEPENDENCY_FACTORY_ANDROID_H_ - -#include "components/devtools_bridge/session_dependency_factory.h" -#include "jni.h" - -namespace devtools_bridge { -namespace android { - -class SessionDependencyFactoryAndroid : public SessionDependencyFactory { - public: - SessionDependencyFactoryAndroid(); - ~SessionDependencyFactoryAndroid() override; - - static bool RegisterNatives(JNIEnv* env); - - scoped_ptr<AbstractPeerConnection> CreatePeerConnection( - scoped_ptr<RTCConfiguration> config, - scoped_ptr<AbstractPeerConnection::Delegate> delegate) override; - - scoped_refptr<base::TaskRunner> signaling_thread_task_runner() override; - scoped_refptr<base::TaskRunner> io_thread_task_runner() override; - - private: - const scoped_ptr<SessionDependencyFactory> impl_; - - DISALLOW_COPY_AND_ASSIGN(SessionDependencyFactoryAndroid); -}; - -} // namespace android -} // namespace devtools_bridge - -#endif // COMPONENTS_DEVTOOLS_BRIDGE_ANDROID_SESSION_DEPENDENCY_FACTORY_ANDROID_H_
diff --git a/components/devtools_bridge/rtc_configuration.h b/components/devtools_bridge/rtc_configuration.h deleted file mode 100644 index 7eb0a220..0000000 --- a/components/devtools_bridge/rtc_configuration.h +++ /dev/null
@@ -1,39 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_DEVTOOLS_BRIDGE_RTC_CONFIGURATION_H_ -#define COMPONENTS_DEVTOOLS_BRIDGE_RTC_CONFIGURATION_H_ - -#include <string> - -#include "base/memory/scoped_ptr.h" - -namespace devtools_bridge { - -/** - * WebRTC configuration for DevTools Bridge. - */ -class RTCConfiguration { - public: - class Impl; - - RTCConfiguration() {} - virtual ~RTCConfiguration() {} - - virtual void AddIceServer( - const std::string& uri, - const std::string& username, - const std::string& credential) = 0; - - virtual const Impl& impl() const = 0; - - static scoped_ptr<RTCConfiguration> CreateInstance(); - - private: - DISALLOW_COPY_AND_ASSIGN(RTCConfiguration); -}; - -} // namespace devtools_bridge - -#endif // COMPONENTS_DEVTOOLS_BRIDGE_RTC_CONFIGURATION_H_
diff --git a/components/devtools_bridge/session_dependency_factory.cc b/components/devtools_bridge/session_dependency_factory.cc deleted file mode 100644 index 2efa641..0000000 --- a/components/devtools_bridge/session_dependency_factory.cc +++ /dev/null
@@ -1,641 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/devtools_bridge/session_dependency_factory.h" - -#include "base/bind.h" -#include "base/location.h" -#include "base/task_runner.h" -#include "base/threading/thread.h" -#include "components/devtools_bridge/abstract_data_channel.h" -#include "components/devtools_bridge/abstract_peer_connection.h" -#include "components/devtools_bridge/rtc_configuration.h" -#include "third_party/libjingle/source/talk/app/webrtc/mediaconstraintsinterface.h" -#include "third_party/libjingle/source/talk/app/webrtc/peerconnectioninterface.h" -#include "third_party/webrtc/base/bind.h" -#include "third_party/webrtc/base/messagehandler.h" -#include "third_party/webrtc/base/messagequeue.h" -#include "third_party/webrtc/base/ssladapter.h" -#include "third_party/webrtc/base/thread.h" - -namespace devtools_bridge { - -class RTCConfiguration::Impl - : public RTCConfiguration, - public webrtc::PeerConnectionInterface::RTCConfiguration { - public: - void AddIceServer(const std::string& uri, - const std::string& username, - const std::string& credential) override { - webrtc::PeerConnectionInterface::IceServer server; - server.uri = uri; - server.username = username; - server.password = credential; - servers.push_back(server); - } - - const Impl& impl() const override { - return *this; - } - - private: - webrtc::PeerConnectionInterface::RTCConfiguration base_; -}; - -namespace { - -template <typename T> -void CheckedRelease(rtc::scoped_refptr<T>* ptr) { - CHECK_EQ(0, ptr->release()->Release()); -} - -class MediaConstraints - : public webrtc::MediaConstraintsInterface { - public: - ~MediaConstraints() override {} - - const Constraints& GetMandatory() const override { return mandatory_; } - - const Constraints& GetOptional() const override { return optional_; } - - void AddMandatory(const std::string& key, const std::string& value) { - mandatory_.push_back(Constraint(key, value)); - } - - private: - Constraints mandatory_; - Constraints optional_; -}; - -/** - * Posts tasks on signaling thread. If stopped (when SesseionDependencyFactry - * is destroying) ignores posted tasks. - */ -class SignalingThreadTaskRunner : public base::TaskRunner, - private rtc::MessageHandler { - public: - explicit SignalingThreadTaskRunner(rtc::Thread* thread) : thread_(thread) {} - - bool PostDelayedTask(const tracked_objects::Location& from_here, - const base::Closure& task, - base::TimeDelta delay) override { - DCHECK(delay.ToInternalValue() == 0); - - rtc::CritScope scope(&critical_section_); - - if (thread_) - thread_->Send(this, 0, new Task(task)); - - return true; - } - - bool RunsTasksOnCurrentThread() const override { - rtc::CritScope scope(&critical_section_); - - return thread_ != NULL && thread_->IsCurrent(); - } - - void Stop() { - rtc::CritScope scope(&critical_section_); - thread_ = NULL; - } - - private: - typedef rtc::TypedMessageData<base::Closure> Task; - - ~SignalingThreadTaskRunner() override {} - - void OnMessage(rtc::Message* msg) override { - static_cast<Task*>(msg->pdata)->data().Run(); - } - - mutable rtc::CriticalSection critical_section_; - rtc::Thread* thread_; // Guarded by |critical_section_|. -}; - -class DataChannelObserverImpl : public webrtc::DataChannelObserver { - public: - DataChannelObserverImpl( - webrtc::DataChannelInterface* data_channel, - scoped_ptr<AbstractDataChannel::Observer> observer) - : data_channel_(data_channel), - observer_(observer.Pass()) { - } - - void InitState() { - open_ = data_channel_->state() == webrtc::DataChannelInterface::kOpen; - } - - void OnStateChange() override { - bool open = data_channel_->state() == webrtc::DataChannelInterface::kOpen; - - if (open == open_) return; - - open_ = open; - if (open) { - observer_->OnOpen(); - } else { - observer_->OnClose(); - } - } - - void OnMessage(const webrtc::DataBuffer& buffer) override { - observer_->OnMessage(buffer.data.data(), buffer.size()); - } - - private: - webrtc::DataChannelInterface* const data_channel_; - scoped_ptr<AbstractDataChannel::Observer> const observer_; - bool open_; -}; - -/** - * Thread-safe view on AbstractDataChannel. - */ -class DataChannelProxyImpl : public AbstractDataChannel::Proxy { - public: - DataChannelProxyImpl( - SessionDependencyFactory* factory, - rtc::scoped_refptr<webrtc::DataChannelInterface> data_channel) - : data_channel_(data_channel), - signaling_thread_task_runner_( - factory->signaling_thread_task_runner()) { - } - - void StopOnSignalingThread() { - data_channel_ = NULL; - } - - void SendBinaryMessage(const void* data, size_t length) override { - auto buffer = make_scoped_ptr(new webrtc::DataBuffer(rtc::Buffer(), true)); - buffer->data.SetData(static_cast<const uint8_t*>(data), length); - - signaling_thread_task_runner_->PostTask( - FROM_HERE, base::Bind( - &DataChannelProxyImpl::SendMessageOnSignalingThread, - this, - base::Passed(&buffer))); - } - - void Close() override { - signaling_thread_task_runner_->PostTask( - FROM_HERE, base::Bind(&DataChannelProxyImpl::CloseOnSignalingThread, - this)); - } - - private: - - ~DataChannelProxyImpl() override {} - - void SendMessageOnSignalingThread(scoped_ptr<webrtc::DataBuffer> message) { - if (data_channel_ != NULL) - data_channel_->Send(*message); - } - - void CloseOnSignalingThread() { - if (data_channel_ != NULL) - data_channel_->Close(); - } - - // Accessed on signaling thread. - rtc::scoped_refptr<webrtc::DataChannelInterface> data_channel_; - - const scoped_refptr<base::TaskRunner> signaling_thread_task_runner_; -}; - -class DataChannelImpl : public AbstractDataChannel { - public: - DataChannelImpl( - SessionDependencyFactory* factory, - rtc::Thread* const signaling_thread, - rtc::scoped_refptr<webrtc::DataChannelInterface> impl) - : factory_(factory), - signaling_thread_(signaling_thread), - impl_(impl) { - } - - ~DataChannelImpl() override { - if (proxy_.get()) { - signaling_thread_->Invoke<void>(rtc::Bind( - &DataChannelProxyImpl::StopOnSignalingThread, proxy_.get())); - } - } - - void RegisterObserver(scoped_ptr<Observer> observer) override { - observer_.reset(new DataChannelObserverImpl(impl_.get(), observer.Pass())); - signaling_thread_->Invoke<void>(rtc::Bind( - &DataChannelImpl::RegisterObserverOnSignalingThread, this)); - } - - void UnregisterObserver() override { - DCHECK(observer_.get() != NULL); - impl_->UnregisterObserver(); - observer_.reset(); - } - - void SendBinaryMessage(void* data, size_t length) override { - SendMessage(data, length, true); - } - - void SendTextMessage(void* data, size_t length) override { - SendMessage(data, length, false); - } - - void SendMessage(void* data, size_t length, bool is_binary) { - impl_->Send(webrtc::DataBuffer( - rtc::Buffer(static_cast<uint8_t*>(data), length), is_binary)); - } - - void Close() override { - impl_->Close(); - } - - scoped_refptr<Proxy> proxy() override { - if (!proxy_.get()) - proxy_ = new DataChannelProxyImpl(factory_, impl_); - return proxy_; - } - - private: - void RegisterObserverOnSignalingThread() { - // State initialization and observer registration happen atomically - // if done on the signaling thread (see rtc::Thread::Send). - observer_->InitState(); - impl_->RegisterObserver(observer_.get()); - } - - SessionDependencyFactory* const factory_; - scoped_refptr<DataChannelProxyImpl> proxy_; - rtc::Thread* const signaling_thread_; - scoped_ptr<DataChannelObserverImpl> observer_; - const rtc::scoped_refptr<webrtc::DataChannelInterface> impl_; -}; - -class PeerConnectionObserverImpl - : public webrtc::PeerConnectionObserver { - public: - PeerConnectionObserverImpl(AbstractPeerConnection::Delegate* delegate) - : delegate_(delegate), - connected_(false) { - } - - void OnAddStream(webrtc::MediaStreamInterface* stream) override {} - - void OnRemoveStream(webrtc::MediaStreamInterface* stream) override {} - - void OnDataChannel(webrtc::DataChannelInterface* data_channel) override {} - - void OnRenegotiationNeeded() override {} - - void OnSignalingChange( - webrtc::PeerConnectionInterface::SignalingState new_state) override {} - - void OnIceConnectionChange( - webrtc::PeerConnectionInterface::IceConnectionState new_state) override { - bool connected = - new_state == webrtc::PeerConnectionInterface::kIceConnectionConnected || - new_state == webrtc::PeerConnectionInterface::kIceConnectionCompleted; - - if (connected != connected_) { - connected_ = connected; - delegate_->OnIceConnectionChange(connected_); - } - } - - void OnIceCandidate(const webrtc::IceCandidateInterface* candidate) override { - std::string sdp; - candidate->ToString(&sdp); - - delegate_->OnIceCandidate( - candidate->sdp_mid(), candidate->sdp_mline_index(), sdp); - } - - private: - AbstractPeerConnection::Delegate* const delegate_; - bool connected_; -}; - -/** - * Helper object which may outlive PeerConnectionImpl. Provides access - * to the connection and the delegate to operaion callback objects - * in a safe way. Always accessible on the signaling thread. - */ -class PeerConnectionHolder : public rtc::RefCountInterface { - public: - PeerConnectionHolder( - rtc::Thread* signaling_thread, - webrtc::PeerConnectionInterface* connection, - AbstractPeerConnection::Delegate* delegate) - : signaling_thread_(signaling_thread), - connection_(connection), - delegate_(delegate), - disposed_(false) { - } - - ~PeerConnectionHolder() override { DCHECK(disposed_); } - - void Dispose() { - DCHECK(!IsDisposed()); - disposed_ = true; - } - - webrtc::PeerConnectionInterface* connection() { - DCHECK(!IsDisposed()); - return connection_; - } - - AbstractPeerConnection::Delegate* delegate() { - DCHECK(!IsDisposed()); - return delegate_; - } - - bool IsDisposed() { - DCHECK(signaling_thread_->IsCurrent()); - return disposed_; - } - - private: - rtc::Thread* const signaling_thread_; - webrtc::PeerConnectionInterface* const connection_; - AbstractPeerConnection::Delegate* const delegate_; - bool disposed_; -}; - -class CreateAndSetHandler - : public webrtc::CreateSessionDescriptionObserver, - public webrtc::SetSessionDescriptionObserver { - public: - explicit CreateAndSetHandler( - rtc::scoped_refptr<PeerConnectionHolder> holder) - : holder_(holder) { - } - - void OnSuccess(webrtc::SessionDescriptionInterface* desc) override { - if (holder_->IsDisposed()) return; - - type_ = desc->type(); - if (desc->ToString(&description_)) { - holder_->connection()->SetLocalDescription(this, desc); - } else { - OnFailure("Can't serialize session description"); - } - } - - void OnSuccess() override { - if (holder_->IsDisposed()) return; - - if (type_ == webrtc::SessionDescriptionInterface::kOffer) { - holder_->delegate()->OnLocalOfferCreatedAndSetSet(description_); - } else { - DCHECK_EQ(webrtc::SessionDescriptionInterface::kAnswer, type_); - - holder_->delegate()->OnLocalAnswerCreatedAndSetSet(description_); - } - } - - void OnFailure(const std::string& error) override { - if (holder_->IsDisposed()) return; - - holder_->delegate()->OnFailure(error); - } - - private: - const rtc::scoped_refptr<PeerConnectionHolder> holder_; - std::string type_; - std::string description_; -}; - -class SetRemoteDescriptionHandler - : public webrtc::SetSessionDescriptionObserver { - public: - SetRemoteDescriptionHandler( - rtc::scoped_refptr<PeerConnectionHolder> holder) - : holder_(holder) { - } - - void OnSuccess() override { - if (holder_->IsDisposed()) return; - - holder_->delegate()->OnRemoteDescriptionSet(); - } - - void OnFailure(const std::string& error) override { - if (holder_->IsDisposed()) return; - - holder_->delegate()->OnFailure(error); - } - - private: - const rtc::scoped_refptr<PeerConnectionHolder> holder_; -}; - -class PeerConnectionImpl : public AbstractPeerConnection { - public: - PeerConnectionImpl( - SessionDependencyFactory* const factory, - rtc::Thread* signaling_thread, - rtc::scoped_refptr<webrtc::PeerConnectionInterface> connection, - scoped_ptr<PeerConnectionObserverImpl> observer, - scoped_ptr<AbstractPeerConnection::Delegate> delegate) - : factory_(factory), - holder_(new rtc::RefCountedObject<PeerConnectionHolder>( - signaling_thread, connection.get(), delegate.get())), - signaling_thread_(signaling_thread), - connection_(connection), - observer_(observer.Pass()), - delegate_(delegate.Pass()) { - } - - ~PeerConnectionImpl() override { - signaling_thread_->Invoke<void>(rtc::Bind( - &PeerConnectionImpl::DisposeOnSignalingThread, this)); - } - - void CreateAndSetLocalOffer() override { - connection_->CreateOffer(MakeCreateAndSetHandler(), NULL); - } - - void CreateAndSetLocalAnswer() override { - connection_->CreateAnswer(MakeCreateAndSetHandler(), NULL); - } - - void SetRemoteOffer(const std::string& description) override { - SetRemoteDescription( - webrtc::SessionDescriptionInterface::kOffer, description); - } - - void SetRemoteAnswer(const std::string& description) override { - SetRemoteDescription( - webrtc::SessionDescriptionInterface::kAnswer, description); - } - - void SetRemoteDescription( - const std::string& type, const std::string& description) { - webrtc::SdpParseError error; - scoped_ptr<webrtc::SessionDescriptionInterface> value( - webrtc::CreateSessionDescription(type, description, &error)); - if (value == NULL) { - OnParseError(error); - return; - } - // Takes ownership on |value|. - connection_->SetRemoteDescription( - new rtc::RefCountedObject<SetRemoteDescriptionHandler>(holder_), - value.release()); - } - - void AddIceCandidate(const std::string& sdp_mid, - int sdp_mline_index, - const std::string& sdp) override { - webrtc::SdpParseError error; - auto candidate = webrtc::CreateIceCandidate( - sdp_mid, sdp_mline_index, sdp, &error); - if (candidate == NULL) { - OnParseError(error); - return; - } - // Doesn't takes ownership. - connection_->AddIceCandidate(candidate); - delete candidate; - } - - scoped_ptr<AbstractDataChannel> CreateDataChannel(int channelId) override { - webrtc::DataChannelInit init; - init.ordered = true; - init.negotiated = true; - init.id = channelId; - - return make_scoped_ptr(new DataChannelImpl( - factory_, - signaling_thread_, - connection_->CreateDataChannel("", &init))); - } - - private: - webrtc::CreateSessionDescriptionObserver* MakeCreateAndSetHandler() { - return new rtc::RefCountedObject<CreateAndSetHandler>(holder_); - } - - void DisposeOnSignalingThread() { - DCHECK(signaling_thread_->IsCurrent()); - - CheckedRelease(&connection_); - holder_->Dispose(); - } - - void OnParseError(const webrtc::SdpParseError& error) { - // TODO(serya): Send on signaling thread. - } - - SessionDependencyFactory* const factory_; - const rtc::scoped_refptr<PeerConnectionHolder> holder_; - rtc::Thread* const signaling_thread_; - rtc::scoped_refptr<webrtc::PeerConnectionInterface> connection_; - const scoped_ptr<PeerConnectionObserverImpl> observer_; - const scoped_ptr<AbstractPeerConnection::Delegate> delegate_; -}; - -class SessionDependencyFactoryImpl : public SessionDependencyFactory { - public: - SessionDependencyFactoryImpl( - const base::Closure& cleanup_on_signaling_thread) - : cleanup_on_signaling_thread_(cleanup_on_signaling_thread) { - signaling_thread_.SetName("signaling_thread", NULL); - signaling_thread_.Start(); - worker_thread_.SetName("worker_thread", NULL); - worker_thread_.Start(); - - factory_ = webrtc::CreatePeerConnectionFactory( - &worker_thread_, &signaling_thread_, NULL, NULL, NULL); - } - - ~SessionDependencyFactoryImpl() override { - if (signaling_thread_task_runner_.get()) - signaling_thread_task_runner_->Stop(); - - signaling_thread_.Invoke<void>(rtc::Bind( - &SessionDependencyFactoryImpl::DisposeOnSignalingThread, this)); - } - - scoped_ptr<AbstractPeerConnection> CreatePeerConnection( - scoped_ptr<RTCConfiguration> config, - scoped_ptr<AbstractPeerConnection::Delegate> delegate) override { - auto observer = make_scoped_ptr( - new PeerConnectionObserverImpl(delegate.get())); - - MediaConstraints constraints; - constraints.AddMandatory( - MediaConstraints::kEnableDtlsSrtp, MediaConstraints::kValueTrue); - - auto connection = factory_->CreatePeerConnection( - config->impl(), &constraints, NULL, NULL, observer.get()); - - return make_scoped_ptr(new PeerConnectionImpl( - this, &signaling_thread_, connection, observer.Pass(), - delegate.Pass())); - } - - scoped_refptr<base::TaskRunner> signaling_thread_task_runner() override { - if (!signaling_thread_task_runner_.get()) { - signaling_thread_task_runner_ = - new SignalingThreadTaskRunner(&signaling_thread_); - } - return signaling_thread_task_runner_; - } - - scoped_refptr<base::TaskRunner> io_thread_task_runner() override { - if (!io_thread_.get()) { - io_thread_.reset(new base::Thread("devtools bridge IO thread")); - base::Thread::Options options; - options.message_loop_type = base::MessageLoop::TYPE_IO; - CHECK(io_thread_->StartWithOptions(options)); - } - return io_thread_->task_runner(); - } - - private: - void DisposeOnSignalingThread() { - DCHECK(signaling_thread_.IsCurrent()); - CheckedRelease(&factory_); - if (!cleanup_on_signaling_thread_.is_null()) - cleanup_on_signaling_thread_.Run(); - } - - scoped_ptr<base::Thread> io_thread_; - scoped_refptr<SignalingThreadTaskRunner> signaling_thread_task_runner_; - base::Closure cleanup_on_signaling_thread_; - rtc::Thread signaling_thread_; - rtc::Thread worker_thread_; - rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface> factory_; -}; - -} // namespace - -// RTCCOnfiguration - -// static -scoped_ptr<RTCConfiguration> RTCConfiguration::CreateInstance() { - return make_scoped_ptr(new RTCConfiguration::Impl()); -} - -// SessionDependencyFactory - -// static -bool SessionDependencyFactory::InitializeSSL() { - return rtc::InitializeSSL(); -} - -// static -bool SessionDependencyFactory::CleanupSSL() { - return rtc::CleanupSSL(); -} - -// static -scoped_ptr<SessionDependencyFactory> SessionDependencyFactory::CreateInstance( - const base::Closure& cleanup_on_signaling_thread) { - return make_scoped_ptr(new SessionDependencyFactoryImpl( - cleanup_on_signaling_thread)); -} - -} // namespace devtools_bridge
diff --git a/components/devtools_bridge/session_dependency_factory.h b/components/devtools_bridge/session_dependency_factory.h deleted file mode 100644 index 23d7b03..0000000 --- a/components/devtools_bridge/session_dependency_factory.h +++ /dev/null
@@ -1,49 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_DEVTOOLS_BRIDGE_SESSION_DEPENDENCY_FACTORY_H_ -#define COMPONENTS_DEVTOOLS_BRIDGE_SESSION_DEPENDENCY_FACTORY_H_ - -#include <string> - -#include "base/callback.h" -#include "base/memory/scoped_ptr.h" -#include "components/devtools_bridge/abstract_peer_connection.h" -#include "components/devtools_bridge/rtc_configuration.h" - -namespace base { -class TaskRunner; -} - -namespace devtools_bridge { - -/** - * Abstraction layer over WebRTC API used in DevTools Bridge. - * It helps to isolate ref counting and threading logic needed. - */ -class SessionDependencyFactory { - public: - SessionDependencyFactory() {} - virtual ~SessionDependencyFactory() {} - - static bool InitializeSSL(); - static bool CleanupSSL(); - - static scoped_ptr<SessionDependencyFactory> CreateInstance( - const base::Closure& cleanup_on_signaling_thread); - - virtual scoped_ptr<AbstractPeerConnection> CreatePeerConnection( - scoped_ptr<RTCConfiguration> config, - scoped_ptr<AbstractPeerConnection::Delegate> delegate) = 0; - - virtual scoped_refptr<base::TaskRunner> signaling_thread_task_runner() = 0; - virtual scoped_refptr<base::TaskRunner> io_thread_task_runner() = 0; - - private: - DISALLOW_COPY_AND_ASSIGN(SessionDependencyFactory); -}; - -} // namespace devtools_bridge - -#endif // COMPONENTS_DEVTOOLS_BRIDGE_SESSION_DEPENDENCY_FACTORY_H_
diff --git a/components/devtools_bridge/socket_tunnel_connection.cc b/components/devtools_bridge/socket_tunnel_connection.cc deleted file mode 100644 index 2c01aa2..0000000 --- a/components/devtools_bridge/socket_tunnel_connection.cc +++ /dev/null
@@ -1,96 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/devtools_bridge/socket_tunnel_connection.h" - -#include <stdlib.h> - -#include "net/base/io_buffer.h" -#include "net/base/net_errors.h" -#include "net/socket/stream_socket.h" - -namespace devtools_bridge { - -SocketTunnelConnection::SocketTunnelConnection(int index) : index_(index) { -} - -SocketTunnelConnection::~SocketTunnelConnection() { -} - -void SocketTunnelConnection::Write(scoped_refptr<net::IOBufferWithSize> chunk) { - // TODO(serya): While it is unlikely (socket normally much faster than - // data channel) we should disconnect if too much data buffered. - buffer_.push_back(chunk); - if (buffer_.size() == 1) { - current_ = new net::DrainableIOBuffer(chunk.get(), chunk->size()); - WriteCurrent(); - } -} - -void SocketTunnelConnection::BuildControlPacket(char* buffer, - int op_code) { - static_assert(kControlPacketSizeBytes == 3, - "kControlPacketSizeBytes should equal 3"); - buffer[0] = kControlConnectionId; - buffer[1] = op_code; - buffer[2] = index_ + kMinConnectionId; -} - -void SocketTunnelConnection::WriteCurrent() { - while (true) { - while(current_->BytesRemaining() > 0) { - int result = socket()->Write(current_.get(), current_->BytesRemaining(), - base::Bind(&SocketTunnelConnection::OnWriteComplete, - base::Unretained(this))); - if (result > 0) - current_->DidConsume(result); - } - current_ = NULL; - - buffer_.pop_front(); - if (buffer_.empty()) - return; // Stop writing. - - net::IOBufferWithSize* chunk = buffer_.front().get(); - current_ = new net::DrainableIOBuffer(chunk, chunk->size()); - } -} - -void SocketTunnelConnection::OnWriteComplete(int result) { - if (result > 0) { - current_->DidConsume(result); - WriteCurrent(); - } -} - -void SocketTunnelConnection::ReadNextChunk() { - if (!read_buffer_.get()) { - read_buffer_ = new net::GrowableIOBuffer(); - read_buffer_->SetCapacity(kMaxPacketSizeBytes); - } - // Header of the data packet. - *read_buffer_->StartOfBuffer() = index_ + kMinConnectionId; - read_buffer_->set_offset(1); - - int result = socket()->Read( - read_buffer_.get(), - read_buffer_->RemainingCapacity(), - base::Bind(&SocketTunnelConnection::OnReadComplete, - base::Unretained(this))); - if (result == net::ERR_IO_PENDING) - return; - else - OnReadComplete(result); -} - -void SocketTunnelConnection::OnReadComplete(int result) { - if (result > 0) { - OnDataPacketRead(read_buffer_->StartOfBuffer(), - read_buffer_->offset() + result); - } else { - OnReadError(result); - } -} - -} // namespace devtools_bridge
diff --git a/components/devtools_bridge/socket_tunnel_connection.h b/components/devtools_bridge/socket_tunnel_connection.h deleted file mode 100644 index c6638926..0000000 --- a/components/devtools_bridge/socket_tunnel_connection.h +++ /dev/null
@@ -1,99 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_DEVTOOLS_BRIDGE_SOCKET_TUNNEL_CONNECTION_H_ -#define COMPONENTS_DEVTOOLS_BRIDGE_SOCKET_TUNNEL_CONNECTION_H_ - -#include <deque> -#include <string> - -#include "base/memory/ref_counted.h" -#include "base/memory/scoped_ptr.h" - -namespace net { -class DrainableIOBuffer; -class GrowableIOBuffer; -class IOBufferWithSize; -class StreamSocket; -} - -namespace devtools_bridge { - -/** - * Abstract base class for SocketTunnelServer/Client connection. - * - * Connection binds a pair of net::StreamSocket (or alike) through - * a data channel. SocketTunnel may handle up to kMaxConnectionCount - * simultaneous connection (DevTools can keep ~10 connection; - * other connections hang in unopened state; additional connections - * could help to deal with data channel latency). - * - * Client should create net::StreamListenSocket (or logical equivalent) - * and listen for incoming connection. When one comes it sends CLIENT_OPEN - * packet to the server. - * - * Server transforms client's packet to calls of net::StreamSocket. On - * CLIENT_OPEN it creates a socket and connects. If connection succeeds - * it sends back SERVER_OPEN_ACK. If it fails it sends SERVER_CLOSE. - * - * After SERVER_OPEN_ACK server may send SERVER_CLOSE any time (if the socket - * it connects to has closed on another side). If client closes the connection - * sending CLIENT_CLOSE server acknowledges it by sending SERVER_CLOSE. - * Client may reuse connection ID once it received SERVER_CLOSE (because - * data channel is ordered and reliable). - */ -class SocketTunnelConnection { - public: - enum ClientOpCode { - CLIENT_OPEN = 0, - CLIENT_CLOSE = 1 - }; - - enum ServerOpCode { - SERVER_OPEN_ACK = 0, - SERVER_CLOSE = 1 - }; - - static const int kMaxConnectionCount = 64; - - static const int kMaxPacketSizeBytes = 1024 * 4; - static const int kControlPacketSizeBytes = 3; - - static const int kControlConnectionId = 0; - - static const int kMinConnectionId = 1; - static const int kMaxConnectionId = - kMinConnectionId + kMaxConnectionCount - 1; - - void Write(scoped_refptr<net::IOBufferWithSize> chunk); - void ReadNextChunk(); - - protected: - SocketTunnelConnection(int index); - ~SocketTunnelConnection(); - - const int index_; - - // |buffer| length must be kControlPacketSizeBytes. - void BuildControlPacket(char* buffer, int op_code); - - virtual net::StreamSocket* socket() = 0; - virtual void OnDataPacketRead(const void* data, size_t length) = 0; - virtual void OnReadError(int error) = 0; - - private: - void WriteCurrent(); - void OnWriteComplete(int result); - void OnReadComplete(int result); - - std::deque<scoped_refptr<net::IOBufferWithSize> > buffer_; - scoped_refptr<net::DrainableIOBuffer> current_; - scoped_refptr<net::GrowableIOBuffer> read_buffer_; - - DISALLOW_COPY_AND_ASSIGN(SocketTunnelConnection); -}; - -} // namespace devtools_bridge - -#endif // COMPONENTS_DEVTOOLS_BRIDGE_SOCKET_TUNNEL_CONNECTION_H_
diff --git a/components/devtools_bridge/socket_tunnel_packet_handler.cc b/components/devtools_bridge/socket_tunnel_packet_handler.cc deleted file mode 100644 index ea609ae..0000000 --- a/components/devtools_bridge/socket_tunnel_packet_handler.cc +++ /dev/null
@@ -1,64 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/devtools_bridge/socket_tunnel_packet_handler.h" - -#include <stdlib.h> - -#include "components/devtools_bridge/socket_tunnel_connection.h" -#include "net/base/io_buffer.h" -#include "net/base/net_errors.h" - -namespace devtools_bridge { - -static const int kControlConnectionId = - SocketTunnelConnection::kControlConnectionId; -static const int kMinConnectionId = SocketTunnelConnection::kMinConnectionId; -static const int kMaxConnectionId = SocketTunnelConnection::kMaxConnectionId; -static const int kControlPacketSizeBytes = - SocketTunnelConnection::kControlPacketSizeBytes; - -void SocketTunnelPacketHandler::DecodePacket(const void* data, size_t length) { - const unsigned char* bytes = static_cast<const unsigned char*>(data); - if (length == 0) { - DLOG(ERROR) << "Empty packet"; - HandleProtocolError(); - return; - } - int connection_id = bytes[0]; - if (connection_id != kControlConnectionId) { - if (connection_id < kMinConnectionId || - connection_id > kMaxConnectionId) { - DLOG(ERROR) << "Invalid connection ID: " << connection_id; - HandleProtocolError(); - return; - } - - int connection_index = connection_id - kMinConnectionId; - scoped_refptr<net::IOBufferWithSize> packet( - new net::IOBufferWithSize(length - 1)); - memcpy(packet->data(), bytes + 1, length - 1); - HandleDataPacket(connection_index, packet); - } else if (length >= kControlPacketSizeBytes) { - static_assert(kControlPacketSizeBytes == 3, - "kControlPacketSizeBytes should equal 3"); - - int op_code = bytes[1]; - connection_id = bytes[2]; - if (connection_id < kMinConnectionId || - connection_id > kMaxConnectionId) { - DLOG(ERROR) << "Invalid connection ID: " << connection_id; - HandleProtocolError(); - return; - } - int connection_index = connection_id - kMinConnectionId; - HandleControlPacket(connection_index, op_code); - } else { - DLOG(ERROR) << "Invalid packet"; - HandleProtocolError(); - return; - } -} - -} // namespace devtools_bridge
diff --git a/components/devtools_bridge/socket_tunnel_packet_handler.h b/components/devtools_bridge/socket_tunnel_packet_handler.h deleted file mode 100644 index dc64f30..0000000 --- a/components/devtools_bridge/socket_tunnel_packet_handler.h +++ /dev/null
@@ -1,37 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_DEVTOOLS_BRIDGE_SOCKET_TUNNEL_PACKET_HANDLER_H_ -#define COMPONENTS_DEVTOOLS_BRIDGE_SOCKET_TUNNEL_PACKET_HANDLER_H_ - -#include "base/memory/ref_counted.h" - -namespace net { -class IOBufferWithSize; -} - -namespace devtools_bridge { - -/** - * Abstract base class for handling SocketTunnelServer/Client messages. - */ -class SocketTunnelPacketHandler { - public: - virtual void HandleControlPacket(int connection_index, int op_code) = 0; - virtual void HandleDataPacket( - int connection_index, scoped_refptr<net::IOBufferWithSize> data) = 0; - virtual void HandleProtocolError() = 0; - - void DecodePacket(const void* data, size_t length); - - protected: - SocketTunnelPacketHandler() {} - - private: - DISALLOW_COPY_AND_ASSIGN(SocketTunnelPacketHandler); -}; - -} // namespace devtools_bridge - -#endif // COMPONENTS_DEVTOOLS_BRIDGE_SOCKET_TUNNEL_PACKET_HANDLER_H_
diff --git a/components/devtools_bridge/socket_tunnel_server.cc b/components/devtools_bridge/socket_tunnel_server.cc deleted file mode 100644 index afa07a2..0000000 --- a/components/devtools_bridge/socket_tunnel_server.cc +++ /dev/null
@@ -1,266 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/devtools_bridge/socket_tunnel_server.h" - -#include "base/bind.h" -#include "base/location.h" -#include "components/devtools_bridge/abstract_data_channel.h" -#include "components/devtools_bridge/session_dependency_factory.h" -#include "components/devtools_bridge/socket_tunnel_connection.h" -#include "components/devtools_bridge/socket_tunnel_packet_handler.h" -#include "net/base/io_buffer.h" -#include "net/base/net_errors.h" -#include "net/socket/unix_domain_client_socket_posix.h" - -namespace devtools_bridge { - -class SocketTunnelServer::Connection : public SocketTunnelConnection { - public: - class Delegate { - public: - virtual void RemoveConnection(int index) = 0; - virtual void SendPacket( - const void* data, size_t length) = 0; - }; - - Connection(Delegate* delegate, int index, const std::string& socket_name) - : SocketTunnelConnection(index), - delegate_(delegate), - socket_(socket_name, true) { - } - - void Connect() { - int result = socket()->Connect(base::Bind( - &Connection::OnConnectionComplete, base::Unretained(this))); - if (result != net::ERR_IO_PENDING) - OnConnectionComplete(result); - } - - void ClosedByClient() { - if (socket()->IsConnected()) { - socket()->Disconnect(); - SendControlPacket(SERVER_CLOSE); - } - delegate_->RemoveConnection(index_); - } - - protected: - net::StreamSocket* socket() override { - return &socket_; - } - - void OnDataPacketRead(const void* data, size_t length) override { - delegate_->SendPacket(data, length); - ReadNextChunk(); - } - - void OnReadError(int error) override { - socket()->Disconnect(); - SendControlPacket(SERVER_CLOSE); - delegate_->RemoveConnection(index_); - delegate_ = NULL; - } - - private: - void OnConnectionComplete(int result) { - if (result == net::OK) { - SendControlPacket(SERVER_OPEN_ACK); - ReadNextChunk(); - } else { - SendControlPacket(SERVER_CLOSE); - delegate_->RemoveConnection(index_); - delegate_ = NULL; - } - } - - void SendControlPacket(ServerOpCode op_code) { - char buffer[kControlPacketSizeBytes]; - BuildControlPacket(buffer, op_code); - delegate_->SendPacket(buffer, kControlPacketSizeBytes); - } - - Delegate* delegate_; - net::UnixDomainClientSocket socket_; -}; - -/** - * Lives on the IO thread. - */ -class SocketTunnelServer::ConnectionController - : private Connection::Delegate { - public: - ConnectionController( - scoped_refptr<base::TaskRunner> io_task_runner, - scoped_refptr<AbstractDataChannel::Proxy> data_channel, - const std::string& socket_name) - : io_task_runner_(io_task_runner), - data_channel_(data_channel), - socket_name_(socket_name) { - DCHECK(data_channel_.get()); - } - - void HandleControlPacket(int connection_index, int op_code) { - DCHECK(connection_index < kMaxConnectionCount); - switch (op_code) { - case SocketTunnelConnection::CLIENT_OPEN: - if (connections_[connection_index].get() != NULL) { - DLOG(ERROR) << "Opening connection which already open: " - << connection_index; - HandleProtocolError(); - return; - } - connections_[connection_index].reset( - new Connection(this, connection_index, socket_name_)); - connections_[connection_index]->Connect(); - break; - - case SocketTunnelConnection::CLIENT_CLOSE: - if (connections_[connection_index].get() == NULL) { - // Ignore. Client may close the connection before received - // notification from the server. - return; - } - connections_[connection_index]->ClosedByClient(); - break; - - default: - DLOG(ERROR) << "Invalid op_code: " << op_code; - HandleProtocolError(); - return; - } - } - - void HandleDataPacket(int connection_index, - scoped_refptr<net::IOBufferWithSize> packet) { - Connection* connection = connections_[connection_index].get(); - if (connection != NULL) - connection->Write(packet); - } - - void HandleProtocolError() { - data_channel_->Close(); - } - - void CloseAllConnections() { - for (int i = 0; i < kMaxConnectionCount; i++) { - connections_[i].reset(); - } - } - - private: - static void DeleteConnectionImpl(Connection*) {} - - // Connection::Delegate implementation - void RemoveConnection(int connection_index) override { - // Remove immediately, delete later to preserve this of the caller. - Connection* connection = connections_[connection_index].release(); - io_task_runner_->PostTask( - FROM_HERE, base::Bind(&ConnectionController::DeleteConnectionImpl, - base::Owned(connection))); - } - - void SendPacket(const void* data, size_t length) override { - data_channel_->SendBinaryMessage(data, length); - } - - static const int kMaxConnectionCount = - SocketTunnelConnection::kMaxConnectionCount; - - scoped_refptr<base::TaskRunner> io_task_runner_; - scoped_refptr<AbstractDataChannel::Proxy> data_channel_; - scoped_ptr<Connection> connections_[kMaxConnectionCount]; - const std::string socket_name_; -}; - -class SocketTunnelServer::DataChannelObserver - : public AbstractDataChannel::Observer, - private SocketTunnelPacketHandler { - public: - DataChannelObserver(scoped_refptr<base::TaskRunner> io_task_runner, - scoped_ptr<ConnectionController> controller) - : io_task_runner_(io_task_runner), - controller_(controller.Pass()) { - } - - ~DataChannelObserver() override { - // Deleting on IO thread allows post tasks with base::Unretained - // because all of them will be processed before deletion. - io_task_runner_->PostTask( - FROM_HERE, base::Bind(&DataChannelObserver::DeleteControllerOnIOThread, - base::Passed(&controller_))); - } - - void OnOpen() override { - // Nothing to do. Activity could only be initiated by a control packet. - } - - void OnClose() override { - io_task_runner_->PostTask( - FROM_HERE, base::Bind( - &ConnectionController::CloseAllConnections, - base::Unretained(controller_.get()))); - } - - void OnMessage(const void* data, size_t length) override { - DecodePacket(data, length); - } - - private: - static void DeleteControllerOnIOThread( - scoped_ptr<ConnectionController> controller) {} - - // SocketTunnelPacketHandler implementation. - - void HandleControlPacket(int connection_index, int op_code) override { - io_task_runner_->PostTask( - FROM_HERE, base::Bind( - &ConnectionController::HandleControlPacket, - base::Unretained(controller_.get()), - connection_index, - op_code)); - } - - void HandleDataPacket(int connection_index, - scoped_refptr<net::IOBufferWithSize> data) override { - io_task_runner_->PostTask( - FROM_HERE, base::Bind( - &ConnectionController::HandleDataPacket, - base::Unretained(controller_.get()), - connection_index, - data)); - } - - void HandleProtocolError() override { - io_task_runner_->PostTask( - FROM_HERE, base::Bind( - &ConnectionController::HandleProtocolError, - base::Unretained(controller_.get()))); - } - - const scoped_refptr<base::TaskRunner> io_task_runner_; - scoped_ptr<ConnectionController> controller_; -}; - -SocketTunnelServer::SocketTunnelServer(SessionDependencyFactory* factory, - AbstractDataChannel* data_channel, - const std::string& socket_name) - : data_channel_(data_channel) { - scoped_ptr<ConnectionController> controller( - new ConnectionController(factory->io_thread_task_runner(), - data_channel->proxy(), - socket_name)); - - scoped_ptr<DataChannelObserver> data_channel_observer( - new DataChannelObserver(factory->io_thread_task_runner(), - controller.Pass())); - - data_channel_->RegisterObserver(data_channel_observer.Pass()); -} - -SocketTunnelServer::~SocketTunnelServer() { - data_channel_->UnregisterObserver(); -} - -} // namespace devtools_bridge
diff --git a/components/devtools_bridge/socket_tunnel_server.h b/components/devtools_bridge/socket_tunnel_server.h deleted file mode 100644 index 1dd3f4c..0000000 --- a/components/devtools_bridge/socket_tunnel_server.h +++ /dev/null
@@ -1,41 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_DEVTOOLS_BRIDGE_SOCKET_TUNNEL_SERVER_H_ -#define COMPONENTS_DEVTOOLS_BRIDGE_SOCKET_TUNNEL_SERVER_H_ - -#include <map> -#include <string> - -#include "base/memory/scoped_ptr.h" - -namespace net { -class StreamSocket; -} - -namespace devtools_bridge { - -class AbstractDataChannel; -class SessionDependencyFactory; - -class SocketTunnelServer { - public: - SocketTunnelServer(SessionDependencyFactory* factory, - AbstractDataChannel* data_channel, - const std::string& socket_name); - ~SocketTunnelServer(); - - private: - class Connection; - class ConnectionController; - class DataChannelObserver; - - AbstractDataChannel* const data_channel_; - - DISALLOW_COPY_AND_ASSIGN(SocketTunnelServer); -}; - -} // namespace devtools_bridge - -#endif // COMPONENTS_DEVTOOLS_BRIDGE_SOCKET_TUNNEL_SERVER_H_
diff --git a/components/devtools_bridge/test/android/javatests/jni/jni_onload.cc b/components/devtools_bridge/test/android/javatests/jni/jni_onload.cc deleted file mode 100644 index 4238dec..0000000 --- a/components/devtools_bridge/test/android/javatests/jni/jni_onload.cc +++ /dev/null
@@ -1,38 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/android/base_jni_onload.h" -#include "base/android/base_jni_registrar.h" -#include "base/android/jni_android.h" -#include "base/bind.h" -#include "components/devtools_bridge/android/apiary_client_factory.h" -#include "components/devtools_bridge/android/session_dependency_factory_android.h" - -namespace { - -using namespace devtools_bridge::android; - -bool RegisterJNI(JNIEnv* env) { - return base::android::RegisterJni(env) && - SessionDependencyFactoryAndroid::RegisterNatives(env) && - ApiaryClientFactory::RegisterNatives(env); -} - -bool Init() { - return devtools_bridge::SessionDependencyFactory::InitializeSSL(); -} - -} // namespace - -JNI_EXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) { - std::vector<base::android::RegisterCallback> register_callbacks; - register_callbacks.push_back(base::Bind(&RegisterJNI)); - std::vector<base::android::InitCallback> init_callbacks; - init_callbacks.push_back(base::Bind(&Init)); - if (!base::android::OnJNIOnLoadRegisterJNI(vm, register_callbacks) || - !base::android::OnJNIOnLoadInit(init_callbacks)) { - return -1; - } - return JNI_VERSION_1_4; -}
diff --git a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/ClientSession.java b/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/ClientSession.java deleted file mode 100644 index dfc16484..0000000 --- a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/ClientSession.java +++ /dev/null
@@ -1,248 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.components.devtools_bridge; - -import java.io.IOException; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * Client session. Creates client socket tunnel for clientSocketName as a default tunnel. - * See SessionBase for details. - */ -public class ClientSession extends SessionBase { - private final ServerSessionInterface mServer; - private RTCConfiguration mConfig; - private Cancellable mIceExchangeTask; - private boolean mIceExchangeRequested = false; - private IceExchangeHandler mPendingIceExchangeRequest; - - private int mExchangeDelayMs = -1; - - protected int mInitialIceExchangeDelayMs = 200; - protected int mMaxIceExchangeDelayMs = 5000; - - private final Map<Integer, SocketTunnelClient> mPendingTunnel = - new HashMap<Integer, SocketTunnelClient>(); - - public ClientSession(SessionDependencyFactory factory, - Executor executor, - ServerSessionInterface server, - String clientSocketName) throws IOException { - super(factory, executor, new SocketTunnelClient(clientSocketName)); - mServer = server; - } - - public void start(RTCConfiguration config) { - checkCalledOnSessionThread(); - - super.start(config, new ServerMessageHandler()); - mConfig = config; - - for (Map.Entry<Integer, SocketTunnelClient> entry : mPendingTunnel.entrySet()) { - int channelId = entry.getKey(); - entry.getValue().bind(connection().createDataChannel(channelId)); - } - - connection().createAndSetLocalDescription( - AbstractPeerConnection.SessionDescriptionType.OFFER); - } - - @Override - public void stop() { - for (SocketTunnelClient tunnel : mPendingTunnel.values()) - tunnel.unbind().dispose(); - - if (mIceExchangeTask != null) - mIceExchangeTask.cancel(); - - super.stop(); - } - - @Override - protected void onLocalDescriptionCreatedAndSet( - AbstractPeerConnection.SessionDescriptionType type, String offer) { - assert type == AbstractPeerConnection.SessionDescriptionType.OFFER; - mServer.startSession(mConfig, offer, new CreateSessionHandler()); - mConfig = null; - } - - private void onAnswerReceived(String answer) { - connection().setRemoteDescription( - AbstractPeerConnection.SessionDescriptionType.ANSWER, answer); - } - - @Override - protected void onRemoteDescriptionSet() { - onSessionNegotiated(); - } - - protected void onSessionNegotiated() { - assert !isIceExchangeStarted(); - updateIceExchangeStatus(); - assert isIceExchangeStarted(); - } - - @Override - protected void onControlChannelOpened() { - assert isIceExchangeStarted(); - updateIceExchangeStatus(); - } - - @Override - protected void onIceConnectionChange() { - super.onIceConnectionChange(); - updateIceExchangeStatus(); - } - - private void updateIceExchangeStatus() { - boolean needed = !isConnected() || !isControlChannelOpened(); - if (needed == isIceExchangeStarted()) - return; - if (needed) - startIceExchange(); - else - stopIceExchange(); - } - - private boolean isIceExchangeStarted() { - return mExchangeDelayMs >= 0; - } - - private void startIceExchange() { - assert !isIceExchangeStarted(); - mExchangeDelayMs = mInitialIceExchangeDelayMs; - startAutoCloseTimer(); - - if (!isIceExchangeScheduledOrPending()) { - scheduleIceExchange(mExchangeDelayMs); - } - - assert isIceExchangeScheduledOrPending(); - assert isIceExchangeStarted(); - } - - private void stopIceExchange() { - assert isIceExchangeStarted(); - mExchangeDelayMs = -1; - stopAutoCloseTimer(); - - // Last exchange will happen, not more will be scheduled (unless mIceExchangeRequested). - assert isIceExchangeScheduledOrPending(); - assert !isIceExchangeStarted(); - } - - private void scheduleIceExchange(int delay) { - assert mIceExchangeTask == null; - mIceExchangeTask = postOnSessionThread(delay, new Runnable() { - @Override - public void run() { - mIceExchangeTask = null; - - mServer.iceExchange(takeIceCandidates(), new IceExchangeHandler()); - mIceExchangeRequested = false; - } - }); - } - - private boolean isIceExchangeScheduledOrPending() { - return mIceExchangeTask != null || mPendingIceExchangeRequest != null; - } - - private void onServerCandidates(List<String> serverCandidates) { - addIceCandidates(serverCandidates); - - if (isIceExchangeStarted()) { - mExchangeDelayMs *= 2; - if (mExchangeDelayMs > mMaxIceExchangeDelayMs) { - mExchangeDelayMs = mMaxIceExchangeDelayMs; - } - - scheduleIceExchange(mExchangeDelayMs); - } else if (mIceExchangeRequested) { - scheduleIceExchange(mInitialIceExchangeDelayMs); - } - } - - /** - * Queries single ICE eqchange cycle regardless of ICE exchange process. - */ - private void queryIceExchange() { - mIceExchangeRequested = true; - if (mIceExchangeTask == null && mPendingIceExchangeRequest != null) { - assert !isIceExchangeStarted(); - scheduleIceExchange(mInitialIceExchangeDelayMs); - } - } - - private final class CreateSessionHandler implements NegotiationCallback { - @Override - public void onSuccess(String answer) { - checkCalledOnSessionThread(); - - onAnswerReceived(answer); - } - - @Override - public void onFailure(String message) { - checkCalledOnSessionThread(); - - ClientSession.this.onFailure(message); - } - } - - private final class IceExchangeHandler implements IceExchangeCallback { - public IceExchangeHandler() { - assert mPendingIceExchangeRequest == null; - mPendingIceExchangeRequest = this; - } - - @Override - public void onSuccess(List<String> serverCandidates) { - checkCalledOnSessionThread(); - - mPendingIceExchangeRequest = null; - if (isStarted()) { - onServerCandidates(serverCandidates); - } - } - - @Override - public void onFailure(String message) { - checkCalledOnSessionThread(); - - mPendingIceExchangeRequest = null; - if (isStarted()) { - ClientSession.this.onFailure(message); - } - } - } - - private final class ServerMessageHandler extends SessionControlMessages.ServerMessageHandler { - @Override - protected void onMessage(SessionControlMessages.ServerMessage message) { - switch (message.type) { - case ICE_EXCHANGE: - queryIceExchange(); - break; - - case UNKNOWN_RESPONSE: - onUnknownResponse((SessionControlMessages.UnknownResponseMessage) message); - break; - } - } - } - - private void onUnknownResponse(SessionControlMessages.UnknownResponseMessage message) { - // TODO(serya): Handle server version incompatibility. - } - - @Override - protected void sendControlMessage(SessionControlMessages.Message<?> message) { - assert message instanceof SessionControlMessages.ClientMessage; - super.sendControlMessage(message); - } -}
diff --git a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/ClientSessionTestingHost.java b/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/ClientSessionTestingHost.java deleted file mode 100644 index 441353a8..0000000 --- a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/ClientSessionTestingHost.java +++ /dev/null
@@ -1,91 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.components.devtools_bridge; - -import android.util.Log; - -import java.io.IOException; - -/** - * Helper class which handles a client session in tests. Having direct reference to - * the server it runs its client session on a dedicated thread and proxies all call - * between them to satisfy theading requirements. - */ -public class ClientSessionTestingHost { - private static final String TAG = "ClientSessionTestingHost"; - - private final SignalingReceiver mTarget; - private final SessionBase.Executor mTargetExecutor; - private final LocalSessionBridge.ThreadedExecutor mClientExecutor; - private final String mSessionId; - private final ClientSession mClientSession; - - public ClientSessionTestingHost( - SessionDependencyFactory factory, - SignalingReceiver target, SessionBase.Executor targetExecutor, - String sessionId, String clientSocketName) - throws IOException { - mTarget = target; - mTargetExecutor = targetExecutor; - mClientExecutor = new LocalSessionBridge.ThreadedExecutor(); - - mSessionId = sessionId; - - SignalingReceiverProxy proxy = new SignalingReceiverProxy( - mTargetExecutor, mClientExecutor, target, 0); - - mClientSession = new ClientSession( - factory, - mClientExecutor, - proxy.asServerSession(mSessionId), - clientSocketName) { - @Override - protected void closeSelf() { - Log.d(TAG, "Closed self"); - super.closeSelf(); - } - - @Override - protected void onControlChannelOpened() { - Log.d(TAG, "Control channel opened"); - super.onControlChannelOpened(); - } - - @Override - protected void onControlChannelClosed() { - Log.d(TAG, "Control channel closed"); - super.onControlChannelClosed(); - } - - @Override - protected void onFailure(String message) { - Log.e(TAG, "Failure: " + message); - super.onFailure(message); - } - }; - } - - public void dispose() { - mClientExecutor.runSynchronously(new Runnable() { - @Override - public void run() { - mClientSession.dispose(); - } - }); - } - - public void start() { - start(new RTCConfiguration()); - } - - public void start(final RTCConfiguration config) { - mClientExecutor.runSynchronously(new Runnable() { - @Override - public void run() { - mClientSession.start(config); - } - }); - } -}
diff --git a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/DataChannelMock.java b/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/DataChannelMock.java deleted file mode 100644 index 59a1679..0000000 --- a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/DataChannelMock.java +++ /dev/null
@@ -1,135 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.components.devtools_bridge; - -import junit.framework.Assert; - -import java.nio.ByteBuffer; -import java.util.concurrent.LinkedBlockingQueue; - -/** - * Mock of AbstractDataChannel tests. Also base class for DataPipe channels. - */ -public class DataChannelMock extends AbstractDataChannel { - private final SignalingThreadMock mSignalingThread; - private Observer mObserver; - private boolean mOpen = false; - private final LinkedBlockingQueue<ByteBuffer> mQueue = new LinkedBlockingQueue<ByteBuffer>(); - - // |signalingThread| will be disposed in the |dispose| method. If successor needs - // to control it's lifetime it must override |disposeSignalingThread| and not to invoke super's - // implementation. - protected DataChannelMock(SignalingThreadMock signalingThread) { - mSignalingThread = signalingThread; - } - - public DataChannelMock() { - this(new SignalingThreadMock()); - } - - public void open() { - onStateChange(AbstractDataChannel.State.OPEN); - } - - @Override - public void close() { - onStateChange(AbstractDataChannel.State.CLOSED); - } - - private void onStateChange(final State state) { - mSignalingThread.invoke(new Runnable() { - @Override - public void run() { - mObserver.onStateChange(state); - } - }); - } - - // Sends onMessage to the observer. - public void notifyMessage(ByteBuffer data) { - final byte[] bytes = toByteArray(data); - mSignalingThread.invoke(new Runnable() { - @Override - public void run() { - notifyMessageOnSignalingThread(ByteBuffer.wrap(bytes)); - } - }); - } - - protected void notifyMessageOnSignalingThread(ByteBuffer buffer) { - mObserver.onMessage(buffer); - } - - // Blocks until message received. Removes it from the queue and returns. - public ByteBuffer receive() { - try { - return mQueue.take(); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - } - - @Override - public void registerObserver(final Observer observer) { - mSignalingThread.invoke(new Runnable() { - @Override - public void run() { - Assert.assertNull(mObserver); - mObserver = observer; - Assert.assertNotNull(mObserver); - } - }); - } - - @Override - public void unregisterObserver() { - mSignalingThread.invoke(new Runnable() { - @Override - public void run() { - Assert.assertNotNull(mObserver); - mObserver = null; - } - }); - } - - private byte[] toByteArray(ByteBuffer data) { - final byte[] result = new byte[data.remaining()]; - data.get(result); - return result; - } - - @Override - public void send(ByteBuffer message, MessageType type) { - final byte[] data = toByteArray(message); - assert data.length > 0; - mSignalingThread.post(new Runnable() { - @Override - public void run() { - sendOnSignalingThread(ByteBuffer.wrap(data)); - android.util.Log.d("DataChannelMock", "Packet sent."); - } - }); - } - - protected void sendOnSignalingThread(ByteBuffer message) { - boolean success = mQueue.offer(message); - assert success; - } - - @Override - public void dispose() { - mSignalingThread.invoke(new Runnable() { - @Override - public void run() { - Assert.assertNull(mObserver); - } - }); - disposeSignalingThread(); - } - - protected void disposeSignalingThread() { - mSignalingThread.dispose(); - } -}
diff --git a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/DataChannelObserverMock.java b/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/DataChannelObserverMock.java deleted file mode 100644 index 68972da..0000000 --- a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/DataChannelObserverMock.java +++ /dev/null
@@ -1,36 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.components.devtools_bridge; - -import java.nio.ByteBuffer; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.LinkedBlockingDeque; - -/** - * Mock for AbstractDataChannel.Observer. - */ -public class DataChannelObserverMock implements AbstractDataChannel.Observer { - public final CountDownLatch opened = new CountDownLatch(1); - public final CountDownLatch closed = new CountDownLatch(1); - public final LinkedBlockingDeque<byte[]> received = new LinkedBlockingDeque<byte[]>(); - - public void onStateChange(AbstractDataChannel.State state) { - switch (state) { - case OPEN: - opened.countDown(); - break; - - case CLOSED: - closed.countDown(); - break; - } - } - - public void onMessage(ByteBuffer message) { - byte[] bytes = new byte[message.remaining()]; - message.get(bytes); - received.add(bytes); - } -}
diff --git a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/DataPipe.java b/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/DataPipe.java deleted file mode 100644 index 7283047..0000000 --- a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/DataPipe.java +++ /dev/null
@@ -1,120 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.components.devtools_bridge; - -import java.nio.ByteBuffer; - -/** - * Represents a pair of connected AbstractDataChannel's. Sends to one channel - * come to another and vice versa. - */ -public class DataPipe { - private static final int DATA_CHANNEL_ID = 0; - - final PeerConnectionObserverMock mObserver1 = new PeerConnectionObserverMock(); - final PeerConnectionObserverMock mObserver2 = new PeerConnectionObserverMock(); - - DataChannelObserverMock mDataChannelObserverMock1 = new DataChannelObserverMock(); - DataChannelObserverMock mDataChannelObserverMock2 = new DataChannelObserverMock(); - - final AbstractPeerConnection mConnection1; - final AbstractPeerConnection mConnection2; - - final AbstractDataChannel mDataChannel1; - final AbstractDataChannel mDataChannel2; - - DataPipe(SessionDependencyFactory factory) { - RTCConfiguration config = new RTCConfiguration(); - mConnection1 = factory.createPeerConnection(config, mObserver1); - mConnection2 = factory.createPeerConnection(config, mObserver2); - - mObserver1.iceCandidatesSink = mConnection2; - mObserver2.iceCandidatesSink = mConnection1; - - mDataChannel1 = mConnection1.createDataChannel(DATA_CHANNEL_ID); - mDataChannel2 = mConnection2.createDataChannel(DATA_CHANNEL_ID); - } - - void dispose() { - mDataChannel1.dispose(); - mDataChannel2.dispose(); - mConnection1.dispose(); - mConnection2.dispose(); - } - - void negotiate() throws Exception { - mConnection1.createAndSetLocalDescription( - AbstractPeerConnection.SessionDescriptionType.OFFER); - mObserver1.localDescriptionAvailable.await(); - - mConnection2.setRemoteDescription( - AbstractPeerConnection.SessionDescriptionType.OFFER, - mObserver1.localDescription); - mObserver2.remoteDescriptionSet.await(); - - mConnection2.createAndSetLocalDescription( - AbstractPeerConnection.SessionDescriptionType.ANSWER); - mObserver2.localDescriptionAvailable.await(); - - mConnection1.setRemoteDescription( - AbstractPeerConnection.SessionDescriptionType.ANSWER, - mObserver2.localDescription); - mObserver1.remoteDescriptionSet.await(); - } - - void awaitConnected() throws Exception { - mObserver1.connected.await(); - mObserver2.connected.await(); - } - - void send(int channelIndex, String data) { - byte[] bytes = data.getBytes(); - ByteBuffer rawMessage = ByteBuffer.allocateDirect(bytes.length); - rawMessage.put(bytes); - rawMessage.limit(rawMessage.position()); - rawMessage.position(0); - dataChannel(channelIndex).send(rawMessage, AbstractDataChannel.MessageType.TEXT); - } - - void send(int channelIndex, ByteBuffer rawMessage) { - dataChannel(channelIndex).send(rawMessage, AbstractDataChannel.MessageType.BINARY); - } - - AbstractDataChannel dataChannel(int channelIndex) { - switch (channelIndex) { - case 0: - return mDataChannel1; - - case 1: - return mDataChannel2; - - default: - throw new ArrayIndexOutOfBoundsException(); - } - } - - DataChannelObserverMock dataChannelObserver(int channelIndex) { - switch (channelIndex) { - case 0: - return mDataChannelObserverMock1; - - case 1: - return mDataChannelObserverMock2; - - default: - throw new ArrayIndexOutOfBoundsException(); - } - } - - void registerDatatChannelObservers() { - mDataChannel1.registerObserver(mDataChannelObserverMock1); - mDataChannel2.registerObserver(mDataChannelObserverMock2); - } - - void unregisterDatatChannelObservers() { - mDataChannel1.unregisterObserver(); - mDataChannel2.unregisterObserver(); - } -}
diff --git a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/DevToolsBridgeServerSandbox.java b/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/DevToolsBridgeServerSandbox.java deleted file mode 100644 index 7364e0cc..0000000 --- a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/DevToolsBridgeServerSandbox.java +++ /dev/null
@@ -1,96 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.components.devtools_bridge; - -import android.content.Context; -import android.os.Process; -import android.util.Log; - -import org.chromium.components.devtools_bridge.util.LooperExecutor; - -import java.io.IOException; - -/** - * Sandbox for manual testing {@link DevToolsBridgeServer} - */ -public class DevToolsBridgeServerSandbox { - private static final String TAG = "DevToolsBridgeServerSandbox"; - private static final String SERVER_SOCKET_NAME = "chrome_shell_devtools_remote"; - - private Context mContext; - private LooperExecutor mExecutor; - private DevToolsBridgeServer mServer; - private SessionDependencyFactory mFactory; - private ClientSessionTestingHost mClientSession1; - private ClientSessionTestingHost mClientSession2; - - public void start(Context context) { - assert mContext == null; - mContext = context; - mExecutor = LooperExecutor.newInstanceForMainLooper(mContext); - mServer = new DevToolsBridgeServer(new ServerDelegate(context)); - - mFactory = SessionDependencyFactory.newInstance(); - mClientSession1 = createSession("Session 1", "webview_devtools_remote_" + Process.myPid()); - mClientSession2 = createSession("Session 2", "chrome_devtools_remote_" + Process.myPid()); - - mClientSession1.start(); - mClientSession2.start(); - } - - public void stop() { - mClientSession1.dispose(); - mClientSession2.dispose(); - mFactory.dispose(); - mClientSession1 = null; - mClientSession2 = null; - mFactory = null; - mServer.dispose(); - mServer = null; - mContext = null; - } - - private ClientSessionTestingHost createSession(String sessionId, String socketName) { - try { - return new ClientSessionTestingHost( - mFactory, mServer, mExecutor, sessionId, socketName); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - private void stopInternal() { - Log.d(TAG, "Service disconnected. Stopping client sessions"); - mClientSession1.dispose(); - mClientSession2.dispose(); - mFactory.dispose(); - mClientSession1 = null; - mClientSession2 = null; - mFactory = null; - } - - private static class ServerDelegate implements DevToolsBridgeServer.Delegate { - private Context mContext; - - public ServerDelegate(Context context) { - mContext = context; - } - - @Override - public Context getContext() { - return mContext; - } - - @Override - public void onSessionCountChange(int sessionCount) { - Log.i(TAG, sessionCount + " active session"); - } - - @Override - public void querySocketName(DevToolsBridgeServer.QuerySocketCallback callback) { - callback.onSuccess(SERVER_SOCKET_NAME); - } - } -}
diff --git a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/GCDClientSessionTestingHost.java b/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/GCDClientSessionTestingHost.java deleted file mode 100644 index c3fd83a..0000000 --- a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/GCDClientSessionTestingHost.java +++ /dev/null
@@ -1,101 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.components.devtools_bridge; - -import android.util.Log; - -import org.chromium.components.devtools_bridge.apiary.TestApiaryClientFactory; -import org.chromium.components.devtools_bridge.commands.Command; -import org.chromium.components.devtools_bridge.commands.CommandSender; - -import java.io.IOException; -import java.util.Random; - -/** - * Helper class which handles a client session in manual tests. Connects to a - * remote server with GCD. - */ -public class GCDClientSessionTestingHost { - private static final String TAG = "GCDClientSessionTestingHost"; - private static final Random sRandom = new Random(); - - private final TestApiaryClientFactory mClientFactory; - private final SessionDependencyFactory mFactory; - private final LocalSessionBridge.ThreadedExecutor mIOExecutor; - private final ClientSessionTestingHost mBase; - private final String mOAuthToken; - private final String mRemoteInstanceId; - - private volatile boolean mStarted; - - public GCDClientSessionTestingHost( - String oAuthToken, String socketName, String remoteInstanceId) throws IOException { - mClientFactory = new TestApiaryClientFactory(); - mFactory = SessionDependencyFactory.newInstance(); - mIOExecutor = new LocalSessionBridge.ThreadedExecutor(); - - String sessionId = Integer.toString(sRandom.nextInt()); - - mBase = new ClientSessionTestingHost( - mFactory, new ServerProxy(remoteInstanceId), mIOExecutor, sessionId, socketName); - - mOAuthToken = oAuthToken; - mRemoteInstanceId = remoteInstanceId; - } - - public boolean isStarted() { - return mStarted; - } - - public void start(final Runnable completionCallback) { - mIOExecutor.postOnSessionThread(0, new Runnable() { - @Override - public void run() { - try { - mBase.start(mClientFactory.newConfigClient().fetch()); - mStarted = true; - } catch (IOException e) { - Log.e(TAG, "Failed to start", e); - } finally { - completionCallback.run(); - } - } - - }); - } - - public void dispose() { - mBase.dispose(); - mIOExecutor.runSynchronously(new Runnable() { - @Override - public void run() { - // All previously scheduled operations have completed. - mClientFactory.close(); - } - }); - mIOExecutor.dispose(); - } - - private class ServerProxy extends CommandSender { - private final String mInstanceId; - - public ServerProxy(String instanceId) { - mInstanceId = instanceId; - } - - protected void send(Command command, Runnable completionCallback) { - assert mIOExecutor.isCalledOnSessionThread(); - - try { - mClientFactory.newTestGCDClient(mOAuthToken).send(mRemoteInstanceId, command); - } catch (IOException e) { - Log.e(TAG, "Exception when sending a command", e); - command.setFailure("IOException: " + e.getMessage()); - } finally { - completionCallback.run(); - } - } - } -}
diff --git a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/LocalSessionBridge.java b/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/LocalSessionBridge.java deleted file mode 100644 index 13f24181..0000000 --- a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/LocalSessionBridge.java +++ /dev/null
@@ -1,303 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.components.devtools_bridge; - -import android.util.Log; - -import java.io.IOException; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicReference; - -/** - * Helper class designated for automatic and manual testing. Creates a pair of ClientSession and - * ServerSession on separate and threads binds them through and adapters that makes call the calls - * on correct threads (no serialization needed for communication). - */ -public class LocalSessionBridge { - private static final String TAG = "LocalSessionBridge"; - - private volatile int mDelayMs = 0; - - private final SessionDependencyFactory mFactory = SessionDependencyFactory.newInstance(); - - private final ThreadedExecutor mServerExecutor = new ThreadedExecutor(); - private final ThreadedExecutor mClientExecutor = new ThreadedExecutor(); - - private final ServerSessionMock mServerSession; - private final ClientSessionMock mClientSession; - - private boolean mStarted = false; - - private final CountDownLatch mNegotiated = new CountDownLatch(2); - private final CountDownLatch mControlChannelOpened = new CountDownLatch(2); - private final CountDownLatch mClientAutoClosed = new CountDownLatch(1); - private final CountDownLatch mServerAutoClosed = new CountDownLatch(1); - private final CountDownLatch mTunnelConfirmed = new CountDownLatch(1); - - private int mServerAutoCloseTimeoutMs = -1; - private int mClientAutoCloseTimeoutMs = -1; - - public LocalSessionBridge(String serverSocketName, String clientSocketName) throws IOException { - mServerSession = new ServerSessionMock(serverSocketName); - mClientSession = new ClientSessionMock(mServerSession, clientSocketName); - } - - public void setMessageDeliveryDelayMs(int value) { - mDelayMs = value; - } - - void setClientAutoCloseTimeoutMs(int value) { - assert !isStarted(); - - mClientAutoCloseTimeoutMs = value; - } - - void setServerAutoCloseTimeoutMs(int value) { - assert !isStarted(); - - mServerAutoCloseTimeoutMs = value; - } - - public void dispose() { - mServerExecutor.runSynchronously(new Runnable() { - @Override - public void run() { - mServerSession.dispose(); - } - }); - mClientExecutor.runSynchronously(new Runnable() { - @Override - public void run() { - mClientSession.dispose(); - } - }); - - mServerExecutor.dispose(); - mClientExecutor.dispose(); - mFactory.dispose(); - } - - public void start() { - start(new RTCConfiguration()); - } - - public void start(final RTCConfiguration config) { - if (mServerAutoCloseTimeoutMs >= 0) - mServerSession.setAutoCloseTimeoutMs(mServerAutoCloseTimeoutMs); - if (mClientAutoCloseTimeoutMs >= 0) - mClientSession.setAutoCloseTimeoutMs(mClientAutoCloseTimeoutMs); - mClientExecutor.runSynchronously(new Runnable() { - @Override - public void run() { - mClientSession.start(config); - } - }); - mStarted = true; - } - - private boolean isStarted() { - return mStarted; - } - - public void stop() { - assert mStarted; - - mServerExecutor.runSynchronously(new Runnable() { - @Override - public void run() { - mServerSession.stop(); - } - }); - mClientExecutor.runSynchronously(new Runnable() { - @Override - public void run() { - mClientSession.stop(); - } - }); - mStarted = false; - } - - public void awaitNegotiated() throws InterruptedException { - mNegotiated.await(); - } - - public void awaitControlChannelOpened() throws InterruptedException { - mControlChannelOpened.await(); - } - - public void awaitClientAutoClosed() throws InterruptedException { - mClientAutoClosed.await(); - } - - public void awaitServerAutoClosed() throws InterruptedException { - mServerAutoClosed.await(); - } - - private class ServerSessionMock extends ServerSession { - public ServerSessionMock(String serverSocketName) { - super(LocalSessionBridge.this.mFactory, mServerExecutor, serverSocketName); - } - - public void setAutoCloseTimeoutMs(int value) { - mAutoCloseTimeoutMs = value; - } - - @Override - protected void onSessionNegotiated() { - Log.d(TAG, "Server negotiated"); - mNegotiated.countDown(); - super.onSessionNegotiated(); - } - - @Override - protected void onControlChannelOpened() { - Log.d(TAG, "Server's control channel opened"); - super.onControlChannelOpened(); - mControlChannelOpened.countDown(); - } - - @Override - protected void onIceCandidate(String candidate) { - Log.d(TAG, "Server's ICE candidate: " + candidate); - super.onIceCandidate(candidate); - } - - @Override - protected void closeSelf() { - Log.d(TAG, "Server autoclosed"); - super.closeSelf(); - mServerAutoClosed.countDown(); - } - - @Override - protected SocketTunnel newSocketTunnelServer(String serverSocketName) { - SocketTunnel tunnel = super.newSocketTunnelServer(serverSocketName); - Log.d(TAG, "Server tunnel created on " + serverSocketName); - return tunnel; - } - } - - private class ClientSessionMock extends ClientSession { - public ClientSessionMock(ServerSession serverSession, String clientSocketName) - throws IOException { - super(LocalSessionBridge.this.mFactory, - mClientExecutor, - createServerSessionProxy(serverSession), - clientSocketName); - } - - public void setAutoCloseTimeoutMs(int value) { - mAutoCloseTimeoutMs = value; - } - - @Override - protected void onSessionNegotiated() { - Log.d(TAG, "Client negotiated"); - mNegotiated.countDown(); - super.onSessionNegotiated(); - } - - @Override - protected void onControlChannelOpened() { - Log.d(TAG, "Client's control channel opened"); - super.onControlChannelOpened(); - mControlChannelOpened.countDown(); - } - - @Override - protected void onIceCandidate(String candidate) { - Log.d(TAG, "Client's ICE candidate: " + candidate); - super.onIceCandidate(candidate); - } - - @Override - protected void closeSelf() { - Log.d(TAG, "Client autoclosed"); - super.closeSelf(); - mClientAutoClosed.countDown(); - } - } - - /** - * Implementation of SessionBase.Executor on top of ScheduledExecutorService. - */ - public static final class ThreadedExecutor implements SessionBase.Executor { - private final ScheduledExecutorService mExecutor = - Executors.newSingleThreadScheduledExecutor(); - private final AtomicReference<Thread> mSessionThread = new AtomicReference<Thread>(); - - @Override - public SessionBase.Cancellable postOnSessionThread(int delayMs, Runnable runnable) { - return new CancellableFuture(mExecutor.schedule( - new SessionThreadRunner(runnable), delayMs, TimeUnit.MILLISECONDS)); - } - - @Override - public boolean isCalledOnSessionThread() { - return Thread.currentThread() == mSessionThread.get(); - } - - public void runSynchronously(Runnable runnable) { - try { - mExecutor.submit(new SessionThreadRunner(runnable)).get(); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } catch (ExecutionException e) { - throw new RuntimeException(e); - } - } - - public void dispose() { - mExecutor.shutdownNow(); - } - - private class SessionThreadRunner implements Runnable { - private final Runnable mRunnable; - - public SessionThreadRunner(Runnable runnable) { - mRunnable = runnable; - } - - @Override - public void run() { - Thread thread = mSessionThread.getAndSet(Thread.currentThread()); - assert thread == null; - try { - mRunnable.run(); - } finally { - thread = mSessionThread.getAndSet(null); - } - assert thread == Thread.currentThread(); - } - } - } - - private static final class CancellableFuture implements SessionBase.Cancellable { - private final ScheduledFuture<?> mFuture; - - public CancellableFuture(ScheduledFuture<?> future) { - mFuture = future; - } - - @Override - public void cancel() { - mFuture.cancel(false); - } - } - - private SessionBase.ServerSessionInterface createServerSessionProxy( - SessionBase.ServerSessionInterface serverSession) { - String sessionId = ""; - - return new SignalingReceiverProxy( - mServerExecutor, mClientExecutor, serverSession, sessionId, mDelayMs) - .asServerSession(sessionId); - } -}
diff --git a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/PacketDecoder.java b/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/PacketDecoder.java deleted file mode 100644 index d8e0dff5..0000000 --- a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/PacketDecoder.java +++ /dev/null
@@ -1,67 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.components.devtools_bridge; - -import java.nio.ByteBuffer; - -/** - * Decodes data packets of SocketTunnelClient and SocketTunnelServer for tests. - */ -public final class PacketDecoder extends SocketTunnelBase.PacketDecoderBase { - private boolean mControlPacket = false; - private boolean mDataPacket; - private int mOpCode; - private int mConnectionId; - private byte[] mData; - - protected void onReceivedDataPacket(int connectionId, byte[] data) { - mDataPacket = true; - mConnectionId = connectionId; - mData = data; - } - - @Override - protected void onReceivedControlPacket(int connectionId, byte opCode) { - mControlPacket = true; - mOpCode = opCode; - mConnectionId = connectionId; - } - - public static PacketDecoder tryDecode(ByteBuffer packet) throws SocketTunnelBase.ProtocolError { - PacketDecoder decoder = new PacketDecoder(); - decoder.decodePacket(packet); - return decoder; - } - - public static PacketDecoder decode(ByteBuffer packet) { - try { - return tryDecode(packet); - } catch (SocketTunnelBase.ProtocolError e) { - throw new RuntimeException(e); - } - } - - public boolean isControlPacket() { - return mControlPacket; - } - - public boolean isDataPacket() { - return mDataPacket; - } - - public int opCode() { - assert isControlPacket(); - return mOpCode; - } - - public int connectionId() { - return mConnectionId; - } - - public byte[] data() { - assert isDataPacket(); - return mData.clone(); - } -}
diff --git a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/PeerConnectionObserverMock.java b/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/PeerConnectionObserverMock.java deleted file mode 100644 index fc1fdd4..0000000 --- a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/PeerConnectionObserverMock.java +++ /dev/null
@@ -1,54 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.components.devtools_bridge; - -import org.chromium.base.annotations.SuppressFBWarnings; - -import java.util.concurrent.CountDownLatch; - -/** - * Mock for AbstractPeerConnection.Observer. - */ -@SuppressFBWarnings("URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD") -public class PeerConnectionObserverMock implements AbstractPeerConnection.Observer { - public AbstractPeerConnection.SessionDescriptionType localDescriptionType; - public String localDescription; - - public final CountDownLatch localDescriptionAvailable = new CountDownLatch(1); - public final CountDownLatch failureAvailable = new CountDownLatch(1); - public final CountDownLatch remoteDescriptionSet = new CountDownLatch(1); - public final CountDownLatch connected = new CountDownLatch(1); - - public AbstractPeerConnection iceCandidatesSink; - - @Override - public void onFailure(String description) { - failureAvailable.countDown(); - } - - @Override - public void onLocalDescriptionCreatedAndSet( - AbstractPeerConnection.SessionDescriptionType type, String description) { - localDescriptionType = type; - localDescription = description; - localDescriptionAvailable.countDown(); - } - - @Override - public void onRemoteDescriptionSet() { - remoteDescriptionSet.countDown(); - } - - @Override - public void onIceCandidate(String iceCandidate) { - if (iceCandidatesSink != null) - iceCandidatesSink.addIceCandidate(iceCandidate); - } - - @Override - public void onIceConnectionChange(boolean connected) { - this.connected.countDown(); - } -}
diff --git a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/SignalingReceiverMock.java b/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/SignalingReceiverMock.java deleted file mode 100644 index 6d1fb25..0000000 --- a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/SignalingReceiverMock.java +++ /dev/null
@@ -1,50 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.components.devtools_bridge; - -import org.chromium.base.annotations.SuppressFBWarnings; - -import java.util.List; - -/** - * Mock of SignalingReceiver. - */ -@SuppressFBWarnings("URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD") -public class SignalingReceiverMock implements SignalingReceiver { - public String sessionId; - public String offer; - public SessionBase.NegotiationCallback negotiationCallback; - public SessionBase.IceExchangeCallback iceExchangeCallback; - - @Override - public void startSession( - String sessionId, - RTCConfiguration config, - String offer, - SessionBase.NegotiationCallback callback) { - this.sessionId = sessionId; - this.offer = offer; - this.negotiationCallback = callback; - } - - @Override - public void renegotiate( - String sessionId, - String offer, - SessionBase.NegotiationCallback callback) { - this.sessionId = sessionId; - this.offer = offer; - this.negotiationCallback = callback; - } - - @Override - public void iceExchange( - String sessionId, - List<String> clientCandidates, - SessionBase.IceExchangeCallback callback) { - this.sessionId = sessionId; - this.iceExchangeCallback = callback; - } -}
diff --git a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/SignalingReceiverProxy.java b/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/SignalingReceiverProxy.java deleted file mode 100644 index f57637b..0000000 --- a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/SignalingReceiverProxy.java +++ /dev/null
@@ -1,137 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.components.devtools_bridge; - -import org.chromium.components.devtools_bridge.commands.Command; -import org.chromium.components.devtools_bridge.commands.CommandReceiver; -import org.chromium.components.devtools_bridge.commands.CommandSender; - -import java.util.List; - -/** - * Helper proxy that binds client and server sessions living on different executors. - */ -final class SignalingReceiverProxy extends CommandSender { - private final CommandReceiver mReceiver; - private final SessionBase.Executor mServerExecutor; - private final SessionBase.Executor mClientExecutor; - private final int mDelayMs; - - public SignalingReceiverProxy( - SessionBase.Executor serverExecutor, - SessionBase.Executor clientExecutor, - SignalingReceiver server, - int delayMs) { - mServerExecutor = serverExecutor; - mClientExecutor = clientExecutor; - mReceiver = new CommandReceiver(server); - mDelayMs = delayMs; - } - - public SignalingReceiverProxy( - SessionBase.Executor serverExecutor, - SessionBase.Executor clientExecutor, - SessionBase.ServerSessionInterface serverSession, - String sessionId, - int delayMs) { - this(serverExecutor, clientExecutor, - new SignalingReceiverAdaptor(serverSession, sessionId), - delayMs); - } - - public SessionBase.Executor serverExecutor() { - return mServerExecutor; - } - - public SessionBase.Executor clientExecutor() { - return mClientExecutor; - } - - @Override - protected void send(final Command command, final Runnable completionCallback) { - assert mClientExecutor.isCalledOnSessionThread(); - - mServerExecutor.postOnSessionThread(mDelayMs, new Runnable() { - @Override - public void run() { - mReceiver.receive(command, new Runnable() { - @Override - public void run() { - assert mServerExecutor.isCalledOnSessionThread(); - mClientExecutor.postOnSessionThread(mDelayMs, completionCallback); - } - }); - } - }); - } - - public SessionBase.ServerSessionInterface asServerSession(String sessionId) { - return new ServerSessionAdapter(this, sessionId); - } - - private static final class ServerSessionAdapter implements SessionBase.ServerSessionInterface { - private final SignalingReceiver mAdaptee; - private final String mSessionId; - - public ServerSessionAdapter(SignalingReceiver adaptee, String sessionId) { - mAdaptee = adaptee; - mSessionId = sessionId; - } - - @Override - public void startSession( - RTCConfiguration config, String offer, SessionBase.NegotiationCallback callback) { - mAdaptee.startSession(mSessionId, config, offer, callback); - } - - @Override - public void renegotiate(String offer, SessionBase.NegotiationCallback callback) { - mAdaptee.renegotiate(mSessionId, offer, callback); - } - - @Override - public void iceExchange( - List<String> clientCandidates, SessionBase.IceExchangeCallback callback) { - mAdaptee.iceExchange(mSessionId, clientCandidates, callback); - } - } - - private static final class SignalingReceiverAdaptor implements SignalingReceiver { - private final SessionBase.ServerSessionInterface mAdaptee; - private final String mSessionId; - - public SignalingReceiverAdaptor( - SessionBase.ServerSessionInterface adaptee, String sessionId) { - mAdaptee = adaptee; - mSessionId = sessionId; - } - - @Override - public void startSession( - String sessionId, RTCConfiguration config, String offer, - SessionBase.NegotiationCallback callback) { - if (mSessionId.equals(sessionId)) { - mAdaptee.startSession(config, offer, callback); - } - } - - @Override - public void renegotiate( - String sessionId, String offer, SessionBase.NegotiationCallback callback) { - if (mSessionId.equals(sessionId)) { - mAdaptee.renegotiate(offer, callback); - } - } - - @Override - public void iceExchange( - String sessionId, List<String> clientCandidates, - SessionBase.IceExchangeCallback callback) { - if (mSessionId.equals(sessionId)) { - mAdaptee.iceExchange(clientCandidates, callback); - } - } - } -}
diff --git a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/SignalingThreadMock.java b/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/SignalingThreadMock.java deleted file mode 100644 index 8d62f78..0000000 --- a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/SignalingThreadMock.java +++ /dev/null
@@ -1,162 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.components.devtools_bridge; - -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.LinkedBlockingDeque; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; - -/** - * Convinience class for tests. Like WebRTC threads supports posts - * and synchronous invokes. - */ -class SignalingThreadMock { - // TODO: use scaleTimeout when natives for org.chromium.base get available. - private static final int EXECUTION_TIME_LIMIT_MS = 5000; - - private final AtomicInteger mInvokationCounter = new AtomicInteger(0); - private final ExecutorService mExecutor = Executors.newSingleThreadExecutor(); - private final ScheduledExecutorService mWatchDogExecutor = - Executors.newSingleThreadScheduledExecutor(); - private ScheduledFuture<?> mWatchDogFuture; - private final Thread mThread; - private final BlockingQueue<Runnable> mExecutionQueue = new LinkedBlockingDeque<Runnable>(); - - public SignalingThreadMock() { - mThread = new Thread() { - @Override - public void run() { - try { - runExecutionLoop(); - } catch (InterruptedException e) { - // Normal finish. - } - } - }; - mThread.start(); - } - - private void runExecutionLoop() throws InterruptedException { - while (true) { - mExecutionQueue.take().run(); - } - } - - public void invoke(final Runnable runnable) { - try { - invoke(new TestUtils.RunnableAdapter(runnable)); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - public <T> T invoke(final Callable<T> callable) throws Exception { - if (isOnThread()) return callable.call(); - - try { - return new InvokeWrapper<T>(callable).invoke(); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } catch (ExecutionException e) { - throw (Exception) e.getCause(); - } - } - - public void post(Runnable runnable) { - boolean success = mExecutionQueue.offer(new PostWrapper(runnable)); - assert success; - } - - public void dispose() { - mWatchDogExecutor.shutdown(); - mThread.interrupt(); - try { - mThread.join(); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - } - - public boolean isOnThread() { - return Thread.currentThread() == mThread; - } - - private void onStartedExecution(final int index, final Exception timeoutException) { - mWatchDogFuture = mWatchDogExecutor.schedule(new Runnable() { - @Override - public void run() { - throw new RuntimeException( - "Time limit on " + Integer.toString(index) + " invocation", - timeoutException); - } - }, EXECUTION_TIME_LIMIT_MS, TimeUnit.MILLISECONDS); - } - - private void onFinishedExecution() { - mWatchDogFuture.cancel(false); - } - - private abstract class WrapperBase implements Runnable { - private final int mIndex; - private final Exception mTimeoutException; - - protected WrapperBase() { - mIndex = mInvokationCounter.incrementAndGet(); - mTimeoutException = new Exception("Timeout exception"); - } - - @Override - public final void run() { - onStartedExecution(mIndex, mTimeoutException); - try { - runWrapped(); - } finally { - onFinishedExecution(); - } - } - - protected abstract void runWrapped(); - } - - private class InvokeWrapper<T> extends WrapperBase { - private final Callable<T> mWrapped; - private final TestUtils.InvokeHelper<T> mHelper = new TestUtils.InvokeHelper<T>(); - - public InvokeWrapper(Callable<T> wrapped) { - mWrapped = wrapped; - } - - @Override - protected void runWrapped() { - mHelper.runOnTargetThread(mWrapped); - } - - public T invoke() throws Exception { - boolean success = mExecutionQueue.offer(this); - assert success; - return mHelper.takeResult(); - } - } - - private class PostWrapper extends WrapperBase { - private final Runnable mWrapped; - - public PostWrapper(Runnable wrapped) { - mWrapped = wrapped; - } - - @Override - protected void runWrapped() { - mWrapped.run(); - } - } -}
diff --git a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/SocketTunnelBase.java b/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/SocketTunnelBase.java deleted file mode 100644 index bc15d76e..0000000 --- a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/SocketTunnelBase.java +++ /dev/null
@@ -1,399 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.components.devtools_bridge; - -import android.net.LocalSocket; -import android.net.LocalSocketAddress; - -import java.io.IOException; -import java.nio.ByteBuffer; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicReference; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReadWriteLock; -import java.util.concurrent.locks.ReentrantReadWriteLock; - -/** - * Base class for client and server that tunnels DevToolsServer's UNIX socket - * over WebRTC data channel. - * - * Server runs on a android device with Chromium (or alike). Client runs where socket - * needed to be accesses (it could be the same device if socket names are different; this - * configuration useful for testing). - * - * Client listens LocalServerSocket and each time it receives connection it forwards - * CLIENT_OPEN packet to the server with newly assigned connection id. On receiving this packet - * server tries to connect to DevToolsServer socket. If succeeded it sends back SERVER_OPEN_ACK - * with the same connection id. If failed it sends SERVER_CLOSE. - * - * When input stream on client shuts down it sends CLIENT_CLOSE. The same with SERVER_CLOSE - * on the server side (only if SERVER_OPEN_ACK had sent). Between CLIENT_OPEN and CLIENT_CLOSE - * any amount of data packets may be transferred (the same for SERVER_OPEN_ACK/SERVER_CLOSE - * on the server side). - * - * Since all communication is reliable and ordered it's safe for client to assume that - * if CLIENT_CLOSE has sent and SERVER_CLOSE has received with the same connection ID this - * ID is safe to be reused. - */ -public abstract class SocketTunnelBase implements SocketTunnel { - // Data channel is threadsafe but access to the reference needs synchronization. - private final ReadWriteLock mDataChanneliReferenceLock = new ReentrantReadWriteLock(); - private volatile AbstractDataChannel mDataChannel; - - // Packet structure encapsulated in buildControlPacket, buildDataPacket and PacketDecoderBase. - // Structure of control packet: - // 1-st byte: CONTROL_CONNECTION_ID. - // 2-d byte: op code. - // 3-d byte: connection id. - // - // Structure of data packet: - // 1-st byte: connection id. - // 2..n: data. - - private static final int CONTROL_PACKET_SIZE = 3; - - // Client to server control packets. - protected static final byte CLIENT_OPEN = (byte) 0; - protected static final byte CLIENT_CLOSE = (byte) 1; - - // Server to client control packets. - protected static final byte SERVER_OPEN_ACK = (byte) 0; - protected static final byte SERVER_CLOSE = (byte) 1; - - // Must not exceed WebRTC limit. Exceeding it closes - // data channel automatically. TODO(serya): WebRTC limit supposed to be removed. - static final int READING_BUFFER_SIZE = 4 * 1024; - - private static final int CONTROL_CONNECTION_ID = 0; - - // DevTools supports up to ~10 connections at the time. A few extra IDs usefull for - // delays in closing acknowledgement. - protected static final int MIN_CONNECTION_ID = 1; - protected static final int MAX_CONNECTION_ID = 64; - - // Signaling thread isn't accessible via API. Assumes that first caller - // checkCalledOnSignalingThread is called on it indeed. It also works well for tests. - private final AtomicReference<Thread> mSignalingThread = new AtomicReference<Thread>(); - - // For writing in socket without blocking signaling thread. - private final ExecutorService mWritingThread = Executors.newSingleThreadExecutor(); - - @Override - public boolean isBound() { - final Lock lock = mDataChanneliReferenceLock.readLock(); - lock.lock(); - try { - return mDataChannel != null; - } finally { - lock.unlock(); - } - } - - /** - * Binds the tunnel to the data channel. Tunnel starts its activity when data channel - * open. - */ - @Override - public void bind(AbstractDataChannel dataChannel) { - // Observer registrution must not be done in constructor. - final Lock lock = mDataChanneliReferenceLock.writeLock(); - lock.lock(); - try { - mDataChannel = dataChannel; - } finally { - lock.unlock(); - } - dataChannel.registerObserver(new DataChannelObserver()); - } - - /** - * Stops all tunnel activity and returns the prevously bound data channel. - * It's safe to dispose the data channel after it. - */ - @Override - public AbstractDataChannel unbind() { - final Lock lock = mDataChanneliReferenceLock.writeLock(); - lock.lock(); - final AbstractDataChannel dataChannel; - try { - dataChannel = mDataChannel; - mDataChannel = null; - } finally { - lock.unlock(); - } - dataChannel.unregisterObserver(); - mSignalingThread.set(null); - mWritingThread.shutdownNow(); - return dataChannel; - } - - protected void checkCalledOnSignalingThread() { - if (!mSignalingThread.compareAndSet(null, Thread.currentThread())) { - if (mSignalingThread.get() != Thread.currentThread()) { - throw new RuntimeException("Must be called on signaling thread"); - } - } - } - - protected static void checkConnectionId(int connectionId) throws ProtocolError { - if (connectionId < MIN_CONNECTION_ID || connectionId > MAX_CONNECTION_ID) { - throw new ProtocolError("Invalid connection id: " + Integer.toString(connectionId)); - } - } - - protected void onProtocolError(ProtocolError e) { - checkCalledOnSignalingThread(); - - // When integrity of data channel is broken then best way to survive is to close it. - final Lock lock = mDataChanneliReferenceLock.readLock(); - lock.lock(); - try { - mDataChannel.close(); - } finally { - lock.unlock(); - } - } - - protected abstract void onReceivedDataPacket(int connectionId, byte[] data) - throws ProtocolError; - protected abstract void onReceivedControlPacket(int connectionId, byte opCode) - throws ProtocolError; - protected void onSocketException(IOException e, int connectionId) {} - protected void onDataChannelOpened() {} - protected void onDataChannelClosed() {} - - static ByteBuffer buildControlPacket(int connectionId, byte opCode) { - ByteBuffer packet = ByteBuffer.allocateDirect(CONTROL_PACKET_SIZE); - packet.put((byte) CONTROL_CONNECTION_ID); - packet.put(opCode); - packet.put((byte) connectionId); - return packet; - } - - static ByteBuffer buildDataPacket(int connectionId, byte[] buffer, int count) { - ByteBuffer packet = ByteBuffer.allocateDirect(count + 1); - packet.put((byte) connectionId); - packet.put(buffer, 0, count); - return packet; - } - - protected void sendToDataChannel(ByteBuffer packet) { - packet.limit(packet.position()); - packet.position(0); - final Lock lock = mDataChanneliReferenceLock.readLock(); - lock.lock(); - try { - if (mDataChannel != null) { - mDataChannel.send(packet, AbstractDataChannel.MessageType.BINARY); - } - } finally { - lock.unlock(); - } - } - - /** - * Packet decoding exposed for tests. - */ - abstract static class PacketDecoderBase { - protected void decodePacket(ByteBuffer packet) throws ProtocolError { - if (packet.remaining() == 0) { - throw new ProtocolError("Empty packet"); - } - - int connectionId = packet.get(); - if (connectionId != CONTROL_CONNECTION_ID) { - checkConnectionId(connectionId); - byte[] data = new byte[packet.remaining()]; - packet.get(data); - onReceivedDataPacket(connectionId, data); - } else { - if (packet.remaining() != CONTROL_PACKET_SIZE - 1) { - throw new ProtocolError("Invalid control packet size"); - } - - byte opCode = packet.get(); - connectionId = packet.get(); - checkConnectionId(connectionId); - onReceivedControlPacket(connectionId, opCode); - } - } - - protected abstract void onReceivedDataPacket(int connectionId, byte[] data) - throws ProtocolError; - protected abstract void onReceivedControlPacket(int connectionId, byte opcode) - throws ProtocolError; - } - - private final class DataChannelObserver - extends PacketDecoderBase implements AbstractDataChannel.Observer { - @Override - public void onStateChange(AbstractDataChannel.State state) { - checkCalledOnSignalingThread(); - - if (state == AbstractDataChannel.State.OPEN) { - onDataChannelOpened(); - } else { - onDataChannelClosed(); - } - } - - @Override - public void onMessage(ByteBuffer message) { - checkCalledOnSignalingThread(); - - try { - decodePacket(message); - } catch (ProtocolError e) { - onProtocolError(e); - } - } - - @Override - protected void onReceivedDataPacket(int connectionId, byte[] data) throws ProtocolError { - checkCalledOnSignalingThread(); - - SocketTunnelBase.this.onReceivedDataPacket(connectionId, data); - } - - @Override - protected void onReceivedControlPacket(int connectionId, byte opCode) throws ProtocolError { - checkCalledOnSignalingThread(); - - SocketTunnelBase.this.onReceivedControlPacket(connectionId, opCode); - } - } - - /** - * Any problem happened while handling incoming message that breaks state integrity. - */ - static class ProtocolError extends Exception { - public ProtocolError(String description) { - super(description); - } - } - - /** - * Base utility class for client and server connections. - */ - protected abstract class ConnectionBase { - protected final int mId; - protected final LocalSocket mSocket; - private final AtomicInteger mOpenedStreams = new AtomicInteger(2); // input and output. - private volatile boolean mConnected; - private byte[] mBuffer; - - private ConnectionBase(int id, LocalSocket socket, boolean preconnected) { - mId = id; - mSocket = socket; - mConnected = preconnected; - } - - protected ConnectionBase(int id, LocalSocket socket) { - this(id, socket, true); - } - - protected ConnectionBase(int id) { - this(id, new LocalSocket(), false); - } - - protected boolean connect(LocalSocketAddress address) { - assert !mConnected; - try { - mSocket.connect(address); - mConnected = true; - return true; - } catch (IOException e) { - onSocketException(e, mId); - return false; - } - } - - protected void runReadingLoop() { - mBuffer = new byte[READING_BUFFER_SIZE]; - try { - boolean open; - do { - open = pump(); - } while (open); - } catch (IOException e) { - onSocketException(e, mId); - } finally { - mBuffer = null; - } - } - - private boolean pump() throws IOException { - int count = mSocket.getInputStream().read(mBuffer); - if (count <= 0) - return false; - sendToDataChannel(buildDataPacket(mId, mBuffer, count)); - return true; - } - - protected void writeData(byte[] data) { - // Called on writing thread. - try { - mSocket.getOutputStream().write(data); - } catch (IOException e) { - onSocketException(e, mId); - } - } - - public void onReceivedDataPacket(final byte[] data) { - mWritingThread.execute(new Runnable() { - @Override - public void run() { - writeData(data); - } - }); - } - - public void terminate() { - close(); - } - - protected void shutdownOutput() { - // Shutdown output on writing thread to make sure all pending writes finished. - mWritingThread.execute(new Runnable() { - @Override - public void run() { - shutdownOutputOnWritingThread(); - } - }); - } - - private void shutdownOutputOnWritingThread() { - try { - if (mConnected) mSocket.shutdownOutput(); - } catch (IOException e) { - onSocketException(e, mId); - } - releaseStream(); - } - - protected void shutdownInput() { - try { - if (mConnected) mSocket.shutdownInput(); - } catch (IOException e) { - onSocketException(e, mId); - } - releaseStream(); - } - - private void releaseStream() { - if (mOpenedStreams.decrementAndGet() == 0) close(); - } - - protected void close() { - try { - mSocket.close(); - } catch (IOException e) { - onSocketException(e, mId); - } - } - } -}
diff --git a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/SocketTunnelClient.java b/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/SocketTunnelClient.java deleted file mode 100644 index 97e7c327..0000000 --- a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/SocketTunnelClient.java +++ /dev/null
@@ -1,314 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.components.devtools_bridge; - -import android.net.LocalServerSocket; -import android.net.LocalSocket; -import android.util.Log; - -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.atomic.AtomicReference; - -/** - * Listens LocalServerSocket and tunnels all connections to the SocketTunnelServer. - */ -public class SocketTunnelClient extends SocketTunnelBase { - private static final String TAG = "SocketTunnelClient"; - - private enum State { - INITIAL, RUNNING, STOPPED - } - - private final AtomicReference<State> mState = new AtomicReference<State>(State.INITIAL); - - private final LocalServerSocket mSocket; - private final ExecutorService mThreadPool = Executors.newCachedThreadPool(); - - // Connections with opened server to client stream. Always accesses on signaling thread. - private final Map<Integer, Connection> mServerConnections = - new HashMap<Integer, Connection>(); - - // Accepted connections are kept here until server returns SERVER_OPEN_ACK or SERVER_CLOSE. - // New connections are added in the listening loop, checked and removed on signaling thread. - // So add/read/remove synchronized through message round trip. - private final ConcurrentMap<Integer, Connection> mPendingConnections = - new ConcurrentHashMap<Integer, Connection>(); - - private final IdRegistry mIdRegistry = new IdRegistry(MIN_CONNECTION_ID, MAX_CONNECTION_ID, 2); - - /** - * This class responsible for generating valid connection IDs. It count usage of connection: - * one user for client to server stream and one for server to client one. When both are closed - * it's safe to reuse ID. - */ - private static final class IdRegistry { - private final int[] mLocks; - private final int mMin; - private final int mMax; - private final int mMaxLocks; - private final Object mLock = new Object(); - - public IdRegistry(int minId, int maxId, int maxLocks) { - assert minId < maxId; - assert maxLocks > 0; - - mMin = minId; - mMax = maxId; - mMaxLocks = maxLocks; - mLocks = new int[maxId - minId + 1]; - } - - public void lock(int id) { - synchronized (mLock) { - int index = toIndex(id); - if (mLocks[index] == 0 || mLocks[index] == mMaxLocks) { - throw new RuntimeException(); - } - mLocks[index]++; - } - } - - public void release(int id) { - synchronized (mLock) { - int index = toIndex(id); - if (mLocks[index] == 0) { - throw new RuntimeException("Releasing unlocked id " + Integer.toString(id)); - } - mLocks[index]--; - } - } - - public boolean isLocked(int id) { - synchronized (mLock) { - return mLocks[toIndex(id)] > 0; - } - } - - public int generate() throws NoIdAvailableException { - synchronized (mLock) { - for (int id = mMin; id != mMax; id++) { - int index = toIndex(id); - if (mLocks[index] == 0) { - mLocks[index] = 1; - return id; - } - } - } - throw new NoIdAvailableException(); - } - - private int toIndex(int id) { - if (id < mMin || id > mMax) { - throw new RuntimeException(); - } - return id - mMin; - } - } - - private static class NoIdAvailableException extends Exception {} - - public SocketTunnelClient(String socketName) throws IOException { - mSocket = new LocalServerSocket(socketName); - } - - public boolean hasConnections() { - return mServerConnections.size() + mPendingConnections.size() > 0; - } - - @Override - public AbstractDataChannel unbind() { - AbstractDataChannel dataChannel = super.unbind(); - if (mState.compareAndSet(State.RUNNING, State.STOPPED)) { - terminateAllConnections(); - closeSocket(); - } - return dataChannel; - } - - @Override - public void dispose() { - if (mState.compareAndSet(State.INITIAL, State.STOPPED)) { - closeSocket(); - } - assert mState.get() == State.STOPPED; - mThreadPool.shutdown(); - } - - @Override - protected void onReceivedDataPacket(int connectionId, byte[] data) throws ProtocolError { - checkCalledOnSignalingThread(); - - if (!mServerConnections.containsKey(connectionId)) - throw new ProtocolError("Unknows connection id"); - - mServerConnections.get(connectionId).onReceivedDataPacket(data); - } - - @Override - protected void onReceivedControlPacket(int connectionId, byte opCode) throws ProtocolError { - switch (opCode) { - case SERVER_OPEN_ACK: - onServerOpenAck(connectionId); - break; - - case SERVER_CLOSE: - onServerClose(connectionId); - break; - - default: - throw new ProtocolError("Invalid opCode"); - } - } - - private void onServerOpenAck(int connectionId) throws ProtocolError { - checkCalledOnSignalingThread(); - - if (mServerConnections.containsKey(connectionId)) { - throw new ProtocolError("Connection already acknowledged"); - } - - if (!mPendingConnections.containsKey(connectionId)) { - throw new ProtocolError("Unknow connection id"); - } - - // Check/get is safe since it can be only removed on this thread. - Connection connection = mPendingConnections.get(connectionId); - mPendingConnections.remove(connectionId); - - mServerConnections.put(connectionId, connection); - - // Lock for client to server stream. - mIdRegistry.lock(connectionId); - mThreadPool.execute(connection); - } - - private void onServerClose(int connectionId) throws ProtocolError { - checkCalledOnSignalingThread(); - - if (mServerConnections.containsKey(connectionId)) { - Connection connection = mServerConnections.get(connectionId); - mServerConnections.remove(connectionId); - mIdRegistry.release(connectionId); // Release sever to client stream. - connection.closedByServer(); - } else if (mPendingConnections.containsKey(connectionId)) { - Connection connection = mPendingConnections.get(connectionId); - mPendingConnections.remove(connectionId); - connection.closedByServer(); - sendToDataChannel(buildControlPacket(connectionId, CLIENT_CLOSE)); - mIdRegistry.release(connectionId); // Release sever to client stream. - } else { - throw new ProtocolError("Closing unknown connection"); - } - } - - @Override - protected void onDataChannelOpened() { - if (!mState.compareAndSet(State.INITIAL, State.RUNNING)) { - throw new InvalidStateException(); - } - - mThreadPool.execute(new Runnable() { - @Override - public void run() { - runListenLoop(); - } - }); - } - - @Override - protected void onDataChannelClosed() { - // All new connections will be rejected. - if (!mState.compareAndSet(State.RUNNING, State.STOPPED)) { - throw new InvalidStateException(); - } - - closeSocket(); - } - - private void terminateAllConnections() { - - for (Connection connection : mServerConnections.values()) { - connection.terminate(); - } - - for (Connection connection : mPendingConnections.values()) { - connection.terminate(); - } - - closeSocket(); - } - - private void closeSocket() { - try { - mSocket.close(); - } catch (IOException e) { - Log.d(TAG, "Failed to close socket: " + e); - onSocketException(e, -1); - } - } - - private void runListenLoop() { - try { - while (true) { - LocalSocket socket = mSocket.accept(); - State state = mState.get(); - if (mState.get() == State.RUNNING) { - // Make sure no socket processed when stopped. - clientOpenConnection(socket); - } else { - socket.close(); - } - } - } catch (IOException e) { - if (mState.get() != State.RUNNING) { - onSocketException(e, -1); - } - // Else exception expected (socket closed). - } - } - - private void clientOpenConnection(LocalSocket socket) throws IOException { - try { - int id = mIdRegistry.generate(); // id generated locked for server to client stream. - Connection connection = new Connection(id, socket); - mPendingConnections.put(id, connection); - sendToDataChannel(buildControlPacket(id, CLIENT_OPEN)); - } catch (NoIdAvailableException e) { - socket.close(); - } - } - - private final class Connection extends ConnectionBase implements Runnable { - public Connection(int id, LocalSocket socket) { - super(id, socket); - } - - public void closedByServer() { - shutdownOutput(); - } - - @Override - public void run() { - assert mIdRegistry.isLocked(mId); - - runReadingLoop(); - - shutdownInput(); - sendToDataChannel(buildControlPacket(mId, CLIENT_CLOSE)); - mIdRegistry.release(mId); // Unlock for client to server stream. - } - } - - /** - * Method called in inappropriate state. - */ - public static class InvalidStateException extends RuntimeException {} -}
diff --git a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/TestDevToolsBridgeService.java b/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/TestDevToolsBridgeService.java deleted file mode 100644 index 39c8a03..0000000 --- a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/TestDevToolsBridgeService.java +++ /dev/null
@@ -1,87 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.components.devtools_bridge; - -import android.app.Notification; -import android.app.PendingIntent; -import android.content.Intent; -import android.widget.Toast; - -import com.google.ipc.invalidation.external.client.contrib.MultiplexingGcmListener; - -/** - * Service for manual testing DevToolsBridgeServer with GCD signaling. - */ -public final class TestDevToolsBridgeService extends DevToolsBridgeServiceBase { - private static final String SOCKET_NAME = "chrome_shell_devtools_remote"; - public final int NOTIFICATION_ID = 1; - public final String DISCONNECT_ALL_CLIENTS_ACTION = - "action.DISCONNECT_ALL_CLIENTS_ACTION"; - public final String UPDATE_GCM_CHANNEL_ID_ACTION = - "action.UPDATE_GCM_CHANNEL_ID"; - - /** - * Redirects intents to the TestDevToolsBridgeService. - */ - public static final class Receiver extends ReceiverBase { - public Receiver() { - super(TestDevToolsBridgeService.class); - } - } - - @Override - protected void querySocketName(DevToolsBridgeServer.QuerySocketCallback callback) { - callback.onSuccess(SOCKET_NAME); - } - - @Override - protected void onFirstSessionStarted() { - startForeground(NOTIFICATION_ID, newForegroundNotification()); - } - - @Override - protected void onLastSessionStopped() { - stopForeground(true); - } - - @Override - protected void onHandleIntent(Intent intent) { - if (DISCONNECT_ALL_CLIENTS_ACTION.equals(intent.getAction())) { - server().closeAllSessions(); - } else if (UPDATE_GCM_CHANNEL_ID_ACTION.equals(intent.getAction())) { - String channelId = MultiplexingGcmListener.initializeGcm(this); - if (channelId.isEmpty()) { - Toast.makeText(this, "Not registered", Toast.LENGTH_SHORT).show(); - } else { - server().updateCloudMessagesId(channelId, startTask()); - Toast.makeText(this, "Updating. See log for results.", Toast.LENGTH_SHORT).show(); - } - } - } - - private PendingIntent newPendingIntent(String action) { - Intent intent = new Intent(this, getClass()); - intent.setAction(action); - return PendingIntent.getService(this, 0, intent, 0); - } - - private Notification newForegroundNotification() { - return new Notification.Builder(this) - // Mandatory fields - .setSmallIcon(android.R.drawable.alert_dark_frame) - .setContentTitle("TestDevToolsBridgeService") - .setContentText("Remote debugger connected") - - // Optional - .addAction(android.R.drawable.ic_delete, - "Disconnect", newPendingIntent(DISCONNECT_ALL_CLIENTS_ACTION)) - .addAction(android.R.drawable.ic_menu_manage, - "Update GCM channel", newPendingIntent(UPDATE_GCM_CHANNEL_ID_ACTION)) - .setOngoing(true) - .setWhen(System.currentTimeMillis()) - - .build(); - } -}
diff --git a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/TestUtils.java b/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/TestUtils.java deleted file mode 100644 index 5a280e73..0000000 --- a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/TestUtils.java +++ /dev/null
@@ -1,137 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.components.devtools_bridge; - -import android.net.LocalSocket; -import android.net.LocalSocketAddress; - -import java.io.IOException; -import java.util.concurrent.Callable; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; - -/** - * Utilities to testing a socket tunnel. - */ -public class TestUtils { - private static final String CHARSET = "UTF-8"; - - // Sends |request| string to UNIX socket socketName on another thread and returns - // Future<String> for obtainings response. - public static Future<String> asyncRequest(final String socketName, final String request) { - - final ExecutorService executor = Executors.newSingleThreadExecutor(); - - return executor.submit(new Callable<String>() { - @Override - public String call() throws Exception { - LocalSocket socket = new LocalSocket(); - socket.connect(new LocalSocketAddress(socketName)); - write(socket, request); - - String response = readAll(socket); - socket.close(); - - executor.shutdown(); - return response; - } - }); - } - - public static void write(LocalSocket socket, String data) throws IOException { - socket.getOutputStream().write(data.getBytes(CHARSET)); - socket.getOutputStream().flush(); - } - - // Reads all bytes from socket input stream until EOF and converts it to UTF-8 string. - public static String read(LocalSocket socket, int length) throws IOException { - byte[] buffer = new byte[length]; - int position = 0; - while (position < buffer.length) { - int count = socket.getInputStream().read(buffer, position, buffer.length - position); - if (count == -1) - break; - position += count; - } - return new String(buffer, 0, position, CHARSET); - } - - public static String readAll(LocalSocket socket) throws IOException { - return read(socket, 1000); - } - - /** - * Utility class for thread synchronization. Allow to track moving through series of steps. - */ - public static class StateBarrier<T> { - private T mState; - private final Object mLock = new Object(); - - public StateBarrier(T initialState) { - mState = initialState; - } - - // Waits until state |from| reached and change state to |to|. - public void advance(T from, T to) { - synchronized (mLock) { - while (mState.equals(from)) { - try { - mLock.wait(); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - } - mState = to; - mLock.notifyAll(); - } - } - } - - /** - * Helper with runs code on another thread and synchronously take the result. - */ - public static class InvokeHelper<T> { - private final CountDownLatch mDone = new CountDownLatch(1); - - private T mResult = null; - private Exception mException = null; - - public void runOnTargetThread(Callable<T> callable) { - try { - mResult = callable.call(); - } catch (Exception e) { - mException = e; - } - mDone.countDown(); - } - - public T takeResult() throws Exception { - mDone.await(); - if (mException != null) - throw mException; - else - return mResult; - } - } - - /** - * Adapts Runnable to Callable<Void>. - */ - public static class RunnableAdapter implements Callable<Void> { - private final Runnable mAdaptee; - - public RunnableAdapter(Runnable adaptee) { - mAdaptee = adaptee; - } - - @Override - public Void call() { - mAdaptee.run(); - return null; - } - } -}
diff --git a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/apiary/TestApiaryClientFactory.java b/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/apiary/TestApiaryClientFactory.java deleted file mode 100644 index c0b235b..0000000 --- a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/apiary/TestApiaryClientFactory.java +++ /dev/null
@@ -1,18 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.components.devtools_bridge.apiary; - -/** - * Implementation of ApiaryClientFactory for manual testing. - */ -public class TestApiaryClientFactory extends ApiaryClientFactory { - public TestGCDClient newTestGCDClient(String oAuthToken) { - return new TestGCDClient(mHttpClient, getAPIKey(), oAuthToken); - } - - public TurnConfigClient newConfigClient() { - return new TurnConfigClient(mHttpClient); - } -}
diff --git a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/apiary/TestGCDClient.java b/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/apiary/TestGCDClient.java deleted file mode 100644 index 397a2515..0000000 --- a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/apiary/TestGCDClient.java +++ /dev/null
@@ -1,59 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.components.devtools_bridge.apiary; - -import android.util.JsonReader; - -import org.apache.http.client.HttpClient; - -import org.chromium.components.devtools_bridge.commands.Command; -import org.chromium.components.devtools_bridge.gcd.RemoteInstance; -import org.chromium.components.devtools_bridge.gcd.TestMessageReader; -import org.chromium.components.devtools_bridge.gcd.TestMessageWriter; - -import java.io.IOException; -import java.util.List; - -/** - * Extension of GCDClient with methods needed for the testing app. - */ -public class TestGCDClient extends GCDClient { - private static final String SEND_TIMEOUT_MS = "20000"; - - TestGCDClient(HttpClient httpClient, String apiKey, String oAuthToken) { - super(httpClient, apiKey, oAuthToken); - assert oAuthToken != null; - } - - public List<RemoteInstance> fetchInstances() throws IOException { - return mHttpClient.execute( - newHttpGet("/devices"), - new JsonResponseHandler<List<RemoteInstance>>() { - @Override - public List<RemoteInstance> readResponse(JsonReader reader) - throws IOException { - return new TestMessageReader(reader).readRemoteInstances(); - } - }); - } - - public void send(String remoteInstanceId, final Command command) throws IOException { - String query = "expireInMs=" + SEND_TIMEOUT_MS - + "&responseAwaitMs=" + SEND_TIMEOUT_MS; - - String content = new TestMessageWriter().writeCommand(remoteInstanceId, command) - .close().toString(); - - mHttpClient.execute( - newHttpPost("/commands", query, content), - new JsonResponseHandler<Boolean>() { - @Override - public Boolean readResponse(JsonReader reader) throws IOException { - new TestMessageReader(reader).readCommandResult(command); - return Boolean.TRUE; - } - }); - } -}
diff --git a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/apiary/TurnConfigClient.java b/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/apiary/TurnConfigClient.java deleted file mode 100644 index 2b26938..0000000 --- a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/apiary/TurnConfigClient.java +++ /dev/null
@@ -1,76 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.components.devtools_bridge.apiary; - -import android.util.JsonReader; - -import org.apache.http.client.HttpClient; -import org.apache.http.client.methods.HttpGet; - -import org.chromium.components.devtools_bridge.RTCConfiguration; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -/** - * Client for fetching TURN configuration form a demo server. - */ -public final class TurnConfigClient { - private static final String URL = - "http://computeengineondemand.appspot.com/turn?username=28230128&key=4080218913"; - private static final String STUN_URL = "stun.l.google.com:19302"; - - private final HttpClient mHttpClient; - - TurnConfigClient(HttpClient httpClient) { - mHttpClient = httpClient; - } - - public RTCConfiguration fetch() throws IOException { - return mHttpClient.execute( - new HttpGet(URL), new ConfigResponseHandler()); - } - - private class ConfigResponseHandler extends JsonResponseHandler<RTCConfiguration> { - public RTCConfiguration readResponse(JsonReader reader) throws IOException { - List<String> uris = null; - String username = null; - String password = null; - - reader.beginObject(); - while (reader.hasNext()) { - String name = reader.nextName(); - if ("username".equals(name)) { - username = reader.nextString(); - } else if ("password".equals(name)) { - password = reader.nextString(); - } else if ("uris".equals(name)) { - uris = readStringList(reader); - } else { - reader.skipValue(); - } - } - reader.endObject(); - - RTCConfiguration.Builder builder = new RTCConfiguration.Builder(); - builder.addIceServer(STUN_URL); - for (String uri : uris) { - builder.addIceServer(uri, username, password); - } - return builder.build(); - } - } - - private List<String> readStringList(JsonReader reader) throws IOException { - ArrayList<String> result = new ArrayList<String>(); - reader.beginArray(); - while (reader.hasNext()) { - result.add(reader.nextString()); - } - reader.endArray(); - return result; - } -}
diff --git a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/commands/CommandSender.java b/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/commands/CommandSender.java deleted file mode 100644 index 2bb4d7d..0000000 --- a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/commands/CommandSender.java +++ /dev/null
@@ -1,75 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.components.devtools_bridge.commands; - -import org.chromium.components.devtools_bridge.RTCConfiguration; -import org.chromium.components.devtools_bridge.SessionBase; -import org.chromium.components.devtools_bridge.SignalingReceiver; - -import java.util.List; - -/** - * Implementation of SignalingReceiver which wraps each call into a Command object. - */ -public abstract class CommandSender implements SignalingReceiver { - protected abstract void send(Command command, Runnable completionCallback); - - @Override - public void startSession( - String sessionId, RTCConfiguration config, String offer, - final SessionBase.NegotiationCallback callback) { - final Commands.StartSessionCommand command = - new Commands.StartSessionCommand(sessionId, config, offer); - send(command, new Runnable() { - @Override - public void run() { - if (!handleFailure(command, callback)) { - callback.onSuccess(command.getResult()); - } - } - }); - } - - @Override - public void renegotiate( - String sessionId, String offer, final SessionBase.NegotiationCallback callback) { - final Commands.RenegotiateCommand command = - new Commands.RenegotiateCommand(sessionId, offer); - send(command, new Runnable() { - @Override - public void run() { - if (!handleFailure(command, callback)) { - callback.onSuccess(command.getResult()); - } - } - }); - } - - @Override - public void iceExchange( - String sessionId, List<String> clientCandidates, - final SessionBase.IceExchangeCallback callback) { - final Commands.IceExchangeCommand command = - new Commands.IceExchangeCommand(sessionId, clientCandidates); - send(command, new Runnable() { - @Override - public void run() { - if (!handleFailure(command, callback)) { - callback.onSuccess(command.getResult()); - } - } - }); - } - - private static boolean handleFailure(Command command, SessionBase.ServerCallback callback) { - if (command.state() == Command.State.DONE) return false; - if (command.state() == Command.State.ERROR) { - callback.onFailure(command.getErrorMessage()); - } else { - callback.onFailure("Invalid command state: " + command.state()); - } - return true; - } -}
diff --git a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/gcd/RemoteInstance.java b/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/gcd/RemoteInstance.java deleted file mode 100644 index 7379bd5..0000000 --- a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/gcd/RemoteInstance.java +++ /dev/null
@@ -1,26 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.components.devtools_bridge.gcd; - -/** - * Remote DevTools bridge instance (for testing app). - */ -public final class RemoteInstance { - public final String id; - public final String displayName; - - public RemoteInstance(String id, String displayName) { - assert id != null; - assert displayName != null; - - this.id = id; - this.displayName = displayName; - } - - @Override - public String toString() { - return displayName + ": " + id; - } -}
diff --git a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/gcd/TestMessageReader.java b/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/gcd/TestMessageReader.java deleted file mode 100644 index 3505af8..0000000 --- a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/gcd/TestMessageReader.java +++ /dev/null
@@ -1,124 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.components.devtools_bridge.gcd; - -import android.util.JsonReader; -import android.util.Log; - -import org.chromium.components.devtools_bridge.commands.Command; -import org.chromium.components.devtools_bridge.commands.CommandFormatException; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -/** - * Reader for additional messages (used only in the testing app). - */ -public final class TestMessageReader { - private static final String TAG = "TestMessageReader"; - - private final JsonReader mReader; - - public TestMessageReader(JsonReader reader) { - mReader = reader; - } - - public List<RemoteInstance> readRemoteInstances() throws IOException { - final List<RemoteInstance> result = new ArrayList<RemoteInstance>(); - - mReader.beginObject(); - while (mReader.hasNext()) { - String name = mReader.nextName(); - if (name.equals("devices")) { - mReader.beginArray(); - while (mReader.hasNext()) { - result.add(readInstance()); - } - mReader.endArray(); - } else { - mReader.skipValue(); - } - } - mReader.endObject(); - return result; - } - - private RemoteInstance readInstance() throws IOException { - String id = null; - String displayName = null; - - mReader.beginObject(); - while (mReader.hasNext()) { - String name = mReader.nextName(); - if (name.equals("id")) { - id = mReader.nextString(); - } else if (name.equals("displayName")) { - displayName = mReader.nextString(); - } else { - mReader.skipValue(); - } - } - mReader.endObject(); - if (id == null) { - throw new IllegalArgumentException("Missing remote instance id"); - } - if (displayName == null) { - throw new IllegalArgumentException("Missing remote instance display name"); - } - return new RemoteInstance(id, displayName); - } - - public void readCommandResult(Command command) throws IOException { - String state = null; - Map<String, String> outParams = null; - String errorMessage = null; - - mReader.beginObject(); - while (mReader.hasNext()) { - String name = mReader.nextName(); - if (name.equals("state")) { - state = mReader.nextString(); - } else if (name.equals("results")) { - outParams = MessageReader.readStringMap(mReader); - } else if (name.equals("error")) { - errorMessage = readErrorMessage(); - } else { - mReader.skipValue(); - } - } - mReader.endObject(); - - if ("done".equals(state) && outParams != null) { - try { - command.setSuccess(outParams); - } catch (CommandFormatException e) { - Log.e(TAG, "Invalid command format", e); - command.setFailure("Invalid format: " + e.getMessage()); - } - } else if ("error".equals(state) && errorMessage != null) { - Log.w(TAG, "Command error: " + errorMessage); - command.setFailure(errorMessage); - } else { - Log.w(TAG, "Invalid command state: " + state); - command.setFailure("Invalid state: " + state); - } - } - - private String readErrorMessage() throws IOException { - String result = null; - mReader.beginObject(); - while (mReader.hasNext()) { - if (mReader.nextName().equals("message")) { - result = mReader.nextString(); - } else { - mReader.skipValue(); - } - } - mReader.endObject(); - return result; - } -}
diff --git a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/gcd/TestMessageWriter.java b/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/gcd/TestMessageWriter.java deleted file mode 100644 index 1d4d75b7..0000000 --- a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/gcd/TestMessageWriter.java +++ /dev/null
@@ -1,65 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.components.devtools_bridge.gcd; - -import android.util.JsonWriter; - -import org.chromium.components.devtools_bridge.commands.Command; -import org.chromium.components.devtools_bridge.commands.ParamDefinition; - -import java.io.IOException; -import java.io.StringWriter; - -/** - * Helper class for constructing GCD JSON messages (HTTP requests) used in the DevTools bridge. - */ -public final class TestMessageWriter { - private final StringWriter mStringWriter; - private final JsonWriter mWriter; - boolean mClosed = false; - - public TestMessageWriter() { - mStringWriter = new StringWriter(); - mWriter = new JsonWriter(mStringWriter); - } - - public TestMessageWriter close() throws IOException { - assert !mClosed; - mWriter.close(); - mClosed = true; - return this; - } - - @Override - public String toString() { - assert mClosed; - return mStringWriter.toString(); - } - - public TestMessageWriter writeCommand( - String remoteInstanceId, Command command) throws IOException { - mWriter.beginObject() - .name("deviceId").value(remoteInstanceId) - .name("name").value(command.type.definition.fullName()); - - mWriter.name("parameters").beginObject(); - command.visitInParams(new Command.ParamVisitor() { - @Override - public void visit(ParamDefinition<?> param, String value) { - try { - mWriter.name(param.name()).value(value); - } catch (IOException e) { - // IO excepion must not happen since we writng to a string. - throw new RuntimeException(e); - } - } - }); - mWriter.endObject(); - - mWriter.endObject(); - - return this; - } -}
diff --git a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/ui/RemoteInstanceListFragment.java b/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/ui/RemoteInstanceListFragment.java deleted file mode 100644 index 8441da0e..0000000 --- a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/ui/RemoteInstanceListFragment.java +++ /dev/null
@@ -1,350 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.components.devtools_bridge.ui; - -import android.accounts.Account; -import android.accounts.AccountManager; -import android.accounts.AccountManagerCallback; -import android.accounts.AccountManagerFuture; -import android.app.Activity; -import android.app.ListFragment; -import android.content.Intent; -import android.os.AsyncTask; -import android.os.Bundle; -import android.util.Log; -import android.view.ContextMenu; -import android.view.LayoutInflater; -import android.view.MenuItem; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ArrayAdapter; -import android.widget.ListView; -import android.widget.Toast; - -import org.chromium.components.devtools_bridge.RTCConfiguration; -import org.chromium.components.devtools_bridge.SessionBase; -import org.chromium.components.devtools_bridge.apiary.ApiaryClientFactory; -import org.chromium.components.devtools_bridge.apiary.TestApiaryClientFactory; -import org.chromium.components.devtools_bridge.commands.Command; -import org.chromium.components.devtools_bridge.commands.CommandSender; -import org.chromium.components.devtools_bridge.gcd.RemoteInstance; - -import java.io.IOException; -import java.util.List; - -/** - * Fragment of application for manual testing the DevTools bridge. Shows instances - * registered in GCD and lets unregister them. - */ -public abstract class RemoteInstanceListFragment extends ListFragment { - private static final String TAG = "RemoteInstanceListFragment"; - private static final String NO_ID = ""; - private static final int CODE_ACCOUNT_SELECTED = 1; - - private final TestApiaryClientFactory mClientFactory = new TestApiaryClientFactory(); - private ArrayAdapter<RemoteInstance> mListAdapter; - private String mOAuthToken; - private RemoteInstance mSelected; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - mListAdapter = new ArrayAdapter<RemoteInstance>( - getActivity(), android.R.layout.simple_list_item_1); - new UpdateListAction().execute(); - setListAdapter(mListAdapter); - } - - @Override - public void onDestroy() { - new AsyncTask<Void, Void, Void>() { - @Override - protected final Void doInBackground(Void... args) { - mClientFactory.close(); - return null; - } - }.execute(); - super.onDestroy(); - } - - @Override - public View onCreateView( - LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View root = super.onCreateView(inflater, container, savedInstanceState); - registerForContextMenu(root); - return root; - } - - @Override - public void onListItemClick(ListView listView, View view, int position, long id) { - mSelected = mListAdapter.getItem(position); - if (mOAuthToken == null) { - signIn(); - } else { - getActivity().openContextMenu(view); - } - } - - @Override - public void onCreateContextMenu( - ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) { - super.onCreateContextMenu(menu, view, menuInfo); - - if (mOAuthToken == null) return; - - menu.add("Connect") - .setOnMenuItemClickListener(new ConnectAction()) - .setEnabled(mSelected != null); - menu.add("Send invalid offer") - .setOnMenuItemClickListener(new SendInvalidOfferAction()) - .setEnabled(mSelected != null); - menu.add("Delete") - .setOnMenuItemClickListener(new DeleteInstanceAction(mSelected)) - .setEnabled(mSelected != null); - menu.add("Update list") - .setOnMenuItemClickListener(new UpdateListAction()); - menu.add("Delete all") - .setOnMenuItemClickListener(new DeleteAllAction()); - } - - public void signIn() { - AccountManager manager = AccountManager.get(getActivity()); - - Intent intent = manager.newChooseAccountIntent( - null /* selectedAccount */, - null /* allowableAccounts */, - new String[] { "com.google" } /* allowableAccountTypes */, - true /* alwaysPromptForAccount */, - "Sign into GCD" /* descriptionOverrideText */, - null /* addAccountAuthTokenType */, - null /* addAccountRequiredFeatures */, - null /* addAccountOptions */); - startActivityForResult(intent, CODE_ACCOUNT_SELECTED); - } - - @Override - public void onActivityResult(final int requestCode, final int resultCode, final Intent data) { - if (requestCode == CODE_ACCOUNT_SELECTED && resultCode == Activity.RESULT_OK) { - queryOAuthToken(new Account( - data.getStringExtra(AccountManager.KEY_ACCOUNT_NAME), - data.getStringExtra(AccountManager.KEY_ACCOUNT_TYPE))); - } - } - - protected abstract void connect(String oAuthToken, String remoteInstanceId); - - public void queryOAuthToken(Account accout) { - AccountManager manager = AccountManager.get(getActivity()); - - manager.getAuthToken( - accout, - "oauth2:" + ApiaryClientFactory.OAUTH_SCOPE, null /* options */, getActivity(), - new AccountManagerCallback<Bundle>() { - @Override - public void run(AccountManagerFuture<Bundle> future) { - try { - mOAuthToken = future.getResult().getString( - AccountManager.KEY_AUTHTOKEN); - updateList(); - } catch (Exception e) { - Log.d(TAG, "Failed to get token: ", e); - } - } - }, null); - } - - public void updateList() { - new UpdateListAction().execute(); - } - - private final class ConnectAction implements MenuItem.OnMenuItemClickListener { - @Override - public boolean onMenuItemClick(MenuItem item) { - if (mOAuthToken != null && mSelected != null) { - connect(mOAuthToken, mSelected.id); - return true; - } - return false; - } - } - - private abstract class AsyncAction extends AsyncTask<Void, Void, Boolean> - implements MenuItem.OnMenuItemClickListener { - private final String mActionName; - - protected AsyncAction(String actionName) { - mActionName = actionName; - } - - @Override - public boolean onMenuItemClick(MenuItem item) { - execute(); - return true; - } - - @Override - protected final Boolean doInBackground(Void... args) { - try { - doInBackgroundImpl(); - return Boolean.TRUE; - } catch (IOException e) { - Log.e(TAG, mActionName + " failed", e); - return Boolean.FALSE; - } - } - - @Override - protected void onPostExecute(Boolean success) { - if (Boolean.TRUE.equals(success)) { - onSuccess(); - showToast(mActionName + " completed"); - } else { - onFailure(); - showToast(mActionName + " failed"); - } - } - - protected void showToast(String message) { - Toast.makeText(getActivity(), message, Toast.LENGTH_SHORT).show(); - } - - protected abstract void doInBackgroundImpl() throws IOException; - protected abstract void onSuccess(); - protected void onFailure() {} - } - - private final class SendInvalidOfferAction extends AsyncAction { - private final String mOAuthTokenCopy = mOAuthToken; - private final RemoteInstance mSelectedCopy = mSelected; - private IOException mException; - - public SendInvalidOfferAction() { - super("Sending invalid offer"); - } - - @Override - protected final void doInBackgroundImpl() throws IOException { - if (mOAuthTokenCopy == null || mSelected == null) { - throw new IOException("Action cann't be applied."); - } - - final String sessionId = "sessionId"; - final String offer = "INVALID_OFFER"; - final RTCConfiguration config = new RTCConfiguration(); - - CommandSender sender = new CommandSender() { - @Override - protected void send(Command command, Runnable completionCallback) { - try { - mClientFactory.newTestGCDClient(mOAuthTokenCopy) - .send(mSelectedCopy.id, command); - } catch (IOException e) { - mException = e; - command.setFailure("IO exception"); - } finally { - completionCallback.run(); - } - } - }; - - sender.startSession(sessionId, config, offer, new SessionBase.NegotiationCallback() { - @Override - public void onSuccess(String answer) { - mException = new IOException("Unexpected success"); - } - - @Override - public void onFailure(String errorMessage) { - Log.i(TAG, "Expected failure: " + errorMessage); - } - }); - - if (mException != null) - throw mException; - } - - @Override - protected void onSuccess() { - } - } - - private final class UpdateListAction extends AsyncAction { - private final String mOAuthTokenCopy = mOAuthToken; - private List<RemoteInstance> mResult; - - public UpdateListAction() { - super("Updating instance list"); - } - - @Override - protected final void doInBackgroundImpl() throws IOException { - if (mOAuthTokenCopy == null) return; - - mResult = mClientFactory.newTestGCDClient(mOAuthTokenCopy).fetchInstances(); - } - - @Override - protected void onSuccess() { - mListAdapter.clear(); - if (mOAuthTokenCopy == null) { - mListAdapter.add(new RemoteInstance(NO_ID, "Sign in")); - } else if (mResult.size() > 0) { - mListAdapter.addAll(mResult); - } else { - mListAdapter.add(new RemoteInstance(NO_ID, "Empty list")); - } - } - - @Override - protected void onFailure() { - mListAdapter.clear(); - mListAdapter.add(new RemoteInstance(NO_ID, "Update failed")); - } - - @Override - protected void showToast(String message) {} - } - - private final class DeleteInstanceAction extends AsyncAction { - private final String mOAuthTokenCopy = mOAuthToken; - private final RemoteInstance mInstance; - - public DeleteInstanceAction(RemoteInstance instance) { - super("Deleting instance"); - mInstance = instance; - } - - @Override - protected final void doInBackgroundImpl() throws IOException { - mClientFactory.newTestGCDClient(mOAuthTokenCopy).deleteInstance(mInstance.id); - } - - @Override - protected void onSuccess() { - updateList(); - } - } - - private final class DeleteAllAction extends AsyncAction { - private final String mOAuthTokenCopy = mOAuthToken; - - public DeleteAllAction() { - super("Deleting all"); - } - - @Override - protected final void doInBackgroundImpl() throws IOException { - for (RemoteInstance instance : - mClientFactory.newTestGCDClient(mOAuthTokenCopy).fetchInstances()) { - mClientFactory.newTestGCDClient(mOAuthTokenCopy).deleteInstance(instance.id); - } - } - - @Override - protected void onSuccess() { - updateList(); - } - } -}
diff --git a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/util/TestSource.java b/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/util/TestSource.java deleted file mode 100644 index 9a53a39f..0000000 --- a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/util/TestSource.java +++ /dev/null
@@ -1,32 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.components.devtools_bridge.util; - -import android.util.JsonReader; -import android.util.JsonWriter; - -import java.io.StringReader; -import java.io.StringWriter; - -/** - * Helper class for testing JSON-based readers. - */ -public class TestSource { - private final StringWriter mSource; - private final JsonWriter mSourceWriter; - - public TestSource() { - mSource = new StringWriter(); - mSourceWriter = new JsonWriter(mSource); - } - - public JsonReader read() { - return new JsonReader(new StringReader(mSource.toString())); - } - - public JsonWriter write() { - return mSourceWriter; - } -}
diff --git a/components/devtools_http_handler/devtools_http_handler.cc b/components/devtools_http_handler/devtools_http_handler.cc index 3c9a8e77..67c061c7c 100644 --- a/components/devtools_http_handler/devtools_http_handler.cc +++ b/components/devtools_http_handler/devtools_http_handler.cc
@@ -813,13 +813,11 @@ // Serialize value and message. std::string json_value; if (value) { - base::JSONWriter::WriteWithOptions(value, - base::JSONWriter::OPTIONS_PRETTY_PRINT, - &json_value); + base::JSONWriter::WriteWithOptions( + *value, base::JSONWriter::OPTIONS_PRETTY_PRINT, &json_value); } std::string json_message; - scoped_ptr<base::Value> message_object(new base::StringValue(message)); - base::JSONWriter::Write(message_object.get(), &json_message); + base::JSONWriter::Write(base::StringValue(message), &json_message); net::HttpServerResponseInfo response(status_code); response.SetBody(json_value + message, "application/json; charset=UTF-8");
diff --git a/components/dom_distiller/core/distiller_page.cc b/components/dom_distiller/core/distiller_page.cc index 8eb6585..74e6f1c 100644 --- a/components/dom_distiller/core/distiller_page.cc +++ b/components/dom_distiller/core/distiller_page.cc
@@ -40,7 +40,7 @@ scoped_ptr<base::Value> options_value( dom_distiller::proto::json::DomDistillerOptions::WriteToValue(options)); std::string options_json; - if (!base::JSONWriter::Write(options_value.get(), &options_json)) { + if (!base::JSONWriter::Write(*options_value, &options_json)) { NOTREACHED(); } size_t options_offset = script.find(kOptionsPlaceholder);
diff --git a/components/dom_distiller/core/page_features_unittest.cc b/components/dom_distiller/core/page_features_unittest.cc index 413c55f7..1fee593 100644 --- a/components/dom_distiller/core/page_features_unittest.cc +++ b/components/dom_distiller/core/page_features_unittest.cc
@@ -70,7 +70,7 @@ // CalculateDerivedFeaturesFromJSON expects a base::Value of the stringified // JSON (and not a base::Value of the JSON itself) std::string stringified_json; - ASSERT_TRUE(base::JSONWriter::Write(core_features, &stringified_json)); + ASSERT_TRUE(base::JSONWriter::Write(*core_features, &stringified_json)); scoped_ptr<base::Value> stringified_value( new base::StringValue(stringified_json)); std::vector<double> derived(
diff --git a/components/dom_distiller/core/viewer.cc b/components/dom_distiller/core/viewer.cc index e19f378..0244a4f51 100644 --- a/components/dom_distiller/core/viewer.cc +++ b/components/dom_distiller/core/viewer.cc
@@ -159,9 +159,9 @@ std::string yes; std::string no; - base::JSONWriter::Write(&question_val, &question); - base::JSONWriter::Write(&yes_val, &yes); - base::JSONWriter::Write(&no_val, &no); + base::JSONWriter::Write(question_val, &question); + base::JSONWriter::Write(yes_val, &yes); + base::JSONWriter::Write(no_val, &no); return "showFeedbackForm(" + question + ", " + yes + ", " + no + ");"; } @@ -172,7 +172,7 @@ std::string output(page_proto->html()); EnsureNonEmptyContent(&output); base::StringValue value(output); - base::JSONWriter::Write(&value, &output); + base::JSONWriter::Write(value, &output); std::string page_update("addToPage("); page_update += output + ");"; return page_update + GetToggleLoadingIndicatorJs( @@ -184,7 +184,7 @@ base::StringValue value(l10n_util::GetStringUTF8( IDS_DOM_DISTILLER_VIEWER_FAILED_TO_FIND_ARTICLE_CONTENT)); std::string output; - base::JSONWriter::Write(&value, &output); + base::JSONWriter::Write(value, &output); std::string page_update("addToPage("); page_update += output + ");"; return page_update; @@ -226,8 +226,7 @@ std::string output(unsafe_output_stream.str()); EnsureNonEmptyContent(&output); - base::StringValue value(output); - base::JSONWriter::Write(&value, &output); + base::JSONWriter::Write(base::StringValue(output), &output); std::string page_update("addToPage("); page_update += output + ");"; return page_update + GetToggleLoadingIndicatorJs(true);
diff --git a/components/domain_reliability/context.cc b/components/domain_reliability/context.cc index 230581f..5a35090 100644 --- a/components/domain_reliability/context.cc +++ b/components/domain_reliability/context.cc
@@ -223,9 +223,7 @@ DCHECK(upload_time_.is_null()); upload_time_ = time_->NowTicks(); std::string report_json; - scoped_ptr<const Value> report_value(CreateReport(upload_time_)); - base::JSONWriter::Write(report_value.get(), &report_json); - report_value.reset(); + base::JSONWriter::Write(*CreateReport(upload_time_), &report_json); size_t collector_index = scheduler_.OnUploadStart(); @@ -281,7 +279,7 @@ resources_value->Append(resource_report.release()); } - DictionaryValue* report_value = new DictionaryValue(); + scoped_ptr<DictionaryValue> report_value(new DictionaryValue()); if (!config().version.empty()) report_value->SetString("config_version", config().version); report_value->SetString("reporter", upload_reporter_string_); @@ -289,7 +287,7 @@ if (!resources_value->empty()) report_value->Set("resources", resources_value.release()); - return scoped_ptr<const Value>(report_value); + return report_value.Pass(); } void DomainReliabilityContext::MarkUpload() {
diff --git a/components/domain_reliability/monitor.cc b/components/domain_reliability/monitor.cc index 83a6af19..014f34d 100644 --- a/components/domain_reliability/monitor.cc +++ b/components/domain_reliability/monitor.cc
@@ -11,7 +11,10 @@ #include "base/task_runner.h" #include "base/time/time.h" #include "components/domain_reliability/baked_in_configs.h" +#include "net/base/ip_endpoint.h" #include "net/base/load_flags.h" +#include "net/base/net_errors.h" +#include "net/base/net_util.h" #include "net/http/http_response_headers.h" #include "net/url_request/url_request.h" #include "net/url_request/url_request_context.h" @@ -19,6 +22,55 @@ namespace domain_reliability { +namespace { + +int URLRequestStatusToNetError(const net::URLRequestStatus& status) { + switch (status.status()) { + case net::URLRequestStatus::SUCCESS: + return net::OK; + case net::URLRequestStatus::IO_PENDING: + return net::ERR_IO_PENDING; + case net::URLRequestStatus::CANCELED: + return net::ERR_ABORTED; + case net::URLRequestStatus::FAILED: + return status.error(); + default: + NOTREACHED(); + return net::ERR_UNEXPECTED; + } +} + +// Updates the status, chrome_error, and server_ip fields of |beacon| from +// the endpoint and result of |attempt|. If there is no matching status for +// the result, returns false (which means the attempt should not result in a +// beacon being reported). +bool UpdateBeaconFromAttempt(DomainReliabilityBeacon* beacon, + const net::ConnectionAttempt& attempt) { + if (!GetDomainReliabilityBeaconStatus( + attempt.result, beacon->http_response_code, &beacon->status)) { + return false; + } + beacon->chrome_error = attempt.result; + if (!attempt.endpoint.address().empty()) + beacon->server_ip = attempt.endpoint.ToString(); + else + beacon->server_ip = ""; + return true; +} + +// TODO(ttuttle): This function is absurd. See if |socket_address| in +// HttpResponseInfo can become an IPEndPoint. +bool ConvertHostPortPairToIPEndPoint(const net::HostPortPair& host_port_pair, + net::IPEndPoint* ip_endpoint_out) { + net::IPAddressNumber ip_address_number; + if (!net::ParseIPLiteralToNumber(host_port_pair.host(), &ip_address_number)) + return false; + *ip_endpoint_out = net::IPEndPoint(ip_address_number, host_port_pair.port()); + return true; +} + +} // namespace + DomainReliabilityMonitor::DomainReliabilityMonitor( const std::string& upload_reporter_string, const scoped_refptr<base::SingleThreadTaskRunner>& pref_thread, @@ -150,8 +202,9 @@ if (!started) return; RequestInfo request_info(*request); - if (request_info.AccessedNetwork()) { - OnRequestLegComplete(request_info); + OnRequestLegComplete(request_info); + + if (request_info.response_info.network_accessed) { // A request was just using the network, so now is a good time to run any // pending and eligible uploads. dispatcher_.RunEligibleTasks(); @@ -221,13 +274,27 @@ load_flags(request.load_flags()), is_upload(DomainReliabilityUploader::URLRequestIsUpload(request)) { request.GetLoadTimingInfo(&load_timing_info); + request.GetConnectionAttempts(&connection_attempts); } DomainReliabilityMonitor::RequestInfo::~RequestInfo() {} -bool DomainReliabilityMonitor::RequestInfo::AccessedNetwork() const { - return status.status() != net::URLRequestStatus::CANCELED && - response_info.network_accessed; +// static +bool DomainReliabilityMonitor::RequestInfo::ShouldReportRequest( + const DomainReliabilityMonitor::RequestInfo& request) { + // Don't report requests for Domain Reliability uploads or that weren't + // supposed to send cookies. + if (request.is_upload) + return false; + if (request.load_flags & net::LOAD_DO_NOT_SEND_COOKIES) + return false; + // Report requests that accessed the network or failed with an error code + // that Domain Reliability is interested in. + if (request.response_info.network_accessed) + return true; + if (URLRequestStatusToNetError(request.status) != net::OK) + return true; + return false; } void DomainReliabilityMonitor::OnRequestLegComplete( @@ -236,44 +303,30 @@ DCHECK(OnNetworkThread()); DCHECK(discard_uploads_set_); + if (!RequestInfo::ShouldReportRequest(request)) + return; + int response_code; if (request.response_info.headers.get()) response_code = request.response_info.headers->response_code(); else response_code = -1; - std::string beacon_status; - int error_code = net::OK; - if (request.status.status() == net::URLRequestStatus::FAILED) - error_code = request.status.error(); - - // Ignore requests where: - // 1. The request did not access the network. - // 2. The request is not supposed to send cookies (to avoid associating the - // request with any potentially unique data in the config). - // 3. The request was itself a Domain Reliability upload (to avoid loops). - // 4. There is no matching beacon status for the error or HTTP response code - // (to avoid leaking network-local errors). - if (!request.AccessedNetwork() || - (request.load_flags & net::LOAD_DO_NOT_SEND_COOKIES) || - request.is_upload || - !GetDomainReliabilityBeaconStatus( - error_code, response_code, &beacon_status)) { - return; - } - - DomainReliabilityBeacon beacon; - beacon.status = beacon_status; - beacon.chrome_error = error_code; - // If the response was cached, the socket address was the address that the - // response was originally received from, so it shouldn't be copied into the - // beacon. - // - // TODO(ttuttle): Wire up a way to get the real socket address in that case. + net::IPEndPoint url_request_endpoint; + // If response was cached, socket address will be from the serialized + // response info in the cache, so don't report it. + // TODO(ttuttle): Plumb out the "current" socket address so we can always + // report it. if (!request.response_info.was_cached && !request.response_info.was_fetched_via_proxy) { - beacon.server_ip = request.response_info.socket_address.host(); + ConvertHostPortPairToIPEndPoint(request.response_info.socket_address, + &url_request_endpoint); } + + net::ConnectionAttempt url_request_attempt( + url_request_endpoint, URLRequestStatusToNetError(request.status)); + + DomainReliabilityBeacon beacon; beacon.protocol = GetDomainReliabilityProtocol( request.response_info.connection_info, request.response_info.ssl_info.is_valid()); @@ -282,6 +335,25 @@ beacon.elapsed = time_->NowTicks() - beacon.start_time; beacon.was_proxied = request.response_info.was_fetched_via_proxy; beacon.domain = request.url.host(); + + // This is not foolproof -- it's possible that we'll see the same error twice + // (e.g. an SSL error during connection on one attempt, and then an error + // that maps to the same code during a read). + // TODO(ttuttle): Find a way for this code to reliably tell whether we + // eventually established a connection or not. + bool url_request_attempt_is_duplicate = false; + for (const auto& attempt : request.connection_attempts) { + if (attempt.result == url_request_attempt.result) + url_request_attempt_is_duplicate = true; + if (!UpdateBeaconFromAttempt(&beacon, attempt)) + continue; + context_manager_.RouteBeacon(request.url, beacon); + } + + if (url_request_attempt_is_duplicate) + return; + if (!UpdateBeaconFromAttempt(&beacon, url_request_attempt)) + return; context_manager_.RouteBeacon(request.url, beacon); }
diff --git a/components/domain_reliability/monitor.h b/components/domain_reliability/monitor.h index 6fd0bfbf..5260f9f 100644 --- a/components/domain_reliability/monitor.h +++ b/components/domain_reliability/monitor.h
@@ -25,6 +25,7 @@ #include "net/base/load_timing_info.h" #include "net/base/network_change_notifier.h" #include "net/http/http_response_info.h" +#include "net/socket/connection_attempts.h" #include "net/url_request/url_request_status.h" namespace base { @@ -137,13 +138,14 @@ explicit RequestInfo(const net::URLRequest& request); ~RequestInfo(); - bool AccessedNetwork() const; + static bool ShouldReportRequest(const RequestInfo& request); GURL url; net::URLRequestStatus status; net::HttpResponseInfo response_info; int load_flags; net::LoadTimingInfo load_timing_info; + net::ConnectionAttempts connection_attempts; bool is_upload; };
diff --git a/components/error_page/renderer/net_error_helper_core.cc b/components/error_page/renderer/net_error_helper_core.cc index 9a92d74..0c89ec3c 100644 --- a/components/error_page/renderer/net_error_helper_core.cc +++ b/components/error_page/renderer/net_error_helper_core.cc
@@ -198,7 +198,7 @@ request_dict.Set("params", params_dict.release()); std::string request_body; - bool success = base::JSONWriter::Write(&request_dict, &request_body); + bool success = base::JSONWriter::Write(request_dict, &request_body); DCHECK(success); return request_body; }
diff --git a/components/error_page/renderer/net_error_helper_core_unittest.cc b/components/error_page/renderer/net_error_helper_core_unittest.cc index 97897fb3..5ec9377 100644 --- a/components/error_page/renderer/net_error_helper_core_unittest.cc +++ b/components/error_page/renderer/net_error_helper_core_unittest.cc
@@ -84,13 +84,13 @@ for (int i = 0; i < num_corrections; ++i) url_corrections->Append(corrections[i].ToValue()); - scoped_ptr<base::DictionaryValue> response(new base::DictionaryValue()); - response->Set("result.UrlCorrections", url_corrections); - response->SetString("result.eventId", kNavigationCorrectionEventId); - response->SetString("result.fingerprint", kNavigationCorrectionFingerprint); + base::DictionaryValue response; + response.Set("result.UrlCorrections", url_corrections); + response.SetString("result.eventId", kNavigationCorrectionEventId); + response.SetString("result.fingerprint", kNavigationCorrectionFingerprint); std::string json; - base::JSONWriter::Write(response.get(), &json); + base::JSONWriter::Write(response, &json); return json; }
diff --git a/components/gcm_driver/instance_id/instance_id_driver.cc b/components/gcm_driver/instance_id/instance_id_driver.cc index edb5270..3377b3b 100644 --- a/components/gcm_driver/instance_id/instance_id_driver.cc +++ b/components/gcm_driver/instance_id/instance_id_driver.cc
@@ -4,26 +4,17 @@ #include "components/gcm_driver/instance_id/instance_id_driver.h" -#include "base/metrics/field_trial.h" #include "components/gcm_driver/instance_id/instance_id.h" namespace instance_id { -namespace { -#if !defined(OS_ANDROID) -const char kInstanceIDFieldTrialName[] = "InstanceID"; -const char kInstanceIDFieldTrialEnabledGroupName[] = "Enabled"; -#endif // !defined(OS_ANDROID) -} // namespace - // static bool InstanceIDDriver::IsInstanceIDEnabled() { #if defined(OS_ANDROID) - return true; + // Not implemented yet. + return false; #else - std::string group_name = - base::FieldTrialList::FindFullName(kInstanceIDFieldTrialName); - return group_name == kInstanceIDFieldTrialEnabledGroupName; + return true; #endif // defined(OS_ANDROID) }
diff --git a/components/history/core/browser/delete_directive_handler.cc b/components/history/core/browser/delete_directive_handler.cc index 0aba13f..71d7f03 100644 --- a/components/history/core/browser/delete_directive_handler.cc +++ b/components/history/core/browser/delete_directive_handler.cc
@@ -32,7 +32,7 @@ scoped_ptr<base::DictionaryValue> value( syncer::HistoryDeleteDirectiveSpecificsToValue(delete_directive)); std::string str; - base::JSONWriter::Write(value.get(), &str); + base::JSONWriter::Write(*value, &str); return str; }
diff --git a/components/history/core/browser/web_history_service.cc b/components/history/core/browser/web_history_service.cc index 4a8b3aa7f..b4047f6b 100644 --- a/components/history/core/browser/web_history_service.cc +++ b/components/history/core/browser/web_history_service.cc
@@ -362,7 +362,7 @@ } delete_request.Set("del", deletions.release()); std::string post_data; - base::JSONWriter::Write(&delete_request, &post_data); + base::JSONWriter::Write(delete_request, &post_data); GURL url(kHistoryDeleteHistoryUrl); @@ -426,7 +426,7 @@ new_enabled_value); enable_audio_history.SetString("client", "audio"); std::string post_data; - base::JSONWriter::Write(&enable_audio_history, &post_data); + base::JSONWriter::Write(enable_audio_history, &post_data); request->SetPostData(post_data); request->Start();
diff --git a/components/html_viewer/blink_url_request_type_converters.cc b/components/html_viewer/blink_url_request_type_converters.cc index 920583c..9e6a40d 100644 --- a/components/html_viewer/blink_url_request_type_converters.cc +++ b/components/html_viewer/blink_url_request_type_converters.cc
@@ -26,17 +26,17 @@ if (LowerCaseEqualsASCII(name_latin1, "accept")) has_accept_header_ = true; - HTTPHeaderPtr header = HTTPHeader::New(); + HttpHeaderPtr header = HttpHeader::New(); header->name = name_latin1; header->value = value_latin1; buffer_.push_back(header.Pass()); } - Array<HTTPHeaderPtr> GetBuffer() { + Array<HttpHeaderPtr> GetBuffer() { // In some cases, WebKit doesn't add an Accept header, but not having the // header confuses some web servers. See bug 808613. if (!has_accept_header_) { - HTTPHeaderPtr header = HTTPHeader::New(); + HttpHeaderPtr header = HttpHeader::New(); header->name = "Accept"; header->value = "*/*"; buffer_.push_back(header.Pass()); @@ -46,7 +46,7 @@ } private: - Array<HTTPHeaderPtr> buffer_; + Array<HttpHeaderPtr> buffer_; bool has_accept_header_; };
diff --git a/components/html_viewer/web_mime_registry_impl.cc b/components/html_viewer/web_mime_registry_impl.cc index 976a777..7954aba7 100644 --- a/components/html_viewer/web_mime_registry_impl.cc +++ b/components/html_viewer/web_mime_registry_impl.cc
@@ -10,6 +10,7 @@ #include "base/strings/utf_string_conversions.h" #include "components/mime_util/mime_util.h" #include "media/base/key_systems.h" +#include "media/base/mime_util.h" #include "media/filters/stream_parser_factory.h" #include "net/base/mime_util.h" #include "third_party/WebKit/public/platform/WebString.h" @@ -63,7 +64,7 @@ const blink::WebString& key_system) { const std::string mime_type_ascii = ToASCIIOrEmpty(mime_type); // Not supporting the container is a flat-out no. - if (!net::IsSupportedMediaMimeType(mime_type_ascii)) + if (!media::IsSupportedMediaMimeType(mime_type_ascii)) return IsNotSupported; // Mojo does not currently support any key systems. @@ -71,18 +72,18 @@ return IsNotSupported; // Check list of strict codecs to see if it is supported. - if (net::IsStrictMediaMimeType(mime_type_ascii)) { + if (media::IsStrictMediaMimeType(mime_type_ascii)) { // Check if the codecs are a perfect match. std::vector<std::string> strict_codecs; - net::ParseCodecString(ToASCIIOrEmpty(codecs), &strict_codecs, false); + media::ParseCodecString(ToASCIIOrEmpty(codecs), &strict_codecs, false); return static_cast<WebMimeRegistry::SupportsType>( - net::IsSupportedStrictMediaMimeType(mime_type_ascii, strict_codecs)); + media::IsSupportedStrictMediaMimeType(mime_type_ascii, strict_codecs)); } // If we don't recognize the codec, it's possible we support it. std::vector<std::string> parsed_codecs; - net::ParseCodecString(ToASCIIOrEmpty(codecs), &parsed_codecs, true); - if (!net::AreSupportedMediaCodecs(parsed_codecs)) + media::ParseCodecString(ToASCIIOrEmpty(codecs), &parsed_codecs, true); + if (!media::AreSupportedMediaCodecs(parsed_codecs)) return MayBeSupported; // Otherwise we have a perfect match. @@ -97,7 +98,7 @@ return false; std::vector<std::string> parsed_codec_ids; - net::ParseCodecString(ToASCIIOrEmpty(codecs), &parsed_codec_ids, false); + media::ParseCodecString(ToASCIIOrEmpty(codecs), &parsed_codec_ids, false); return media::StreamParserFactory::IsTypeSupported(mime_type_ascii, parsed_codec_ids); }
diff --git a/components/invalidation/invalidation_test_util.cc b/components/invalidation/invalidation_test_util.cc index 3368797..6fcd8ef 100644 --- a/components/invalidation/invalidation_test_util.cc +++ b/components/invalidation/invalidation_test_util.cc
@@ -99,9 +99,8 @@ } // namespace void PrintTo(const AckHandle& ack_handle, ::std::ostream* os) { - scoped_ptr<base::Value> value(ack_handle.ToValue()); std::string printable_ack_handle; - base::JSONWriter::Write(value.get(), &printable_ack_handle); + base::JSONWriter::Write(*ack_handle.ToValue(), &printable_ack_handle); *os << "{ ack_handle: " << printable_ack_handle << " }"; }
diff --git a/components/invalidation/invalidation_util.cc b/components/invalidation/invalidation_util.cc index 50e3a5c..d3706f4 100644 --- a/components/invalidation/invalidation_util.cc +++ b/components/invalidation/invalidation_util.cc
@@ -61,9 +61,8 @@ } std::string ObjectIdToString(const invalidation::ObjectId& object_id) { - scoped_ptr<base::DictionaryValue> value(ObjectIdToValue(object_id)); std::string str; - base::JSONWriter::Write(value.get(), &str); + base::JSONWriter::Write(*ObjectIdToValue(object_id), &str); return str; }
diff --git a/components/invalidation/p2p_invalidator.cc b/components/invalidation/p2p_invalidator.cc index c583d44..906a201d 100644 --- a/components/invalidation/p2p_invalidator.cc +++ b/components/invalidation/p2p_invalidator.cc
@@ -102,13 +102,12 @@ } std::string P2PNotificationData::ToString() const { - scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); - dict->SetString(kSenderIdKey, sender_id_); - dict->SetString(kNotificationTypeKey, - P2PNotificationTargetToString(target_)); - dict->Set(kInvalidationsKey, invalidation_map_.ToValue().release()); + base::DictionaryValue dict; + dict.SetString(kSenderIdKey, sender_id_); + dict.SetString(kNotificationTypeKey, P2PNotificationTargetToString(target_)); + dict.Set(kInvalidationsKey, invalidation_map_.ToValue().release()); std::string json; - base::JSONWriter::Write(dict.get(), &json); + base::JSONWriter::Write(dict, &json); return json; }
diff --git a/components/mime_util/BUILD.gn b/components/mime_util/BUILD.gn index 096db1a..0e3a813 100644 --- a/components/mime_util/BUILD.gn +++ b/components/mime_util/BUILD.gn
@@ -12,6 +12,11 @@ "//base", "//net", ] + + # iOS doesn't use and must not depend on //media + if (!is_ios) { + deps += [ "//media" ] + } } source_set("unit_tests") {
diff --git a/components/mime_util/DEPS b/components/mime_util/DEPS index 7e0780e..2b1acf8 100644 --- a/components/mime_util/DEPS +++ b/components/mime_util/DEPS
@@ -3,5 +3,6 @@ # any dependencies on //content "-content", + "+media/base/mime_util.h", # Only for platforms other than iOS "+net/base", ]
diff --git a/components/mime_util/mime_util.cc b/components/mime_util/mime_util.cc index a017f45..5e5d004 100644 --- a/components/mime_util/mime_util.cc +++ b/components/mime_util/mime_util.cc
@@ -9,6 +9,11 @@ #include "base/strings/string_util.h" #include "build/build_config.h" +#if !defined(OS_IOS) +// iOS doesn't use and must not depend on //media +#include "media/base/mime_util.h" +#endif + namespace mime_util { namespace { @@ -153,11 +158,13 @@ bool MimeUtil::IsSupportedNonImageMimeType(const std::string& mime_type) const { return non_image_types_.find(base::StringToLowerASCII(mime_type)) != non_image_types_.end() || +#if !defined(OS_IOS) + media::IsSupportedMediaMimeType(mime_type) || +#endif (StartsWithASCII(mime_type, "text/", false /* case insensitive */) && !IsUnsupportedTextMimeType(mime_type)) || (StartsWithASCII(mime_type, "application/", false) && - net::MatchesMimeType("application/*+json", mime_type)) || - net::IsSupportedMediaMimeType(mime_type); + net::MatchesMimeType("application/*+json", mime_type)); } bool MimeUtil::IsUnsupportedTextMimeType(const std::string& mime_type) const {
diff --git a/components/mime_util/mime_util.gyp b/components/mime_util/mime_util.gyp index 66b4228..c922f98 100644 --- a/components/mime_util/mime_util.gyp +++ b/components/mime_util/mime_util.gyp
@@ -16,6 +16,14 @@ 'mime_util.cc', 'mime_util.h', ], + 'conditions': [ + ['OS!="ios"', { + # iOS doesn't use and must not depend on //media + 'dependencies': [ + '../../media/media.gyp:media', + ], + }], + ], } ], }
diff --git a/components/nacl/renderer/ppb_nacl_private_impl.cc b/components/nacl/renderer/ppb_nacl_private_impl.cc index 5ebc61f..e77b977f 100644 --- a/components/nacl/renderer/ppb_nacl_private_impl.cc +++ b/components/nacl/renderer/ppb_nacl_private_impl.cc
@@ -1190,12 +1190,12 @@ base::JSONReader json_reader; int json_read_error_code; std::string json_read_error_msg; - base::Value* json_data = json_reader.ReadAndReturnError( + scoped_ptr<base::Value> json_data(json_reader.ReadAndReturnError( buffer.get(), base::JSON_PARSE_RFC, &json_read_error_code, - &json_read_error_msg); - if (json_data == NULL) { + &json_read_error_msg)); + if (!json_data) { load_manager->ReportLoadError( PP_NACL_ERROR_PNACL_RESOURCE_FETCH, std::string("Parsing resource info failed: JSON parse error: ") +
diff --git a/components/native_viewport/BUILD.gn b/components/native_viewport/BUILD.gn index 5b27f1d6..a313b26 100644 --- a/components/native_viewport/BUILD.gn +++ b/components/native_viewport/BUILD.gn
@@ -57,6 +57,8 @@ source_set("lib") { sources = [ + "native_viewport_application_delegate.cc", + "native_viewport_application_delegate.h", "native_viewport_impl.cc", "native_viewport_impl.h", "onscreen_context_provider.cc",
diff --git a/components/native_viewport/main.cc b/components/native_viewport/main.cc index 7cc33236..1a749f4 100644 --- a/components/native_viewport/main.cc +++ b/components/native_viewport/main.cc
@@ -2,83 +2,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "base/command_line.h" -#include "base/macros.h" #include "base/message_loop/message_loop.h" -#include "components/gles2/gpu_impl.h" -#include "components/native_viewport/native_viewport_impl.h" -#include "components/native_viewport/public/cpp/args.h" +#include "components/native_viewport/native_viewport_application_delegate.h" #include "mojo/application/application_runner_chromium.h" -#include "mojo/application/public/cpp/application_connection.h" -#include "mojo/application/public/cpp/application_delegate.h" -#include "mojo/application/public/cpp/application_impl.h" -#include "mojo/application/public/cpp/interface_factory_impl.h" -#include "mojo/common/tracing_impl.h" #include "third_party/mojo/src/mojo/public/c/system/main.h" -#include "ui/events/event_switches.h" -#include "ui/gl/gl_surface.h" - -using mojo::ApplicationConnection; -using mojo::Gpu; -using mojo::NativeViewport; - -namespace native_viewport { - -class NativeViewportAppDelegate : public mojo::ApplicationDelegate, - public mojo::InterfaceFactory<NativeViewport>, - public mojo::InterfaceFactory<Gpu> { - public: - NativeViewportAppDelegate() : is_headless_(false) {} - ~NativeViewportAppDelegate() override {} - - private: - // mojo::ApplicationDelegate implementation. - void Initialize(mojo::ApplicationImpl* application) override { - tracing_.Initialize(application); - - base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); - is_headless_ = command_line->HasSwitch(mojo::kUseHeadlessConfig); - if (!is_headless_) { - if (command_line->HasSwitch(mojo::kUseTestConfig)) - gfx::GLSurface::InitializeOneOffForTests(); - else - gfx::GLSurface::InitializeOneOff(); - } - } - - bool ConfigureIncomingConnection(ApplicationConnection* connection) override { - connection->AddService<NativeViewport>(this); - connection->AddService<Gpu>(this); - return true; - } - - // mojo::InterfaceFactory<NativeViewport> implementation. - void Create(ApplicationConnection* connection, - mojo::InterfaceRequest<NativeViewport> request) override { - if (!gpu_state_.get()) - gpu_state_ = new gles2::GpuState; - new NativeViewportImpl(is_headless_, gpu_state_, request.Pass()); - } - - // mojo::InterfaceFactory<Gpu> implementation. - void Create(ApplicationConnection* connection, - mojo::InterfaceRequest<Gpu> request) override { - if (!gpu_state_.get()) - gpu_state_ = new gles2::GpuState; - new gles2::GpuImpl(request.Pass(), gpu_state_); - } - - scoped_refptr<gles2::GpuState> gpu_state_; - bool is_headless_; - mojo::TracingImpl tracing_; - - DISALLOW_COPY_AND_ASSIGN(NativeViewportAppDelegate); -}; -} MojoResult MojoMain(MojoHandle shell_handle) { mojo::ApplicationRunnerChromium runner( - new native_viewport::NativeViewportAppDelegate); + new native_viewport::NativeViewportApplicationDelegate); runner.set_message_loop_type(base::MessageLoop::TYPE_UI); return runner.Run(shell_handle); }
diff --git a/components/native_viewport/native_viewport_application_delegate.cc b/components/native_viewport/native_viewport_application_delegate.cc new file mode 100644 index 0000000..4f247c7a5 --- /dev/null +++ b/components/native_viewport/native_viewport_application_delegate.cc
@@ -0,0 +1,61 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/native_viewport/native_viewport_application_delegate.h" + +#include "base/command_line.h" +#include "components/native_viewport/native_viewport_impl.h" +#include "components/native_viewport/public/cpp/args.h" +#include "mojo/application/public/cpp/application_connection.h" +#include "mojo/application/public/cpp/application_impl.h" +#include "ui/events/event_switches.h" +#include "ui/gl/gl_surface.h" + +namespace native_viewport { + +NativeViewportApplicationDelegate::NativeViewportApplicationDelegate() + : is_headless_(false) { +} + +NativeViewportApplicationDelegate::~NativeViewportApplicationDelegate() { +} + +void NativeViewportApplicationDelegate::Initialize( + mojo::ApplicationImpl* application) { + tracing_.Initialize(application); + + base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); + is_headless_ = command_line->HasSwitch(mojo::kUseHeadlessConfig); + if (!is_headless_) { + if (command_line->HasSwitch(mojo::kUseTestConfig)) + gfx::GLSurface::InitializeOneOffForTests(); + else + gfx::GLSurface::InitializeOneOff(); + } +} + +bool NativeViewportApplicationDelegate::ConfigureIncomingConnection( + mojo::ApplicationConnection* connection) { + connection->AddService<mojo::NativeViewport>(this); + connection->AddService<mojo::Gpu>(this); + return true; +} + +void NativeViewportApplicationDelegate::Create( + mojo::ApplicationConnection* connection, + mojo::InterfaceRequest<mojo::NativeViewport> request) { + if (!gpu_state_.get()) + gpu_state_ = new gles2::GpuState; + new NativeViewportImpl(is_headless_, gpu_state_, request.Pass()); +} + +void NativeViewportApplicationDelegate::Create( + mojo::ApplicationConnection* connection, + mojo::InterfaceRequest<mojo::Gpu> request) { + if (!gpu_state_.get()) + gpu_state_ = new gles2::GpuState; + new gles2::GpuImpl(request.Pass(), gpu_state_); +} + +} // namespace native_viewport
diff --git a/components/native_viewport/native_viewport_application_delegate.h b/components/native_viewport/native_viewport_application_delegate.h new file mode 100644 index 0000000..4584fff --- /dev/null +++ b/components/native_viewport/native_viewport_application_delegate.h
@@ -0,0 +1,53 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_NATIVE_VIEWPORT_NATIVE_VIEWPORT_APPLICATION_DELEGATE_H_ +#define COMPONENTS_NATIVE_VIEWPORT_NATIVE_VIEWPORT_APPLICATION_DELEGATE_H_ + +#include "base/macros.h" +#include "components/gles2/gpu_impl.h" +#include "components/native_viewport/public/interfaces/native_viewport.mojom.h" +#include "mojo/application/public/cpp/application_delegate.h" +#include "mojo/application/public/cpp/interface_factory_impl.h" +#include "mojo/common/tracing_impl.h" + +namespace mojo { +class ApplicationConnection; +class ApplicationImpl; +} + +namespace native_viewport { + +class NativeViewportApplicationDelegate + : public mojo::ApplicationDelegate, + public mojo::InterfaceFactory<mojo::NativeViewport>, + public mojo::InterfaceFactory<mojo::Gpu> { + public: + NativeViewportApplicationDelegate(); + ~NativeViewportApplicationDelegate() override; + + private: + // mojo::ApplicationDelegate implementation. + void Initialize(mojo::ApplicationImpl* application) override; + bool ConfigureIncomingConnection( + mojo::ApplicationConnection* connection) override; + + // mojo::InterfaceFactory<NativeViewport> implementation. + void Create(mojo::ApplicationConnection* connection, + mojo::InterfaceRequest<mojo::NativeViewport> request) override; + + // mojo::InterfaceFactory<Gpu> implementation. + void Create(mojo::ApplicationConnection* connection, + mojo::InterfaceRequest<mojo::Gpu> request) override; + + scoped_refptr<gles2::GpuState> gpu_state_; + bool is_headless_; + mojo::TracingImpl tracing_; + + DISALLOW_COPY_AND_ASSIGN(NativeViewportApplicationDelegate); +}; + +} // namespace native_viewport + +#endif // COMPONENTS_NATIVE_VIEWPORT_NATIVE_VIEWPORT_APPLICATION_DELEGATE_H_
diff --git a/components/omnibox/search_suggestion_parser.cc b/components/omnibox/search_suggestion_parser.cc index 96933cf..26d1933e 100644 --- a/components/omnibox/search_suggestion_parser.cc +++ b/components/omnibox/search_suggestion_parser.cc
@@ -518,7 +518,7 @@ answer->AddImageURLsTo(&results->answers_image_urls); std::string contents; - base::JSONWriter::Write(answer_json, &contents); + base::JSONWriter::Write(*answer_json, &contents); answer_contents = base::UTF8ToUTF16(contents); } else { answer_type_str = base::string16();
diff --git a/components/password_manager/core/browser/affiliated_match_helper.cc b/components/password_manager/core/browser/affiliated_match_helper.cc index 6acfb59f..225de22 100644 --- a/components/password_manager/core/browser/affiliated_match_helper.cc +++ b/components/password_manager/core/browser/affiliated_match_helper.cc
@@ -114,6 +114,10 @@ } } +void AffiliatedMatchHelper::TrimAffiliationCache() { + affiliation_service_->TrimCache(); +} + // static bool AffiliatedMatchHelper::IsValidAndroidCredential( const autofill::PasswordForm& form) {
diff --git a/components/password_manager/core/browser/affiliated_match_helper.h b/components/password_manager/core/browser/affiliated_match_helper.h index b3ba8860..6f7b9097 100644 --- a/components/password_manager/core/browser/affiliated_match_helper.h +++ b/components/password_manager/core/browser/affiliated_match_helper.h
@@ -80,6 +80,9 @@ const autofill::PasswordForm& android_form, const AffiliatedRealmsCallback& result_callback); + // Removes cached affiliation data that is no longer needed. + void TrimAffiliationCache(); + // Returns whether or not |form| represents an Android credential. static bool IsValidAndroidCredential(const autofill::PasswordForm& form);
diff --git a/components/password_manager/core/browser/affiliation_backend.cc b/components/password_manager/core/browser/affiliation_backend.cc index 48301dbf..fd4af444 100644 --- a/components/password_manager/core/browser/affiliation_backend.cc +++ b/components/password_manager/core/browser/affiliation_backend.cc
@@ -5,6 +5,7 @@ #include "components/password_manager/core/browser/affiliation_backend.h" #include <stdint.h> +#include <algorithm> #include "base/bind.h" #include "base/location.h" @@ -98,8 +99,30 @@ void AffiliationBackend::TrimCache() { DCHECK(thread_checker_ && thread_checker_->CalledOnValidThread()); - // TODO(engedy): Implement this. crbug.com/437865. - NOTIMPLEMENTED(); + // Discard all equivalence classes except those that contain >= 1 facet for + // which there is a FacetManager claiming that it needs to keep the data. + std::vector<AffiliatedFacetsWithUpdateTime> all_affiliations; + cache_->GetAllAffiliations(&all_affiliations); + for (const auto& affiliation : all_affiliations) { + bool can_discard = true; + for (const auto& facet_uri : affiliation.facets) { + FacetManager* facet_manager = facet_managers_.get(facet_uri); + if (facet_manager && !facet_manager->CanCachedDataBeDiscarded()) { + can_discard = false; + break; + } + } + if (can_discard) { + // The database should not be serving empty equivalence classes. + CHECK(affiliation.facets.size()); + cache_->DeleteAffiliationsForFacet(affiliation.facets[0]); + } + } +} + +// static +void AffiliationBackend::DeleteCache(const base::FilePath& db_path) { + AffiliationDatabase::Delete(db_path); } FacetManager* AffiliationBackend::GetOrCreateFacetManager(
diff --git a/components/password_manager/core/browser/affiliation_backend.h b/components/password_manager/core/browser/affiliation_backend.h index abd84d6..a1a2c96 100644 --- a/components/password_manager/core/browser/affiliation_backend.h +++ b/components/password_manager/core/browser/affiliation_backend.h
@@ -79,6 +79,10 @@ const base::Time& keep_fresh_until); void TrimCache(); + // Deletes the cache database file at |db_path|, and all auxiliary files. The + // database must be closed before calling this. + static void DeleteCache(const base::FilePath& db_path); + private: friend class AffiliationBackendTest;
diff --git a/components/password_manager/core/browser/affiliation_backend_unittest.cc b/components/password_manager/core/browser/affiliation_backend_unittest.cc index a0421d386..256fb00 100644 --- a/components/password_manager/core/browser/affiliation_backend_unittest.cc +++ b/components/password_manager/core/browser/affiliation_backend_unittest.cc
@@ -13,6 +13,7 @@ #include "base/test/test_simple_task_runner.h" #include "base/time/clock.h" #include "base/time/tick_clock.h" +#include "components/password_manager/core/browser/affiliation_database.h" #include "components/password_manager/core/browser/affiliation_fetch_throttler.h" #include "components/password_manager/core/browser/affiliation_fetch_throttler_delegate.h" #include "components/password_manager/core/browser/facet_manager.h" @@ -262,6 +263,16 @@ backend_task_runner_->FastForwardBy(delta); } + // Directly opens the database and returns the number of equivalence classes + // stored therein. + size_t GetNumOfEquivalenceClassInDatabase() { + AffiliationDatabase database; + EXPECT_TRUE(database.Init(db_path())); + std::vector<AffiliatedFacetsWithUpdateTime> all_affiliations; + database.GetAllAffiliations(&all_affiliations); + return all_affiliations.size(); + } + size_t backend_facet_manager_count() { return backend()->facet_manager_count_for_testing(); } @@ -279,6 +290,8 @@ AffiliationBackend* backend() { return backend_.get(); } + const base::FilePath& db_path() const { return db_path_; } + base::TestMockTimeTaskRunner* backend_task_runner() { return backend_task_runner_.get(); } @@ -300,12 +313,11 @@ private: // testing::Test: void SetUp() override { - base::FilePath database_path; - ASSERT_TRUE(CreateTemporaryFile(&database_path)); + ASSERT_TRUE(CreateTemporaryFile(&db_path_)); backend_.reset(new AffiliationBackend( NULL, backend_task_runner_, backend_task_runner_->GetMockClock(), backend_task_runner_->GetMockTickClock())); - backend_->Initialize(database_path); + backend_->Initialize(db_path()); mock_fetch_throttler_ = new MockAffiliationFetchThrottler(backend_.get()); backend_->SetThrottlerForTesting( make_scoped_ptr<AffiliationFetchThrottler>(mock_fetch_throttler_)); @@ -321,6 +333,7 @@ scoped_refptr<base::TestMockTimeTaskRunner> backend_task_runner_; scoped_refptr<base::TestSimpleTaskRunner> consumer_task_runner_; + base::FilePath db_path_; ScopedFakeAffiliationAPI fake_affiliation_api_; MockAffiliationConsumer mock_consumer_; scoped_ptr<AffiliationBackend> backend_; @@ -773,6 +786,76 @@ EXPECT_FALSE(backend_task_runner()->HasPendingTask()); } +// Verify removal of equivalence classes that contain only facets for which +// there are no FacetManagers. +TEST_F(AffiliationBackendTest, TrimCacheDiscardsDataWithoutFacetManagers) { + ASSERT_NO_FATAL_FAILURE(GetAffiliationsAndExpectFetchAndThenResult( + FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1), + GetTestEquivalenceClassAlpha())); + ASSERT_NO_FATAL_FAILURE(PrefetchAndExpectFetch( + FacetURI::FromCanonicalSpec(kTestFacetURIBeta1), + backend_task_runner()->Now() + GetShortTestPeriod())); + Prefetch(FacetURI::FromCanonicalSpec(kTestFacetURIBeta2), base::Time::Max()); + ASSERT_NO_FATAL_FAILURE(ExpectNoFetchNeeded()); + EXPECT_EQ(2u, GetNumOfEquivalenceClassInDatabase()); + + AdvanceTime(GetShortTestPeriod()); + + // Worst-case scenario: the first prefetch has just expired, the other has + // just been canceled when TrimCache() is called; plus immediately afterwards + // the backend is destroyed. + ASSERT_NO_FATAL_FAILURE(CancelPrefetch( + FacetURI::FromCanonicalSpec(kTestFacetURIBeta2), base::Time::Max())); + backend()->TrimCache(); + DestroyBackend(); + EXPECT_EQ(0u, GetNumOfEquivalenceClassInDatabase()); +} + +// Verify removal of equivalence classes that contain only facets for which +// there are either no FacetManagers, or only such that do not need the data. +TEST_F(AffiliationBackendTest, + TrimCacheDiscardsDataNoLongerNeededByFacetManagers) { + FacetURI facet_uri(FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1)); + + // Set up some stale data in the database. + ASSERT_NO_FATAL_FAILURE(GetAffiliationsAndExpectFetchAndThenResult( + facet_uri, GetTestEquivalenceClassAlpha())); + AdvanceTime(GetCacheHardExpiryPeriod()); + EXPECT_FALSE(IsCachedDataFreshForFacet(facet_uri)); + + // Now start prefetching the same facet, but keep the network fetch hanging. + Prefetch(facet_uri, base::Time::Max()); + ASSERT_TRUE(mock_fetch_throttler()->has_signaled_network_request_needed()); + EXPECT_EQ(1u, GetNumOfEquivalenceClassInDatabase()); + + // The already stale data should be removed regardless of the active prefetch. + backend()->TrimCache(); + EXPECT_EQ(0u, GetNumOfEquivalenceClassInDatabase()); + + mock_fetch_throttler()->reset_signaled_network_request_needed(); +} + +// Verify preservation of equivalence classes that contain >= 1 facet for which +// there is a FacetManager claiming that it needs to keep the data. +TEST_F(AffiliationBackendTest, TrimCacheRetainsDataThatNeededByFacetManagers) { + FacetURI facet_uri(FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1)); + + ASSERT_NO_FATAL_FAILURE(PrefetchAndExpectFetch( + facet_uri, backend_task_runner()->Now() + GetCacheHardExpiryPeriod())); + backend()->TrimCache(); + + // Also verify that the last update time of the affiliation data is preserved, + // i.e., that it expires when it would normally have expired. + AdvanceTime(GetCacheHardExpiryPeriod() - Epsilon()); + EXPECT_TRUE(IsCachedDataFreshForFacet(facet_uri)); + ASSERT_NO_FATAL_FAILURE(ExpectThatEquivalenceClassIsServedFromCache( + GetTestEquivalenceClassAlpha())); + AdvanceTime(Epsilon()); + EXPECT_FALSE(IsCachedDataFreshForFacet(facet_uri)); + ASSERT_NO_FATAL_FAILURE( + GetAffiliationsAndExpectFailureWithoutFetch(facet_uri)); +} + TEST_F(AffiliationBackendTest, NothingExplodesWhenShutDownDuringFetch) { GetAffiliations(mock_consumer(), FacetURI::FromCanonicalSpec(kTestFacetURIAlpha2), @@ -797,4 +880,11 @@ testing::Mock::VerifyAndClearExpectations(mock_consumer()); } +TEST_F(AffiliationBackendTest, DeleteCache) { + DestroyBackend(); + ASSERT_TRUE(base::PathExists(db_path())); + AffiliationBackend::DeleteCache(db_path()); + ASSERT_FALSE(base::PathExists(db_path())); +} + } // namespace password_manager
diff --git a/components/password_manager/core/browser/affiliation_database.cc b/components/password_manager/core/browser/affiliation_database.cc index 0757d711..bab8f366 100644 --- a/components/password_manager/core/browser/affiliation_database.cc +++ b/components/password_manager/core/browser/affiliation_database.cc
@@ -214,6 +214,12 @@ transaction.Commit(); } +// static +void AffiliationDatabase::Delete(const base::FilePath& path) { + bool success = sql::Connection::Delete(path); + DCHECK(success); +} + bool AffiliationDatabase::CreateTablesAndIndicesIfNeeded() { if (!sql_connection_->Execute( "CREATE TABLE IF NOT EXISTS eq_classes("
diff --git a/components/password_manager/core/browser/affiliation_database.h b/components/password_manager/core/browser/affiliation_database.h index 11d2c0e..621add9c 100644 --- a/components/password_manager/core/browser/affiliation_database.h +++ b/components/password_manager/core/browser/affiliation_database.h
@@ -70,6 +70,10 @@ const AffiliatedFacetsWithUpdateTime& affiliated_facets, std::vector<AffiliatedFacetsWithUpdateTime>* removed_affiliations); + // Deletes the database file at |path| along with all its auxiliary files. The + // database must be closed before calling this. + static void Delete(const base::FilePath& path); + private: // Creates any tables and indices that do not already exist in the database. bool CreateTablesAndIndicesIfNeeded();
diff --git a/components/password_manager/core/browser/affiliation_database_unittest.cc b/components/password_manager/core/browser/affiliation_database_unittest.cc index 6fc8a7e..4734392 100644 --- a/components/password_manager/core/browser/affiliation_database_unittest.cc +++ b/components/password_manager/core/browser/affiliation_database_unittest.cc
@@ -5,6 +5,7 @@ #include "components/password_manager/core/browser/affiliation_database.h" #include "base/files/file_util.h" +#include "base/files/scoped_temp_dir.h" #include "sql/test/scoped_error_ignorer.h" #include "sql/test/test_helpers.h" #include "testing/gmock/include/gmock/gmock.h" @@ -69,7 +70,7 @@ ~AffiliationDatabaseTest() override {} void SetUp() override { - ASSERT_TRUE(CreateTemporaryFile(&db_path_)); + ASSERT_TRUE(temp_directory_.CreateUniqueTempDir()); OpenDatabase(); } @@ -88,10 +89,13 @@ AffiliationDatabase& db() { return *db_; } - const base::FilePath& db_path() { return db_path_; } + base::FilePath db_path() { + return temp_directory_.path().Append( + FILE_PATH_LITERAL("Test Affiliation Database")); + } private: - base::FilePath db_path_; + base::ScopedTempDir temp_directory_; scoped_ptr<AffiliationDatabase> db_; DISALLOW_COPY_AND_ASSIGN(AffiliationDatabaseTest); @@ -290,4 +294,13 @@ EXPECT_EQ(0u, affiliations.size()); } +// Verify that all files get deleted. +TEST_F(AffiliationDatabaseTest, Delete) { + ASSERT_NO_FATAL_FAILURE(StoreInitialTestData()); + CloseDatabase(); + + AffiliationDatabase::Delete(db_path()); + EXPECT_TRUE(base::IsDirectoryEmpty(db_path().DirName())); +} + } // namespace password_manager
diff --git a/components/password_manager/core/browser/affiliation_service.cc b/components/password_manager/core/browser/affiliation_service.cc index 0bcade91..30fbe632 100644 --- a/components/password_manager/core/browser/affiliation_service.cc +++ b/components/password_manager/core/browser/affiliation_service.cc
@@ -89,4 +89,12 @@ base::Bind(&AffiliationBackend::TrimCache, base::Unretained(backend_))); } +// static +void AffiliationService::DeleteCache( + const base::FilePath& db_path, + base::SingleThreadTaskRunner* backend_task_runner) { + backend_task_runner->PostTask( + FROM_HERE, base::Bind(&AffiliationBackend::DeleteCache, db_path)); +} + } // namespace password_manager
diff --git a/components/password_manager/core/browser/affiliation_service.h b/components/password_manager/core/browser/affiliation_service.h index adc2349e..fd81a3bd 100644 --- a/components/password_manager/core/browser/affiliation_service.h +++ b/components/password_manager/core/browser/affiliation_service.h
@@ -142,6 +142,12 @@ // triggered by this call. void TrimCache(); + // Posts a task to the |backend_task_runner| to delete the cache database file + // at |db_path|, and all auxiliary files. The database must be closed before + // calling this. + static void DeleteCache(const base::FilePath& db_path, + base::SingleThreadTaskRunner* backend_task_runner); + private: // The backend, owned by this AffiliationService instance, but living on the // DB thread. It will be deleted asynchronously during shutdown on the DB
diff --git a/components/password_manager/core/browser/facet_manager.cc b/components/password_manager/core/browser/facet_manager.cc index ea84f50e..a0e9e86 100644 --- a/components/password_manager/core/browser/facet_manager.cc +++ b/components/password_manager/core/browser/facet_manager.cc
@@ -187,6 +187,11 @@ GetMaximumKeepFreshUntilThreshold() <= clock_->Now(); } +bool FacetManager::CanCachedDataBeDiscarded() const { + return GetMaximumKeepFreshUntilThreshold() <= clock_->Now() || + !IsCachedDataFresh(); +} + bool FacetManager::DoesRequireFetch() const { return (!pending_requests_.empty() && !IsCachedDataFresh()) || GetNextRequiredFetchTimeDueToPrefetch() <= clock_->Now();
diff --git a/components/password_manager/core/browser/facet_manager.h b/components/password_manager/core/browser/facet_manager.h index 81c5fed..5e3ee77 100644 --- a/components/password_manager/core/browser/facet_manager.h +++ b/components/password_manager/core/browser/facet_manager.h
@@ -58,6 +58,10 @@ // more meaningful state than a newly created instance would have. bool CanBeDiscarded() const; + // Returns whether or not cached data for this facet can be discarded without + // harm when trimming the database. + bool CanCachedDataBeDiscarded() const; + // Returns whether or not affiliation information relating to this facet needs // to be fetched right now. bool DoesRequireFetch() const;
diff --git a/components/password_manager/core/browser/facet_manager_unittest.cc b/components/password_manager/core/browser/facet_manager_unittest.cc index 4cc3b30..01ae885f 100644 --- a/components/password_manager/core/browser/facet_manager_unittest.cc +++ b/components/password_manager/core/browser/facet_manager_unittest.cc
@@ -288,6 +288,7 @@ for (base::TimeDelta step : SamplingPoints(until_time - Now())) { SCOPED_TRACE(testing::Message() << "dT: " << DeltaNow()); EXPECT_FALSE(facet_manager()->CanBeDiscarded()); + EXPECT_FALSE(facet_manager()->CanCachedDataBeDiscarded()); ExpectRequestsServedFromCache(); ExpectNoFetchNeeded(); AdvanceTime(step); @@ -411,6 +412,7 @@ TEST_F(FacetManagerTest, NewInstanceCanBeDiscarded) { CreateFacetManager(); EXPECT_TRUE(facet_manager()->CanBeDiscarded()); + EXPECT_TRUE(facet_manager()->CanCachedDataBeDiscarded()); EXPECT_FALSE(facet_manager()->DoesRequireFetch()); EXPECT_FALSE(main_task_runner()->HasPendingTask()); } @@ -1300,6 +1302,34 @@ DestroyFacetManager(); } +TEST_F(FacetManagerTest, CachedDataCannotBeDiscarded) { + CreateFacetManager(); + + const base::TimeDelta kPrefetchLength = + 2 * GetCacheSoftExpiryPeriod() + GetCacheHardExpiryPeriod(); + + facet_manager_notifier()->set_accuracy(NotificationAccuracy::NEVER_CALLED); + + const base::Time prefetch_end = Now() + kPrefetchLength; + std::vector<ExpectedFetchDetails> expected_fetches(1); + expected_fetches[0].time = Now(); + + Prefetch(prefetch_end); + ASSERT_NO_FATAL_FAILURE(AdvanceTimeAndVerifyPrefetchWithFetchesAt( + Now() + GetCacheSoftExpiryPeriod(), expected_fetches)); + for (base::TimeDelta step : SamplingPoints(prefetch_end - Now())) { + SCOPED_TRACE(testing::Message() << "dT: " << DeltaNow()); + EXPECT_FALSE(facet_manager()->CanBeDiscarded()); + ASSERT_TRUE(facet_manager()->DoesRequireFetch()); + if (DeltaNow() < GetCacheHardExpiryPeriod()) + ExpectRequestsServedFromCache(); + AdvanceTime(step); + } + EXPECT_TRUE(facet_manager()->CanBeDiscarded()); + EXPECT_FALSE(main_task_runner()->HasPendingTask()); + DestroyFacetManager(); +} + // RequestNotificationAtTime() ends up calling NotifyAtRequestedTime() always // a bit earlier than needed. This should result in NotifyAtRequestedTime() // being called repeatedly until the callback is finally on time, but should @@ -1402,4 +1432,87 @@ DestroyFacetManager(); } +TEST_F(FacetManagerTest, StaleCachedDataBeCanDiscardedWhilePendingFetch) { + CreateFacetManager(); + ASSERT_FALSE(facet_manager()->IsCachedDataFresh()); + + GetAffiliations(StrategyOnCacheMiss::FETCH_OVER_NETWORK); + ASSERT_NO_FATAL_FAILURE(ExpectFetchNeeded()); + EXPECT_FALSE(facet_manager()->CanBeDiscarded()); + EXPECT_TRUE(facet_manager()->CanCachedDataBeDiscarded()); + + fake_facet_manager_host()->reset_need_network_request(); +} + +TEST_F(FacetManagerTest, CachedDataBeCanDiscardedAfterOnDemandGetAffiliatons) { + CreateFacetManager(); + ASSERT_FALSE(facet_manager()->IsCachedDataFresh()); + + GetAffiliations(StrategyOnCacheMiss::FETCH_OVER_NETWORK); + ASSERT_NO_FATAL_FAILURE(ExpectFetchNeeded()); + ASSERT_NO_FATAL_FAILURE(CompleteFetch()); + ExpectConsumerSuccessCallback(); + + EXPECT_TRUE(facet_manager()->IsCachedDataFresh()); + EXPECT_TRUE(facet_manager()->CanBeDiscarded()); + EXPECT_TRUE(facet_manager()->CanCachedDataBeDiscarded()); +} + +// The cached data can be discarded (indicated by 'd') if and only if it is no +// longer needed to be kept fresh, or if it already stale. +// +// t=0 S H F2+S F2+H +// / / / / / +// ---o--------------------------o-------o------------------o-------o------> t +// : : : +// [F-------------------------NNNNNNNNNNNF---) +// ddd ddd... +// +TEST_F(FacetManagerTest, + CachedDataCanBeDiscardedAfterAndSometimesDuringPrefetch) { + CreateFacetManager(); + Prefetch(Now() + GetCacheHardExpiryPeriod() + 2 * GetShortTestPeriod()); + ASSERT_NO_FATAL_FAILURE(ExpectFetchNeeded()); + ASSERT_NO_FATAL_FAILURE(CompleteFetch()); + + for (base::TimeDelta step : SamplingPoints(GetCacheHardExpiryPeriod())) { + SCOPED_TRACE(testing::Message() << "dT: " << DeltaNow()); + EXPECT_FALSE(facet_manager()->CanCachedDataBeDiscarded()); + AdvanceTime(step); + } + + for (base::TimeDelta step : SamplingPoints(GetShortTestPeriod())) { + SCOPED_TRACE(testing::Message() << "dT: " << DeltaNow()); + EXPECT_TRUE(facet_manager()->CanCachedDataBeDiscarded()); + AdvanceTime(step); + } + + ASSERT_NO_FATAL_FAILURE(ExpectFetchNeeded()); + ASSERT_NO_FATAL_FAILURE(CompleteFetch()); + + for (base::TimeDelta step : SamplingPoints(GetShortTestPeriod())) { + SCOPED_TRACE(testing::Message() << "dT: " << DeltaNow()); + EXPECT_FALSE(facet_manager()->CanCachedDataBeDiscarded()); + AdvanceTime(step); + } + + EXPECT_TRUE(facet_manager()->CanBeDiscarded()); + EXPECT_TRUE(facet_manager()->CanCachedDataBeDiscarded()); +} + +TEST_F(FacetManagerTest, CachedDataBeCanDiscardedAfterCancelledPrefetch) { + CreateFacetManager(); + Prefetch(base::Time::Max()); + ASSERT_NO_FATAL_FAILURE(ExpectFetchNeeded()); + ASSERT_NO_FATAL_FAILURE(CompleteFetch()); + + EXPECT_FALSE(facet_manager()->CanCachedDataBeDiscarded()); + + AdvanceTime(GetShortTestPeriod()); + CancelPrefetch(base::Time::Max()); + + EXPECT_TRUE(facet_manager()->CanBeDiscarded()); + EXPECT_TRUE(facet_manager()->CanCachedDataBeDiscarded()); +} + } // namespace password_manager
diff --git a/components/password_manager/core/browser/password_store.cc b/components/password_manager/core/browser/password_store.cc index 4a357919..08e827db 100644 --- a/components/password_manager/core/browser/password_store.cc +++ b/components/password_manager/core/browser/password_store.cc
@@ -116,6 +116,11 @@ this, delete_begin, delete_end)); } +void PasswordStore::TrimAffiliationCache() { + if (affiliated_match_helper_) + affiliated_match_helper_->TrimAffiliationCache(); +} + void PasswordStore::GetLogins(const PasswordForm& form, AuthorizationPromptPolicy prompt_policy, PasswordStoreConsumer* consumer) {
diff --git a/components/password_manager/core/browser/password_store.h b/components/password_manager/core/browser/password_store.h index c1194cfc..c49aecb 100644 --- a/components/password_manager/core/browser/password_store.h +++ b/components/password_manager/core/browser/password_store.h
@@ -102,6 +102,10 @@ virtual void RemoveLoginsSyncedBetween(base::Time delete_begin, base::Time delete_end); + // Removes cached affiliation data that is no longer needed; provided that + // affiliation-based matching is enabled. + void TrimAffiliationCache(); + // Searches for a matching PasswordForm, and notifies |consumer| on // completion. The request will be cancelled if the consumer is destroyed. // |prompt_policy| indicates whether it's permissible to prompt the user to
diff --git a/components/policy/core/common/cloud/cloud_policy_constants.cc b/components/policy/core/common/cloud/cloud_policy_constants.cc index 43324e1..4fa62f55 100644 --- a/components/policy/core/common/cloud/cloud_policy_constants.cc +++ b/components/policy/core/common/cloud/cloud_policy_constants.cc
@@ -42,8 +42,8 @@ const char kValueUserAffiliationManaged[] = "managed"; const char kValueUserAffiliationNone[] = "none"; const char kValueRequestDeviceAttributeUpdatePermission[] = - "attribute_update_permission"; -const char kValueRequestDeviceAttributeUpdate[] = "attribute_update"; + "device_attribute_update_permission"; +const char kValueRequestDeviceAttributeUpdate[] = "device_attribute_update"; const char kChromeDevicePolicyType[] = "google/chromeos/device"; #if defined(OS_CHROMEOS)
diff --git a/components/policy/core/common/cloud/cloud_policy_core.cc b/components/policy/core/common/cloud/cloud_policy_core.cc index f1f5fca..302808e 100644 --- a/components/policy/core/common/cloud/cloud_policy_core.cc +++ b/components/policy/core/common/cloud/cloud_policy_core.cc
@@ -19,6 +19,10 @@ CloudPolicyCore::Observer::~Observer() {} +void CloudPolicyCore::Observer::OnRemoteCommandsServiceStarted( + CloudPolicyCore* core) { +} + CloudPolicyCore::CloudPolicyCore( const std::string& policy_type, const std::string& settings_entity_id, @@ -59,6 +63,8 @@ // Do an initial remote commands fetch immediately. remote_commands_service_->FetchRemoteCommands(); + + FOR_EACH_OBSERVER(Observer, observers_, OnRemoteCommandsServiceStarted(this)); } void CloudPolicyCore::RefreshSoon() {
diff --git a/components/policy/core/common/cloud/cloud_policy_core.h b/components/policy/core/common/cloud/cloud_policy_core.h index 031aa34..7a9bf59a 100644 --- a/components/policy/core/common/cloud/cloud_policy_core.h +++ b/components/policy/core/common/cloud/cloud_policy_core.h
@@ -50,6 +50,10 @@ // Called before the core is disconnected. virtual void OnCoreDisconnecting(CloudPolicyCore* core) = 0; + + // Called after the remote commands service is started. Defaults to be + // empty. + virtual void OnRemoteCommandsServiceStarted(CloudPolicyCore* core); }; // |task_runner| is the runner for policy refresh tasks.
diff --git a/components/policy/core/common/cloud/policy_header_service.cc b/components/policy/core/common/cloud/policy_header_service.cc index d0f6980..62519c75 100644 --- a/components/policy/core/common/cloud/policy_header_service.cc +++ b/components/policy/core/common/cloud/policy_header_service.cc
@@ -74,7 +74,7 @@ // TODO(atwilson): add user_policy_token once the server starts sending it // down (http://crbug.com/326799). std::string json; - base::JSONWriter::Write(&value, &json); + base::JSONWriter::Write(value, &json); DCHECK(!json.empty()); // Base64-encode the result so we can include it in a header.
diff --git a/components/policy/core/common/policy_loader_win.cc b/components/policy/core/common/policy_loader_win.cc index f223da5..f49f944e 100644 --- a/components/policy/core/common/policy_loader_win.cc +++ b/components/policy/core/common/policy_loader_win.cc
@@ -128,7 +128,7 @@ } std::string serialized; - base::JSONWriter::Write(json.get(), &serialized); + base::JSONWriter::Write(*json, &serialized); return serialized; }
diff --git a/components/policy/core/common/policy_loader_win_unittest.cc b/components/policy/core/common/policy_loader_win_unittest.cc index 76adc44..c2db3f2 100644 --- a/components/policy/core/common/policy_loader_win_unittest.cc +++ b/components/policy/core/common/policy_loader_win_unittest.cc
@@ -402,7 +402,7 @@ const std::string& policy_name, const base::DictionaryValue* policy_value) { std::string json; - base::JSONWriter::Write(policy_value, &json); + base::JSONWriter::Write(*policy_value, &json); RegKey key(hive_, kTestPolicyKey, KEY_ALL_ACCESS); ASSERT_TRUE(key.Valid()); key.WriteValue(UTF8ToUTF16(policy_name).c_str(), @@ -506,7 +506,7 @@ const std::string& policy_name, const base::DictionaryValue* policy_value) { std::string json; - base::JSONWriter::Write(policy_value, &json); + base::JSONWriter::Write(*policy_value, &json); AppendStringToPRegFile(kTestPolicyKey, policy_name, json); } @@ -910,11 +910,11 @@ policy.Set("list", list.DeepCopy()); // Encode |policy| before adding the "dict" entry. std::string encoded_dict; - base::JSONWriter::Write(&policy, &encoded_dict); + base::JSONWriter::Write(policy, &encoded_dict); ASSERT_FALSE(encoded_dict.empty()); policy.Set("dict", policy.DeepCopy()); std::string encoded_list; - base::JSONWriter::Write(&list, &encoded_list); + base::JSONWriter::Write(list, &encoded_list); ASSERT_FALSE(encoded_list.empty()); base::DictionaryValue encoded_policy; encoded_policy.SetString("null", "");
diff --git a/components/policy/core/common/policy_test_utils.cc b/components/policy/core/common/policy_test_utils.cc index 79180e4..e9116b76 100644 --- a/components/policy/core/common/policy_test_utils.cc +++ b/components/policy/core/common/policy_test_utils.cc
@@ -222,9 +222,8 @@ std::ostream& operator<<(std::ostream& os, const policy::PolicyMap::Entry& e) { std::string value; - base::JSONWriter::WriteWithOptions(e.value, - base::JSONWriter::OPTIONS_PRETTY_PRINT, - &value); + base::JSONWriter::WriteWithOptions( + *e.value, base::JSONWriter::OPTIONS_PRETTY_PRINT, &value); os << "{" << std::endl << " \"level\": " << e.level << "," << std::endl << " \"scope\": " << e.scope << "," << std::endl
diff --git a/components/policy/core/common/remote_commands/remote_commands_service.cc b/components/policy/core/common/remote_commands/remote_commands_service.cc index 1b3bb678..d7b53bc 100644 --- a/components/policy/core/common/remote_commands/remote_commands_service.cc +++ b/components/policy/core/common/remote_commands/remote_commands_service.cc
@@ -30,7 +30,7 @@ } bool RemoteCommandsService::FetchRemoteCommands() { - if (!client_->is_registered()) + if (!client_ || !client_->is_registered()) return false; if (command_fetch_in_progress_) {
diff --git a/components/policy/proto/device_management_backend.proto b/components/policy/proto/device_management_backend.proto index 37322aa..aab6a9e 100644 --- a/components/policy/proto/device_management_backend.proto +++ b/components/policy/proto/device_management_backend.proto
@@ -350,6 +350,18 @@ // Indicates the state that the device should be in. optional DeviceState device_state = 17; + // The object source which hosts command queue objects within the + // invalidation service. This value is combined with + // command_invalidation_name to form the object ID used to + // register for invalidations to the command queue. + optional int32 command_invalidation_source = 18; + + // The name which uniquely identifies this device’s queue within + // the invalidation service object source. This value is combined + // with command_invalidation_source to form the object ID used to + // register for invalidations to the command queue. + optional bytes command_invalidation_name = 19; + // The free-text location info the admin enters to associate the device // with a location. optional string annotated_location = 20;
diff --git a/components/printing/renderer/print_web_view_helper.cc b/components/printing/renderer/print_web_view_helper.cc index 7d1b9078..bd6267c8 100644 --- a/components/printing/renderer/print_web_view_helper.cc +++ b/components/printing/renderer/print_web_view_helper.cc
@@ -83,7 +83,7 @@ const char* script_format, const base::Value& parameters) { std::string json; - base::JSONWriter::Write(¶meters, &json); + base::JSONWriter::Write(parameters, &json); std::string script = base::StringPrintf(script_format, json.c_str()); frame->executeScript(blink::WebString(base::UTF8ToUTF16(script))); }
diff --git a/components/proximity_auth/client.cc b/components/proximity_auth/client.cc index a0b6a06..255b6f6 100644 --- a/components/proximity_auth/client.cc +++ b/components/proximity_auth/client.cc
@@ -37,7 +37,7 @@ // Serializes the |value| to a JSON string and returns the result. std::string SerializeValueToJson(const base::Value& value) { std::string json; - base::JSONWriter::Write(&value, &json); + base::JSONWriter::Write(value, &json); return json; }
diff --git a/components/search_engines/keyword_table.cc b/components/search_engines/keyword_table.cc index 3e21c1f..7de6217 100644 --- a/components/search_engines/keyword_table.cc +++ b/components/search_engines/keyword_table.cc
@@ -100,7 +100,7 @@ for (size_t i = 0; i < data.alternate_urls.size(); ++i) alternate_urls_value.AppendString(data.alternate_urls[i]); std::string alternate_urls; - base::JSONWriter::Write(&alternate_urls_value, &alternate_urls); + base::JSONWriter::Write(alternate_urls_value, &alternate_urls); s->BindInt64(id_column, data.id); s->BindString16(starting_column, data.short_name());
diff --git a/components/search_provider_logos/logo_cache.cc b/components/search_provider_logos/logo_cache.cc index bfa419e..c6272ee5 100644 --- a/components/search_provider_logos/logo_cache.cc +++ b/components/search_provider_logos/logo_cache.cc
@@ -152,7 +152,7 @@ metadata.can_show_after_expiration); dict.SetInteger(kNumBytesKey, num_bytes); SetTimeValue(dict, kExpirationTimeKey, metadata.expiration_time); - base::JSONWriter::Write(&dict, str); + base::JSONWriter::Write(dict, str); } base::FilePath LogoCache::GetLogoPath() {
diff --git a/components/search_provider_logos/logo_tracker_unittest.cc b/components/search_provider_logos/logo_tracker_unittest.cc index 590985a..fcd4653 100644 --- a/components/search_provider_logos/logo_tracker_unittest.cc +++ b/components/search_provider_logos/logo_tracker_unittest.cc
@@ -139,7 +139,7 @@ static_cast<int>(time_to_live.InMilliseconds())); std::string output; - base::JSONWriter::Write(&dict, &output); + base::JSONWriter::Write(dict, &output); return output; }
diff --git a/components/signin/core/browser/account_tracker_service.cc b/components/signin/core/browser/account_tracker_service.cc index ec24462..d29adf1 100644 --- a/components/signin/core/browser/account_tracker_service.cc +++ b/components/signin/core/browser/account_tracker_service.cc
@@ -10,6 +10,7 @@ #include "base/metrics/field_trial.h" #include "base/prefs/scoped_user_pref_update.h" #include "base/profiler/scoped_tracker.h" +#include "base/strings/string_split.h" #include "base/strings/utf_string_conversions.h" #include "base/trace_event/trace_event.h" #include "components/signin/core/browser/refresh_token_annotation_request.h" @@ -17,6 +18,8 @@ #include "components/signin/core/browser/signin_manager.h" #include "components/signin/core/common/signin_pref_names.h" #include "components/signin/core/common/signin_switches.h" +#include "google_apis/gaia/gaia_auth_consumer.h" +#include "google_apis/gaia/gaia_auth_fetcher.h" #include "google_apis/gaia/gaia_auth_util.h" #include "google_apis/gaia/gaia_constants.h" #include "google_apis/gaia/gaia_oauth_client.h" @@ -31,6 +34,7 @@ const char kAccountFullNamePath[] = "full_name"; const char kAccountGivenNamePath[] = "given_name"; const char kAccountLocalePath[] = "locale"; +const char kAccountServiceFlagsPath[] = "service_flags"; const base::TimeDelta kRefreshFromTokenServiceDelay = base::TimeDelta::FromHours(24); @@ -50,7 +54,8 @@ const char AccountTrackerService::kNoHostedDomainFound[] = "NO_HOSTED_DOMAIN"; class AccountInfoFetcher : public OAuth2TokenService::Consumer, - public gaia::GaiaOAuthClient::Delegate { + public gaia::GaiaOAuthClient::Delegate, + public GaiaAuthConsumer { public: AccountInfoFetcher(OAuth2TokenService* token_service, net::URLRequestContextGetter* request_context_getter, @@ -61,6 +66,7 @@ const std::string& account_id() { return account_id_; } void Start(); + void SendSuccessIfDoneFetching(); // OAuth2TokenService::Consumer implementation. void OnGetTokenSuccess(const OAuth2TokenService::Request* request, @@ -75,6 +81,12 @@ void OnOAuthError() override; void OnNetworkError(int response_code) override; + // Overridden from GaiaAuthConsumer: + void OnClientLoginSuccess(const ClientLoginResult& result) override; + void OnClientLoginFailure(const GoogleServiceAuthError& error) override; + void OnGetUserInfoSuccess(const UserInfoMap& data) override; + void OnGetUserInfoFailure(const GoogleServiceAuthError& error) override; + private: OAuth2TokenService* token_service_; net::URLRequestContextGetter* request_context_getter_; @@ -83,6 +95,10 @@ scoped_ptr<OAuth2TokenService::Request> login_token_request_; scoped_ptr<gaia::GaiaOAuthClient> gaia_oauth_client_; + scoped_ptr<GaiaAuthFetcher> gaia_auth_fetcher_; + + scoped_ptr<base::DictionaryValue> fetched_user_info_; + scoped_ptr<std::vector<std::string> > fetched_service_flags_; }; AccountInfoFetcher::AccountInfoFetcher( @@ -108,10 +124,18 @@ OAuth2TokenService::ScopeSet scopes; scopes.insert(GaiaConstants::kGoogleUserInfoEmail); scopes.insert(GaiaConstants::kGoogleUserInfoProfile); + scopes.insert(GaiaConstants::kOAuth1LoginScope); login_token_request_ = token_service_->StartRequest( account_id_, scopes, this); } +void AccountInfoFetcher::SendSuccessIfDoneFetching() { + if (fetched_user_info_ && fetched_service_flags_) { + service_->OnUserInfoFetchSuccess( + this, fetched_user_info_.get(), fetched_service_flags_.get()); + } +} + void AccountInfoFetcher::OnGetTokenSuccess( const OAuth2TokenService::Request* request, const std::string& access_token, @@ -121,9 +145,14 @@ DCHECK_EQ(request, login_token_request_.get()); gaia_oauth_client_.reset(new gaia::GaiaOAuthClient(request_context_getter_)); - const int kMaxRetries = 3; gaia_oauth_client_->GetUserInfo(access_token, kMaxRetries, this); + + gaia_auth_fetcher_.reset( + new GaiaAuthFetcher( + this, GaiaConstants::kChromeSource, request_context_getter_)); + gaia_auth_fetcher_->StartOAuthLogin( + access_token, GaiaConstants::kGaiaService); } void AccountInfoFetcher::OnGetTokenFailure( @@ -148,7 +177,36 @@ "OnGetUserInfoResponse", "account_id", account_id_); - service_->OnUserInfoFetchSuccess(this, user_info.get()); + fetched_user_info_ = user_info.Pass(); + SendSuccessIfDoneFetching(); +} + +void AccountInfoFetcher::OnClientLoginSuccess( + const ClientLoginResult& result) { + gaia_auth_fetcher_->StartGetUserInfo(result.lsid); +} + +void AccountInfoFetcher::OnClientLoginFailure( + const GoogleServiceAuthError& error) { + service_->OnUserInfoFetchFailure(this); +} + +void AccountInfoFetcher::OnGetUserInfoSuccess(const UserInfoMap& data) { + fetched_service_flags_.reset(new std::vector<std::string>); + UserInfoMap::const_iterator services_iter = data.find("allServices"); + if (services_iter != data.end()) { + base::SplitString(services_iter->second, ',', fetched_service_flags_.get()); + SendSuccessIfDoneFetching(); + } else { + DLOG(WARNING) << "AccountInfoFetcher::OnGetUserInfoSuccess: " + << "GetUserInfo response didn't include allServices field."; + service_->OnUserInfoFetchFailure(this); + } +} + +void AccountInfoFetcher::OnGetUserInfoFailure( + const GoogleServiceAuthError& error) { + service_->OnUserInfoFetchFailure(this); } void AccountInfoFetcher::OnOAuthError() { @@ -440,7 +498,8 @@ void AccountTrackerService::SetAccountStateFromUserInfo( const std::string& account_id, - const base::DictionaryValue* user_info) { + const base::DictionaryValue* user_info, + const std::vector<std::string>* service_flags) { AccountState& state = accounts_[account_id]; std::string gaia_id; @@ -461,6 +520,8 @@ user_info->GetString("given_name", &state.info.given_name); user_info->GetString("locale", &state.info.locale); + state.info.service_flags = *service_flags; + NotifyAccountUpdated(state); SaveToPrefs(state); } @@ -468,11 +529,12 @@ void AccountTrackerService::OnUserInfoFetchSuccess( AccountInfoFetcher* fetcher, - const base::DictionaryValue* user_info) { + const base::DictionaryValue* user_info, + const std::vector<std::string>* service_flags) { const std::string& account_id = fetcher->account_id(); DCHECK(ContainsKey(accounts_, account_id)); - SetAccountStateFromUserInfo(account_id, user_info); + SetAccountStateFromUserInfo(account_id, user_info, service_flags); DeleteFetcher(fetcher); } @@ -516,6 +578,18 @@ state.info.given_name = base::UTF16ToUTF8(value); if (dict->GetString(kAccountLocalePath, &value)) state.info.locale = base::UTF16ToUTF8(value); + + const base::ListValue* service_flags_list; + if (dict->GetList(kAccountServiceFlagsPath, &service_flags_list)) { + std::string flag; + for(base::Value* flag: *service_flags_list) { + std::string flag_string; + if(flag->GetAsString(&flag_string)) { + state.info.service_flags.push_back(flag_string); + } + } + } + if (state.info.IsValid()) NotifyAccountUpdated(state); } @@ -552,6 +626,12 @@ dict->SetString(kAccountFullNamePath, state.info.full_name); dict->SetString(kAccountGivenNamePath, state.info.given_name); dict->SetString(kAccountLocalePath, state.info.locale); + + scoped_ptr<base::ListValue> service_flags_list; + service_flags_list.reset(new base::ListValue); + service_flags_list->AppendStrings(state.info.service_flags); + + dict->Set(kAccountServiceFlagsPath, service_flags_list.Pass()); } void AccountTrackerService::RemoveFromPrefs(const AccountState& state) {
diff --git a/components/signin/core/browser/account_tracker_service.h b/components/signin/core/browser/account_tracker_service.h index 2040e70..4debf41 100644 --- a/components/signin/core/browser/account_tracker_service.h +++ b/components/signin/core/browser/account_tracker_service.h
@@ -58,6 +58,7 @@ std::string given_name; std::string hosted_domain; std::string locale; + std::vector<std::string> service_flags; // TODO(rogerta): eventually this structure will include other information // about the account, like full name, profile picture URL, etc. @@ -130,15 +131,18 @@ protected: // Available to be called in tests. - void SetAccountStateFromUserInfo(const std::string& account_id, - const base::DictionaryValue* user_info); + void SetAccountStateFromUserInfo( + const std::string& account_id, + const base::DictionaryValue* user_info, + const std::vector<std::string>* service_flags); private: friend class AccountInfoFetcher; // These methods are called by fetchers. void OnUserInfoFetchSuccess(AccountInfoFetcher* fetcher, - const base::DictionaryValue* user_info); + const base::DictionaryValue* user_info, + const std::vector<std::string>* service_flags); void OnUserInfoFetchFailure(AccountInfoFetcher* fetcher); // Refreshes the AccountInfo associated with |account_id| if it's invalid or
diff --git a/components/signin/core/browser/account_tracker_service_unittest.cc b/components/signin/core/browser/account_tracker_service_unittest.cc index 3ea1ab4..fe4a929 100644 --- a/components/signin/core/browser/account_tracker_service_unittest.cc +++ b/components/signin/core/browser/account_tracker_service_unittest.cc
@@ -39,6 +39,10 @@ \"hd\": \"\", \ }"; +const std::string kLSIDResponse = "{ lsid: \"Foo\" }"; + +const std::string kServiceFlags = "allServices=Service1,Service2"; + enum TrackingEventType { UPDATED, REMOVED, @@ -74,6 +78,9 @@ EXPECT_EQ(AccountIdToFullName(account_id), info.full_name); EXPECT_EQ(AccountIdToGivenName(account_id), info.given_name); EXPECT_EQ(AccountIdToLocale(account_id), info.locale); + EXPECT_EQ(2U, info.service_flags.size()); + EXPECT_EQ("Service1", info.service_flags[0]); + EXPECT_EQ("Service2", info.service_flags[1]); } class TrackingEvent { @@ -340,6 +347,8 @@ ReturnOAuthUrlFetchResults(gaia::GaiaOAuthClient::kUrlFetcherId, net::HTTP_OK, GenerateValidTokenInfoResponse(account_id)); + ReturnOAuthUrlFetchResults(0, net::HTTP_OK, kLSIDResponse); + ReturnOAuthUrlFetchResults(0, net::HTTP_OK, kServiceFlags); } void AccountTrackerServiceTest::ReturnOAuthUrlFetchSuccessIncomplete(
diff --git a/components/signin/core/browser/mutable_profile_oauth2_token_service.cc b/components/signin/core/browser/mutable_profile_oauth2_token_service.cc index 849c7731..9995142 100644 --- a/components/signin/core/browser/mutable_profile_oauth2_token_service.cc +++ b/components/signin/core/browser/mutable_profile_oauth2_token_service.cc
@@ -373,9 +373,6 @@ << "account_id=" << account_id; std::string revoke_reason = refresh_token_present ? "token differs" : "token is missing"; - LOG(WARNING) << "Revoking refresh token on server. " - << "Reason: token update, " << revoke_reason; - RevokeCredentialsOnServer(refresh_tokens_[account_id]->refresh_token()); CancelRequestsForAccount(account_id); ClearCacheForAccount(account_id); refresh_tokens_[account_id]->set_refresh_token(refresh_token);
diff --git a/components/sync_driver/pref_names.cc b/components/sync_driver/pref_names.cc index 1a5727a..8caf875 100644 --- a/components/sync_driver/pref_names.cc +++ b/components/sync_driver/pref_names.cc
@@ -104,6 +104,12 @@ // that we only want to use once. const char kSyncPassphrasePrompted[] = "sync.passphrase_prompted"; +// Stores how many times received MEMORY_PRESSURE_LEVEL_CRITICAL. +const char kSyncMemoryPressureWarningCount[] = "sync.memory_warning_count"; + +// Stores if sync shutdown cleanly. +const char kSyncShutdownCleanly[] = "sync.shutdown_cleanly"; + } // namespace prefs } // namespace sync_driver
diff --git a/components/sync_driver/pref_names.h b/components/sync_driver/pref_names.h index 3cbce22..2491390 100644 --- a/components/sync_driver/pref_names.h +++ b/components/sync_driver/pref_names.h
@@ -66,6 +66,9 @@ extern const char kSyncPassphrasePrompted[]; +extern const char kSyncMemoryPressureWarningCount[]; +extern const char kSyncShutdownCleanly[]; + } // namespace prefs } // namespace sync_driver
diff --git a/components/sync_driver/sync_prefs.cc b/components/sync_driver/sync_prefs.cc index 82106ee..9f80075 100644 --- a/components/sync_driver/sync_prefs.cc +++ b/components/sync_driver/sync_prefs.cc
@@ -83,6 +83,10 @@ registry->RegisterIntegerPref(prefs::kSyncRemainingRollbackTries, 0); registry->RegisterBooleanPref(prefs::kSyncPassphrasePrompted, false); + + registry->RegisterIntegerPref(prefs::kSyncMemoryPressureWarningCount, -1); + + registry->RegisterBooleanPref(prefs::kSyncShutdownCleanly, false); } void SyncPrefs::AddSyncPrefObserver(SyncPrefObserver* sync_pref_observer) { @@ -455,4 +459,22 @@ pref_service_->SetBoolean(prefs::kSyncPassphrasePrompted, value); } +int SyncPrefs::GetMemoryPressureWarningCount() const { + return pref_service_->GetInteger(prefs::kSyncMemoryPressureWarningCount); +} + +void SyncPrefs::SetMemoryPressureWarningCount(int value) { + pref_service_->SetInteger(prefs::kSyncMemoryPressureWarningCount, value); +} + +bool SyncPrefs::DidSyncShutdownCleanly() const { + return pref_service_->GetBoolean(prefs::kSyncShutdownCleanly); +} + +void SyncPrefs::SetCleanShutdown(bool value) { + pref_service_->SetBoolean(prefs::kSyncShutdownCleanly, value); +} + } // namespace sync_driver + +
diff --git a/components/sync_driver/sync_prefs.h b/components/sync_driver/sync_prefs.h index 5a3abe5..10b3bcd 100644 --- a/components/sync_driver/sync_prefs.h +++ b/components/sync_driver/sync_prefs.h
@@ -143,6 +143,16 @@ // For testing. void SetManagedForTest(bool is_managed); + // Get/Set number of memory warnings received. + int GetMemoryPressureWarningCount() const; + void SetMemoryPressureWarningCount(int value); + + // Check if the previous shutdown was clean. + bool DidSyncShutdownCleanly() const; + + // Set whetherthe last shutdown was clean. + void SetCleanShutdown(bool value); + private: void RegisterPrefGroups();
diff --git a/components/user_manager/user_manager_base.cc b/components/user_manager/user_manager_base.cc index 8b1feae..3e11ff8 100644 --- a/components/user_manager/user_manager_base.cc +++ b/components/user_manager/user_manager_base.cc
@@ -1148,6 +1148,10 @@ void UserManagerBase::SetKnownUserDeviceId(const UserID& user_id, const std::string& device_id) { + const std::string known_device_id = GetKnownUserDeviceId(user_id); + if (!known_device_id.empty() && device_id != known_device_id) { + NOTREACHED() << "Trying to change device ID for known user."; + } SetKnownUserStringPref(user_id, kDeviceId, device_id); }
diff --git a/components/webcrypto/jwk.cc b/components/webcrypto/jwk.cc index 4e1781d..8a9ad74 100644 --- a/components/webcrypto/jwk.cc +++ b/components/webcrypto/jwk.cc
@@ -369,7 +369,7 @@ void JwkWriter::ToJson(std::vector<uint8_t>* utf8_bytes) const { std::string json; - base::JSONWriter::Write(&dict_, &json); + base::JSONWriter::Write(dict_, &json); utf8_bytes->assign(json.begin(), json.end()); }
diff --git a/components/webcrypto/test/test_helpers.cc b/components/webcrypto/test/test_helpers.cc index 76da7fa..8e24c95f 100644 --- a/components/webcrypto/test/test_helpers.cc +++ b/components/webcrypto/test/test_helpers.cc
@@ -168,7 +168,7 @@ std::vector<uint8_t> MakeJsonVector(const base::DictionaryValue& dict) { std::string json; - base::JSONWriter::Write(&dict, &json); + base::JSONWriter::Write(dict, &json); return MakeJsonVector(json); }
diff --git a/content/browser/accessibility/accessibility_tree_formatter_mac.mm b/content/browser/accessibility/accessibility_tree_formatter_mac.mm index 7b99225..b3799a9 100644 --- a/content/browser/accessibility/accessibility_tree_formatter_mac.mm +++ b/content/browser/accessibility/accessibility_tree_formatter_mac.mm
@@ -267,7 +267,7 @@ const base::Value* value; if (dict.Get(requestedAttributeUTF8, &value)) { std::string json_value; - base::JSONWriter::Write(value, &json_value); + base::JSONWriter::Write(*value, &json_value); WriteAttribute( [defaultAttributes containsObject:requestedAttribute], StringPrintf("%s=%s",
diff --git a/content/browser/accessibility/accessibility_ui.cc b/content/browser/accessibility/accessibility_ui.cc index 3bfa6ee6..1a46646 100644 --- a/content/browser/accessibility/accessibility_ui.cc +++ b/content/browser/accessibility/accessibility_ui.cc
@@ -116,14 +116,14 @@ rvh_list->Append(BuildTargetDescriptor(rvh)); } - scoped_ptr<base::DictionaryValue> data(new base::DictionaryValue()); - data->Set("list", rvh_list.release()); - data->SetInteger( + base::DictionaryValue data; + data.Set("list", rvh_list.release()); + data.SetInteger( "global_a11y_mode", BrowserAccessibilityStateImpl::GetInstance()->accessibility_mode()); std::string json_string; - base::JSONWriter::Write(data.get(), &json_string); + base::JSONWriter::Write(data, &json_string); callback.Run(base::RefCountedString::TakeString(&json_string)); return true;
diff --git a/content/browser/android/in_process/synchronous_compositor_impl.cc b/content/browser/android/in_process/synchronous_compositor_impl.cc index 24232ae..d3c6b83 100644 --- a/content/browser/android/in_process/synchronous_compositor_impl.cc +++ b/content/browser/android/in_process/synchronous_compositor_impl.cc
@@ -316,6 +316,7 @@ void SynchronousCompositorImpl::DidActivatePendingTree() { DCHECK(compositor_client_); compositor_client_->DidUpdateContent(); + DeliverMessages(); } gfx::ScrollOffset SynchronousCompositorImpl::GetTotalScrollOffset() {
diff --git a/content/browser/android/tracing_controller_android.cc b/content/browser/android/tracing_controller_android.cc index 6953a0de..5c14535a 100644 --- a/content/browser/android/tracing_controller_android.cc +++ b/content/browser/android/tracing_controller_android.cc
@@ -91,14 +91,14 @@ void TracingControllerAndroid::OnKnownCategoriesReceived( const std::set<std::string>& categories_received) { - scoped_ptr<base::ListValue> category_list(new base::ListValue()); + base::ListValue category_list; for (std::set<std::string>::const_iterator it = categories_received.begin(); it != categories_received.end(); ++it) { - category_list->AppendString(*it); + category_list.AppendString(*it); } std::string received_category_list; - base::JSONWriter::Write(category_list.get(), &received_category_list); + base::JSONWriter::Write(category_list, &received_category_list); // This log is required by adb_profile_chrome.py. LOG(WARNING) << "{\"traceCategoriesList\": " << received_category_list << "}";
diff --git a/content/browser/appcache/appcache_disk_cache.cc b/content/browser/appcache/appcache_disk_cache.cc index 382ed45..03d348c7 100644 --- a/content/browser/appcache/appcache_disk_cache.cc +++ b/content/browser/appcache/appcache_disk_cache.cc
@@ -8,6 +8,7 @@ #include "base/bind_helpers.h" #include "base/files/file_path.h" #include "base/logging.h" +#include "base/memory/ref_counted.h" #include "base/single_thread_task_runner.h" #include "base/stl_util.h" #include "base/strings/string_number_conversions.h" @@ -114,70 +115,95 @@ // Separate object to hold state for each Create, Delete, or Doom call // while the call is in-flight and to produce an EntryImpl upon completion. -class AppCacheDiskCache::ActiveCall { +class AppCacheDiskCache::ActiveCall + : public base::RefCounted<AppCacheDiskCache::ActiveCall> { public: - explicit ActiveCall(AppCacheDiskCache* owner) - : entry_(NULL), - owner_(owner), - entry_ptr_(NULL) { + static int CreateEntry(const base::WeakPtr<AppCacheDiskCache>& owner, + int64 key, Entry** entry, + const net::CompletionCallback& callback) { + scoped_refptr<ActiveCall> active_call( + new ActiveCall(owner, entry, callback)); + int rv = owner->disk_cache()->CreateEntry( + base::Int64ToString(key), &active_call->entry_ptr_, + base::Bind(&ActiveCall::OnAsyncCompletion, active_call)); + return active_call->HandleImmediateReturnValue(rv); } - int CreateEntry(int64 key, Entry** entry, - const net::CompletionCallback& callback) { - int rv = owner_->disk_cache()->CreateEntry( - base::Int64ToString(key), &entry_ptr_, - base::Bind(&ActiveCall::OnAsyncCompletion, base::Unretained(this))); - return HandleImmediateReturnValue(rv, entry, callback); + static int OpenEntry(const base::WeakPtr<AppCacheDiskCache>& owner, + int64 key, Entry** entry, + const net::CompletionCallback& callback) { + scoped_refptr<ActiveCall> active_call( + new ActiveCall(owner, entry, callback)); + int rv = owner->disk_cache()->OpenEntry( + base::Int64ToString(key), &active_call->entry_ptr_, + base::Bind(&ActiveCall::OnAsyncCompletion, active_call)); + return active_call->HandleImmediateReturnValue(rv); } - int OpenEntry(int64 key, Entry** entry, - const net::CompletionCallback& callback) { - int rv = owner_->disk_cache()->OpenEntry( - base::Int64ToString(key), &entry_ptr_, - base::Bind(&ActiveCall::OnAsyncCompletion, base::Unretained(this))); - return HandleImmediateReturnValue(rv, entry, callback); - } - - int DoomEntry(int64 key, const net::CompletionCallback& callback) { - int rv = owner_->disk_cache()->DoomEntry( + static int DoomEntry(const base::WeakPtr<AppCacheDiskCache>& owner, + int64 key, const net::CompletionCallback& callback) { + scoped_refptr<ActiveCall> active_call( + new ActiveCall(owner, nullptr, callback)); + int rv = owner->disk_cache()->DoomEntry( base::Int64ToString(key), - base::Bind(&ActiveCall::OnAsyncCompletion, base::Unretained(this))); - return HandleImmediateReturnValue(rv, NULL, callback); + base::Bind(&ActiveCall::OnAsyncCompletion, active_call)); + return active_call->HandleImmediateReturnValue(rv); } private: - int HandleImmediateReturnValue(int rv, Entry** entry, - const net::CompletionCallback& callback) { + friend class base::RefCounted<AppCacheDiskCache::ActiveCall>; + + ActiveCall(const base::WeakPtr<AppCacheDiskCache>& owner, + Entry** entry, + const net::CompletionCallback& callback) + : owner_(owner), + entry_(entry), + callback_(callback), + entry_ptr_(nullptr) { + DCHECK(owner_); + } + + ~ActiveCall() {} + + int HandleImmediateReturnValue(int rv) { if (rv == net::ERR_IO_PENDING) { // OnAsyncCompletion will be called later. - callback_ = callback; - entry_ = entry; - owner_->AddActiveCall(this); - return net::ERR_IO_PENDING; + return rv; } - if (rv == net::OK && entry) - *entry = new EntryImpl(entry_ptr_, owner_); - delete this; + + if (rv == net::OK && entry_) { + DCHECK(entry_ptr_); + *entry_ = new EntryImpl(entry_ptr_, owner_.get()); + } return rv; } void OnAsyncCompletion(int rv) { - owner_->RemoveActiveCall(this); - if (rv == net::OK && entry_) - *entry_ = new EntryImpl(entry_ptr_, owner_); + if (rv == net::OK && entry_) { + DCHECK(entry_ptr_); + if (owner_) { + *entry_ = new EntryImpl(entry_ptr_, owner_.get()); + } else { + entry_ptr_->Close(); + rv = net::ERR_ABORTED; + } + } callback_.Run(rv); - callback_.Reset(); - delete this; } + base::WeakPtr<AppCacheDiskCache> owner_; Entry** entry_; net::CompletionCallback callback_; - AppCacheDiskCache* owner_; disk_cache::Entry* entry_ptr_; }; AppCacheDiskCache::AppCacheDiskCache() - : is_disabled_(false) { +#if defined(APPCACHE_USE_SIMPLE_CACHE) + : AppCacheDiskCache(true) +#else + : AppCacheDiskCache(false) +#endif +{ } AppCacheDiskCache::~AppCacheDiskCache() { @@ -225,7 +251,6 @@ } open_entries_.clear(); disk_cache_.reset(); - STLDeleteElements(&active_calls_); } int AppCacheDiskCache::CreateEntry(int64 key, Entry** entry, @@ -243,7 +268,8 @@ if (!disk_cache_) return net::ERR_FAILED; - return (new ActiveCall(this))->CreateEntry(key, entry, callback); + return ActiveCall::CreateEntry( + weak_factory_.GetWeakPtr(), key, entry, callback); } int AppCacheDiskCache::OpenEntry(int64 key, Entry** entry, @@ -261,7 +287,8 @@ if (!disk_cache_) return net::ERR_FAILED; - return (new ActiveCall(this))->OpenEntry(key, entry, callback); + return ActiveCall::OpenEntry( + weak_factory_.GetWeakPtr(), key, entry, callback); } int AppCacheDiskCache::DoomEntry(int64 key, @@ -278,7 +305,13 @@ if (!disk_cache_) return net::ERR_FAILED; - return (new ActiveCall(this))->DoomEntry(key, callback); + return ActiveCall::DoomEntry(weak_factory_.GetWeakPtr(), key, callback); +} + +AppCacheDiskCache::AppCacheDiskCache(bool use_simple_cache) + : use_simple_cache_(use_simple_cache), + is_disabled_(false), + weak_factory_(this) { } AppCacheDiskCache::PendingCall::PendingCall() @@ -310,14 +343,10 @@ is_disabled_ = false; create_backend_callback_ = new CreateBackendCallbackShim(this); -#if defined(APPCACHE_USE_SIMPLE_CACHE) - const net::BackendType backend_type = net::CACHE_BACKEND_SIMPLE; -#else - const net::BackendType backend_type = net::CACHE_BACKEND_DEFAULT; -#endif int rv = disk_cache::CreateCacheBackend( cache_type, - backend_type, + use_simple_cache_ ? net::CACHE_BACKEND_SIMPLE + : net::CACHE_BACKEND_DEFAULT, cache_directory, cache_size, force,
diff --git a/content/browser/appcache/appcache_disk_cache.h b/content/browser/appcache/appcache_disk_cache.h index 8995e83c..9165e1d 100644 --- a/content/browser/appcache/appcache_disk_cache.h +++ b/content/browser/appcache/appcache_disk_cache.h
@@ -52,6 +52,9 @@ const net::CompletionCallback& callback) override; int DoomEntry(int64 key, const net::CompletionCallback& callback) override; + protected: + explicit AppCacheDiskCache(bool use_simple_cache); + private: class CreateBackendCallbackShim; class EntryImpl; @@ -96,18 +99,18 @@ const scoped_refptr<base::SingleThreadTaskRunner>& cache_thread, const net::CompletionCallback& callback); void OnCreateBackendComplete(int rv); - void AddActiveCall(ActiveCall* call) { active_calls_.insert(call); } - void RemoveActiveCall(ActiveCall* call) { active_calls_.erase(call); } void AddOpenEntry(EntryImpl* entry) { open_entries_.insert(entry); } void RemoveOpenEntry(EntryImpl* entry) { open_entries_.erase(entry); } + bool use_simple_cache_; bool is_disabled_; net::CompletionCallback init_callback_; scoped_refptr<CreateBackendCallbackShim> create_backend_callback_; PendingCalls pending_calls_; - ActiveCalls active_calls_; OpenEntries open_entries_; scoped_ptr<disk_cache::Backend> disk_cache_; + + base::WeakPtrFactory<AppCacheDiskCache> weak_factory_; }; } // namespace content
diff --git a/content/browser/browser_main_loop.cc b/content/browser/browser_main_loop.cc index 4d6c6c3..643cd38 100644 --- a/content/browser/browser_main_loop.cc +++ b/content/browser/browser_main_loop.cc
@@ -50,7 +50,6 @@ #include "content/common/host_discardable_shared_memory_manager.h" #include "content/common/host_shared_bitmap_manager.h" #include "content/public/browser/browser_main_parts.h" -#include "content/public/browser/browser_shutdown.h" #include "content/public/browser/content_browser_client.h" #include "content/public/browser/render_process_host.h" #include "content/public/browser/tracing_controller.h" @@ -336,30 +335,6 @@ // The currently-running BrowserMainLoop. There can be one or zero. BrowserMainLoop* g_current_browser_main_loop = NULL; -// This is just to be able to keep ShutdownThreadsAndCleanUp out of -// the public interface of BrowserMainLoop. -class BrowserShutdownImpl { - public: - static void ImmediateShutdownAndExitProcess() { - DCHECK(g_current_browser_main_loop); - g_current_browser_main_loop->ShutdownThreadsAndCleanUp(); - -#if defined(OS_WIN) - // At this point the message loop is still running yet we've shut everything - // down. If any messages are processed we'll likely crash. Exit now. - ExitProcess(RESULT_CODE_NORMAL_EXIT); -#elif defined(OS_POSIX) && !defined(OS_MACOSX) - _exit(RESULT_CODE_NORMAL_EXIT); -#else - NOTIMPLEMENTED(); -#endif - } -}; - -void ImmediateShutdownAndExitProcess() { - BrowserShutdownImpl::ImmediateShutdownAndExitProcess(); -} - // For measuring memory usage after each task. Behind a command line flag. class BrowserMainLoop::MemoryObserver : public base::MessageLoop::TaskObserver { public:
diff --git a/content/browser/devtools/devtools_agent_host_impl.cc b/content/browser/devtools/devtools_agent_host_impl.cc index cba575e..4ccb496 100644 --- a/content/browser/devtools/devtools_agent_host_impl.cc +++ b/content/browser/devtools/devtools_agent_host_impl.cc
@@ -242,7 +242,7 @@ delegate->HandleCommand(this, command.get())); if (response) { std::string json_response; - base::JSONWriter::Write(response.get(), &json_response); + base::JSONWriter::Write(*response, &json_response); SendMessageToClient(json_response); return true; }
diff --git a/content/browser/devtools/protocol/devtools_protocol_browsertest.cc b/content/browser/devtools/protocol/devtools_protocol_browsertest.cc index cbae682..573aca4 100644 --- a/content/browser/devtools/protocol/devtools_protocol_browsertest.cc +++ b/content/browser/devtools/protocol/devtools_protocol_browsertest.cc
@@ -39,7 +39,7 @@ command.Set(kParamsParam, params.release()); std::string json_command; - base::JSONWriter::Write(&command, &json_command); + base::JSONWriter::Write(command, &json_command); agent_host_->DispatchProtocolMessage(json_command); base::MessageLoop::current()->Run(); }
diff --git a/content/browser/devtools/protocol/devtools_protocol_client.cc b/content/browser/devtools/protocol/devtools_protocol_client.cc index 4658b08..4b7c25d 100644 --- a/content/browser/devtools/protocol/devtools_protocol_client.cc +++ b/content/browser/devtools/protocol/devtools_protocol_client.cc
@@ -46,7 +46,7 @@ void DevToolsProtocolClient::SendMessage(const base::DictionaryValue& message) { std::string json_message; - base::JSONWriter::Write(&message, &json_message); + base::JSONWriter::Write(message, &json_message); SendRawMessage(json_message); }
diff --git a/content/browser/devtools/render_frame_devtools_agent_host.cc b/content/browser/devtools/render_frame_devtools_agent_host.cc index 6f40d6fa..665885a2 100644 --- a/content/browser/devtools/render_frame_devtools_agent_host.cc +++ b/content/browser/devtools/render_frame_devtools_agent_host.cc
@@ -417,6 +417,7 @@ void RenderFrameDevToolsAgentHost::ClearRenderFrameHost() { DCHECK(render_frame_host_); render_frame_host_ = nullptr; + WebContentsObserver::Observe(nullptr); dom_handler_->SetRenderFrameHost(nullptr); if (emulation_handler_) emulation_handler_->SetRenderFrameHost(nullptr);
diff --git a/content/browser/dom_storage/dom_storage_area.cc b/content/browser/dom_storage/dom_storage_area.cc index 67c7b98..e76f5c9 100644 --- a/content/browser/dom_storage/dom_storage_area.cc +++ b/content/browser/dom_storage/dom_storage_area.cc
@@ -37,8 +37,8 @@ // To avoid excessive IO we apply limits to the amount of data being written // and the frequency of writes. The specific values used are somewhat arbitrary. -const int kMaxBytesPerDay = kPerStorageAreaQuota * 2; -const int kMaxCommitsPerHour = 6; +const int kMaxBytesPerHour = kPerStorageAreaQuota; +const int kMaxCommitsPerHour = 60; } // namespace @@ -109,7 +109,7 @@ is_shutdown_(false), commit_batches_in_flight_(0), start_time_(base::TimeTicks::Now()), - data_rate_limiter_(kMaxBytesPerDay, base::TimeDelta::FromHours(24)), + data_rate_limiter_(kMaxBytesPerHour, base::TimeDelta::FromHours(1)), commit_rate_limiter_(kMaxCommitsPerHour, base::TimeDelta::FromHours(1)) { if (!directory.empty()) { base::FilePath path = directory.Append(DatabaseFileNameFromOrigin(origin_)); @@ -134,7 +134,7 @@ is_shutdown_(false), commit_batches_in_flight_(0), start_time_(base::TimeTicks::Now()), - data_rate_limiter_(kMaxBytesPerDay, base::TimeDelta::FromHours(24)), + data_rate_limiter_(kMaxBytesPerHour, base::TimeDelta::FromHours(1)), commit_rate_limiter_(kMaxCommitsPerHour, base::TimeDelta::FromHours(1)) { DCHECK(namespace_id != kLocalStorageNamespaceId); if (session_storage_backing) {
diff --git a/content/browser/frame_host/navigation_controller_impl.cc b/content/browser/frame_host/navigation_controller_impl.cc index 8339b730..b9d69554 100644 --- a/content/browser/frame_host/navigation_controller_impl.cc +++ b/content/browser/frame_host/navigation_controller_impl.cc
@@ -13,6 +13,7 @@ #include "base/strings/utf_string_conversions.h" #include "base/time/time.h" #include "base/trace_event/trace_event.h" +#include "build/build_config.h" #include "cc/base/switches.h" #include "components/mime_util/mime_util.h" #include "content/browser/bad_message.h" @@ -40,8 +41,8 @@ #include "content/public/common/content_client.h" #include "content/public/common/content_constants.h" #include "content/public/common/content_switches.h" +#include "media/base/mime_util.h" #include "net/base/escape.h" -#include "net/base/mime_util.h" #include "net/base/net_util.h" #include "skia/ext/platform_canvas.h" #include "url/url_constants.h" @@ -496,7 +497,7 @@ const std::string& mime_type = delegate_->GetContentsMimeType(); bool is_viewable_mime_type = mime_util::IsSupportedNonImageMimeType(mime_type) && - !net::IsSupportedMediaMimeType(mime_type); + !media::IsSupportedMediaMimeType(mime_type); NavigationEntry* visible_entry = GetVisibleEntry(); return visible_entry && !visible_entry->IsViewSourceMode() && is_viewable_mime_type && !delegate_->GetInterstitialPage();
diff --git a/content/browser/frame_host/render_frame_host_impl_browsertest.cc b/content/browser/frame_host/render_frame_host_impl_browsertest.cc index 9344c92..33826a0 100644 --- a/content/browser/frame_host/render_frame_host_impl_browsertest.cc +++ b/content/browser/frame_host/render_frame_host_impl_browsertest.cc
@@ -56,7 +56,9 @@ using RenderFrameHostImplBrowserTest = ContentBrowserTest; // Test that when creating a new window, the main frame is correctly focused. -IN_PROC_BROWSER_TEST_F(RenderFrameHostImplBrowserTest, IsFocused_AtLoad) { +// flaky http://crbug.com/452631 +IN_PROC_BROWSER_TEST_F(RenderFrameHostImplBrowserTest, + DISABLED_IsFocused_AtLoad) { EXPECT_TRUE( NavigateToURL(shell(), GetTestUrl("render_frame_host", "focus.html"))); @@ -122,7 +124,9 @@ // Test that even if the frame is focused in the frame tree but its // RenderWidgetHost is not focused, it is not considered as focused. -IN_PROC_BROWSER_TEST_F(RenderFrameHostImplBrowserTest, IsFocused_Widget) { +// flaky http://crbug.com/452631 +IN_PROC_BROWSER_TEST_F(RenderFrameHostImplBrowserTest, + DISABLED_IsFocused_Widget) { EXPECT_TRUE( NavigateToURL(shell(), GetTestUrl("render_frame_host", "focus.html"))); WebContents* web_contents = shell()->web_contents();
diff --git a/content/browser/frame_host/render_frame_host_manager_unittest.cc b/content/browser/frame_host/render_frame_host_manager_unittest.cc index 0d36597..ec75f5b 100644 --- a/content/browser/frame_host/render_frame_host_manager_unittest.cc +++ b/content/browser/frame_host/render_frame_host_manager_unittest.cc
@@ -202,6 +202,31 @@ DISALLOW_COPY_AND_ASSIGN(RenderFrameHostDeletedObserver); }; +// This WebContents observer keep track of its RVH change. +class RenderViewHostChangedObserver : public WebContentsObserver { + public: + RenderViewHostChangedObserver(WebContents* web_contents) + : WebContentsObserver(web_contents), host_changed_(false) {} + + // WebContentsObserver. + void RenderViewHostChanged(RenderViewHost* old_host, + RenderViewHost* new_host) override { + host_changed_ = true; + } + + bool DidHostChange() { + bool host_changed = host_changed_; + Reset(); + return host_changed; + } + + void Reset() { host_changed_ = false; } + + private: + bool host_changed_; + DISALLOW_COPY_AND_ASSIGN(RenderViewHostChangedObserver); +}; + // This observer is used to check whether IPC messages are being filtered for // swapped out RenderFrameHost objects. It observes the plugin crash and favicon // update events, which the FilterMessagesWhileSwappedOut test simulates being @@ -932,14 +957,11 @@ // Tests the Navigate function. We navigate three sites consecutively and check // how the pending/committed RenderViewHost are modified. TEST_F(RenderFrameHostManagerTest, Navigate) { - TestNotificationTracker notifications; - SiteInstance* instance = SiteInstance::Create(browser_context()); scoped_ptr<TestWebContents> web_contents( TestWebContents::Create(browser_context(), instance)); - notifications.ListenFor(NOTIFICATION_RENDER_VIEW_HOST_CHANGED, - Source<WebContents>(web_contents.get())); + RenderViewHostChangedObserver change_observer(web_contents.get()); RenderFrameHostManager* manager = web_contents->GetRenderManagerForTesting(); RenderFrameHostImpl* host = NULL; @@ -996,7 +1018,7 @@ EXPECT_TRUE(GetPendingFrameHost(manager)); ASSERT_EQ(host, GetPendingFrameHost(manager)); - notifications.Reset(); + change_observer.Reset(); // Commit. manager->DidNavigateFrame(GetPendingFrameHost(manager), true); @@ -1006,9 +1028,8 @@ // Check the pending RenderFrameHost has been committed. EXPECT_FALSE(GetPendingFrameHost(manager)); - // We should observe a notification. - EXPECT_TRUE( - notifications.Check1AndReset(NOTIFICATION_RENDER_VIEW_HOST_CHANGED)); + // We should observe RVH changed event. + EXPECT_TRUE(change_observer.DidHostChange()); } // Tests WebUI creation. @@ -1612,8 +1633,6 @@ // Test that we reuse the same guest SiteInstance if we navigate across sites. TEST_F(RenderFrameHostManagerTest, NoSwapOnGuestNavigations) { - TestNotificationTracker notifications; - GURL guest_url(std::string(kGuestScheme).append("://abc123")); SiteInstance* instance = SiteInstance::CreateForURL(browser_context(), guest_url); @@ -1675,9 +1694,8 @@ BeforeUnloadFiredWebContentsDelegate delegate; scoped_ptr<TestWebContents> web_contents( TestWebContents::Create(browser_context(), instance)); + RenderViewHostChangedObserver change_observer(web_contents.get()); web_contents->SetDelegate(&delegate); - notifications.ListenFor(NOTIFICATION_RENDER_VIEW_HOST_CHANGED, - Source<WebContents>(web_contents.get())); RenderFrameHostManager* manager = web_contents->GetRenderManagerForTesting(); @@ -1693,10 +1711,8 @@ EXPECT_EQ(host, manager->current_frame_host()); EXPECT_FALSE(GetPendingFrameHost(manager)); - // We should observe a notification. - EXPECT_TRUE( - notifications.Check1AndReset(NOTIFICATION_RENDER_VIEW_HOST_CHANGED)); - notifications.Reset(); + // We should observe RVH changed event. + EXPECT_TRUE(change_observer.DidHostChange()); // Commit. manager->DidNavigateFrame(host, true);
diff --git a/content/browser/geolocation/network_location_provider_unittest.cc b/content/browser/geolocation/network_location_provider_unittest.cc index b8ef6ca..cc43330b 100644 --- a/content/browser/geolocation/network_location_provider_unittest.cc +++ b/content/browser/geolocation/network_location_provider_unittest.cc
@@ -191,7 +191,7 @@ static std::string PrettyJson(const base::Value& value) { std::string pretty; base::JSONWriter::WriteWithOptions( - &value, base::JSONWriter::OPTIONS_PRETTY_PRINT, &pretty); + value, base::JSONWriter::OPTIONS_PRETTY_PRINT, &pretty); return pretty; }
diff --git a/content/browser/geolocation/network_location_request.cc b/content/browser/geolocation/network_location_request.cc index 253e321b..2a6c17ca 100644 --- a/content/browser/geolocation/network_location_request.cc +++ b/content/browser/geolocation/network_location_request.cc
@@ -221,7 +221,7 @@ AddWifiData(wifi_data, age, &request); if (!access_token.empty()) request.SetString(kAccessTokenString, access_token); - base::JSONWriter::Write(&request, upload_data); + base::JSONWriter::Write(request, upload_data); } void AddString(const std::string& property_name, const std::string& value,
diff --git a/content/browser/indexed_db/indexed_db_backing_store.cc b/content/browser/indexed_db/indexed_db_backing_store.cc index 79ab192..819aba5 100644 --- a/content/browser/indexed_db/indexed_db_backing_store.cc +++ b/content/browser/indexed_db/indexed_db_backing_store.cc
@@ -958,7 +958,7 @@ base::DictionaryValue root_dict; root_dict.SetString("message", message); std::string output_js; - base::JSONWriter::Write(&root_dict, &output_js); + base::JSONWriter::Write(root_dict, &output_js); base::File file(info_path, base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
diff --git a/content/browser/indexed_db/indexed_db_database.cc b/content/browser/indexed_db/indexed_db_database.cc index 6fbc77f87..8a924eb4 100644 --- a/content/browser/indexed_db/indexed_db_database.cc +++ b/content/browser/indexed_db/indexed_db_database.cc
@@ -745,9 +745,7 @@ IndexedDBTransaction* transaction) { IDB_TRACE1("IndexedDBDatabase::GetAllOperation", "txn.id", transaction->id()); - DCHECK_GE(max_count, 0); - if (!max_count) - max_count = std::numeric_limits<decltype(max_count)>::max(); + DCHECK_GT(max_count, 0); DCHECK(metadata_.object_stores.find(object_store_id) != metadata_.object_stores.end());
diff --git a/content/browser/indexed_db/indexed_db_index_writer.cc b/content/browser/indexed_db/indexed_db_index_writer.cc index c9de8a3..53ae963 100644 --- a/content/browser/indexed_db/indexed_db_index_writer.cc +++ b/content/browser/indexed_db/indexed_db_index_writer.cc
@@ -160,7 +160,7 @@ if (!can_add_keys) return true; - index_writers->push_back(index_writer.release()); + index_writers->push_back(index_writer.Pass()); } *completed = true;
diff --git a/content/browser/media/capture/capture_resolution_chooser.cc b/content/browser/media/capture/capture_resolution_chooser.cc new file mode 100644 index 0000000..698882a --- /dev/null +++ b/content/browser/media/capture/capture_resolution_chooser.cc
@@ -0,0 +1,120 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/browser/media/capture/capture_resolution_chooser.h" + +#include "media/base/limits.h" +#include "media/base/video_util.h" + +namespace content { + +namespace { + +// Compute the minimum frame size from the given |max_frame_size| and +// |resolution_change_policy|. +gfx::Size ComputeMinimumCaptureSize( + const gfx::Size& max_frame_size, + media::ResolutionChangePolicy resolution_change_policy) { + switch (resolution_change_policy) { + case media::RESOLUTION_POLICY_FIXED_RESOLUTION: + return max_frame_size; + case media::RESOLUTION_POLICY_FIXED_ASPECT_RATIO: { + // TODO(miu): This is a place-holder until "min constraints" are plumbed- + // in from the MediaStream framework. http://crbug.com/473336 + const int kMinLines = 180; + if (max_frame_size.height() <= kMinLines) + return max_frame_size; + const gfx::Size result( + kMinLines * max_frame_size.width() / max_frame_size.height(), + kMinLines); + if (result.width() <= 0 || result.width() > media::limits::kMaxDimension) + return max_frame_size; + return result; + } + case media::RESOLUTION_POLICY_ANY_WITHIN_LIMIT: + return gfx::Size(1, 1); + case media::RESOLUTION_POLICY_LAST: + break; + } + NOTREACHED(); + return gfx::Size(1, 1); +} + +// Returns |size|, unless it exceeds |max_size| or is under |min_size|. When +// the bounds are exceeded, computes and returns an alternate size of similar +// aspect ratio that is within the bounds. +gfx::Size ComputeBoundedCaptureSize(const gfx::Size& size, + const gfx::Size& min_size, + const gfx::Size& max_size) { + if (size.width() > max_size.width() || size.height() > max_size.height()) { + gfx::Size result = media::ScaleSizeToFitWithinTarget(size, max_size); + result.SetToMax(min_size); + return result; + } else if (size.width() < min_size.width() || + size.height() < min_size.height()) { + gfx::Size result = media::ScaleSizeToEncompassTarget(size, min_size); + result.SetToMin(max_size); + return result; + } else { + return size; + } +} + +} // namespace + +CaptureResolutionChooser::CaptureResolutionChooser( + const gfx::Size& max_frame_size, + media::ResolutionChangePolicy resolution_change_policy) + : max_frame_size_(max_frame_size), + min_frame_size_(ComputeMinimumCaptureSize(max_frame_size, + resolution_change_policy)), + resolution_change_policy_(resolution_change_policy), + constrained_size_(max_frame_size) { + DCHECK_LT(0, max_frame_size_.width()); + DCHECK_LT(0, max_frame_size_.height()); + DCHECK_LE(min_frame_size_.width(), max_frame_size_.width()); + DCHECK_LE(min_frame_size_.height(), max_frame_size_.height()); + + RecomputeCaptureSize(); +} + +CaptureResolutionChooser::~CaptureResolutionChooser() {} + +void CaptureResolutionChooser::SetSourceSize(const gfx::Size& source_size) { + if (source_size.IsEmpty()) + return; + + switch (resolution_change_policy_) { + case media::RESOLUTION_POLICY_FIXED_RESOLUTION: + // Source size changes do not affect the frame resolution. Frame + // resolution is always fixed to |max_frame_size_|. + break; + + case media::RESOLUTION_POLICY_FIXED_ASPECT_RATIO: + constrained_size_ = ComputeBoundedCaptureSize( + media::PadToMatchAspectRatio(source_size, max_frame_size_), + min_frame_size_, + max_frame_size_); + RecomputeCaptureSize(); + break; + + case media::RESOLUTION_POLICY_ANY_WITHIN_LIMIT: + constrained_size_ = ComputeBoundedCaptureSize( + source_size, min_frame_size_, max_frame_size_); + RecomputeCaptureSize(); + break; + + case media::RESOLUTION_POLICY_LAST: + NOTREACHED(); + } +} + +void CaptureResolutionChooser::RecomputeCaptureSize() { + // TODO(miu): An upcoming change will introduce the ability to find the best + // capture resolution, given the current capabilities of the system. + // http://crbug.com/156767 + capture_size_ = constrained_size_; +} + +} // namespace content
diff --git a/content/browser/media/capture/capture_resolution_chooser.h b/content/browser/media/capture/capture_resolution_chooser.h new file mode 100644 index 0000000..f1bda79 --- /dev/null +++ b/content/browser/media/capture/capture_resolution_chooser.h
@@ -0,0 +1,59 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_BROWSER_MEDIA_CAPTURE_CAPTURE_RESOLUTION_CHOOSER_H_ +#define CONTENT_BROWSER_MEDIA_CAPTURE_CAPTURE_RESOLUTION_CHOOSER_H_ + +#include "content/common/content_export.h" +#include "media/base/video_capture_types.h" +#include "ui/gfx/geometry/size.h" + +namespace content { + +// Encapsulates the logic that determines the capture frame resolution based on: +// 1. The configured maximum frame resolution and resolution change policy. +// 2. The resolution of the source content. +// 3. The current capabilities of the end-to-end system, in terms of the +// maximum number of pixels per frame. +class CONTENT_EXPORT CaptureResolutionChooser { + public: + // media::ResolutionChangePolicy determines whether the variable frame + // resolutions being computed must adhere to a fixed aspect ratio or not, or + // that there must only be a single fixed resolution. + CaptureResolutionChooser( + const gfx::Size& max_frame_size, + media::ResolutionChangePolicy resolution_change_policy); + ~CaptureResolutionChooser(); + + // Returns the current capture frame resolution to use. + gfx::Size capture_size() const { + return capture_size_; + } + + // Updates the capture size based on a change in the resolution of the source + // content. + void SetSourceSize(const gfx::Size& source_size); + + private: + // Called after any update that requires |capture_size_| be re-computed. + void RecomputeCaptureSize(); + + // Hard constraints. + const gfx::Size max_frame_size_; + const gfx::Size min_frame_size_; // Computed from the ctor arguments. + + // Specifies the set of heuristics to use. + const media::ResolutionChangePolicy resolution_change_policy_; + + // The capture frame resolution to use, ignoring the limitations imposed by + // the capability metric. + gfx::Size constrained_size_; + + // The current computed capture frame resolution. + gfx::Size capture_size_; +}; + +} // namespace content + +#endif // CONTENT_BROWSER_MEDIA_CAPTURE_RESOLUTION_CHOOSER_H_
diff --git a/content/browser/media/capture/capture_resolution_chooser_unittest.cc b/content/browser/media/capture/capture_resolution_chooser_unittest.cc new file mode 100644 index 0000000..d91c0ce --- /dev/null +++ b/content/browser/media/capture/capture_resolution_chooser_unittest.cc
@@ -0,0 +1,169 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/browser/media/capture/capture_resolution_chooser.h" + +#include "base/location.h" +#include "testing/gtest/include/gtest/gtest.h" + +using tracked_objects::Location; + +namespace content { + +namespace { + +// 16:9 maximum and minimum frame sizes. +const int kMaxFrameWidth = 3840; +const int kMaxFrameHeight = 2160; +const int kMinFrameWidth = 320; +const int kMinFrameHeight = 180; + +// Checks whether |size| is strictly between (inclusive) |min_size| and +// |max_size| and has the same aspect ratio as |max_size|. +void ExpectIsWithinBoundsAndSameAspectRatio(const Location& location, + const gfx::Size& min_size, + const gfx::Size& max_size, + const gfx::Size& size) { + SCOPED_TRACE(::testing::Message() << "From here: " << location.ToString()); + EXPECT_LE(min_size.width(), size.width()); + EXPECT_LE(min_size.height(), size.height()); + EXPECT_GE(max_size.width(), size.width()); + EXPECT_GE(max_size.height(), size.height()); + EXPECT_NEAR(static_cast<double>(max_size.width()) / max_size.height(), + static_cast<double>(size.width()) / size.height(), + 0.01); +} + +} // namespace + +TEST(CaptureResolutionChooserTest, + FixedResolutionPolicy_CaptureSizeAlwaysFixed) { + const gfx::Size the_one_frame_size(kMaxFrameWidth, kMaxFrameHeight); + CaptureResolutionChooser chooser(the_one_frame_size, + media::RESOLUTION_POLICY_FIXED_RESOLUTION); + EXPECT_EQ(the_one_frame_size, chooser.capture_size()); + + chooser.SetSourceSize(the_one_frame_size); + EXPECT_EQ(the_one_frame_size, chooser.capture_size()); + + chooser.SetSourceSize(gfx::Size(kMaxFrameWidth + 424, kMaxFrameHeight - 101)); + EXPECT_EQ(the_one_frame_size, chooser.capture_size()); + + chooser.SetSourceSize(gfx::Size(kMaxFrameWidth - 202, kMaxFrameHeight + 56)); + EXPECT_EQ(the_one_frame_size, chooser.capture_size()); + + chooser.SetSourceSize(gfx::Size(kMinFrameWidth, kMinFrameHeight)); + EXPECT_EQ(the_one_frame_size, chooser.capture_size()); +} + +TEST(CaptureResolutionChooserTest, + FixedAspectRatioPolicy_CaptureSizeHasSameAspectRatio) { + CaptureResolutionChooser chooser( + gfx::Size(kMaxFrameWidth, kMaxFrameHeight), + media::RESOLUTION_POLICY_FIXED_ASPECT_RATIO); + + // Starting condition. + const gfx::Size min_size(kMinFrameWidth, kMinFrameHeight); + const gfx::Size max_size(kMaxFrameWidth, kMaxFrameHeight); + ExpectIsWithinBoundsAndSameAspectRatio( + FROM_HERE, min_size, max_size, chooser.capture_size()); + + // Max size in --> max size out. + chooser.SetSourceSize(gfx::Size(kMaxFrameWidth, kMaxFrameHeight)); + ExpectIsWithinBoundsAndSameAspectRatio( + FROM_HERE, min_size, max_size, chooser.capture_size()); + + // Various source sizes within bounds. + chooser.SetSourceSize(gfx::Size(640, 480)); + ExpectIsWithinBoundsAndSameAspectRatio( + FROM_HERE, min_size, max_size, chooser.capture_size()); + + chooser.SetSourceSize(gfx::Size(480, 640)); + ExpectIsWithinBoundsAndSameAspectRatio( + FROM_HERE, min_size, max_size, chooser.capture_size()); + + chooser.SetSourceSize(gfx::Size(640, 640)); + ExpectIsWithinBoundsAndSameAspectRatio( + FROM_HERE, min_size, max_size, chooser.capture_size()); + + // Bad source size results in no update. + const gfx::Size unchanged_size = chooser.capture_size(); + chooser.SetSourceSize(gfx::Size(0, 0)); + EXPECT_EQ(unchanged_size, chooser.capture_size()); + + // Downscaling size (preserving aspect ratio) when source size exceeds the + // upper bounds. + chooser.SetSourceSize(gfx::Size(kMaxFrameWidth * 2, kMaxFrameHeight * 2)); + ExpectIsWithinBoundsAndSameAspectRatio( + FROM_HERE, min_size, max_size, chooser.capture_size()); + + chooser.SetSourceSize(gfx::Size(kMaxFrameWidth * 2, kMaxFrameHeight)); + ExpectIsWithinBoundsAndSameAspectRatio( + FROM_HERE, min_size, max_size, chooser.capture_size()); + + chooser.SetSourceSize(gfx::Size(kMaxFrameWidth, kMaxFrameHeight * 2)); + ExpectIsWithinBoundsAndSameAspectRatio( + FROM_HERE, min_size, max_size, chooser.capture_size()); + + // Upscaling size (preserving aspect ratio) when source size is under the + // lower bounds. + chooser.SetSourceSize(gfx::Size(kMinFrameWidth / 2, kMinFrameHeight / 2)); + ExpectIsWithinBoundsAndSameAspectRatio( + FROM_HERE, min_size, max_size, chooser.capture_size()); + + chooser.SetSourceSize(gfx::Size(kMinFrameWidth / 2, kMaxFrameHeight)); + ExpectIsWithinBoundsAndSameAspectRatio( + FROM_HERE, min_size, max_size, chooser.capture_size()); + + chooser.SetSourceSize(gfx::Size(kMinFrameWidth, kMinFrameHeight / 2)); + ExpectIsWithinBoundsAndSameAspectRatio( + FROM_HERE, min_size, max_size, chooser.capture_size()); +} + +TEST(CaptureResolutionChooserTest, + AnyWithinLimitPolicy_CaptureSizeIsAnythingWithinLimits) { + const gfx::Size max_size(kMaxFrameWidth, kMaxFrameHeight); + CaptureResolutionChooser chooser( + max_size, media::RESOLUTION_POLICY_ANY_WITHIN_LIMIT); + + // Starting condition. + EXPECT_EQ(max_size, chooser.capture_size()); + + // Max size in --> max size out. + chooser.SetSourceSize(max_size); + EXPECT_EQ(max_size, chooser.capture_size()); + + // Various source sizes within bounds. + chooser.SetSourceSize(gfx::Size(640, 480)); + EXPECT_EQ(gfx::Size(640, 480), chooser.capture_size()); + + chooser.SetSourceSize(gfx::Size(480, 640)); + EXPECT_EQ(gfx::Size(480, 640), chooser.capture_size()); + + chooser.SetSourceSize(gfx::Size(640, 640)); + EXPECT_EQ(gfx::Size(640, 640), chooser.capture_size()); + + chooser.SetSourceSize(gfx::Size(2, 2)); + EXPECT_EQ(gfx::Size(2, 2), chooser.capture_size()); + + // Bad source size results in no update. + const gfx::Size unchanged_size = chooser.capture_size(); + chooser.SetSourceSize(gfx::Size(0, 0)); + EXPECT_EQ(unchanged_size, chooser.capture_size()); + + // Downscaling size (preserving aspect ratio) when source size exceeds the + // upper bounds. + chooser.SetSourceSize(gfx::Size(kMaxFrameWidth * 2, kMaxFrameHeight * 2)); + EXPECT_EQ(max_size, chooser.capture_size()); + + chooser.SetSourceSize(gfx::Size(kMaxFrameWidth * 2, kMaxFrameHeight)); + EXPECT_EQ(gfx::Size(kMaxFrameWidth, kMaxFrameHeight / 2), + chooser.capture_size()); + + chooser.SetSourceSize(gfx::Size(kMaxFrameWidth, kMaxFrameHeight * 2)); + EXPECT_EQ(gfx::Size(kMaxFrameWidth / 2, kMaxFrameHeight), + chooser.capture_size()); +} + +} // namespace content
diff --git a/content/browser/media/capture/content_video_capture_device_core.cc b/content/browser/media/capture/content_video_capture_device_core.cc index 8d44104c..da0862c 100644 --- a/content/browser/media/capture/content_video_capture_device_core.cc +++ b/content/browser/media/capture/content_video_capture_device_core.cc
@@ -49,7 +49,9 @@ oracle_(base::TimeDelta::FromMicroseconds( static_cast<int64>(1000000.0 / params.requested_format.frame_rate + 0.5 /* to round to nearest int */))), - params_(params) {} + params_(params), + resolution_chooser_(params.requested_format.frame_size, + params.resolution_change_policy) {} ThreadSafeCaptureOracle::~ThreadSafeCaptureOracle() {} @@ -67,9 +69,7 @@ if (!client_) return false; // Capture is stopped. - if (capture_size_.IsEmpty()) - capture_size_ = max_frame_size(); - const gfx::Size visible_size = capture_size_; + const gfx::Size visible_size = resolution_chooser_.capture_size(); // Always round up the coded size to multiple of 16 pixels. // See http://crbug.com/402151. const gfx::Size coded_size((visible_size.width() + 15) & ~15, @@ -141,30 +141,15 @@ gfx::Size ThreadSafeCaptureOracle::GetCaptureSize() const { base::AutoLock guard(lock_); - return capture_size_.IsEmpty() ? max_frame_size() : capture_size_; + return resolution_chooser_.capture_size(); } void ThreadSafeCaptureOracle::UpdateCaptureSize(const gfx::Size& source_size) { base::AutoLock guard(lock_); - - // Update |capture_size_| based on |source_size| if either: 1) The resolution - // change policy specifies fixed frame sizes and |capture_size_| has not yet - // been set; or 2) The resolution change policy specifies dynamic frame - // sizes. - if (capture_size_.IsEmpty() || params_.resolution_change_policy == - media::RESOLUTION_POLICY_ANY_WITHIN_LIMIT) { - capture_size_ = source_size; - // The capture size should not exceed the maximum frame size. - if (capture_size_.width() > max_frame_size().width() || - capture_size_.height() > max_frame_size().height()) { - capture_size_ = media::ComputeLetterboxRegion( - gfx::Rect(max_frame_size()), capture_size_).size(); - } - // The capture size must be even and not less than the minimum frame size. - capture_size_ = gfx::Size( - std::max(kMinFrameWidth, MakeEven(capture_size_.width())), - std::max(kMinFrameHeight, MakeEven(capture_size_.height()))); - } + resolution_chooser_.SetSourceSize(source_size); + VLOG(1) << "Source size changed to " << source_size.ToString() + << " --> Capture size is now " + << resolution_chooser_.capture_size().ToString(); } void ThreadSafeCaptureOracle::Stop() { @@ -234,23 +219,15 @@ return; } - if (params.requested_format.frame_size.width() < kMinFrameWidth || - params.requested_format.frame_size.height() < kMinFrameHeight) { - std::string error_msg = - "invalid frame size: " + params.requested_format.frame_size.ToString(); - DVLOG(1) << error_msg; - client->OnError(error_msg); - return; - } + if (params.requested_format.frame_size.IsEmpty()) { + std::string error_msg = + "invalid frame size: " + params.requested_format.frame_size.ToString(); + DVLOG(1) << error_msg; + client->OnError(error_msg); + return; + } - media::VideoCaptureParams new_params = params; - // Frame dimensions must each be an even integer since the client wants (or - // will convert to) YUV420. - new_params.requested_format.frame_size.SetSize( - MakeEven(params.requested_format.frame_size.width()), - MakeEven(params.requested_format.frame_size.height())); - - oracle_proxy_ = new ThreadSafeCaptureOracle(client.Pass(), new_params); + oracle_proxy_ = new ThreadSafeCaptureOracle(client.Pass(), params); // Starts the capture machine asynchronously. BrowserThread::PostTaskAndReplyWithResult( @@ -259,7 +236,7 @@ base::Bind(&VideoCaptureMachine::Start, base::Unretained(capture_machine_.get()), oracle_proxy_, - new_params), + params), base::Bind(&ContentVideoCaptureDeviceCore::CaptureStarted, AsWeakPtr())); TransitionStateTo(kCapturing);
diff --git a/content/browser/media/capture/content_video_capture_device_core.h b/content/browser/media/capture/content_video_capture_device_core.h index f477a15..67dffd6 100644 --- a/content/browser/media/capture/content_video_capture_device_core.h +++ b/content/browser/media/capture/content_video_capture_device_core.h
@@ -11,6 +11,7 @@ #include "base/memory/weak_ptr.h" #include "base/threading/thread.h" #include "base/threading/thread_checker.h" +#include "content/browser/media/capture/capture_resolution_chooser.h" #include "content/browser/media/capture/video_capture_oracle.h" #include "content/common/content_export.h" #include "media/base/video_frame.h" @@ -23,15 +24,6 @@ namespace content { -const int kMinFrameWidth = 2; -const int kMinFrameHeight = 2; - -// Returns the nearest even integer closer to zero. -template<typename IntType> -IntType MakeEven(IntType x) { - return x & static_cast<IntType>(-2); -} - class VideoCaptureMachine; // Thread-safe, refcounted proxy to the VideoCaptureOracle. This proxy wraps @@ -104,8 +96,8 @@ // The video capture parameters used to construct the oracle proxy. const media::VideoCaptureParams params_; - // The current video capture size. - gfx::Size capture_size_; + // Determines video capture frame sizes. + CaptureResolutionChooser resolution_chooser_; }; // Keeps track of the video capture source frames and executes copying on the
diff --git a/content/browser/media/capture/desktop_capture_device.cc b/content/browser/media/capture/desktop_capture_device.cc index a11e473..e42a678 100644 --- a/content/browser/media/capture/desktop_capture_device.cc +++ b/content/browser/media/capture/desktop_capture_device.cc
@@ -12,6 +12,7 @@ #include "base/synchronization/lock.h" #include "base/threading/thread.h" #include "base/timer/timer.h" +#include "content/browser/media/capture/capture_resolution_chooser.h" #include "content/browser/media/capture/desktop_capture_device_uma_types.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/desktop_media_id.h" @@ -72,11 +73,6 @@ webrtc::SharedMemory* CreateSharedMemory(size_t size) override; void OnCaptureCompleted(webrtc::DesktopFrame* frame) override; - // Chooses new output properties based on the supplied source size and the - // properties requested to Allocate(), and dispatches OnFrameInfo[Changed] - // notifications. - void RefreshCaptureFormat(const webrtc::DesktopSize& frame_size); - // Method that is scheduled on |task_runner_| to be called on regular interval // to capture a frame. void OnCaptureTimer(); @@ -97,24 +93,20 @@ // on the task_runner_ thread. scoped_ptr<Client> client_; - // Requested video capture format (width, height, frame rate, etc). - media::VideoCaptureParams requested_params_; - - // Actual video capture format being generated. - media::VideoCaptureFormat capture_format_; + // Requested video capture frame rate. + float requested_frame_rate_; // Size of frame most recently captured from the source. webrtc::DesktopSize previous_frame_size_; + // Determines the size of frames to deliver to the |client_|. + scoped_ptr<CaptureResolutionChooser> resolution_chooser_; + // DesktopFrame into which captured frames are down-scaled and/or letterboxed, // depending upon the caller's requested capture capabilities. If frames can // be returned to the caller directly then this is NULL. scoped_ptr<webrtc::DesktopFrame> output_frame_; - // Sub-rectangle of |output_frame_| into which the source will be scaled - // and/or letterboxed. - webrtc::DesktopRect output_rect_; - // Timer used to capture the frame. base::OneShotTimer<Core> capture_timer_; @@ -167,12 +159,10 @@ DCHECK(!client_.get()); client_ = client.Pass(); - requested_params_ = params; - - capture_format_ = requested_params_.requested_format; - - // This capturer always outputs ARGB, non-interlaced. - capture_format_.pixel_format = media::PIXEL_FORMAT_ARGB; + requested_frame_rate_ = params.requested_format.frame_rate; + resolution_chooser_.reset(new CaptureResolutionChooser( + params.requested_format.frame_size, + params.resolution_change_policy)); power_save_blocker_.reset( PowerSaveBlocker::Create( @@ -238,16 +228,29 @@ scoped_ptr<webrtc::DesktopFrame> owned_frame(frame); + // If the frame size has changed, drop the output frame (if any), and + // determine the new output size. + if (!previous_frame_size_.equals(frame->size())) { + output_frame_.reset(); + resolution_chooser_->SetSourceSize(gfx::Size(frame->size().width(), + frame->size().height())); + previous_frame_size_ = frame->size(); + } + // Align to 2x2 pixel boundaries, as required by OnIncomingCapturedData() so + // it can convert the frame to I420 format. + const webrtc::DesktopSize output_size( + resolution_chooser_->capture_size().width() & ~1, + resolution_chooser_->capture_size().height() & ~1); + if (output_size.is_empty()) + return; + // On OSX We receive a 1x1 frame when the shared window is minimized. It // cannot be subsampled to I420 and will be dropped downstream. So we replace // it with a black frame to avoid the video appearing frozen at the last // frame. if (frame->size().width() == 1 || frame->size().height() == 1) { if (!black_frame_.get()) { - black_frame_.reset( - new webrtc::BasicDesktopFrame( - webrtc::DesktopSize(capture_format_.frame_size.width(), - capture_format_.frame_size.height()))); + black_frame_.reset(new webrtc::BasicDesktopFrame(output_size)); memset(black_frame_->data(), 0, black_frame_->stride() * black_frame_->size().height()); @@ -256,11 +259,6 @@ frame = black_frame_.get(); } - // Handle initial frame size and size changes. - RefreshCaptureFormat(frame->size()); - - webrtc::DesktopSize output_size(capture_format_.frame_size.width(), - capture_format_.frame_size.height()); size_t output_bytes = output_size.width() * output_size.height() * webrtc::DesktopFrame::kBytesPerPixel; const uint8_t* output_data = NULL; @@ -270,7 +268,7 @@ // match the output size. // Allocate a buffer of the correct size to scale the frame into. - // |output_frame_| is cleared whenever |output_rect_| changes, so we don't + // |output_frame_| is cleared whenever the output size changes, so we don't // need to worry about clearing out stale pixel data in letterboxed areas. if (!output_frame_) { output_frame_.reset(new webrtc::BasicDesktopFrame(output_size)); @@ -280,13 +278,15 @@ // TODO(wez): Optimize this to scale only changed portions of the output, // using ARGBScaleClip(). + const webrtc::DesktopRect output_rect = + ComputeLetterboxRect(output_size, frame->size()); uint8_t* output_rect_data = output_frame_->data() + - output_frame_->stride() * output_rect_.top() + - webrtc::DesktopFrame::kBytesPerPixel * output_rect_.left(); + output_frame_->stride() * output_rect.top() + + webrtc::DesktopFrame::kBytesPerPixel * output_rect.left(); libyuv::ARGBScale(frame->data(), frame->stride(), frame->size().width(), frame->size().height(), output_rect_data, output_frame_->stride(), - output_rect_.width(), output_rect_.height(), + output_rect.width(), output_rect.height(), libyuv::kFilterBilinear); output_data = output_frame_->data(); } else if (IsFrameUnpackedOrInverted(frame)) { @@ -311,49 +311,14 @@ } client_->OnIncomingCapturedData( - output_data, output_bytes, capture_format_, 0, base::TimeTicks::Now()); -} - -void DesktopCaptureDevice::Core::RefreshCaptureFormat( - const webrtc::DesktopSize& frame_size) { - if (previous_frame_size_.equals(frame_size)) - return; - - // Clear the output frame, if any, since it will either need resizing, or - // clearing of stale data in letterbox areas, anyway. - output_frame_.reset(); - - if (previous_frame_size_.is_empty() || - requested_params_.resolution_change_policy == - media::RESOLUTION_POLICY_ANY_WITHIN_LIMIT) { - // If this is the first frame, or the receiver supports variable resolution - // then determine the output size by treating the requested width & height - // as maxima. - if (frame_size.width() > - requested_params_.requested_format.frame_size.width() || - frame_size.height() > - requested_params_.requested_format.frame_size.height()) { - output_rect_ = ComputeLetterboxRect( - webrtc::DesktopSize( - requested_params_.requested_format.frame_size.width(), - requested_params_.requested_format.frame_size.height()), - frame_size); - output_rect_.Translate(-output_rect_.left(), -output_rect_.top()); - } else { - output_rect_ = webrtc::DesktopRect::MakeSize(frame_size); - } - capture_format_.frame_size.SetSize(output_rect_.width(), - output_rect_.height()); - } else { - // Otherwise the output frame size cannot change, so just scale and - // letterbox. - output_rect_ = ComputeLetterboxRect( - webrtc::DesktopSize(capture_format_.frame_size.width(), - capture_format_.frame_size.height()), - frame_size); - } - - previous_frame_size_ = frame_size; + output_data, + output_bytes, + media::VideoCaptureFormat(gfx::Size(output_size.width(), + output_size.height()), + requested_frame_rate_, + media::PIXEL_FORMAT_ARGB), + 0, + base::TimeTicks::Now()); } void DesktopCaptureDevice::Core::OnCaptureTimer() { @@ -375,7 +340,8 @@ // Limit frame-rate to reduce CPU consumption. base::TimeDelta capture_period = std::max( (last_capture_duration * 100) / kMaximumCpuConsumptionPercentage, - base::TimeDelta::FromSeconds(1) / capture_format_.frame_rate); + base::TimeDelta::FromMicroseconds(static_cast<int64>( + 1000000.0 / requested_frame_rate_ + 0.5 /* round to nearest int */))); // Schedule a task for the next frame. capture_timer_.Start(FROM_HERE, capture_period - last_capture_duration,
diff --git a/content/browser/media/capture/desktop_capture_device_unittest.cc b/content/browser/media/capture/desktop_capture_device_unittest.cc index c86ddd38..56e06ff66 100644 --- a/content/browser/media/capture/desktop_capture_device_unittest.cc +++ b/content/browser/media/capture/desktop_capture_device_unittest.cc
@@ -4,6 +4,7 @@ #include "content/browser/media/capture/desktop_capture_device.h" +#include <algorithm> #include <string> #include "base/basictypes.h" @@ -22,8 +23,10 @@ using ::testing::AnyNumber; using ::testing::DoAll; using ::testing::Expectation; +using ::testing::Invoke; using ::testing::InvokeWithoutArgs; using ::testing::SaveArg; +using ::testing::WithArg; namespace content { @@ -33,10 +36,10 @@ return arg.width == width && arg.height == height; } -const int kTestFrameWidth1 = 100; -const int kTestFrameHeight1 = 100; -const int kTestFrameWidth2 = 200; -const int kTestFrameHeight2 = 150; +const int kTestFrameWidth1 = 500; +const int kTestFrameHeight1 = 500; +const int kTestFrameWidth2 = 400; +const int kTestFrameHeight2 = 300; const int kFrameRate = 30; @@ -208,6 +211,32 @@ bool generate_cropped_frames_; }; +// Helper used to check that only two specific frame sizes are delivered to the +// OnIncomingCapturedData() callback. +class FormatChecker { + public: + FormatChecker(const gfx::Size& size_for_even_frames, + const gfx::Size& size_for_odd_frames) + : size_for_even_frames_(size_for_even_frames), + size_for_odd_frames_(size_for_odd_frames), + frame_count_(0) {} + + void ExpectAcceptableSize(const media::VideoCaptureFormat& format) { + if (frame_count_ % 2 == 0) + EXPECT_EQ(size_for_even_frames_, format.frame_size); + else + EXPECT_EQ(size_for_odd_frames_, format.frame_size); + ++frame_count_; + EXPECT_EQ(kFrameRate, format.frame_rate); + EXPECT_EQ(media::PIXEL_FORMAT_ARGB, format.pixel_format); + } + + private: + const gfx::Size size_for_even_frames_; + const gfx::Size size_for_odd_frames_; + int frame_count_; +}; + } // namespace class DesktopCaptureDeviceTest : public testing::Test { @@ -277,15 +306,15 @@ CreateScreenCaptureDevice(scoped_ptr<webrtc::DesktopCapturer>(mock_capturer)); - media::VideoCaptureFormat format; + FormatChecker format_checker(gfx::Size(kTestFrameWidth1, kTestFrameHeight1), + gfx::Size(kTestFrameWidth1, kTestFrameHeight1)); base::WaitableEvent done_event(false, false); - int frame_size; scoped_ptr<MockDeviceClient> client(new MockDeviceClient()); EXPECT_CALL(*client, OnError(_)).Times(0); EXPECT_CALL(*client, OnIncomingCapturedData(_, _, _, _, _)).WillRepeatedly( - DoAll(SaveArg<1>(&frame_size), - SaveArg<2>(&format), + DoAll(WithArg<2>(Invoke(&format_checker, + &FormatChecker::ExpectAcceptableSize)), InvokeWithoutArgs(&done_event, &base::WaitableEvent::Signal))); media::VideoCaptureParams capture_params; @@ -293,23 +322,66 @@ kTestFrameHeight1); capture_params.requested_format.frame_rate = kFrameRate; capture_params.requested_format.pixel_format = media::PIXEL_FORMAT_I420; + capture_params.resolution_change_policy = + media::RESOLUTION_POLICY_FIXED_RESOLUTION; capture_device_->AllocateAndStart(capture_params, client.Pass()); // Capture at least two frames, to ensure that the source frame size has - // changed while capturing. - EXPECT_TRUE(done_event.TimedWait(TestTimeouts::action_max_timeout())); - done_event.Reset(); - EXPECT_TRUE(done_event.TimedWait(TestTimeouts::action_max_timeout())); + // changed to two different sizes while capturing. The mock for + // OnIncomingCapturedData() will use FormatChecker to examine the format of + // each frame being delivered. + for (int i = 0; i < 2; ++i) { + EXPECT_TRUE(done_event.TimedWait(TestTimeouts::action_max_timeout())); + done_event.Reset(); + } capture_device_->StopAndDeAllocate(); +} - EXPECT_EQ(kTestFrameWidth1, format.frame_size.width()); - EXPECT_EQ(kTestFrameHeight1, format.frame_size.height()); - EXPECT_EQ(kFrameRate, format.frame_rate); - EXPECT_EQ(media::PIXEL_FORMAT_ARGB, format.pixel_format); +// Test that screen capturer behaves correctly if the source frame size changes, +// where the video frames sent the the client vary in resolution but maintain +// the same aspect ratio. +TEST_F(DesktopCaptureDeviceTest, ScreenResolutionChangeFixedAspectRatio) { + FakeScreenCapturer* mock_capturer = new FakeScreenCapturer(); - EXPECT_EQ(format.frame_size.GetArea() * 4, frame_size); + CreateScreenCaptureDevice(scoped_ptr<webrtc::DesktopCapturer>(mock_capturer)); + + FormatChecker format_checker(gfx::Size(888, 500), gfx::Size(532, 300)); + base::WaitableEvent done_event(false, false); + + scoped_ptr<MockDeviceClient> client(new MockDeviceClient()); + EXPECT_CALL(*client, OnError(_)).Times(0); + EXPECT_CALL(*client, OnIncomingCapturedData(_, _, _, _, _)).WillRepeatedly( + DoAll(WithArg<2>(Invoke(&format_checker, + &FormatChecker::ExpectAcceptableSize)), + InvokeWithoutArgs(&done_event, &base::WaitableEvent::Signal))); + + media::VideoCaptureParams capture_params; + const gfx::Size high_def_16_by_9(1920, 1080); + ASSERT_GE(high_def_16_by_9.width(), + std::max(kTestFrameWidth1, kTestFrameWidth2)); + ASSERT_GE(high_def_16_by_9.height(), + std::max(kTestFrameHeight1, kTestFrameHeight2)); + capture_params.requested_format.frame_size = high_def_16_by_9; + capture_params.requested_format.frame_rate = kFrameRate; + capture_params.requested_format.pixel_format = media::PIXEL_FORMAT_I420; + capture_params.resolution_change_policy = + media::RESOLUTION_POLICY_FIXED_ASPECT_RATIO; + + capture_device_->AllocateAndStart( + capture_params, client.Pass()); + + // Capture at least three frames, to ensure that the source frame size has + // changed to two different sizes while capturing. The mock for + // OnIncomingCapturedData() will use FormatChecker to examine the format of + // each frame being delivered. + for (int i = 0; i < 3; ++i) { + EXPECT_TRUE(done_event.TimedWait(TestTimeouts::action_max_timeout())); + done_event.Reset(); + } + + capture_device_->StopAndDeAllocate(); } // Test that screen capturer behaves correctly if the source frame size changes @@ -319,38 +391,42 @@ CreateScreenCaptureDevice(scoped_ptr<webrtc::DesktopCapturer>(mock_capturer)); - media::VideoCaptureFormat format; + FormatChecker format_checker(gfx::Size(kTestFrameWidth1, kTestFrameHeight1), + gfx::Size(kTestFrameWidth2, kTestFrameHeight2)); base::WaitableEvent done_event(false, false); scoped_ptr<MockDeviceClient> client(new MockDeviceClient()); EXPECT_CALL(*client, OnError(_)).Times(0); EXPECT_CALL(*client, OnIncomingCapturedData(_, _, _, _, _)).WillRepeatedly( - DoAll(SaveArg<2>(&format), + DoAll(WithArg<2>(Invoke(&format_checker, + &FormatChecker::ExpectAcceptableSize)), InvokeWithoutArgs(&done_event, &base::WaitableEvent::Signal))); media::VideoCaptureParams capture_params; - capture_params.requested_format.frame_size.SetSize(kTestFrameWidth2, - kTestFrameHeight2); + const gfx::Size high_def_16_by_9(1920, 1080); + ASSERT_GE(high_def_16_by_9.width(), + std::max(kTestFrameWidth1, kTestFrameWidth2)); + ASSERT_GE(high_def_16_by_9.height(), + std::max(kTestFrameHeight1, kTestFrameHeight2)); + capture_params.requested_format.frame_size = high_def_16_by_9; capture_params.requested_format.frame_rate = kFrameRate; capture_params.requested_format.pixel_format = media::PIXEL_FORMAT_I420; + capture_params.resolution_change_policy = + media::RESOLUTION_POLICY_ANY_WITHIN_LIMIT; capture_device_->AllocateAndStart( capture_params, client.Pass()); // Capture at least three frames, to ensure that the source frame size has - // changed at least twice while capturing. - EXPECT_TRUE(done_event.TimedWait(TestTimeouts::action_max_timeout())); - done_event.Reset(); - EXPECT_TRUE(done_event.TimedWait(TestTimeouts::action_max_timeout())); - done_event.Reset(); - EXPECT_TRUE(done_event.TimedWait(TestTimeouts::action_max_timeout())); + // changed to two different sizes while capturing. The mock for + // OnIncomingCapturedData() will use FormatChecker to examine the format of + // each frame being delivered. + for (int i = 0; i < 3; ++i) { + EXPECT_TRUE(done_event.TimedWait(TestTimeouts::action_max_timeout())); + done_event.Reset(); + } capture_device_->StopAndDeAllocate(); - - EXPECT_EQ(kTestFrameWidth1, format.frame_size.width()); - EXPECT_EQ(kTestFrameHeight1, format.frame_size.height()); - EXPECT_EQ(kFrameRate, format.frame_rate); - EXPECT_EQ(media::PIXEL_FORMAT_ARGB, format.pixel_format); } // This test verifies that an unpacked frame is converted to a packed frame.
diff --git a/content/browser/media/capture/web_contents_audio_input_stream.cc b/content/browser/media/capture/web_contents_audio_input_stream.cc index 629d106..8fd1f97 100644 --- a/content/browser/media/capture/web_contents_audio_input_stream.cc +++ b/content/browser/media/capture/web_contents_audio_input_stream.cc
@@ -91,7 +91,7 @@ // Called by WebContentsTracker when the target of the audio mirroring has // changed. - void OnTargetChanged(RenderWidgetHost* target); + void OnTargetChanged(bool had_target); // Injected dependencies. const int initial_render_process_id_; @@ -305,11 +305,10 @@ delete stream; } -void WebContentsAudioInputStream::Impl::OnTargetChanged( - RenderWidgetHost* target) { +void WebContentsAudioInputStream::Impl::OnTargetChanged(bool had_target) { DCHECK(thread_checker_.CalledOnValidThread()); - is_target_lost_ = !target; + is_target_lost_ = !had_target; if (state_ == MIRRORING) { if (is_target_lost_) {
diff --git a/content/browser/media/capture/web_contents_audio_input_stream_unittest.cc b/content/browser/media/capture/web_contents_audio_input_stream_unittest.cc index ffe8b4b5..0eebd7a8 100644 --- a/content/browser/media/capture/web_contents_audio_input_stream_unittest.cc +++ b/content/browser/media/capture/web_contents_audio_input_stream_unittest.cc
@@ -356,13 +356,7 @@ private: void SimulateChangeCallback(int render_process_id, int render_frame_id) { ASSERT_FALSE(change_callback_.is_null()); - if (render_process_id == -1 || render_frame_id == -1) { - change_callback_.Run(NULL); - } else { - // For our tests, any non-NULL value will suffice since it will not be - // dereferenced. - change_callback_.Run(reinterpret_cast<RenderWidgetHost*>(0xdeadbee5)); - } + change_callback_.Run(render_process_id != -1 && render_frame_id != -1); } scoped_ptr<TestBrowserThreadBundle> thread_bundle_;
diff --git a/content/browser/media/capture/web_contents_tracker.cc b/content/browser/media/capture/web_contents_tracker.cc index a9e161f..5007a583 100644 --- a/content/browser/media/capture/web_contents_tracker.cc +++ b/content/browser/media/capture/web_contents_tracker.cc
@@ -44,6 +44,7 @@ DCHECK(task_runner_->BelongsToCurrentThread()); callback_.Reset(); + resize_callback_.Reset(); if (BrowserThread::CurrentlyOn(BrowserThread::UI)) { WebContentsObserver::Observe(NULL); @@ -78,6 +79,12 @@ return rwh; } +void WebContentsTracker::SetResizeChangeCallback( + const base::Closure& callback) { + DCHECK(!task_runner_.get() || task_runner_->BelongsToCurrentThread()); + resize_callback_ = callback; +} + void WebContentsTracker::OnPossibleTargetChange(bool force_callback_run) { DCHECK_CURRENTLY_ON(BrowserThread::UI); @@ -89,19 +96,29 @@ last_target_ = rwh; if (task_runner_->BelongsToCurrentThread()) { - MaybeDoCallback(rwh); - } else { - task_runner_->PostTask( - FROM_HERE, - base::Bind(&WebContentsTracker::MaybeDoCallback, this, rwh)); + MaybeDoCallback(rwh != nullptr); + return; } + + task_runner_->PostTask( + FROM_HERE, + base::Bind(&WebContentsTracker::MaybeDoCallback, this, rwh != nullptr)); } -void WebContentsTracker::MaybeDoCallback(RenderWidgetHost* rwh) { +void WebContentsTracker::MaybeDoCallback(bool was_still_tracking) { DCHECK(task_runner_->BelongsToCurrentThread()); if (!callback_.is_null()) - callback_.Run(rwh); + callback_.Run(was_still_tracking); + if (was_still_tracking) + MaybeDoResizeCallback(); +} + +void WebContentsTracker::MaybeDoResizeCallback() { + DCHECK(task_runner_->BelongsToCurrentThread()); + + if (!resize_callback_.is_null()) + resize_callback_.Run(); } void WebContentsTracker::StartObservingWebContents(int render_process_id, @@ -128,6 +145,19 @@ OnPossibleTargetChange(false); } +void WebContentsTracker::MainFrameWasResized(bool width_changed) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + + if (task_runner_->BelongsToCurrentThread()) { + MaybeDoResizeCallback(); + return; + } + + task_runner_->PostTask( + FROM_HERE, + base::Bind(&WebContentsTracker::MaybeDoResizeCallback, this)); +} + void WebContentsTracker::WebContentsDestroyed() { Observe(NULL); OnPossibleTargetChange(false);
diff --git a/content/browser/media/capture/web_contents_tracker.h b/content/browser/media/capture/web_contents_tracker.h index 613c971..591c5e3 100644 --- a/content/browser/media/capture/web_contents_tracker.h +++ b/content/browser/media/capture/web_contents_tracker.h
@@ -40,15 +40,15 @@ explicit WebContentsTracker(bool track_fullscreen_rwh); // Callback to indicate a new RenderWidgetHost should be targeted for capture. - // This is also invoked with NULL to indicate tracking will not continue + // This is also invoked with false to indicate tracking will not continue // (i.e., the WebContents instance was not found or has been destroyed). - typedef base::Callback<void(RenderWidgetHost* rwh)> ChangeCallback; + typedef base::Callback<void(bool was_still_tracking)> ChangeCallback; // Start tracking. The last-known |render_process_id| and // |main_render_frame_id| are provided, and |callback| will be run once to - // indicate the current capture target (this may occur during the invocation - // of Start(), or in the future). The callback will be invoked on the same - // thread calling Start(). + // indicate whether tracking successfully started (this may occur during the + // invocation of Start(), or in the future). The callback will be invoked on + // the same thread calling Start(). virtual void Start(int render_process_id, int main_render_frame_id, const ChangeCallback& callback); @@ -59,6 +59,12 @@ // Current target. This must only be called on the UI BrowserThread. RenderWidgetHost* GetTargetRenderWidgetHost() const; + // Set a callback that is run whenever the main frame of the WebContents is + // resized. This method must be called on the same thread that calls + // Start()/Stop(), and |callback| will be run on that same thread. Calling + // the Stop() method guarantees the callback will never be invoked again. + void SetResizeChangeCallback(const base::Closure& callback); + protected: friend class base::RefCountedThreadSafe<WebContentsTracker>; ~WebContentsTracker() override; @@ -72,7 +78,12 @@ // Called on the thread that Start()/Stop() are called on. Checks whether the // callback is still valid and, if so, runs it. - void MaybeDoCallback(RenderWidgetHost* rwh); + void MaybeDoCallback(bool was_still_tracking); + + // Called on the thread that Start()/Stop() are called on. Checks whether the + // callback is still valid and, if so, runs it to indicate the main frame has + // changed in size. + void MaybeDoResizeCallback(); // Look-up the current WebContents instance associated with the given // |render_process_id| and |main_render_frame_id| and begin observing it. @@ -86,6 +97,10 @@ void RenderFrameHostChanged(RenderFrameHost* old_host, RenderFrameHost* new_host) override; + // WebContentsObserver override to notify the client that the source size has + // changed. + void MainFrameWasResized(bool width_changed) override; + // WebContentsObserver override to notify the client that the capture target // has been permanently lost. void WebContentsDestroyed() override; @@ -109,6 +124,9 @@ // This is used to eliminate duplicate callback runs. RenderWidgetHost* last_target_; + // Callback to run when the target RenderWidgetHost has resized. + base::Closure resize_callback_; + DISALLOW_COPY_AND_ASSIGN(WebContentsTracker); };
diff --git a/content/browser/media/capture/web_contents_video_capture_device.cc b/content/browser/media/capture/web_contents_video_capture_device.cc index 8380682f..292d856 100644 --- a/content/browser/media/capture/web_contents_video_capture_device.cc +++ b/content/browser/media/capture/web_contents_video_capture_device.cc
@@ -79,7 +79,6 @@ #include "third_party/skia/include/core/SkBitmap.h" #include "third_party/skia/include/core/SkColor.h" #include "ui/gfx/display.h" -#include "ui/gfx/geometry/size.h" #include "ui/gfx/geometry/size_conversions.h" #include "ui/gfx/screen.h" @@ -87,20 +86,6 @@ namespace { -// Compute a letterbox region, aligned to even coordinates. -gfx::Rect ComputeYV12LetterboxRegion(const gfx::Rect& visible_rect, - const gfx::Size& content_size) { - - gfx::Rect result = media::ComputeLetterboxRegion(visible_rect, content_size); - - result.set_x(MakeEven(result.x())); - result.set_y(MakeEven(result.y())); - result.set_width(std::max(kMinFrameWidth, MakeEven(result.width()))); - result.set_height(std::max(kMinFrameHeight, MakeEven(result.height()))); - - return result; -} - void DeleteOnWorkerThread(scoped_ptr<base::Thread> render_thread, const base::Closure& callback) { render_thread.reset(); @@ -254,8 +239,12 @@ deliver_frame_cb, bool success); - // Remove the old subscription, and start a new one if |rwh| is not NULL. - void RenewFrameSubscription(RenderWidgetHost* rwh); + // Remove the old subscription, and attempt to start a new one if |had_target| + // is true. + void RenewFrameSubscription(bool had_target); + + // Called whenever the render widget is resized. + void UpdateCaptureSize(); // Parameters saved in constructor. const int initial_render_process_id_; @@ -396,7 +385,7 @@ // Calculate the width and height of the content region in the |output|, based // on the aspect ratio of |input|. - gfx::Rect region_in_frame = ComputeYV12LetterboxRegion( + const gfx::Rect region_in_frame = media::ComputeLetterboxRegion( output->visible_rect(), gfx::Size(input.width(), input.height())); // Scale the bitmap to the required size, if necessary. @@ -425,12 +414,20 @@ TRACE_EVENT_ASYNC_STEP_INTO0("gpu.capture", "Capture", output.get(), "YUV"); { - SkAutoLockPixels scaled_bitmap_locker(scaled_bitmap); + // Align to 2x2 pixel boundaries, as required by + // media::CopyRGBToVideoFrame(). + const gfx::Rect region_in_yv12_frame(region_in_frame.x() & ~1, + region_in_frame.y() & ~1, + region_in_frame.width() & ~1, + region_in_frame.height() & ~1); + if (region_in_yv12_frame.IsEmpty()) + return; + SkAutoLockPixels scaled_bitmap_locker(scaled_bitmap); media::CopyRGBToVideoFrame( reinterpret_cast<uint8*>(scaled_bitmap.getPixels()), scaled_bitmap.rowBytes(), - region_in_frame, + region_in_yv12_frame, output.get()); } @@ -501,6 +498,9 @@ // Note: Creation of the first WeakPtr in the following statement will cause // IsStarted() to return true from now on. + tracker_->SetResizeChangeCallback( + base::Bind(&WebContentsCaptureMachine::UpdateCaptureSize, + weak_ptr_factory_.GetWeakPtr())); tracker_->Start(initial_render_process_id_, initial_main_render_frame_id_, base::Bind(&WebContentsCaptureMachine::RenewFrameSubscription, weak_ptr_factory_.GetWeakPtr())); @@ -522,7 +522,7 @@ // Note: RenewFrameSubscription() must be called before stopping |tracker_| so // the web_contents() can be notified that the capturing is ending. - RenewFrameSubscription(NULL); + RenewFrameSubscription(false); tracker_->Stop(); // The render thread cannot be stopped on the UI thread, so post a message @@ -551,11 +551,6 @@ } gfx::Size view_size = view->GetViewBounds().size(); - gfx::Size fitted_size; - if (!view_size.IsEmpty()) { - fitted_size = ComputeYV12LetterboxRegion(target->visible_rect(), - view_size).size(); - } if (view_size != last_view_size_) { last_view_size_ = view_size; @@ -574,6 +569,8 @@ weak_ptr_factory_.GetWeakPtr(), start_time, deliver_frame_cb)); } else { + const gfx::Size fitted_size = view_size.IsEmpty() ? gfx::Size() : + media::ComputeLetterboxRegion(target->visible_rect(), view_size).size(); rwh->CopyFromBackingStore( gfx::Rect(), fitted_size, // Size here is a request not always honored. @@ -589,7 +586,10 @@ gfx::Size WebContentsCaptureMachine::ComputeOptimalTargetSize() const { DCHECK_CURRENTLY_ON(BrowserThread::UI); - gfx::Size optimal_size = oracle_proxy_->GetCaptureSize(); + // TODO(miu): Propagate capture frame size changes as new "preferred size" + // updates, rather than just using the max frame size. + // http://crbug.com/350491 + gfx::Size optimal_size = oracle_proxy_->max_frame_size(); // If the ratio between physical and logical pixels is greater than 1:1, // shrink |optimal_size| by that amount. Then, when external code resizes the @@ -657,9 +657,12 @@ deliver_frame_cb.Run(start_time, success); } -void WebContentsCaptureMachine::RenewFrameSubscription(RenderWidgetHost* rwh) { +void WebContentsCaptureMachine::RenewFrameSubscription(bool had_target) { DCHECK_CURRENTLY_ON(BrowserThread::UI); + RenderWidgetHost* const rwh = + had_target ? tracker_->GetTargetRenderWidgetHost() : nullptr; + // Always destroy the old subscription before creating a new one. const bool had_subscription = !!subscription_; subscription_.reset(); @@ -688,6 +691,18 @@ weak_ptr_factory_.GetWeakPtr()))); } +void WebContentsCaptureMachine::UpdateCaptureSize() { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + + if (!oracle_proxy_) + return; + RenderWidgetHost* const rwh = tracker_->GetTargetRenderWidgetHost(); + RenderWidgetHostView* const view = rwh ? rwh->GetView() : nullptr; + if (!view) + return; + oracle_proxy_->UpdateCaptureSize(view->GetViewBounds().size()); +} + } // namespace WebContentsVideoCaptureDevice::WebContentsVideoCaptureDevice(
diff --git a/content/browser/media/capture/web_contents_video_capture_device_unittest.cc b/content/browser/media/capture/web_contents_video_capture_device_unittest.cc index ab430a7..02b297f3 100644 --- a/content/browser/media/capture/web_contents_video_capture_device_unittest.cc +++ b/content/browser/media/capture/web_contents_video_capture_device_unittest.cc
@@ -11,11 +11,13 @@ #include "base/time/time.h" #include "base/timer/timer.h" #include "content/browser/browser_thread_impl.h" +#include "content/browser/frame_host/render_frame_host_impl.h" #include "content/browser/media/capture/video_capture_oracle.h" #include "content/browser/media/capture/web_contents_capture_util.h" #include "content/browser/renderer_host/media/video_capture_buffer_pool.h" #include "content/browser/renderer_host/render_view_host_factory.h" #include "content/browser/renderer_host/render_widget_host_impl.h" +#include "content/browser/web_contents/web_contents_impl.h" #include "content/public/browser/notification_service.h" #include "content/public/browser/notification_types.h" #include "content/public/browser/render_widget_host_view_frame_subscriber.h" @@ -77,7 +79,6 @@ // counted. class CaptureTestSourceController { public: - CaptureTestSourceController() : color_(SK_ColorMAGENTA), copy_result_size_(kTestWidth, kTestHeight), @@ -162,13 +163,22 @@ explicit CaptureTestView(RenderWidgetHostImpl* rwh, CaptureTestSourceController* controller) : TestRenderWidgetHostView(rwh), - controller_(controller) {} + controller_(controller), + fake_bounds_(100, 100, 100 + kTestWidth, 100 + kTestHeight) {} ~CaptureTestView() override {} // TestRenderWidgetHostView overrides. gfx::Rect GetViewBounds() const override { - return gfx::Rect(100, 100, 100 + kTestWidth, 100 + kTestHeight); + return fake_bounds_; + } + + void SetSize(const gfx::Size& size) override { + SetBounds(gfx::Rect(fake_bounds_.origin(), size)); + } + + void SetBounds(const gfx::Rect& rect) override { + fake_bounds_ = rect; } bool CanCopyToVideoFrame() const override { @@ -213,6 +223,7 @@ private: scoped_ptr<RenderWidgetHostViewFrameSubscriber> subscriber_; CaptureTestSourceController* const controller_; + gfx::Rect fake_bounds_; DISALLOW_IMPLICIT_CONSTRUCTORS(CaptureTestView); }; @@ -308,9 +319,10 @@ // WebContentsVideoCaptureDevice. class StubClient : public media::VideoCaptureDevice::Client { public: - StubClient(const base::Callback<void(SkColor)>& color_callback, - const base::Closure& error_callback) - : color_callback_(color_callback), + StubClient( + const base::Callback<void(SkColor, const gfx::Size&)>& report_callback, + const base::Closure& error_callback) + : report_callback_(report_callback), error_callback_(error_callback) { buffer_pool_ = new VideoCaptureBufferPool(2); } @@ -360,20 +372,29 @@ scoped_ptr<Buffer> buffer, const scoped_refptr<media::VideoFrame>& frame, const base::TimeTicks& timestamp) override { - EXPECT_EQ(gfx::Size(kTestWidth, kTestHeight), frame->visible_rect().size()); + EXPECT_FALSE(frame->visible_rect().IsEmpty()); EXPECT_EQ(media::VideoFrame::I420, frame->format()); double frame_rate = 0; EXPECT_TRUE( frame->metadata()->GetDouble(media::VideoFrameMetadata::FRAME_RATE, &frame_rate)); EXPECT_EQ(kTestFramesPerSecond, frame_rate); - uint8 yuv[3]; - for (int plane = 0; plane < 3; ++plane) - yuv[plane] = frame->visible_data(plane)[0]; - // TODO(nick): We just look at the first pixel presently, because if - // the analysis is too slow, the backlog of frames will grow without bound - // and trouble erupts. http://crbug.com/174519 - color_callback_.Run((SkColorSetRGB(yuv[0], yuv[1], yuv[2]))); + + // TODO(miu): We just look at the center pixel presently, because if the + // analysis is too slow, the backlog of frames will grow without bound and + // trouble erupts. http://crbug.com/174519 + using media::VideoFrame; + const gfx::Point center = frame->visible_rect().CenterPoint(); + const int center_offset_y = + (frame->stride(VideoFrame::kYPlane) * center.y()) + center.x(); + const int center_offset_uv = + (frame->stride(VideoFrame::kUPlane) * (center.y() / 2)) + + (center.x() / 2); + report_callback_.Run( + SkColorSetRGB(frame->data(VideoFrame::kYPlane)[center_offset_y], + frame->data(VideoFrame::kUPlane)[center_offset_uv], + frame->data(VideoFrame::kVPlane)[center_offset_uv]), + frame->visible_rect().size()); } void OnError(const std::string& reason) override { error_callback_.Run(); } @@ -407,7 +428,7 @@ }; scoped_refptr<VideoCaptureBufferPool> buffer_pool_; - base::Callback<void(SkColor)> color_callback_; + base::Callback<void(SkColor, const gfx::Size&)> report_callback_; base::Closure error_callback_; DISALLOW_COPY_AND_ASSIGN(StubClient); @@ -417,9 +438,11 @@ public: StubClientObserver() : error_encountered_(false), - wait_color_yuv_(0xcafe1950) { + wait_color_yuv_(0xcafe1950), + wait_size_(kTestWidth, kTestHeight) { client_.reset(new StubClient( - base::Bind(&StubClientObserver::OnColor, base::Unretained(this)), + base::Bind(&StubClientObserver::DidDeliverFrame, + base::Unretained(this)), base::Bind(&StubClientObserver::OnError, base::Unretained(this)))); } @@ -429,16 +452,30 @@ return client_.Pass(); } - void QuitIfConditionMet(SkColor color) { + void QuitIfConditionsMet(SkColor color, const gfx::Size& size) { base::AutoLock guard(lock_); - if (wait_color_yuv_ == color || error_encountered_) + if (error_encountered_) + base::MessageLoop::current()->Quit(); + else if (wait_color_yuv_ == color && wait_size_.IsEmpty()) + base::MessageLoop::current()->Quit(); + else if (wait_color_yuv_ == color && wait_size_ == size) base::MessageLoop::current()->Quit(); } + // Run the current loop until a frame is delivered with the |expected_color| + // and any non-empty frame size. void WaitForNextColor(SkColor expected_color) { + WaitForNextColorAndFrameSize(expected_color, gfx::Size()); + } + + // Run the current loop until a frame is delivered with the |expected_color| + // and is of the |expected_size|. + void WaitForNextColorAndFrameSize(SkColor expected_color, + const gfx::Size& expected_size) { { base::AutoLock guard(lock_); wait_color_yuv_ = ConvertRgbToYuv(expected_color); + wait_size_ = expected_size; error_encountered_ = false; } RunCurrentLoopWithDeadline(); @@ -452,6 +489,7 @@ { base::AutoLock guard(lock_); wait_color_yuv_ = kNotInterested; + wait_size_ = gfx::Size(); error_encountered_ = false; } RunCurrentLoopWithDeadline(); @@ -472,22 +510,25 @@ error_encountered_ = true; } BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind( - &StubClientObserver::QuitIfConditionMet, + &StubClientObserver::QuitIfConditionsMet, base::Unretained(this), - kNothingYet)); + kNothingYet, + gfx::Size())); } - void OnColor(SkColor color) { + void DidDeliverFrame(SkColor color, const gfx::Size& size) { BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind( - &StubClientObserver::QuitIfConditionMet, + &StubClientObserver::QuitIfConditionsMet, base::Unretained(this), - color)); + color, + size)); } private: base::Lock lock_; bool error_encountered_; SkColor wait_color_yuv_; + gfx::Size wait_size_; scoped_ptr<StubClient> client_; DISALLOW_COPY_AND_ASSIGN(StubClientObserver); @@ -622,6 +663,22 @@ } } + void SimulateSourceSizeChange(const gfx::Size& size) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + CaptureTestView* test_view = static_cast<CaptureTestView*>( + web_contents_->GetRenderViewHost()->GetView()); + test_view->SetSize(size); + // Normally, RenderWidgetHostImpl would notify WebContentsImpl that the size + // has changed. However, in this test setup where there is no render + // process, we must notify WebContentsImpl directly. + WebContentsImpl* const as_web_contents_impl = + static_cast<WebContentsImpl*>(web_contents_.get()); + RenderWidgetHostDelegate* const as_rwh_delegate = + static_cast<RenderWidgetHostDelegate*>(as_web_contents_impl); + as_rwh_delegate->RenderWidgetWasResized( + as_web_contents_impl->GetMainFrame()->GetRenderWidgetHost(), true); + } + void DestroyVideoCaptureDevice() { device_.reset(); } StubClientObserver* client_observer() { @@ -879,5 +936,158 @@ device()->StopAndDeAllocate(); } +// Tests that, when configured with the FIXED_ASPECT_RATIO resolution change +// policy, the source size changes result in video frames of possibly varying +// resolutions, but all with the same aspect ratio. +TEST_F(WebContentsVideoCaptureDeviceTest, VariableResolution_FixedAspectRatio) { + media::VideoCaptureParams capture_params; + capture_params.requested_format.frame_size.SetSize(kTestWidth, kTestHeight); + capture_params.requested_format.frame_rate = kTestFramesPerSecond; + capture_params.requested_format.pixel_format = media::PIXEL_FORMAT_I420; + capture_params.resolution_change_policy = + media::RESOLUTION_POLICY_FIXED_ASPECT_RATIO; + + device()->AllocateAndStart(capture_params, client_observer()->PassClient()); + + for (int i = 0; i < 6; i++) { + const char* name = NULL; + switch (i % 3) { + case 0: + source()->SetCanCopyToVideoFrame(true); + source()->SetUseFrameSubscriber(false); + name = "VideoFrame"; + break; + case 1: + source()->SetCanCopyToVideoFrame(false); + source()->SetUseFrameSubscriber(true); + name = "Subscriber"; + break; + case 2: + source()->SetCanCopyToVideoFrame(false); + source()->SetUseFrameSubscriber(false); + name = "SkBitmap"; + break; + default: + FAIL(); + } + + SCOPED_TRACE(base::StringPrintf("Using %s path, iteration #%d", name, i)); + + // Source size equals maximum size. Expect delivered frames to be + // kTestWidth by kTestHeight. + source()->SetSolidColor(SK_ColorRED); + SimulateSourceSizeChange(gfx::Size(kTestWidth, kTestHeight)); + SimulateDrawEvent(); + ASSERT_NO_FATAL_FAILURE(client_observer()->WaitForNextColorAndFrameSize( + SK_ColorRED, gfx::Size(kTestWidth, kTestHeight))); + + // Source size is half in both dimensions. Expect delivered frames to be of + // the same aspect ratio as kTestWidth by kTestHeight, but larger than the + // half size because the minimum height is 180 lines. + source()->SetSolidColor(SK_ColorGREEN); + SimulateSourceSizeChange(gfx::Size(kTestWidth / 2, kTestHeight / 2)); + SimulateDrawEvent(); + ASSERT_NO_FATAL_FAILURE(client_observer()->WaitForNextColorAndFrameSize( + SK_ColorGREEN, gfx::Size(180 * kTestWidth / kTestHeight, 180))); + + // Source size changes aspect ratio. Expect delivered frames to be padded + // in the horizontal dimension to preserve aspect ratio. + source()->SetSolidColor(SK_ColorBLUE); + SimulateSourceSizeChange(gfx::Size(kTestWidth / 2, kTestHeight)); + SimulateDrawEvent(); + ASSERT_NO_FATAL_FAILURE(client_observer()->WaitForNextColorAndFrameSize( + SK_ColorBLUE, gfx::Size(kTestWidth, kTestHeight))); + + // Source size changes aspect ratio again. Expect delivered frames to be + // padded in the vertical dimension to preserve aspect ratio. + source()->SetSolidColor(SK_ColorBLACK); + SimulateSourceSizeChange(gfx::Size(kTestWidth, kTestHeight / 2)); + SimulateDrawEvent(); + ASSERT_NO_FATAL_FAILURE(client_observer()->WaitForNextColorAndFrameSize( + SK_ColorBLACK, gfx::Size(kTestWidth, kTestHeight))); + } + + device()->StopAndDeAllocate(); +} + +// Tests that, when configured with the ANY_WITHIN_LIMIT resolution change +// policy, the source size changes result in video frames of possibly varying +// resolutions. +TEST_F(WebContentsVideoCaptureDeviceTest, VariableResolution_AnyWithinLimits) { + media::VideoCaptureParams capture_params; + capture_params.requested_format.frame_size.SetSize(kTestWidth, kTestHeight); + capture_params.requested_format.frame_rate = kTestFramesPerSecond; + capture_params.requested_format.pixel_format = media::PIXEL_FORMAT_I420; + capture_params.resolution_change_policy = + media::RESOLUTION_POLICY_ANY_WITHIN_LIMIT; + + device()->AllocateAndStart(capture_params, client_observer()->PassClient()); + + for (int i = 0; i < 6; i++) { + const char* name = NULL; + switch (i % 3) { + case 0: + source()->SetCanCopyToVideoFrame(true); + source()->SetUseFrameSubscriber(false); + name = "VideoFrame"; + break; + case 1: + source()->SetCanCopyToVideoFrame(false); + source()->SetUseFrameSubscriber(true); + name = "Subscriber"; + break; + case 2: + source()->SetCanCopyToVideoFrame(false); + source()->SetUseFrameSubscriber(false); + name = "SkBitmap"; + break; + default: + FAIL(); + } + + SCOPED_TRACE(base::StringPrintf("Using %s path, iteration #%d", name, i)); + + // Source size equals maximum size. Expect delivered frames to be + // kTestWidth by kTestHeight. + source()->SetSolidColor(SK_ColorRED); + SimulateSourceSizeChange(gfx::Size(kTestWidth, kTestHeight)); + SimulateDrawEvent(); + ASSERT_NO_FATAL_FAILURE(client_observer()->WaitForNextColorAndFrameSize( + SK_ColorRED, gfx::Size(kTestWidth, kTestHeight))); + + // Source size is half in both dimensions. Expect delivered frames to also + // be half in both dimensions. + source()->SetSolidColor(SK_ColorGREEN); + SimulateSourceSizeChange(gfx::Size(kTestWidth / 2, kTestHeight / 2)); + SimulateDrawEvent(); + ASSERT_NO_FATAL_FAILURE(client_observer()->WaitForNextColorAndFrameSize( + SK_ColorGREEN, gfx::Size(kTestWidth / 2, kTestHeight / 2))); + + // Source size changes to something arbitrary. Since the source size is + // less than the maximum size, expect delivered frames to be the same size + // as the source size. + source()->SetSolidColor(SK_ColorBLUE); + gfx::Size arbitrary_source_size(kTestWidth / 2 + 42, kTestHeight - 10); + SimulateSourceSizeChange(arbitrary_source_size); + SimulateDrawEvent(); + ASSERT_NO_FATAL_FAILURE(client_observer()->WaitForNextColorAndFrameSize( + SK_ColorBLUE, arbitrary_source_size)); + + // Source size changes to something arbitrary that exceeds the maximum frame + // size. Since the source size exceeds the maximum size, expect delivered + // frames to be downscaled. + source()->SetSolidColor(SK_ColorBLACK); + arbitrary_source_size = gfx::Size(kTestWidth * 2 + 99, kTestHeight / 2); + SimulateSourceSizeChange(arbitrary_source_size); + SimulateDrawEvent(); + ASSERT_NO_FATAL_FAILURE(client_observer()->WaitForNextColorAndFrameSize( + SK_ColorBLACK, gfx::Size(kTestWidth, + kTestWidth * arbitrary_source_size.height() / + arbitrary_source_size.width()))); + } + + device()->StopAndDeAllocate(); +} + } // namespace } // namespace content
diff --git a/content/browser/media/cdm/browser_cdm_manager.cc b/content/browser/media/cdm/browser_cdm_manager.cc index 1c6c77a..813a8bad 100644 --- a/content/browser/media/cdm/browser_cdm_manager.cc +++ b/content/browser/media/cdm/browser_cdm_manager.cc
@@ -35,6 +35,11 @@ namespace { +#if defined(OS_ANDROID) +// Android only supports 128-bit key IDs. +const size_t kAndroidKeyIdBytes = 128 / 8; +#endif + // The ID used in this class is a concatenation of |render_frame_id| and // |cdm_id|, i.e. (render_frame_id << 32) + cdm_id. @@ -345,6 +350,15 @@ promise->reject(MediaKeys::INVALID_ACCESS_ERROR, 0, "Init data too long."); return; } +#if defined(OS_ANDROID) + // 'webm' initData is a single key ID. On Android the length is restricted. + if (init_data_type == INIT_DATA_TYPE_WEBM && + init_data.size() != kAndroidKeyIdBytes) { + promise->reject(MediaKeys::INVALID_ACCESS_ERROR, 0, + "'webm' initData is not the correct length."); + return; + } +#endif media::EmeInitDataType eme_init_data_type; switch (init_data_type) {
diff --git a/content/browser/media/cdm/browser_cdm_manager.h b/content/browser/media/cdm/browser_cdm_manager.h index e58d459..57684da 100644 --- a/content/browser/media/cdm/browser_cdm_manager.h +++ b/content/browser/media/cdm/browser_cdm_manager.h
@@ -31,8 +31,6 @@ namespace content { -struct InitializeCdmParameters; - // This class manages all CDM objects. It receives control operations from the // the render process, and forwards them to corresponding CDM object. Callbacks // from CDM objects are converted to IPCs and then sent to the render process.
diff --git a/content/browser/media/webrtc_browsertest.cc b/content/browser/media/webrtc_browsertest.cc index 5506d8e..e69d4c9 100644 --- a/content/browser/media/webrtc_browsertest.cc +++ b/content/browser/media/webrtc_browsertest.cc
@@ -144,15 +144,9 @@ } // Flaky on TSAN v2. http://crbug.com/408006 -#if defined(THREAD_SANITIZER) -#define MAYBE_CanSetupVideoCallAndDisableLocalVideo \ - DISABLED_CanSetupVideoCallAndDisableLocalVideo -#else -#define MAYBE_CanSetupVideoCallAndDisableLocalVideo \ - CanSetupVideoCallAndDisableLocalVideo -#endif +// Flaky everywhere: http://crbug.com/477498 IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest, - MAYBE_CanSetupVideoCallAndDisableLocalVideo) { + DISABLED_CanSetupVideoCallAndDisableLocalVideo) { const std::string javascript = "callAndDisableLocalVideo({video: true});"; MakeTypicalPeerConnectionCall(javascript);
diff --git a/content/browser/net/quota_policy_cookie_store_unittest.cc b/content/browser/net/quota_policy_cookie_store_unittest.cc index d4a036a..070d524 100644 --- a/content/browser/net/quota_policy_cookie_store_unittest.cc +++ b/content/browser/net/quota_policy_cookie_store_unittest.cc
@@ -37,7 +37,8 @@ public: QuotaPolicyCookieStoreTest() : pool_owner_(new base::SequencedWorkerPoolOwner(3, "Background Pool")), - loaded_event_(false, false) { + loaded_event_(false, false), + destroy_event_(false, false) { } void OnLoaded(const CanonicalCookieVector& cookies) { @@ -53,6 +54,20 @@ *cookies = cookies_; } + void ReleaseStore() { + EXPECT_TRUE(background_task_runner()->RunsTasksOnCurrentThread()); + store_ = nullptr; + destroy_event_.Signal(); + } + + void DestroyStoreOnBackgroundThread() { + background_task_runner()->PostTask( + FROM_HERE, base::Bind(&QuotaPolicyCookieStoreTest::ReleaseStore, + base::Unretained(this))); + destroy_event_.Wait(); + DestroyStore(); + } + protected: scoped_refptr<base::SequencedTaskRunner> background_task_runner() { return pool_owner_->pool()->GetSequencedTaskRunner( @@ -111,6 +126,7 @@ TestBrowserThreadBundle bundle_; scoped_ptr<base::SequencedWorkerPoolOwner> pool_owner_; base::WaitableEvent loaded_event_; + base::WaitableEvent destroy_event_; base::ScopedTempDir temp_dir_; scoped_refptr<QuotaPolicyCookieStore> store_; CanonicalCookieVector cookies_; @@ -127,9 +143,10 @@ t += base::TimeDelta::FromInternalValue(10); AddCookie("A", "B", "persistent.com", "/", t); - // Replace the store effectively destroying the current one and forcing it - // to write its data to disk. Then we can see if after loading it again it - // is still there. + // Replace the store, which forces the current store to flush data to + // disk. Then, after reloading the store, confirm that the data was flushed by + // making sure it loads successfully. This ensures that all pending commits + // are made to the store before allowing it to be closed. DestroyStore(); // Reload and test for persistence. @@ -172,9 +189,10 @@ t += base::TimeDelta::FromInternalValue(10); AddCookie("A", "B", "nonpersistent.com", "/", t); - // Replace the store effectively destroying the current one and forcing it - // to write its data to disk. Then we can see if after loading it again it - // is still there. + // Replace the store, which forces the current store to flush data to + // disk. Then, after reloading the store, confirm that the data was flushed by + // making sure it loads successfully. This ensures that all pending commits + // are made to the store before allowing it to be closed. DestroyStore(); // Specify storage policy that makes "nonpersistent.com" session only. scoped_refptr<content::MockSpecialStoragePolicy> storage_policy = @@ -182,7 +200,7 @@ storage_policy->AddSessionOnly( net::cookie_util::CookieOriginToURL("nonpersistent.com", false)); - // Reload and test for persistence + // Reload and test for persistence. STLDeleteElements(&cookies); CreateAndLoad(storage_policy.get(), &cookies); EXPECT_EQ(3U, cookies.size()); @@ -240,5 +258,35 @@ STLDeleteElements(&cookies); } +// Tests that the special storage policy is properly applied even when the store +// is destroyed on a background thread. +TEST_F(QuotaPolicyCookieStoreTest, TestDestroyOnBackgroundThread) { + // Specify storage policy that makes "nonpersistent.com" session only. + scoped_refptr<content::MockSpecialStoragePolicy> storage_policy = + new content::MockSpecialStoragePolicy(); + storage_policy->AddSessionOnly( + net::cookie_util::CookieOriginToURL("nonpersistent.com", false)); + + CanonicalCookieVector cookies; + CreateAndLoad(storage_policy.get(), &cookies); + ASSERT_EQ(0U, cookies.size()); + + base::Time t = base::Time::Now(); + AddCookie("A", "B", "nonpersistent.com", "/", t); + + // Replace the store, which forces the current store to flush data to + // disk. Then, after reloading the store, confirm that the data was flushed by + // making sure it loads successfully. This ensures that all pending commits + // are made to the store before allowing it to be closed. + DestroyStoreOnBackgroundThread(); + + // Reload and test for persistence. + STLDeleteElements(&cookies); + CreateAndLoad(storage_policy.get(), &cookies); + EXPECT_EQ(0U, cookies.size()); + + STLDeleteElements(&cookies); +} + } // namespace } // namespace content
diff --git a/content/browser/power_save_blocker_x11.cc b/content/browser/power_save_blocker_x11.cc index 9cd6113e..bc20e02 100644 --- a/content/browser/power_save_blocker_x11.cc +++ b/content/browser/power_save_blocker_x11.cc
@@ -93,6 +93,11 @@ void ApplyBlock(DBusAPI api); void RemoveBlock(DBusAPI api); + // Asynchronous callback functions for ApplyBlock and RemoveBlock. + // Functions do not receive ownership of |response|. + void ApplyBlockFinished(DBusAPI api, dbus::Response* response); + void RemoveBlockFinished(dbus::Response* response); + // If DPMS (the power saving system in X11) is not enabled, then we don't want // to try to disable power saving, since on some desktop environments that may // enable DPMS with very poor default settings (e.g. turning off the display @@ -115,6 +120,15 @@ bool enqueue_apply_; base::Lock lock_; + // Indicates that a D-Bus power save blocking request is in flight. + bool block_inflight_; + // Used to detect erronous redundant calls to RemoveBlock(). + bool unblock_inflight_; + // Indicates that RemoveBlock() is called before ApplyBlock() has finished. + // If it's true, then the RemoveBlock() call will be processed immediately + // after ApplyBlock() has finished. + bool enqueue_unblock_; + scoped_refptr<dbus::Bus> bus_; // The cookie that identifies our inhibit request, @@ -139,6 +153,9 @@ base::AutoLock lock(lock_); DCHECK(!enqueue_apply_); enqueue_apply_ = true; + block_inflight_ = false; + unblock_inflight_ = false; + enqueue_unblock_ = false; BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(&Delegate::InitOnUIThread, this)); } @@ -172,7 +189,8 @@ void PowerSaveBlockerImpl::Delegate::ApplyBlock(DBusAPI api) { DCHECK_CURRENTLY_ON(BrowserThread::FILE); - DCHECK(!bus_.get()); // ApplyBlock() should only be called once. + DCHECK(!bus_); // ApplyBlock() should only be called once. + DCHECK(!block_inflight_); dbus::Bus::Options options; options.bus_type = dbus::Bus::SESSION; @@ -233,26 +251,53 @@ break; } - // We could do this method call asynchronously, but if we did, we'd need to - // handle the case where we want to cancel the block before we get a reply. - // We're on the FILE thread so it should be OK to block briefly here. - scoped_ptr<dbus::Response> response(object_proxy->CallMethodAndBlock( - method_call.get(), dbus::ObjectProxy::TIMEOUT_USE_DEFAULT)); + block_inflight_ = true; + object_proxy->CallMethod( + method_call.get(), dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, + base::Bind(&PowerSaveBlockerImpl::Delegate::ApplyBlockFinished, this, + api)); +} + +void PowerSaveBlockerImpl::Delegate::ApplyBlockFinished( + DBusAPI api, + dbus::Response* response) { + DCHECK_CURRENTLY_ON(BrowserThread::FILE); + DCHECK(bus_); + DCHECK(block_inflight_); + block_inflight_ = false; + if (response) { // The method returns an inhibit_cookie, used to uniquely identify // this request. It should be used as an argument to Uninhibit() // in order to remove the request. - dbus::MessageReader message_reader(response.get()); + dbus::MessageReader message_reader(response); if (!message_reader.PopUint32(&inhibit_cookie_)) LOG(ERROR) << "Invalid Inhibit() response: " << response->ToString(); } else { LOG(ERROR) << "No response to Inhibit() request!"; } + + if (enqueue_unblock_) { + enqueue_unblock_ = false; + // RemoveBlock() was called while the Inhibit operation was in flight, + // so go ahead and remove the block now. + BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, + base::Bind(&Delegate::RemoveBlock, this, api_)); + } } void PowerSaveBlockerImpl::Delegate::RemoveBlock(DBusAPI api) { DCHECK_CURRENTLY_ON(BrowserThread::FILE); - DCHECK(bus_.get()); // RemoveBlock() should only be called once. + DCHECK(bus_); // RemoveBlock() should only be called once. + DCHECK(!unblock_inflight_); + + if (block_inflight_) { + DCHECK(!enqueue_unblock_); + // Can't call RemoveBlock until ApplyBlock's async operation has + // finished. Enqueue it for execution once ApplyBlock is done. + enqueue_unblock_ = true; + return; + } scoped_refptr<dbus::ObjectProxy> object_proxy; scoped_ptr<dbus::MethodCall> method_call; @@ -279,8 +324,18 @@ dbus::MessageWriter message_writer(method_call.get()); message_writer.AppendUint32(inhibit_cookie_); - scoped_ptr<dbus::Response> response(object_proxy->CallMethodAndBlock( - method_call.get(), dbus::ObjectProxy::TIMEOUT_USE_DEFAULT)); + unblock_inflight_ = true; + object_proxy->CallMethod( + method_call.get(), dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, + base::Bind(&PowerSaveBlockerImpl::Delegate::RemoveBlockFinished, this)); +} + +void PowerSaveBlockerImpl::Delegate::RemoveBlockFinished( + dbus::Response* response) { + DCHECK_CURRENTLY_ON(BrowserThread::FILE); + DCHECK(bus_); + unblock_inflight_ = false; + if (!response) LOG(ERROR) << "No response to Uninhibit() request!"; // We don't care about checking the result. We assume it works; we can't
diff --git a/content/browser/presentation/presentation_service_impl.cc b/content/browser/presentation/presentation_service_impl.cc index 7a0bab8..916dded 100644 --- a/content/browser/presentation/presentation_service_impl.cc +++ b/content/browser/presentation/presentation_service_impl.cc
@@ -18,8 +18,17 @@ #include "content/public/common/frame_navigate_params.h" #include "content/public/common/presentation_constants.h" +namespace content { + namespace { +const int kInvalidRequestSessionId = -1; + +int GetNextRequestSessionId() { + static int next_request_session_id = 0; + return ++next_request_session_id; +} + // The return value takes ownership of the contents of |input|. presentation::SessionMessagePtr ToMojoSessionMessage( content::PresentationSessionMessage* input) { @@ -76,9 +85,15 @@ return output.Pass(); } -} // namespace +void InvokeNewSessionMojoCallbackWithError( + const NewSessionMojoCallback& callback) { + callback.Run( + presentation::PresentationSessionInfoPtr(), + presentation::PresentationError::From( + PresentationError(PRESENTATION_ERROR_UNKNOWN, "Internal error"))); +} -namespace content { +} // namespace PresentationServiceImpl::PresentationServiceImpl( RenderFrameHost* render_frame_host, @@ -86,8 +101,7 @@ PresentationServiceDelegate* delegate) : WebContentsObserver(web_contents), delegate_(delegate), - is_start_session_pending_(false), - next_request_session_id_(0), + start_session_request_id_(kInvalidRequestSessionId), weak_factory_(this) { DCHECK(render_frame_host); DCHECK(web_contents); @@ -103,7 +117,6 @@ PresentationServiceImpl::~PresentationServiceImpl() { if (delegate_) delegate_->RemoveObserver(render_process_id_, render_frame_id_); - FlushNewSessionCallbacks(); } // static @@ -213,13 +226,21 @@ return; } - if (is_start_session_pending_) { - queued_start_session_requests_.push_back(make_linked_ptr( - new StartSessionRequest(presentation_url, presentation_id, callback))); + // Currently not processing a request, so no need for queueing. + if (start_session_request_id_ == kInvalidRequestSessionId) { + DoStartSession(make_scoped_ptr(new StartSessionRequest( + presentation_url, presentation_id, callback))); return; } - DoStartSession(presentation_url, presentation_id, callback); + if (queued_start_session_requests_.size() >= kMaxNumQueuedSessionRequests) { + InvokeNewSessionMojoCallbackWithError(callback); + return; + } + + queued_start_session_requests_.push_back( + make_linked_ptr(new StartSessionRequest( + presentation_url, presentation_id, callback))); } void PresentationServiceImpl::JoinSession( @@ -232,98 +253,120 @@ return; } - int request_session_id = RegisterNewSessionCallback(callback); + int request_session_id = RegisterJoinSessionCallback(callback); + if (request_session_id == kInvalidRequestSessionId) { + InvokeNewSessionMojoCallbackWithError(callback); + return; + } delegate_->JoinSession( render_process_id_, render_frame_id_, presentation_url, presentation_id, - base::Bind(&PresentationServiceImpl::OnStartOrJoinSessionSucceeded, - weak_factory_.GetWeakPtr(), false, request_session_id), - base::Bind(&PresentationServiceImpl::OnStartOrJoinSessionError, - weak_factory_.GetWeakPtr(), false, request_session_id)); + base::Bind(&PresentationServiceImpl::OnJoinSessionSucceeded, + weak_factory_.GetWeakPtr(), request_session_id), + base::Bind(&PresentationServiceImpl::OnJoinSessionError, + weak_factory_.GetWeakPtr(), request_session_id)); } void PresentationServiceImpl::HandleQueuedStartSessionRequests() { - if (queued_start_session_requests_.empty()) { - is_start_session_pending_ = false; + if (queued_start_session_requests_.empty()) return; - } + linked_ptr<StartSessionRequest> request = queued_start_session_requests_.front(); queued_start_session_requests_.pop_front(); - DoStartSession(request->presentation_url(), - request->presentation_id(), - request->PassCallback()); + DoStartSession(make_scoped_ptr(request.release())); } -int PresentationServiceImpl::RegisterNewSessionCallback( +int PresentationServiceImpl::RegisterJoinSessionCallback( const NewSessionMojoCallback& callback) { - ++next_request_session_id_; - pending_session_cbs_[next_request_session_id_].reset( - new NewSessionMojoCallback(callback)); - return next_request_session_id_; -} + if (pending_join_session_cbs_.size() >= kMaxNumQueuedSessionRequests) + return kInvalidRequestSessionId; -void PresentationServiceImpl::FlushNewSessionCallbacks() { - for (auto& pending_entry : pending_session_cbs_) { - InvokeNewSessionMojoCallbackWithError(*pending_entry.second); - } - pending_session_cbs_.clear(); + int request_id = GetNextRequestSessionId(); + pending_join_session_cbs_[request_id].reset( + new NewSessionMojoCallbackWrapper(callback)); + return request_id; } void PresentationServiceImpl::DoStartSession( - const std::string& presentation_url, - const std::string& presentation_id, - const NewSessionMojoCallback& callback) { - int request_session_id = RegisterNewSessionCallback(callback); - is_start_session_pending_ = true; + scoped_ptr<StartSessionRequest> request) { + DCHECK_EQ(kInvalidRequestSessionId, start_session_request_id_); + DCHECK(!pending_start_session_cb_.get()); + + int request_session_id = GetNextRequestSessionId(); + start_session_request_id_ = request_session_id; + pending_start_session_cb_ = request->PassCallback(); + delegate_->StartSession( render_process_id_, render_frame_id_, - presentation_url, - presentation_id, - base::Bind(&PresentationServiceImpl::OnStartOrJoinSessionSucceeded, - weak_factory_.GetWeakPtr(), true, request_session_id), - base::Bind(&PresentationServiceImpl::OnStartOrJoinSessionError, - weak_factory_.GetWeakPtr(), true, request_session_id)); + request->presentation_url(), + request->presentation_id(), + base::Bind(&PresentationServiceImpl::OnStartSessionSucceeded, + weak_factory_.GetWeakPtr(), request_session_id), + base::Bind(&PresentationServiceImpl::OnStartSessionError, + weak_factory_.GetWeakPtr(), request_session_id)); } -void PresentationServiceImpl::OnStartOrJoinSessionSucceeded( - bool is_start_session, +void PresentationServiceImpl::OnStartSessionSucceeded( int request_session_id, const PresentationSessionInfo& session_info) { - RunAndEraseNewSessionMojoCallback( + if (request_session_id == start_session_request_id_) { + CHECK(pending_start_session_cb_.get()); + pending_start_session_cb_->Run( + presentation::PresentationSessionInfo::From(session_info), + presentation::PresentationErrorPtr()); + pending_start_session_cb_.reset(); + start_session_request_id_ = kInvalidRequestSessionId; + HandleQueuedStartSessionRequests(); + } +} + +void PresentationServiceImpl::OnStartSessionError( + int request_session_id, + const PresentationError& error) { + if (request_session_id == start_session_request_id_) { + CHECK(pending_start_session_cb_.get()); + pending_start_session_cb_->Run( + presentation::PresentationSessionInfoPtr(), + presentation::PresentationError::From(error)); + pending_start_session_cb_.reset(); + start_session_request_id_ = kInvalidRequestSessionId; + HandleQueuedStartSessionRequests(); + } +} + +void PresentationServiceImpl::OnJoinSessionSucceeded( + int request_session_id, + const PresentationSessionInfo& session_info) { + RunAndEraseJoinSessionMojoCallback( request_session_id, presentation::PresentationSessionInfo::From(session_info), presentation::PresentationErrorPtr()); - if (is_start_session) - HandleQueuedStartSessionRequests(); } -void PresentationServiceImpl::OnStartOrJoinSessionError( - bool is_start_session, +void PresentationServiceImpl::OnJoinSessionError( int request_session_id, const PresentationError& error) { - RunAndEraseNewSessionMojoCallback( + RunAndEraseJoinSessionMojoCallback( request_session_id, presentation::PresentationSessionInfoPtr(), presentation::PresentationError::From(error)); - if (is_start_session) - HandleQueuedStartSessionRequests(); } -void PresentationServiceImpl::RunAndEraseNewSessionMojoCallback( +void PresentationServiceImpl::RunAndEraseJoinSessionMojoCallback( int request_session_id, presentation::PresentationSessionInfoPtr session, presentation::PresentationErrorPtr error) { - auto it = pending_session_cbs_.find(request_session_id); - if (it == pending_session_cbs_.end()) + auto it = pending_join_session_cbs_.find(request_session_id); + if (it == pending_join_session_cbs_.end()) return; DCHECK(it->second.get()); it->second->Run(session.Pass(), error.Pass()); - pending_session_cbs_.erase(it); + pending_join_session_cbs_.erase(it); } void PresentationServiceImpl::SetDefaultPresentationURL( @@ -489,15 +532,23 @@ default_presentation_url_.clear(); default_presentation_id_.clear(); + screen_availability_listener_.reset(); + queued_start_session_requests_.clear(); - FlushNewSessionCallbacks(); + start_session_request_id_ = kInvalidRequestSessionId; + pending_start_session_cb_.reset(); + + pending_join_session_cbs_.clear(); + default_session_start_context_.reset(); + if (on_session_messages_callback_.get()) { on_session_messages_callback_->Run( mojo::Array<presentation::SessionMessagePtr>()); on_session_messages_callback_.reset(); } + if (send_message_callback_) { // Run the callback with false, indicating the renderer to stop sending // the requests and invalidate all pending requests. @@ -506,15 +557,6 @@ } } -// static -void PresentationServiceImpl::InvokeNewSessionMojoCallbackWithError( - const NewSessionMojoCallback& callback) { - callback.Run( - presentation::PresentationSessionInfoPtr(), - presentation::PresentationError::From( - PresentationError(PRESENTATION_ERROR_UNKNOWN, "Internal error"))); -} - void PresentationServiceImpl::OnDelegateDestroyed() { DVLOG(2) << "PresentationServiceImpl::OnDelegateDestroyed"; delegate_ = nullptr; @@ -551,26 +593,40 @@ service_->client_->OnScreenAvailabilityUpdated(available); } +PresentationServiceImpl::NewSessionMojoCallbackWrapper +::NewSessionMojoCallbackWrapper(const NewSessionMojoCallback& callback) + : callback_(callback) { +} + +PresentationServiceImpl::NewSessionMojoCallbackWrapper +::~NewSessionMojoCallbackWrapper() { + if (!callback_.is_null()) + InvokeNewSessionMojoCallbackWithError(callback_); +} + +void PresentationServiceImpl::NewSessionMojoCallbackWrapper::Run( + presentation::PresentationSessionInfoPtr session, + presentation::PresentationErrorPtr error) { + DCHECK(!callback_.is_null()); + callback_.Run(session.Pass(), error.Pass()); + callback_.reset(); +} + PresentationServiceImpl::StartSessionRequest::StartSessionRequest( const std::string& presentation_url, const std::string& presentation_id, const NewSessionMojoCallback& callback) : presentation_url_(presentation_url), presentation_id_(presentation_id), - callback_(callback) { + callback_wrapper_(new NewSessionMojoCallbackWrapper(callback)) { } PresentationServiceImpl::StartSessionRequest::~StartSessionRequest() { - // Ensure that a pending callback is not dropped. - if (!callback_.is_null()) - InvokeNewSessionMojoCallbackWithError(callback_); } -PresentationServiceImpl::NewSessionMojoCallback +scoped_ptr<PresentationServiceImpl::NewSessionMojoCallbackWrapper> PresentationServiceImpl::StartSessionRequest::PassCallback() { - NewSessionMojoCallback callback = callback_; - callback_.reset(); - return callback; + return callback_wrapper_.Pass(); } PresentationServiceImpl::DefaultSessionStartContext
diff --git a/content/browser/presentation/presentation_service_impl.h b/content/browser/presentation/presentation_service_impl.h index aeb32f0..9d4f5a12 100644 --- a/content/browser/presentation/presentation_service_impl.h +++ b/content/browser/presentation/presentation_service_impl.h
@@ -31,6 +31,10 @@ struct PresentationSessionMessage; class RenderFrameHost; +using NewSessionMojoCallback = mojo::Callback< + void(presentation::PresentationSessionInfoPtr, + presentation::PresentationErrorPtr)>; + // Implementation of Mojo PresentationService. // It handles Presentation API requests coming from Blink / renderer process // and delegates the requests to the embedder's media router via @@ -78,10 +82,14 @@ DefaultSessionStartReset); FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest, ReceiveSessionMessagesAfterReset); + FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest, + MaxPendingStartSessionRequests); + FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest, + MaxPendingJoinSessionRequests); - using NewSessionMojoCallback = - mojo::Callback<void(presentation::PresentationSessionInfoPtr, - presentation::PresentationErrorPtr)>; + // Maximum number of queued StartSession or JoinSession requests. + static const int kMaxNumQueuedSessionRequests = 10; + using DefaultSessionMojoCallback = mojo::Callback<void(presentation::PresentationSessionInfoPtr)>; using SessionStateCallback = @@ -133,7 +141,24 @@ scoped_ptr<PresentationSessionInfo> session_; }; - // Context for a StartSession request. + // Ensures the provided NewSessionMojoCallback is invoked exactly once + // before it goes out of scope. + class NewSessionMojoCallbackWrapper { + public: + explicit NewSessionMojoCallbackWrapper( + const NewSessionMojoCallback& callback); + ~NewSessionMojoCallbackWrapper(); + + void Run(presentation::PresentationSessionInfoPtr session, + presentation::PresentationErrorPtr error); + + private: + NewSessionMojoCallback callback_; + + DISALLOW_COPY_AND_ASSIGN(NewSessionMojoCallbackWrapper); + }; + + // Context for a queued StartSession request. class CONTENT_EXPORT StartSessionRequest { public: StartSessionRequest(const std::string& presentation_url, @@ -141,9 +166,7 @@ const NewSessionMojoCallback& callback); ~StartSessionRequest(); - // Retrieves the pending callback from this request, transferring ownership - // to the caller. - NewSessionMojoCallback PassCallback(); + scoped_ptr<NewSessionMojoCallbackWrapper> PassCallback(); const std::string& presentation_url() const { return presentation_url_; } const std::string& presentation_id() const { return presentation_id_; } @@ -151,7 +174,9 @@ private: const std::string presentation_url_; const std::string presentation_id_; - NewSessionMojoCallback callback_; + scoped_ptr<NewSessionMojoCallbackWrapper> callback_wrapper_; + + DISALLOW_COPY_AND_ASSIGN(StartSessionRequest); }; // |render_frame_host|: The RFH this instance is associated with. @@ -210,10 +235,11 @@ void OnDefaultPresentationStarted(const PresentationSessionInfo& session) override; - // Finds the callback from |pending_session_cbs_| using |request_session_id|. + // Finds the callback from |pending_join_session_cbs_| using + // |request_session_id|. // If it exists, invoke it with |session| and |error|, then erase it from - // |pending_session_cbs_|. - void RunAndEraseNewSessionMojoCallback( + // |pending_join_session_cbs_|. + void RunAndEraseJoinSessionMojoCallback( int request_session_id, presentation::PresentationSessionInfoPtr session, presentation::PresentationErrorPtr error); @@ -229,21 +255,22 @@ // These functions are bound as base::Callbacks and passed to // embedder's implementation of PresentationServiceDelegate for later // invocation. - void OnStartOrJoinSessionSucceeded( - bool is_start_session, + void OnStartSessionSucceeded( int request_session_id, const PresentationSessionInfo& session_info); - void OnStartOrJoinSessionError( - bool is_start_session, + void OnStartSessionError( + int request_session_id, + const PresentationError& error); + void OnJoinSessionSucceeded( + int request_session_id, + const PresentationSessionInfo& session_info); + void OnJoinSessionError( int request_session_id, const PresentationError& error); void OnSendMessageCallback(); // Requests delegate to start a session. - void DoStartSession( - const std::string& presentation_url, - const std::string& presentation_id, - const NewSessionMojoCallback& callback); + void DoStartSession(scoped_ptr<StartSessionRequest> request); // Passed to embedder's implementation of PresentationServiceDelegate for // later invocation when session messages arrive. @@ -258,16 +285,10 @@ // the first one in the queue. void HandleQueuedStartSessionRequests(); - // Associates |callback| with a unique request ID and stores it in a map. - int RegisterNewSessionCallback( - const NewSessionMojoCallback& callback); - - // Flushes all pending new session callbacks with error responses. - void FlushNewSessionCallbacks(); - - // Invokes |callback| with an error. - static void InvokeNewSessionMojoCallbackWithError( - const NewSessionMojoCallback& callback); + // Associates a JoinSession |callback| with a unique request ID and + // stores it in a map. + // Returns a positive value on success. + int RegisterJoinSessionCallback(const NewSessionMojoCallback& callback); // Returns true if this object is associated with |render_frame_host|. bool FrameMatches(content::RenderFrameHost* render_frame_host) const; @@ -290,11 +311,14 @@ // it is removed from head of the queue. std::deque<linked_ptr<StartSessionRequest>> queued_start_session_requests_; - // Indicates that a StartSession request is currently being processed. - bool is_start_session_pending_; + // For StartSession requests. + // Set to a positive value when a StartSession request is being processed. + int start_session_request_id_; + scoped_ptr<NewSessionMojoCallbackWrapper> pending_start_session_cb_; - int next_request_session_id_; - base::hash_map<int, linked_ptr<NewSessionMojoCallback>> pending_session_cbs_; + // For JoinSession requests. + base::hash_map<int, linked_ptr<NewSessionMojoCallbackWrapper>> + pending_join_session_cbs_; scoped_ptr<DefaultSessionStartContext> default_session_start_context_;
diff --git a/content/browser/presentation/presentation_service_impl_unittest.cc b/content/browser/presentation/presentation_service_impl_unittest.cc index 177da86..677418f 100644 --- a/content/browser/presentation/presentation_service_impl_unittest.cc +++ b/content/browser/presentation/presentation_service_impl_unittest.cc
@@ -43,6 +43,11 @@ expected->data.Equals(actual->data); } +void DoNothing( + presentation::PresentationSessionInfoPtr info, + presentation::PresentationErrorPtr error) { +} + } // namespace class MockPresentationServiceDelegate : public PresentationServiceDelegate { @@ -124,8 +129,7 @@ class PresentationServiceImplTest : public RenderViewHostImplTestHarness { public: - PresentationServiceImplTest() - : default_session_started_count_(0) {} + PresentationServiceImplTest() : default_session_started_count_(0) {} void SetUp() override { RenderViewHostImplTestHarness::SetUp(); @@ -784,4 +788,53 @@ SaveQuitClosureAndRunLoop(); } +TEST_F(PresentationServiceImplTest, MaxPendingStartSessionRequests) { + const char* presentation_url = "http://fooUrl%d"; + const char* presentation_id = "presentationId%d"; + int num_requests = PresentationServiceImpl::kMaxNumQueuedSessionRequests + 1; + int i = 0; + // First request will be processed. The subsequent + // |kMaxNumQueuedSessionRequests| requests will be queued. + EXPECT_CALL(mock_delegate_, StartSession(_, _, _, _, _, _)).Times(1); + for (; i < num_requests; ++i) { + service_ptr_->StartSession( + base::StringPrintf(presentation_url, i), + base::StringPrintf(presentation_id, i), + base::Bind(&DoNothing)); + } + + // Exceeded maximum queue size, should invoke mojo callback with error. + service_ptr_->StartSession( + base::StringPrintf(presentation_url, i), + base::StringPrintf(presentation_id, i), + base::Bind( + &PresentationServiceImplTest::ExpectNewSessionMojoCallbackError, + base::Unretained(this))); + SaveQuitClosureAndRunLoop(); +} + +TEST_F(PresentationServiceImplTest, MaxPendingJoinSessionRequests) { + const char* presentation_url = "http://fooUrl%d"; + const char* presentation_id = "presentationId%d"; + int num_requests = PresentationServiceImpl::kMaxNumQueuedSessionRequests; + int i = 0; + EXPECT_CALL(mock_delegate_, JoinSession(_, _, _, _, _, _)) + .Times(num_requests); + for (; i < num_requests; ++i) { + service_ptr_->JoinSession( + base::StringPrintf(presentation_url, i), + base::StringPrintf(presentation_id, i), + base::Bind(&DoNothing)); + } + + // Exceeded maximum queue size, should invoke mojo callback with error. + service_ptr_->JoinSession( + base::StringPrintf(presentation_url, i), + base::StringPrintf(presentation_id, i), + base::Bind( + &PresentationServiceImplTest::ExpectNewSessionMojoCallbackError, + base::Unretained(this))); + SaveQuitClosureAndRunLoop(); +} + } // namespace content
diff --git a/content/browser/service_worker/service_worker_disk_cache.cc b/content/browser/service_worker/service_worker_disk_cache.cc index 4b6237f..925bdcf 100644 --- a/content/browser/service_worker/service_worker_disk_cache.cc +++ b/content/browser/service_worker/service_worker_disk_cache.cc
@@ -6,6 +6,10 @@ namespace content { +ServiceWorkerDiskCache::ServiceWorkerDiskCache() + : AppCacheDiskCache(true /* use_simple_cache */) { +} + ServiceWorkerResponseReader::ServiceWorkerResponseReader( int64 response_id, ServiceWorkerDiskCache* disk_cache) : AppCacheResponseReader(response_id, 0, disk_cache) {
diff --git a/content/browser/service_worker/service_worker_disk_cache.h b/content/browser/service_worker/service_worker_disk_cache.h index 7b9b4e4..1ba34b44 100644 --- a/content/browser/service_worker/service_worker_disk_cache.h +++ b/content/browser/service_worker/service_worker_disk_cache.h
@@ -18,6 +18,8 @@ class CONTENT_EXPORT ServiceWorkerDiskCache : public AppCacheDiskCache { + public: + ServiceWorkerDiskCache(); }; class CONTENT_EXPORT ServiceWorkerResponseReader
diff --git a/content/browser/service_worker/service_worker_metrics.cc b/content/browser/service_worker/service_worker_metrics.cc index dc3c157..c0d882d3 100644 --- a/content/browser/service_worker/service_worker_metrics.cc +++ b/content/browser/service_worker/service_worker_metrics.cc
@@ -107,4 +107,13 @@ SERVICE_WORKER_ERROR_MAX_VALUE); } +void ServiceWorkerMetrics::RecordEventStatus(size_t fired_events, + size_t handled_events) { + if (!fired_events) + return; + int unhandled_ratio = (fired_events - handled_events) * 100 / fired_events; + UMA_HISTOGRAM_PERCENTAGE("ServiceWorker.UnhandledEventRatio", + unhandled_ratio); +} + } // namespace content
diff --git a/content/browser/service_worker/service_worker_metrics.h b/content/browser/service_worker/service_worker_metrics.h index 7b477af..400cd7e 100644 --- a/content/browser/service_worker/service_worker_metrics.h +++ b/content/browser/service_worker/service_worker_metrics.h
@@ -65,6 +65,10 @@ static void RecordActivateEventStatus(ServiceWorkerStatusCode status); static void RecordInstallEventStatus(ServiceWorkerStatusCode status); + // Records the ratio of unhandled events to the all events fired during + // the lifetime of ServiceWorker. + static void RecordEventStatus(size_t fired_events, size_t handled_events); + private: DISALLOW_IMPLICIT_CONSTRUCTORS(ServiceWorkerMetrics); };
diff --git a/content/browser/service_worker/service_worker_version.cc b/content/browser/service_worker/service_worker_version.cc index 9504bef..4299a26c 100644 --- a/content/browser/service_worker/service_worker_version.cc +++ b/content/browser/service_worker/service_worker_version.cc
@@ -366,6 +366,25 @@ const int ServiceWorkerVersion::kStartWorkerTimeoutMinutes = 5; const int ServiceWorkerVersion::kRequestTimeoutMinutes = 5; +class ServiceWorkerVersion::ServiceWorkerEventMetrics { + public: + ServiceWorkerEventMetrics() {} + ~ServiceWorkerEventMetrics() { + ServiceWorkerMetrics::RecordEventStatus(fired_events, handled_events); + } + + void RecordEventStatus(bool handled) { + ++fired_events; + if (handled) + ++handled_events; + } + + private: + size_t fired_events = 0; + size_t handled_events = 0; + DISALLOW_COPY_AND_ASSIGN(ServiceWorkerEventMetrics); +}; + ServiceWorkerVersion::ServiceWorkerVersion( ServiceWorkerRegistration* registration, const GURL& script_url, @@ -379,6 +398,7 @@ context_(context), script_cache_map_(this, context), ping_state_(NOT_PINGING), + metrics_(new ServiceWorkerEventMetrics), weak_factory_(this) { DCHECK(context_); DCHECK(registration); @@ -1185,6 +1205,10 @@ return; } + // TODO(kinuko): Record other event statuses too. + const bool handled = (result == SERVICE_WORKER_FETCH_EVENT_RESULT_RESPONSE); + metrics_->RecordEventStatus(handled); + scoped_refptr<ServiceWorkerVersion> protect(this); callback->Run(SERVICE_WORKER_OK, result, response); RemoveCallbackAndStopIfRedundant(&fetch_callbacks_, request_id);
diff --git a/content/browser/service_worker/service_worker_version.h b/content/browser/service_worker/service_worker_version.h index b020c25214..af011e5 100644 --- a/content/browser/service_worker/service_worker_version.h +++ b/content/browser/service_worker/service_worker_version.h
@@ -329,6 +329,8 @@ FRIEND_TEST_ALL_PREFIXES(ServiceWorkerVersionBrowserTest, TimeoutWorkerInEvent); + class ServiceWorkerEventMetrics; + typedef ServiceWorkerVersion self; using ServiceWorkerClients = std::vector<ServiceWorkerClientInfo>; @@ -553,6 +555,8 @@ // running |start_callbacks_|. ServiceWorkerStatusCode start_worker_status_ = SERVICE_WORKER_OK; + scoped_ptr<ServiceWorkerEventMetrics> metrics_; + base::WeakPtrFactory<ServiceWorkerVersion> weak_factory_; DISALLOW_COPY_AND_ASSIGN(ServiceWorkerVersion);
diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc index 3ae902e..c09d429 100644 --- a/content/browser/site_per_process_browsertest.cc +++ b/content/browser/site_per_process_browsertest.cc
@@ -1505,16 +1505,10 @@ TestNavigationObserver observer(shell()->web_contents()); // Navigate the first subframe to a cross-site page with two subframes. - // NavigateFrameToURL can't be used here because it doesn't guarantee that - // FrameTreeNodes will have been created for child frames when it returns. - RenderFrameHostCreatedObserver frame_observer(shell()->web_contents(), 4); GURL foo_url( embedded_test_server()->GetURL("foo.com", "/frame_tree/1-1.html")); - NavigationController::LoadURLParams params(foo_url); - params.transition_type = ui::PAGE_TRANSITION_LINK; - params.frame_tree_node_id = root->child_at(0)->frame_tree_node_id(); - root->child_at(0)->navigator()->GetController()->LoadURLWithParams(params); - frame_observer.Wait(); + NavigateFrameToURL(root->child_at(0), foo_url); + EXPECT_TRUE(WaitForLoadStop(shell()->web_contents())); // We can't use a TestNavigationObserver to verify the URL here, // since the frame has children that may have clobbered it in the observer. @@ -1591,13 +1585,11 @@ TestNavigationObserver observer(shell()->web_contents()); // Navigate the second (sandboxed) subframe to a cross-site page with a - // subframe. Use RenderFrameHostCreatedObserver to guarantee that all - // FrameTreeNodes are created for child frames. - RenderFrameHostCreatedObserver frame_observer(shell()->web_contents(), 4); + // subframe. GURL foo_url( embedded_test_server()->GetURL("foo.com", "/frame_tree/1-1.html")); NavigateFrameToURL(root->child_at(1), foo_url); - frame_observer.Wait(); + EXPECT_TRUE(WaitForLoadStop(shell()->web_contents())); // We can't use a TestNavigationObserver to verify the URL here, // since the frame has children that may have clobbered it in the observer.
diff --git a/content/browser/tracing/tracing_ui.cc b/content/browser/tracing/tracing_ui.cc index 58fbb75..546fd74d 100644 --- a/content/browser/tracing/tracing_ui.cc +++ b/content/browser/tracing/tracing_ui.cc
@@ -40,14 +40,14 @@ void OnGotCategories(const WebUIDataSource::GotDataCallback& callback, const std::set<std::string>& categorySet) { - scoped_ptr<base::ListValue> category_list(new base::ListValue()); + base::ListValue category_list; for (std::set<std::string>::const_iterator it = categorySet.begin(); it != categorySet.end(); it++) { - category_list->AppendString(*it); + category_list.AppendString(*it); } base::RefCountedString* res = new base::RefCountedString(); - base::JSONWriter::Write(category_list.get(), &res->data()); + base::JSONWriter::Write(category_list, &res->data()); callback.Run(res); } @@ -133,12 +133,12 @@ void OnTraceBufferStatusResult(const WebUIDataSource::GotDataCallback& callback, float percent_full, size_t approximate_event_count) { - scoped_ptr<base::DictionaryValue> status(new base::DictionaryValue()); - status->SetDouble("percentFull", percent_full); - status->SetInteger("approximateEventCount", approximate_event_count); + base::DictionaryValue status; + status.SetDouble("percentFull", percent_full); + status.SetInteger("approximateEventCount", approximate_event_count); std::string status_json; - base::JSONWriter::Write(status.get(), &status_json); + base::JSONWriter::Write(status, &status_json); base::RefCountedString* status_base64 = new base::RefCountedString(); base::Base64Encode(status_json, &status_base64->data()); @@ -177,18 +177,17 @@ TracingController::GetInstance()->GetMonitoringStatus( &is_monitoring, &category_filter, &options); - scoped_ptr<base::DictionaryValue> - monitoring_options(new base::DictionaryValue()); - monitoring_options->SetBoolean("isMonitoring", is_monitoring); - monitoring_options->SetString("categoryFilter", category_filter.ToString()); - monitoring_options->SetBoolean("useSystemTracing", options.enable_systrace); - monitoring_options->SetBoolean( + base::DictionaryValue monitoring_options; + monitoring_options.SetBoolean("isMonitoring", is_monitoring); + monitoring_options.SetString("categoryFilter", category_filter.ToString()); + monitoring_options.SetBoolean("useSystemTracing", options.enable_systrace); + monitoring_options.SetBoolean( "useContinuousTracing", options.record_mode == base::trace_event::RECORD_CONTINUOUSLY); - monitoring_options->SetBoolean("useSampling", options.enable_sampling); + monitoring_options.SetBoolean("useSampling", options.enable_sampling); std::string monitoring_options_json; - base::JSONWriter::Write(monitoring_options.get(), &monitoring_options_json); + base::JSONWriter::Write(monitoring_options, &monitoring_options_json); base::RefCountedString* monitoring_options_base64 = new base::RefCountedString();
diff --git a/content/browser/web_contents/web_contents_android.cc b/content/browser/web_contents/web_contents_android.cc index 7600035..dc23623c 100644 --- a/content/browser/web_contents/web_contents_android.cc +++ b/content/browser/web_contents/web_contents_android.cc
@@ -46,7 +46,7 @@ const base::Value* result) { JNIEnv* env = base::android::AttachCurrentThread(); std::string json; - base::JSONWriter::Write(result, &json); + base::JSONWriter::Write(*result, &json); ScopedJavaLocalRef<jstring> j_json = ConvertUTF8ToJavaString(env, json); Java_WebContentsImpl_onEvaluateJavaScriptResult( env, j_json.obj(), callback.obj());
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc index 269b4716..d8bdf924 100644 --- a/content/browser/web_contents/web_contents_impl.cc +++ b/content/browser/web_contents/web_contents_impl.cc
@@ -3347,14 +3347,6 @@ FOR_EACH_OBSERVER(WebContentsObserver, observers_, RenderViewHostChanged(old_host, new_host)); - // TODO(avi): Remove. http://crbug.com/170921 - std::pair<RenderViewHost*, RenderViewHost*> details = - std::make_pair(old_host, new_host); - NotificationService::current()->Notify( - NOTIFICATION_RENDER_VIEW_HOST_CHANGED, - Source<WebContents>(this), - Details<std::pair<RenderViewHost*, RenderViewHost*> >(&details)); - // Ensure that the associated embedder gets cleared after a RenderViewHost // gets swapped, so we don't reuse the same embedder next time a // RenderViewHost is attached to this WebContents.
diff --git a/content/browser/webui/web_ui_impl.cc b/content/browser/webui/web_ui_impl.cc index a9194a9..1f953a2 100644 --- a/content/browser/webui/web_ui_impl.cc +++ b/content/browser/webui/web_ui_impl.cc
@@ -36,7 +36,7 @@ if (i > 0) parameters += base::char16(','); - base::JSONWriter::Write(arg_list[i], &json); + base::JSONWriter::Write(*arg_list[i], &json); parameters += base::UTF8ToUTF16(json); } return base::ASCIIToUTF16(function_name) +
diff --git a/content/child/DEPS b/content/child/DEPS index 6670427..f677068 100644 --- a/content/child/DEPS +++ b/content/child/DEPS
@@ -9,6 +9,6 @@ "+content/app/strings/grit", # For generated headers "+content/public/child", - "+media/base/android", + "+media/base", "+v8/include/v8.h" ]
diff --git a/content/child/assert_matching_enums.cc b/content/child/assert_matching_enums.cc index 0d087ed..0fc87bf 100644 --- a/content/child/assert_matching_enums.cc +++ b/content/child/assert_matching_enums.cc
@@ -8,7 +8,7 @@ #include "base/macros.h" #include "cc/animation/animation.h" #include "content/public/common/screen_orientation_values.h" -#include "net/base/mime_util.h" +#include "media/base/mime_util.h" #include "third_party/WebKit/public/platform/WebCompositorAnimation.h" #include "third_party/WebKit/public/platform/WebMimeRegistry.h" #include "third_party/WebKit/public/platform/WebScreenOrientationLockType.h" @@ -40,11 +40,11 @@ // SupportsType STATIC_ASSERT_MATCHING_ENUM(blink::WebMimeRegistry::IsNotSupported, - net::IsNotSupported); + media::IsNotSupported); STATIC_ASSERT_MATCHING_ENUM(blink::WebMimeRegistry::IsSupported, - net::IsSupported); + media::IsSupported); STATIC_ASSERT_MATCHING_ENUM(blink::WebMimeRegistry::MayBeSupported, - net::MayBeSupported); + media::MayBeSupported); // TargetProperty STATIC_ASSERT_MATCHING_ENUM(
diff --git a/content/child/background_sync/background_sync_provider.cc b/content/child/background_sync/background_sync_provider.cc index 3a445d8..cdf0353 100644 --- a/content/child/background_sync/background_sync_provider.cc +++ b/content/child/background_sync/background_sync_provider.cc
@@ -213,6 +213,7 @@ registrations[i]).release(); } callbacks->onSuccess(results); + break; case BACKGROUND_SYNC_ERROR_NOT_FOUND: // This error should never be returned from // BackgroundSyncManager::GetRegistrations
diff --git a/content/child/background_sync/background_sync_provider_thread_proxy.cc b/content/child/background_sync/background_sync_provider_thread_proxy.cc index 2361c4b..378c45c 100644 --- a/content/child/background_sync/background_sync_provider_thread_proxy.cc +++ b/content/child/background_sync/background_sync_provider_thread_proxy.cc
@@ -40,7 +40,7 @@ WorkerTaskRunner::Instance()->PostTask( worker_thread_id_, base::Bind(&blink::WebCallbacks<S, T>::onSuccess, - base::Unretained(callbacks_.get()), results)); + base::Owned(callbacks_.release()), results)); } virtual void onError(T* error) { @@ -49,7 +49,7 @@ WorkerTaskRunner::Instance()->PostTask( worker_thread_id_, base::Bind(&blink::WebCallbacks<S, T>::onError, - base::Unretained(callbacks_.get()), error)); + base::Owned(callbacks_.release()), error)); } private:
diff --git a/content/common/frame_messages.h b/content/common/frame_messages.h index 5271e4e1..8fa0063 100644 --- a/content/common/frame_messages.h +++ b/content/common/frame_messages.h
@@ -61,12 +61,14 @@ IPC_STRUCT_TRAITS_MEMBER(unfiltered_link_url) IPC_STRUCT_TRAITS_MEMBER(src_url) IPC_STRUCT_TRAITS_MEMBER(has_image_contents) + IPC_STRUCT_TRAITS_MEMBER(properties) IPC_STRUCT_TRAITS_MEMBER(page_url) IPC_STRUCT_TRAITS_MEMBER(keyword_url) IPC_STRUCT_TRAITS_MEMBER(frame_url) IPC_STRUCT_TRAITS_MEMBER(frame_page_state) IPC_STRUCT_TRAITS_MEMBER(media_flags) IPC_STRUCT_TRAITS_MEMBER(selection_text) + IPC_STRUCT_TRAITS_MEMBER(title_text) IPC_STRUCT_TRAITS_MEMBER(suggested_filename) IPC_STRUCT_TRAITS_MEMBER(misspelled_word) IPC_STRUCT_TRAITS_MEMBER(misspelling_hash)
diff --git a/content/common/gpu/client/context_provider_command_buffer.cc b/content/common/gpu/client/context_provider_command_buffer.cc index 2f00de1..58e34b64 100644 --- a/content/common/gpu/client/context_provider_command_buffer.cc +++ b/content/common/gpu/client/context_provider_command_buffer.cc
@@ -137,7 +137,7 @@ gr_context_.reset(new GrContextForWebGraphicsContext3D(context3d_.get())); // If GlContext is already lost, also abandon the new GrContext. - if (IsContextLost()) + if (gr_context_->get() && IsContextLost()) gr_context_->get()->abandonContext(); return gr_context_->get();
diff --git a/content/common/gpu/gpu_command_buffer_stub.cc b/content/common/gpu/gpu_command_buffer_stub.cc index 5c878fca..bb4044a 100644 --- a/content/common/gpu/gpu_command_buffer_stub.cc +++ b/content/common/gpu/gpu_command_buffer_stub.cc
@@ -118,7 +118,7 @@ void AppendAsTraceFormat(std::string* out) const override { std::string tmp; - base::JSONWriter::Write(value_.get(), &tmp); + base::JSONWriter::Write(*value_, &tmp); *out += tmp; }
diff --git a/content/common/origin_util_unittest.cc b/content/common/origin_util_unittest.cc index 2991a9d9..49598f65 100644 --- a/content/common/origin_util_unittest.cc +++ b/content/common/origin_util_unittest.cc
@@ -20,6 +20,12 @@ EXPECT_FALSE(IsOriginSecure(GURL("ws://example.com/fun.html"))); EXPECT_TRUE(IsOriginSecure(GURL("http://localhost/fun.html"))); + EXPECT_TRUE(IsOriginSecure(GURL("http://pumpkin.localhost/fun.html"))); + EXPECT_TRUE( + IsOriginSecure(GURL("http://crumpet.pumpkin.localhost/fun.html"))); + EXPECT_TRUE(IsOriginSecure(GURL("http://pumpkin.localhost:8080/fun.html"))); + EXPECT_TRUE( + IsOriginSecure(GURL("http://crumpet.pumpkin.localhost:3000/fun.html"))); EXPECT_FALSE(IsOriginSecure(GURL("http://localhost.com/fun.html"))); EXPECT_TRUE(IsOriginSecure(GURL("https://localhost.com/fun.html")));
diff --git a/content/content_browser.gypi b/content/content_browser.gypi index c3c9dcd..63fef96 100644 --- a/content/content_browser.gypi +++ b/content/content_browser.gypi
@@ -91,7 +91,6 @@ 'public/browser/browser_plugin_guest_manager.cc', 'public/browser/browser_plugin_guest_manager.h', 'public/browser/browser_ppapi_host.h', - 'public/browser/browser_shutdown.h', 'public/browser/browser_thread.h', 'public/browser/browser_thread_delegate.h', 'public/browser/browser_url_handler.h', @@ -974,6 +973,8 @@ 'browser/media/capture/animated_content_sampler.h', 'browser/media/capture/audio_mirroring_manager.cc', 'browser/media/capture/audio_mirroring_manager.h', + 'browser/media/capture/capture_resolution_chooser.cc', + 'browser/media/capture/capture_resolution_chooser.h', 'browser/media/capture/content_video_capture_device_core.cc', 'browser/media/capture/content_video_capture_device_core.h', 'browser/media/capture/feedback_signal_accumulator.cc',
diff --git a/content/content_renderer.gypi b/content/content_renderer.gypi index f6a9eee..52ce045 100644 --- a/content/content_renderer.gypi +++ b/content/content_renderer.gypi
@@ -561,11 +561,6 @@ 'renderer/pepper/url_request_info_util.h', 'renderer/pepper/url_response_info_util.cc', 'renderer/pepper/url_response_info_util.h', - 'renderer/pepper/usb_key_code_conversion.cc', - 'renderer/pepper/usb_key_code_conversion.h', - 'renderer/pepper/usb_key_code_conversion_linux.cc', - 'renderer/pepper/usb_key_code_conversion_mac.cc', - 'renderer/pepper/usb_key_code_conversion_win.cc', 'renderer/pepper/v8_var_converter.cc', 'renderer/pepper/v8_var_converter.h', 'renderer/pepper/v8object_var.cc',
diff --git a/content/content_shell.gypi b/content/content_shell.gypi index 65ca72b..08e1ca0 100644 --- a/content/content_shell.gypi +++ b/content/content_shell.gypi
@@ -1119,6 +1119,7 @@ ['OS=="win"', { 'targets': [ { + # GN version: //content/shell:crash_service 'target_name': 'content_shell_crash_service', 'type': 'executable', 'dependencies': [
diff --git a/content/content_tests.gypi b/content/content_tests.gypi index 61bdc91..82b1554a 100644 --- a/content/content_tests.gypi +++ b/content/content_tests.gypi
@@ -471,6 +471,7 @@ 'browser/media/audio_stream_monitor_unittest.cc', 'browser/media/capture/animated_content_sampler_unittest.cc', 'browser/media/capture/audio_mirroring_manager_unittest.cc', + 'browser/media/capture/capture_resolution_chooser_unittest.cc', 'browser/media/capture/feedback_signal_accumulator_unittest.cc', 'browser/media/capture/smooth_event_sampler_unittest.cc', 'browser/media/capture/video_capture_oracle_unittest.cc',
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeChildFrameTest.java b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeChildFrameTest.java index 2d494d0..40ea4ae 100644 --- a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeChildFrameTest.java +++ b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeChildFrameTest.java
@@ -13,6 +13,10 @@ import org.chromium.content_public.browser.NavigationController; import org.chromium.content_public.browser.WebContents; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + /** * Part of the test suite for the WebView's Java Bridge. * @@ -105,6 +109,63 @@ "queryProperties(window.frames[0])")); } + // Regression test for crbug.com/484927 -- make sure that existence of transient + // objects held by multiple RenderFrames doesn't cause an infinite loop when one + // of them gets removed. + @SmallTest + @Feature({"AndroidWebView", "Android-JavaBridge"}) + public void testRemovingTransientObjectHolders() throws Throwable { + class Test { + private Object mInner = new Object(); + // Expecting the inner object to be retrieved twice. + private CountDownLatch mLatch = new CountDownLatch(2); + @JavascriptInterface + public Object getInner() { + mLatch.countDown(); + return mInner; + } + public void waitForInjection() throws Throwable { + if (!mLatch.await(5, TimeUnit.SECONDS)) { + throw new TimeoutException(); + } + } + } + final Test testObject = new Test(); + + // Due to crbug.com/486262, Java objects are sometimes not injected + // into newly added frames. To work around this, we load the page first, so + // all the frames got created, then inject the object. + // Thus, the script code fails on the first execution (as no Java object is + // injected yet), but then works just fine after reload. + loadDataSync(getWebContents().getNavigationController(), + "<html>" + + "<head><script>window.inner_ref = test.getInner()</script></head>" + + "<body>" + + " <iframe id='frame' " + + " srcdoc='<script>window.inner_ref = test.getInner()</script>'>" + + " </iframe>" + + "</body></html>", "text/html", false); + injectObjectAndReload(testObject, "test"); + testObject.waitForInjection(); + // Just in case, check that the object wrappers are in place. + assertEquals("\"object\"", + executeJavaScriptAndGetResult(getWebContents(), "typeof inner_ref")); + assertEquals("\"object\"", + executeJavaScriptAndGetResult(getWebContents(), + "typeof window.frames[0].inner_ref")); + // Remove the iframe, this will trigger a removal of RenderFrame, which was causing + // the bug condition, as the transient object still has a holder -- the main window. + assertEquals("{}", + executeJavaScriptAndGetResult(getWebContents(), + "(function(){ " + + "var f = document.getElementById('frame');" + + "f.parentNode.removeChild(f); return f; })()")); + // Just in case, check that the remaining wrapper is still accessible. + assertEquals("\"object\"", + executeJavaScriptAndGetResult(getWebContents(), + "typeof inner_ref")); + } + private String executeJavaScriptAndGetResult(final WebContents webContents, final String script) throws Throwable { final String[] result = new String[1];
diff --git a/content/public/browser/browser_shutdown.h b/content/public/browser/browser_shutdown.h deleted file mode 100644 index 7581533..0000000 --- a/content/public/browser/browser_shutdown.h +++ /dev/null
@@ -1,30 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CONTENT_PUBLIC_BROWSER_BROWSER_SHUTDOWN_H_ -#define CONTENT_PUBLIC_BROWSER_BROWSER_SHUTDOWN_H_ - -#include "content/common/content_export.h" - -namespace content { - -// This can be used for as-fast-as-possible shutdown, in cases where -// time for shutdown is limited and we just need to write out as much -// data as possible before our time runs out. -// -// This causes the shutdown sequence embodied by -// BrowserMainParts::PostMainMessageLoopRun through -// BrowserMainParts::PostDestroyThreads to occur, i.e. we pretend the -// message loop finished, all threads are stopped in sequence and then -// PostDestroyThreads is called. -// -// As this violates the normal order of shutdown, likely leaving the -// process in a bad state, the last thing this function does is -// terminate the process (right after calling -// BrowserMainParts::PostDestroyThreads). -CONTENT_EXPORT void ImmediateShutdownAndExitProcess(); - -} // namespace content - -#endif // CONTENT_PUBLIC_BROWSER_BROWSER_SHUTDOWN_H_
diff --git a/content/public/browser/notification_types.h b/content/public/browser/notification_types.h index 08ffd33..a7043153 100644 --- a/content/public/browser/notification_types.h +++ b/content/public/browser/notification_types.h
@@ -112,13 +112,6 @@ // DEPRECATED: Use WebContentsObserver::RenderViewReady() NOTIFICATION_WEB_CONTENTS_CONNECTED, - // This notification is sent when a WebContents swaps its render view host - // with another one, possibly changing processes. The source is a - // Source<WebContents> with a pointer to the WebContents, details is a - // std::pair::<old RenderViewHost, new RenderViewHost>. - // DEPRECATED: Use WebContentsObserver::RenderViewHostChanged() - NOTIFICATION_RENDER_VIEW_HOST_CHANGED, - // This message is sent after a WebContents is disconnected from the // renderer process. The source is a Source<WebContents> with a pointer to // the WebContents (the pointer is usable). No details are expected.
diff --git a/content/public/common/context_menu_params.h b/content/public/common/context_menu_params.h index 9fe170a0..e45ad0a 100644 --- a/content/public/common/context_menu_params.h +++ b/content/public/common/context_menu_params.h
@@ -5,6 +5,7 @@ #ifndef CONTENT_PUBLIC_COMMON_CONTEXT_MENU_PARAMS_H_ #define CONTENT_PUBLIC_COMMON_CONTEXT_MENU_PARAMS_H_ +#include <map> #include <string> #include <vector> @@ -104,6 +105,10 @@ // This is the text of the selection that the context menu was invoked on. base::string16 selection_text; + // This is the title or alt (if title not available) text of the selection + // that the context menu was invoked on. + base::string16 title_text; + // This is the suggested filename to be used when saving file through "Save // Link As" option of context menu. base::string16 suggested_filename; @@ -151,6 +156,9 @@ ui::MenuSourceType source_type; + // Extra properties for the context menu. + std::map<std::string, std::string> properties; + #if defined(OS_ANDROID) // Points representing the coordinates in the document space of the start and // end of the selection, if there is one.
diff --git a/content/public/renderer/content_renderer_client.h b/content/public/renderer/content_renderer_client.h index 9e1e7d7..1d4a47e 100644 --- a/content/public/renderer/content_renderer_client.h +++ b/content/public/renderer/content_renderer_client.h
@@ -5,6 +5,7 @@ #ifndef CONTENT_PUBLIC_RENDERER_CONTENT_RENDERER_CLIENT_H_ #define CONTENT_PUBLIC_RENDERER_CONTENT_RENDERER_CLIENT_H_ +#include <map> #include <string> #include <vector> @@ -47,6 +48,7 @@ class WebSpeechSynthesizer; class WebSpeechSynthesizerClient; class WebThemeEngine; +class WebURLResponse; class WebURLRequest; class WebWorkerContentSettingsClientProxy; struct WebPluginParams; @@ -305,6 +307,12 @@ // Allows an embedder to provide a blink::WebAppBannerClient. virtual scoped_ptr<blink::WebAppBannerClient> CreateAppBannerClient( RenderFrame* render_frame); + + // Gives the embedder a chance to add properties to the context menu. + // Currently only called when the context menu is for an image. + virtual void AddImageContextMenuProperties( + const blink::WebURLResponse& response, + std::map<std::string, std::string>* properties) {} }; } // namespace content
diff --git a/content/public/test/browser_test_utils.cc b/content/public/test/browser_test_utils.cc index 4132af4..9513d0e 100644 --- a/content/public/test/browser_test_utils.cc +++ b/content/public/test/browser_test_utils.cc
@@ -43,6 +43,7 @@ #include "ui/base/resource/resource_bundle.h" #include "ui/compositor/test/draw_waiter_for_test.h" #include "ui/events/gesture_detection/gesture_configuration.h" +#include "ui/events/keycodes/dom/dom_code.h" #include "ui/events/keycodes/dom/keycode_converter.h" #include "ui/resources/grit/webui_resources.h" @@ -445,7 +446,8 @@ bool shift, bool alt, bool command) { - int native_key_code = ui::KeycodeConverter::CodeToNativeKeycode(code); + int native_key_code = ui::KeycodeConverter::DomCodeToNativeKeycode( + ui::KeycodeConverter::CodeStringToDomCode(code)); int modifiers = 0; @@ -453,96 +455,75 @@ // For our simulation we can use either the left keys or the right keys. if (control) { modifiers |= blink::WebInputEvent::ControlKey; - InjectRawKeyEvent(web_contents, - blink::WebInputEvent::RawKeyDown, - ui::VKEY_CONTROL, - ui::KeycodeConverter::CodeToNativeKeycode("ControlLeft"), - modifiers); + InjectRawKeyEvent( + web_contents, blink::WebInputEvent::RawKeyDown, ui::VKEY_CONTROL, + ui::KeycodeConverter::DomCodeToNativeKeycode(ui::DomCode::CONTROL_LEFT), + modifiers); } if (shift) { modifiers |= blink::WebInputEvent::ShiftKey; - InjectRawKeyEvent(web_contents, - blink::WebInputEvent::RawKeyDown, - ui::VKEY_SHIFT, - ui::KeycodeConverter::CodeToNativeKeycode("ShiftLeft"), - modifiers); + InjectRawKeyEvent( + web_contents, blink::WebInputEvent::RawKeyDown, ui::VKEY_SHIFT, + ui::KeycodeConverter::DomCodeToNativeKeycode(ui::DomCode::SHIFT_LEFT), + modifiers); } if (alt) { modifiers |= blink::WebInputEvent::AltKey; - InjectRawKeyEvent(web_contents, - blink::WebInputEvent::RawKeyDown, - ui::VKEY_MENU, - ui::KeycodeConverter::CodeToNativeKeycode("AltLeft"), - modifiers); + InjectRawKeyEvent( + web_contents, blink::WebInputEvent::RawKeyDown, ui::VKEY_MENU, + ui::KeycodeConverter::DomCodeToNativeKeycode(ui::DomCode::ALT_LEFT), + modifiers); } if (command) { modifiers |= blink::WebInputEvent::MetaKey; - InjectRawKeyEvent(web_contents, - blink::WebInputEvent::RawKeyDown, - ui::VKEY_COMMAND, - ui::KeycodeConverter::CodeToNativeKeycode("OSLeft"), - modifiers); + InjectRawKeyEvent( + web_contents, blink::WebInputEvent::RawKeyDown, ui::VKEY_COMMAND, + ui::KeycodeConverter::DomCodeToNativeKeycode(ui::DomCode::OS_LEFT), + modifiers); } + InjectRawKeyEvent(web_contents, blink::WebInputEvent::RawKeyDown, key_code, + native_key_code, modifiers); - InjectRawKeyEvent( - web_contents, - blink::WebInputEvent::RawKeyDown, - key_code, - native_key_code, - modifiers); + InjectRawKeyEvent(web_contents, blink::WebInputEvent::Char, key_code, + native_key_code, modifiers); - InjectRawKeyEvent( - web_contents, - blink::WebInputEvent::Char, - key_code, - native_key_code, - modifiers); - - InjectRawKeyEvent( - web_contents, - blink::WebInputEvent::KeyUp, - key_code, - native_key_code, - modifiers); + InjectRawKeyEvent(web_contents, blink::WebInputEvent::KeyUp, key_code, + native_key_code, modifiers); // The order of these key releases shouldn't matter for our simulation. if (control) { modifiers &= ~blink::WebInputEvent::ControlKey; - InjectRawKeyEvent(web_contents, - blink::WebInputEvent::KeyUp, - ui::VKEY_CONTROL, - ui::KeycodeConverter::CodeToNativeKeycode("ControlLeft"), - modifiers); + InjectRawKeyEvent( + web_contents, blink::WebInputEvent::KeyUp, ui::VKEY_CONTROL, + ui::KeycodeConverter::DomCodeToNativeKeycode(ui::DomCode::CONTROL_LEFT), + modifiers); } if (shift) { modifiers &= ~blink::WebInputEvent::ShiftKey; - InjectRawKeyEvent(web_contents, - blink::WebInputEvent::KeyUp, - ui::VKEY_SHIFT, - ui::KeycodeConverter::CodeToNativeKeycode("ShiftLeft"), - modifiers); + InjectRawKeyEvent( + web_contents, blink::WebInputEvent::KeyUp, ui::VKEY_SHIFT, + ui::KeycodeConverter::DomCodeToNativeKeycode(ui::DomCode::SHIFT_LEFT), + modifiers); } if (alt) { modifiers &= ~blink::WebInputEvent::AltKey; - InjectRawKeyEvent(web_contents, - blink::WebInputEvent::KeyUp, - ui::VKEY_MENU, - ui::KeycodeConverter::CodeToNativeKeycode("AltLeft"), - modifiers); + InjectRawKeyEvent( + web_contents, blink::WebInputEvent::KeyUp, ui::VKEY_MENU, + ui::KeycodeConverter::DomCodeToNativeKeycode(ui::DomCode::ALT_LEFT), + modifiers); } if (command) { modifiers &= ~blink::WebInputEvent::MetaKey; - InjectRawKeyEvent(web_contents, - blink::WebInputEvent::KeyUp, - ui::VKEY_COMMAND, - ui::KeycodeConverter::CodeToNativeKeycode("OSLeft"), - modifiers); + InjectRawKeyEvent( + web_contents, blink::WebInputEvent::KeyUp, ui::VKEY_COMMAND, + ui::KeycodeConverter::DomCodeToNativeKeycode(ui::DomCode::OS_LEFT), + modifiers); } ASSERT_EQ(modifiers, 0);
diff --git a/content/renderer/context_menu_params_builder.cc b/content/renderer/context_menu_params_builder.cc index 63dcd4d..1e4df2e 100644 --- a/content/renderer/context_menu_params_builder.cc +++ b/content/renderer/context_menu_params_builder.cc
@@ -7,6 +7,7 @@ #include "base/logging.h" #include "content/common/ssl_status_serialization.h" #include "content/public/common/context_menu_params.h" +#include "content/public/renderer/content_renderer_client.h" #include "content/renderer/dom_utils.h" #include "content/renderer/history_serialization.h" #include "content/renderer/menu_item_builder.h" @@ -31,6 +32,7 @@ params.frame_url = data.frameURL; params.media_flags = data.mediaFlags; params.selection_text = data.selectedText; + params.title_text = data.titleText; params.misspelled_word = data.misspelledWord; params.misspelling_hash = data.misspellingHash; params.spellcheck_enabled = data.isSpellCheckingEnabled; @@ -43,6 +45,11 @@ params.referrer_policy = data.referrerPolicy; params.suggested_filename = data.suggestedFilename; + if (!data.imageResponse.isNull()) { + GetContentClient()->renderer()->AddImageContextMenuProperties( + data.imageResponse, ¶ms.properties); + } + for (size_t i = 0; i < data.dictionarySuggestions.size(); ++i) params.dictionary_suggestions.push_back(data.dictionarySuggestions[i]); @@ -59,7 +66,7 @@ blink::WebNode selectedNode = DomUtils::ExtractParentAnchorNode(data.node); blink::WebElement selectedElement = selectedNode.to<blink::WebElement>(); if (!selectedElement.isNull() && selectedNode.isLink()) { - params.link_text = selectedElement.innerText(); + params.link_text = selectedElement.textContent(); } else { LOG(ERROR) << "Creating a ContextMenuParams for a node that has a link" << "url but is not an ElementNode or does not have an"
diff --git a/content/renderer/dom_serializer_browsertest.cc b/content/renderer/dom_serializer_browsertest.cc index b1759421..2cb395c 100644 --- a/content/renderer/dom_serializer_browsertest.cc +++ b/content/renderer/dom_serializer_browsertest.cc
@@ -582,8 +582,9 @@ '%', 0x2285, 0x00b9, '\'', 0 }; WebString value = body_element.getAttribute("title"); + WebString content = doc.contentAsTextForTesting(); ASSERT_TRUE(base::UTF16ToWide(value) == parsed_value); - ASSERT_TRUE(base::UTF16ToWide(body_element.innerText()) == parsed_value); + ASSERT_TRUE(base::UTF16ToWide(content) == parsed_value); // Do serialization. SerializeDomForURL(file_url, false);
diff --git a/content/renderer/gpu/frame_swap_message_queue.cc b/content/renderer/gpu/frame_swap_message_queue.cc index 5a31382..84fcdd4e 100644 --- a/content/renderer/gpu/frame_swap_message_queue.cc +++ b/content/renderer/gpu/frame_swap_message_queue.cc
@@ -146,13 +146,17 @@ GetSubQueue(policy)->QueueMessage(source_frame_number, msg.Pass(), is_first); } -void FrameSwapMessageQueue::DidSwap(int source_frame_number) { +void FrameSwapMessageQueue::DidActivate(int source_frame_number) { base::AutoLock lock(lock_); - visual_state_queue_->DrainMessages(source_frame_number, &next_drain_messages_); } +void FrameSwapMessageQueue::DidSwap(int source_frame_number) { + base::AutoLock lock(lock_); + swap_queue_->DrainMessages(0, &next_drain_messages_); +} + void FrameSwapMessageQueue::DidNotSwap(int source_frame_number, cc::SwapPromise::DidNotSwapReason reason, ScopedVector<IPC::Message>* messages) { @@ -164,21 +168,18 @@ visual_state_queue_->DrainMessages(source_frame_number, messages); break; case cc::SwapPromise::COMMIT_FAILS: - // Do not queue any responses here. - // If COMMIT_FAILS the renderer is shutting down, which will - // result in the RenderFrameHostImpl destructor firing the - // remaining response callbacks itself. + case cc::SwapPromise::ACTIVATION_FAILS: + // Do not queue any responses here. If ACTIVATION_FAILS or + // COMMIT_FAILS the renderer is shutting down, which will result + // in the RenderFrameHostImpl destructor firing the remaining + // response callbacks itself. break; - default: - NOTREACHED(); } } void FrameSwapMessageQueue::DrainMessages( ScopedVector<IPC::Message>* messages) { lock_.AssertAcquired(); - - swap_queue_->DrainMessages(0, messages); messages->insert(messages->end(), next_drain_messages_.begin(), next_drain_messages_.end());
diff --git a/content/renderer/gpu/frame_swap_message_queue.h b/content/renderer/gpu/frame_swap_message_queue.h index 51eb229e..b12b417 100644 --- a/content/renderer/gpu/frame_swap_message_queue.h +++ b/content/renderer/gpu/frame_swap_message_queue.h
@@ -52,14 +52,19 @@ // Returns true if there are no messages in the queue. bool Empty() const; - // Should be called when a successful swap occurs. The messages for that swap - // can be obtained by calling DrainMessages. + // Should be called when a successful activation occurs. The messages for + // that activation can be obtained by calling DrainMessages. + // + // |source_frame_number| frame number for which the activate occurred. + void DidActivate(int source_frame_number); + + // Should be called when a successful swap occurs. The messages for that + // swap can be obtained by calling DrainMessages. // // |source_frame_number| frame number for which the swap occurred. void DidSwap(int source_frame_number); - // Should be called when we know a swap will not occur. This also means we - // won't be expecting a DrainMessages call. + // Should be called when we know a swap will not occur. // // |source_frame_number| frame number for which the swap will not occur. // |reason| reason for the which the swap will not occur.
diff --git a/content/renderer/gpu/frame_swap_message_queue_unittest.cc b/content/renderer/gpu/frame_swap_message_queue_unittest.cc index dc802c0..8040598 100644 --- a/content/renderer/gpu/frame_swap_message_queue_unittest.cc +++ b/content/renderer/gpu/frame_swap_message_queue_unittest.cc
@@ -47,6 +47,7 @@ void DrainMessages(int source_frame_number, ScopedVector<IPC::Message>* messages) { messages->clear(); + queue_->DidActivate(source_frame_number); queue_->DidSwap(source_frame_number); scoped_ptr<FrameSwapMessageQueue::SendMessageScope> send_message_scope = queue_->AcquireSendMessageScope(); @@ -92,6 +93,7 @@ ASSERT_TRUE(queue_->Empty()); QueueVisualStateMessage(1, CloneMessage(first_message_)); ASSERT_FALSE(queue_->Empty()); + queue_->DidActivate(1); queue_->DidSwap(1); ASSERT_FALSE(queue_->Empty()); } @@ -208,17 +210,31 @@ QueueNextSwapMessage(CloneMessage(first_message_)); QueueVisualStateMessage(2, CloneMessage(second_message_)); QueueVisualStateMessage(3, CloneMessage(third_message_)); + const int rid[] = {first_message_.routing_id(), + second_message_.routing_id(), + third_message_.routing_id()}; - queue_->DidNotSwap(2, cc::SwapPromise::COMMIT_NO_UPDATE, &messages); - ASSERT_EQ(2u, messages.size()); - ASSERT_TRUE(HasMessageForId(messages, first_message_.routing_id())); - ASSERT_TRUE(HasMessageForId(messages, second_message_.routing_id())); + bool msg_delivered = reason != cc::SwapPromise::COMMIT_FAILS && + reason != cc::SwapPromise::ACTIVATION_FAILS; + + queue_->DidNotSwap(2, reason, &messages); + ASSERT_TRUE(msg_delivered == HasMessageForId(messages, rid[0])); + ASSERT_TRUE(msg_delivered == HasMessageForId(messages, rid[1])); + ASSERT_FALSE(HasMessageForId(messages, rid[2])); messages.clear(); - queue_->DidNotSwap(3, cc::SwapPromise::COMMIT_NO_UPDATE, &messages); - ASSERT_EQ(1u, messages.size()); - ASSERT_TRUE(HasMessageForId(messages, third_message_.routing_id())); + queue_->DidNotSwap(3, reason, &messages); + ASSERT_FALSE(HasMessageForId(messages, rid[0])); + ASSERT_FALSE(HasMessageForId(messages, rid[1])); + ASSERT_TRUE(msg_delivered == HasMessageForId(messages, rid[2])); messages.clear(); + + // all undelivered messages should still be available for RenderFrameHostImpl + // to deliver. + DrainMessages(3, &messages); + ASSERT_TRUE(msg_delivered != HasMessageForId(messages, rid[0])); + ASSERT_TRUE(msg_delivered != HasMessageForId(messages, rid[1])); + ASSERT_TRUE(msg_delivered != HasMessageForId(messages, rid[2])); } TEST_F(FrameSwapMessageQueueTest, TestDidNotSwapNoUpdate) { @@ -230,23 +246,11 @@ } TEST_F(FrameSwapMessageQueueTest, TestDidNotSwapCommitFails) { - ScopedVector<IPC::Message> messages; + TestDidNotSwap(cc::SwapPromise::COMMIT_FAILS); +} - QueueNextSwapMessage(CloneMessage(first_message_)); - QueueVisualStateMessage(2, CloneMessage(second_message_)); - QueueVisualStateMessage(3, CloneMessage(third_message_)); - - queue_->DidNotSwap(2, cc::SwapPromise::COMMIT_FAILS, &messages); - ASSERT_EQ(0u, messages.size()); - messages.clear(); - - queue_->DidNotSwap(3, cc::SwapPromise::COMMIT_FAILS, &messages); - ASSERT_EQ(0u, messages.size()); - messages.clear(); - - DrainMessages(1, &messages); - ASSERT_EQ(1u, messages.size()); - ASSERT_TRUE(HasMessageForId(messages, first_message_.routing_id())); +TEST_F(FrameSwapMessageQueueTest, TestDidNotSwapActivationFails) { + TestDidNotSwap(cc::SwapPromise::ACTIVATION_FAILS); } class NotifiesDeletionMessage : public IPC::Message { @@ -281,6 +285,7 @@ QueueVisualStateMessage(1, make_scoped_ptr(new NotifiesDeletionMessage( &message_deleted, first_message_))); + queue_->DidActivate(1); queue_->DidSwap(1); queue_ = NULL; ASSERT_TRUE(message_deleted);
diff --git a/content/renderer/gpu/queue_message_swap_promise.cc b/content/renderer/gpu/queue_message_swap_promise.cc index c8abf899..ff524418 100644 --- a/content/renderer/gpu/queue_message_swap_promise.cc +++ b/content/renderer/gpu/queue_message_swap_promise.cc
@@ -32,6 +32,14 @@ #endif } +void QueueMessageSwapPromise::DidActivate() { +#if DCHECK_IS_ON() + DCHECK(!completed_); +#endif + message_queue_->DidActivate(source_frame_number_); + // The OutputSurface will take care of the Drain+Send. +} + void QueueMessageSwapPromise::DidSwap(cc::CompositorFrameMetadata* metadata) { #if DCHECK_IS_ON() DCHECK(!completed_);
diff --git a/content/renderer/gpu/queue_message_swap_promise.h b/content/renderer/gpu/queue_message_swap_promise.h index e0fcf8c..37198b2 100644 --- a/content/renderer/gpu/queue_message_swap_promise.h +++ b/content/renderer/gpu/queue_message_swap_promise.h
@@ -6,7 +6,6 @@ #define CONTENT_RENDERER_GPU_QUEUE_MESSAGE_SWAP_PROMISE_H_ #include "base/memory/ref_counted.h" -#include "base/memory/scoped_ptr.h" #include "cc/output/swap_promise.h" namespace IPC { @@ -25,8 +24,8 @@ ~QueueMessageSwapPromise() override; + void DidActivate() override; void DidSwap(cc::CompositorFrameMetadata* metadata) override; - void DidNotSwap(DidNotSwapReason reason) override; int64 TraceId() const override;
diff --git a/content/renderer/gpu/queue_message_swap_promise_unittest.cc b/content/renderer/gpu/queue_message_swap_promise_unittest.cc index ab640bf..1261cb2 100644 --- a/content/renderer/gpu/queue_message_swap_promise_unittest.cc +++ b/content/renderer/gpu/queue_message_swap_promise_unittest.cc
@@ -115,8 +115,10 @@ for (ScopedVector<cc::SwapPromise>::iterator i = promises_.begin(); i != promises_.end(); ++i) { - if (*i) + if (*i) { + (*i)->DidActivate(); (*i)->DidSwap(NULL); + } } } @@ -144,11 +146,13 @@ QueueMessages(data, arraysize(data)); ASSERT_TRUE(promises_[0]); + promises_[0]->DidActivate(); + promises_[0]->DidSwap(NULL); + EXPECT_TRUE(DirectSendMessages().empty()); EXPECT_FALSE(frame_swap_message_queue_->Empty()); + // frame_swap_message_queue_->DidSwap(1); EXPECT_TRUE(NextSwapHasMessage(messages_[0])); - - CleanupPromises(); } TEST_F(QueueMessageSwapPromiseTest, NextSwapPolicyNeedsAtMostOnePromise) { @@ -201,6 +205,7 @@ promises_[0]->DidNotSwap(cc::SwapPromise::COMMIT_FAILS); EXPECT_TRUE(DirectSendMessages().empty()); EXPECT_FALSE(frame_swap_message_queue_->Empty()); + frame_swap_message_queue_->DidSwap(2); EXPECT_TRUE(NextSwapHasMessage(messages_[0])); } @@ -236,7 +241,7 @@ CleanupPromises(); } -TEST_F(QueueMessageSwapPromiseTest, VisualStateSwapPromiseDidSwap) { +TEST_F(QueueMessageSwapPromiseTest, VisualStateSwapPromiseDidActivate) { QueueMessageData data[] = { /* { policy, source_frame_number } */ {MESSAGE_DELIVERY_POLICY_WITH_VISUAL_STATE, 1}, @@ -245,6 +250,7 @@ }; QueueMessages(data, arraysize(data)); + promises_[0]->DidActivate(); promises_[0]->DidSwap(NULL); ASSERT_FALSE(promises_[1]); ScopedVector<IPC::Message> messages; @@ -254,7 +260,8 @@ EXPECT_TRUE(ContainsMessage(messages, messages_[1])); EXPECT_FALSE(ContainsMessage(messages, messages_[2])); - promises_[2]->DidSwap(NULL); + promises_[2]->DidActivate(); + promises_[2]->DidNotSwap(cc::SwapPromise::SWAP_FAILS); messages.swap(NextSwapMessages()); EXPECT_EQ(1u, messages.size()); EXPECT_TRUE(ContainsMessage(messages, messages_[2])); @@ -274,59 +281,43 @@ }; QueueMessages(data, arraysize(data)); + // If we fail to swap with COMMIT_FAILS or ACTIVATE_FAILS, then + // messages are delivered by the RenderFrameHostImpl destructor, + // rather than directly by the swap promise. + bool msg_delivered = reason != cc::SwapPromise::COMMIT_FAILS && + reason != cc::SwapPromise::ACTIVATION_FAILS; + promises_[0]->DidNotSwap(reason); ASSERT_FALSE(promises_[1]); EXPECT_TRUE(NextSwapMessages().empty()); - EXPECT_EQ(2u, DirectSendMessages().size()); - EXPECT_TRUE(ContainsMessage(DirectSendMessages(), messages_[0])); - EXPECT_TRUE(ContainsMessage(DirectSendMessages(), messages_[1])); + EXPECT_EQ(msg_delivered, ContainsMessage(DirectSendMessages(), messages_[0])); + EXPECT_EQ(msg_delivered, ContainsMessage(DirectSendMessages(), messages_[1])); EXPECT_FALSE(ContainsMessage(DirectSendMessages(), messages_[2])); promises_[2]->DidNotSwap(reason); EXPECT_TRUE(NextSwapMessages().empty()); - EXPECT_TRUE(ContainsMessage(DirectSendMessages(), messages_[2])); + EXPECT_EQ(msg_delivered, ContainsMessage(DirectSendMessages(), messages_[2])); EXPECT_TRUE(NextSwapMessages().empty()); - EXPECT_TRUE(frame_swap_message_queue_->Empty()); + EXPECT_EQ(msg_delivered, frame_swap_message_queue_->Empty()); } -TEST_F(QueueMessageSwapPromiseTest, VisalStateSwapPromiseDidNotSwapNoUpdate) { +TEST_F(QueueMessageSwapPromiseTest, VisualStateSwapPromiseDidNotSwapNoUpdate) { VisualStateSwapPromiseDidNotSwap(cc::SwapPromise::COMMIT_NO_UPDATE); } TEST_F(QueueMessageSwapPromiseTest, VisualStateSwapPromiseDidNotSwapCommitFails) { - // COMMIT_FAILS is treated differently: - // If we fail to swap with COMMIT_FAILS, then the renderer is - // shutting down, which implies that the RenderFrameHostImpl - // destructor will eventually be called, firing the remaining - // response callbacks (with swap_success = false) itself. - QueueMessageData data[] = { - /* { policy, source_frame_number } */ - {MESSAGE_DELIVERY_POLICY_WITH_VISUAL_STATE, 1}, - {MESSAGE_DELIVERY_POLICY_WITH_VISUAL_STATE, 1}, - {MESSAGE_DELIVERY_POLICY_WITH_VISUAL_STATE, 2}, - }; - QueueMessages(data, arraysize(data)); - - promises_[0]->DidNotSwap(cc::SwapPromise::COMMIT_FAILS); - ASSERT_FALSE(promises_[1]); - EXPECT_TRUE(NextSwapMessages().empty()); - EXPECT_EQ(0u, DirectSendMessages().size()); - EXPECT_FALSE(ContainsMessage(DirectSendMessages(), messages_[0])); - EXPECT_FALSE(ContainsMessage(DirectSendMessages(), messages_[1])); - EXPECT_FALSE(ContainsMessage(DirectSendMessages(), messages_[2])); - - promises_[2]->DidNotSwap(cc::SwapPromise::COMMIT_FAILS); - EXPECT_TRUE(NextSwapMessages().empty()); - EXPECT_FALSE(ContainsMessage(DirectSendMessages(), messages_[2])); - - EXPECT_TRUE(NextSwapMessages().empty()); - EXPECT_FALSE(frame_swap_message_queue_->Empty()); + VisualStateSwapPromiseDidNotSwap(cc::SwapPromise::COMMIT_FAILS); } -TEST_F(QueueMessageSwapPromiseTest, VisalStateSwapPromiseDidNotSwapSwapFails) { +TEST_F(QueueMessageSwapPromiseTest, VisualStateSwapPromiseDidNotSwapSwapFails) { VisualStateSwapPromiseDidNotSwap(cc::SwapPromise::SWAP_FAILS); } +TEST_F(QueueMessageSwapPromiseTest, + VisualStateSwapPromiseDidNotSwapActivationFails) { + VisualStateSwapPromiseDidNotSwap(cc::SwapPromise::ACTIVATION_FAILS); +} + } // namespace content
diff --git a/content/renderer/media/crypto/ppapi_decryptor.cc b/content/renderer/media/crypto/ppapi_decryptor.cc index 81abba65..b828de5 100644 --- a/content/renderer/media/crypto/ppapi_decryptor.cc +++ b/content/renderer/media/crypto/ppapi_decryptor.cc
@@ -44,6 +44,7 @@ base::MessageLoopProxy::current()->PostTask( FROM_HERE, base::Bind(cdm_created_cb, nullptr, "Plugin instance creation failed.")); + return; } scoped_ptr<PpapiDecryptor> ppapi_decryptor(
diff --git a/content/renderer/media/webrtc_audio_capturer.cc b/content/renderer/media/webrtc_audio_capturer.cc index c59695a..df46265 100644 --- a/content/renderer/media/webrtc_audio_capturer.cc +++ b/content/renderer/media/webrtc_audio_capturer.cc
@@ -14,6 +14,7 @@ #include "content/renderer/media/media_stream_audio_processor.h" #include "content/renderer/media/media_stream_audio_processor_options.h" #include "content/renderer/media/media_stream_audio_source.h" +#include "content/renderer/media/media_stream_constraints_util.h" #include "content/renderer/media/webrtc_audio_device_impl.h" #include "content/renderer/media/webrtc_local_audio_track.h" #include "content/renderer/media/webrtc_logging.h" @@ -23,6 +24,11 @@ namespace { +// Audio buffer sizes are specified in milliseconds. +const char kAudioLatency[] = "latencyMs"; +const int kMinAudioLatencyMs = 0; +const int kMaxAudioLatencyMs = 10000; + // Method to check if any of the data in |audio_source| has energy. bool HasDataEnergy(const media::AudioBus& audio_source) { for (int ch = 0; ch < audio_source.channels(); ++ch) { @@ -89,7 +95,7 @@ // Wrapper which allows to use std::find_if() when adding and removing // sinks to/from the list. struct TrackWrapper { - TrackWrapper(WebRtcLocalAudioTrack* track) : track_(track) {} + explicit TrackWrapper(WebRtcLocalAudioTrack* track) : track_(track) {} bool operator()( const scoped_refptr<WebRtcAudioCapturer::TrackOwner>& owner) const { return owner->IsEqual(track_); @@ -199,10 +205,27 @@ device_info_.device.input.sample_rate); } + // Initialize the buffer size to zero, which means it wasn't specified. + // If it is out of range, we return it to zero. + int buffer_size_ms = 0; + int buffer_size_samples = 0; + GetConstraintValueAsInteger(constraints_, kAudioLatency, &buffer_size_ms); + if (buffer_size_ms < kMinAudioLatencyMs || + buffer_size_ms > kMaxAudioLatencyMs) { + DVLOG(1) << "Ignoring out of range buffer size " << buffer_size_ms; + } else { + buffer_size_samples = + device_info_.device.input.sample_rate * buffer_size_ms / 1000; + } + DVLOG_IF(1, buffer_size_samples > 0) + << "Custom audio buffer size: " << buffer_size_samples << " samples"; + // Create and configure the default audio capturing source. SetCapturerSourceInternal( - AudioDeviceFactory::NewInputDevice(render_frame_id_), channel_layout, - static_cast<float>(device_info_.device.input.sample_rate)); + AudioDeviceFactory::NewInputDevice(render_frame_id_), + channel_layout, + device_info_.device.input.sample_rate, + buffer_size_samples); // Add the capturer to the WebRtcAudioDeviceImpl since it needs some hardware // information from the capturer. @@ -287,7 +310,8 @@ void WebRtcAudioCapturer::SetCapturerSourceInternal( const scoped_refptr<media::AudioCapturerSource>& source, media::ChannelLayout channel_layout, - float sample_rate) { + int sample_rate, + int buffer_size) { DCHECK(thread_checker_.CalledOnValidThread()); DVLOG(1) << "SetCapturerSource(channel_layout=" << channel_layout << "," << "sample_rate=" << sample_rate << ")"; @@ -308,15 +332,21 @@ if (old_source.get()) old_source->Stop(); + // If the buffer size is zero, it has not been specified. + // We either default to 10ms, or use the hardware buffer size. + if (buffer_size == 0) + buffer_size = GetBufferSize(sample_rate); + // Dispatch the new parameters both to the sink(s) and to the new source, // also apply the new |constraints|. // The idea is to get rid of any dependency of the microphone parameters // which would normally be used by default. // bits_per_sample is always 16 for now. - int buffer_size = GetBufferSize(sample_rate); media::AudioParameters params(media::AudioParameters::AUDIO_PCM_LOW_LATENCY, - channel_layout, sample_rate, - 16, buffer_size, + channel_layout, + sample_rate, + 16, + buffer_size, device_info_.device.input.effects); { @@ -365,7 +395,8 @@ // WebRtc native buffer size. SetCapturerSourceInternal(AudioDeviceFactory::NewInputDevice(render_frame_id), input_params.channel_layout(), - static_cast<float>(input_params.sample_rate())); + input_params.sample_rate(), + 0); } void WebRtcAudioCapturer::Start() { @@ -588,8 +619,10 @@ const scoped_refptr<media::AudioCapturerSource>& source, media::AudioParameters params) { // Create a new audio stream as source which uses the new source. - SetCapturerSourceInternal(source, params.channel_layout(), - static_cast<float>(params.sample_rate())); + SetCapturerSourceInternal(source, + params.channel_layout(), + params.sample_rate(), + 0); } } // namespace content
diff --git a/content/renderer/media/webrtc_audio_capturer.h b/content/renderer/media/webrtc_audio_capturer.h index ca10ff2a..f1ada132 100644 --- a/content/renderer/media/webrtc_audio_capturer.h +++ b/content/renderer/media/webrtc_audio_capturer.h
@@ -139,10 +139,12 @@ // desires to provide their own captured audio data. Client is responsible // for calling Start() on its own source to get the ball rolling. // Called on the main render thread. + // buffer_size is optional. Set to 0 to let it be chosen automatically. void SetCapturerSourceInternal( const scoped_refptr<media::AudioCapturerSource>& source, media::ChannelLayout channel_layout, - float sample_rate); + int sample_rate, + int buffer_size); // Starts recording audio. // Triggered by AddSink() on the main render thread or a Libjingle working
diff --git a/content/renderer/pepper/event_conversion.cc b/content/renderer/pepper/event_conversion.cc index 164e33e..becef7b 100644 --- a/content/renderer/pepper/event_conversion.cc +++ b/content/renderer/pepper/event_conversion.cc
@@ -13,13 +13,13 @@ #include "base/strings/utf_string_conversion_utils.h" #include "base/strings/utf_string_conversions.h" #include "content/common/input/web_touch_event_traits.h" -#include "content/renderer/pepper/usb_key_code_conversion.h" #include "ppapi/c/pp_input_event.h" #include "ppapi/shared_impl/ppb_input_event_shared.h" #include "ppapi/shared_impl/time_conversion.h" #include "third_party/WebKit/public/platform/WebGamepads.h" #include "third_party/WebKit/public/platform/WebString.h" #include "third_party/WebKit/public/web/WebInputEvent.h" +#include "ui/events/keycodes/dom/keycode_converter.h" using ppapi::EventTimeToPPTimeTicks; using ppapi::InputEventData; @@ -135,7 +135,8 @@ InputEventData result = GetEventWithCommonFieldsAndType(event); result.event_modifiers = key_event.modifiers; result.key_code = key_event.windowsKeyCode; - result.code = CodeForKeyboardEvent(key_event); + result.code = ui::KeycodeConverter::DomCodeToCodeString( + static_cast<ui::DomCode>(key_event.domCode)); result_events->push_back(result); }
diff --git a/content/renderer/pepper/usb_key_code_conversion.cc b/content/renderer/pepper/usb_key_code_conversion.cc deleted file mode 100644 index 129e663..0000000 --- a/content/renderer/pepper/usb_key_code_conversion.cc +++ /dev/null
@@ -1,25 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "content/renderer/pepper/usb_key_code_conversion.h" - -#include "build/build_config.h" - -using blink::WebKeyboardEvent; - -namespace content { - -#if !defined(OS_LINUX) && !defined(OS_MACOSX) && !defined(OS_WIN) - -uint32_t UsbKeyCodeForKeyboardEvent(const WebKeyboardEvent& key_event) { - return 0; -} - -const char* CodeForKeyboardEvent(const WebKeyboardEvent& key_event) { - return NULL; -} - -#endif - -} // namespace content
diff --git a/content/renderer/pepper/usb_key_code_conversion.h b/content/renderer/pepper/usb_key_code_conversion.h deleted file mode 100644 index 9554c572..0000000 --- a/content/renderer/pepper/usb_key_code_conversion.h +++ /dev/null
@@ -1,29 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CONTENT_RENDERER_PEPPER_USB_KEY_CODE_CONVERSION_H_ -#define CONTENT_RENDERER_PEPPER_USB_KEY_CODE_CONVERSION_H_ - -#include "ppapi/c/pp_stdint.h" - -namespace blink { -class WebKeyboardEvent; -} // namespace blink - -namespace content { - -// Returns a 32-bit "USB Key Code" for the key identifier by the supplied -// WebKeyboardEvent. The supplied event must be a KeyDown or KeyUp. -// The code consists of the USB Page (in the high-order 16-bit word) and -// USB Usage Id of the key. If no translation can be performed then zero -// is returned. -uint32_t UsbKeyCodeForKeyboardEvent(const blink::WebKeyboardEvent& key_event); - -// Returns a string that represents the UI Event |code| parameter as specified -// in http://www.w3.org/TR/uievents/ -const char* CodeForKeyboardEvent(const blink::WebKeyboardEvent& key_event); - -} // namespace content - -#endif // CONTENT_RENDERER_PEPPER_USB_KEY_CODE_CONVERSION_H_
diff --git a/content/renderer/pepper/usb_key_code_conversion_linux.cc b/content/renderer/pepper/usb_key_code_conversion_linux.cc index 26452b40..9164e7bf 100644 --- a/content/renderer/pepper/usb_key_code_conversion_linux.cc +++ b/content/renderer/pepper/usb_key_code_conversion_linux.cc
@@ -22,7 +22,8 @@ } const char* CodeForKeyboardEvent(const WebKeyboardEvent& key_event) { - return ui::KeycodeConverter::NativeKeycodeToCode(key_event.nativeKeyCode); + return ui::KeycodeConverter::DomCodeToCodeString( + ui::KeycodeConverter::NativeKeycodeToDomCode(key_event.nativeKeyCode)); } } // namespace content
diff --git a/content/renderer/pepper/usb_key_code_conversion_mac.cc b/content/renderer/pepper/usb_key_code_conversion_mac.cc index 6448f7c..15e16da1 100644 --- a/content/renderer/pepper/usb_key_code_conversion_mac.cc +++ b/content/renderer/pepper/usb_key_code_conversion_mac.cc
@@ -18,7 +18,8 @@ } const char* CodeForKeyboardEvent(const WebKeyboardEvent& key_event) { - return ui::KeycodeConverter::NativeKeycodeToCode(key_event.nativeKeyCode); + return ui::KeycodeConverter::DomCodeToCodeString( + ui::KeycodeConverter::NativeKeycodeToDomCode(key_event.nativeKeyCode)); } } // namespace content
diff --git a/content/renderer/pepper/usb_key_code_conversion_win.cc b/content/renderer/pepper/usb_key_code_conversion_win.cc index d270ff0..637a583 100644 --- a/content/renderer/pepper/usb_key_code_conversion_win.cc +++ b/content/renderer/pepper/usb_key_code_conversion_win.cc
@@ -27,7 +27,8 @@ if ((key_event.nativeKeyCode & (1 << 24)) != 0) scancode |= 0xe000; - return ui::KeycodeConverter::NativeKeycodeToCode(scancode); + return ui::KeycodeConverter::DomCodeToCodeString( + ui::KeycodeConverter::NativeKeycodeToDomCode(scancode)); } } // namespace content
diff --git a/content/renderer/renderer_blink_platform_impl.cc b/content/renderer/renderer_blink_platform_impl.cc index 0e9864fd..4e3895d 100644 --- a/content/renderer/renderer_blink_platform_impl.cc +++ b/content/renderer/renderer_blink_platform_impl.cc
@@ -14,6 +14,7 @@ #include "base/numerics/safe_conversions.h" #include "base/strings/string_number_conversions.h" #include "base/strings/utf_string_conversions.h" +#include "build/build_config.h" #include "cc/blink/context_provider_web_context.h" #include "components/scheduler/child/web_scheduler_impl.h" #include "components/scheduler/renderer/renderer_scheduler.h" @@ -63,9 +64,9 @@ #include "media/audio/audio_output_device.h" #include "media/base/audio_hardware_config.h" #include "media/base/key_systems.h" +#include "media/base/mime_util.h" #include "media/blink/webcontentdecryptionmodule_impl.h" #include "media/filters/stream_parser_factory.h" -#include "net/base/mime_util.h" #include "net/base/net_util.h" #include "storage/common/database/database_identifier.h" #include "storage/common/quota/quota_types.h" @@ -412,7 +413,7 @@ const WebString& key_system) { const std::string mime_type_ascii = ToASCIIOrEmpty(mime_type); // Not supporting the container is a flat-out no. - if (!net::IsSupportedMediaMimeType(mime_type_ascii)) + if (!media::IsSupportedMediaMimeType(mime_type_ascii)) return IsNotSupported; if (!key_system.isEmpty()) { @@ -425,7 +426,7 @@ std::string key_system_ascii = media::GetUnprefixedKeySystemName(base::UTF16ToASCII(key_system)); std::vector<std::string> strict_codecs; - net::ParseCodecString(ToASCIIOrEmpty(codecs), &strict_codecs, true); + media::ParseCodecString(ToASCIIOrEmpty(codecs), &strict_codecs, true); if (!media::PrefixedIsSupportedKeySystemWithMediaMimeType( mime_type_ascii, strict_codecs, key_system_ascii)) { @@ -436,18 +437,18 @@ } // Check list of strict codecs to see if it is supported. - if (net::IsStrictMediaMimeType(mime_type_ascii)) { + if (media::IsStrictMediaMimeType(mime_type_ascii)) { // Check if the codecs are a perfect match. std::vector<std::string> strict_codecs; - net::ParseCodecString(ToASCIIOrEmpty(codecs), &strict_codecs, false); + media::ParseCodecString(ToASCIIOrEmpty(codecs), &strict_codecs, false); return static_cast<WebMimeRegistry::SupportsType> ( - net::IsSupportedStrictMediaMimeType(mime_type_ascii, strict_codecs)); + media::IsSupportedStrictMediaMimeType(mime_type_ascii, strict_codecs)); } // If we don't recognize the codec, it's possible we support it. std::vector<std::string> parsed_codecs; - net::ParseCodecString(ToASCIIOrEmpty(codecs), &parsed_codecs, true); - if (!net::AreSupportedMediaCodecs(parsed_codecs)) + media::ParseCodecString(ToASCIIOrEmpty(codecs), &parsed_codecs, true); + if (!media::AreSupportedMediaCodecs(parsed_codecs)) return MayBeSupported; // Otherwise we have a perfect match. @@ -459,7 +460,7 @@ const WebString& codecs) { const std::string mime_type_ascii = ToASCIIOrEmpty(mime_type); std::vector<std::string> parsed_codec_ids; - net::ParseCodecString(ToASCIIOrEmpty(codecs), &parsed_codec_ids, false); + media::ParseCodecString(ToASCIIOrEmpty(codecs), &parsed_codec_ids, false); if (mime_type_ascii.empty()) return false; return media::StreamParserFactory::IsTypeSupported(
diff --git a/content/renderer/stats_collection_controller.cc b/content/renderer/stats_collection_controller.cc index 6f42a02..9cbdab2b 100644 --- a/content/renderer/stats_collection_controller.cc +++ b/content/renderer/stats_collection_controller.cc
@@ -66,7 +66,7 @@ item.SetDouble("load_duration_ms", (load_stop_time - load_start_time).InMillisecondsF()); } - base::JSONWriter::Write(&item, result); + base::JSONWriter::Write(item, result); } } // namespace
diff --git a/content/shell/BUILD.gn b/content/shell/BUILD.gn index 95450b5..e894419 100644 --- a/content/shell/BUILD.gn +++ b/content/shell/BUILD.gn
@@ -555,3 +555,20 @@ } } } + +if (is_win) { + # GYP version: content/content_shell_and_tests.gyp:content_shell_crash_service + executable("crash_service") { + sources = [ + "tools/content_shell_crash_service.cc", + ] + + deps = [ + "//base", + "//components/crash/tools:crash_service", + ] + + configs -= [ "//build/config/win:console" ] + configs += [ "//build/config/win:windowed" ] + } +}
diff --git a/content/shell/DEPS b/content/shell/DEPS index 552ba8e..fadafc0 100644 --- a/content/shell/DEPS +++ b/content/shell/DEPS
@@ -29,6 +29,9 @@ # For enabling media related features. "+media/base/media_switches.h", + + # For media::RemoveProprietaryMediaTypesAndCodecsForTests. + "+media/base/mime_util.h", ] specific_include_rules = {
diff --git a/content/shell/app/shell_main_delegate.cc b/content/shell/app/shell_main_delegate.cc index e5199f1..65a4fdf 100644 --- a/content/shell/app/shell_main_delegate.cc +++ b/content/shell/app/shell_main_delegate.cc
@@ -12,6 +12,7 @@ #include "base/lazy_instance.h" #include "base/logging.h" #include "base/path_service.h" +#include "build/build_config.h" #include "cc/base/switches.h" #include "content/public/browser/browser_main_runner.h" #include "content/public/common/content_switches.h" @@ -27,6 +28,7 @@ #include "content/shell/renderer/layout_test/layout_test_content_renderer_client.h" #include "content/shell/renderer/shell_content_renderer_client.h" #include "media/base/media_switches.h" +#include "media/base/mime_util.h" #include "net/cookies/cookie_monster.h" #include "ui/base/resource/resource_bundle.h" #include "ui/base/ui_base_paths.h" @@ -206,7 +208,7 @@ // Unless/until WebM files are added to the media layout tests, we need to // avoid removing MP4/H264/AAC so that layout tests can run on Android. #if !defined(OS_ANDROID) - net::RemoveProprietaryMediaTypesAndCodecsForTests(); + media::RemoveProprietaryMediaTypesAndCodecsForTests(); #endif if (!BlinkTestPlatformInitialize()) {
diff --git a/content/shell/browser/shell_devtools_frontend.cc b/content/shell/browser/shell_devtools_frontend.cc index 0cd1c93..2ad0c2ed 100644 --- a/content/shell/browser/shell_devtools_frontend.cc +++ b/content/shell/browser/shell_devtools_frontend.cc
@@ -267,9 +267,9 @@ base::FundamentalValue total_size(static_cast<int>(message.length())); for (size_t pos = 0; pos < message.length(); pos += kMaxMessageChunkSize) { - base::StringValue message_value(message.substr(pos, kMaxMessageChunkSize)); std::string param; - base::JSONWriter::Write(&message_value, ¶m); + base::JSONWriter::Write( + base::StringValue(message.substr(pos, kMaxMessageChunkSize)), ¶m); std::string code = "DevToolsAPI.dispatchMessageChunk(" + param + ");"; base::string16 javascript = base::UTF8ToUTF16(code); web_contents()->GetMainFrame()->ExecuteJavaScript(javascript); @@ -308,13 +308,13 @@ std::string javascript = function_name + "("; if (arg1) { std::string json; - base::JSONWriter::Write(arg1, &json); + base::JSONWriter::Write(*arg1, &json); javascript.append(json); if (arg2) { - base::JSONWriter::Write(arg2, &json); + base::JSONWriter::Write(*arg2, &json); javascript.append(", ").append(json); if (arg3) { - base::JSONWriter::Write(arg3, &json); + base::JSONWriter::Write(*arg3, &json); javascript.append(", ").append(json); } }
diff --git a/content/shell/renderer/layout_test/leak_detector.cc b/content/shell/renderer/layout_test/leak_detector.cc index a00fdba..41645bb 100644 --- a/content/shell/renderer/layout_test/leak_detector.cc +++ b/content/shell/renderer/layout_test/leak_detector.cc
@@ -85,7 +85,7 @@ if (!detail.empty()) { std::string detail_str; - base::JSONWriter::Write(&detail, &detail_str); + base::JSONWriter::Write(detail, &detail_str); report.detail = detail_str; report.leaked = true; }
diff --git a/content/shell/renderer/test_runner/test_interfaces.cc b/content/shell/renderer/test_runner/test_interfaces.cc index fda79745..2dd3e418 100644 --- a/content/shell/renderer/test_runner/test_interfaces.cc +++ b/content/shell/renderer/test_runner/test_interfaces.cc
@@ -119,7 +119,7 @@ base::DictionaryValue settings; settings.SetString("testPath", base::GetQuotedJSONString(spec)); std::string settings_string; - base::JSONWriter::Write(&settings, &settings_string); + base::JSONWriter::Write(settings, &settings_string); test_runner_->ShowDevTools(settings_string, std::string()); } if (spec.find("/viewsource/") != std::string::npos) {
diff --git a/content/shell/renderer/test_runner/web_test_proxy.cc b/content/shell/renderer/test_runner/web_test_proxy.cc index 8b3cfdee..6b97d39d 100644 --- a/content/shell/renderer/test_runner/web_test_proxy.cc +++ b/content/shell/renderer/test_runner/web_test_proxy.cc
@@ -311,12 +311,7 @@ } std::string DumpDocumentText(blink::WebFrame* frame) { - // We use the document element's text instead of the body text here because - // not all documents have a body, such as XML documents. - blink::WebElement document_element = frame->document().documentElement(); - if (document_element.isNull()) - return std::string(); - return document_element.innerText().utf8(); + return frame->document().contentAsTextForTesting().utf8(); } std::string DumpFramesAsText(blink::WebFrame* frame, bool recursive) {
diff --git a/content/test/data/media/webrtc_test_utilities.js b/content/test/data/media/webrtc_test_utilities.js index cf75ef6d..5fd3811 100644 --- a/content/test/data/media/webrtc_test_utilities.js +++ b/content/test/data/media/webrtc_test_utilities.js
@@ -66,14 +66,9 @@ var width = VIDEO_TAG_WIDTH; var height = VIDEO_TAG_HEIGHT; var videoElement = $(videoElementName); + var canvas = $(videoElementName + '-canvas'); var oldPixels = []; - var startTimeMs = new Date().getTime(); var waitVideo = setInterval(function() { - var canvas = $(videoElementName + '-canvas'); - if (canvas == null) { - console.log('Waiting for ' + videoElementName + '-canvas' + ' to appear'); - return; - } var context = canvas.getContext('2d'); context.drawImage(videoElement, 0, 0, width, height); var pixels = context.getImageData(0, 0 , width, height / 3).data; @@ -87,12 +82,6 @@ callback(videoElement.videoWidth, videoElement.videoHeight); } oldPixels = pixels; - - var elapsedTime = new Date().getTime() - startTimeMs; - if (elapsedTime > 3000) { - startTimeMs = new Date().getTime(); - console.log('Still waiting for video to satisfy ' + predicate.toString()); - } }, 200); } @@ -197,19 +186,12 @@ return false; } -// Pixels is an array where pixels[0] is the R value for the first pixel, -// pixels[1] is the G value, and so on. function isVideoBlack(pixels) { for (var i = 0; i < pixels.length; i++) { - if ((i + 1) % 4 == 0) { - // Ignore the alpha channel. - continue; - } - - // A black pixel has 0 for R,G and B but allow a bit more here to account - // for rounding errors in libyuv. - if (pixels[i] > 3) { - console.log('Found nonblack pixel at ' + i + ', was ' + pixels[i]); + // |pixels| is in RGBA. Ignore the alpha channel. + // We allow it to be off by 1, to account for rounding errors in YUV + // conversion. + if (pixels[i] != 0 && pixels[i] != 1 && (i + 1) % 4 != 0) { return false; } }
diff --git a/content/test/gpu/gpu_tests/pixel_expectations.py b/content/test/gpu/gpu_tests/pixel_expectations.py index a8b1dda..0ef5d92 100644 --- a/content/test/gpu/gpu_tests/pixel_expectations.py +++ b/content/test/gpu/gpu_tests/pixel_expectations.py
@@ -11,4 +11,6 @@ # Sample Usage: # self.Fail('Pixel.Canvas2DRedBox', # ['mac', 'amd', ('nvidia', 0x1234)], bug=123) - pass + self.Fail('Pixel.Canvas2DRedBox', bug=485183) + self.Fail('Pixel.CSS3DBlueBox', bug=485183) + self.Fail('Pixel.WebGLGreenTriangle', bug=485183)
diff --git a/content/test/gpu/gpu_tests/webgl_conformance_expectations.py b/content/test/gpu/gpu_tests/webgl_conformance_expectations.py index 52c7790..2e782df 100644 --- a/content/test/gpu/gpu_tests/webgl_conformance_expectations.py +++ b/content/test/gpu/gpu_tests/webgl_conformance_expectations.py
@@ -80,6 +80,8 @@ ['win', 'd3d9'], bug=896) # angle bug ID self.Skip('conformance/extensions/oes-texture-half-float-with-canvas.html', ['win', 'd3d9'], bug=896) # angle bug ID + self.Fail('conformance/glsl/bugs/conditional-discard-optimization.html', + ['win', 'd3d9'], bug=488552) # Mac failures self.Fail('conformance/glsl/misc/shaders-with-invariance.html',
diff --git a/content/test/gpu/page_sets/pixel_tests.py b/content/test/gpu/page_sets/pixel_tests.py index e747d3c..877311d 100644 --- a/content/test/gpu/page_sets/pixel_tests.py +++ b/content/test/gpu/page_sets/pixel_tests.py
@@ -30,19 +30,19 @@ url='file://../../data/gpu/pixel_canvas2d.html', name=base_name + '.Canvas2DRedBox', test_rect=[0, 0, 300, 300], - revision=4, + revision=5, page_set=self)) self.AddUserStory(PixelTestsPage( url='file://../../data/gpu/pixel_css3d.html', name=base_name + '.CSS3DBlueBox', test_rect=[0, 0, 300, 300], - revision=12, + revision=13, page_set=self)) self.AddUserStory(PixelTestsPage( url='file://../../data/gpu/pixel_webgl.html', name=base_name + '.WebGLGreenTriangle', test_rect=[0, 0, 300, 300], - revision=9, + revision=10, page_set=self))
diff --git a/dbus/values_util.cc b/dbus/values_util.cc index c27c272..c162878 100644 --- a/dbus/values_util.cc +++ b/dbus/values_util.cc
@@ -48,10 +48,10 @@ } else { // If the type of keys is not STRING, convert it to string. scoped_ptr<base::Value> key(PopDataAsValue(&entry_reader)); - if (!key.get()) + if (!key) return false; // Use JSONWriter to convert an arbitrary value to a string. - base::JSONWriter::Write(key.get(), &key_string); + base::JSONWriter::Write(*key, &key_string); } // Get the value and set the key-value pair. base::Value* value = PopDataAsValue(&entry_reader);
diff --git a/dbus/values_util_unittest.cc b/dbus/values_util_unittest.cc index 27ec2d0..6abc56a 100644 --- a/dbus/values_util_unittest.cc +++ b/dbus/values_util_unittest.cc
@@ -377,11 +377,9 @@ // Create the expected value. base::DictionaryValue dictionary_value; for (size_t i = 0; i != values.size(); ++i) { - scoped_ptr<base::Value> key_value(new base::FundamentalValue(keys[i])); std::string key_string; - base::JSONWriter::Write(key_value.get(), &key_string); - dictionary_value.SetWithoutPathExpansion( - key_string, new base::FundamentalValue(values[i])); + base::JSONWriter::Write(base::FundamentalValue(keys[i]), &key_string); + dictionary_value.SetIntegerWithoutPathExpansion(key_string, values[i]); } // Pop a dictionary.
diff --git a/device/bluetooth/BUILD.gn b/device/bluetooth/BUILD.gn index 3de7132..31b54e17 100644 --- a/device/bluetooth/BUILD.gn +++ b/device/bluetooth/BUILD.gn
@@ -215,6 +215,8 @@ sources = [ "test/mock_bluetooth_adapter.cc", "test/mock_bluetooth_adapter.h", + "test/mock_bluetooth_advertisement.cc", + "test/mock_bluetooth_advertisement.h", "test/mock_bluetooth_device.cc", "test/mock_bluetooth_device.h", "test/mock_bluetooth_discovery_session.cc",
diff --git a/device/bluetooth/bluetooth.gyp b/device/bluetooth/bluetooth.gyp index 4d734c52..d36a2ce 100644 --- a/device/bluetooth/bluetooth.gyp +++ b/device/bluetooth/bluetooth.gyp
@@ -211,6 +211,8 @@ # Note: file list duplicated in GN build. 'test/mock_bluetooth_adapter.cc', 'test/mock_bluetooth_adapter.h', + 'test/mock_bluetooth_advertisement.cc', + 'test/mock_bluetooth_advertisement.h', 'test/mock_bluetooth_device.cc', 'test/mock_bluetooth_device.h', 'test/mock_bluetooth_discovery_session.cc',
diff --git a/device/bluetooth/test/mock_bluetooth_adapter.cc b/device/bluetooth/test/mock_bluetooth_adapter.cc index 4b47579..46d8cb7c 100644 --- a/device/bluetooth/test/mock_bluetooth_adapter.cc +++ b/device/bluetooth/test/mock_bluetooth_adapter.cc
@@ -4,6 +4,8 @@ #include "device/bluetooth/test/mock_bluetooth_adapter.h" +#include "device/bluetooth/test/mock_bluetooth_advertisement.h" + namespace device { MockBluetoothAdapter::Observer::Observer() {} @@ -50,6 +52,7 @@ scoped_ptr<BluetoothAdvertisement::Data> advertisement_data, const CreateAdvertisementCallback& callback, const CreateAdvertisementErrorCallback& error_callback) { + callback.Run(new MockBluetoothAdvertisement); } } // namespace device
diff --git a/device/bluetooth/test/mock_bluetooth_advertisement.cc b/device/bluetooth/test/mock_bluetooth_advertisement.cc new file mode 100644 index 0000000..ddba516 --- /dev/null +++ b/device/bluetooth/test/mock_bluetooth_advertisement.cc
@@ -0,0 +1,21 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "device/bluetooth/test/mock_bluetooth_advertisement.h" + +namespace device { + +MockBluetoothAdvertisement::MockBluetoothAdvertisement() { +} + +MockBluetoothAdvertisement::~MockBluetoothAdvertisement() { +} + +void MockBluetoothAdvertisement::Unregister( + const SuccessCallback& success_callback, + const ErrorCallback& error_callback) { + success_callback.Run(); +} + +} // namespace chromeos
diff --git a/device/bluetooth/test/mock_bluetooth_advertisement.h b/device/bluetooth/test/mock_bluetooth_advertisement.h new file mode 100644 index 0000000..ddaeef4 --- /dev/null +++ b/device/bluetooth/test/mock_bluetooth_advertisement.h
@@ -0,0 +1,29 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef DEVICE_BLUETOOTH_BLUETOOTH_ADVERTISEMENT_CHROMEOS_H_ +#define DEVICE_BLUETOOTH_BLUETOOTH_ADVERTISEMENT_CHROMEOS_H_ + +#include "base/macros.h" +#include "device/bluetooth/bluetooth_advertisement.h" + +namespace device { + +class MockBluetoothAdvertisement : public device::BluetoothAdvertisement { + public: + MockBluetoothAdvertisement(); + + // BluetoothAdvertisement overrides: + void Unregister(const SuccessCallback& success_callback, + const ErrorCallback& error_callback) override; + + private: + ~MockBluetoothAdvertisement() override; + + DISALLOW_COPY_AND_ASSIGN(MockBluetoothAdvertisement); +}; + +} // namespace chromeos + +#endif // DEVICE_BLUETOOTH_BLUETOOTH_ADVERTISEMENT_CHROMEOS_H_
diff --git a/extensions/browser/api/bluetooth_low_energy/bluetooth_api_advertisement.cc b/extensions/browser/api/bluetooth_low_energy/bluetooth_api_advertisement.cc new file mode 100644 index 0000000..c1a9248 --- /dev/null +++ b/extensions/browser/api/bluetooth_low_energy/bluetooth_api_advertisement.cc
@@ -0,0 +1,35 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "extensions/browser/api/bluetooth_low_energy/bluetooth_api_advertisement.h" + +#include "base/lazy_instance.h" +#include "device/bluetooth/bluetooth_advertisement.h" +#include "net/base/io_buffer.h" + +namespace extensions { + +// static +static base::LazyInstance<BrowserContextKeyedAPIFactory< + ApiResourceManager<BluetoothApiAdvertisement>>> g_server_factory = + LAZY_INSTANCE_INITIALIZER; + +// static +template <> +BrowserContextKeyedAPIFactory<ApiResourceManager<BluetoothApiAdvertisement>>* +ApiResourceManager<BluetoothApiAdvertisement>::GetFactoryInstance() { + return g_server_factory.Pointer(); +} + +BluetoothApiAdvertisement::BluetoothApiAdvertisement( + const std::string& owner_extension_id, + scoped_refptr<device::BluetoothAdvertisement> advertisement) + : ApiResource(owner_extension_id), advertisement_(advertisement) { + DCHECK(content::BrowserThread::CurrentlyOn(kThreadId)); +} + +BluetoothApiAdvertisement::~BluetoothApiAdvertisement() { +} + +} // namespace extensions
diff --git a/extensions/browser/api/bluetooth_low_energy/bluetooth_api_advertisement.h b/extensions/browser/api/bluetooth_low_energy/bluetooth_api_advertisement.h new file mode 100644 index 0000000..6144bc27 --- /dev/null +++ b/extensions/browser/api/bluetooth_low_energy/bluetooth_api_advertisement.h
@@ -0,0 +1,56 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef EXTENSIONS_BROWSER_API_BLUETOOTH_LOW_ENERGY_BLUETOOTH_API_ADVERTISEMENT_H_ +#define EXTENSIONS_BROWSER_API_BLUETOOTH_LOW_ENERGY_BLUETOOTH_API_ADVERTISEMENT_H_ + +#include <string> + +#include "device/bluetooth/bluetooth_advertisement.h" +#include "extensions/browser/api/api_resource.h" +#include "extensions/browser/api/api_resource_manager.h" +#include "extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_event_router.h" + +namespace device { +class BluetoothAdvertisement; +} // namespace device + +namespace apibtle = extensions::core_api::bluetooth_low_energy; + +namespace extensions { + +// Representation of advertisement instances from the "bluetooth" namespace, +// abstracting the underlying BluetoothAdvertisementXxx class. All methods +// must be called on the |kThreadId| thread. +class BluetoothApiAdvertisement : public ApiResource { + public: + BluetoothApiAdvertisement(const std::string& owner_extension_id, + scoped_refptr<device::BluetoothAdvertisement>); + ~BluetoothApiAdvertisement() override; + + device::BluetoothAdvertisement* advertisement() { + return advertisement_.get(); + } + + // Implementations of |BluetoothAdvertisement| require being called on the + // UI thread. + static const content::BrowserThread::ID kThreadId = + content::BrowserThread::UI; + + private: + friend class ApiResourceManager<BluetoothApiAdvertisement>; + + static const char* service_name() { + return "BluetoothApiAdvertisementManager"; + } + + // The underlying advertisement instance. + scoped_refptr<device::BluetoothAdvertisement> advertisement_; + + DISALLOW_COPY_AND_ASSIGN(BluetoothApiAdvertisement); +}; + +} // namespace extensions + +#endif // EXTENSIONS_BROWSER_API_BLUETOOTH_LOW_ENERGY_BLUETOOTH_API_ADVERTISEMENT_H_
diff --git a/extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_api.cc b/extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_api.cc index a072c0c8..9545d48 100644 --- a/extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_api.cc +++ b/extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_api.cc
@@ -4,10 +4,13 @@ #include "extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_api.h" +#include <algorithm> + #include "base/bind.h" #include "base/lazy_instance.h" #include "base/strings/stringprintf.h" #include "content/public/browser/browser_thread.h" +#include "extensions/browser/api/bluetooth_low_energy/bluetooth_api_advertisement.h" #include "extensions/browser/api/bluetooth_low_energy/utils.h" #include "extensions/browser/event_router.h" #include "extensions/common/api/bluetooth/bluetooth_manifest_data.h" @@ -44,6 +47,11 @@ const char kErrorTimeout[] = "Operation timed out"; const char kErrorUnsupportedDevice[] = "This device is not supported on the current platform"; +const char kErrorInvalidAdvertisementLength[] = "Invalid advertisement length"; +const char kStatusAdvertisementAlreadyExists[] = + "An advertisement is already advertising"; +const char kStatusAdvertisementDoesNotExist[] = + "This advertisement does not exist"; // Returns the correct error string based on error status |status|. This is used // to set the value of |chrome.runtime.lastError.message| and should not be @@ -100,6 +108,31 @@ callback.Run(); } +scoped_ptr<device::BluetoothAdvertisement::ManufacturerData> +CreateManufacturerData( + std::vector<linked_ptr<apibtle::ManufacturerData>>* manufacturer_data) { + scoped_ptr<device::BluetoothAdvertisement::ManufacturerData> created_data( + new device::BluetoothAdvertisement::ManufacturerData()); + for (const auto& it : *manufacturer_data) { + std::vector<uint8_t> data(it->data.size()); + std::copy(it->data.begin(), it->data.end(), data.begin()); + (*created_data)[it->id] = data; + } + return created_data; +} + +scoped_ptr<device::BluetoothAdvertisement::ServiceData> CreateServiceData( + std::vector<linked_ptr<apibtle::ServiceData>>* service_data) { + scoped_ptr<device::BluetoothAdvertisement::ServiceData> created_data( + new device::BluetoothAdvertisement::ServiceData()); + for (const auto& it : *service_data) { + std::vector<uint8_t> data(it->data.size()); + std::copy(it->data.begin(), it->data.end(), data.begin()); + (*created_data)[it->uuid] = data; + } + return created_data; +} + } // namespace @@ -793,6 +826,44 @@ SendResponse(false); } +BluetoothLowEnergyAdvertisementFunction:: + BluetoothLowEnergyAdvertisementFunction() + : advertisements_manager_(nullptr) { +} + +BluetoothLowEnergyAdvertisementFunction:: + ~BluetoothLowEnergyAdvertisementFunction() { +} + +int BluetoothLowEnergyAdvertisementFunction::AddAdvertisement( + BluetoothApiAdvertisement* advertisement) { + DCHECK(advertisements_manager_); + return advertisements_manager_->Add(advertisement); +} + +BluetoothApiAdvertisement* +BluetoothLowEnergyAdvertisementFunction::GetAdvertisement( + int advertisement_id) { + DCHECK(advertisements_manager_); + return advertisements_manager_->Get(extension_id(), advertisement_id); +} + +void BluetoothLowEnergyAdvertisementFunction::RemoveAdvertisement( + int advertisement_id) { + DCHECK(advertisements_manager_); + advertisements_manager_->Remove(extension_id(), advertisement_id); +} + +bool BluetoothLowEnergyAdvertisementFunction::RunAsync() { + Initialize(); + return BluetoothLowEnergyExtensionFunction::RunAsync(); +} + +void BluetoothLowEnergyAdvertisementFunction::Initialize() { + advertisements_manager_ = + ApiResourceManager<BluetoothApiAdvertisement>::Get(browser_context()); +} + // RegisterAdvertisement: bool BluetoothLowEnergyRegisterAdvertisementFunction::DoWork() { @@ -819,11 +890,65 @@ apibtle::RegisterAdvertisement::Params::Create(*args_)); EXTENSION_FUNCTION_VALIDATE(params.get() != NULL); - // TODO(rkc): Implement this function. + scoped_ptr<device::BluetoothAdvertisement::Data> advertisement_data( + new device::BluetoothAdvertisement::Data( + params->advertisement.type == + apibtle::AdvertisementType::ADVERTISEMENT_TYPE_BROADCAST + ? device::BluetoothAdvertisement::AdvertisementType:: + ADVERTISEMENT_TYPE_BROADCAST + : device::BluetoothAdvertisement::AdvertisementType:: + ADVERTISEMENT_TYPE_PERIPHERAL)); + + advertisement_data->set_service_uuids( + params->advertisement.service_uuids.Pass()); + advertisement_data->set_solicit_uuids( + params->advertisement.solicit_uuids.Pass()); + if (params->advertisement.manufacturer_data) { + advertisement_data->set_manufacturer_data( + CreateManufacturerData(params->advertisement.manufacturer_data.get()) + .Pass()); + } + if (params->advertisement.service_data) { + advertisement_data->set_service_data( + CreateServiceData(params->advertisement.service_data.get()).Pass()); + } + + event_router->adapter()->RegisterAdvertisement( + advertisement_data.Pass(), + base::Bind( + &BluetoothLowEnergyRegisterAdvertisementFunction::SuccessCallback, + this), + base::Bind( + &BluetoothLowEnergyRegisterAdvertisementFunction::ErrorCallback, + this)); return true; } +void BluetoothLowEnergyRegisterAdvertisementFunction::SuccessCallback( + scoped_refptr<device::BluetoothAdvertisement> advertisement) { + results_ = apibtle::RegisterAdvertisement::Results::Create(AddAdvertisement( + new BluetoothApiAdvertisement(extension_id(), advertisement))); + SendResponse(true); +} + +void BluetoothLowEnergyRegisterAdvertisementFunction::ErrorCallback( + device::BluetoothAdvertisement::ErrorCode status) { + switch (status) { + case device::BluetoothAdvertisement::ErrorCode:: + ERROR_ADVERTISEMENT_ALREADY_EXISTS: + SetError(kStatusAdvertisementAlreadyExists); + break; + case device::BluetoothAdvertisement::ErrorCode:: + ERROR_ADVERTISEMENT_INVALID_LENGTH: + SetError(kErrorInvalidAdvertisementLength); + break; + default: + SetError(kErrorOperationFailed); + } + SendResponse(false); +} + // UnregisterAdvertisement: bool BluetoothLowEnergyUnregisterAdvertisementFunction::DoWork() { @@ -846,10 +971,45 @@ apibtle::UnregisterAdvertisement::Params::Create(*args_)); EXTENSION_FUNCTION_VALIDATE(params.get() != NULL); - // TODO(rkc): Implement this function. + BluetoothApiAdvertisement* advertisement = + GetAdvertisement(params->advertisement_id); + if (!advertisement) { + error_ = kStatusAdvertisementDoesNotExist; + SendResponse(false); + return false; + } + + advertisement->advertisement()->Unregister( + base::Bind( + &BluetoothLowEnergyUnregisterAdvertisementFunction::SuccessCallback, + this, params->advertisement_id), + base::Bind( + &BluetoothLowEnergyUnregisterAdvertisementFunction::ErrorCallback, + this, params->advertisement_id)); return true; } +void BluetoothLowEnergyUnregisterAdvertisementFunction::SuccessCallback( + int advertisement_id) { + RemoveAdvertisement(advertisement_id); + SendResponse(true); +} + +void BluetoothLowEnergyUnregisterAdvertisementFunction::ErrorCallback( + int advertisement_id, + device::BluetoothAdvertisement::ErrorCode status) { + RemoveAdvertisement(advertisement_id); + switch (status) { + case device::BluetoothAdvertisement::ErrorCode:: + ERROR_ADVERTISEMENT_DOES_NOT_EXIST: + SetError(kStatusAdvertisementDoesNotExist); + break; + default: + SetError(kErrorOperationFailed); + } + SendResponse(false); +} + } // namespace core_api } // namespace extensions
diff --git a/extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_api.h b/extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_api.h index debb635c..b6e6f8f2 100644 --- a/extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_api.h +++ b/extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_api.h
@@ -6,6 +6,8 @@ #define EXTENSIONS_BROWSER_API_BLUETOOTH_LOW_ENERGY_BLUETOOTH_LOW_ENERGY_API_H_ #include "base/memory/scoped_ptr.h" +#include "device/bluetooth/bluetooth_advertisement.h" +#include "extensions/browser/api/api_resource_manager.h" #include "extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_event_router.h" #include "extensions/browser/browser_context_keyed_api_factory.h" #include "extensions/browser/extension_function.h" @@ -13,6 +15,7 @@ namespace extensions { +class BluetoothApiAdvertisement; class BluetoothLowEnergyEventRouter; // The profile-keyed service that manages the bluetoothLowEnergy extension API. @@ -329,9 +332,33 @@ std::string instance_id_; }; -class BluetoothLowEnergyRegisterAdvertisementFunction +class BluetoothLowEnergyAdvertisementFunction : public BluetoothLowEnergyExtensionFunction { public: + BluetoothLowEnergyAdvertisementFunction(); + + protected: + ~BluetoothLowEnergyAdvertisementFunction() override; + + // Takes ownership. + int AddAdvertisement(BluetoothApiAdvertisement* advertisement); + BluetoothApiAdvertisement* GetAdvertisement(int advertisement_id); + void RemoveAdvertisement(int advertisement_id); + + // ExtensionFunction override. + bool RunAsync() override; + + private: + void Initialize(); + + ApiResourceManager<BluetoothApiAdvertisement>* advertisements_manager_; + + DISALLOW_COPY_AND_ASSIGN(BluetoothLowEnergyAdvertisementFunction); +}; + +class BluetoothLowEnergyRegisterAdvertisementFunction + : public BluetoothLowEnergyAdvertisementFunction { + public: DECLARE_EXTENSION_FUNCTION("bluetoothLowEnergy.registerAdvertisement", BLUETOOTHLOWENERGY_REGISTERADVERTISEMENT); @@ -342,17 +369,15 @@ bool DoWork() override; private: - // Success and error callbacks, called by - // BluetoothLowEnergyEventRouter::WriteDescriptorValue. - void SuccessCallback(); - void ErrorCallback(BluetoothLowEnergyEventRouter::Status status); + void SuccessCallback(scoped_refptr<device::BluetoothAdvertisement>); + void ErrorCallback(device::BluetoothAdvertisement::ErrorCode status); // The instance ID of the requested descriptor. std::string instance_id_; }; class BluetoothLowEnergyUnregisterAdvertisementFunction - : public BluetoothLowEnergyExtensionFunction { + : public BluetoothLowEnergyAdvertisementFunction { public: DECLARE_EXTENSION_FUNCTION("bluetoothLowEnergy.unregisterAdvertisement", BLUETOOTHLOWENERGY_UNREGISTERADVERTISEMENT); @@ -364,10 +389,9 @@ bool DoWork() override; private: - // Success and error callbacks, called by - // BluetoothLowEnergyEventRouter::WriteDescriptorValue. - void SuccessCallback(); - void ErrorCallback(BluetoothLowEnergyEventRouter::Status status); + void SuccessCallback(int advertisement_id); + void ErrorCallback(int advertisement_id, + device::BluetoothAdvertisement::ErrorCode status); // The instance ID of the requested descriptor. std::string instance_id_;
diff --git a/extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_apitest.cc b/extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_apitest.cc index d300dfa..398cca8e 100644 --- a/extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_apitest.cc +++ b/extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_apitest.cc
@@ -1320,4 +1320,21 @@ mock_adapter_, device0_.get(), service0_.get()); } +#if defined(OS_CHROMEOS) +#define MAYBE_RegisterAdvertisement RegisterAdvertisement +#else +#define MAYBE_RegisterAdvertisement DISABLED_RegisterAdvertisement +#endif + +IN_PROC_BROWSER_TEST_F(BluetoothLowEnergyApiTest, MAYBE_RegisterAdvertisement) { + ResultCatcher catcher; + catcher.RestrictToBrowserContext(browser()->profile()); + + // Run the test. + ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII( + "bluetooth_low_energy/register_advertisement"))); + + EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); +} + } // namespace
diff --git a/extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_event_router.h b/extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_event_router.h index b6bad5c..f265505 100644 --- a/extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_event_router.h +++ b/extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_event_router.h
@@ -268,6 +268,8 @@ device::BluetoothGattDescriptor* descriptor, const std::vector<uint8>& value) override; + device::BluetoothAdapter* adapter() { return adapter_.get(); } + private: // Called by BluetoothAdapterFactory. void OnGetAdapter(const base::Closure& callback,
diff --git a/extensions/browser/api/cast_channel/cast_channel_api.cc b/extensions/browser/api/cast_channel/cast_channel_api.cc index e00646e..4ad8624b 100644 --- a/extensions/browser/api/cast_channel/cast_channel_api.cc +++ b/extensions/browser/api/cast_channel/cast_channel_api.cc
@@ -59,7 +59,7 @@ std::string ParamToString(const T& info) { scoped_ptr<base::DictionaryValue> dict = info.ToValue(); std::string out; - base::JSONWriter::Write(dict.get(), &out); + base::JSONWriter::Write(*dict, &out); return out; }
diff --git a/extensions/browser/api/cast_channel/keep_alive_delegate.cc b/extensions/browser/api/cast_channel/keep_alive_delegate.cc index 73c356f4..df23519 100644 --- a/extensions/browser/api/cast_channel/keep_alive_delegate.cc +++ b/extensions/browser/api/cast_channel/keep_alive_delegate.cc
@@ -68,7 +68,7 @@ output.set_namespace_(kHeartbeatNamespace); base::DictionaryValue type_dict; type_dict.SetString(kTypeNodeId, message_type); - if (!base::JSONWriter::Write(&type_dict, output.mutable_payload_utf8())) { + if (!base::JSONWriter::Write(type_dict, output.mutable_payload_utf8())) { LOG(ERROR) << "Failed to serialize dictionary."; return output; }
diff --git a/extensions/browser/api/storage/settings_quota_unittest.cc b/extensions/browser/api/storage/settings_quota_unittest.cc index 391043e0..02e8735e 100644 --- a/extensions/browser/api/storage/settings_quota_unittest.cc +++ b/extensions/browser/api/storage/settings_quota_unittest.cc
@@ -24,23 +24,22 @@ class ExtensionSettingsQuotaTest : public testing::Test { public: ExtensionSettingsQuotaTest() - : byte_value_1_(new base::FundamentalValue(1)), - byte_value_16_(new base::StringValue("sixteen bytes.")), - byte_value_256_(new base::ListValue()), + : byte_value_1_(1), + byte_value_16_("sixteen bytes."), delegate_(new TestingValueStore()) { for (int i = 1; i < 89; ++i) { - byte_value_256_->Append(new base::FundamentalValue(i)); + byte_value_256_.AppendInteger(i); } ValidateByteValues(); } void ValidateByteValues() { std::string validate_sizes; - base::JSONWriter::Write(byte_value_1_.get(), &validate_sizes); + base::JSONWriter::Write(byte_value_1_, &validate_sizes); ASSERT_EQ(1u, validate_sizes.size()); - base::JSONWriter::Write(byte_value_16_.get(), &validate_sizes); + base::JSONWriter::Write(byte_value_16_, &validate_sizes); ASSERT_EQ(16u, validate_sizes.size()); - base::JSONWriter::Write(byte_value_256_.get(), &validate_sizes); + base::JSONWriter::Write(byte_value_256_, &validate_sizes); ASSERT_EQ(256u, validate_sizes.size()); } @@ -64,9 +63,9 @@ } // Values with different serialized sizes. - scoped_ptr<base::Value> byte_value_1_; - scoped_ptr<base::Value> byte_value_16_; - scoped_ptr<base::ListValue> byte_value_256_; + base::FundamentalValue byte_value_1_; + base::StringValue byte_value_16_; + base::ListValue byte_value_256_; // Quota enforcing storage area being tested. scoped_ptr<SettingsStorageQuotaEnforcer> storage_; @@ -79,7 +78,7 @@ base::DictionaryValue empty; CreateStorage(0, UINT_MAX, UINT_MAX); - EXPECT_TRUE(storage_->Set(DEFAULTS, "a", *byte_value_1_)->HasError()); + EXPECT_TRUE(storage_->Set(DEFAULTS, "a", byte_value_1_)->HasError()); EXPECT_FALSE(storage_->Remove("a")->HasError()); EXPECT_FALSE(storage_->Remove("b")->HasError()); EXPECT_TRUE(SettingsEqual(empty)); @@ -89,7 +88,7 @@ base::DictionaryValue empty; CreateStorage(8u, UINT_MAX, UINT_MAX); EXPECT_TRUE( - storage_->Set(DEFAULTS, "Really long key", *byte_value_1_)->HasError()); + storage_->Set(DEFAULTS, "Really long key", byte_value_1_)->HasError()); EXPECT_TRUE(SettingsEqual(empty)); } @@ -97,12 +96,12 @@ base::DictionaryValue settings; CreateStorage(8u, UINT_MAX, UINT_MAX); - EXPECT_FALSE(storage_->Set(DEFAULTS, "a", *byte_value_1_)->HasError()); - settings.Set("a", byte_value_1_->DeepCopy()); + EXPECT_FALSE(storage_->Set(DEFAULTS, "a", byte_value_1_)->HasError()); + settings.Set("a", byte_value_1_.CreateDeepCopy()); EXPECT_TRUE(SettingsEqual(settings)); - EXPECT_TRUE(storage_->Set(DEFAULTS, "b", *byte_value_16_)->HasError()); - EXPECT_TRUE(storage_->Set(DEFAULTS, "c", *byte_value_256_)->HasError()); + EXPECT_TRUE(storage_->Set(DEFAULTS, "b", byte_value_16_)->HasError()); + EXPECT_TRUE(storage_->Set(DEFAULTS, "c", byte_value_256_)->HasError()); EXPECT_TRUE(SettingsEqual(settings)); } @@ -111,20 +110,20 @@ CreateStorage(40, UINT_MAX, UINT_MAX); base::DictionaryValue to_set; - to_set.Set("a", byte_value_1_->DeepCopy()); - to_set.Set("b", byte_value_16_->DeepCopy()); + to_set.Set("a", byte_value_1_.CreateDeepCopy()); + to_set.Set("b", byte_value_16_.CreateDeepCopy()); EXPECT_FALSE(storage_->Set(DEFAULTS, to_set)->HasError()); - settings.Set("a", byte_value_1_->DeepCopy()); - settings.Set("b", byte_value_16_->DeepCopy()); + settings.Set("a", byte_value_1_.CreateDeepCopy()); + settings.Set("b", byte_value_16_.CreateDeepCopy()); EXPECT_TRUE(SettingsEqual(settings)); // Should be able to set value to other under-quota value. - to_set.Set("a", byte_value_16_->DeepCopy()); + to_set.Set("a", byte_value_16_.CreateDeepCopy()); EXPECT_FALSE(storage_->Set(DEFAULTS, to_set)->HasError()); - settings.Set("a", byte_value_16_->DeepCopy()); + settings.Set("a", byte_value_16_.CreateDeepCopy()); EXPECT_TRUE(SettingsEqual(settings)); - EXPECT_TRUE(storage_->Set(DEFAULTS, "c", *byte_value_256_)->HasError()); + EXPECT_TRUE(storage_->Set(DEFAULTS, "c", byte_value_256_)->HasError()); EXPECT_TRUE(SettingsEqual(settings)); } @@ -132,7 +131,7 @@ base::DictionaryValue empty; CreateStorage(UINT_MAX, UINT_MAX, 0); - EXPECT_TRUE(storage_->Set(DEFAULTS, "a", *byte_value_1_)->HasError()); + EXPECT_TRUE(storage_->Set(DEFAULTS, "a", byte_value_1_)->HasError()); EXPECT_FALSE(storage_->Remove("a")->HasError()); EXPECT_FALSE(storage_->Remove("b")->HasError()); EXPECT_TRUE(SettingsEqual(empty)); @@ -142,17 +141,17 @@ base::DictionaryValue settings; CreateStorage(UINT_MAX, UINT_MAX, 1); - EXPECT_FALSE(storage_->Set(DEFAULTS, "a", *byte_value_1_)->HasError()); - settings.Set("a", byte_value_1_->DeepCopy()); + EXPECT_FALSE(storage_->Set(DEFAULTS, "a", byte_value_1_)->HasError()); + settings.Set("a", byte_value_1_.CreateDeepCopy()); EXPECT_TRUE(SettingsEqual(settings)); // Should be able to set existing key to other value without going over quota. - EXPECT_FALSE(storage_->Set(DEFAULTS, "a", *byte_value_16_)->HasError()); - settings.Set("a", byte_value_16_->DeepCopy()); + EXPECT_FALSE(storage_->Set(DEFAULTS, "a", byte_value_16_)->HasError()); + settings.Set("a", byte_value_16_.CreateDeepCopy()); EXPECT_TRUE(SettingsEqual(settings)); - EXPECT_TRUE(storage_->Set(DEFAULTS, "b", *byte_value_16_)->HasError()); - EXPECT_TRUE(storage_->Set(DEFAULTS, "c", *byte_value_256_)->HasError()); + EXPECT_TRUE(storage_->Set(DEFAULTS, "b", byte_value_16_)->HasError()); + EXPECT_TRUE(storage_->Set(DEFAULTS, "c", byte_value_256_)->HasError()); EXPECT_TRUE(SettingsEqual(settings)); } @@ -161,21 +160,21 @@ CreateStorage(UINT_MAX, UINT_MAX, 2); base::DictionaryValue to_set; - to_set.Set("a", byte_value_1_->DeepCopy()); - to_set.Set("b", byte_value_16_->DeepCopy()); + to_set.Set("a", byte_value_1_.CreateDeepCopy()); + to_set.Set("b", byte_value_16_.CreateDeepCopy()); EXPECT_FALSE(storage_->Set(DEFAULTS, to_set)->HasError()); - settings.Set("a", byte_value_1_->DeepCopy()); - settings.Set("b", byte_value_16_->DeepCopy()); + settings.Set("a", byte_value_1_.CreateDeepCopy()); + settings.Set("b", byte_value_16_.CreateDeepCopy()); EXPECT_TRUE(SettingsEqual(settings)); // Should be able to set existing keys to other values without going over // quota. - to_set.Set("a", byte_value_16_->DeepCopy()); + to_set.Set("a", byte_value_16_.CreateDeepCopy()); EXPECT_FALSE(storage_->Set(DEFAULTS, to_set)->HasError()); - settings.Set("a", byte_value_16_->DeepCopy()); + settings.Set("a", byte_value_16_.CreateDeepCopy()); EXPECT_TRUE(SettingsEqual(settings)); - EXPECT_TRUE(storage_->Set(DEFAULTS, "c", *byte_value_256_)->HasError()); + EXPECT_TRUE(storage_->Set(DEFAULTS, "c", byte_value_256_)->HasError()); EXPECT_TRUE(SettingsEqual(settings)); } @@ -183,32 +182,32 @@ base::DictionaryValue settings; CreateStorage(266, UINT_MAX, 2); - storage_->Set(DEFAULTS, "b", *byte_value_16_); - settings.Set("b", byte_value_16_->DeepCopy()); + storage_->Set(DEFAULTS, "b", byte_value_16_); + settings.Set("b", byte_value_16_.CreateDeepCopy()); // Not enough quota. - storage_->Set(DEFAULTS, "c", *byte_value_256_); + storage_->Set(DEFAULTS, "c", byte_value_256_); EXPECT_TRUE(SettingsEqual(settings)); // Try again with "b" removed, enough quota. EXPECT_FALSE(storage_->Remove("b")->HasError()); settings.Remove("b", NULL); - EXPECT_FALSE(storage_->Set(DEFAULTS, "c", *byte_value_256_)->HasError()); - settings.Set("c", byte_value_256_->DeepCopy()); + EXPECT_FALSE(storage_->Set(DEFAULTS, "c", byte_value_256_)->HasError()); + settings.Set("c", byte_value_256_.CreateDeepCopy()); EXPECT_TRUE(SettingsEqual(settings)); // Enough byte quota but max keys not high enough. - EXPECT_FALSE(storage_->Set(DEFAULTS, "a", *byte_value_1_)->HasError()); - settings.Set("a", byte_value_1_->DeepCopy()); + EXPECT_FALSE(storage_->Set(DEFAULTS, "a", byte_value_1_)->HasError()); + settings.Set("a", byte_value_1_.CreateDeepCopy()); EXPECT_TRUE(SettingsEqual(settings)); - EXPECT_TRUE(storage_->Set(DEFAULTS, "b", *byte_value_1_)->HasError()); + EXPECT_TRUE(storage_->Set(DEFAULTS, "b", byte_value_1_)->HasError()); EXPECT_TRUE(SettingsEqual(settings)); // Back under max keys. EXPECT_FALSE(storage_->Remove("a")->HasError()); settings.Remove("a", NULL); - EXPECT_FALSE(storage_->Set(DEFAULTS, "b", *byte_value_1_)->HasError()); - settings.Set("b", byte_value_1_->DeepCopy()); + EXPECT_FALSE(storage_->Set(DEFAULTS, "b", byte_value_1_)->HasError()); + settings.Set("b", byte_value_1_.CreateDeepCopy()); EXPECT_TRUE(SettingsEqual(settings)); } @@ -218,12 +217,12 @@ // Max out bytes. base::DictionaryValue to_set; - to_set.Set("b1", byte_value_16_->DeepCopy()); - to_set.Set("b2", byte_value_16_->DeepCopy()); + to_set.Set("b1", byte_value_16_.CreateDeepCopy()); + to_set.Set("b2", byte_value_16_.CreateDeepCopy()); storage_->Set(DEFAULTS, to_set); - settings.Set("b1", byte_value_16_->DeepCopy()); - settings.Set("b2", byte_value_16_->DeepCopy()); - EXPECT_TRUE(storage_->Set(DEFAULTS, "a", *byte_value_1_)->HasError()); + settings.Set("b1", byte_value_16_.CreateDeepCopy()); + settings.Set("b2", byte_value_16_.CreateDeepCopy()); + EXPECT_TRUE(storage_->Set(DEFAULTS, "a", byte_value_1_)->HasError()); EXPECT_TRUE(SettingsEqual(settings)); // Remove some settings that don't exist. @@ -235,18 +234,18 @@ EXPECT_TRUE(SettingsEqual(settings)); // Still no quota. - EXPECT_TRUE(storage_->Set(DEFAULTS, "a", *byte_value_1_)->HasError()); + EXPECT_TRUE(storage_->Set(DEFAULTS, "a", byte_value_1_)->HasError()); EXPECT_TRUE(SettingsEqual(settings)); // Max out key count. to_set.Clear(); - to_set.Set("b1", byte_value_1_->DeepCopy()); - to_set.Set("b2", byte_value_1_->DeepCopy()); + to_set.Set("b1", byte_value_1_.CreateDeepCopy()); + to_set.Set("b2", byte_value_1_.CreateDeepCopy()); storage_->Set(DEFAULTS, to_set); - settings.Set("b1", byte_value_1_->DeepCopy()); - settings.Set("b2", byte_value_1_->DeepCopy()); - storage_->Set(DEFAULTS, "b3", *byte_value_1_); - settings.Set("b3", byte_value_1_->DeepCopy()); + settings.Set("b1", byte_value_1_.CreateDeepCopy()); + settings.Set("b2", byte_value_1_.CreateDeepCopy()); + storage_->Set(DEFAULTS, "b3", byte_value_1_); + settings.Set("b3", byte_value_1_.CreateDeepCopy()); EXPECT_TRUE(SettingsEqual(settings)); // Remove some settings that don't exist. @@ -258,7 +257,7 @@ EXPECT_TRUE(SettingsEqual(settings)); // Still no quota. - EXPECT_TRUE(storage_->Set(DEFAULTS, "a", *byte_value_1_)->HasError()); + EXPECT_TRUE(storage_->Set(DEFAULTS, "a", byte_value_1_)->HasError()); EXPECT_TRUE(SettingsEqual(settings)); } @@ -269,35 +268,35 @@ // Test running out of byte quota. { base::DictionaryValue to_set; - to_set.Set("a", byte_value_16_->DeepCopy()); - to_set.Set("b", byte_value_16_->DeepCopy()); + to_set.Set("a", byte_value_16_.CreateDeepCopy()); + to_set.Set("b", byte_value_16_.CreateDeepCopy()); EXPECT_FALSE(storage_->Set(DEFAULTS, to_set)->HasError()); - EXPECT_TRUE(storage_->Set(DEFAULTS, "c", *byte_value_16_)->HasError()); + EXPECT_TRUE(storage_->Set(DEFAULTS, "c", byte_value_16_)->HasError()); EXPECT_FALSE(storage_->Clear()->HasError()); // (repeat) EXPECT_FALSE(storage_->Set(DEFAULTS, to_set)->HasError()); - EXPECT_TRUE(storage_->Set(DEFAULTS, "c", *byte_value_16_)->HasError()); + EXPECT_TRUE(storage_->Set(DEFAULTS, "c", byte_value_16_)->HasError()); } // Test reaching max keys. storage_->Clear(); { base::DictionaryValue to_set; - to_set.Set("a", byte_value_1_->DeepCopy()); - to_set.Set("b", byte_value_1_->DeepCopy()); - to_set.Set("c", byte_value_1_->DeepCopy()); - to_set.Set("d", byte_value_1_->DeepCopy()); - to_set.Set("e", byte_value_1_->DeepCopy()); + to_set.Set("a", byte_value_1_.CreateDeepCopy()); + to_set.Set("b", byte_value_1_.CreateDeepCopy()); + to_set.Set("c", byte_value_1_.CreateDeepCopy()); + to_set.Set("d", byte_value_1_.CreateDeepCopy()); + to_set.Set("e", byte_value_1_.CreateDeepCopy()); EXPECT_FALSE(storage_->Set(DEFAULTS, to_set)->HasError()); - EXPECT_TRUE(storage_->Set(DEFAULTS, "f", *byte_value_1_)->HasError()); + EXPECT_TRUE(storage_->Set(DEFAULTS, "f", byte_value_1_)->HasError()); storage_->Clear(); // (repeat) EXPECT_FALSE(storage_->Set(DEFAULTS, to_set)->HasError()); - EXPECT_TRUE(storage_->Set(DEFAULTS, "f", *byte_value_1_)->HasError()); + EXPECT_TRUE(storage_->Set(DEFAULTS, "f", byte_value_1_)->HasError()); } } @@ -306,20 +305,20 @@ CreateStorage(20, UINT_MAX, UINT_MAX); // Change a setting to make it go over quota. - storage_->Set(DEFAULTS, "a", *byte_value_16_); - settings.Set("a", byte_value_16_->DeepCopy()); + storage_->Set(DEFAULTS, "a", byte_value_16_); + settings.Set("a", byte_value_16_.CreateDeepCopy()); EXPECT_TRUE(SettingsEqual(settings)); - EXPECT_TRUE(storage_->Set(DEFAULTS, "a", *byte_value_256_)->HasError()); + EXPECT_TRUE(storage_->Set(DEFAULTS, "a", byte_value_256_)->HasError()); EXPECT_TRUE(SettingsEqual(settings)); // Change a setting to reduce usage and room for another setting. - EXPECT_TRUE(storage_->Set(DEFAULTS, "foobar", *byte_value_1_)->HasError()); - storage_->Set(DEFAULTS, "a", *byte_value_1_); - settings.Set("a", byte_value_1_->DeepCopy()); + EXPECT_TRUE(storage_->Set(DEFAULTS, "foobar", byte_value_1_)->HasError()); + storage_->Set(DEFAULTS, "a", byte_value_1_); + settings.Set("a", byte_value_1_.CreateDeepCopy()); - EXPECT_FALSE(storage_->Set(DEFAULTS, "foobar", *byte_value_1_)->HasError()); - settings.Set("foobar", byte_value_1_->DeepCopy()); + EXPECT_FALSE(storage_->Set(DEFAULTS, "foobar", byte_value_1_)->HasError()); + settings.Set("foobar", byte_value_1_.CreateDeepCopy()); EXPECT_TRUE(SettingsEqual(settings)); } @@ -327,22 +326,22 @@ base::DictionaryValue settings; CreateStorage(40, UINT_MAX, UINT_MAX); - storage_->Set(DEFAULTS, "a", *byte_value_16_); - settings.Set("a", byte_value_16_->DeepCopy()); + storage_->Set(DEFAULTS, "a", byte_value_16_); + settings.Set("a", byte_value_16_.CreateDeepCopy()); // The entire change is over quota. base::DictionaryValue to_set; - to_set.Set("b", byte_value_16_->DeepCopy()); - to_set.Set("c", byte_value_16_->DeepCopy()); + to_set.Set("b", byte_value_16_.CreateDeepCopy()); + to_set.Set("c", byte_value_16_.CreateDeepCopy()); EXPECT_TRUE(storage_->Set(DEFAULTS, to_set)->HasError()); EXPECT_TRUE(SettingsEqual(settings)); // The entire change is over quota, but quota reduced in existing key. - to_set.Set("a", byte_value_1_->DeepCopy()); + to_set.Set("a", byte_value_1_.CreateDeepCopy()); EXPECT_FALSE(storage_->Set(DEFAULTS, to_set)->HasError()); - settings.Set("a", byte_value_1_->DeepCopy()); - settings.Set("b", byte_value_16_->DeepCopy()); - settings.Set("c", byte_value_16_->DeepCopy()); + settings.Set("a", byte_value_1_.CreateDeepCopy()); + settings.Set("b", byte_value_16_.CreateDeepCopy()); + settings.Set("c", byte_value_16_.CreateDeepCopy()); EXPECT_TRUE(SettingsEqual(settings)); } @@ -350,44 +349,44 @@ base::DictionaryValue settings; CreateStorage(UINT_MAX, UINT_MAX, 2); - storage_->Set(DEFAULTS, "a", *byte_value_1_); - settings.Set("a", byte_value_1_->DeepCopy()); + storage_->Set(DEFAULTS, "a", byte_value_1_); + settings.Set("a", byte_value_1_.CreateDeepCopy()); base::DictionaryValue to_set; - to_set.Set("b", byte_value_16_->DeepCopy()); - to_set.Set("c", byte_value_16_->DeepCopy()); + to_set.Set("b", byte_value_16_.CreateDeepCopy()); + to_set.Set("c", byte_value_16_.CreateDeepCopy()); EXPECT_TRUE(storage_->Set(DEFAULTS, to_set)->HasError()); EXPECT_TRUE(SettingsEqual(settings)); } TEST_F(ExtensionSettingsQuotaTest, WithInitialDataAndByteQuota) { base::DictionaryValue settings; - delegate_->Set(DEFAULTS, "a", *byte_value_256_); - settings.Set("a", byte_value_256_->DeepCopy()); + delegate_->Set(DEFAULTS, "a", byte_value_256_); + settings.Set("a", byte_value_256_.CreateDeepCopy()); CreateStorage(280, UINT_MAX, UINT_MAX); EXPECT_TRUE(SettingsEqual(settings)); // Add some data. - EXPECT_FALSE(storage_->Set(DEFAULTS, "b", *byte_value_16_)->HasError()); - settings.Set("b", byte_value_16_->DeepCopy()); + EXPECT_FALSE(storage_->Set(DEFAULTS, "b", byte_value_16_)->HasError()); + settings.Set("b", byte_value_16_.CreateDeepCopy()); EXPECT_TRUE(SettingsEqual(settings)); // Not enough quota. - EXPECT_TRUE(storage_->Set(DEFAULTS, "c", *byte_value_16_)->HasError()); + EXPECT_TRUE(storage_->Set(DEFAULTS, "c", byte_value_16_)->HasError()); EXPECT_TRUE(SettingsEqual(settings)); // Reduce usage of original setting so that "c" can fit. - EXPECT_FALSE(storage_->Set(DEFAULTS, "a", *byte_value_16_)->HasError()); - settings.Set("a", byte_value_16_->DeepCopy()); + EXPECT_FALSE(storage_->Set(DEFAULTS, "a", byte_value_16_)->HasError()); + settings.Set("a", byte_value_16_.CreateDeepCopy()); EXPECT_TRUE(SettingsEqual(settings)); - EXPECT_FALSE(storage_->Set(DEFAULTS, "c", *byte_value_16_)->HasError()); - settings.Set("c", byte_value_16_->DeepCopy()); + EXPECT_FALSE(storage_->Set(DEFAULTS, "c", byte_value_16_)->HasError()); + settings.Set("c", byte_value_16_.CreateDeepCopy()); EXPECT_TRUE(SettingsEqual(settings)); // Remove to free up some more data. - EXPECT_TRUE(storage_->Set(DEFAULTS, "d", *byte_value_256_)->HasError()); + EXPECT_TRUE(storage_->Set(DEFAULTS, "d", byte_value_256_)->HasError()); std::vector<std::string> to_remove; to_remove.push_back("a"); @@ -397,61 +396,61 @@ settings.Remove("b", NULL); EXPECT_TRUE(SettingsEqual(settings)); - EXPECT_FALSE(storage_->Set(DEFAULTS, "d", *byte_value_256_)->HasError()); - settings.Set("d", byte_value_256_->DeepCopy()); + EXPECT_FALSE(storage_->Set(DEFAULTS, "d", byte_value_256_)->HasError()); + settings.Set("d", byte_value_256_.CreateDeepCopy()); EXPECT_TRUE(SettingsEqual(settings)); } TEST_F(ExtensionSettingsQuotaTest, WithInitialDataAndMaxKeys) { base::DictionaryValue settings; - delegate_->Set(DEFAULTS, "a", *byte_value_1_); - settings.Set("a", byte_value_1_->DeepCopy()); + delegate_->Set(DEFAULTS, "a", byte_value_1_); + settings.Set("a", byte_value_1_.CreateDeepCopy()); CreateStorage(UINT_MAX, UINT_MAX, 2); - EXPECT_FALSE(storage_->Set(DEFAULTS, "b", *byte_value_1_)->HasError()); - settings.Set("b", byte_value_1_->DeepCopy()); + EXPECT_FALSE(storage_->Set(DEFAULTS, "b", byte_value_1_)->HasError()); + settings.Set("b", byte_value_1_.CreateDeepCopy()); - EXPECT_TRUE(storage_->Set(DEFAULTS, "c", *byte_value_1_)->HasError()); + EXPECT_TRUE(storage_->Set(DEFAULTS, "c", byte_value_1_)->HasError()); EXPECT_TRUE(SettingsEqual(settings)); } TEST_F(ExtensionSettingsQuotaTest, InitiallyOverByteQuota) { base::DictionaryValue settings; - settings.Set("a", byte_value_16_->DeepCopy()); - settings.Set("b", byte_value_16_->DeepCopy()); - settings.Set("c", byte_value_16_->DeepCopy()); + settings.Set("a", byte_value_16_.CreateDeepCopy()); + settings.Set("b", byte_value_16_.CreateDeepCopy()); + settings.Set("c", byte_value_16_.CreateDeepCopy()); delegate_->Set(DEFAULTS, settings); CreateStorage(40, UINT_MAX, UINT_MAX); EXPECT_TRUE(SettingsEqual(settings)); - EXPECT_TRUE(storage_->Set(DEFAULTS, "d", *byte_value_16_)->HasError()); + EXPECT_TRUE(storage_->Set(DEFAULTS, "d", byte_value_16_)->HasError()); // Take under quota by reducing size of an existing setting - EXPECT_FALSE(storage_->Set(DEFAULTS, "a", *byte_value_1_)->HasError()); - settings.Set("a", byte_value_1_->DeepCopy()); + EXPECT_FALSE(storage_->Set(DEFAULTS, "a", byte_value_1_)->HasError()); + settings.Set("a", byte_value_1_.CreateDeepCopy()); EXPECT_TRUE(SettingsEqual(settings)); // Should be able set another small setting. - EXPECT_FALSE(storage_->Set(DEFAULTS, "d", *byte_value_1_)->HasError()); - settings.Set("d", byte_value_1_->DeepCopy()); + EXPECT_FALSE(storage_->Set(DEFAULTS, "d", byte_value_1_)->HasError()); + settings.Set("d", byte_value_1_.CreateDeepCopy()); EXPECT_TRUE(SettingsEqual(settings)); } TEST_F(ExtensionSettingsQuotaTest, InitiallyOverMaxKeys) { base::DictionaryValue settings; - settings.Set("a", byte_value_16_->DeepCopy()); - settings.Set("b", byte_value_16_->DeepCopy()); - settings.Set("c", byte_value_16_->DeepCopy()); + settings.Set("a", byte_value_16_.CreateDeepCopy()); + settings.Set("b", byte_value_16_.CreateDeepCopy()); + settings.Set("c", byte_value_16_.CreateDeepCopy()); delegate_->Set(DEFAULTS, settings); CreateStorage(UINT_MAX, UINT_MAX, 2); EXPECT_TRUE(SettingsEqual(settings)); // Can't set either an existing or new setting. - EXPECT_TRUE(storage_->Set(DEFAULTS, "d", *byte_value_16_)->HasError()); - EXPECT_TRUE(storage_->Set(DEFAULTS, "a", *byte_value_1_)->HasError()); + EXPECT_TRUE(storage_->Set(DEFAULTS, "d", byte_value_16_)->HasError()); + EXPECT_TRUE(storage_->Set(DEFAULTS, "a", byte_value_1_)->HasError()); EXPECT_TRUE(SettingsEqual(settings)); // Should be able after removing 2. @@ -461,13 +460,13 @@ settings.Remove("b", NULL); EXPECT_TRUE(SettingsEqual(settings)); - EXPECT_FALSE(storage_->Set(DEFAULTS, "e", *byte_value_1_)->HasError()); - settings.Set("e", byte_value_1_->DeepCopy()); + EXPECT_FALSE(storage_->Set(DEFAULTS, "e", byte_value_1_)->HasError()); + settings.Set("e", byte_value_1_.CreateDeepCopy()); EXPECT_TRUE(SettingsEqual(settings)); // Still can't set any. - EXPECT_TRUE(storage_->Set(DEFAULTS, "d", *byte_value_16_)->HasError()); - EXPECT_TRUE(storage_->Set(DEFAULTS, "a", *byte_value_1_)->HasError()); + EXPECT_TRUE(storage_->Set(DEFAULTS, "d", byte_value_16_)->HasError()); + EXPECT_TRUE(storage_->Set(DEFAULTS, "a", byte_value_1_)->HasError()); EXPECT_TRUE(SettingsEqual(settings)); } @@ -475,7 +474,7 @@ base::DictionaryValue empty; CreateStorage(UINT_MAX, 0, UINT_MAX); - EXPECT_TRUE(storage_->Set(DEFAULTS, "a", *byte_value_1_)->HasError()); + EXPECT_TRUE(storage_->Set(DEFAULTS, "a", byte_value_1_)->HasError()); EXPECT_FALSE(storage_->Remove("a")->HasError()); EXPECT_FALSE(storage_->Remove("b")->HasError()); EXPECT_TRUE(SettingsEqual(empty)); @@ -486,15 +485,15 @@ CreateStorage(UINT_MAX, 20, UINT_MAX); - EXPECT_FALSE(storage_->Set(DEFAULTS, "a", *byte_value_1_)->HasError()); - EXPECT_FALSE(storage_->Set(DEFAULTS, "a", *byte_value_16_)->HasError()); - settings.Set("a", byte_value_16_->DeepCopy()); - EXPECT_TRUE(storage_->Set(DEFAULTS, "a", *byte_value_256_)->HasError()); + EXPECT_FALSE(storage_->Set(DEFAULTS, "a", byte_value_1_)->HasError()); + EXPECT_FALSE(storage_->Set(DEFAULTS, "a", byte_value_16_)->HasError()); + settings.Set("a", byte_value_16_.CreateDeepCopy()); + EXPECT_TRUE(storage_->Set(DEFAULTS, "a", byte_value_256_)->HasError()); - EXPECT_FALSE(storage_->Set(DEFAULTS, "b", *byte_value_1_)->HasError()); - EXPECT_FALSE(storage_->Set(DEFAULTS, "b", *byte_value_16_)->HasError()); - settings.Set("b", byte_value_16_->DeepCopy()); - EXPECT_TRUE(storage_->Set(DEFAULTS, "b", *byte_value_256_)->HasError()); + EXPECT_FALSE(storage_->Set(DEFAULTS, "b", byte_value_1_)->HasError()); + EXPECT_FALSE(storage_->Set(DEFAULTS, "b", byte_value_16_)->HasError()); + settings.Set("b", byte_value_16_.CreateDeepCopy()); + EXPECT_TRUE(storage_->Set(DEFAULTS, "b", byte_value_256_)->HasError()); EXPECT_TRUE(SettingsEqual(settings)); } @@ -502,25 +501,25 @@ TEST_F(ExtensionSettingsQuotaTest, QuotaBytesPerSettingWithInitialSettings) { base::DictionaryValue settings; - delegate_->Set(DEFAULTS, "a", *byte_value_1_); - delegate_->Set(DEFAULTS, "b", *byte_value_16_); - delegate_->Set(DEFAULTS, "c", *byte_value_256_); + delegate_->Set(DEFAULTS, "a", byte_value_1_); + delegate_->Set(DEFAULTS, "b", byte_value_16_); + delegate_->Set(DEFAULTS, "c", byte_value_256_); CreateStorage(UINT_MAX, 20, UINT_MAX); - EXPECT_FALSE(storage_->Set(DEFAULTS, "a", *byte_value_1_)->HasError()); - EXPECT_FALSE(storage_->Set(DEFAULTS, "a", *byte_value_16_)->HasError()); - settings.Set("a", byte_value_16_->DeepCopy()); - EXPECT_TRUE(storage_->Set(DEFAULTS, "a", *byte_value_256_)->HasError()); + EXPECT_FALSE(storage_->Set(DEFAULTS, "a", byte_value_1_)->HasError()); + EXPECT_FALSE(storage_->Set(DEFAULTS, "a", byte_value_16_)->HasError()); + settings.Set("a", byte_value_16_.CreateDeepCopy()); + EXPECT_TRUE(storage_->Set(DEFAULTS, "a", byte_value_256_)->HasError()); - EXPECT_FALSE(storage_->Set(DEFAULTS, "b", *byte_value_1_)->HasError()); - EXPECT_FALSE(storage_->Set(DEFAULTS, "b", *byte_value_16_)->HasError()); - settings.Set("b", byte_value_16_->DeepCopy()); - EXPECT_TRUE(storage_->Set(DEFAULTS, "b", *byte_value_256_)->HasError()); + EXPECT_FALSE(storage_->Set(DEFAULTS, "b", byte_value_1_)->HasError()); + EXPECT_FALSE(storage_->Set(DEFAULTS, "b", byte_value_16_)->HasError()); + settings.Set("b", byte_value_16_.CreateDeepCopy()); + EXPECT_TRUE(storage_->Set(DEFAULTS, "b", byte_value_256_)->HasError()); - EXPECT_FALSE(storage_->Set(DEFAULTS, "c", *byte_value_1_)->HasError()); - EXPECT_FALSE(storage_->Set(DEFAULTS, "c", *byte_value_16_)->HasError()); - settings.Set("c", byte_value_16_->DeepCopy()); - EXPECT_TRUE(storage_->Set(DEFAULTS, "c", *byte_value_256_)->HasError()); + EXPECT_FALSE(storage_->Set(DEFAULTS, "c", byte_value_1_)->HasError()); + EXPECT_FALSE(storage_->Set(DEFAULTS, "c", byte_value_16_)->HasError()); + settings.Set("c", byte_value_16_.CreateDeepCopy()); + EXPECT_TRUE(storage_->Set(DEFAULTS, "c", byte_value_256_)->HasError()); EXPECT_TRUE(SettingsEqual(settings)); } @@ -532,27 +531,27 @@ // rejected... base::DictionaryValue settings; - delegate_->Set(DEFAULTS, "a", *byte_value_1_); - delegate_->Set(DEFAULTS, "b", *byte_value_16_); - delegate_->Set(DEFAULTS, "c", *byte_value_256_); + delegate_->Set(DEFAULTS, "a", byte_value_1_); + delegate_->Set(DEFAULTS, "b", byte_value_16_); + delegate_->Set(DEFAULTS, "c", byte_value_256_); CreateStorage(UINT_MAX, 20, UINT_MAX); - EXPECT_FALSE(storage_->Set(IGNORE_QUOTA, "a", *byte_value_1_)->HasError()); - EXPECT_FALSE(storage_->Set(IGNORE_QUOTA, "a", *byte_value_16_)->HasError()); - EXPECT_FALSE(storage_->Set(IGNORE_QUOTA, "a", *byte_value_256_)->HasError()); - settings.Set("a", byte_value_256_->DeepCopy()); + EXPECT_FALSE(storage_->Set(IGNORE_QUOTA, "a", byte_value_1_)->HasError()); + EXPECT_FALSE(storage_->Set(IGNORE_QUOTA, "a", byte_value_16_)->HasError()); + EXPECT_FALSE(storage_->Set(IGNORE_QUOTA, "a", byte_value_256_)->HasError()); + settings.Set("a", byte_value_256_.CreateDeepCopy()); - EXPECT_FALSE(storage_->Set(IGNORE_QUOTA, "b", *byte_value_1_)->HasError()); - EXPECT_FALSE(storage_->Set(IGNORE_QUOTA, "b", *byte_value_16_)->HasError()); - EXPECT_FALSE(storage_->Set(IGNORE_QUOTA, "b", *byte_value_256_)->HasError()); - settings.Set("b", byte_value_256_->DeepCopy()); + EXPECT_FALSE(storage_->Set(IGNORE_QUOTA, "b", byte_value_1_)->HasError()); + EXPECT_FALSE(storage_->Set(IGNORE_QUOTA, "b", byte_value_16_)->HasError()); + EXPECT_FALSE(storage_->Set(IGNORE_QUOTA, "b", byte_value_256_)->HasError()); + settings.Set("b", byte_value_256_.CreateDeepCopy()); - EXPECT_FALSE(storage_->Set(IGNORE_QUOTA, "c", *byte_value_1_)->HasError()); - EXPECT_FALSE(storage_->Set(IGNORE_QUOTA, "c", *byte_value_16_)->HasError()); - settings.Set("c", byte_value_16_->DeepCopy()); + EXPECT_FALSE(storage_->Set(IGNORE_QUOTA, "c", byte_value_1_)->HasError()); + EXPECT_FALSE(storage_->Set(IGNORE_QUOTA, "c", byte_value_16_)->HasError()); + settings.Set("c", byte_value_16_.CreateDeepCopy()); // ... except the last. Make sure it can still fail. - EXPECT_TRUE(storage_->Set(DEFAULTS, "c", *byte_value_256_)->HasError()); + EXPECT_TRUE(storage_->Set(DEFAULTS, "c", byte_value_256_)->HasError()); EXPECT_TRUE(SettingsEqual(settings)); } @@ -570,21 +569,21 @@ EXPECT_EQ(0u, storage_->GetBytesInUse("b")); EXPECT_EQ(0u, storage_->GetBytesInUse(ab)); - storage_->Set(DEFAULTS, "a", *byte_value_1_); + storage_->Set(DEFAULTS, "a", byte_value_1_); EXPECT_EQ(2u, storage_->GetBytesInUse()); EXPECT_EQ(2u, storage_->GetBytesInUse("a")); EXPECT_EQ(0u, storage_->GetBytesInUse("b")); EXPECT_EQ(2u, storage_->GetBytesInUse(ab)); - storage_->Set(DEFAULTS, "b", *byte_value_1_); + storage_->Set(DEFAULTS, "b", byte_value_1_); EXPECT_EQ(4u, storage_->GetBytesInUse()); EXPECT_EQ(2u, storage_->GetBytesInUse("a")); EXPECT_EQ(2u, storage_->GetBytesInUse("b")); EXPECT_EQ(4u, storage_->GetBytesInUse(ab)); - storage_->Set(DEFAULTS, "c", *byte_value_1_); + storage_->Set(DEFAULTS, "c", byte_value_1_); EXPECT_EQ(6u, storage_->GetBytesInUse()); EXPECT_EQ(2u, storage_->GetBytesInUse("a"));
diff --git a/extensions/browser/api/storage/settings_storage_quota_enforcer.cc b/extensions/browser/api/storage/settings_storage_quota_enforcer.cc index e448a5d..1fbcbbd 100644 --- a/extensions/browser/api/storage/settings_storage_quota_enforcer.cc +++ b/extensions/browser/api/storage/settings_storage_quota_enforcer.cc
@@ -38,7 +38,7 @@ // TODO(kalman): This is duplicating work that the leveldb delegate // implementation is about to do, and it would be nice to avoid this. std::string value_as_json; - base::JSONWriter::Write(&value, &value_as_json); + base::JSONWriter::Write(value, &value_as_json); size_t new_size = key.size() + value_as_json.size(); size_t existing_size = (*used_per_setting)[key];
diff --git a/extensions/browser/api/web_request/web_request_api.cc b/extensions/browser/api/web_request/web_request_api.cc index 7de492e..f6c7527 100644 --- a/extensions/browser/api/web_request/web_request_api.cc +++ b/extensions/browser/api/web_request/web_request_api.cc
@@ -2374,7 +2374,7 @@ headers_value->GetDictionary(i, &header_value)); if (!FromHeaderDictionary(header_value, &name, &value)) { std::string serialized_header; - base::JSONWriter::Write(header_value, &serialized_header); + base::JSONWriter::Write(*header_value, &serialized_header); RespondWithError(event_name, sub_event_name, request_id,
diff --git a/extensions/browser/browser_context_keyed_api_factory.h b/extensions/browser/browser_context_keyed_api_factory.h index dfd2887..fc0add24 100644 --- a/extensions/browser/browser_context_keyed_api_factory.h +++ b/extensions/browser/browser_context_keyed_api_factory.h
@@ -43,9 +43,9 @@ static const bool kServiceIsNULLWhileTesting = false; // Users of this factory template must define a GetFactoryInstance() - // and manage their own instances (typically using LazyInstance or - // Singleton), because those cannot be included in more than one - // translation unit (and thus cannot be initialized in a header file). + // and manage their own instances (using LazyInstance), because those cannot + // be included in more than one translation unit (and thus cannot be + // initialized in a header file). // // In the header file, declare GetFactoryInstance(), e.g.: // class HistoryAPI {
diff --git a/extensions/browser/computed_hashes.cc b/extensions/browser/computed_hashes.cc index 473ee3c..35ea5255 100644 --- a/extensions/browser/computed_hashes.cc +++ b/extensions/browser/computed_hashes.cc
@@ -156,7 +156,7 @@ top_dictionary.SetInteger(kVersionKey, kVersion); top_dictionary.Set(kFileHashesKey, file_list_.release()); - if (!base::JSONWriter::Write(&top_dictionary, &json)) + if (!base::JSONWriter::Write(top_dictionary, &json)) return false; int written = base::WriteFile(path, json.data(), json.size()); if (static_cast<unsigned>(written) != json.size()) {
diff --git a/extensions/browser/event_router.cc b/extensions/browser/event_router.cc index 365cd2f..afd92d03 100644 --- a/extensions/browser/event_router.cc +++ b/extensions/browser/event_router.cc
@@ -155,14 +155,21 @@ const EventFilteringInfo& info) { int event_id = g_extension_event_id.GetNext(); + if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { + // This is called from WebRequest API. + // TODO(lazyboy): Skip this entirely: http://crbug.com/488747. + BrowserThread::PostTask( + BrowserThread::UI, FROM_HERE, + base::Bind(&EventRouter::IncrementInFlightEventsOnUI, + browser_context_id, extension_id, event_id, event_name)); + } else { + IncrementInFlightEventsOnUI(browser_context_id, extension_id, event_id, + event_name); + } + DispatchExtensionMessage(ipc_sender, browser_context_id, extension_id, event_id, event_name, event_args.get(), user_gesture, info); - - BrowserThread::PostTask( - BrowserThread::UI, FROM_HERE, - base::Bind(&EventRouter::IncrementInFlightEventsOnUI, browser_context_id, - extension_id, event_id, event_name)); } EventRouter::EventRouter(BrowserContext* browser_context,
diff --git a/extensions/browser/extension_function_histogram_value.h b/extensions/browser/extension_function_histogram_value.h index 9839de0..8a7081c0 100644 --- a/extensions/browser/extension_function_histogram_value.h +++ b/extensions/browser/extension_function_histogram_value.h
@@ -1068,7 +1068,7 @@ DEVELOPERPRIVATE_SHOWOPTIONS, DEVELOPERPRIVATE_SHOWPATH, FILEMANAGERPRIVATE_ADDPROVIDEDFILESYSTEM, - FILEMANAGERPRIVATE_CONFIGUREPROVIDEDFILESYSTEM, + FILEMANAGERPRIVATE_CONFIGUREVOLUME, SEARCHENGINESPRIVATE_GETSEARCHENGINES, SEARCHENGINESPRIVATE_SETSELECTEDSEARCHENGINE, AUTOFILLPRIVATE_SAVEADDRESS, @@ -1098,6 +1098,7 @@ PASSWORDSPRIVATE_REMOVESAVEDPASSWORD, PASSWORDSPRIVATE_REMOVEPASSWORDEXCEPTION, PASSWORDSPRIVATE_GETPLAINTEXTPASSWORD, + LAUNCHERPAGE_HIDE, // Last entry: Add new entries above and ensure to update // tools/metrics/histograms/histograms.xml. ENUM_BOUNDARY
diff --git a/extensions/browser/guest_view/web_view/web_view_guest.cc b/extensions/browser/guest_view/web_view/web_view_guest.cc index 11aad86..43f68b9 100644 --- a/extensions/browser/guest_view/web_view/web_view_guest.cc +++ b/extensions/browser/guest_view/web_view/web_view_guest.cc
@@ -330,8 +330,6 @@ content::NOTIFICATION_RESOURCE_RECEIVED_REDIRECT, content::Source<WebContents>(web_contents())); - if (web_view_guest_delegate_) - web_view_guest_delegate_->OnDidInitialize(); AttachWebViewHelpers(web_contents()); rules_registry_id_ = GetOrGenerateRulesRegistryID( @@ -786,11 +784,6 @@ new GuestViewEvent(webview::kEventLoadCommit, args.Pass())); find_helper_.CancelAllFindSessions(); - - if (web_view_guest_delegate_) { - web_view_guest_delegate_->OnDidCommitProvisionalLoadForFrame( - !render_frame_host->GetParent()); - } } void WebViewGuest::DidFailProvisionalLoad( @@ -814,12 +807,6 @@ new GuestViewEvent(webview::kEventLoadStart, args.Pass())); } -void WebViewGuest::DocumentLoadedInFrame( - content::RenderFrameHost* render_frame_host) { - if (web_view_guest_delegate_) - web_view_guest_delegate_->OnDocumentLoadedInFrame(render_frame_host); -} - void WebViewGuest::RenderProcessGone(base::TerminationStatus status) { // Cancel all find sessions in progress. find_helper_.CancelAllFindSessions();
diff --git a/extensions/browser/guest_view/web_view/web_view_guest.h b/extensions/browser/guest_view/web_view/web_view_guest.h index dcfd378a79..9260b74 100644 --- a/extensions/browser/guest_view/web_view/web_view_guest.h +++ b/extensions/browser/guest_view/web_view/web_view_guest.h
@@ -295,8 +295,6 @@ const GURL& validated_url, bool is_error_page, bool is_iframe_srcdoc) override; - void DocumentLoadedInFrame( - content::RenderFrameHost* render_frame_host) override; void RenderProcessGone(base::TerminationStatus status) override; void UserAgentOverrideSet(const std::string& user_agent) override; void FrameNameChanged(content::RenderFrameHost* render_frame_host,
diff --git a/extensions/browser/guest_view/web_view/web_view_guest_delegate.h b/extensions/browser/guest_view/web_view/web_view_guest_delegate.h index b6e0f1a9..0ab06150 100644 --- a/extensions/browser/guest_view/web_view/web_view_guest_delegate.h +++ b/extensions/browser/guest_view/web_view/web_view_guest_delegate.h
@@ -38,15 +38,6 @@ // Called to attach helpers just after additional initialization is performed. virtual void OnAttachWebViewHelpers(content::WebContents* contents) = 0; - // Called when the guest WebContents commits a provisional load in any frame. - virtual void OnDidCommitProvisionalLoadForFrame(bool is_main_frame) = 0; - - // Called just after additional initialization is performed. - virtual void OnDidInitialize() = 0; - - virtual void OnDocumentLoadedInFrame( - content::RenderFrameHost* render_frame_host) = 0; - // Called immediately after the guest WebContents has been destroyed. virtual void OnGuestDestroyed() = 0;
diff --git a/extensions/browser/user_script_loader.cc b/extensions/browser/user_script_loader.cc index 7daf95d2..44070930 100644 --- a/extensions/browser/user_script_loader.cc +++ b/extensions/browser/user_script_loader.cc
@@ -378,9 +378,9 @@ void UserScriptLoader::SendUpdate(content::RenderProcessHost* process, base::SharedMemory* shared_memory, const std::set<HostID>& changed_hosts) { - // Don't allow injection of extensions' content scripts into <webview>. - if (process->IsIsolatedGuest() && host_id().id().empty()) - return; + // Don't allow injection of non-whitelisted extensions' content scripts + // into <webview>. + bool whitelisted_only = process->IsIsolatedGuest() && host_id().id().empty(); // Make sure we only send user scripts to processes in our browser_context. if (!ExtensionsBrowserClient::Get()->IsSameContext( @@ -398,8 +398,8 @@ return; // This can legitimately fail if the renderer asserts at startup. if (base::SharedMemory::IsHandleValid(handle_for_process)) { - process->Send(new ExtensionMsg_UpdateUserScripts(handle_for_process, - host_id(), changed_hosts)); + process->Send(new ExtensionMsg_UpdateUserScripts( + handle_for_process, host_id(), changed_hosts, whitelisted_only)); } }
diff --git a/extensions/browser/value_store/leveldb_value_store.cc b/extensions/browser/value_store/leveldb_value_store.cc index ad8076d..4b7d274e 100644 --- a/extensions/browser/value_store/leveldb_value_store.cc +++ b/extensions/browser/value_store/leveldb_value_store.cc
@@ -389,7 +389,7 @@ if (write_new_value) { std::string value_as_json; - if (!base::JSONWriter::Write(&value, &value_as_json)) + if (!base::JSONWriter::Write(value, &value_as_json)) return Error::Create(OTHER_ERROR, kCannotSerialize, util::NewKey(key)); batch->Put(key, value_as_json); }
diff --git a/extensions/browser/value_store/value_store_change.cc b/extensions/browser/value_store/value_store_change.cc index 822c9b9..904ec82 100644 --- a/extensions/browser/value_store/value_store_change.cc +++ b/extensions/browser/value_store/value_store_change.cc
@@ -23,7 +23,7 @@ changes_value.SetWithoutPathExpansion(it->key(), change_value); } std::string json; - base::JSONWriter::Write(&changes_value, &json); + base::JSONWriter::Write(changes_value, &json); return json; }
diff --git a/extensions/browser/value_store/value_store_unittest.cc b/extensions/browser/value_store/value_store_unittest.cc index 4293459a..c2ecbab5 100644 --- a/extensions/browser/value_store/value_store_unittest.cc +++ b/extensions/browser/value_store/value_store_unittest.cc
@@ -18,9 +18,8 @@ // Gets the pretty-printed JSON for a value. std::string GetJSON(const base::Value& value) { std::string json; - base::JSONWriter::WriteWithOptions(&value, - base::JSONWriter::OPTIONS_PRETTY_PRINT, - &json); + base::JSONWriter::WriteWithOptions( + value, base::JSONWriter::OPTIONS_PRETTY_PRINT, &json); return json; }
diff --git a/extensions/common/api/_behavior_features.json b/extensions/common/api/_behavior_features.json index 7d5e923..9c81f727 100644 --- a/extensions/common/api/_behavior_features.json +++ b/extensions/common/api/_behavior_features.json
@@ -24,7 +24,8 @@ "platforms": ["chromeos"], "whitelist": [ "307E96539209F95A1A8740C713E6998A73657D96", // http://crbug.com/485292 - "81986D4F846CEDDDB962643FA501D1780DD441BB" // http://crbug.com/485292 + "81986D4F846CEDDDB962643FA501D1780DD441BB", // http://crbug.com/485292 + "9E287A8257E58EFB13E89C86A4B75A3AC4B058D8" // http://crbug.com/485292 ] }, "whitelisted_for_incognito": {
diff --git a/extensions/common/api/_permission_features.json b/extensions/common/api/_permission_features.json index 03116b8..2897a81 100644 --- a/extensions/common/api/_permission_features.json +++ b/extensions/common/api/_permission_features.json
@@ -260,7 +260,7 @@ "extension_types": [ "extension", "legacy_packaged_app", "platform_app" ] }, "printerProvider": { - "channel": "dev", + "channel": "stable", "extension_types": ["extension", "platform_app" ] }, // Note: runtime is not actually a permission, but some systems check these
diff --git a/extensions/common/api/virtual_keyboard_private.json b/extensions/common/api/virtual_keyboard_private.json index 71bdd0e..f8dd8268e2 100644 --- a/extensions/common/api/virtual_keyboard_private.json +++ b/extensions/common/api/virtual_keyboard_private.json
@@ -39,7 +39,17 @@ "type": "string", "description": "The value of type attribute of the focused text input box.", "enum": ["text", "number", "password", "date", "url", "tel", "email"] - } + }, + { + "id": "Bounds", + "type": "object", + "properties": { + "left": {"type": "integer", "description": "The position of the virtual keyboard window's left edge."}, + "top": {"type": "integer", "description": "The position of the virtual keyboard window's top edge."}, + "width": {"type": "integer", "description": "The width of the virtual keyboard window."}, + "height": {"type": "integer", "description": "The height of the virtual keyboard window."} + } + } ], "functions": [ { @@ -208,6 +218,18 @@ } } ] + }, + { + "name": "onBoundsChanged", + "type": "function", + "description": "This event is sent when virtual keyboard bounds changed and overscroll/resize is enabled.", + "parameters": [ + { + "name": "bounds", + "description": "The virtual keyboard bounds", + "$ref": "Bounds" + } + ] } ] }
diff --git a/extensions/common/extension_messages.h b/extensions/common/extension_messages.h index 73adbcd20..5dc4981 100644 --- a/extensions/common/extension_messages.h +++ b/extensions/common/extension_messages.h
@@ -457,10 +457,13 @@ // region will be updated. Note that the empty set => all hosts case is not // supported for per-extension programmatically-defined script regions; in such // regions, the owner is expected to list itself as the only changed host. -IPC_MESSAGE_CONTROL3(ExtensionMsg_UpdateUserScripts, +// If |whitelisted_only| is true, this process should only run whitelisted +// scripts and not all user scripts. +IPC_MESSAGE_CONTROL4(ExtensionMsg_UpdateUserScripts, base::SharedMemoryHandle, HostID /* owner */, - std::set<HostID> /* changed hosts */) + std::set<HostID> /* changed hosts */, + bool /* whitelisted_only */) // Trigger to execute declarative content script under browser control. IPC_MESSAGE_ROUTED4(ExtensionMsg_ExecuteDeclarativeScript,
diff --git a/extensions/common/permissions/manifest_permission.cc b/extensions/common/permissions/manifest_permission.cc index a3a3a09..6be6b18 100644 --- a/extensions/common/permissions/manifest_permission.cc +++ b/extensions/common/permissions/manifest_permission.cc
@@ -48,7 +48,7 @@ void ManifestPermission::Log(std::string* log) const { base::JSONWriter::WriteWithOptions( - ToValue().get(), base::JSONWriter::OPTIONS_PRETTY_PRINT, log); + *ToValue(), base::JSONWriter::OPTIONS_PRETTY_PRINT, log); } } // namespace extensions
diff --git a/extensions/common/permissions/set_disjunction_permission.h b/extensions/common/permissions/set_disjunction_permission.h index 87d1858..28b6867 100644 --- a/extensions/common/permissions/set_disjunction_permission.h +++ b/extensions/common/permissions/set_disjunction_permission.h
@@ -122,7 +122,7 @@ data_set_.insert(data); } else { std::string unknown_permission; - base::JSONWriter::Write(item_value, &unknown_permission); + base::JSONWriter::Write(*item_value, &unknown_permission); if (unhandled_permissions) { unhandled_permissions->push_back(unknown_permission); } else {
diff --git a/extensions/common/value_builder.cc b/extensions/common/value_builder.cc index 3d8c2890..4011e70 100644 --- a/extensions/common/value_builder.cc +++ b/extensions/common/value_builder.cc
@@ -20,7 +20,7 @@ std::string DictionaryBuilder::ToJSON() const { std::string json; base::JSONWriter::WriteWithOptions( - dict_.get(), base::JSONWriter::OPTIONS_PRETTY_PRINT, &json); + *dict_, base::JSONWriter::OPTIONS_PRETTY_PRINT, &json); return json; }
diff --git a/extensions/extensions.gypi b/extensions/extensions.gypi index 7985f28..f90e9a2 100644 --- a/extensions/extensions.gypi +++ b/extensions/extensions.gypi
@@ -264,6 +264,8 @@ 'browser/api/bluetooth/bluetooth_extension_function.h', 'browser/api/bluetooth/bluetooth_private_api.cc', 'browser/api/bluetooth/bluetooth_private_api.h', + 'browser/api/bluetooth_low_energy/bluetooth_api_advertisement.cc', + 'browser/api/bluetooth_low_energy/bluetooth_api_advertisement.h', 'browser/api/bluetooth_low_energy/bluetooth_low_energy_api.cc', 'browser/api/bluetooth_low_energy/bluetooth_low_energy_api.h', 'browser/api/bluetooth_low_energy/bluetooth_low_energy_connection.cc',
diff --git a/extensions/renderer/messaging_bindings.cc b/extensions/renderer/messaging_bindings.cc index b4b315b..595bee1 100644 --- a/extensions/renderer/messaging_bindings.cc +++ b/extensions/renderer/messaging_bindings.cc
@@ -10,7 +10,9 @@ #include "base/basictypes.h" #include "base/bind.h" #include "base/bind_helpers.h" +#include "base/callback.h" #include "base/lazy_instance.h" +#include "base/memory/weak_ptr.h" #include "base/message_loop/message_loop.h" #include "base/values.h" #include "components/guest_view/common/guest_view_constants.h" @@ -51,6 +53,72 @@ namespace { +// Binds |callback| to run when |object| is garbage collected. So as to not +// re-entrantly call into v8, we execute this function asynchronously, at +// which point |context| may have been invalidated. If so, |callback| is not +// run, and |fallback| will be called instead. +// +// Deletes itself when the object args[0] is garbage collected or when the +// context is invalidated. +class GCCallback : public base::SupportsWeakPtr<GCCallback> { + public: + GCCallback(ScriptContext* context, + const v8::Local<v8::Object>& object, + const v8::Local<v8::Function>& callback, + const base::Closure& fallback) + : context_(context), + object_(context->isolate(), object), + callback_(context->isolate(), callback), + fallback_(fallback) { + object_.SetWeak(this, FirstWeakCallback, v8::WeakCallbackType::kParameter); + context->AddInvalidationObserver( + base::Bind(&GCCallback::OnContextInvalidated, AsWeakPtr())); + } + + private: + static void FirstWeakCallback(const v8::WeakCallbackInfo<GCCallback>& data) { + // v8 says we need to explicitly reset weak handles from their callbacks. + // It's not implicit as one might expect. + data.GetParameter()->object_.Reset(); + data.SetSecondPassCallback(SecondWeakCallback); + } + + static void SecondWeakCallback(const v8::WeakCallbackInfo<GCCallback>& data) { + base::MessageLoop::current()->PostTask( + FROM_HERE, + base::Bind(&GCCallback::RunCallback, data.GetParameter()->AsWeakPtr())); + } + + void RunCallback() { + CHECK(context_); + v8::Isolate* isolate = context_->isolate(); + v8::HandleScope handle_scope(isolate); + context_->CallFunction(v8::Local<v8::Function>::New(isolate, callback_)); + delete this; + } + + void OnContextInvalidated() { + fallback_.Run(); + context_ = NULL; + delete this; + } + + // ScriptContext which owns this GCCallback. + ScriptContext* context_; + + // Holds a global handle to the object this GCCallback is bound to. + v8::Global<v8::Object> object_; + + // Function to run when |object_| bound to this GCCallback is GC'd. + v8::Global<v8::Function> callback_; + + // Function to run if context is invalidated before we have a chance + // to execute |callback_|. + base::Closure fallback_; + + DISALLOW_COPY_AND_ASSIGN(GCCallback); +}; + struct ExtensionData { struct PortData { int ref_count; // how many contexts have a handle to this port @@ -81,7 +149,9 @@ class ExtensionImpl : public ObjectBackedNativeHandler { public: ExtensionImpl(Dispatcher* dispatcher, ScriptContext* context) - : ObjectBackedNativeHandler(context), dispatcher_(dispatcher) { + : ObjectBackedNativeHandler(context), + dispatcher_(dispatcher), + weak_ptr_factory_(this) { RouteFunction( "CloseChannel", base::Bind(&ExtensionImpl::CloseChannel, base::Unretained(this))); @@ -166,10 +236,13 @@ // the other end of the channel. void PortRelease(const v8::FunctionCallbackInfo<v8::Value>& args) { // Arguments are (int32 port_id). - CHECK_EQ(1, args.Length()); - CHECK(args[0]->IsInt32()); + CHECK(args.Length() == 1 && args[0]->IsInt32()); + ReleasePort(args[0]->Int32Value()); + } - int port_id = args[0]->Int32Value(); + // Implementation of both the PortRelease native handler call, and callback + // when contexts are invalidated to release their ports. + void ReleasePort(int port_id) { if (HasPortData(port_id) && --GetPortData(port_id).ref_count == 0) { // Send via the RenderThread because the RenderFrame might be closing. content::RenderThread::Get()->Send( @@ -178,75 +251,33 @@ } } - // Holds a |callback| to run sometime after |object| is GC'ed. |callback| will - // not be executed re-entrantly to avoid running JS in an unexpected state. - class GCCallback { - public: - static void Bind(v8::Local<v8::Object> object, - v8::Local<v8::Function> callback, - v8::Isolate* isolate) { - GCCallback* cb = new GCCallback(object, callback, isolate); - cb->object_.SetWeak(cb, FirstWeakCallback, - v8::WeakCallbackType::kParameter); - } - - private: - static void FirstWeakCallback( - const v8::WeakCallbackInfo<GCCallback>& data) { - // v8 says we need to explicitly reset weak handles from their callbacks. - // It's not implicit as one might expect. - data.GetParameter()->object_.Reset(); - data.SetSecondPassCallback(SecondWeakCallback); - } - - static void SecondWeakCallback( - const v8::WeakCallbackInfo<GCCallback>& data) { - base::MessageLoop::current()->PostTask( - FROM_HERE, - base::Bind(&GCCallback::RunCallback, - base::Owned(data.GetParameter()))); - } - - GCCallback(v8::Local<v8::Object> object, - v8::Local<v8::Function> callback, - v8::Isolate* isolate) - : object_(isolate, object), - callback_(isolate, callback), - isolate_(isolate) {} - - void RunCallback() { - v8::HandleScope handle_scope(isolate_); - v8::Local<v8::Function> callback = - v8::Local<v8::Function>::New(isolate_, callback_); - v8::Local<v8::Context> context = callback->CreationContext(); - if (context.IsEmpty()) - return; - v8::Context::Scope context_scope(context); - blink::WebScopedMicrotaskSuppression suppression; - callback->Call(context->Global(), 0, NULL); - } - - v8::Global<v8::Object> object_; - v8::Global<v8::Function> callback_; - v8::Isolate* isolate_; - - DISALLOW_COPY_AND_ASSIGN(GCCallback); - }; - - // void BindToGC(object, callback) + // void BindToGC(object, callback, port_id) // // Binds |callback| to be invoked *sometime after* |object| is garbage // collected. We don't call the method re-entrantly so as to avoid executing - // JS in some bizarro undefined mid-GC state. + // JS in some bizarro undefined mid-GC state, nor do we then call into the + // script context if it's been invalidated. + // + // If the script context *is* invalidated in the meantime, as a slight hack, + // release the port with ID |port_id| if it's >= 0. void BindToGC(const v8::FunctionCallbackInfo<v8::Value>& args) { - CHECK(args.Length() == 2 && args[0]->IsObject() && args[1]->IsFunction()); - GCCallback::Bind(args[0].As<v8::Object>(), - args[1].As<v8::Function>(), - args.GetIsolate()); + CHECK(args.Length() == 3 && args[0]->IsObject() && args[1]->IsFunction() && + args[2]->IsInt32()); + int port_id = args[2]->Int32Value(); + base::Closure fallback = base::Bind(&base::DoNothing); + if (port_id >= 0) { + fallback = base::Bind(&ExtensionImpl::ReleasePort, + weak_ptr_factory_.GetWeakPtr(), port_id); + } + // Destroys itself when the object is GC'd or context is invalidated. + new GCCallback(context(), args[0].As<v8::Object>(), + args[1].As<v8::Function>(), fallback); } // Dispatcher handle. Not owned. Dispatcher* dispatcher_; + + base::WeakPtrFactory<ExtensionImpl> weak_ptr_factory_; }; void DispatchOnConnectToScriptContext(
diff --git a/extensions/renderer/resources/guest_view/web_view/web_view_action_requests.js b/extensions/renderer/resources/guest_view/web_view/web_view_action_requests.js index e58e620d..f5be50a 100644 --- a/extensions/renderer/resources/guest_view/web_view/web_view_action_requests.js +++ b/extensions/renderer/resources/guest_view/web_view/web_view_action_requests.js
@@ -66,7 +66,8 @@ if (defaultPrevented) { // Track the lifetime of |request| with the garbage collector. - MessagingNatives.BindToGC(request, this.defaultAction.bind(this)); + var portId = -1; // (hack) there is no Extension Port to release + MessagingNatives.BindToGC(request, this.defaultAction.bind(this), portId); } else { this.defaultAction(); }
diff --git a/extensions/renderer/resources/messaging.js b/extensions/renderer/resources/messaging.js index 7a5c9104..e39795b 100644 --- a/extensions/renderer/resources/messaging.js +++ b/extensions/renderer/resources/messaging.js
@@ -179,12 +179,18 @@ // doesn't keep a reference to it, we need to clean up the port. Do // so by attaching to the garbage collection of the responseCallback // using some native hackery. + // + // If the context is destroyed before this has a chance to execute, + // BindToGC knows to release |portId| (important for updating C++ state + // both in this renderer and on the other end). We don't need to clear + // any JavaScript state, as calling destroy_() would usually do - but + // the context has been destroyed, so there isn't any JS state to clear. messagingNatives.BindToGC(responseCallback, function() { if (port) { privates(port).impl.destroy_(); port = null; } - }); + }, portId); var rv = requestEvent.dispatch(request, sender, responseCallback); if (isSendMessage) { responseCallbackPreserved =
diff --git a/extensions/renderer/script_context.cc b/extensions/renderer/script_context.cc index f384f0c..ac87f70 100644 --- a/extensions/renderer/script_context.cc +++ b/extensions/renderer/script_context.cc
@@ -176,7 +176,7 @@ } v8::Local<v8::Value> ScriptContext::CallFunction( - v8::Local<v8::Function> function, + const v8::Local<v8::Function>& function, int argc, v8::Local<v8::Value> argv[]) const { v8::EscapableHandleScope handle_scope(isolate()); @@ -196,6 +196,11 @@ function, global, argc, argv))); } +v8::Local<v8::Value> ScriptContext::CallFunction( + const v8::Local<v8::Function>& function) const { + return CallFunction(function, 0, nullptr); +} + Feature::Availability ScriptContext::GetAvailability( const std::string& api_name) { // Hack: Hosted apps should have the availability of messaging APIs based on
diff --git a/extensions/renderer/script_context.h b/extensions/renderer/script_context.h index 73579b9..012f11f7 100644 --- a/extensions/renderer/script_context.h +++ b/extensions/renderer/script_context.h
@@ -108,9 +108,11 @@ // must do that if they want. // // USE THIS METHOD RATHER THAN v8::Function::Call WHEREVER POSSIBLE. - v8::Local<v8::Value> CallFunction(v8::Local<v8::Function> function, + v8::Local<v8::Value> CallFunction(const v8::Local<v8::Function>& function, int argc, v8::Local<v8::Value> argv[]) const; + v8::Local<v8::Value> CallFunction( + const v8::Local<v8::Function>& function) const; void DispatchEvent(const char* event_name, v8::Local<v8::Array> args) const;
diff --git a/extensions/renderer/user_script_set.cc b/extensions/renderer/user_script_set.cc index 58e9de1..929c017 100644 --- a/extensions/renderer/user_script_set.cc +++ b/extensions/renderer/user_script_set.cc
@@ -9,6 +9,7 @@ #include "content/public/renderer/render_thread.h" #include "extensions/common/extension.h" #include "extensions/common/extension_set.h" +#include "extensions/common/extensions_client.h" #include "extensions/common/permissions/permissions_data.h" #include "extensions/renderer/extension_injection_host.h" #include "extensions/renderer/extensions_renderer_client.h" @@ -86,7 +87,8 @@ } bool UserScriptSet::UpdateUserScripts(base::SharedMemoryHandle shared_memory, - const std::set<HostID>& changed_hosts) { + const std::set<HostID>& changed_hosts, + bool whitelisted_only) { bool only_inject_incognito = ExtensionsRendererClient::Get()->IsIncognitoProcess(); @@ -140,6 +142,13 @@ if (only_inject_incognito && !script->is_incognito_enabled()) continue; // This script shouldn't run in an incognito tab. + const Extension* extension = extensions_->GetByID(script->extension_id()); + if (whitelisted_only && + (!extension || + !PermissionsData::CanExecuteScriptEverywhere(extension))) { + continue; + } + scripts_.push_back(script.release()); }
diff --git a/extensions/renderer/user_script_set.h b/extensions/renderer/user_script_set.h index a371a94d..5ce5152 100644 --- a/extensions/renderer/user_script_set.h +++ b/extensions/renderer/user_script_set.h
@@ -68,7 +68,8 @@ // Updates scripts given the shared memory region containing user scripts. // Returns true if the scripts were successfully updated. bool UpdateUserScripts(base::SharedMemoryHandle shared_memory, - const std::set<HostID>& changed_hosts); + const std::set<HostID>& changed_hosts, + bool whitelisted_only); const std::vector<UserScript*>& scripts() const { return scripts_.get(); }
diff --git a/extensions/renderer/user_script_set_manager.cc b/extensions/renderer/user_script_set_manager.cc index 5a317a14..1c8f72d 100644 --- a/extensions/renderer/user_script_set_manager.cc +++ b/extensions/renderer/user_script_set_manager.cc
@@ -96,7 +96,8 @@ void UserScriptSetManager::OnUpdateUserScripts( base::SharedMemoryHandle shared_memory, const HostID& host_id, - const std::set<HostID>& changed_hosts) { + const std::set<HostID>& changed_hosts, + bool whitelisted_only) { if (!base::SharedMemory::IsHandleValid(shared_memory)) { NOTREACHED() << "Bad scripts handle"; return; @@ -147,7 +148,9 @@ effective_hosts = &all_hosts; } - if (scripts->UpdateUserScripts(shared_memory, *effective_hosts)) { + if (scripts->UpdateUserScripts(shared_memory, + *effective_hosts, + whitelisted_only)) { FOR_EACH_OBSERVER( Observer, observers_,
diff --git a/extensions/renderer/user_script_set_manager.h b/extensions/renderer/user_script_set_manager.h index 49e547a3..02d22efc 100644 --- a/extensions/renderer/user_script_set_manager.h +++ b/extensions/renderer/user_script_set_manager.h
@@ -91,7 +91,8 @@ // Handle the UpdateUserScripts extension message. void OnUpdateUserScripts(base::SharedMemoryHandle shared_memory, const HostID& host_id, - const std::set<HostID>& changed_hosts); + const std::set<HostID>& changed_hosts, + bool whitelisted_only); // Scripts statically defined in extension manifests. UserScriptSet static_scripts_;
diff --git a/google_apis/drive/drive_api_requests.cc b/google_apis/drive/drive_api_requests.cc index 5cd289a..57a3ec1 100644 --- a/google_apis/drive/drive_api_requests.cc +++ b/google_apis/drive/drive_api_requests.cc
@@ -130,7 +130,7 @@ AttachProperties(properties, &root); std::string json_string; - base::JSONWriter::Write(&root, &json_string); + base::JSONWriter::Write(root, &json_string); return json_string; } @@ -417,7 +417,7 @@ root.SetString("title", title_); AttachProperties(properties_, &root); - base::JSONWriter::Write(&root, upload_content); + base::JSONWriter::Write(root, upload_content); DVLOG(1) << "FilesInsert data: " << *upload_content_type << ", [" << *upload_content << "]"; @@ -491,7 +491,7 @@ } AttachProperties(properties_, &root); - base::JSONWriter::Write(&root, upload_content); + base::JSONWriter::Write(root, upload_content); DVLOG(1) << "FilesPatch data: " << *upload_content_type << ", [" << *upload_content << "]"; @@ -545,7 +545,7 @@ if (!title_.empty()) root.SetString("title", title_); - base::JSONWriter::Write(&root, upload_content); + base::JSONWriter::Write(root, upload_content); DVLOG(1) << "FilesCopy data: " << *upload_content_type << ", [" << *upload_content << "]"; return true; @@ -755,7 +755,7 @@ base::DictionaryValue root; root.SetString("id", id_); - base::JSONWriter::Write(&root, upload_content); + base::JSONWriter::Write(root, upload_content); DVLOG(1) << "InsertResource data: " << *upload_content_type << ", [" << *upload_content << "]"; return true; @@ -834,7 +834,7 @@ } AttachProperties(properties_, &root); - base::JSONWriter::Write(&root, upload_content); + base::JSONWriter::Write(root, upload_content); DVLOG(1) << "InitiateUploadNewFile data: " << *upload_content_type << ", [" << *upload_content << "]"; @@ -906,7 +906,7 @@ return false; *upload_content_type = util::kContentTypeApplicationJson; - base::JSONWriter::Write(&root, upload_content); + base::JSONWriter::Write(root, upload_content); DVLOG(1) << "InitiateUploadExistingFile data: " << *upload_content_type << ", [" << *upload_content << "]"; return true; @@ -1158,7 +1158,7 @@ break; } root.SetString("value", value_); - base::JSONWriter::Write(&root, upload_content); + base::JSONWriter::Write(root, upload_content); return true; }
diff --git a/google_apis/gaia/fake_gaia.cc b/google_apis/gaia/fake_gaia.cc index bf2331d9..1bf87ca7 100644 --- a/google_apis/gaia/fake_gaia.cc +++ b/google_apis/gaia/fake_gaia.cc
@@ -390,7 +390,7 @@ void FakeGaia::FormatJSONResponse(const base::DictionaryValue& response_dict, BasicHttpResponse* http_response) { std::string response_json; - base::JSONWriter::Write(&response_dict, &response_json); + base::JSONWriter::Write(response_dict, &response_json); http_response->set_content(response_json); http_response->set_code(net::HTTP_OK); }
diff --git a/google_apis/gaia/gaia_auth_fetcher.cc b/google_apis/gaia/gaia_auth_fetcher.cc index 83d6522..b19e5f4 100644 --- a/google_apis/gaia/gaia_auth_fetcher.cc +++ b/google_apis/gaia/gaia_auth_fetcher.cc
@@ -115,6 +115,9 @@ "client_secret=%s&" "code=%s"; // static +const char GaiaAuthFetcher::kOAuth2CodeToTokenPairDeviceIdParam[] = + "device_id=%s&device_type=chrome"; +// static const char GaiaAuthFetcher::kOAuth2RevokeTokenBodyFormat[] = "token=%s"; // static @@ -341,7 +344,8 @@ // static std::string GaiaAuthFetcher::MakeGetTokenPairBody( - const std::string& auth_code) { + const std::string& auth_code, + const std::string& device_id) { std::string encoded_scope = net::EscapeUrlEncodedData( GaiaConstants::kOAuth1LoginScope, true); std::string encoded_client_id = net::EscapeUrlEncodedData( @@ -349,11 +353,15 @@ std::string encoded_client_secret = net::EscapeUrlEncodedData( GaiaUrls::GetInstance()->oauth2_chrome_client_secret(), true); std::string encoded_auth_code = net::EscapeUrlEncodedData(auth_code, true); - return base::StringPrintf(kOAuth2CodeToTokenPairBodyFormat, - encoded_scope.c_str(), - encoded_client_id.c_str(), - encoded_client_secret.c_str(), - encoded_auth_code.c_str()); + std::string body = base::StringPrintf( + kOAuth2CodeToTokenPairBodyFormat, encoded_scope.c_str(), + encoded_client_id.c_str(), encoded_client_secret.c_str(), + encoded_auth_code.c_str()); + if (!device_id.empty()) { + body += "&" + base::StringPrintf(kOAuth2CodeToTokenPairDeviceIdParam, + device_id.c_str()); + } + return body; } // static @@ -678,10 +686,16 @@ void GaiaAuthFetcher::StartAuthCodeForOAuth2TokenExchange( const std::string& auth_code) { + StartAuthCodeForOAuth2TokenExchangeWithDeviceId(auth_code, std::string()); +} + +void GaiaAuthFetcher::StartAuthCodeForOAuth2TokenExchangeWithDeviceId( + const std::string& auth_code, + const std::string& device_id) { DCHECK(!fetch_pending_) << "Tried to fetch two things at once!"; DVLOG(1) << "Starting OAuth token pair fetch"; - request_body_ = MakeGetTokenPairBody(auth_code); + request_body_ = MakeGetTokenPairBody(auth_code, device_id); fetcher_ = CreateGaiaFetcher(getter_, request_body_, std::string(), oauth2_token_gurl_, kLoadFlagsIgnoreCookies, this);
diff --git a/google_apis/gaia/gaia_auth_fetcher.h b/google_apis/gaia/gaia_auth_fetcher.h index c2c8f64..31ea47d 100644 --- a/google_apis/gaia/gaia_auth_fetcher.h +++ b/google_apis/gaia/gaia_auth_fetcher.h
@@ -139,6 +139,17 @@ // called on the consumer on the original thread. void StartAuthCodeForOAuth2TokenExchange(const std::string& auth_code); + // Start a request to exchange the authorization code for an OAuthLogin-scoped + // oauth2 token. + // Resulting refresh token is annotated on the server with |device_id|. Format + // of device_id on the server is at most 64 unicode characters. + // + // Either OnClientOAuthSuccess or OnClientOAuthFailure will be + // called on the consumer on the original thread. + void StartAuthCodeForOAuth2TokenExchangeWithDeviceId( + const std::string& auth_code, + const std::string& device_id); + // Start a request to get user info for the account identified by |lsid|. // // Either OnGetUserInfoSuccess or OnGetUserInfoFailure will be @@ -238,6 +249,8 @@ static const char kClientLoginToOAuth2WithDeviceTypeBodyFormat[]; // The format of the POST body to get OAuth2 token pair from auth code. static const char kOAuth2CodeToTokenPairBodyFormat[]; + // Additional param for the POST body to get OAuth2 token pair from auth code. + static const char kOAuth2CodeToTokenPairDeviceIdParam[]; // The format of the POST body to revoke an OAuth2 token. static const char kOAuth2RevokeTokenBodyFormat[]; // The format of the POST body for GetUserInfo. @@ -379,8 +392,10 @@ const char* const service); // Create body to get OAuth2 auth code. static std::string MakeGetAuthCodeBody(bool include_device_type); - // Given auth code, create body to get OAuth2 token pair. - static std::string MakeGetTokenPairBody(const std::string& auth_code); + // Given auth code and device ID (optional), create body to get OAuth2 token + // pair. + static std::string MakeGetTokenPairBody(const std::string& auth_code, + const std::string& device_id); // Given an OAuth2 token, create body to revoke the token. std::string MakeRevokeTokenBody(const std::string& auth_token); // Supply the lsid returned from ClientLogin in order to fetch
diff --git a/gpu/BUILD.gn b/gpu/BUILD.gn index 4df2569..f9b7300 100644 --- a/gpu/BUILD.gn +++ b/gpu/BUILD.gn
@@ -241,9 +241,10 @@ "//testing/gtest", "//third_party/angle:translator", "//ui/gfx", - "//ui/gfx:test_support", "//ui/gfx/geometry", + "//ui/gfx:test_support", "//ui/gl", + "//ui/gl:gl_unittest_utils", "//gpu/command_buffer/common:gles2_utils", "//gpu/command_buffer/client:gles2_c_lib", "//gpu/command_buffer/client:gles2_implementation",
diff --git a/gpu/tools/compositor_model_bench/render_tree.cc b/gpu/tools/compositor_model_bench/render_tree.cc index 8712a97..ff60961 100644 --- a/gpu/tools/compositor_model_bench/render_tree.cc +++ b/gpu/tools/compositor_model_bench/render_tree.cc
@@ -442,7 +442,7 @@ string outjson; - JSONWriter::WriteWithOptions(node, base::JSONWriter::OPTIONS_PRETTY_PRINT, + JSONWriter::WriteWithOptions(*node, base::JSONWriter::OPTIONS_PRETTY_PRINT, &outjson); LOG(ERROR) << "Unrecognized node type! JSON:\n\n" "-----------------------\n" <<
diff --git a/ios/web/web_state/ui/crw_web_controller_observer_unittest.mm b/ios/web/web_state/ui/crw_web_controller_observer_unittest.mm index 9fd9358..9b99c9a 100644 --- a/ios/web/web_state/ui/crw_web_controller_observer_unittest.mm +++ b/ios/web/web_state/ui/crw_web_controller_observer_unittest.mm
@@ -68,7 +68,7 @@ base::DictionaryValue command; command.SetString("command", "test.testMessage"); std::string message; - base::JSONWriter::Write(&command, &message); + base::JSONWriter::Write(command, &message); this->RunJavaScript([NSString stringWithFormat:@"__gCrWeb.message.invokeOnHost(%s)", message.c_str()]); this->WaitForBackgroundTasks(); @@ -91,7 +91,7 @@ command.SetString("target", "target"); command.SetString("referrerPolicy", "referrerPolicy"); std::string message; - base::JSONWriter::Write(&command, &message); + base::JSONWriter::Write(command, &message); this->RunJavaScript( [NSString stringWithFormat:@"__gCrWeb.message.invokeOnHostImmediate(%s)", message.c_str()]); @@ -112,7 +112,7 @@ for (int count = 0; count <= kNumberMessages; count++) { std::string message; command.SetInteger("number", count); - base::JSONWriter::Write(&command, &message); + base::JSONWriter::Write(command, &message); ASSERT_EQ(0U, [this->fake_web_controller_observer_ commandsReceived].size()); this->RunJavaScript(
diff --git a/ios/web/webui/web_ui_ios_impl.mm b/ios/web/webui/web_ui_ios_impl.mm index 810f3a7..8913f79d7 100644 --- a/ios/web/webui/web_ui_ios_impl.mm +++ b/ios/web/webui/web_ui_ios_impl.mm
@@ -27,7 +27,7 @@ if (i > 0) parameters += base::char16(','); - base::JSONWriter::Write(arg_list[i], &json); + base::JSONWriter::Write(*arg_list[i], &json); parameters += base::UTF8ToUTF16(json); } return base::ASCIIToUTF16(function_name) + base::char16('(') + parameters +
diff --git a/ipc/ipc_message_utils.cc b/ipc/ipc_message_utils.cc index adb14d1..a00e857e 100644 --- a/ipc/ipc_message_utils.cc +++ b/ipc/ipc_message_utils.cc
@@ -451,7 +451,7 @@ void ParamTraits<base::DictionaryValue>::Log(const param_type& p, std::string* l) { std::string json; - base::JSONWriter::Write(&p, &json); + base::JSONWriter::Write(p, &json); l->append(json); } @@ -533,7 +533,7 @@ void ParamTraits<base::ListValue>::Log(const param_type& p, std::string* l) { std::string json; - base::JSONWriter::Write(&p, &json); + base::JSONWriter::Write(p, &json); l->append(json); }
diff --git a/jingle/glue/chrome_async_socket_unittest.cc b/jingle/glue/chrome_async_socket_unittest.cc index 78b07a6c..a785553 100644 --- a/jingle/glue/chrome_async_socket_unittest.cc +++ b/jingle/glue/chrome_async_socket_unittest.cc
@@ -93,6 +93,14 @@ writes_.push_back(mock_write); } + bool AllReadDataConsumed() const override { + return reads_.empty(); + } + + bool AllWriteDataConsumed() const override { + return writes_.empty(); + } + private: std::deque<net::MockRead> reads_; bool has_pending_read_;
diff --git a/jingle/glue/utils.cc b/jingle/glue/utils.cc index 4d35650..4c9f4b6 100644 --- a/jingle/glue/utils.cc +++ b/jingle/glue/utils.cc
@@ -46,7 +46,7 @@ value.SetInteger("generation", candidate.generation()); std::string result; - base::JSONWriter::Write(&value, &result); + base::JSONWriter::Write(value, &result); return result; }
diff --git a/mandoline/app/android/apk/AndroidManifest.xml b/mandoline/app/android/apk/AndroidManifest.xml index 07318e39..b59b8c9 100644 --- a/mandoline/app/android/apk/AndroidManifest.xml +++ b/mandoline/app/android/apk/AndroidManifest.xml
@@ -26,6 +26,9 @@ android:hardwareAccelerated="true"> <intent-filter> <action android:name="android.intent.action.VIEW"/> + <category android:name="android.intent.category.DEFAULT"/> + <data android:scheme="http"/> + <data android:scheme="https"/> </intent-filter> </activity> </application>
diff --git a/mandoline/app/core_services_initialization.cc b/mandoline/app/core_services_initialization.cc index 5eeb30ce..612dd2b 100644 --- a/mandoline/app/core_services_initialization.cc +++ b/mandoline/app/core_services_initialization.cc
@@ -14,6 +14,11 @@ mojo::shell::ApplicationManager* manager = context->application_manager(); manager->RegisterApplicationPackageAlias(GURL("mojo:clipboard"), GURL("mojo:core_services"), "Core"); +#if !defined(OS_ANDROID) + manager->RegisterApplicationPackageAlias(GURL("mojo:native_viewport_service"), + GURL("mojo:core_services"), + "Surfaces"); +#endif manager->RegisterApplicationPackageAlias( GURL("mojo:network_service"), GURL("mojo:core_services"), "Network"); #if !defined(OS_ANDROID)
diff --git a/mandoline/services/core_services/BUILD.gn b/mandoline/services/core_services/BUILD.gn index 4bc6c9e..19ec9af 100644 --- a/mandoline/services/core_services/BUILD.gn +++ b/mandoline/services/core_services/BUILD.gn
@@ -77,8 +77,9 @@ if (!is_android) { deps += [ + "//components/native_viewport:lib", + "//components/native_viewport/public/cpp:args", "//mandoline/ui/omnibox:lib", - "//mojo/services/network:lib", ] } }
diff --git a/mandoline/services/core_services/DEPS b/mandoline/services/core_services/DEPS index 5234781d..2035162d 100644 --- a/mandoline/services/core_services/DEPS +++ b/mandoline/services/core_services/DEPS
@@ -1,6 +1,7 @@ include_rules = [ "+components/clipboard", "+components/kiosk_wm", + "+components/native_viewport", "+components/resource_provider", "+components/surfaces", "+components/view_manager",
diff --git a/mandoline/services/core_services/core_services_application_delegate.cc b/mandoline/services/core_services/core_services_application_delegate.cc index 90e9314..5eeb52c 100644 --- a/mandoline/services/core_services/core_services_application_delegate.cc +++ b/mandoline/services/core_services/core_services_application_delegate.cc
@@ -6,6 +6,7 @@ #include "base/bind.h" #include "components/clipboard/clipboard_application_delegate.h" +#include "components/native_viewport/native_viewport_application_delegate.h" #include "components/resource_provider/resource_provider_app.h" #include "components/surfaces/surfaces_service_application.h" #include "components/view_manager/view_manager_app.h" @@ -13,12 +14,12 @@ #include "mojo/application/public/cpp/application_connection.h" #include "mojo/application/public/cpp/application_impl.h" #include "mojo/common/message_pump_mojo.h" +#include "mojo/services/network/network_service_delegate.h" #include "mojo/services/tracing/tracing_app.h" #include "url/gurl.h" #if !defined(OS_ANDROID) #include "mandoline/ui/omnibox/omnibox_impl.h" -#include "mojo/services/network/network_service_delegate.h" #endif namespace core_services { @@ -129,8 +130,12 @@ if (url == "mojo://clipboard/") delegate.reset(new clipboard::ClipboardApplicationDelegate); #if !defined(OS_ANDROID) + else if (url == "mojo://native_viewport_service/") + delegate.reset(new native_viewport::NativeViewportApplicationDelegate); +#endif else if (url == "mojo://network_service/") delegate.reset(new NetworkServiceDelegate); +#if !defined(OS_ANDROID) else if (url == "mojo://omnibox/") delegate.reset(new mandoline::OmniboxImpl); #endif @@ -152,6 +157,8 @@ // In the case of mojo:network_service, we must use an IO message loop. if (url == "mojo://network_service/") { thread_options.message_loop_type = base::MessageLoop::TYPE_IO; + } else if (url == "mojo://native_viewport_service/") { + thread_options.message_loop_type = base::MessageLoop::TYPE_UI; } else { // We must use a MessagePumpMojo to awake on mojo messages. thread_options.message_pump_factory =
diff --git a/mandoline/ui/browser/BUILD.gn b/mandoline/ui/browser/BUILD.gn index 48149ee..bebb90d 100644 --- a/mandoline/ui/browser/BUILD.gn +++ b/mandoline/ui/browser/BUILD.gn
@@ -71,5 +71,6 @@ mojom("interfaces") { sources = [ "omnibox.mojom", + "view_embedder.mojom", ] }
diff --git a/mandoline/ui/browser/browser.cc b/mandoline/ui/browser/browser.cc index 741346a81..19d0d130 100644 --- a/mandoline/ui/browser/browser.cc +++ b/mandoline/ui/browser/browser.cc
@@ -36,7 +36,7 @@ omnibox_(nullptr), navigator_host_(this), ui_(nullptr) { - exposed_services_impl_.AddService(this); + exposed_services_impl_.AddService<mojo::NavigatorHost>(this); } Browser::~Browser() { @@ -72,6 +72,7 @@ bool Browser::ConfigureOutgoingConnection( mojo::ApplicationConnection* connection) { + connection->AddService<ViewEmbedder>(this); return true; } @@ -122,24 +123,6 @@ ReplaceContentWithURL(url); } -void Browser::Create(mojo::ApplicationConnection* connection, - mojo::InterfaceRequest<mojo::NavigatorHost> request) { - navigator_host_.Bind(request.Pass()); -} - -void Browser::ShowOmnibox( - const mojo::String& url, - mojo::InterfaceRequest<mojo::ServiceProvider> services, - mojo::ServiceProviderPtr exposed_services) { - if (!omnibox_) { - omnibox_ = root_->view_manager()->CreateView(); - root_->AddChild(omnibox_); - omnibox_->SetVisible(true); - omnibox_->SetBounds(root_->bounds()); - } - omnibox_->Embed(url, services.Pass(), exposed_services.Pass()); -} - void Browser::Embed(const mojo::String& url, mojo::InterfaceRequest<mojo::ServiceProvider> services, mojo::ServiceProviderPtr exposed_services) { @@ -170,4 +153,27 @@ navigator_host_.RecordNavigation(url); } +void Browser::Create(mojo::ApplicationConnection* connection, + mojo::InterfaceRequest<mojo::NavigatorHost> request) { + navigator_host_.Bind(request.Pass()); +} + +void Browser::Create(mojo::ApplicationConnection* connection, + mojo::InterfaceRequest<ViewEmbedder> request) { + view_embedder_bindings_.AddBinding(this, request.Pass()); +} + +void Browser::ShowOmnibox( + const mojo::String& url, + mojo::InterfaceRequest<mojo::ServiceProvider> services, + mojo::ServiceProviderPtr exposed_services) { + if (!omnibox_) { + omnibox_ = root_->view_manager()->CreateView(); + root_->AddChild(omnibox_); + omnibox_->SetVisible(true); + omnibox_->SetBounds(root_->bounds()); + } + omnibox_->Embed(url, services.Pass(), exposed_services.Pass()); +} + } // namespace mandoline
diff --git a/mandoline/ui/browser/browser.h b/mandoline/ui/browser/browser.h index a972509..0cb7612 100644 --- a/mandoline/ui/browser/browser.h +++ b/mandoline/ui/browser/browser.h
@@ -11,10 +11,12 @@ #include "mandoline/services/navigation/public/interfaces/navigation.mojom.h" #include "mandoline/ui/browser/navigator_host_impl.h" #include "mandoline/ui/browser/omnibox.mojom.h" +#include "mandoline/ui/browser/view_embedder.mojom.h" #include "mojo/application/public/cpp/application_delegate.h" #include "mojo/application/public/cpp/application_impl.h" #include "mojo/application/public/cpp/connect.h" #include "mojo/application/public/cpp/service_provider_impl.h" +#include "mojo/common/weak_binding_set.h" #include "ui/mojo/events/input_events.mojom.h" #include "url/gurl.h" @@ -31,7 +33,9 @@ public mojo::ViewManagerDelegate, public mojo::ViewManagerRootClient, public OmniboxClient, - public mojo::InterfaceFactory<mojo::NavigatorHost> { + public ViewEmbedder, + public mojo::InterfaceFactory<mojo::NavigatorHost>, + public mojo::InterfaceFactory<ViewEmbedder> { public: Browser(); ~Browser() override; @@ -63,13 +67,18 @@ // Overridden from OmniboxClient: void OpenURL(const mojo::String& url) override; + // Overridden from ViewEmbedder: + void Embed(const mojo::String& url, + mojo::InterfaceRequest<mojo::ServiceProvider> services, + mojo::ServiceProviderPtr exposed_services) override; + // Overridden from mojo::InterfaceFactory<mojo::NavigatorHost>: void Create(mojo::ApplicationConnection* connection, mojo::InterfaceRequest<mojo::NavigatorHost> request) override; - void Embed(const mojo::String& url, - mojo::InterfaceRequest<mojo::ServiceProvider> services, - mojo::ServiceProviderPtr exposed_services); + // Overridden from mojo::InterfaceFactory<ViewEmbedder>: + void Create(mojo::ApplicationConnection* connection, + mojo::InterfaceRequest<ViewEmbedder> request) override; void ShowOmnibox(const mojo::String& url, mojo::InterfaceRequest<mojo::ServiceProvider> services, @@ -88,6 +97,8 @@ mojo::ServiceProviderImpl exposed_services_impl_; scoped_ptr<MergedServiceProvider> merged_service_provider_; + mojo::WeakBindingSet<ViewEmbedder> view_embedder_bindings_; + NavigatorHostImpl navigator_host_; GURL current_url_;
diff --git a/mandoline/ui/browser/view_embedder.mojom b/mandoline/ui/browser/view_embedder.mojom new file mode 100644 index 0000000..238da6fe --- /dev/null +++ b/mandoline/ui/browser/view_embedder.mojom
@@ -0,0 +1,13 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +module mandoline; + +import "mojo/application/public/interfaces/service_provider.mojom"; + +interface ViewEmbedder { + Embed(string url, + mojo.ServiceProvider&? services, + mojo.ServiceProvider? exposed_services); +};
diff --git a/mandoline/ui/omnibox/omnibox_impl.cc b/mandoline/ui/omnibox/omnibox_impl.cc index e41149d..b310c032 100644 --- a/mandoline/ui/omnibox/omnibox_impl.cc +++ b/mandoline/ui/omnibox/omnibox_impl.cc
@@ -39,6 +39,7 @@ mojo::ApplicationConnection* connection) { connection->AddService<Omnibox>(this); connection->AddService(view_manager_client_factory_.get()); + connection->ConnectToService(&view_embedder_); return true; } @@ -59,9 +60,11 @@ edit_->set_controller(this); } + const int kOpacity = 0xC0; views::WidgetDelegateView* widget_delegate = new views::WidgetDelegateView; widget_delegate->GetContentsView()->set_background( - views::Background::CreateSolidBackground(0xFFDDDDDD)); + views::Background::CreateSolidBackground( + SkColorSetA(0xDDDDDD, kOpacity))); widget_delegate->GetContentsView()->AddChildView(edit_); widget_delegate->GetContentsView()->SetLayoutManager(this); @@ -74,8 +77,11 @@ new NativeWidgetViewManager(widget, app_impl_->shell(), root); params.delegate = widget_delegate; params.bounds = root->bounds().To<gfx::Rect>(); + params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; widget->Init(params); widget->Show(); + widget->GetCompositor()->SetBackgroundColor( + SkColorSetA(SK_ColorBLACK, kOpacity)); root->SetFocus(); edit_->SetText(url_.To<base::string16>()); edit_->SelectAll(false); @@ -129,7 +135,8 @@ void OmniboxImpl::ShowForURL(const mojo::String& url) { url_ = url; - // TODO: get embedding working. + + view_embedder_->Embed("mojo:omnibox", nullptr, nullptr); } } // namespace mandoline
diff --git a/mandoline/ui/omnibox/omnibox_impl.h b/mandoline/ui/omnibox/omnibox_impl.h index 0d59c76..2c3e97ab 100644 --- a/mandoline/ui/omnibox/omnibox_impl.h +++ b/mandoline/ui/omnibox/omnibox_impl.h
@@ -7,6 +7,7 @@ #include "components/view_manager/public/cpp/view_manager_delegate.h" #include "mandoline/ui/browser/omnibox.mojom.h" +#include "mandoline/ui/browser/view_embedder.mojom.h" #include "mojo/application/public/cpp/application_delegate.h" #include "mojo/application/public/cpp/interface_factory.h" #include "mojo/common/weak_binding_set.h" @@ -68,6 +69,7 @@ views::Textfield* edit_; mojo::WeakBindingSet<Omnibox> bindings_; scoped_ptr<mojo::ViewManagerClientFactory> view_manager_client_factory_; + ViewEmbedderPtr view_embedder_; DISALLOW_COPY_AND_ASSIGN(OmniboxImpl); };
diff --git a/media/audio/audio_manager_base.cc b/media/audio/audio_manager_base.cc index dbe1b68..fe7c12e 100644 --- a/media/audio/audio_manager_base.cc +++ b/media/audio/audio_manager_base.cc
@@ -200,6 +200,9 @@ return NULL; } + DVLOG(2) << "Creating a new AudioInputStream with buffer size = " + << params.frames_per_buffer(); + AudioInputStream* stream; switch (params.format()) { case AudioParameters::AUDIO_PCM_LINEAR:
diff --git a/media/base/BUILD.gn b/media/base/BUILD.gn index 2474ff9..d81171e 100644 --- a/media/base/BUILD.gn +++ b/media/base/BUILD.gn
@@ -63,6 +63,7 @@ "byte_queue.h", "cdm_callback_promise.cc", "cdm_callback_promise.h", + "cdm_config.h", "cdm_context.cc", "cdm_context.h", "cdm_factory.cc", @@ -119,6 +120,8 @@ "media_permission.h", "media_switches.cc", "media_switches.h", + "mime_util.cc", + "mime_util.h", "moving_average.cc", "moving_average.h", "multi_channel_resampler.cc", @@ -380,6 +383,7 @@ "fake_demuxer_stream_unittest.cc", "gmock_callback_support_unittest.cc", "key_systems_unittest.cc", + "mime_util_unittest.cc", "moving_average_unittest.cc", "multi_channel_resampler_unittest.cc", "null_video_sink_unittest.cc",
diff --git a/media/base/android/java/src/org/chromium/media/MediaCodecBridge.java b/media/base/android/java/src/org/chromium/media/MediaCodecBridge.java index 018c475..04066e0e 100644 --- a/media/base/android/java/src/org/chromium/media/MediaCodecBridge.java +++ b/media/base/android/java/src/org/chromium/media/MediaCodecBridge.java
@@ -15,11 +15,11 @@ import android.media.MediaFormat; import android.os.Build; import android.os.Bundle; -import android.util.Log; import android.view.Surface; import org.chromium.base.CalledByNative; import org.chromium.base.JNINamespace; +import org.chromium.base.Log; import java.nio.ByteBuffer; import java.util.ArrayList;
diff --git a/media/base/cdm_config.h b/media/base/cdm_config.h index 4b57ebb..6f72348 100644 --- a/media/base/cdm_config.h +++ b/media/base/cdm_config.h
@@ -12,7 +12,7 @@ // The runtime configuration for new CDM instances as computed by // |requestMediaKeySystemAccess|. This is in some sense the Chromium-side // counterpart of Blink's WebMediaKeySystemConfiguration. -struct MEDIA_EXPORT CdmConfig { +struct CdmConfig { // Allow access to a distinctive identifier. bool allow_distinctive_identifier = false;
diff --git a/media/base/media_log.cc b/media/base/media_log.cc index c89c415..462299b 100644 --- a/media/base/media_log.cc +++ b/media/base/media_log.cc
@@ -139,7 +139,7 @@ media::MediaLog::PipelineStatusToString(status); } std::string params_json; - base::JSONWriter::Write(&event.params, ¶ms_json); + base::JSONWriter::Write(event.params, ¶ms_json); return EventTypeToString(event.type) + " " + params_json; }
diff --git a/media/base/mime_util.cc b/media/base/mime_util.cc new file mode 100644 index 0000000..bc12773 --- /dev/null +++ b/media/base/mime_util.cc
@@ -0,0 +1,668 @@ +// Copyright 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <map> + +#include "base/containers/hash_tables.h" +#include "base/lazy_instance.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/string_split.h" +#include "base/strings/string_util.h" +#include "build/build_config.h" +#include "media/base/mime_util.h" + +#if defined(OS_ANDROID) +#include "base/android/build_info.h" +#endif + +namespace media { + +// Singleton utility class for mime types. +class MimeUtil { + public: + enum Codec { + INVALID_CODEC, + PCM, + MP3, + MPEG2_AAC_LC, + MPEG2_AAC_MAIN, + MPEG2_AAC_SSR, + MPEG4_AAC_LC, + MPEG4_AAC_SBR_v1, + MPEG4_AAC_SBR_PS_v2, + VORBIS, + OPUS, + H264_BASELINE, + H264_MAIN, + H264_HIGH, + VP8, + VP9, + THEORA + }; + + bool IsSupportedMediaMimeType(const std::string& mime_type) const; + + bool AreSupportedMediaCodecs(const std::vector<std::string>& codecs) const; + + void ParseCodecString(const std::string& codecs, + std::vector<std::string>* codecs_out, + bool strip); + + bool IsStrictMediaMimeType(const std::string& mime_type) const; + SupportsType IsSupportedStrictMediaMimeType( + const std::string& mime_type, + const std::vector<std::string>& codecs) const; + + void RemoveProprietaryMediaTypesAndCodecsForTests(); + + private: + friend struct base::DefaultLazyInstanceTraits<MimeUtil>; + + typedef base::hash_set<int> CodecSet; + typedef std::map<std::string, CodecSet> StrictMappings; + struct CodecEntry { + CodecEntry() : codec(INVALID_CODEC), is_ambiguous(true) {} + CodecEntry(Codec c, bool ambiguous) : codec(c), is_ambiguous(ambiguous) {} + Codec codec; + bool is_ambiguous; + }; + typedef std::map<std::string, CodecEntry> StringToCodecMappings; + + MimeUtil(); + + // For faster lookup, keep hash sets. + void InitializeMimeTypeMaps(); + + // Returns IsSupported if all codec IDs in |codecs| are unambiguous + // and are supported by the platform. MayBeSupported is returned if + // at least one codec ID in |codecs| is ambiguous but all the codecs + // are supported by the platform. IsNotSupported is returned if at + // least one codec ID is not supported by the platform. + SupportsType AreSupportedCodecs( + const CodecSet& supported_codecs, + const std::vector<std::string>& codecs) const; + + // Converts a codec ID into an Codec enum value and indicates + // whether the conversion was ambiguous. + // Returns true if this method was able to map |codec_id| to a specific + // Codec enum value. |codec| and |is_ambiguous| are only valid if true + // is returned. Otherwise their value is undefined after the call. + // |is_ambiguous| is true if |codec_id| did not have enough information to + // unambiguously determine the proper Codec enum value. If |is_ambiguous| + // is true |codec| contains the best guess for the intended Codec enum value. + bool StringToCodec(const std::string& codec_id, + Codec* codec, + bool* is_ambiguous) const; + + // Returns true if |codec| is supported by the platform. + // Note: This method will return false if the platform supports proprietary + // codecs but |allow_proprietary_codecs_| is set to false. + bool IsCodecSupported(Codec codec) const; + + // Returns true if |codec| refers to a proprietary codec. + bool IsCodecProprietary(Codec codec) const; + + // Returns true and sets |*default_codec| if |mime_type| has a default codec + // associated with it. Returns false otherwise and the value of + // |*default_codec| is undefined. + bool GetDefaultCodecLowerCase(const std::string& mime_type_lower_case, + Codec* default_codec) const; + + // Returns true if |mime_type_lower_case| has a default codec associated with + // it and IsCodecSupported() returns true for that particular codec. + bool IsDefaultCodecSupportedLowerCase( + const std::string& mime_type_lower_case) const; + + using MimeTypes = base::hash_set<std::string>; + MimeTypes media_map_; + + // A map of mime_types and hash map of the supported codecs for the mime_type. + StrictMappings strict_format_map_; + + // Keeps track of whether proprietary codec support should be + // advertised to callers. + bool allow_proprietary_codecs_; + + // Lookup table for string compare based string -> Codec mappings. + StringToCodecMappings string_to_codec_map_; + + DISALLOW_COPY_AND_ASSIGN(MimeUtil); +}; // class MimeUtil + +// This variable is Leaky because it is accessed from WorkerPool threads. +static base::LazyInstance<MimeUtil>::Leaky g_media_mime_util = + LAZY_INSTANCE_INITIALIZER; + + +// A list of media types: http://en.wikipedia.org/wiki/Internet_media_type +// A comprehensive mime type list: http://plugindoc.mozdev.org/winmime.php +// This set of codecs is supported by all variations of Chromium. +static const char* const common_media_types[] = { + // Ogg. + "audio/ogg", + "application/ogg", +#if !defined(OS_ANDROID) // Android doesn't support Ogg Theora. + "video/ogg", +#endif + + // WebM. + "video/webm", + "audio/webm", + + // Wav. + "audio/wav", + "audio/x-wav", + +#if defined(OS_ANDROID) + // HLS. + "application/vnd.apple.mpegurl", + "application/x-mpegurl", +#endif +}; + +// List of proprietary types only supported by Google Chrome. +static const char* const proprietary_media_types[] = { + // MPEG-4. + "video/mp4", + "video/x-m4v", + "audio/mp4", + "audio/x-m4a", + + // MP3. + "audio/mp3", + "audio/x-mp3", + "audio/mpeg", + "audio/aac", + +#if defined(ENABLE_MPEG2TS_STREAM_PARSER) + // MPEG-2 TS. + "video/mp2t", +#endif +}; + +#if defined(OS_ANDROID) +static bool IsCodecSupportedOnAndroid(MimeUtil::Codec codec) { + switch (codec) { + case MimeUtil::INVALID_CODEC: + return false; + + case MimeUtil::PCM: + case MimeUtil::MP3: + case MimeUtil::MPEG4_AAC_LC: + case MimeUtil::MPEG4_AAC_SBR_v1: + case MimeUtil::MPEG4_AAC_SBR_PS_v2: + case MimeUtil::H264_BASELINE: + case MimeUtil::H264_MAIN: + case MimeUtil::H264_HIGH: + case MimeUtil::VP8: + case MimeUtil::VORBIS: + return true; + + case MimeUtil::MPEG2_AAC_LC: + case MimeUtil::MPEG2_AAC_MAIN: + case MimeUtil::MPEG2_AAC_SSR: + // MPEG-2 variants of AAC are not supported on Android. + return false; + + case MimeUtil::VP9: + // VP9 is supported only in KitKat+ (API Level 19). + return base::android::BuildInfo::GetInstance()->sdk_int() >= 19; + + case MimeUtil::OPUS: + // Opus is supported only in Lollipop+ (API Level 21). + return base::android::BuildInfo::GetInstance()->sdk_int() >= 21; + + case MimeUtil::THEORA: + return false; + } + + return false; +} +#endif + +struct MediaFormatStrict { + const char* const mime_type; + const char* const codecs_list; +}; + +// Following is the list of RFC 6381 compliant codecs: +// mp4a.66 - MPEG-2 AAC MAIN +// mp4a.67 - MPEG-2 AAC LC +// mp4a.68 - MPEG-2 AAC SSR +// mp4a.69 - MPEG-2 extension to MPEG-1 +// mp4a.6B - MPEG-1 audio +// mp4a.40.2 - MPEG-4 AAC LC +// mp4a.40.02 - MPEG-4 AAC LC (leading 0 in aud-oti for compatibility) +// mp4a.40.5 - MPEG-4 HE-AAC v1 (AAC LC + SBR) +// mp4a.40.05 - MPEG-4 HE-AAC v1 (AAC LC + SBR) (leading 0 in aud-oti for +// compatibility) +// mp4a.40.29 - MPEG-4 HE-AAC v2 (AAC LC + SBR + PS) +// +// avc1.42E0xx - H.264 Baseline +// avc1.4D40xx - H.264 Main +// avc1.6400xx - H.264 High +static const char kMP4AudioCodecsExpression[] = + "mp4a.66,mp4a.67,mp4a.68,mp4a.69,mp4a.6B,mp4a.40.2,mp4a.40.02,mp4a.40.5," + "mp4a.40.05,mp4a.40.29"; +static const char kMP4VideoCodecsExpression[] = + // This is not a complete list of supported avc1 codecs. It is simply used + // to register support for the corresponding Codec enum. Instead of using + // strings in these three arrays, we should use the Codec enum values. + // This will avoid confusion and unnecessary parsing at runtime. + // kUnambiguousCodecStringMap/kAmbiguousCodecStringMap should be the only + // mapping from strings to codecs. See crbug.com/461009. + "avc1.42E00A,avc1.4D400A,avc1.64000A," + "mp4a.66,mp4a.67,mp4a.68,mp4a.69,mp4a.6B,mp4a.40.2,mp4a.40.02,mp4a.40.5," + "mp4a.40.05,mp4a.40.29"; + +// These containers are also included in +// common_media_types/proprietary_media_types. See crbug.com/461012. +static const MediaFormatStrict format_codec_mappings[] = { + {"video/webm", "opus,vorbis,vp8,vp8.0,vp9,vp9.0"}, + {"audio/webm", "opus,vorbis"}, + {"audio/wav", "1"}, + {"audio/x-wav", "1"}, +// Android does not support Opus in Ogg container. +#if defined(OS_ANDROID) + {"video/ogg", "theora,vorbis"}, + {"audio/ogg", "vorbis"}, + {"application/ogg", "theora,vorbis"}, +#else + {"video/ogg", "opus,theora,vorbis"}, + {"audio/ogg", "opus,vorbis"}, + {"application/ogg", "opus,theora,vorbis"}, +#endif + {"audio/mpeg", "mp3"}, + {"audio/mp3", ""}, + {"audio/x-mp3", ""}, + {"audio/mp4", kMP4AudioCodecsExpression}, + {"audio/x-m4a", kMP4AudioCodecsExpression}, + {"video/mp4", kMP4VideoCodecsExpression}, + {"video/x-m4v", kMP4VideoCodecsExpression}, + {"application/x-mpegurl", kMP4VideoCodecsExpression}, + {"application/vnd.apple.mpegurl", kMP4VideoCodecsExpression}}; + +struct CodecIDMappings { + const char* const codec_id; + MimeUtil::Codec codec; +}; + +// List of codec IDs that provide enough information to determine the +// codec and profile being requested. +// +// The "mp4a" strings come from RFC 6381. +static const CodecIDMappings kUnambiguousCodecStringMap[] = { + {"1", MimeUtil::PCM}, // We only allow this for WAV so it isn't ambiguous. + // avc1/avc3.XXXXXX may be unambiguous; handled by ParseH264CodecID(). + {"mp3", MimeUtil::MP3}, + {"mp4a.66", MimeUtil::MPEG2_AAC_MAIN}, + {"mp4a.67", MimeUtil::MPEG2_AAC_LC}, + {"mp4a.68", MimeUtil::MPEG2_AAC_SSR}, + {"mp4a.69", MimeUtil::MP3}, + {"mp4a.6B", MimeUtil::MP3}, + {"mp4a.40.2", MimeUtil::MPEG4_AAC_LC}, + {"mp4a.40.02", MimeUtil::MPEG4_AAC_LC}, + {"mp4a.40.5", MimeUtil::MPEG4_AAC_SBR_v1}, + {"mp4a.40.05", MimeUtil::MPEG4_AAC_SBR_v1}, + {"mp4a.40.29", MimeUtil::MPEG4_AAC_SBR_PS_v2}, + {"vorbis", MimeUtil::VORBIS}, + {"opus", MimeUtil::OPUS}, + {"vp8", MimeUtil::VP8}, + {"vp8.0", MimeUtil::VP8}, + {"vp9", MimeUtil::VP9}, + {"vp9.0", MimeUtil::VP9}, + {"theora", MimeUtil::THEORA}}; + +// List of codec IDs that are ambiguous and don't provide +// enough information to determine the codec and profile. +// The codec in these entries indicate the codec and profile +// we assume the user is trying to indicate. +static const CodecIDMappings kAmbiguousCodecStringMap[] = { + {"mp4a.40", MimeUtil::MPEG4_AAC_LC}, + {"avc1", MimeUtil::H264_BASELINE}, + {"avc3", MimeUtil::H264_BASELINE}, + // avc1/avc3.XXXXXX may be ambiguous; handled by ParseH264CodecID(). +}; + +MimeUtil::MimeUtil() : allow_proprietary_codecs_(false) { + InitializeMimeTypeMaps(); +} + +SupportsType MimeUtil::AreSupportedCodecs( + const CodecSet& supported_codecs, + const std::vector<std::string>& codecs) const { + DCHECK(!supported_codecs.empty()); + DCHECK(!codecs.empty()); + + SupportsType result = IsSupported; + for (size_t i = 0; i < codecs.size(); ++i) { + bool is_ambiguous = true; + Codec codec = INVALID_CODEC; + if (!StringToCodec(codecs[i], &codec, &is_ambiguous)) + return IsNotSupported; + + if (!IsCodecSupported(codec) || + supported_codecs.find(codec) == supported_codecs.end()) { + return IsNotSupported; + } + + if (is_ambiguous) + result = MayBeSupported; + } + + return result; +} + +void MimeUtil::InitializeMimeTypeMaps() { + // Initialize the supported media types. + for (size_t i = 0; i < arraysize(common_media_types); ++i) + media_map_.insert(common_media_types[i]); +#if defined(USE_PROPRIETARY_CODECS) + allow_proprietary_codecs_ = true; + + for (size_t i = 0; i < arraysize(proprietary_media_types); ++i) + media_map_.insert(proprietary_media_types[i]); +#endif + + for (size_t i = 0; i < arraysize(kUnambiguousCodecStringMap); ++i) { + string_to_codec_map_[kUnambiguousCodecStringMap[i].codec_id] = + CodecEntry(kUnambiguousCodecStringMap[i].codec, false); + } + + for (size_t i = 0; i < arraysize(kAmbiguousCodecStringMap); ++i) { + string_to_codec_map_[kAmbiguousCodecStringMap[i].codec_id] = + CodecEntry(kAmbiguousCodecStringMap[i].codec, true); + } + + // Initialize the strict supported media types. + for (size_t i = 0; i < arraysize(format_codec_mappings); ++i) { + std::vector<std::string> mime_type_codecs; + ParseCodecString(format_codec_mappings[i].codecs_list, + &mime_type_codecs, + false); + + CodecSet codecs; + for (size_t j = 0; j < mime_type_codecs.size(); ++j) { + Codec codec = INVALID_CODEC; + bool is_ambiguous = true; + CHECK(StringToCodec(mime_type_codecs[j], &codec, &is_ambiguous)); + DCHECK(!is_ambiguous); + codecs.insert(codec); + } + + strict_format_map_[format_codec_mappings[i].mime_type] = codecs; + } +} + +bool MimeUtil::IsSupportedMediaMimeType(const std::string& mime_type) const { + return media_map_.find(base::StringToLowerASCII(mime_type)) != + media_map_.end(); +} + + +bool MimeUtil::AreSupportedMediaCodecs( + const std::vector<std::string>& codecs) const { + for (size_t i = 0; i < codecs.size(); ++i) { + Codec codec = INVALID_CODEC; + bool is_ambiguous = true; + if (!StringToCodec(codecs[i], &codec, &is_ambiguous) || + !IsCodecSupported(codec)) { + return false; + } + } + return true; +} + +void MimeUtil::ParseCodecString(const std::string& codecs, + std::vector<std::string>* codecs_out, + bool strip) { + std::string no_quote_codecs; + base::TrimString(codecs, "\"", &no_quote_codecs); + base::SplitString(no_quote_codecs, ',', codecs_out); + + if (!strip) + return; + + // Strip everything past the first '.' + for (std::vector<std::string>::iterator it = codecs_out->begin(); + it != codecs_out->end(); + ++it) { + size_t found = it->find_first_of('.'); + if (found != std::string::npos) + it->resize(found); + } +} + +bool MimeUtil::IsStrictMediaMimeType(const std::string& mime_type) const { + return strict_format_map_.find(base::StringToLowerASCII(mime_type)) != + strict_format_map_.end(); +} + +SupportsType MimeUtil::IsSupportedStrictMediaMimeType( + const std::string& mime_type, + const std::vector<std::string>& codecs) const { + const std::string mime_type_lower_case = base::StringToLowerASCII(mime_type); + StrictMappings::const_iterator it_strict_map = + strict_format_map_.find(mime_type_lower_case); + if (it_strict_map == strict_format_map_.end()) + return codecs.empty() ? MayBeSupported : IsNotSupported; + + if (it_strict_map->second.empty()) { + // We get here if the mimetype does not expect a codecs parameter. + return (codecs.empty() && + IsDefaultCodecSupportedLowerCase(mime_type_lower_case)) + ? IsSupported + : IsNotSupported; + } + + if (codecs.empty()) { + // We get here if the mimetype expects to get a codecs parameter, + // but didn't get one. If |mime_type_lower_case| does not have a default + // codec the best we can do is say "maybe" because we don't have enough + // information. + Codec default_codec = INVALID_CODEC; + if (!GetDefaultCodecLowerCase(mime_type_lower_case, &default_codec)) + return MayBeSupported; + + return IsCodecSupported(default_codec) ? IsSupported : IsNotSupported; + } + + return AreSupportedCodecs(it_strict_map->second, codecs); +} + +void MimeUtil::RemoveProprietaryMediaTypesAndCodecsForTests() { + for (size_t i = 0; i < arraysize(proprietary_media_types); ++i) + media_map_.erase(proprietary_media_types[i]); + allow_proprietary_codecs_ = false; +} + +// Returns true iff |profile_str| conforms to hex string "42y0", where y is one +// of [8..F]. Requiring constraint_set0_flag be set and profile_idc be 0x42 is +// taken from ISO-14496-10 7.3.2.1, 7.4.2.1, and Annex A.2.1. +// +// |profile_str| is the first four characters of the H.264 suffix string +// (ignoring the last 2 characters of the full 6 character suffix that are +// level_idc). From ISO-14496-10 7.3.2.1, it consists of: +// 8 bits: profile_idc: required to be 0x42 here. +// 1 bit: constraint_set0_flag : required to be true here. +// 1 bit: constraint_set1_flag : ignored here. +// 1 bit: constraint_set2_flag : ignored here. +// 1 bit: constraint_set3_flag : ignored here. +// 4 bits: reserved : required to be 0 here. +// +// The spec indicates other ways, not implemented here, that a |profile_str| +// can indicate a baseline conforming decoder is sufficient for decode in Annex +// A.2.1: "[profile_idc not necessarily 0x42] with constraint_set0_flag set and +// in which level_idc and constraint_set3_flag represent a level less than or +// equal to the specified level." +static bool IsValidH264BaselineProfile(const std::string& profile_str) { + uint32 constraint_set_bits; + if (profile_str.size() != 4 || + profile_str[0] != '4' || + profile_str[1] != '2' || + profile_str[3] != '0' || + !base::HexStringToUInt(base::StringPiece(profile_str.c_str() + 2, 1), + &constraint_set_bits)) { + return false; + } + + return constraint_set_bits >= 8; +} + +static bool IsValidH264Level(const std::string& level_str) { + uint32 level; + if (level_str.size() != 2 || !base::HexStringToUInt(level_str, &level)) + return false; + + // Valid levels taken from Table A-1 in ISO-14496-10. + // Essentially |level_str| is toHex(10 * level). + return ((level >= 10 && level <= 13) || + (level >= 20 && level <= 22) || + (level >= 30 && level <= 32) || + (level >= 40 && level <= 42) || + (level >= 50 && level <= 51)); +} + +// Handle parsing H.264 codec IDs as outlined in RFC 6381 and ISO-14496-10. +// avc1.42y0xx, y >= 8 - H.264 Baseline +// avc1.4D40xx - H.264 Main +// avc1.6400xx - H.264 High +// +// avc1.xxxxxx & avc3.xxxxxx are considered ambiguous forms that are trying to +// signal H.264 Baseline. For example, the idc_level, profile_idc and +// constraint_set3_flag pieces may explicitly require decoder to conform to +// baseline profile at the specified level (see Annex A and constraint_set0 in +// ISO-14496-10). +static bool ParseH264CodecID(const std::string& codec_id, + MimeUtil::Codec* codec, + bool* is_ambiguous) { + // Make sure we have avc1.xxxxxx or avc3.xxxxxx + if (codec_id.size() != 11 || + (!StartsWithASCII(codec_id, "avc1.", true) && + !StartsWithASCII(codec_id, "avc3.", true))) { + return false; + } + + std::string profile = StringToUpperASCII(codec_id.substr(5, 4)); + if (IsValidH264BaselineProfile(profile)) { + *codec = MimeUtil::H264_BASELINE; + } else if (profile == "4D40") { + *codec = MimeUtil::H264_MAIN; + } else if (profile == "6400") { + *codec = MimeUtil::H264_HIGH; + } else { + *codec = MimeUtil::H264_BASELINE; + *is_ambiguous = true; + return true; + } + + *is_ambiguous = !IsValidH264Level(StringToUpperASCII(codec_id.substr(9))); + return true; +} + +bool MimeUtil::StringToCodec(const std::string& codec_id, + Codec* codec, + bool* is_ambiguous) const { + StringToCodecMappings::const_iterator itr = + string_to_codec_map_.find(codec_id); + if (itr != string_to_codec_map_.end()) { + *codec = itr->second.codec; + *is_ambiguous = itr->second.is_ambiguous; + return true; + } + + // If |codec_id| is not in |string_to_codec_map_|, then we assume that it is + // an H.264 codec ID because currently those are the only ones that can't be + // stored in the |string_to_codec_map_| and require parsing. + return ParseH264CodecID(codec_id, codec, is_ambiguous); +} + +bool MimeUtil::IsCodecSupported(Codec codec) const { + DCHECK_NE(codec, INVALID_CODEC); + +#if defined(OS_ANDROID) + if (!IsCodecSupportedOnAndroid(codec)) + return false; +#endif + + return allow_proprietary_codecs_ || !IsCodecProprietary(codec); +} + +bool MimeUtil::IsCodecProprietary(Codec codec) const { + switch (codec) { + case INVALID_CODEC: + case MP3: + case MPEG2_AAC_LC: + case MPEG2_AAC_MAIN: + case MPEG2_AAC_SSR: + case MPEG4_AAC_LC: + case MPEG4_AAC_SBR_v1: + case MPEG4_AAC_SBR_PS_v2: + case H264_BASELINE: + case H264_MAIN: + case H264_HIGH: + return true; + + case PCM: + case VORBIS: + case OPUS: + case VP8: + case VP9: + case THEORA: + return false; + } + + return true; +} + +bool MimeUtil::GetDefaultCodecLowerCase(const std::string& mime_type_lower_case, + Codec* default_codec) const { + if (mime_type_lower_case == "audio/mpeg" || + mime_type_lower_case == "audio/mp3" || + mime_type_lower_case == "audio/x-mp3") { + *default_codec = MimeUtil::MP3; + return true; + } + + return false; +} + +bool MimeUtil::IsDefaultCodecSupportedLowerCase( + const std::string& mime_type_lower_case) const { + Codec default_codec = Codec::INVALID_CODEC; + if (!GetDefaultCodecLowerCase(mime_type_lower_case, &default_codec)) + return false; + return IsCodecSupported(default_codec); +} + +bool IsSupportedMediaMimeType(const std::string& mime_type) { + return g_media_mime_util.Get().IsSupportedMediaMimeType(mime_type); +} + +bool AreSupportedMediaCodecs(const std::vector<std::string>& codecs) { + return g_media_mime_util.Get().AreSupportedMediaCodecs(codecs); +} + +bool IsStrictMediaMimeType(const std::string& mime_type) { + return g_media_mime_util.Get().IsStrictMediaMimeType(mime_type); +} + +SupportsType IsSupportedStrictMediaMimeType( + const std::string& mime_type, + const std::vector<std::string>& codecs) { + return g_media_mime_util.Get().IsSupportedStrictMediaMimeType( + mime_type, codecs); +} + +void ParseCodecString(const std::string& codecs, + std::vector<std::string>* codecs_out, + const bool strip) { + g_media_mime_util.Get().ParseCodecString(codecs, codecs_out, strip); +} + +void RemoveProprietaryMediaTypesAndCodecsForTests() { + g_media_mime_util.Get().RemoveProprietaryMediaTypesAndCodecsForTests(); +} + +} // namespace media
diff --git a/media/base/mime_util.h b/media/base/mime_util.h new file mode 100644 index 0000000..a5c80d5 --- /dev/null +++ b/media/base/mime_util.h
@@ -0,0 +1,76 @@ +// Copyright 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MEDIA_BASE_MIME_UTIL_H__ +#define MEDIA_BASE_MIME_UTIL_H__ + +#include <string> +#include <vector> + +#include "media/base/media_export.h" + +namespace media { + +// Check to see if a particular MIME type is in the list of +// supported/recognized MIME types. +MEDIA_EXPORT bool IsSupportedMediaMimeType(const std::string& mime_type); + +// Returns true if and only if all codecs are supported, false otherwise. +MEDIA_EXPORT bool AreSupportedMediaCodecs( + const std::vector<std::string>& codecs); + +// Parses a codec string, populating |codecs_out| with the prefix of each codec +// in the string |codecs_in|. For example, passed "aaa.b.c,dd.eee", if +// |strip| == true |codecs_out| will contain {"aaa", "dd"}, if |strip| == false +// |codecs_out| will contain {"aaa.b.c", "dd.eee"}. +// See http://www.ietf.org/rfc/rfc4281.txt. +MEDIA_EXPORT void ParseCodecString(const std::string& codecs, + std::vector<std::string>* codecs_out, + bool strip); + +// Check to see if a particular MIME type is in our list which only supports a +// certain subset of codecs. +MEDIA_EXPORT bool IsStrictMediaMimeType(const std::string& mime_type); + +// Indicates that the MIME type and (possible codec string) are supported by the +// underlying platform. +enum SupportsType { + // The underlying platform is known not to support the given MIME type and + // codec combination. + IsNotSupported, + + // The underlying platform is known to support the given MIME type and codec + // combination. + IsSupported, + + // The underlying platform is unsure whether the given MIME type and codec + // combination can be rendered or not before actually trying to play it. + MayBeSupported +}; + +// Checks the |mime_type| and |codecs| against the MIME types known to support +// only a particular subset of codecs. +// * Returns IsSupported if the |mime_type| is supported and all the codecs +// within the |codecs| are supported for the |mime_type|. +// * Returns MayBeSupported if the |mime_type| is supported and is known to +// support only a subset of codecs, but |codecs| was empty. Also returned if +// all the codecs in |codecs| are supported, but additional codec parameters +// were supplied (such as profile) for which the support cannot be decided. +// * Returns IsNotSupported if either the |mime_type| is not supported or the +// |mime_type| is supported but at least one of the codecs within |codecs| is +// not supported for the |mime_type|. +MEDIA_EXPORT SupportsType IsSupportedStrictMediaMimeType( + const std::string& mime_type, + const std::vector<std::string>& codecs); + +// Test only method that removes proprietary media types and codecs from the +// list of supported MIME types and codecs. These types and codecs must be +// removed to ensure consistent layout test results across all Chromium +// variations. +MEDIA_EXPORT void RemoveProprietaryMediaTypesAndCodecsForTests(); + +} // namespace media + +#endif // MEDIA_BASE_MIME_UTIL_H__ +
diff --git a/media/base/mime_util_unittest.cc b/media/base/mime_util_unittest.cc new file mode 100644 index 0000000..d1d6722 --- /dev/null +++ b/media/base/mime_util_unittest.cc
@@ -0,0 +1,142 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/basictypes.h" +#include "base/strings/string_split.h" +#include "build/build_config.h" +#include "media/base/mime_util.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace media { + +TEST(MimeUtilTest, StrictMediaMimeType) { + EXPECT_TRUE(IsStrictMediaMimeType("video/webm")); + EXPECT_TRUE(IsStrictMediaMimeType("Video/WEBM")); + EXPECT_TRUE(IsStrictMediaMimeType("audio/webm")); + + EXPECT_TRUE(IsStrictMediaMimeType("audio/wav")); + EXPECT_TRUE(IsStrictMediaMimeType("audio/x-wav")); + + EXPECT_TRUE(IsStrictMediaMimeType("video/ogg")); + EXPECT_TRUE(IsStrictMediaMimeType("audio/ogg")); + EXPECT_TRUE(IsStrictMediaMimeType("application/ogg")); + + EXPECT_TRUE(IsStrictMediaMimeType("audio/mpeg")); + EXPECT_TRUE(IsStrictMediaMimeType("audio/mp3")); + EXPECT_TRUE(IsStrictMediaMimeType("audio/x-mp3")); + + EXPECT_TRUE(IsStrictMediaMimeType("video/mp4")); + EXPECT_TRUE(IsStrictMediaMimeType("video/x-m4v")); + EXPECT_TRUE(IsStrictMediaMimeType("audio/mp4")); + EXPECT_TRUE(IsStrictMediaMimeType("audio/x-m4a")); + + EXPECT_TRUE(IsStrictMediaMimeType("application/x-mpegurl")); + EXPECT_TRUE(IsStrictMediaMimeType("application/vnd.apple.mpegurl")); + + EXPECT_FALSE(IsStrictMediaMimeType("video/unknown")); + EXPECT_FALSE(IsStrictMediaMimeType("Video/UNKNOWN")); + EXPECT_FALSE(IsStrictMediaMimeType("audio/unknown")); + EXPECT_FALSE(IsStrictMediaMimeType("application/unknown")); + EXPECT_FALSE(IsStrictMediaMimeType("unknown/unknown")); +} + +TEST(MimeUtilTest, CommonMediaMimeType) { + EXPECT_TRUE(IsSupportedMediaMimeType("audio/webm")); + EXPECT_TRUE(IsSupportedMediaMimeType("video/webm")); + + EXPECT_TRUE(IsSupportedMediaMimeType("audio/wav")); + EXPECT_TRUE(IsSupportedMediaMimeType("audio/x-wav")); + + EXPECT_TRUE(IsSupportedMediaMimeType("audio/ogg")); + EXPECT_TRUE(IsSupportedMediaMimeType("application/ogg")); +#if defined(OS_ANDROID) + EXPECT_FALSE(IsSupportedMediaMimeType("video/ogg")); +#else + EXPECT_TRUE(IsSupportedMediaMimeType("video/ogg")); +#endif // OS_ANDROID + +#if defined(OS_ANDROID) + // HLS is supported on Android API level 14 and higher and Chrome supports + // API levels 15 and higher, so these are expected to be supported. + bool kHlsSupported = true; +#else + bool kHlsSupported = false; +#endif + + EXPECT_EQ(kHlsSupported, IsSupportedMediaMimeType("application/x-mpegurl")); + EXPECT_EQ(kHlsSupported, IsSupportedMediaMimeType("Application/X-MPEGURL")); + EXPECT_EQ(kHlsSupported, IsSupportedMediaMimeType( + "application/vnd.apple.mpegurl")); + +#if defined(USE_PROPRIETARY_CODECS) + EXPECT_TRUE(IsSupportedMediaMimeType("audio/mp4")); + EXPECT_TRUE(IsSupportedMediaMimeType("audio/x-m4a")); + EXPECT_TRUE(IsSupportedMediaMimeType("video/mp4")); + EXPECT_TRUE(IsSupportedMediaMimeType("video/x-m4v")); + + EXPECT_TRUE(IsSupportedMediaMimeType("audio/mp3")); + EXPECT_TRUE(IsSupportedMediaMimeType("audio/x-mp3")); + EXPECT_TRUE(IsSupportedMediaMimeType("audio/mpeg")); + EXPECT_TRUE(IsSupportedMediaMimeType("audio/aac")); + +#if defined(ENABLE_MPEG2TS_STREAM_PARSER) + EXPECT_TRUE(IsSupportedMediaMimeType("video/mp2t")); +#else + EXPECT_FALSE(IsSupportedMediaMimeType("video/mp2t")); +#endif +#else + EXPECT_FALSE(IsSupportedMediaMimeType("audio/mp4")); + EXPECT_FALSE(IsSupportedMediaMimeType("audio/x-m4a")); + EXPECT_FALSE(IsSupportedMediaMimeType("video/mp4")); + EXPECT_FALSE(IsSupportedMediaMimeType("video/x-m4v")); + + EXPECT_FALSE(IsSupportedMediaMimeType("audio/mp3")); + EXPECT_FALSE(IsSupportedMediaMimeType("audio/x-mp3")); + EXPECT_FALSE(IsSupportedMediaMimeType("audio/mpeg")); + EXPECT_FALSE(IsSupportedMediaMimeType("audio/aac")); +#endif // USE_PROPRIETARY_CODECS + EXPECT_FALSE(IsSupportedMediaMimeType("video/mp3")); + + EXPECT_FALSE(IsSupportedMediaMimeType("video/unknown")); + EXPECT_FALSE(IsSupportedMediaMimeType("audio/unknown")); + EXPECT_FALSE(IsSupportedMediaMimeType("unknown/unknown")); +} + +// Note: codecs should only be a list of 2 or fewer; hence the restriction of +// results' length to 2. +TEST(MimeUtilTest, ParseCodecString) { + const struct { + const char* const original; + size_t expected_size; + const char* const results[2]; + } tests[] = { + { "\"bogus\"", 1, { "bogus" } }, + { "0", 1, { "0" } }, + { "avc1.42E01E, mp4a.40.2", 2, { "avc1", "mp4a" } }, + { "\"mp4v.20.240, mp4a.40.2\"", 2, { "mp4v", "mp4a" } }, + { "mp4v.20.8, samr", 2, { "mp4v", "samr" } }, + { "\"theora, vorbis\"", 2, { "theora", "vorbis" } }, + { "", 0, { } }, + { "\"\"", 0, { } }, + { "\" \"", 0, { } }, + { ",", 2, { "", "" } }, + }; + + for (size_t i = 0; i < arraysize(tests); ++i) { + std::vector<std::string> codecs_out; + ParseCodecString(tests[i].original, &codecs_out, true); + ASSERT_EQ(tests[i].expected_size, codecs_out.size()); + for (size_t j = 0; j < tests[i].expected_size; ++j) + EXPECT_EQ(tests[i].results[j], codecs_out[j]); + } + + // Test without stripping the codec type. + std::vector<std::string> codecs_out; + ParseCodecString("avc1.42E01E, mp4a.40.2", &codecs_out, false); + ASSERT_EQ(2u, codecs_out.size()); + EXPECT_EQ("avc1.42E01E", codecs_out[0]); + EXPECT_EQ("mp4a.40.2", codecs_out[1]); +} + +} // namespace media
diff --git a/media/base/video_util.cc b/media/base/video_util.cc index d794674..e04a5a3c 100644 --- a/media/base/video_util.cc +++ b/media/base/video_util.cc
@@ -270,6 +270,23 @@ } } +// Common logic for the letterboxing and scale-within/scale-encompassing +// functions. Scales |size| to either fit within or encompass |target|, +// depending on whether |fit_within_target| is true. +static gfx::Size ScaleSizeToTarget(const gfx::Size& size, + const gfx::Size& target, + bool fit_within_target) { + if (size.IsEmpty()) + return gfx::Size(); // Corner case: Aspect ratio is undefined. + + const int64 x = static_cast<int64>(size.width()) * target.height(); + const int64 y = static_cast<int64>(size.height()) * target.width(); + const bool use_target_width = fit_within_target ? (y < x) : (x < y); + return use_target_width ? + gfx::Size(target.width(), static_cast<int>(y / size.width())) : + gfx::Size(static_cast<int>(x / size.height()), target.height()); +} + gfx::Rect ComputeLetterboxRegion(const gfx::Rect& bounds, const gfx::Size& content) { // If |content| has an undefined aspect ratio, let's not try to divide by @@ -277,19 +294,33 @@ if (content.IsEmpty()) return gfx::Rect(); - int64 x = static_cast<int64>(content.width()) * bounds.height(); - int64 y = static_cast<int64>(content.height()) * bounds.width(); - - gfx::Size letterbox(bounds.width(), bounds.height()); - if (y < x) - letterbox.set_height(static_cast<int>(y / content.width())); - else - letterbox.set_width(static_cast<int>(x / content.height())); gfx::Rect result = bounds; - result.ClampToCenteredSize(letterbox); + result.ClampToCenteredSize(ScaleSizeToTarget(content, bounds.size(), true)); return result; } +gfx::Size ScaleSizeToFitWithinTarget(const gfx::Size& size, + const gfx::Size& target) { + return ScaleSizeToTarget(size, target, true); +} + +gfx::Size ScaleSizeToEncompassTarget(const gfx::Size& size, + const gfx::Size& target) { + return ScaleSizeToTarget(size, target, false); +} + +gfx::Size PadToMatchAspectRatio(const gfx::Size& size, + const gfx::Size& target) { + if (target.IsEmpty()) + return gfx::Size(); // Aspect ratio is undefined. + + const int64 x = static_cast<int64>(size.width()) * target.height(); + const int64 y = static_cast<int64>(size.height()) * target.width(); + if (x < y) + return gfx::Size(static_cast<int>(y / target.height()), size.height()); + return gfx::Size(size.width(), static_cast<int>(x / target.width())); +} + void CopyRGBToVideoFrame(const uint8* source, int stride, const gfx::Rect& region_in_frame,
diff --git a/media/base/video_util.h b/media/base/video_util.h index 7798ebe0..abbcad4 100644 --- a/media/base/video_util.h +++ b/media/base/video_util.h
@@ -84,6 +84,29 @@ MEDIA_EXPORT gfx::Rect ComputeLetterboxRegion(const gfx::Rect& bounds, const gfx::Size& content); +// Return a scaled |size| whose area is less than or equal to |target|, where +// one of its dimensions is equal to |target|'s. The aspect ratio of |size| is +// preserved as closely as possible. If |size| is empty, the result will be +// empty. +MEDIA_EXPORT gfx::Size ScaleSizeToFitWithinTarget(const gfx::Size& size, + const gfx::Size& target); + +// Return a scaled |size| whose area is greater than or equal to |target|, where +// one of its dimensions is equal to |target|'s. The aspect ratio of |size| is +// preserved as closely as possible. If |size| is empty, the result will be +// empty. +MEDIA_EXPORT gfx::Size ScaleSizeToEncompassTarget(const gfx::Size& size, + const gfx::Size& target); + +// Returns |size| with only one of its dimensions increased such that the result +// matches the aspect ratio of |target|. This is different from +// ScaleSizeToEncompassTarget() in two ways: 1) The goal is to match the aspect +// ratio of |target| rather than that of |size|. 2) Only one of the dimensions +// of |size| may change, and it may only be increased (padded). If either +// |size| or |target| is empty, the result will be empty. +MEDIA_EXPORT gfx::Size PadToMatchAspectRatio(const gfx::Size& size, + const gfx::Size& target); + // Copy an RGB bitmap into the specified |region_in_frame| of a YUV video frame. // Fills the regions outside |region_in_frame| with black. MEDIA_EXPORT void CopyRGBToVideoFrame(const uint8* source,
diff --git a/media/base/video_util_unittest.cc b/media/base/video_util_unittest.cc index 9ac13c1f..79c5315 100644 --- a/media/base/video_util_unittest.cc +++ b/media/base/video_util_unittest.cc
@@ -328,6 +328,8 @@ INSTANTIATE_TEST_CASE_P(, VideoUtilRotationTest, testing::ValuesIn(kVideoRotationTestData)); +// Tests the ComputeLetterboxRegion function. Also, because of shared code +// internally, this also tests ScaleSizeToFitWithinTarget(). TEST_F(VideoUtilTest, ComputeLetterboxRegion) { EXPECT_EQ(gfx::Rect(167, 0, 666, 500), ComputeLetterboxRegion(gfx::Rect(0, 0, 1000, 500), @@ -348,6 +350,48 @@ gfx::Size(0, 0)).IsEmpty()); } +TEST_F(VideoUtilTest, ScaleSizeToEncompassTarget) { + EXPECT_EQ(gfx::Size(1000, 750), + ScaleSizeToEncompassTarget(gfx::Size(640, 480), + gfx::Size(1000, 500))); + EXPECT_EQ(gfx::Size(1333, 1000), + ScaleSizeToEncompassTarget(gfx::Size(640, 480), + gfx::Size(500, 1000))); + EXPECT_EQ(gfx::Size(1000, 562), + ScaleSizeToEncompassTarget(gfx::Size(1920, 1080), + gfx::Size(1000, 500))); + EXPECT_EQ(gfx::Size(133, 100), + ScaleSizeToEncompassTarget(gfx::Size(400, 300), + gfx::Size(100, 100))); + EXPECT_EQ(gfx::Size(2666666666, 2000000000), + ScaleSizeToEncompassTarget(gfx::Size(40000, 30000), + gfx::Size(2000000000, 2000000000))); + EXPECT_TRUE(ScaleSizeToEncompassTarget( + gfx::Size(0, 0), gfx::Size(2000000000, 2000000000)).IsEmpty()); +} + +TEST_F(VideoUtilTest, PadToMatchAspectRatio) { + EXPECT_EQ(gfx::Size(640, 480), + PadToMatchAspectRatio(gfx::Size(640, 480), gfx::Size(640, 480))); + EXPECT_EQ(gfx::Size(640, 480), + PadToMatchAspectRatio(gfx::Size(640, 480), gfx::Size(4, 3))); + EXPECT_EQ(gfx::Size(960, 480), + PadToMatchAspectRatio(gfx::Size(640, 480), gfx::Size(1000, 500))); + EXPECT_EQ(gfx::Size(640, 1280), + PadToMatchAspectRatio(gfx::Size(640, 480), gfx::Size(500, 1000))); + EXPECT_EQ(gfx::Size(2160, 1080), + PadToMatchAspectRatio(gfx::Size(1920, 1080), gfx::Size(1000, 500))); + EXPECT_EQ(gfx::Size(400, 400), + PadToMatchAspectRatio(gfx::Size(400, 300), gfx::Size(100, 100))); + EXPECT_EQ(gfx::Size(400, 400), + PadToMatchAspectRatio(gfx::Size(300, 400), gfx::Size(100, 100))); + EXPECT_EQ(gfx::Size(40000, 40000), + PadToMatchAspectRatio(gfx::Size(40000, 30000), + gfx::Size(2000000000, 2000000000))); + EXPECT_TRUE(PadToMatchAspectRatio( + gfx::Size(40000, 30000), gfx::Size(0, 0)).IsEmpty()); +} + TEST_F(VideoUtilTest, LetterboxYUV) { int width = 40; int height = 30;
diff --git a/media/blink/key_system_config_selector.cc b/media/blink/key_system_config_selector.cc index 24cbf9f3..ff53449d 100644 --- a/media/blink/key_system_config_selector.cc +++ b/media/blink/key_system_config_selector.cc
@@ -11,8 +11,8 @@ #include "media/base/cdm_config.h" #include "media/base/key_systems.h" #include "media/base/media_permission.h" +#include "media/base/mime_util.h" #include "media/blink/webmediaplayer_util.h" -#include "net/base/mime_util.h" #include "third_party/WebKit/public/platform/WebMediaKeySystemConfiguration.h" #include "third_party/WebKit/public/platform/WebSecurityOrigin.h" #include "third_party/WebKit/public/platform/WebString.h" @@ -284,7 +284,7 @@ std::string container_lower = base::StringToLowerASCII(container_mime_type); // Check that |container_mime_type| is supported by Chrome. - if (!net::IsSupportedMediaMimeType(container_lower)) + if (!media::IsSupportedMediaMimeType(container_lower)) return false; // Check that |codecs| are supported by Chrome. This is done primarily to @@ -292,10 +292,10 @@ // codecs that Chrome does not (which could complicate the robustness // algorithm). std::vector<std::string> codec_vector; - net::ParseCodecString(codecs, &codec_vector, false); + media::ParseCodecString(codecs, &codec_vector, false); if (!codec_vector.empty() && - (net::IsSupportedStrictMediaMimeType(container_lower, codec_vector) != - net::IsSupported)) { + (media::IsSupportedStrictMediaMimeType(container_lower, codec_vector) != + media::IsSupported)) { return false; } @@ -303,7 +303,7 @@ // This check does not handle extended codecs, so extended codec information // is stripped (extended codec information was checked above). std::vector<std::string> stripped_codec_vector; - net::ParseCodecString(codecs, &stripped_codec_vector, true); + media::ParseCodecString(codecs, &stripped_codec_vector, true); EmeConfigRule codecs_rule = key_systems_->GetContentTypeConfigRule( key_system, media_type, container_lower, stripped_codec_vector); if (!config_state->IsRuleSupported(codecs_rule))
diff --git a/media/cast/sender/fake_software_video_encoder.cc b/media/cast/sender/fake_software_video_encoder.cc index 7a2a333..0cd01396 100644 --- a/media/cast/sender/fake_software_video_encoder.cc +++ b/media/cast/sender/fake_software_video_encoder.cc
@@ -57,7 +57,7 @@ values.SetInteger("ref", encoded_frame->referenced_frame_id); values.SetInteger("id", encoded_frame->frame_id); values.SetInteger("size", frame_size_); - base::JSONWriter::Write(&values, &encoded_frame->data); + base::JSONWriter::Write(values, &encoded_frame->data); encoded_frame->data.resize( std::max<size_t>(encoded_frame->data.size(), frame_size_), ' '); }
diff --git a/media/cast/test/sender.cc b/media/cast/test/sender.cc index e34ecf12..73986987 100644 --- a/media/cast/test/sender.cc +++ b/media/cast/test/sender.cc
@@ -187,13 +187,13 @@ scoped_ptr<base::DictionaryValue> stats = video_event_subscriber->GetStats(); std::string json; base::JSONWriter::WriteWithOptions( - stats.get(), base::JSONWriter::OPTIONS_PRETTY_PRINT, &json); + *stats, base::JSONWriter::OPTIONS_PRETTY_PRINT, &json); VLOG(0) << "Video stats: " << json; stats = audio_event_subscriber->GetStats(); json.clear(); base::JSONWriter::WriteWithOptions( - stats.get(), base::JSONWriter::OPTIONS_PRETTY_PRINT, &json); + *stats, base::JSONWriter::OPTIONS_PRETTY_PRINT, &json); VLOG(0) << "Audio stats: " << json; }
diff --git a/media/cast/test/simulator.cc b/media/cast/test/simulator.cc index 6c277d56..a3a560e 100644 --- a/media/cast/test/simulator.cc +++ b/media/cast/test/simulator.cc
@@ -766,7 +766,7 @@ values.SetString("sim-id", sim_id); std::string extra_data; - base::JSONWriter::Write(&values, &extra_data); + base::JSONWriter::Write(values, &extra_data); // Run. media::cast::RunSimulation(source_path, log_output_path, metrics_output_path,
diff --git a/media/formats/mp4/box_definitions.cc b/media/formats/mp4/box_definitions.cc index a08cb26d..5a15240 100644 --- a/media/formats/mp4/box_definitions.cc +++ b/media/formats/mp4/box_definitions.cc
@@ -657,12 +657,15 @@ FourCC Movie::BoxType() const { return FOURCC_MOOV; } bool Movie::Parse(BoxReader* reader) { - return reader->ScanChildren() && - reader->ReadChild(&header) && - reader->ReadChildren(&tracks) && - // Media Source specific: 'mvex' required - reader->ReadChild(&extends) && - reader->MaybeReadChildren(&pssh); + RCHECK(reader->ScanChildren() && reader->ReadChild(&header) && + reader->ReadChildren(&tracks)); + + RCHECK_MEDIA_LOGGED(reader->ReadChild(&extends), reader->log_cb(), + "Detected unfragmented MP4. Media Source Extensions " + "require ISO BMFF moov to contain mvex to indicate that " + "Movie Fragments are to be expected."); + + return reader->MaybeReadChildren(&pssh); } TrackFragmentDecodeTime::TrackFragmentDecodeTime() : decode_time(0) {}
diff --git a/media/formats/mp4/box_definitions.h b/media/formats/mp4/box_definitions.h index 1271403..026effe 100644 --- a/media/formats/mp4/box_definitions.h +++ b/media/formats/mp4/box_definitions.h
@@ -11,6 +11,7 @@ #include "base/basictypes.h" #include "base/compiler_specific.h" #include "media/base/media_export.h" +#include "media/base/media_log.h" #include "media/formats/mp4/aac.h" #include "media/formats/mp4/avc.h" #include "media/formats/mp4/box_reader.h"
diff --git a/media/formats/mp4/box_reader.cc b/media/formats/mp4/box_reader.cc index edebddd..5105726d 100644 --- a/media/formats/mp4/box_reader.cc +++ b/media/formats/mp4/box_reader.cc
@@ -219,7 +219,8 @@ CHECK(Read4Into8(&size) && ReadFourCC(&type_)); if (size == 0) { - // Media Source specific: we do not support boxes that run to EOS. + MEDIA_LOG(DEBUG, log_cb_) << "Media Source Extensions do not support ISO " + "BMFF boxes that run to EOS"; *err = true; return false; } else if (size == 1) {
diff --git a/media/formats/mp4/box_reader.h b/media/formats/mp4/box_reader.h index 3360204..6b59361 100644 --- a/media/formats/mp4/box_reader.h +++ b/media/formats/mp4/box_reader.h
@@ -22,7 +22,10 @@ struct MEDIA_EXPORT Box { virtual ~Box(); + + // Parse errors may be logged using the BoxReader's log callback. virtual bool Parse(BoxReader* reader) = 0; + virtual FourCC BoxType() const = 0; };
diff --git a/media/formats/mp4/rcheck.h b/media/formats/mp4/rcheck.h index fb0f8f27..d756487 100644 --- a/media/formats/mp4/rcheck.h +++ b/media/formats/mp4/rcheck.h
@@ -6,13 +6,25 @@ #define MEDIA_FORMATS_MP4_RCHECK_H_ #include "base/logging.h" +#include "media/base/media_log.h" -#define RCHECK(x) \ - do { \ - if (!(x)) { \ - DLOG(ERROR) << "Failure while parsing MP4: " << #x; \ - return false; \ - } \ - } while (0) +#define RCHECK_MEDIA_LOGGED(condition, log_cb, msg) \ + do { \ + if (!(condition)) { \ + DLOG(ERROR) << "Failure while parsing MP4: " #condition; \ + MEDIA_LOG(ERROR, log_cb) << "Failure parsing MP4: " << (msg); \ + return false; \ + } \ + } while (0) + +// TODO(wolenetz,chcunningham): Where appropriate, replace usage of this macro +// in favor of RCHECK_MEDIA_LOGGED. See https://crbug.com/487410. +#define RCHECK(condition) \ + do { \ + if (!(condition)) { \ + DLOG(ERROR) << "Failure while parsing MP4: " #condition; \ + return false; \ + } \ + } while (0) #endif // MEDIA_FORMATS_MP4_RCHECK_H_
diff --git a/media/media.gyp b/media/media.gyp index ed6aa66..312f426 100644 --- a/media/media.gyp +++ b/media/media.gyp
@@ -259,6 +259,7 @@ 'base/byte_queue.h', 'base/cdm_callback_promise.cc', 'base/cdm_callback_promise.h', + 'base/cdm_config.h', 'base/cdm_context.cc', 'base/cdm_context.h', 'base/cdm_factory.cc', @@ -330,6 +331,8 @@ 'base/media_switches.cc', 'base/media_switches.h', 'base/media_win.cc', + 'base/mime_util.cc', + 'base/mime_util.h', 'base/moving_average.cc', 'base/moving_average.h', 'base/multi_channel_resampler.cc', @@ -1141,6 +1144,7 @@ 'base/key_systems_unittest.cc', 'base/mac/video_frame_mac_unittests.cc', 'base/media_file_checker_unittest.cc', + 'base/mime_util_unittest.cc', 'base/moving_average_unittest.cc', 'base/multi_channel_resampler_unittest.cc', 'base/null_video_sink_unittest.cc',
diff --git a/mojo/runner/android/apk/src/org/chromium/mojo/shell/MojoShellActivity.java b/mojo/runner/android/apk/src/org/chromium/mojo/shell/MojoShellActivity.java index a56c43d..901012fb 100644 --- a/mojo/runner/android/apk/src/org/chromium/mojo/shell/MojoShellActivity.java +++ b/mojo/runner/android/apk/src/org/chromium/mojo/shell/MojoShellActivity.java
@@ -6,9 +6,11 @@ import android.app.Activity; import android.content.Intent; +import android.net.Uri; import android.os.Bundle; import android.util.JsonReader; -import android.util.Log; + +import org.chromium.base.Log; import java.io.IOException; import java.io.StringReader; @@ -25,6 +27,22 @@ protected void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); + String[] parameters = getParametersFromIntent(getIntent()); + if (Intent.ACTION_VIEW.equals(getIntent().getAction())) { + Uri uri = getIntent().getData(); + if (uri != null) { + Log.i(TAG, "MojoShellActivity opening " + uri); + if (parameters == null) { + parameters = new String[] {uri.toString()}; + } else { + String[] newParameters = new String[parameters.length + 1]; + System.arraycopy(parameters, 0, newParameters, 0, parameters.length); + newParameters[parameters.length] = uri.toString(); + parameters = newParameters; + } + } + } + // TODO(ppi): Gotcha - the call below will work only once per process lifetime, but the OS // has no obligation to kill the application process between destroying and restarting the // activity. If the application process is kept alive, initialization parameters sent with @@ -32,7 +50,7 @@ // TODO(qsr): We should be passing application context here as required by // InitApplicationContext on the native side. Currently we can't, as PlatformViewportAndroid // relies on this being the activity context. - ShellMain.ensureInitialized(this, getParametersFromIntent(getIntent())); + ShellMain.ensureInitialized(this, parameters); // TODO(eseidel): ShellMain can fail, but we're ignoring the return. ShellMain.start();
diff --git a/mojo/services/network/BUILD.gn b/mojo/services/network/BUILD.gn index 203bd5e..4cc0839 100644 --- a/mojo/services/network/BUILD.gn +++ b/mojo/services/network/BUILD.gn
@@ -115,6 +115,7 @@ testonly = true sources = [ + "http_server_apptest.cc", "udp_socket_apptest.cc", "url_loader_impl_apptest.cc", ]
diff --git a/mojo/services/network/http_connection_impl.cc b/mojo/services/network/http_connection_impl.cc index 47449ecd..be306cd 100644 --- a/mojo/services/network/http_connection_impl.cc +++ b/mojo/services/network/http_connection_impl.cc
@@ -6,14 +6,114 @@ #include <limits> +#include "base/bind_helpers.h" +#include "base/callback.h" +#include "base/logging.h" +#include "base/stl_util.h" +#include "base/strings/string_util.h" +#include "mojo/common/handle_watcher.h" #include "mojo/services/network/http_server_impl.h" #include "mojo/services/network/net_adapters.h" #include "net/base/net_errors.h" +#include "net/http/http_request_headers.h" +#include "net/http/http_status_code.h" #include "net/server/http_server.h" #include "net/server/http_server_request_info.h" +#include "net/server/http_server_response_info.h" +#include "third_party/mojo/src/mojo/public/cpp/bindings/type_converter.h" +#include "third_party/mojo/src/mojo/public/cpp/system/data_pipe.h" namespace mojo { +// SimpleDataPipeReader reads till end-of-file, stores the data in a string and +// notifies completion. +class HttpConnectionImpl::SimpleDataPipeReader { + public: + using CompletionCallback = + base::Callback<void(SimpleDataPipeReader*, scoped_ptr<std::string>)>; + + SimpleDataPipeReader() {} + ~SimpleDataPipeReader() {} + + void Start(ScopedDataPipeConsumerHandle consumer, + const CompletionCallback& completion_callback) { + DCHECK(consumer.is_valid() && !consumer_.is_valid()); + consumer_ = consumer.Pass(); + completion_callback_ = completion_callback; + buffer_.reset(new std::string); + ReadMore(); + } + + private: + void ReadMore() { + const void* buf; + uint32_t buf_size; + MojoResult rv = BeginReadDataRaw(consumer_.get(), &buf, &buf_size, + MOJO_READ_DATA_FLAG_NONE); + if (rv == MOJO_RESULT_OK) { + buffer_->append(static_cast<const char*>(buf), buf_size); + EndReadDataRaw(consumer_.get(), buf_size); + WaitToReadMore(); + } else if (rv == MOJO_RESULT_SHOULD_WAIT) { + WaitToReadMore(); + } else if (rv == MOJO_RESULT_FAILED_PRECONDITION) { + // We reached end-of-file. + completion_callback_.Run(this, buffer_.Pass()); + // Note: This object may have been destroyed in the callback. + } else { + CHECK(false); + } + } + + void WaitToReadMore() { + watcher_.Start(consumer_.get(), MOJO_HANDLE_SIGNAL_READABLE, + MOJO_DEADLINE_INDEFINITE, + base::Bind(&SimpleDataPipeReader::OnHandleReady, + base::Unretained(this))); + } + + void OnHandleReady(MojoResult result) { ReadMore(); } + + ScopedDataPipeConsumerHandle consumer_; + common::HandleWatcher watcher_; + CompletionCallback completion_callback_; + scoped_ptr<std::string> buffer_; + + DISALLOW_COPY_AND_ASSIGN(SimpleDataPipeReader); +}; + +template <> +struct TypeConverter<HttpRequestPtr, net::HttpServerRequestInfo> { + static HttpRequestPtr Convert(const net::HttpServerRequestInfo& obj) { + HttpRequestPtr request(HttpRequest::New()); + request->method = obj.method; + request->url = obj.path; + request->headers.resize(obj.headers.size()); + size_t index = 0; + for (const auto& item : obj.headers) { + HttpHeaderPtr header(HttpHeader::New()); + header->name = item.first; + header->value = item.second; + request->headers[index++] = header.Pass(); + } + if (!obj.data.empty()) { + uint32_t num_bytes = static_cast<uint32_t>(obj.data.size()); + MojoCreateDataPipeOptions options; + options.struct_size = sizeof(MojoCreateDataPipeOptions); + options.flags = MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE; + options.element_num_bytes = 1; + options.capacity_num_bytes = num_bytes; + DataPipe data_pipe(options); + request->body = data_pipe.consumer_handle.Pass(); + MojoResult result = + WriteDataRaw(data_pipe.producer_handle.get(), obj.data.data(), + &num_bytes, MOJO_WRITE_DATA_FLAG_ALL_OR_NONE); + CHECK_EQ(MOJO_RESULT_OK, result); + } + return request.Pass(); + } +}; + HttpConnectionImpl::HttpConnectionImpl(int connection_id, HttpServerImpl* owner, HttpConnectionDelegatePtr delegate, @@ -22,15 +122,33 @@ owner_(owner), delegate_(delegate.Pass()), binding_(this, connection) { + DCHECK(delegate_); binding_.set_error_handler(this); delegate_.set_error_handler(this); } -HttpConnectionImpl::~HttpConnectionImpl() {} +HttpConnectionImpl::~HttpConnectionImpl() { + STLDeleteElements(&response_body_readers_); +} void HttpConnectionImpl::OnReceivedHttpRequest( const net::HttpServerRequestInfo& info) { - // TODO(yzshen): implement it. + if (EncounteredConnectionError()) + return; + + delegate_->OnReceivedRequest( + HttpRequest::From(info), [this](HttpResponsePtr response) { + if (response->body.is_valid()) { + SimpleDataPipeReader* reader = new SimpleDataPipeReader; + response_body_readers_.insert(reader); + reader->Start( + response->body.Pass(), + base::Bind(&HttpConnectionImpl::OnFinishedReadingResponseBody, + base::Unretained(this), base::Passed(&response))); + } else { + OnFinishedReadingResponseBody(response.Pass(), nullptr, nullptr); + } + }); } void HttpConnectionImpl::OnReceivedWebSocketRequest( @@ -65,9 +183,61 @@ } void HttpConnectionImpl::OnConnectionError() { - // The proxy side of |binding_| or the impl side of |delegate_| has closed the - // pipe. The connection is not needed anymore. - owner_->server()->Close(connection_id_); + // This method is called when the proxy side of |binding_| or the impl side of + // |delegate_| has closed the pipe. Although it is set as error handler for + // both |binding_| and |delegate_|, it will only be called at most once + // because when called it closes/resets |binding_| and |delegate_|. + DCHECK(!EncounteredConnectionError()); + + binding_.Close(); + delegate_.reset(); + + // Don't close the connection until all pending responses are sent. + if (response_body_readers_.empty()) + owner_->server()->Close(connection_id_); +} + +void HttpConnectionImpl::OnFinishedReadingResponseBody( + HttpResponsePtr response, + SimpleDataPipeReader* reader, + scoped_ptr<std::string> body) { + if (reader) { + delete reader; + response_body_readers_.erase(reader); + } + + net::HttpServerResponseInfo info( + static_cast<net::HttpStatusCode>(response->status_code)); + + std::string content_type; + for (size_t i = 0; i < response->headers.size(); ++i) { + const HttpHeader& header = *(response->headers[i]); + + if (body) { + // net::HttpServerResponseInfo::SetBody() automatically sets + // Content-Length and Content-Types, so skip the two here. + // + // TODO(yzshen): Consider adding to net::HttpServerResponseInfo a simple + // setter for body which doesn't fiddle with headers. + if (base::strcasecmp(header.name.data(), + net::HttpRequestHeaders::kContentLength) == 0) { + continue; + } else if (base::strcasecmp(header.name.data(), + net::HttpRequestHeaders::kContentType) == 0) { + content_type = header.value; + continue; + } + } + info.AddHeader(header.name, header.value); + } + + if (body) + info.SetBody(*body, content_type); + + owner_->server()->SendResponse(connection_id_, info); + + if (response_body_readers_.empty() && EncounteredConnectionError()) + owner_->server()->Close(connection_id_); } } // namespace mojo
diff --git a/mojo/services/network/http_connection_impl.h b/mojo/services/network/http_connection_impl.h index 84d669a7..7f952310 100644 --- a/mojo/services/network/http_connection_impl.h +++ b/mojo/services/network/http_connection_impl.h
@@ -5,10 +5,13 @@ #ifndef MOJO_SERVICES_NETWORK_HTTP_CONNECTION_IMPL_H_ #define MOJO_SERVICES_NETWORK_HTTP_CONNECTION_IMPL_H_ +#include <set> #include <string> #include "base/macros.h" +#include "base/memory/scoped_ptr.h" #include "mojo/services/network/public/interfaces/http_connection.mojom.h" +#include "mojo/services/network/public/interfaces/http_message.mojom.h" #include "third_party/mojo/src/mojo/public/cpp/bindings/binding.h" #include "third_party/mojo/src/mojo/public/cpp/bindings/error_handler.h" @@ -36,6 +39,8 @@ void OnReceivedWebSocketMessage(const std::string& data); private: + class SimpleDataPipeReader; + // HttpConnection implementation. void SetSendBufferSize(uint32_t size, const SetSendBufferSizeCallback& callback) override; @@ -46,10 +51,20 @@ // ErrorHandler implementation. void OnConnectionError() override; + void OnFinishedReadingResponseBody(HttpResponsePtr response_ptr, + SimpleDataPipeReader* reader, + scoped_ptr<std::string> body); + + bool EncounteredConnectionError() const { + return !binding_.is_bound() || !delegate_; + } + const int connection_id_; HttpServerImpl* const owner_; HttpConnectionDelegatePtr delegate_; Binding<HttpConnection> binding_; + // Owns its elements. + std::set<SimpleDataPipeReader*> response_body_readers_; DISALLOW_COPY_AND_ASSIGN(HttpConnectionImpl); };
diff --git a/mojo/services/network/http_server_apptest.cc b/mojo/services/network/http_server_apptest.cc new file mode 100644 index 0000000..1fe8e50 --- /dev/null +++ b/mojo/services/network/http_server_apptest.cc
@@ -0,0 +1,481 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/macros.h" +#include "base/memory/linked_ptr.h" +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "base/run_loop.h" +#include "base/strings/string_util.h" +#include "mojo/application/application_test_base_chromium.h" +#include "mojo/application/public/cpp/application_connection.h" +#include "mojo/application/public/cpp/application_impl.h" +#include "mojo/common/data_pipe_utils.h" +#include "mojo/services/network/net_address_type_converters.h" +#include "mojo/services/network/public/interfaces/http_server.mojom.h" +#include "mojo/services/network/public/interfaces/network_service.mojom.h" +#include "net/base/io_buffer.h" +#include "net/base/net_errors.h" +#include "net/base/test_completion_callback.h" +#include "net/http/http_response_headers.h" +#include "net/http/http_util.h" +#include "net/socket/tcp_client_socket.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace mojo { +namespace { + +const int kMaxExpectedResponseLength = 2048; + +NetAddressPtr GetLocalHostWithAnyPort() { + NetAddressPtr addr(NetAddress::New()); + addr->family = NET_ADDRESS_FAMILY_IPV4; + addr->ipv4 = NetAddressIPv4::New(); + addr->ipv4->port = 0; + addr->ipv4->addr.resize(4); + addr->ipv4->addr[0] = 127; + addr->ipv4->addr[1] = 0; + addr->ipv4->addr[2] = 0; + addr->ipv4->addr[3] = 1; + + return addr.Pass(); +} + +using TestHeaders = std::vector<std::pair<std::string, std::string>>; + +struct TestRequest { + std::string method; + std::string url; + TestHeaders headers; + scoped_ptr<std::string> body; +}; + +struct TestResponse { + uint32_t status_code; + TestHeaders headers; + scoped_ptr<std::string> body; +}; + +std::string MakeRequestMessage(const TestRequest& data) { + std::string message = data.method + " " + data.url + " HTTP/1.1\r\n"; + for (const auto& item : data.headers) + message += item.first + ": " + item.second + "\r\n"; + message += "\r\n"; + if (data.body) + message += *data.body; + + return message; +} + +HttpResponsePtr MakeResponseStruct(const TestResponse& data) { + HttpResponsePtr response(HttpResponse::New()); + response->status_code = data.status_code; + response->headers.resize(data.headers.size()); + size_t index = 0; + for (const auto& item : data.headers) { + HttpHeaderPtr header(HttpHeader::New()); + header->name = item.first; + header->value = item.second; + response->headers[index++] = header.Pass(); + } + + if (data.body) { + uint32_t num_bytes = static_cast<uint32_t>(data.body->size()); + MojoCreateDataPipeOptions options; + options.struct_size = sizeof(MojoCreateDataPipeOptions); + options.flags = MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE; + options.element_num_bytes = 1; + options.capacity_num_bytes = num_bytes; + DataPipe data_pipe(options); + response->body = data_pipe.consumer_handle.Pass(); + MojoResult result = + WriteDataRaw(data_pipe.producer_handle.get(), data.body->data(), + &num_bytes, MOJO_WRITE_DATA_FLAG_ALL_OR_NONE); + EXPECT_EQ(MOJO_RESULT_OK, result); + } + + return response.Pass(); +} + +void CheckHeaders(const TestHeaders& expected, + const Array<HttpHeaderPtr>& headers) { + // The server impl fiddles with Content-Length and Content-Type. So we don't + // do a strict check here. + std::map<std::string, std::string> header_map; + for (size_t i = 0; i < headers.size(); ++i) { + std::string lower_name = + base::StringToLowerASCII(headers[i]->name.To<std::string>()); + header_map[lower_name] = headers[i]->value; + } + + for (const auto& item : expected) { + std::string lower_name = base::StringToLowerASCII(item.first); + EXPECT_NE(header_map.end(), header_map.find(lower_name)); + EXPECT_EQ(item.second, header_map[lower_name]); + } +} + +void CheckRequest(const TestRequest& expected, HttpRequestPtr request) { + EXPECT_EQ(expected.method, request->method); + EXPECT_EQ(expected.url, request->url); + CheckHeaders(expected.headers, request->headers); + if (expected.body) { + EXPECT_TRUE(request->body.is_valid()); + std::string body; + common::BlockingCopyToString(request->body.Pass(), &body); + EXPECT_EQ(*expected.body, body); + } else { + EXPECT_FALSE(request->body.is_valid()); + } +} + +void CheckResponse(const TestResponse& expected, const std::string& response) { + int header_end = + net::HttpUtil::LocateEndOfHeaders(response.c_str(), response.size()); + std::string assembled_headers = + net::HttpUtil::AssembleRawHeaders(response.c_str(), header_end); + scoped_refptr<net::HttpResponseHeaders> parsed_headers( + new net::HttpResponseHeaders(assembled_headers)); + EXPECT_EQ(expected.status_code, + static_cast<uint32_t>(parsed_headers->response_code())); + for (const auto& item : expected.headers) + EXPECT_TRUE(parsed_headers->HasHeaderValue(item.first, item.second)); + + if (expected.body) { + EXPECT_NE(-1, header_end); + std::string body(response, static_cast<size_t>(header_end)); + EXPECT_EQ(*expected.body, body); + } else { + EXPECT_EQ(response.size(), static_cast<size_t>(header_end)); + } +} + +class TestHttpClient { + public: + TestHttpClient() : connect_result_(net::OK) {} + + void Connect(const net::IPEndPoint& address) { + net::AddressList addresses(address); + net::NetLog::Source source; + socket_.reset(new net::TCPClientSocket(addresses, NULL, source)); + + base::RunLoop run_loop; + connect_result_ = socket_->Connect(base::Bind(&TestHttpClient::OnConnect, + base::Unretained(this), + run_loop.QuitClosure())); + if (connect_result_ == net::ERR_IO_PENDING) + run_loop.Run(); + + ASSERT_EQ(net::OK, connect_result_); + } + + void Send(const std::string& data) { + write_buffer_ = new net::DrainableIOBuffer(new net::StringIOBuffer(data), + data.length()); + Write(); + } + + // Note: This method determines the end of the response only by Content-Length + // and connection termination. Besides, it doesn't truncate at the end of the + // response, so |message| may return more data (e.g., part of the next + // response). + void ReadResponse(std::string* message) { + if (!Read(message, 1)) + return; + while (!IsCompleteResponse(*message)) { + std::string chunk; + if (!Read(&chunk, 1)) + return; + message->append(chunk); + } + return; + } + + private: + void OnConnect(const base::Closure& quit_loop, int result) { + connect_result_ = result; + quit_loop.Run(); + } + + void Write() { + int result = socket_->Write( + write_buffer_.get(), write_buffer_->BytesRemaining(), + base::Bind(&TestHttpClient::OnWrite, base::Unretained(this))); + if (result != net::ERR_IO_PENDING) + OnWrite(result); + } + + void OnWrite(int result) { + ASSERT_GT(result, 0); + write_buffer_->DidConsume(result); + if (write_buffer_->BytesRemaining()) + Write(); + } + + bool Read(std::string* message, int expected_bytes) { + int total_bytes_received = 0; + message->clear(); + while (total_bytes_received < expected_bytes) { + net::TestCompletionCallback callback; + ReadInternal(callback.callback()); + int bytes_received = callback.WaitForResult(); + if (bytes_received <= 0) + return false; + + total_bytes_received += bytes_received; + message->append(read_buffer_->data(), bytes_received); + } + return true; + } + + void ReadInternal(const net::CompletionCallback& callback) { + read_buffer_ = new net::IOBufferWithSize(kMaxExpectedResponseLength); + int result = + socket_->Read(read_buffer_.get(), kMaxExpectedResponseLength, callback); + if (result != net::ERR_IO_PENDING) + callback.Run(result); + } + + bool IsCompleteResponse(const std::string& response) { + // Check end of headers first. + int end_of_headers = + net::HttpUtil::LocateEndOfHeaders(response.data(), response.size()); + if (end_of_headers < 0) + return false; + + // Return true if response has data equal to or more than content length. + int64 body_size = static_cast<int64>(response.size()) - end_of_headers; + DCHECK_LE(0, body_size); + scoped_refptr<net::HttpResponseHeaders> headers( + new net::HttpResponseHeaders(net::HttpUtil::AssembleRawHeaders( + response.data(), end_of_headers))); + return body_size >= headers->GetContentLength(); + } + + scoped_refptr<net::IOBufferWithSize> read_buffer_; + scoped_refptr<net::DrainableIOBuffer> write_buffer_; + scoped_ptr<net::TCPClientSocket> socket_; + int connect_result_; + + DISALLOW_COPY_AND_ASSIGN(TestHttpClient); +}; + +class HttpConnectionDelegateImpl : public HttpConnectionDelegate { + public: + struct PendingRequest { + HttpRequestPtr request; + OnReceivedRequestCallback callback; + }; + + HttpConnectionDelegateImpl(HttpConnectionPtr connection, + InterfaceRequest<HttpConnectionDelegate> request) + : connection_(connection.Pass()), + binding_(this, request.Pass()), + run_loop_(nullptr), + wait_for_request_count_(0) {} + ~HttpConnectionDelegateImpl() override {} + + // HttpConnectionDelegate implementation: + void OnReceivedRequest(HttpRequestPtr request, + const OnReceivedRequestCallback& callback) override { + linked_ptr<PendingRequest> pending_request(new PendingRequest); + pending_request->request = request.Pass(); + pending_request->callback = callback; + pending_requests_.push_back(pending_request); + if (run_loop_ && pending_requests_.size() >= wait_for_request_count_) { + wait_for_request_count_ = 0; + run_loop_->Quit(); + } + } + + void OnReceivedWebSocketRequest( + HttpRequestPtr request, + const OnReceivedWebSocketRequestCallback& callback) override { + NOTREACHED(); + } + + void SendResponse(HttpResponsePtr response) { + ASSERT_FALSE(pending_requests_.empty()); + linked_ptr<PendingRequest> request = pending_requests_[0]; + pending_requests_.erase(pending_requests_.begin()); + request->callback.Run(response.Pass()); + } + + void WaitForRequest(size_t count) { + DCHECK(!run_loop_); + + wait_for_request_count_ = count; + base::RunLoop run_loop; + run_loop_ = &run_loop; + run_loop.Run(); + run_loop_ = nullptr; + } + + std::vector<linked_ptr<PendingRequest>>& pending_requests() { + return pending_requests_; + } + + private: + HttpConnectionPtr connection_; + Binding<HttpConnectionDelegate> binding_; + std::vector<linked_ptr<PendingRequest>> pending_requests_; + // Pointing to a stack-allocated RunLoop instance. + base::RunLoop* run_loop_; + size_t wait_for_request_count_; + + DISALLOW_COPY_AND_ASSIGN(HttpConnectionDelegateImpl); +}; + +class HttpServerDelegateImpl : public HttpServerDelegate { + public: + explicit HttpServerDelegateImpl(HttpServerDelegatePtr* delegate_ptr) + : binding_(this, delegate_ptr), + run_loop_(nullptr), + wait_for_connection_count_(0) {} + ~HttpServerDelegateImpl() override {} + + // HttpServerDelegate implementation. + void OnConnected(HttpConnectionPtr connection, + InterfaceRequest<HttpConnectionDelegate> delegate) override { + connections_.push_back(make_linked_ptr( + new HttpConnectionDelegateImpl(connection.Pass(), delegate.Pass()))); + if (run_loop_ && connections_.size() >= wait_for_connection_count_) { + wait_for_connection_count_ = 0; + run_loop_->Quit(); + } + } + + void WaitForConnection(size_t count) { + DCHECK(!run_loop_); + + wait_for_connection_count_ = count; + base::RunLoop run_loop; + run_loop_ = &run_loop; + run_loop.Run(); + run_loop_ = nullptr; + } + + std::vector<linked_ptr<HttpConnectionDelegateImpl>>& connections() { + return connections_; + } + + private: + Binding<HttpServerDelegate> binding_; + std::vector<linked_ptr<HttpConnectionDelegateImpl>> connections_; + // Pointing to a stack-allocated RunLoop instance. + base::RunLoop* run_loop_; + size_t wait_for_connection_count_; + + DISALLOW_COPY_AND_ASSIGN(HttpServerDelegateImpl); +}; + +class HttpServerAppTest : public test::ApplicationTestBase { + public: + HttpServerAppTest() : message_loop_(base::MessageLoop::TYPE_IO) {} + ~HttpServerAppTest() override {} + + protected: + bool ShouldCreateDefaultRunLoop() override { return false; } + + void SetUp() override { + ApplicationTestBase::SetUp(); + + ApplicationConnection* connection = + application_impl()->ConnectToApplication("mojo:network_service"); + connection->ConnectToService(&network_service_); + } + + void CreateHttpServer(HttpServerDelegatePtr delegate, + NetAddressPtr* out_bound_to) { + network_service_->CreateHttpServer( + GetLocalHostWithAnyPort(), delegate.Pass(), + [out_bound_to](NetworkErrorPtr result, NetAddressPtr bound_to) { + ASSERT_EQ(net::OK, result->code); + EXPECT_NE(0u, bound_to->ipv4->port); + *out_bound_to = bound_to.Pass(); + }); + network_service_.WaitForIncomingMethodCall(); + } + + NetworkServicePtr network_service_; + + private: + base::MessageLoop message_loop_; + + DISALLOW_COPY_AND_ASSIGN(HttpServerAppTest); +}; + +} // namespace + +TEST_F(HttpServerAppTest, BasicHttpRequestResponse) { + NetAddressPtr bound_to; + HttpServerDelegatePtr server_delegate_ptr; + HttpServerDelegateImpl server_delegate_impl(&server_delegate_ptr); + CreateHttpServer(server_delegate_ptr.Pass(), &bound_to); + + TestHttpClient client; + client.Connect(bound_to.To<net::IPEndPoint>()); + + server_delegate_impl.WaitForConnection(1); + HttpConnectionDelegateImpl& connection = + *server_delegate_impl.connections()[0]; + + TestRequest request_data = {"HEAD", "/test", {{"Hello", "World"}}, nullptr}; + client.Send(MakeRequestMessage(request_data)); + + connection.WaitForRequest(1); + + CheckRequest(request_data, connection.pending_requests()[0]->request.Pass()); + + TestResponse response_data = {200, {{"Content-Length", "4"}}, nullptr}; + connection.SendResponse(MakeResponseStruct(response_data)); + // This causes the underlying TCP connection to be closed. The client can + // determine the end of the response based on that. + server_delegate_impl.connections().clear(); + + std::string response_message; + client.ReadResponse(&response_message); + + CheckResponse(response_data, response_message); +} + +TEST_F(HttpServerAppTest, HttpRequestResponseWithBody) { + NetAddressPtr bound_to; + HttpServerDelegatePtr server_delegate_ptr; + HttpServerDelegateImpl server_delegate_impl(&server_delegate_ptr); + CreateHttpServer(server_delegate_ptr.Pass(), &bound_to); + + TestHttpClient client; + client.Connect(bound_to.To<net::IPEndPoint>()); + + server_delegate_impl.WaitForConnection(1); + HttpConnectionDelegateImpl& connection = + *server_delegate_impl.connections()[0]; + + TestRequest request_data = { + "Post", + "/test", + {{"Hello", "World"}, + {"Content-Length", "23"}, + {"Content-Type", "text/plain"}}, + make_scoped_ptr(new std::string("This is a test request!"))}; + client.Send(MakeRequestMessage(request_data)); + + connection.WaitForRequest(1); + + CheckRequest(request_data, connection.pending_requests()[0]->request.Pass()); + + TestResponse response_data = { + 200, + {{"Content-Length", "26"}}, + make_scoped_ptr(new std::string("This is a test response..."))}; + connection.SendResponse(MakeResponseStruct(response_data)); + + std::string response_message; + client.ReadResponse(&response_message); + + CheckResponse(response_data, response_message); +} + +} // namespace mojo
diff --git a/mojo/services/network/public/interfaces/BUILD.gn b/mojo/services/network/public/interfaces/BUILD.gn index 9b5c50f..79ddbdc 100644 --- a/mojo/services/network/public/interfaces/BUILD.gn +++ b/mojo/services/network/public/interfaces/BUILD.gn
@@ -9,6 +9,7 @@ sources = [ "cookie_store.mojom", "http_connection.mojom", + "http_message.mojom", "http_server.mojom", "net_address.mojom", "network_error.mojom",
diff --git a/mojo/services/network/public/interfaces/http_connection.mojom b/mojo/services/network/public/interfaces/http_connection.mojom index bf98038..1733ed22 100644 --- a/mojo/services/network/public/interfaces/http_connection.mojom +++ b/mojo/services/network/public/interfaces/http_connection.mojom
@@ -4,7 +4,7 @@ module mojo; -import "network/public/interfaces/url_loader.mojom"; +import "network/public/interfaces/http_message.mojom"; import "network/public/interfaces/network_error.mojom"; import "network/public/interfaces/web_socket.mojom"; @@ -18,7 +18,7 @@ interface HttpConnectionDelegate { // Called when an HTTP request is received. - OnReceivedRequest(URLRequest request) => (URLResponse response); + OnReceivedRequest(HttpRequest request) => (HttpResponse response); // Called when an WebSocket request is received. // @@ -28,7 +28,7 @@ // WebSocket should be written to the producer end of the |send_stream|. // |web_socket| will be already connected. There is no need to call Connect() // on it. But |client| will still receive a DidConnect() notification. - OnReceivedWebSocketRequest(URLRequest request) + OnReceivedWebSocketRequest(HttpRequest request) => (WebSocket&? web_socket, handle<data_pipe_consumer>? send_stream, WebSocketClient? client);
diff --git a/mojo/services/network/public/interfaces/http_message.mojom b/mojo/services/network/public/interfaces/http_message.mojom new file mode 100644 index 0000000..b89ba843 --- /dev/null +++ b/mojo/services/network/public/interfaces/http_message.mojom
@@ -0,0 +1,23 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +module mojo; + +struct HttpHeader { + string name; + string value; +}; + +struct HttpRequest { + string method = "GET"; + string url; + array<HttpHeader>? headers; + handle<data_pipe_consumer>? body; +}; + +struct HttpResponse { + uint32 status_code = 200; + array<HttpHeader>? headers; + handle<data_pipe_consumer>? body; +};
diff --git a/mojo/services/network/public/interfaces/url_loader.mojom b/mojo/services/network/public/interfaces/url_loader.mojom index 4ca3f8d..d0a7164 100644 --- a/mojo/services/network/public/interfaces/url_loader.mojom +++ b/mojo/services/network/public/interfaces/url_loader.mojom
@@ -4,13 +4,9 @@ module mojo; +import "network/public/interfaces/http_message.mojom"; import "network/public/interfaces/network_error.mojom"; -struct HTTPHeader { - string name; - string value; -}; - struct URLRequest { // The URL to load. string url; @@ -19,7 +15,7 @@ string method = "GET"; // Additional HTTP request headers. - array<HTTPHeader>? headers; + array<HttpHeader>? headers; // The payload for the request body, represented as a concatenation of data // streams. For HTTP requests, the method must be set to "POST" or "PUT". @@ -59,7 +55,7 @@ string? status_line; // The HTTP response headers. - array<HTTPHeader>? headers; + array<HttpHeader>? headers; // The MIME type of the response body. string? mime_type;
diff --git a/mojo/services/network/url_loader_impl.cc b/mojo/services/network/url_loader_impl.cc index 5e2108a..464eda9 100644 --- a/mojo/services/network/url_loader_impl.cc +++ b/mojo/services/network/url_loader_impl.cc
@@ -31,12 +31,12 @@ response->status_code = headers->response_code(); response->status_line = headers->GetStatusLine(); - response->headers = Array<HTTPHeaderPtr>::New(0); + response->headers = Array<HttpHeaderPtr>::New(0); std::vector<String> header_lines; void* iter = nullptr; std::string name, value; while (headers->EnumerateHeaderLines(&iter, &name, &value)) { - HTTPHeaderPtr header = HTTPHeader::New(); + HttpHeaderPtr header = HttpHeader::New(); header->name = name; header->value = value; response->headers.push_back(header.Pass());
diff --git a/mojo/shell/local_fetcher.cc b/mojo/shell/local_fetcher.cc index 4844483..ff7f7d4e 100644 --- a/mojo/shell/local_fetcher.cc +++ b/mojo/shell/local_fetcher.cc
@@ -53,8 +53,8 @@ response->body = data_pipe.consumer_handle.Pass(); int64 file_size; if (base::GetFileSize(path_, &file_size)) { - response->headers = Array<HTTPHeaderPtr>(1); - HTTPHeaderPtr header = HTTPHeader::New(); + response->headers = Array<HttpHeaderPtr>(1); + HttpHeaderPtr header = HttpHeader::New(); header->name = "Content-Length"; header->value = base::StringPrintf("%" PRId64, file_size); response->headers[0] = header.Pass();
diff --git a/native_client_sdk/src/libraries/nacl_io/kernel_wrap_glibc.cc b/native_client_sdk/src/libraries/nacl_io/kernel_wrap_glibc.cc index 308a0929..158c52a 100644 --- a/native_client_sdk/src/libraries/nacl_io/kernel_wrap_glibc.cc +++ b/native_client_sdk/src/libraries/nacl_io/kernel_wrap_glibc.cc
@@ -175,6 +175,7 @@ OP(fdatasync); \ OP(lstat); \ OP(link); \ + OP(rename); \ OP(readlink); \ OP(utimes); @@ -348,6 +349,10 @@ ERRNO_RTN(ki_link(pathname, newpath)); } +int WRAP(rename)(const char* pathname, const char* newpath) { + ERRNO_RTN(ki_rename(pathname, newpath)); +} + int WRAP(readlink)(const char* pathname, char* buf, size_t count,
diff --git a/native_client_sdk/src/libraries/nacl_io/library.dsc b/native_client_sdk/src/libraries/nacl_io/library.dsc index 5f20abd..3c67053 100644 --- a/native_client_sdk/src/libraries/nacl_io/library.dsc +++ b/native_client_sdk/src/libraries/nacl_io/library.dsc
@@ -81,7 +81,6 @@ "syscalls/pipe.c", "syscalls/poll.c", "syscalls/realpath.c", - "syscalls/rename.c", "syscalls/select.c", "syscalls/sigaction.c", "syscalls/signal.c",
diff --git a/native_client_sdk/src/libraries/nacl_io/syscalls/rename.c b/native_client_sdk/src/libraries/nacl_io/syscalls/rename.c deleted file mode 100644 index 8ad73af..0000000 --- a/native_client_sdk/src/libraries/nacl_io/syscalls/rename.c +++ /dev/null
@@ -1,10 +0,0 @@ -/* Copyright (c) 2013 The Chromium Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. */ - -#include "nacl_io/kernel_intercept.h" -#include "nacl_io/kernel_wrap.h" - -int rename(const char* path, const char* newpath) { - return ki_rename(path, newpath); -}
diff --git a/net/BUILD.gn b/net/BUILD.gn index b4b37887..ef7ed9d 100644 --- a/net/BUILD.gn +++ b/net/BUILD.gn
@@ -839,6 +839,8 @@ "proxy/mojo_proxy_resolver_factory_impl.h", "proxy/mojo_proxy_resolver_impl.cc", "proxy/mojo_proxy_resolver_impl.h", + "proxy/proxy_resolver_error_observer_mojo.cc", + "proxy/proxy_resolver_error_observer_mojo.h", ] deps = [ @@ -1493,6 +1495,7 @@ "proxy/load_state_change_coalescer_unittest.cc", "proxy/mojo_proxy_resolver_factory_impl_unittest.cc", "proxy/mojo_proxy_resolver_impl_unittest.cc", + "proxy/proxy_resolver_error_observer_mojo_unittest.cc", "proxy/proxy_resolver_mojo_unittest.cc", "proxy/proxy_service_mojo_unittest.cc", ]
diff --git a/net/base/mime_util.cc b/net/base/mime_util.cc index 7db410b..0d54d65 100644 --- a/net/base/mime_util.cc +++ b/net/base/mime_util.cc
@@ -15,14 +15,11 @@ #include "base/strings/string_split.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" +#include "build/build_config.h" #include "net/base/mime_util.h" #include "net/base/platform_mime_util.h" #include "net/http/http_util.h" -#if defined(OS_ANDROID) -#include "base/android/build_info.h" -#endif - using std::string; namespace net { @@ -30,26 +27,6 @@ // Singleton utility class for mime types. class MimeUtil : public PlatformMimeUtil { public: - enum Codec { - INVALID_CODEC, - PCM, - MP3, - MPEG2_AAC_LC, - MPEG2_AAC_MAIN, - MPEG2_AAC_SSR, - MPEG4_AAC_LC, - MPEG4_AAC_SBR_v1, - MPEG4_AAC_SBR_PS_v2, - VORBIS, - OPUS, - H264_BASELINE, - H264_MAIN, - H264_HIGH, - VP8, - VP9, - THEORA - }; - bool GetMimeTypeFromExtension(const base::FilePath::StringType& ext, std::string* mime_type) const; @@ -59,8 +36,6 @@ bool GetWellKnownMimeTypeFromExtension(const base::FilePath::StringType& ext, std::string* mime_type) const; - bool IsSupportedMediaMimeType(const std::string& mime_type) const; - bool MatchesMimeType(const std::string &mime_type_pattern, const std::string &mime_type) const; @@ -70,94 +45,14 @@ bool IsValidTopLevelMimeType(const std::string& type_string) const; - bool AreSupportedMediaCodecs(const std::vector<std::string>& codecs) const; - - void ParseCodecString(const std::string& codecs, - std::vector<std::string>* codecs_out, - bool strip); - - bool IsStrictMediaMimeType(const std::string& mime_type) const; - SupportsType IsSupportedStrictMediaMimeType( - const std::string& mime_type, - const std::vector<std::string>& codecs) const; - - void RemoveProprietaryMediaTypesAndCodecsForTests(); - private: friend struct base::DefaultLazyInstanceTraits<MimeUtil>; - typedef base::hash_set<std::string> MimeMappings; - - typedef base::hash_set<int> CodecSet; - typedef std::map<std::string, CodecSet> StrictMappings; - struct CodecEntry { - CodecEntry() : codec(INVALID_CODEC), is_ambiguous(true) {} - CodecEntry(Codec c, bool ambiguous) : codec(c), is_ambiguous(ambiguous) {} - Codec codec; - bool is_ambiguous; - }; - typedef std::map<std::string, CodecEntry> StringToCodecMappings; - MimeUtil(); - // Returns IsSupported if all codec IDs in |codecs| are unambiguous - // and are supported by the platform. MayBeSupported is returned if - // at least one codec ID in |codecs| is ambiguous but all the codecs - // are supported by the platform. IsNotSupported is returned if at - // least one codec ID is not supported by the platform. - SupportsType AreSupportedCodecs( - const CodecSet& supported_codecs, - const std::vector<std::string>& codecs) const; - - // For faster lookup, keep hash sets. - void InitializeMimeTypeMaps(); - bool GetMimeTypeFromExtensionHelper(const base::FilePath::StringType& ext, bool include_platform_types, std::string* mime_type) const; - - // Converts a codec ID into an Codec enum value and indicates - // whether the conversion was ambiguous. - // Returns true if this method was able to map |codec_id| to a specific - // Codec enum value. |codec| and |is_ambiguous| are only valid if true - // is returned. Otherwise their value is undefined after the call. - // |is_ambiguous| is true if |codec_id| did not have enough information to - // unambiguously determine the proper Codec enum value. If |is_ambiguous| - // is true |codec| contains the best guess for the intended Codec enum value. - bool StringToCodec(const std::string& codec_id, - Codec* codec, - bool* is_ambiguous) const; - - // Returns true if |codec| is supported by the platform. - // Note: This method will return false if the platform supports proprietary - // codecs but |allow_proprietary_codecs_| is set to false. - bool IsCodecSupported(Codec codec) const; - - // Returns true if |codec| refers to a proprietary codec. - bool IsCodecProprietary(Codec codec) const; - - // Returns true and sets |*default_codec| if |mime_type| has a default codec - // associated with it. Returns false otherwise and the value of - // |*default_codec| is undefined. - bool GetDefaultCodecLowerCase(const std::string& mime_type_lower_case, - Codec* default_codec) const; - - // Returns true if |mime_type_lower_case| has a default codec associated with - // it and IsCodecSupported() returns true for that particular codec. - bool IsDefaultCodecSupportedLowerCase( - const std::string& mime_type_lower_case) const; - - MimeMappings media_map_; - - // A map of mime_types and hash map of the supported codecs for the mime_type. - StrictMappings strict_format_map_; - - // Keeps track of whether proprietary codec support should be - // advertised to callers. - bool allow_proprietary_codecs_; - - // Lookup table for string compare based string -> Codec mappings. - StringToCodecMappings string_to_codec_map_; }; // class MimeUtil // This variable is Leaky because we need to access it from WorkerPool threads. @@ -297,269 +192,7 @@ return false; } -// A list of media types: http://en.wikipedia.org/wiki/Internet_media_type -// A comprehensive mime type list: http://plugindoc.mozdev.org/winmime.php -// This set of codecs is supported by all variations of Chromium. -static const char* const common_media_types[] = { - // Ogg. - "audio/ogg", - "application/ogg", -#if !defined(OS_ANDROID) // Android doesn't support Ogg Theora. - "video/ogg", -#endif - - // WebM. - "video/webm", - "audio/webm", - - // Wav. - "audio/wav", - "audio/x-wav", - -#if defined(OS_ANDROID) - // HLS. - "application/vnd.apple.mpegurl", - "application/x-mpegurl", -#endif -}; - -// List of proprietary types only supported by Google Chrome. -static const char* const proprietary_media_types[] = { - // MPEG-4. - "video/mp4", - "video/x-m4v", - "audio/mp4", - "audio/x-m4a", - - // MP3. - "audio/mp3", - "audio/x-mp3", - "audio/mpeg", - "audio/aac", - -#if defined(ENABLE_MPEG2TS_STREAM_PARSER) - // MPEG-2 TS. - "video/mp2t", -#endif -}; - -#if defined(OS_ANDROID) -static bool IsCodecSupportedOnAndroid(MimeUtil::Codec codec) { - switch (codec) { - case MimeUtil::INVALID_CODEC: - return false; - - case MimeUtil::PCM: - case MimeUtil::MP3: - case MimeUtil::MPEG4_AAC_LC: - case MimeUtil::MPEG4_AAC_SBR_v1: - case MimeUtil::MPEG4_AAC_SBR_PS_v2: - case MimeUtil::H264_BASELINE: - case MimeUtil::H264_MAIN: - case MimeUtil::H264_HIGH: - case MimeUtil::VP8: - case MimeUtil::VORBIS: - return true; - - case MimeUtil::MPEG2_AAC_LC: - case MimeUtil::MPEG2_AAC_MAIN: - case MimeUtil::MPEG2_AAC_SSR: - // MPEG-2 variants of AAC are not supported on Android. - return false; - - case MimeUtil::VP9: - // VP9 is supported only in KitKat+ (API Level 19). - return base::android::BuildInfo::GetInstance()->sdk_int() >= 19; - - case MimeUtil::OPUS: - // Opus is supported only in Lollipop+ (API Level 21). - return base::android::BuildInfo::GetInstance()->sdk_int() >= 21; - - case MimeUtil::THEORA: - return false; - } - - return false; -} -#endif - -struct MediaFormatStrict { - const char* const mime_type; - const char* const codecs_list; -}; - -// Following is the list of RFC 6381 compliant codecs: -// mp4a.66 - MPEG-2 AAC MAIN -// mp4a.67 - MPEG-2 AAC LC -// mp4a.68 - MPEG-2 AAC SSR -// mp4a.69 - MPEG-2 extension to MPEG-1 -// mp4a.6B - MPEG-1 audio -// mp4a.40.2 - MPEG-4 AAC LC -// mp4a.40.02 - MPEG-4 AAC LC (leading 0 in aud-oti for compatibility) -// mp4a.40.5 - MPEG-4 HE-AAC v1 (AAC LC + SBR) -// mp4a.40.05 - MPEG-4 HE-AAC v1 (AAC LC + SBR) (leading 0 in aud-oti for -// compatibility) -// mp4a.40.29 - MPEG-4 HE-AAC v2 (AAC LC + SBR + PS) -// -// avc1.42E0xx - H.264 Baseline -// avc1.4D40xx - H.264 Main -// avc1.6400xx - H.264 High -static const char kMP4AudioCodecsExpression[] = - "mp4a.66,mp4a.67,mp4a.68,mp4a.69,mp4a.6B,mp4a.40.2,mp4a.40.02,mp4a.40.5," - "mp4a.40.05,mp4a.40.29"; -static const char kMP4VideoCodecsExpression[] = - // This is not a complete list of supported avc1 codecs. It is simply used - // to register support for the corresponding Codec enum. Instead of using - // strings in these three arrays, we should use the Codec enum values. - // This will avoid confusion and unnecessary parsing at runtime. - // kUnambiguousCodecStringMap/kAmbiguousCodecStringMap should be the only - // mapping from strings to codecs. See crbug.com/461009. - "avc1.42E00A,avc1.4D400A,avc1.64000A," - "mp4a.66,mp4a.67,mp4a.68,mp4a.69,mp4a.6B,mp4a.40.2,mp4a.40.02,mp4a.40.5," - "mp4a.40.05,mp4a.40.29"; - -// These containers are also included in -// common_media_types/proprietary_media_types. See crbug.com/461012. -static const MediaFormatStrict format_codec_mappings[] = { - {"video/webm", "opus,vorbis,vp8,vp8.0,vp9,vp9.0"}, - {"audio/webm", "opus,vorbis"}, - {"audio/wav", "1"}, - {"audio/x-wav", "1"}, -// Android does not support Opus in Ogg container. -#if defined(OS_ANDROID) - {"video/ogg", "theora,vorbis"}, - {"audio/ogg", "vorbis"}, - {"application/ogg", "theora,vorbis"}, -#else - {"video/ogg", "opus,theora,vorbis"}, - {"audio/ogg", "opus,vorbis"}, - {"application/ogg", "opus,theora,vorbis"}, -#endif - {"audio/mpeg", "mp3"}, - {"audio/mp3", ""}, - {"audio/x-mp3", ""}, - {"audio/mp4", kMP4AudioCodecsExpression}, - {"audio/x-m4a", kMP4AudioCodecsExpression}, - {"video/mp4", kMP4VideoCodecsExpression}, - {"video/x-m4v", kMP4VideoCodecsExpression}, - {"application/x-mpegurl", kMP4VideoCodecsExpression}, - {"application/vnd.apple.mpegurl", kMP4VideoCodecsExpression}}; - -struct CodecIDMappings { - const char* const codec_id; - MimeUtil::Codec codec; -}; - -// List of codec IDs that provide enough information to determine the -// codec and profile being requested. -// -// The "mp4a" strings come from RFC 6381. -static const CodecIDMappings kUnambiguousCodecStringMap[] = { - {"1", MimeUtil::PCM}, // We only allow this for WAV so it isn't ambiguous. - // avc1/avc3.XXXXXX may be unambiguous; handled by ParseH264CodecID(). - {"mp3", MimeUtil::MP3}, - {"mp4a.66", MimeUtil::MPEG2_AAC_MAIN}, - {"mp4a.67", MimeUtil::MPEG2_AAC_LC}, - {"mp4a.68", MimeUtil::MPEG2_AAC_SSR}, - {"mp4a.69", MimeUtil::MP3}, - {"mp4a.6B", MimeUtil::MP3}, - {"mp4a.40.2", MimeUtil::MPEG4_AAC_LC}, - {"mp4a.40.02", MimeUtil::MPEG4_AAC_LC}, - {"mp4a.40.5", MimeUtil::MPEG4_AAC_SBR_v1}, - {"mp4a.40.05", MimeUtil::MPEG4_AAC_SBR_v1}, - {"mp4a.40.29", MimeUtil::MPEG4_AAC_SBR_PS_v2}, - {"vorbis", MimeUtil::VORBIS}, - {"opus", MimeUtil::OPUS}, - {"vp8", MimeUtil::VP8}, - {"vp8.0", MimeUtil::VP8}, - {"vp9", MimeUtil::VP9}, - {"vp9.0", MimeUtil::VP9}, - {"theora", MimeUtil::THEORA}}; - -// List of codec IDs that are ambiguous and don't provide -// enough information to determine the codec and profile. -// The codec in these entries indicate the codec and profile -// we assume the user is trying to indicate. -static const CodecIDMappings kAmbiguousCodecStringMap[] = { - {"mp4a.40", MimeUtil::MPEG4_AAC_LC}, - {"avc1", MimeUtil::H264_BASELINE}, - {"avc3", MimeUtil::H264_BASELINE}, - // avc1/avc3.XXXXXX may be ambiguous; handled by ParseH264CodecID(). -}; - -MimeUtil::MimeUtil() : allow_proprietary_codecs_(false) { - InitializeMimeTypeMaps(); -} - -SupportsType MimeUtil::AreSupportedCodecs( - const CodecSet& supported_codecs, - const std::vector<std::string>& codecs) const { - DCHECK(!supported_codecs.empty()); - DCHECK(!codecs.empty()); - - SupportsType result = IsSupported; - for (size_t i = 0; i < codecs.size(); ++i) { - bool is_ambiguous = true; - Codec codec = INVALID_CODEC; - if (!StringToCodec(codecs[i], &codec, &is_ambiguous)) - return IsNotSupported; - - if (!IsCodecSupported(codec) || - supported_codecs.find(codec) == supported_codecs.end()) { - return IsNotSupported; - } - - if (is_ambiguous) - result = MayBeSupported; - } - - return result; -} - -void MimeUtil::InitializeMimeTypeMaps() { - // Initialize the supported media types. - for (size_t i = 0; i < arraysize(common_media_types); ++i) - media_map_.insert(common_media_types[i]); -#if defined(USE_PROPRIETARY_CODECS) - allow_proprietary_codecs_ = true; - - for (size_t i = 0; i < arraysize(proprietary_media_types); ++i) - media_map_.insert(proprietary_media_types[i]); -#endif - - for (size_t i = 0; i < arraysize(kUnambiguousCodecStringMap); ++i) { - string_to_codec_map_[kUnambiguousCodecStringMap[i].codec_id] = - CodecEntry(kUnambiguousCodecStringMap[i].codec, false); - } - - for (size_t i = 0; i < arraysize(kAmbiguousCodecStringMap); ++i) { - string_to_codec_map_[kAmbiguousCodecStringMap[i].codec_id] = - CodecEntry(kAmbiguousCodecStringMap[i].codec, true); - } - - // Initialize the strict supported media types. - for (size_t i = 0; i < arraysize(format_codec_mappings); ++i) { - std::vector<std::string> mime_type_codecs; - ParseCodecString(format_codec_mappings[i].codecs_list, - &mime_type_codecs, - false); - - CodecSet codecs; - for (size_t j = 0; j < mime_type_codecs.size(); ++j) { - Codec codec = INVALID_CODEC; - bool is_ambiguous = true; - CHECK(StringToCodec(mime_type_codecs[j], &codec, &is_ambiguous)); - DCHECK(!is_ambiguous); - codecs.insert(codec); - } - - strict_format_map_[format_codec_mappings[i].mime_type] = codecs; - } -} - -bool MimeUtil::IsSupportedMediaMimeType(const std::string& mime_type) const { - return media_map_.find(base::StringToLowerASCII(mime_type)) != - media_map_.end(); +MimeUtil::MimeUtil() { } // Tests for MIME parameter equality. Each parameter in the |mime_type_pattern| @@ -703,241 +336,6 @@ return type_string.size() > 2 && StartsWithASCII(type_string, "x-", false); } -bool MimeUtil::AreSupportedMediaCodecs( - const std::vector<std::string>& codecs) const { - for (size_t i = 0; i < codecs.size(); ++i) { - Codec codec = INVALID_CODEC; - bool is_ambiguous = true; - if (!StringToCodec(codecs[i], &codec, &is_ambiguous) || - !IsCodecSupported(codec)) { - return false; - } - } - return true; -} - -void MimeUtil::ParseCodecString(const std::string& codecs, - std::vector<std::string>* codecs_out, - bool strip) { - std::string no_quote_codecs; - base::TrimString(codecs, "\"", &no_quote_codecs); - base::SplitString(no_quote_codecs, ',', codecs_out); - - if (!strip) - return; - - // Strip everything past the first '.' - for (std::vector<std::string>::iterator it = codecs_out->begin(); - it != codecs_out->end(); - ++it) { - size_t found = it->find_first_of('.'); - if (found != std::string::npos) - it->resize(found); - } -} - -bool MimeUtil::IsStrictMediaMimeType(const std::string& mime_type) const { - return strict_format_map_.find(base::StringToLowerASCII(mime_type)) != - strict_format_map_.end(); -} - -SupportsType MimeUtil::IsSupportedStrictMediaMimeType( - const std::string& mime_type, - const std::vector<std::string>& codecs) const { - const std::string mime_type_lower_case = base::StringToLowerASCII(mime_type); - StrictMappings::const_iterator it_strict_map = - strict_format_map_.find(mime_type_lower_case); - if (it_strict_map == strict_format_map_.end()) - return codecs.empty() ? MayBeSupported : IsNotSupported; - - if (it_strict_map->second.empty()) { - // We get here if the mimetype does not expect a codecs parameter. - return (codecs.empty() && - IsDefaultCodecSupportedLowerCase(mime_type_lower_case)) - ? IsSupported - : IsNotSupported; - } - - if (codecs.empty()) { - // We get here if the mimetype expects to get a codecs parameter, - // but didn't get one. If |mime_type_lower_case| does not have a default - // codec the best we can do is say "maybe" because we don't have enough - // information. - Codec default_codec = INVALID_CODEC; - if (!GetDefaultCodecLowerCase(mime_type_lower_case, &default_codec)) - return MayBeSupported; - - return IsCodecSupported(default_codec) ? IsSupported : IsNotSupported; - } - - return AreSupportedCodecs(it_strict_map->second, codecs); -} - -void MimeUtil::RemoveProprietaryMediaTypesAndCodecsForTests() { - for (size_t i = 0; i < arraysize(proprietary_media_types); ++i) - media_map_.erase(proprietary_media_types[i]); - allow_proprietary_codecs_ = false; -} - -// Returns true iff |profile_str| conforms to hex string "42y0", where y is one -// of [8..F]. Requiring constraint_set0_flag be set and profile_idc be 0x42 is -// taken from ISO-14496-10 7.3.2.1, 7.4.2.1, and Annex A.2.1. -// -// |profile_str| is the first four characters of the H.264 suffix string -// (ignoring the last 2 characters of the full 6 character suffix that are -// level_idc). From ISO-14496-10 7.3.2.1, it consists of: -// 8 bits: profile_idc: required to be 0x42 here. -// 1 bit: constraint_set0_flag : required to be true here. -// 1 bit: constraint_set1_flag : ignored here. -// 1 bit: constraint_set2_flag : ignored here. -// 1 bit: constraint_set3_flag : ignored here. -// 4 bits: reserved : required to be 0 here. -// -// The spec indicates other ways, not implemented here, that a |profile_str| -// can indicate a baseline conforming decoder is sufficient for decode in Annex -// A.2.1: "[profile_idc not necessarily 0x42] with constraint_set0_flag set and -// in which level_idc and constraint_set3_flag represent a level less than or -// equal to the specified level." -static bool IsValidH264BaselineProfile(const std::string& profile_str) { - uint32 constraint_set_bits; - if (profile_str.size() != 4 || - profile_str[0] != '4' || - profile_str[1] != '2' || - profile_str[3] != '0' || - !base::HexStringToUInt(base::StringPiece(profile_str.c_str() + 2, 1), - &constraint_set_bits)) { - return false; - } - - return constraint_set_bits >= 8; -} - -static bool IsValidH264Level(const std::string& level_str) { - uint32 level; - if (level_str.size() != 2 || !base::HexStringToUInt(level_str, &level)) - return false; - - // Valid levels taken from Table A-1 in ISO-14496-10. - // Essentially |level_str| is toHex(10 * level). - return ((level >= 10 && level <= 13) || - (level >= 20 && level <= 22) || - (level >= 30 && level <= 32) || - (level >= 40 && level <= 42) || - (level >= 50 && level <= 51)); -} - -// Handle parsing H.264 codec IDs as outlined in RFC 6381 and ISO-14496-10. -// avc1.42y0xx, y >= 8 - H.264 Baseline -// avc1.4D40xx - H.264 Main -// avc1.6400xx - H.264 High -// -// avc1.xxxxxx & avc3.xxxxxx are considered ambiguous forms that are trying to -// signal H.264 Baseline. For example, the idc_level, profile_idc and -// constraint_set3_flag pieces may explicitly require decoder to conform to -// baseline profile at the specified level (see Annex A and constraint_set0 in -// ISO-14496-10). -static bool ParseH264CodecID(const std::string& codec_id, - MimeUtil::Codec* codec, - bool* is_ambiguous) { - // Make sure we have avc1.xxxxxx or avc3.xxxxxx - if (codec_id.size() != 11 || - (!StartsWithASCII(codec_id, "avc1.", true) && - !StartsWithASCII(codec_id, "avc3.", true))) { - return false; - } - - std::string profile = StringToUpperASCII(codec_id.substr(5, 4)); - if (IsValidH264BaselineProfile(profile)) { - *codec = MimeUtil::H264_BASELINE; - } else if (profile == "4D40") { - *codec = MimeUtil::H264_MAIN; - } else if (profile == "6400") { - *codec = MimeUtil::H264_HIGH; - } else { - *codec = MimeUtil::H264_BASELINE; - *is_ambiguous = true; - return true; - } - - *is_ambiguous = !IsValidH264Level(StringToUpperASCII(codec_id.substr(9))); - return true; -} - -bool MimeUtil::StringToCodec(const std::string& codec_id, - Codec* codec, - bool* is_ambiguous) const { - StringToCodecMappings::const_iterator itr = - string_to_codec_map_.find(codec_id); - if (itr != string_to_codec_map_.end()) { - *codec = itr->second.codec; - *is_ambiguous = itr->second.is_ambiguous; - return true; - } - - // If |codec_id| is not in |string_to_codec_map_|, then we assume that it is - // an H.264 codec ID because currently those are the only ones that can't be - // stored in the |string_to_codec_map_| and require parsing. - return ParseH264CodecID(codec_id, codec, is_ambiguous); -} - -bool MimeUtil::IsCodecSupported(Codec codec) const { - DCHECK_NE(codec, INVALID_CODEC); - -#if defined(OS_ANDROID) - if (!IsCodecSupportedOnAndroid(codec)) - return false; -#endif - - return allow_proprietary_codecs_ || !IsCodecProprietary(codec); -} - -bool MimeUtil::IsCodecProprietary(Codec codec) const { - switch (codec) { - case INVALID_CODEC: - case MP3: - case MPEG2_AAC_LC: - case MPEG2_AAC_MAIN: - case MPEG2_AAC_SSR: - case MPEG4_AAC_LC: - case MPEG4_AAC_SBR_v1: - case MPEG4_AAC_SBR_PS_v2: - case H264_BASELINE: - case H264_MAIN: - case H264_HIGH: - return true; - - case PCM: - case VORBIS: - case OPUS: - case VP8: - case VP9: - case THEORA: - return false; - } - - return true; -} - -bool MimeUtil::GetDefaultCodecLowerCase(const std::string& mime_type_lower_case, - Codec* default_codec) const { - if (mime_type_lower_case == "audio/mpeg" || - mime_type_lower_case == "audio/mp3" || - mime_type_lower_case == "audio/x-mp3") { - *default_codec = MimeUtil::MP3; - return true; - } - - return false; -} - -bool MimeUtil::IsDefaultCodecSupportedLowerCase( - const std::string& mime_type_lower_case) const { - Codec default_codec = Codec::INVALID_CODEC; - if (!GetDefaultCodecLowerCase(mime_type_lower_case, &default_codec)) - return false; - return IsCodecSupported(default_codec); -} - //---------------------------------------------------------------------------- // Wrappers for the singleton //---------------------------------------------------------------------------- @@ -963,10 +361,6 @@ extension); } -bool IsSupportedMediaMimeType(const std::string& mime_type) { - return g_mime_util.Get().IsSupportedMediaMimeType(mime_type); -} - bool MatchesMimeType(const std::string& mime_type_pattern, const std::string& mime_type) { return g_mime_util.Get().MatchesMimeType(mime_type_pattern, mime_type); @@ -983,26 +377,6 @@ return g_mime_util.Get().IsValidTopLevelMimeType(type_string); } -bool AreSupportedMediaCodecs(const std::vector<std::string>& codecs) { - return g_mime_util.Get().AreSupportedMediaCodecs(codecs); -} - -bool IsStrictMediaMimeType(const std::string& mime_type) { - return g_mime_util.Get().IsStrictMediaMimeType(mime_type); -} - -SupportsType IsSupportedStrictMediaMimeType( - const std::string& mime_type, - const std::vector<std::string>& codecs) { - return g_mime_util.Get().IsSupportedStrictMediaMimeType(mime_type, codecs); -} - -void ParseCodecString(const std::string& codecs, - std::vector<std::string>* codecs_out, - const bool strip) { - g_mime_util.Get().ParseCodecString(codecs, codecs_out, strip); -} - namespace { // From http://www.w3schools.com/media/media_mimeref.asp and @@ -1185,10 +559,6 @@ HashSetToVector(&unique_extensions, extensions); } -void RemoveProprietaryMediaTypesAndCodecsForTests() { - g_mime_util.Get().RemoveProprietaryMediaTypesAndCodecsForTests(); -} - void AddMultipartValueForUpload(const std::string& value_name, const std::string& value, const std::string& mime_boundary,
diff --git a/net/base/mime_util.h b/net/base/mime_util.h index 80f440e..d4335a91 100644 --- a/net/base/mime_util.h +++ b/net/base/mime_util.h
@@ -50,9 +50,6 @@ const std::string& mime_type, base::FilePath::StringType* extension); -// Check to see if a particular MIME type is in our list. -NET_EXPORT bool IsSupportedMediaMimeType(const std::string& mime_type); - // Returns true if this the mime_type_pattern matches a given mime-type. // Checks for absolute matching and wildcards. MIME types are case insensitive. NET_EXPORT bool MatchesMimeType(const std::string& mime_type_pattern, @@ -81,53 +78,6 @@ // this method. NET_EXPORT bool IsValidTopLevelMimeType(const std::string& type_string); -// Returns true if and only if all codecs are supported, false otherwise. -NET_EXPORT bool AreSupportedMediaCodecs(const std::vector<std::string>& codecs); - -// Parses a codec string, populating |codecs_out| with the prefix of each codec -// in the string |codecs_in|. For example, passed "aaa.b.c,dd.eee", if -// |strip| == true |codecs_out| will contain {"aaa", "dd"}, if |strip| == false -// |codecs_out| will contain {"aaa.b.c", "dd.eee"}. -// See http://www.ietf.org/rfc/rfc4281.txt. -NET_EXPORT void ParseCodecString(const std::string& codecs, - std::vector<std::string>* codecs_out, - bool strip); - -// Check to see if a particular MIME type is in our list which only supports a -// certain subset of codecs. -NET_EXPORT bool IsStrictMediaMimeType(const std::string& mime_type); - -// Indicates that the MIME type and (possible codec string) are supported by the -// underlying platform. -enum SupportsType { - // The underlying platform is known not to support the given MIME type and - // codec combination. - IsNotSupported, - - // The underlying platform is known to support the given MIME type and codec - // combination. - IsSupported, - - // The underlying platform is unsure whether the given MIME type and codec - // combination can be rendered or not before actually trying to play it. - MayBeSupported -}; - -// Checks the |mime_type| and |codecs| against the MIME types known to support -// only a particular subset of codecs. -// * Returns IsSupported if the |mime_type| is supported and all the codecs -// within the |codecs| are supported for the |mime_type|. -// * Returns MayBeSupported if the |mime_type| is supported and is known to -// support only a subset of codecs, but |codecs| was empty. Also returned if -// all the codecs in |codecs| are supported, but additional codec parameters -// were supplied (such as profile) for which the support cannot be decided. -// * Returns IsNotSupported if either the |mime_type| is not supported or the -// |mime_type| is supported but at least one of the codecs within |codecs| is -// not supported for the |mime_type|. -NET_EXPORT SupportsType IsSupportedStrictMediaMimeType( - const std::string& mime_type, - const std::vector<std::string>& codecs); - // Get the extensions associated with the given mime type. There could be // multiple extensions for a given mime type, like "html,htm" for "text/html", // or "txt,text,html,..." for "text/*". @@ -137,12 +87,6 @@ const std::string& mime_type, std::vector<base::FilePath::StringType>* extensions); -// Test only method that removes proprietary media types and codecs from the -// list of supported MIME types and codecs. These types and codecs must be -// removed to ensure consistent layout test results across all Chromium -// variations. -NET_EXPORT void RemoveProprietaryMediaTypesAndCodecsForTests(); - // A list of supported certificate-related mime types. // // A Java counterpart will be generated for this enum.
diff --git a/net/base/mime_util_unittest.cc b/net/base/mime_util_unittest.cc index dca622f..8a0d15d 100644 --- a/net/base/mime_util_unittest.cc +++ b/net/base/mime_util_unittest.cc
@@ -5,13 +5,10 @@ #include "base/basictypes.h" #include "base/strings/string_split.h" #include "base/strings/utf_string_conversions.h" +#include "build/build_config.h" #include "net/base/mime_util.h" #include "testing/gtest/include/gtest/gtest.h" -#if defined(OS_ANDROID) -#include "base/android/build_info.h" -#endif - namespace net { TEST(MimeUtilTest, ExtensionTest) { @@ -69,45 +66,6 @@ } } -TEST(MimeUtilTest, LookupTypes) { -#if defined(OS_ANDROID) - EXPECT_TRUE(IsSupportedMediaMimeType("application/vnd.apple.mpegurl")); - EXPECT_TRUE(IsSupportedMediaMimeType("application/x-mpegurl")); - EXPECT_TRUE(IsSupportedMediaMimeType("Application/X-MPEGURL")); -#endif -} - -TEST(MimeUtilTest, StrictMediaMimeType) { - EXPECT_TRUE(IsStrictMediaMimeType("video/webm")); - EXPECT_TRUE(IsStrictMediaMimeType("Video/WEBM")); - EXPECT_TRUE(IsStrictMediaMimeType("audio/webm")); - - EXPECT_TRUE(IsStrictMediaMimeType("audio/wav")); - EXPECT_TRUE(IsStrictMediaMimeType("audio/x-wav")); - - EXPECT_TRUE(IsStrictMediaMimeType("video/ogg")); - EXPECT_TRUE(IsStrictMediaMimeType("audio/ogg")); - EXPECT_TRUE(IsStrictMediaMimeType("application/ogg")); - - EXPECT_TRUE(IsStrictMediaMimeType("audio/mpeg")); - EXPECT_TRUE(IsStrictMediaMimeType("audio/mp3")); - EXPECT_TRUE(IsStrictMediaMimeType("audio/x-mp3")); - - EXPECT_TRUE(IsStrictMediaMimeType("video/mp4")); - EXPECT_TRUE(IsStrictMediaMimeType("video/x-m4v")); - EXPECT_TRUE(IsStrictMediaMimeType("audio/mp4")); - EXPECT_TRUE(IsStrictMediaMimeType("audio/x-m4a")); - - EXPECT_TRUE(IsStrictMediaMimeType("application/x-mpegurl")); - EXPECT_TRUE(IsStrictMediaMimeType("application/vnd.apple.mpegurl")); - - EXPECT_FALSE(IsStrictMediaMimeType("video/unknown")); - EXPECT_FALSE(IsStrictMediaMimeType("Video/UNKNOWN")); - EXPECT_FALSE(IsStrictMediaMimeType("audio/unknown")); - EXPECT_FALSE(IsStrictMediaMimeType("application/unknown")); - EXPECT_FALSE(IsStrictMediaMimeType("unknown/unknown")); -} - TEST(MimeUtilTest, MatchesMimeType) { // MIME types are case insensitive. EXPECT_TRUE(MatchesMimeType("VIDEO/*", "video/x-mpeg")); @@ -187,104 +145,6 @@ EXPECT_TRUE(MatchesMimeType("ab/*cd", "ab/xxxcd")); } -TEST(MimeUtilTest, CommonMediaMimeType) { -#if defined(OS_ANDROID) - bool HLSSupported; - if (base::android::BuildInfo::GetInstance()->sdk_int() < 14) - HLSSupported = false; - else - HLSSupported = true; -#endif - - EXPECT_TRUE(IsSupportedMediaMimeType("audio/webm")); - EXPECT_TRUE(IsSupportedMediaMimeType("video/webm")); - - EXPECT_TRUE(IsSupportedMediaMimeType("audio/wav")); - EXPECT_TRUE(IsSupportedMediaMimeType("audio/x-wav")); - - EXPECT_TRUE(IsSupportedMediaMimeType("audio/ogg")); - EXPECT_TRUE(IsSupportedMediaMimeType("application/ogg")); -#if defined(OS_ANDROID) - EXPECT_FALSE(IsSupportedMediaMimeType("video/ogg")); - EXPECT_EQ(HLSSupported, IsSupportedMediaMimeType("application/x-mpegurl")); - EXPECT_EQ(HLSSupported, - IsSupportedMediaMimeType("application/vnd.apple.mpegurl")); -#else - EXPECT_TRUE(IsSupportedMediaMimeType("video/ogg")); - EXPECT_FALSE(IsSupportedMediaMimeType("application/x-mpegurl")); - EXPECT_FALSE(IsSupportedMediaMimeType("application/vnd.apple.mpegurl")); -#endif // OS_ANDROID - -#if defined(USE_PROPRIETARY_CODECS) - EXPECT_TRUE(IsSupportedMediaMimeType("audio/mp4")); - EXPECT_TRUE(IsSupportedMediaMimeType("audio/x-m4a")); - EXPECT_TRUE(IsSupportedMediaMimeType("video/mp4")); - EXPECT_TRUE(IsSupportedMediaMimeType("video/x-m4v")); - - EXPECT_TRUE(IsSupportedMediaMimeType("audio/mp3")); - EXPECT_TRUE(IsSupportedMediaMimeType("audio/x-mp3")); - EXPECT_TRUE(IsSupportedMediaMimeType("audio/mpeg")); - EXPECT_TRUE(IsSupportedMediaMimeType("audio/aac")); - -#if defined(ENABLE_MPEG2TS_STREAM_PARSER) - EXPECT_TRUE(IsSupportedMediaMimeType("video/mp2t")); -#else - EXPECT_FALSE(IsSupportedMediaMimeType("video/mp2t")); -#endif -#else - EXPECT_FALSE(IsSupportedMediaMimeType("audio/mp4")); - EXPECT_FALSE(IsSupportedMediaMimeType("audio/x-m4a")); - EXPECT_FALSE(IsSupportedMediaMimeType("video/mp4")); - EXPECT_FALSE(IsSupportedMediaMimeType("video/x-m4v")); - - EXPECT_FALSE(IsSupportedMediaMimeType("audio/mp3")); - EXPECT_FALSE(IsSupportedMediaMimeType("audio/x-mp3")); - EXPECT_FALSE(IsSupportedMediaMimeType("audio/mpeg")); - EXPECT_FALSE(IsSupportedMediaMimeType("audio/aac")); -#endif // USE_PROPRIETARY_CODECS - EXPECT_FALSE(IsSupportedMediaMimeType("video/mp3")); - - EXPECT_FALSE(IsSupportedMediaMimeType("video/unknown")); - EXPECT_FALSE(IsSupportedMediaMimeType("audio/unknown")); - EXPECT_FALSE(IsSupportedMediaMimeType("unknown/unknown")); -} - -// Note: codecs should only be a list of 2 or fewer; hence the restriction of -// results' length to 2. -TEST(MimeUtilTest, ParseCodecString) { - const struct { - const char* const original; - size_t expected_size; - const char* const results[2]; - } tests[] = { - { "\"bogus\"", 1, { "bogus" } }, - { "0", 1, { "0" } }, - { "avc1.42E01E, mp4a.40.2", 2, { "avc1", "mp4a" } }, - { "\"mp4v.20.240, mp4a.40.2\"", 2, { "mp4v", "mp4a" } }, - { "mp4v.20.8, samr", 2, { "mp4v", "samr" } }, - { "\"theora, vorbis\"", 2, { "theora", "vorbis" } }, - { "", 0, { } }, - { "\"\"", 0, { } }, - { "\" \"", 0, { } }, - { ",", 2, { "", "" } }, - }; - - for (size_t i = 0; i < arraysize(tests); ++i) { - std::vector<std::string> codecs_out; - ParseCodecString(tests[i].original, &codecs_out, true); - ASSERT_EQ(tests[i].expected_size, codecs_out.size()); - for (size_t j = 0; j < tests[i].expected_size; ++j) - EXPECT_EQ(tests[i].results[j], codecs_out[j]); - } - - // Test without stripping the codec type. - std::vector<std::string> codecs_out; - ParseCodecString("avc1.42E01E, mp4a.40.2", &codecs_out, false); - ASSERT_EQ(2u, codecs_out.size()); - EXPECT_EQ("avc1.42E01E", codecs_out[0]); - EXPECT_EQ("mp4a.40.2", codecs_out[1]); -} - TEST(MimeUtilTest, TestParseMimeTypeWithoutParameter) { std::string nonAscii("application/nonutf8"); EXPECT_TRUE(ParseMimeTypeWithoutParameter(nonAscii, NULL, NULL));
diff --git a/net/data/proxy_resolver_v8_tracing_unittest/error_on_load.js b/net/data/proxy_resolver_v8_tracing_unittest/error_on_load.js new file mode 100644 index 0000000..2379bbf --- /dev/null +++ b/net/data/proxy_resolver_v8_tracing_unittest/error_on_load.js
@@ -0,0 +1,11 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +alert('Prepare to DIE!'); +var x = null; +return x.split('-'); // Throws exception. + +function FindProxyForURL(url, host) { + return "PROXY i-approve-this-message:42"; +}
diff --git a/net/dns/dns_transaction_unittest.cc b/net/dns/dns_transaction_unittest.cc index 2693a5ca..800e394 100644 --- a/net/dns/dns_transaction_unittest.cc +++ b/net/dns/dns_transaction_unittest.cc
@@ -46,12 +46,12 @@ *length = base::HostToNet16(query_->io_buffer()->size()); writes_.push_back(MockWrite(mode, reinterpret_cast<const char*>(length.get()), - sizeof(uint16))); + sizeof(uint16), num_reads_and_writes())); lengths_.push_back(length.release()); } - writes_.push_back(MockWrite(mode, - query_->io_buffer()->data(), - query_->io_buffer()->size())); + writes_.push_back(MockWrite(mode, query_->io_buffer()->data(), + query_->io_buffer()->size(), + num_reads_and_writes())); } ~DnsSocketData() {} @@ -66,12 +66,12 @@ *length = base::HostToNet16(tcp_length); reads_.push_back(MockRead(mode, reinterpret_cast<const char*>(length.get()), - sizeof(uint16))); + sizeof(uint16), num_reads_and_writes())); lengths_.push_back(length.release()); } - reads_.push_back(MockRead(mode, - response->io_buffer()->data(), - response->io_buffer()->size())); + reads_.push_back(MockRead(mode, response->io_buffer()->data(), + response->io_buffer()->size(), + num_reads_and_writes())); responses_.push_back(response.release()); } @@ -102,19 +102,20 @@ // Add error response. void AddReadError(int error, IoMode mode) { - reads_.push_back(MockRead(mode, error)); + reads_.push_back(MockRead(mode, error, num_reads_and_writes())); } // Build, if needed, and return the SocketDataProvider. No new responses // should be added afterwards. - SocketDataProvider* GetProvider() { + SequencedSocketData* GetProvider() { if (provider_.get()) return provider_.get(); // Terminate the reads with ERR_IO_PENDING to prevent overrun and default to // timeout. - reads_.push_back(MockRead(ASYNC, ERR_IO_PENDING)); - provider_.reset(new DelayedSocketData(1, &reads_[0], reads_.size(), - &writes_[0], writes_.size())); + reads_.push_back( + MockRead(ASYNC, ERR_IO_PENDING, writes_.size() + reads_.size())); + provider_.reset(new SequencedSocketData(&reads_[0], reads_.size(), + &writes_[0], writes_.size())); if (use_tcp_) { provider_->set_connect_data(MockConnect(reads_[0].mode, OK)); } @@ -125,20 +126,16 @@ return query_->id(); } - // Returns true if the expected query was written to the socket. - bool was_written() const { - CHECK(provider_.get()); - return provider_->write_index() > 0; - } - private: + size_t num_reads_and_writes() const { return reads_.size() + writes_.size(); } + scoped_ptr<DnsQuery> query_; bool use_tcp_; ScopedVector<uint16> lengths_; ScopedVector<DnsResponse> responses_; std::vector<MockWrite> writes_; std::vector<MockRead> reads_; - scoped_ptr<DelayedSocketData> provider_; + scoped_ptr<SequencedSocketData> provider_; DISALLOW_COPY_AND_ASSIGN(DnsSocketData); }; @@ -454,7 +451,7 @@ void TearDown() override { // Check that all socket data was at least written to. for (size_t i = 0; i < socket_data_.size(); ++i) { - EXPECT_TRUE(socket_data_[i]->was_written()) << i; + EXPECT_TRUE(socket_data_[i]->GetProvider()->AllWriteDataConsumed()) << i; } } @@ -517,6 +514,11 @@ helper1.StartTransaction(transaction_factory_.get()); helper0.Cancel(); + // Since the transaction has been cancelled, the assocaited socket has been + // destroyed, so make sure the data provide does not attempt to callback + // to the socket. + // TODO(rch): Make the SocketDataProvider and MockSocket do this by default. + socket_data_[0]->GetProvider()->set_socket(nullptr); base::MessageLoop::current()->RunUntilIdle();
diff --git a/net/extras/sqlite/sqlite_persistent_cookie_store.cc b/net/extras/sqlite/sqlite_persistent_cookie_store.cc index 9fdb070..d80464a 100644 --- a/net/extras/sqlite/sqlite_persistent_cookie_store.cc +++ b/net/extras/sqlite/sqlite_persistent_cookie_store.cc
@@ -1224,10 +1224,14 @@ if (cookies.empty()) return; - // Perform deletion on background task runner. - background_task_runner_->PostTask( - FROM_HERE, - base::Bind(&Backend::BackgroundDeleteAllInList, this, cookies)); + if (background_task_runner_->RunsTasksOnCurrentThread()) { + BackgroundDeleteAllInList(cookies); + } else { + // Perform deletion on background task runner. + PostBackgroundTask( + FROM_HERE, + base::Bind(&Backend::BackgroundDeleteAllInList, this, cookies)); + } } void SQLitePersistentCookieStore::Backend::DeleteSessionCookiesOnStartup() {
diff --git a/net/ftp/ftp_network_transaction_unittest.cc b/net/ftp/ftp_network_transaction_unittest.cc index 79e1687..c242658d 100644 --- a/net/ftp/ftp_network_transaction_unittest.cc +++ b/net/ftp/ftp_network_transaction_unittest.cc
@@ -128,6 +128,10 @@ Init(); } + bool AllReadDataConsumed() const override { return state_ == QUIT; } + + bool AllWriteDataConsumed() const override { return state_ == QUIT; } + void set_multiline_welcome(bool multiline) { multiline_welcome_ = multiline; } bool use_epsv() const { return use_epsv_; }
diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc index cf73369..0dbb20c 100644 --- a/net/http/http_network_transaction.cc +++ b/net/http/http_network_transaction.cc
@@ -14,6 +14,7 @@ #include "base/memory/scoped_ptr.h" #include "base/metrics/field_trial.h" #include "base/metrics/histogram.h" +#include "base/metrics/sparse_histogram.h" #include "base/profiler/scoped_tracker.h" #include "base/stl_util.h" #include "base/strings/string_number_conversions.h" @@ -95,12 +96,14 @@ base::Value* NetLogSSLVersionFallbackCallback( const GURL* url, int net_error, + SSLFailureState ssl_failure_state, uint16 version_before, uint16 version_after, NetLogCaptureMode /* capture_mode */) { base::DictionaryValue* dict = new base::DictionaryValue(); dict->SetString("host_and_port", GetHostAndPort(*url)); dict->SetInteger("net_error", net_error); + dict->SetInteger("ssl_failure_state", ssl_failure_state); dict->SetInteger("version_before", version_before); dict->SetInteger("version_after", version_after); return dict; @@ -129,7 +132,9 @@ request_(NULL), priority_(priority), headers_valid_(false), + server_ssl_failure_state_(SSL_FAILURE_NONE), fallback_error_code_(ERR_SSL_INAPPROPRIATE_FALLBACK), + fallback_failure_state_(SSL_FAILURE_NONE), request_headers_(), read_buf_len_(0), total_received_bytes_(0), @@ -499,12 +504,14 @@ } void HttpNetworkTransaction::OnStreamFailed(int result, - const SSLConfig& used_ssl_config) { + const SSLConfig& used_ssl_config, + SSLFailureState ssl_failure_state) { DCHECK_EQ(STATE_CREATE_STREAM_COMPLETE, next_state_); DCHECK_NE(OK, result); DCHECK(stream_request_.get()); DCHECK(!stream_.get()); server_ssl_config_ = used_ssl_config; + server_ssl_failure_state_ = ssl_failure_state; OnIOComplete(result); } @@ -1349,10 +1356,11 @@ if (should_fallback) { net_log_.AddEvent( NetLog::TYPE_SSL_VERSION_FALLBACK, - base::Bind(&NetLogSSLVersionFallbackCallback, - &request_->url, error, server_ssl_config_.version_max, + base::Bind(&NetLogSSLVersionFallbackCallback, &request_->url, error, + server_ssl_failure_state_, server_ssl_config_.version_max, version_max)); fallback_error_code_ = error; + fallback_failure_state_ = server_ssl_failure_state_; server_ssl_config_.version_max = version_max; server_ssl_config_.version_fallback = true; ResetConnectionAndRequestForResend(); @@ -1468,6 +1476,15 @@ UMA_HISTOGRAM_BOOLEAN("Net.ConnectionUsedSSLDeprecatedCipherFallback2", server_ssl_config_.enable_deprecated_cipher_suites); + + if (server_ssl_config_.version_fallback) { + // Record the error code which triggered the fallback and the state the + // handshake was in. + UMA_HISTOGRAM_SPARSE_SLOWLY("Net.SSLFallbackErrorCode", + -fallback_error_code_); + UMA_HISTOGRAM_ENUMERATION("Net.SSLFallbackFailureState", + fallback_failure_state_, SSL_FAILURE_MAX); + } } HttpResponseHeaders* HttpNetworkTransaction::GetResponseHeaders() const {
diff --git a/net/http/http_network_transaction.h b/net/http/http_network_transaction.h index 09e0a972..5ea3999 100644 --- a/net/http/http_network_transaction.h +++ b/net/http/http_network_transaction.h
@@ -22,6 +22,7 @@ #include "net/proxy/proxy_service.h" #include "net/socket/connection_attempts.h" #include "net/ssl/ssl_config_service.h" +#include "net/ssl/ssl_failure_state.h" #include "net/websockets/websocket_handshake_stream_base.h" namespace net { @@ -85,7 +86,9 @@ const SSLConfig& used_ssl_config, const ProxyInfo& used_proxy_info, WebSocketHandshakeStreamBase* stream) override; - void OnStreamFailed(int status, const SSLConfig& used_ssl_config) override; + void OnStreamFailed(int status, + const SSLConfig& used_ssl_config, + SSLFailureState ssl_failure_state) override; void OnCertificateError(int status, const SSLConfig& used_ssl_config, const SSLInfo& ssl_info) override; @@ -294,12 +297,16 @@ SSLConfig server_ssl_config_; SSLConfig proxy_ssl_config_; + // The SSLFailureState of the most recent failed stream. + SSLFailureState server_ssl_failure_state_; // fallback_error_code contains the error code that caused the last TLS // fallback. If the fallback connection results in // ERR_SSL_INAPPROPRIATE_FALLBACK (i.e. the server indicated that the // fallback should not have been needed) then we use this value to return the // original error that triggered the fallback. int fallback_error_code_; + // The SSLFailureState which caused the last TLS version fallback. + SSLFailureState fallback_failure_state_; HttpRequestHeaders request_headers_;
diff --git a/net/http/http_network_transaction_unittest.cc b/net/http/http_network_transaction_unittest.cc index ea328a5..0991940 100644 --- a/net/http/http_network_transaction_unittest.cc +++ b/net/http/http_network_transaction_unittest.cc
@@ -127,7 +127,7 @@ if (!params->GetList("headers", &header_list)) return false; std::string double_quote_headers; - base::JSONWriter::Write(header_list, &double_quote_headers); + base::JSONWriter::Write(*header_list, &double_quote_headers); base::ReplaceChars(double_quote_headers, "\"", "'", headers); return true; } @@ -3686,22 +3686,22 @@ spdy_util_.ConstructSpdyWindowUpdate(1, wrapped_body->size())); MockWrite spdy_writes[] = { - CreateMockWrite(*connect, 1), - CreateMockWrite(*wrapped_get, 3), - CreateMockWrite(*window_update_get_resp, 5), + CreateMockWrite(*connect, 0), + CreateMockWrite(*wrapped_get, 2), + CreateMockWrite(*window_update_get_resp, 6), CreateMockWrite(*window_update_body, 7), }; MockRead spdy_reads[] = { - CreateMockRead(*conn_resp, 2, ASYNC), + CreateMockRead(*conn_resp, 1, ASYNC), + MockRead(ASYNC, ERR_IO_PENDING, 3), CreateMockRead(*wrapped_get_resp, 4, ASYNC), - CreateMockRead(*wrapped_body, 6, ASYNC), + CreateMockRead(*wrapped_body, 5, ASYNC), MockRead(ASYNC, 0, 8), }; - OrderedSocketData spdy_data( - spdy_reads, arraysize(spdy_reads), - spdy_writes, arraysize(spdy_writes)); + SequencedSocketData spdy_data(spdy_reads, arraysize(spdy_reads), spdy_writes, + arraysize(spdy_writes)); session_deps_.socket_factory->AddSocketDataProvider(&spdy_data); SSLSocketDataProvider ssl(ASYNC, OK); @@ -3716,6 +3716,10 @@ int rv = trans->Start(&request, callback1.callback(), log.bound()); EXPECT_EQ(ERR_IO_PENDING, rv); + // Allow the SpdyProxyClientSocket's write callback to complete. + base::MessageLoop::current()->RunUntilIdle(); + // Now allow the read of the response to complete. + spdy_data.CompleteRead(); rv = callback1.WaitForResult(); EXPECT_EQ(OK, rv); @@ -11861,8 +11865,8 @@ reads.push_back(MockRead(ASYNC, OK, 3)); } - OrderedSocketData data(vector_as_array(&reads), reads.size(), - vector_as_array(&writes), writes.size()); + SequencedSocketData data(vector_as_array(&reads), reads.size(), + vector_as_array(&writes), writes.size()); session_deps_.socket_factory->AddSocketDataProvider(&data); // Connection to the origin fails. @@ -11907,6 +11911,10 @@ int rv = trans1->Start(&request1, callback1.callback(), BoundNetLog()); EXPECT_EQ(ERR_IO_PENDING, rv); + base::MessageLoop::current()->RunUntilIdle(); + if (data.IsReadPaused()) { + data.CompleteRead(); + } rv = callback1.WaitForResult(); if (valid) { EXPECT_EQ(OK, rv);
diff --git a/net/http/http_server_properties_manager_unittest.cc b/net/http/http_server_properties_manager_unittest.cc index 7ab6ef06..414613cd 100644 --- a/net/http/http_server_properties_manager_unittest.cc +++ b/net/http/http_server_properties_manager_unittest.cc
@@ -708,7 +708,7 @@ ASSERT_NE(nullptr, http_server_properties); std::string preferences_json; EXPECT_TRUE( - base::JSONWriter::Write(http_server_properties, &preferences_json)); + base::JSONWriter::Write(*http_server_properties, &preferences_json)); EXPECT_EQ(expected_json, preferences_json); }
diff --git a/net/http/http_stream_factory.h b/net/http/http_stream_factory.h index 60ff9d2..b53ee45f 100644 --- a/net/http/http_stream_factory.h +++ b/net/http/http_stream_factory.h
@@ -17,6 +17,7 @@ #include "net/base/request_priority.h" #include "net/http/http_server_properties.h" #include "net/socket/connection_attempts.h" +#include "net/ssl/ssl_failure_state.h" // This file can be included from net/http even though // it is in net/websockets because it doesn't // introduce any link dependency to net/websockets. @@ -86,9 +87,11 @@ // This is the failure to create a stream case. // |used_ssl_config| indicates the actual SSL configuration used for this // stream, since the HttpStreamRequest may have modified the configuration - // during stream processing. + // during stream processing. If an SSL handshake failed, |ssl_failure_state| + // is the state the SSLClientSocket was in. virtual void OnStreamFailed(int status, - const SSLConfig& used_ssl_config) = 0; + const SSLConfig& used_ssl_config, + SSLFailureState ssl_failure_state) = 0; // Called when we have a certificate error for the request. // |used_ssl_config| indicates the actual SSL configuration used for this
diff --git a/net/http/http_stream_factory_impl_job.cc b/net/http/http_stream_factory_impl_job.cc index 1d17b08..b986415 100644 --- a/net/http/http_stream_factory_impl_job.cc +++ b/net/http/http_stream_factory_impl_job.cc
@@ -40,6 +40,7 @@ #include "net/spdy/spdy_session.h" #include "net/spdy/spdy_session_pool.h" #include "net/ssl/ssl_cert_request_info.h" +#include "net/ssl/ssl_failure_state.h" namespace net { @@ -364,10 +365,14 @@ MaybeCopyConnectionAttemptsFromSocketOrHandle(); - if (IsOrphaned()) + if (IsOrphaned()) { stream_factory_->OnOrphanedJobComplete(this); - else - request_->OnStreamFailed(this, result, server_ssl_config_); + } else { + SSLFailureState ssl_failure_state = + connection_ ? connection_->ssl_failure_state() : SSL_FAILURE_NONE; + request_->OnStreamFailed(this, result, server_ssl_config_, + ssl_failure_state); + } // |this| may be deleted after this call. } @@ -799,7 +804,6 @@ HostPortPair destination = proxy_info_.is_quic() ? proxy_info_.proxy_server().host_port_pair() : server_; - next_state_ = STATE_INIT_CONNECTION_COMPLETE; bool secure_quic = using_ssl_ || proxy_info_.is_quic(); int rv = quic_request_.Request( destination, secure_quic, request_info_.privacy_mode,
diff --git a/net/http/http_stream_factory_impl_request.cc b/net/http/http_stream_factory_impl_request.cc index d8a4b5b6..53548b1 100644 --- a/net/http/http_stream_factory_impl_request.cc +++ b/net/http/http_stream_factory_impl_request.cc
@@ -116,7 +116,8 @@ void HttpStreamFactoryImpl::Request::OnStreamFailed( Job* job, int status, - const SSLConfig& used_ssl_config) { + const SSLConfig& used_ssl_config, + SSLFailureState ssl_failure_state) { DCHECK_NE(OK, status); DCHECK(job); if (!bound_job_.get()) { @@ -139,7 +140,7 @@ } else { DCHECK(jobs_.empty()); } - delegate_->OnStreamFailed(status, used_ssl_config); + delegate_->OnStreamFailed(status, used_ssl_config, ssl_failure_state); } void HttpStreamFactoryImpl::Request::OnCertificateError(
diff --git a/net/http/http_stream_factory_impl_request.h b/net/http/http_stream_factory_impl_request.h index 7bc41afc..2244253 100644 --- a/net/http/http_stream_factory_impl_request.h +++ b/net/http/http_stream_factory_impl_request.h
@@ -12,6 +12,7 @@ #include "net/socket/connection_attempts.h" #include "net/socket/ssl_client_socket.h" #include "net/spdy/spdy_session_key.h" +#include "net/ssl/ssl_failure_state.h" #include "url/gurl.h" namespace net { @@ -81,7 +82,10 @@ const SSLConfig& used_ssl_config, const ProxyInfo& used_proxy_info, WebSocketHandshakeStreamBase* stream); - void OnStreamFailed(Job* job, int status, const SSLConfig& used_ssl_config); + void OnStreamFailed(Job* job, + int status, + const SSLConfig& used_ssl_config, + SSLFailureState ssl_failure_state); void OnCertificateError(Job* job, int status, const SSLConfig& used_ssl_config,
diff --git a/net/http/http_stream_factory_impl_request_unittest.cc b/net/http/http_stream_factory_impl_request_unittest.cc index b7afbfe..65a9637 100644 --- a/net/http/http_stream_factory_impl_request_unittest.cc +++ b/net/http/http_stream_factory_impl_request_unittest.cc
@@ -8,6 +8,7 @@ #include "net/proxy/proxy_info.h" #include "net/proxy/proxy_service.h" #include "net/spdy/spdy_test_util_common.h" +#include "net/ssl/ssl_failure_state.h" #include "testing/gtest/include/gtest/gtest.h" namespace net { @@ -38,7 +39,9 @@ const SSLConfig& used_ssl_config, const ProxyInfo& used_proxy_info, WebSocketHandshakeStreamBase* stream) override {} - void OnStreamFailed(int status, const SSLConfig& used_ssl_config) override {} + void OnStreamFailed(int status, + const SSLConfig& used_ssl_config, + SSLFailureState ssl_failure_state) override {} void OnCertificateError(int status, const SSLConfig& used_ssl_config, const SSLInfo& ssl_info) override {} @@ -85,7 +88,7 @@ EXPECT_EQ(MEDIUM, job->priority()); // Make |job| the bound job. - request.OnStreamFailed(job, ERR_FAILED, SSLConfig()); + request.OnStreamFailed(job, ERR_FAILED, SSLConfig(), SSL_FAILURE_NONE); request.SetPriority(IDLE); EXPECT_EQ(IDLE, job->priority());
diff --git a/net/http/http_stream_factory_impl_unittest.cc b/net/http/http_stream_factory_impl_unittest.cc index 1c0b982..6b20b9a7 100644 --- a/net/http/http_stream_factory_impl_unittest.cc +++ b/net/http/http_stream_factory_impl_unittest.cc
@@ -165,7 +165,9 @@ used_proxy_info_ = used_proxy_info; } - void OnStreamFailed(int status, const SSLConfig& used_ssl_config) override {} + void OnStreamFailed(int status, + const SSLConfig& used_ssl_config, + SSLFailureState ssl_failure_state) override {} void OnCertificateError(int status, const SSLConfig& used_ssl_config,
diff --git a/net/http/transport_security_persister.cc b/net/http/transport_security_persister.cc index 08aa07e..22422009 100644 --- a/net/http/transport_security_persister.cc +++ b/net/http/transport_security_persister.cc
@@ -171,9 +171,8 @@ toplevel.Set(HashedDomainToExternalString(hostname), serialized); } - base::JSONWriter::WriteWithOptions(&toplevel, - base::JSONWriter::OPTIONS_PRETTY_PRINT, - output); + base::JSONWriter::WriteWithOptions( + toplevel, base::JSONWriter::OPTIONS_PRETTY_PRINT, output); return true; }
diff --git a/net/interfaces/proxy_resolver_service.mojom b/net/interfaces/proxy_resolver_service.mojom index 57ab121..68f798e 100644 --- a/net/interfaces/proxy_resolver_service.mojom +++ b/net/interfaces/proxy_resolver_service.mojom
@@ -42,11 +42,16 @@ LoadStateChanged(int32 load_state); }; +interface ProxyResolverErrorObserver { + OnPacScriptError(int32 line_number, string error); +}; + interface ProxyResolverFactory { - // TODO(amistry): Add NetLog and ProxyResolverErrorObserver. + // TODO(amistry): Add NetLog. CreateResolver(string pac_script, ProxyResolver& resolver, HostResolver host_resolver, + ProxyResolverErrorObserver? error_observer, ProxyResolverFactoryRequestClient client); };
diff --git a/net/log/test_net_log_entry.cc b/net/log/test_net_log_entry.cc index 948693b..34e9ffa 100644 --- a/net/log/test_net_log_entry.cc +++ b/net/log/test_net_log_entry.cc
@@ -76,7 +76,7 @@ if (!params) return std::string(); std::string json; - base::JSONWriter::Write(params.get(), &json); + base::JSONWriter::Write(*params, &json); return json; }
diff --git a/net/log/trace_net_log_observer.cc b/net/log/trace_net_log_observer.cc index 2ce8bc0..4978e64c 100644 --- a/net/log/trace_net_log_observer.cc +++ b/net/log/trace_net_log_observer.cc
@@ -32,7 +32,7 @@ void AppendAsTraceFormat(std::string* out) const override { if (value_) { std::string tmp; - base::JSONWriter::Write(value_.get(), &tmp); + base::JSONWriter::Write(*value_, &tmp); *out += tmp; } else { *out += "\"\"";
diff --git a/net/log/write_to_file_net_log_observer.cc b/net/log/write_to_file_net_log_observer.cc index 8ef5a71..5c4f951 100644 --- a/net/log/write_to_file_net_log_observer.cc +++ b/net/log/write_to_file_net_log_observer.cc
@@ -43,12 +43,11 @@ // different source and event types, as they may be added and removed // between Chrome versions. std::string json; - if (constants) { - base::JSONWriter::Write(constants, &json); - } else { - scoped_ptr<base::DictionaryValue> scoped_constants(GetNetConstants()); - base::JSONWriter::Write(scoped_constants.get(), &json); - } + if (constants) + base::JSONWriter::Write(*constants, &json); + else + base::JSONWriter::Write(*GetNetConstants(), &json); + fprintf(file_.get(), "{\"constants\": %s,\n", json.c_str()); // Start events array. It's closed in StopObserving(). @@ -78,9 +77,8 @@ DCHECK(url_request_context->CalledOnValidThread()); std::string json; - scoped_ptr<base::DictionaryValue> net_info = - GetNetInfo(url_request_context, NET_INFO_ALL_SOURCES); - base::JSONWriter::Write(net_info.get(), &json); + base::JSONWriter::Write( + *GetNetInfo(url_request_context, NET_INFO_ALL_SOURCES), &json); fprintf(file_.get(), ",\"tabInfo\": %s\n", json.c_str()); } fprintf(file_.get(), "}"); @@ -94,7 +92,7 @@ // work, lines cannot be pretty printed. scoped_ptr<base::Value> value(entry.ToValue()); std::string json; - base::JSONWriter::Write(value.get(), &json); + base::JSONWriter::Write(*value, &json); fprintf(file_.get(), "%s%s", (added_events_ ? ",\n" : ""), json.c_str()); added_events_ = true; }
diff --git a/net/net.gyp b/net/net.gyp index e3d858c6..588e13e 100644 --- a/net/net.gyp +++ b/net/net.gyp
@@ -5,7 +5,9 @@ { 'variables': { 'chromium_code': 1, - + # Defines an extra set of libs with an alternate copy of org.apache.http. + # TODO(yfriedman): Remove this when crbug.com/488192 is fixed. + 'net_test_extra_libs': [], 'linux_link_kerberos%': 0, 'conditions': [ ['chromeos==1 or embedded==1 or OS=="android" or OS=="ios"', { @@ -319,6 +321,7 @@ 'proxy/load_state_change_coalescer_unittest.cc', 'proxy/mojo_proxy_resolver_factory_impl_unittest.cc', 'proxy/mojo_proxy_resolver_impl_unittest.cc', + 'proxy/proxy_resolver_error_observer_mojo_unittest.cc', 'proxy/proxy_resolver_mojo_unittest.cc', 'proxy/proxy_service_mojo_unittest.cc', ], @@ -925,6 +928,8 @@ 'proxy/mojo_proxy_resolver_factory_impl.h', 'proxy/mojo_proxy_resolver_impl.cc', 'proxy/mojo_proxy_resolver_impl.h', + 'proxy/proxy_resolver_error_observer_mojo.cc', + 'proxy/proxy_resolver_error_observer_mojo.h', ], 'dependencies': [ 'mojo_type_converters', @@ -1402,7 +1407,8 @@ }, 'dependencies': [ 'url_request_failed_job_java', - '../base/base.gyp:base_java' + '../base/base.gyp:base_java', + '<@(net_test_extra_libs)', ], 'includes': [ '../build/java.gypi' ], },
diff --git a/net/net.gypi b/net/net.gypi index c2148c0..3510fc36 100644 --- a/net/net.gypi +++ b/net/net.gypi
@@ -170,6 +170,7 @@ 'ssl/ssl_config.h', 'ssl/ssl_config_service.cc', 'ssl/ssl_config_service.h', + 'ssl/ssl_failure_state.h', 'ssl/ssl_info.cc', 'ssl/ssl_info.h', ], @@ -1478,6 +1479,7 @@ 'proxy/proxy_config_unittest.cc', 'proxy/proxy_info_unittest.cc', 'proxy/proxy_list_unittest.cc', + 'proxy/proxy_resolver_error_observer_mojo_unittest.cc', 'proxy/proxy_resolver_mojo_unittest.cc', 'proxy/proxy_resolver_factory_unittest.cc', 'proxy/proxy_resolver_v8_tracing_unittest.cc',
diff --git a/net/proxy/in_process_mojo_proxy_resolver_factory.cc b/net/proxy/in_process_mojo_proxy_resolver_factory.cc index b38a093..cb1cf21 100644 --- a/net/proxy/in_process_mojo_proxy_resolver_factory.cc +++ b/net/proxy/in_process_mojo_proxy_resolver_factory.cc
@@ -30,9 +30,10 @@ const mojo::String& pac_script, mojo::InterfaceRequest<interfaces::ProxyResolver> req, interfaces::HostResolverPtr host_resolver, + interfaces::ProxyResolverErrorObserverPtr error_observer, interfaces::ProxyResolverFactoryRequestClientPtr client) { factory_->CreateResolver(pac_script, req.Pass(), host_resolver.Pass(), - client.Pass()); + error_observer.Pass(), client.Pass()); return nullptr; }
diff --git a/net/proxy/in_process_mojo_proxy_resolver_factory.h b/net/proxy/in_process_mojo_proxy_resolver_factory.h index 8794614f..86895e92 100644 --- a/net/proxy/in_process_mojo_proxy_resolver_factory.h +++ b/net/proxy/in_process_mojo_proxy_resolver_factory.h
@@ -25,6 +25,7 @@ const mojo::String& pac_script, mojo::InterfaceRequest<interfaces::ProxyResolver> req, interfaces::HostResolverPtr host_resolver, + interfaces::ProxyResolverErrorObserverPtr error_observer, interfaces::ProxyResolverFactoryRequestClientPtr client) override; private:
diff --git a/net/proxy/mojo_proxy_resolver_factory.h b/net/proxy/mojo_proxy_resolver_factory.h index a27b81a..89b70f4 100644 --- a/net/proxy/mojo_proxy_resolver_factory.h +++ b/net/proxy/mojo_proxy_resolver_factory.h
@@ -24,6 +24,7 @@ const mojo::String& pac_script, mojo::InterfaceRequest<interfaces::ProxyResolver> req, interfaces::HostResolverPtr host_resolver, + interfaces::ProxyResolverErrorObserverPtr error_observer, interfaces::ProxyResolverFactoryRequestClientPtr client) = 0; protected:
diff --git a/net/proxy/mojo_proxy_resolver_factory_impl.cc b/net/proxy/mojo_proxy_resolver_factory_impl.cc index 9134495b..4a95aa72 100644 --- a/net/proxy/mojo_proxy_resolver_factory_impl.cc +++ b/net/proxy/mojo_proxy_resolver_factory_impl.cc
@@ -10,6 +10,7 @@ #include "net/base/net_errors.h" #include "net/dns/host_resolver_mojo.h" #include "net/proxy/mojo_proxy_resolver_impl.h" +#include "net/proxy/proxy_resolver_error_observer_mojo.h" #include "net/proxy/proxy_resolver_factory.h" #include "net/proxy/proxy_resolver_v8.h" #include "net/proxy/proxy_resolver_v8_tracing.h" @@ -18,30 +19,18 @@ namespace net { namespace { -class DefaultProxyResolverFactory : public LegacyProxyResolverFactory { - public: - DefaultProxyResolverFactory( - HostResolver* host_resolver, - const ProxyResolver::LoadStateChangedCallback& callback) - : LegacyProxyResolverFactory(true), - host_resolver_(host_resolver), - callback_(callback) {} - - scoped_ptr<ProxyResolver> CreateProxyResolver() override { - return make_scoped_ptr(new ProxyResolverV8Tracing(host_resolver_, nullptr, - nullptr, callback_)); - } - - private: - HostResolver* const host_resolver_; - const ProxyResolver::LoadStateChangedCallback callback_; -}; +scoped_ptr<ProxyResolverErrorObserver> ReturnErrorObserver( + scoped_ptr<ProxyResolverErrorObserver> error_observer) { + return error_observer; +} scoped_ptr<ProxyResolverFactory> CreateDefaultProxyResolver( HostResolver* host_resolver, + scoped_ptr<ProxyResolverErrorObserver> error_observer, const ProxyResolver::LoadStateChangedCallback& callback) { - return make_scoped_ptr( - new DefaultProxyResolverFactory(host_resolver, callback)); + return make_scoped_ptr(new ProxyResolverFactoryV8Tracing( + host_resolver, nullptr, callback, + base::Bind(&ReturnErrorObserver, base::Passed(&error_observer)))); } class LoadStateChangeForwarder @@ -121,6 +110,7 @@ const MojoProxyResolverFactoryImpl::Factory& proxy_resolver_factory, mojo::InterfaceRequest<interfaces::ProxyResolver> request, interfaces::HostResolverPtr host_resolver, + interfaces::ProxyResolverErrorObserverPtr error_observer, interfaces::ProxyResolverFactoryRequestClientPtr client); ~Job() override; @@ -148,6 +138,7 @@ const MojoProxyResolverFactoryImpl::Factory& proxy_resolver_factory, mojo::InterfaceRequest<interfaces::ProxyResolver> request, interfaces::HostResolverPtr host_resolver, + interfaces::ProxyResolverErrorObserverPtr error_observer, interfaces::ProxyResolverFactoryRequestClientPtr client) : parent_(factory), host_resolver_(new HostResolverMojo( @@ -158,6 +149,7 @@ proxy_request_(request.Pass()), factory_(proxy_resolver_factory.Run( host_resolver_.get(), + ProxyResolverErrorObserverMojo::Create(error_observer.Pass()), base::Bind(&LoadStateChangeForwarder::OnLoadStateChanged, load_state_change_forwarder_))), client_ptr_(client.Pass()) { @@ -209,13 +201,14 @@ const mojo::String& pac_script, mojo::InterfaceRequest<interfaces::ProxyResolver> request, interfaces::HostResolverPtr host_resolver, + interfaces::ProxyResolverErrorObserverPtr error_observer, interfaces::ProxyResolverFactoryRequestClientPtr client) { // The Job will call RemoveJob on |this| when either the create request // finishes or |request| or |client| encounters a connection error. jobs_.insert(new Job( this, ProxyResolverScriptData::FromUTF8(pac_script.To<std::string>()), proxy_resolver_impl_factory_, request.Pass(), host_resolver.Pass(), - client.Pass())); + error_observer.Pass(), client.Pass())); } void MojoProxyResolverFactoryImpl::RemoveJob(Job* job) {
diff --git a/net/proxy/mojo_proxy_resolver_factory_impl.h b/net/proxy/mojo_proxy_resolver_factory_impl.h index 29bc6536..bf652b7 100644 --- a/net/proxy/mojo_proxy_resolver_factory_impl.h +++ b/net/proxy/mojo_proxy_resolver_factory_impl.h
@@ -14,12 +14,14 @@ namespace net { class HostResolver; +class ProxyResolverErrorObserver; class ProxyResolverFactory; class MojoProxyResolverFactoryImpl : public interfaces::ProxyResolverFactory { public: using Factory = base::Callback<scoped_ptr<net::ProxyResolverFactory>( HostResolver*, + scoped_ptr<ProxyResolverErrorObserver>, const ProxyResolver::LoadStateChangedCallback&)>; explicit MojoProxyResolverFactoryImpl( @@ -38,6 +40,7 @@ const mojo::String& pac_script, mojo::InterfaceRequest<interfaces::ProxyResolver> request, interfaces::HostResolverPtr host_resolver, + interfaces::ProxyResolverErrorObserverPtr error_observer, interfaces::ProxyResolverFactoryRequestClientPtr client) override; void RemoveJob(Job* job);
diff --git a/net/proxy/mojo_proxy_resolver_factory_impl_unittest.cc b/net/proxy/mojo_proxy_resolver_factory_impl_unittest.cc index c5fb69b..2fe9d81b 100644 --- a/net/proxy/mojo_proxy_resolver_factory_impl_unittest.cc +++ b/net/proxy/mojo_proxy_resolver_factory_impl_unittest.cc
@@ -7,6 +7,7 @@ #include "base/strings/utf_string_conversions.h" #include "net/base/test_completion_callback.h" #include "net/proxy/mock_proxy_resolver.h" +#include "net/proxy/proxy_resolver_error_observer.h" #include "net/test/event_waiter.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/mojo/src/mojo/public/cpp/bindings/binding.h" @@ -75,6 +76,7 @@ scoped_ptr<ProxyResolverFactory> CreateFakeProxyResolverFactory( HostResolver* host_resolver, + scoped_ptr<ProxyResolverErrorObserver> error_observer, const ProxyResolver::LoadStateChangedCallback& callback) { EXPECT_TRUE(host_resolver); EXPECT_FALSE(callback.is_null()); @@ -105,12 +107,14 @@ interfaces::HostResolverPtr host_resolver; mojo::InterfaceRequest<interfaces::HostResolver> host_resolver_request = mojo::GetProxy(&host_resolver); + interfaces::ProxyResolverErrorObserverPtr error_observer; + mojo::GetProxy(&error_observer); interfaces::ProxyResolverFactoryRequestClientPtr client_ptr; mojo::Binding<ProxyResolverFactoryRequestClient> client_binding( this, mojo::GetProxy(&client_ptr)); - factory_->CreateResolver(mojo::String::From(kScriptData), - mojo::GetProxy(&proxy_resolver), - host_resolver.Pass(), client_ptr.Pass()); + factory_->CreateResolver( + mojo::String::From(kScriptData), mojo::GetProxy(&proxy_resolver), + host_resolver.Pass(), error_observer.Pass(), client_ptr.Pass()); proxy_resolver.set_error_handler(this); waiter_.WaitForEvent(RESOLVER_CREATED); EXPECT_EQ(0, instances_destroyed_); @@ -136,12 +140,14 @@ mojo::GetProxy(&host_resolver); mojo::Binding<interfaces::HostResolver> binding(nullptr, &host_resolver); binding.set_error_handler(this); + interfaces::ProxyResolverErrorObserverPtr error_observer; + mojo::GetProxy(&error_observer); interfaces::ProxyResolverFactoryRequestClientPtr client_ptr; mojo::Binding<ProxyResolverFactoryRequestClient> client_binding( this, mojo::GetProxy(&client_ptr)); - factory_->CreateResolver(mojo::String::From(kScriptData), - mojo::GetProxy(&proxy_resolver), - host_resolver.Pass(), client_ptr.Pass()); + factory_->CreateResolver( + mojo::String::From(kScriptData), mojo::GetProxy(&proxy_resolver), + host_resolver.Pass(), error_observer.Pass(), client_ptr.Pass()); proxy_resolver.set_error_handler(this); waiter_.WaitForEvent(RESOLVER_CREATED); EXPECT_EQ(0, instances_destroyed_); @@ -165,12 +171,14 @@ interfaces::HostResolverPtr host_resolver; mojo::InterfaceRequest<interfaces::HostResolver> host_resolver_request = mojo::GetProxy(&host_resolver); + interfaces::ProxyResolverErrorObserverPtr error_observer; + mojo::GetProxy(&error_observer); interfaces::ProxyResolverFactoryRequestClientPtr client_ptr; mojo::Binding<ProxyResolverFactoryRequestClient> client_binding( this, mojo::GetProxy(&client_ptr)); - factory_->CreateResolver(mojo::String::From(kScriptData), - mojo::GetProxy(&proxy_resolver), - host_resolver.Pass(), client_ptr.Pass()); + factory_->CreateResolver( + mojo::String::From(kScriptData), mojo::GetProxy(&proxy_resolver), + host_resolver.Pass(), error_observer.Pass(), client_ptr.Pass()); proxy_resolver.set_error_handler(this); waiter_.WaitForEvent(RESOLVER_CREATED); EXPECT_EQ(0, instances_destroyed_); @@ -195,12 +203,14 @@ interfaces::HostResolverPtr host_resolver; mojo::InterfaceRequest<interfaces::HostResolver> host_resolver_request = mojo::GetProxy(&host_resolver); + interfaces::ProxyResolverErrorObserverPtr error_observer; + mojo::GetProxy(&error_observer); interfaces::ProxyResolverFactoryRequestClientPtr client_ptr; mojo::Binding<ProxyResolverFactoryRequestClient> client_binding( this, mojo::GetProxy(&client_ptr)); - factory_->CreateResolver(mojo::String::From(kScriptData), - mojo::GetProxy(&proxy_resolver), - host_resolver.Pass(), client_ptr.Pass()); + factory_->CreateResolver( + mojo::String::From(kScriptData), mojo::GetProxy(&proxy_resolver), + host_resolver.Pass(), error_observer.Pass(), client_ptr.Pass()); proxy_resolver.set_error_handler(this); waiter_.WaitForEvent(RESOLVER_CREATED); EXPECT_EQ(0, instances_destroyed_); @@ -220,12 +230,14 @@ interfaces::HostResolverPtr host_resolver; mojo::InterfaceRequest<interfaces::HostResolver> host_resolver_request = mojo::GetProxy(&host_resolver); + interfaces::ProxyResolverErrorObserverPtr error_observer; + mojo::GetProxy(&error_observer); interfaces::ProxyResolverFactoryRequestClientPtr client_ptr; mojo::Binding<ProxyResolverFactoryRequestClient> client_binding( this, mojo::GetProxy(&client_ptr)); - factory_->CreateResolver(mojo::String::From(kScriptData), - mojo::GetProxy(&proxy_resolver), - host_resolver.Pass(), client_ptr.Pass()); + factory_->CreateResolver( + mojo::String::From(kScriptData), mojo::GetProxy(&proxy_resolver), + host_resolver.Pass(), error_observer.Pass(), client_ptr.Pass()); proxy_resolver.set_error_handler(this); waiter_.WaitForEvent(RESOLVER_CREATED); EXPECT_EQ(0, instances_destroyed_); @@ -247,12 +259,14 @@ mojo::GetProxy(&host_resolver); mojo::Binding<interfaces::HostResolver> binding(nullptr, &host_resolver); binding.set_error_handler(this); + interfaces::ProxyResolverErrorObserverPtr error_observer; + mojo::GetProxy(&error_observer); interfaces::ProxyResolverFactoryRequestClientPtr client_ptr; mojo::Binding<ProxyResolverFactoryRequestClient> client_binding( this, mojo::GetProxy(&client_ptr)); - factory_->CreateResolver(mojo::String::From(kScriptData), - mojo::GetProxy(&proxy_resolver), - host_resolver.Pass(), client_ptr.Pass()); + factory_->CreateResolver( + mojo::String::From(kScriptData), mojo::GetProxy(&proxy_resolver), + host_resolver.Pass(), error_observer.Pass(), client_ptr.Pass()); proxy_resolver.set_error_handler(this); waiter_.WaitForEvent(RESOLVER_CREATED); EXPECT_EQ(0, instances_destroyed_); @@ -271,12 +285,14 @@ mojo::GetProxy(&host_resolver); mojo::Binding<interfaces::HostResolver> binding(nullptr, &host_resolver); binding.set_error_handler(this); + interfaces::ProxyResolverErrorObserverPtr error_observer; + mojo::GetProxy(&error_observer); interfaces::ProxyResolverFactoryRequestClientPtr client_ptr; mojo::Binding<ProxyResolverFactoryRequestClient> client_binding( this, mojo::GetProxy(&client_ptr)); - factory_->CreateResolver(mojo::String::From(kScriptData), - mojo::GetProxy(&proxy_resolver), - host_resolver.Pass(), client_ptr.Pass()); + factory_->CreateResolver( + mojo::String::From(kScriptData), mojo::GetProxy(&proxy_resolver), + host_resolver.Pass(), error_observer.Pass(), client_ptr.Pass()); proxy_resolver.set_error_handler(this); client_binding.set_error_handler(this); waiter_.WaitForEvent(RESOLVER_CREATED);
diff --git a/net/proxy/network_delegate_error_observer.cc b/net/proxy/network_delegate_error_observer.cc index e92065b..1bb0537 100644 --- a/net/proxy/network_delegate_error_observer.cc +++ b/net/proxy/network_delegate_error_observer.cc
@@ -74,6 +74,14 @@ core_->Shutdown(); } +// static +scoped_ptr<ProxyResolverErrorObserver> NetworkDelegateErrorObserver::Create( + NetworkDelegate* network_delegate, + const scoped_refptr<base::SingleThreadTaskRunner>& origin_runner) { + return make_scoped_ptr( + new NetworkDelegateErrorObserver(network_delegate, origin_runner.get())); +} + void NetworkDelegateErrorObserver::OnPACScriptError( int line_number, const base::string16& error) {
diff --git a/net/proxy/network_delegate_error_observer.h b/net/proxy/network_delegate_error_observer.h index 2ae649c..2463913f 100644 --- a/net/proxy/network_delegate_error_observer.h +++ b/net/proxy/network_delegate_error_observer.h
@@ -7,6 +7,7 @@ #include "base/compiler_specific.h" #include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" #include "net/proxy/proxy_resolver_error_observer.h" namespace base { @@ -26,6 +27,10 @@ base::SingleThreadTaskRunner* origin_runner); ~NetworkDelegateErrorObserver() override; + static scoped_ptr<ProxyResolverErrorObserver> Create( + NetworkDelegate* network_delegate, + const scoped_refptr<base::SingleThreadTaskRunner>& origin_runner); + // ProxyResolverErrorObserver implementation. void OnPACScriptError(int line_number, const base::string16& error) override;
diff --git a/net/proxy/proxy_resolver_error_observer_mojo.cc b/net/proxy/proxy_resolver_error_observer_mojo.cc new file mode 100644 index 0000000..a63d5d9 --- /dev/null +++ b/net/proxy/proxy_resolver_error_observer_mojo.cc
@@ -0,0 +1,46 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/proxy/proxy_resolver_error_observer_mojo.h" + +#include "base/bind.h" +#include "base/location.h" +#include "base/thread_task_runner_handle.h" +#include "mojo/common/common_type_converters.h" + +namespace net { + +// static +scoped_ptr<ProxyResolverErrorObserver> ProxyResolverErrorObserverMojo::Create( + interfaces::ProxyResolverErrorObserverPtr error_observer) { + if (!error_observer) + return nullptr; + + return scoped_ptr<ProxyResolverErrorObserver>( + new ProxyResolverErrorObserverMojo(error_observer.Pass())); +} + +void ProxyResolverErrorObserverMojo::OnPACScriptError( + int line_number, + const base::string16& error) { + if (!task_runner_->RunsTasksOnCurrentThread()) { + task_runner_->PostTask( + FROM_HERE, base::Bind(&ProxyResolverErrorObserverMojo::OnPACScriptError, + weak_this_, line_number, error)); + return; + } + error_observer_->OnPacScriptError(line_number, mojo::String::From(error)); +} + +ProxyResolverErrorObserverMojo::ProxyResolverErrorObserverMojo( + interfaces::ProxyResolverErrorObserverPtr error_observer) + : error_observer_(error_observer.Pass()), + task_runner_(base::ThreadTaskRunnerHandle::Get()), + weak_factory_(this) { + weak_this_ = weak_factory_.GetWeakPtr(); +} + +ProxyResolverErrorObserverMojo::~ProxyResolverErrorObserverMojo() = default; + +} // namespace net
diff --git a/net/proxy/proxy_resolver_error_observer_mojo.h b/net/proxy/proxy_resolver_error_observer_mojo.h new file mode 100644 index 0000000..95a8ff9 --- /dev/null +++ b/net/proxy/proxy_resolver_error_observer_mojo.h
@@ -0,0 +1,43 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef NET_PROXY_PROXY_RESOLVER_ERROR_OBSERVER_MOJO_H_ +#define NET_PROXY_PROXY_RESOLVER_ERROR_OBSERVER_MOJO_H_ + +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "base/memory/weak_ptr.h" +#include "base/single_thread_task_runner.h" +#include "net/interfaces/proxy_resolver_service.mojom.h" +#include "net/proxy/proxy_resolver_error_observer.h" + +namespace net { + +// An implementation of ProxyResolverErrorObserver that forwards errors to an +// interfaces::ProxyResolverErrorObserver mojo interface. +class ProxyResolverErrorObserverMojo : public ProxyResolverErrorObserver { + public: + static scoped_ptr<ProxyResolverErrorObserver> Create( + interfaces::ProxyResolverErrorObserverPtr error_observer); + + void OnPACScriptError(int line_number, const base::string16& error) override; + + private: + explicit ProxyResolverErrorObserverMojo( + interfaces::ProxyResolverErrorObserverPtr error_observer); + ~ProxyResolverErrorObserverMojo() override; + + // |error_observer_| may only be accessed when running on |task_runner_|. + interfaces::ProxyResolverErrorObserverPtr error_observer_; + scoped_refptr<base::SingleThreadTaskRunner> task_runner_; + + // Creating a new WeakPtr is only valid on the original thread, but copying an + // existing WeakPtr is valid on any thread so keep |weak_this_| ready to copy. + base::WeakPtr<ProxyResolverErrorObserverMojo> weak_this_; + base::WeakPtrFactory<ProxyResolverErrorObserverMojo> weak_factory_; +}; + +} // namespace net + +#endif // NET_PROXY_PROXY_RESOLVER_ERROR_OBSERVER_MOJO_H_
diff --git a/net/proxy/proxy_resolver_error_observer_mojo_unittest.cc b/net/proxy/proxy_resolver_error_observer_mojo_unittest.cc new file mode 100644 index 0000000..d28bd059 --- /dev/null +++ b/net/proxy/proxy_resolver_error_observer_mojo_unittest.cc
@@ -0,0 +1,103 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/proxy/proxy_resolver_error_observer_mojo.h" + +#include <utility> +#include <vector> + +#include "base/bind.h" +#include "base/strings/utf_string_conversions.h" +#include "base/threading/thread.h" +#include "mojo/common/common_type_converters.h" +#include "net/test/event_waiter.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace net { +namespace { + +class ErrorObserverClient : public interfaces::ProxyResolverErrorObserver { + public: + enum Event { + ERROR_RECEIVED, + }; + + explicit ErrorObserverClient( + mojo::InterfaceRequest<interfaces::ProxyResolverErrorObserver> request); + + EventWaiter<Event>& event_waiter() { return event_waiter_; } + const std::vector<std::pair<int, base::string16>>& errors() const { + return errors_; + } + + private: + void OnPacScriptError(int32_t line_number, + const mojo::String& error) override; + + mojo::Binding<interfaces::ProxyResolverErrorObserver> binding_; + EventWaiter<Event> event_waiter_; + std::vector<std::pair<int, base::string16>> errors_; + + DISALLOW_COPY_AND_ASSIGN(ErrorObserverClient); +}; + +ErrorObserverClient::ErrorObserverClient( + mojo::InterfaceRequest<interfaces::ProxyResolverErrorObserver> request) + : binding_(this, request.Pass()) { +} + +void ErrorObserverClient::OnPacScriptError(int32_t line_number, + const mojo::String& error) { + errors_.push_back(std::make_pair(line_number, error.To<base::string16>())); + event_waiter_.NotifyEvent(ERROR_RECEIVED); +} + +} // namespace + +class ProxyResolverErrorObserverMojoTest : public testing::Test { + public: + ProxyResolverErrorObserver& error_observer() { return *error_observer_; } + ErrorObserverClient& client() { return *client_; } + + private: + void SetUp() override { + interfaces::ProxyResolverErrorObserverPtr error_observer_ptr; + client_.reset(new ErrorObserverClient(mojo::GetProxy(&error_observer_ptr))); + error_observer_ = + ProxyResolverErrorObserverMojo::Create(error_observer_ptr.Pass()); + ASSERT_TRUE(error_observer_); + } + + scoped_ptr<ErrorObserverClient> client_; + scoped_ptr<ProxyResolverErrorObserver> error_observer_; +}; + +TEST_F(ProxyResolverErrorObserverMojoTest, NullHandle) { + EXPECT_FALSE(ProxyResolverErrorObserverMojo::Create( + interfaces::ProxyResolverErrorObserverPtr())); +} + +TEST_F(ProxyResolverErrorObserverMojoTest, ErrorReportedOnMainThread) { + base::string16 error(base::ASCIIToUTF16("error message")); + error_observer().OnPACScriptError(123, error); + client().event_waiter().WaitForEvent(ErrorObserverClient::ERROR_RECEIVED); + ASSERT_EQ(1u, client().errors().size()); + EXPECT_EQ(123, client().errors()[0].first); + EXPECT_EQ(error, client().errors()[0].second); +} + +TEST_F(ProxyResolverErrorObserverMojoTest, ErrorReportedOnAnotherThread) { + base::Thread other_thread("error reporting thread"); + base::string16 error(base::ASCIIToUTF16("error message")); + other_thread.Start(); + other_thread.message_loop()->PostTask( + FROM_HERE, base::Bind(&ProxyResolverErrorObserver::OnPACScriptError, + base::Unretained(&error_observer()), 123, error)); + client().event_waiter().WaitForEvent(ErrorObserverClient::ERROR_RECEIVED); + ASSERT_EQ(1u, client().errors().size()); + EXPECT_EQ(123, client().errors()[0].first); + EXPECT_EQ(error, client().errors()[0].second); +} + +} // namespace net
diff --git a/net/proxy/proxy_resolver_mojo.cc b/net/proxy/proxy_resolver_mojo.cc index c676827..c0e38fb2 100644 --- a/net/proxy/proxy_resolver_mojo.cc +++ b/net/proxy/proxy_resolver_mojo.cc
@@ -4,20 +4,123 @@ #include "net/proxy/proxy_resolver_mojo.h" +#include <set> + #include "base/bind.h" #include "base/logging.h" #include "base/stl_util.h" +#include "base/threading/thread_checker.h" #include "mojo/common/common_type_converters.h" #include "mojo/common/url_type_converters.h" +#include "net/base/load_states.h" #include "net/base/net_errors.h" #include "net/dns/mojo_host_resolver_impl.h" +#include "net/interfaces/host_resolver_service.mojom.h" +#include "net/interfaces/proxy_resolver_service.mojom.h" #include "net/proxy/mojo_proxy_resolver_factory.h" #include "net/proxy/mojo_proxy_type_converters.h" #include "net/proxy/proxy_info.h" +#include "net/proxy/proxy_resolver.h" +#include "net/proxy/proxy_resolver_error_observer.h" +#include "net/proxy/proxy_resolver_script_data.h" #include "third_party/mojo/src/mojo/public/cpp/bindings/binding.h" #include "third_party/mojo/src/mojo/public/cpp/bindings/error_handler.h" namespace net { +namespace { + +class ErrorObserverHolder : public interfaces::ProxyResolverErrorObserver { + public: + ErrorObserverHolder( + scoped_ptr<net::ProxyResolverErrorObserver> error_observer, + mojo::InterfaceRequest<interfaces::ProxyResolverErrorObserver> request); + ~ErrorObserverHolder() override; + + void OnPacScriptError(int32_t line_number, + const mojo::String& error) override; + + private: + scoped_ptr<net::ProxyResolverErrorObserver> error_observer_; + mojo::Binding<interfaces::ProxyResolverErrorObserver> binding_; + + DISALLOW_COPY_AND_ASSIGN(ErrorObserverHolder); +}; + +ErrorObserverHolder::ErrorObserverHolder( + scoped_ptr<net::ProxyResolverErrorObserver> error_observer, + mojo::InterfaceRequest<interfaces::ProxyResolverErrorObserver> request) + : error_observer_(error_observer.Pass()), binding_(this, request.Pass()) { +} + +ErrorObserverHolder::~ErrorObserverHolder() = default; + +void ErrorObserverHolder::OnPacScriptError(int32_t line_number, + const mojo::String& error) { + DCHECK(error_observer_); + error_observer_->OnPACScriptError(line_number, error.To<base::string16>()); +} + +// Implementation of ProxyResolver that connects to a Mojo service to evaluate +// PAC scripts. This implementation only knows about Mojo services, and +// therefore that service may live in or out of process. +// +// This implementation reports disconnections from the Mojo service (i.e. if the +// service is out-of-process and that process crashes) using the error code +// ERR_PAC_SCRIPT_TERMINATED. +class ProxyResolverMojo : public ProxyResolver, public mojo::ErrorHandler { + public: + // Constructs a ProxyResolverMojo that connects to a mojo proxy resolver + // implementation using |resolver_ptr|. The implementation uses + // |host_resolver| as the DNS resolver, using |host_resolver_binding| to + // communicate with it. When deleted, the closure contained within + // |on_delete_callback_runner| will be run. + // TODO(amistry): Add NetLog. + ProxyResolverMojo( + interfaces::ProxyResolverPtr resolver_ptr, + scoped_ptr<interfaces::HostResolver> host_resolver, + scoped_ptr<mojo::Binding<interfaces::HostResolver>> host_resolver_binding, + scoped_ptr<base::ScopedClosureRunner> on_delete_callback_runner, + scoped_ptr<ErrorObserverHolder> error_observer); + ~ProxyResolverMojo() override; + + // ProxyResolver implementation: + int GetProxyForURL(const GURL& url, + ProxyInfo* results, + const net::CompletionCallback& callback, + RequestHandle* request, + const BoundNetLog& net_log) override; + void CancelRequest(RequestHandle request) override; + LoadState GetLoadState(RequestHandle request) const override; + void CancelSetPacScript() override; + int SetPacScript(const scoped_refptr<ProxyResolverScriptData>& pac_script, + const net::CompletionCallback& callback) override; + + private: + class Job; + + // Overridden from mojo::ErrorHandler: + void OnConnectionError() override; + + void RemoveJob(Job* job); + + // Connection to the Mojo proxy resolver. + interfaces::ProxyResolverPtr mojo_proxy_resolver_ptr_; + + // Mojo host resolver service and binding. + scoped_ptr<interfaces::HostResolver> mojo_host_resolver_; + scoped_ptr<mojo::Binding<interfaces::HostResolver>> + mojo_host_resolver_binding_; + + scoped_ptr<ErrorObserverHolder> error_observer_; + + std::set<Job*> pending_jobs_; + + base::ThreadChecker thread_checker_; + + scoped_ptr<base::ScopedClosureRunner> on_delete_callback_runner_; + + DISALLOW_COPY_AND_ASSIGN(ProxyResolverMojo); +}; class ProxyResolverMojo::Job : public interfaces::ProxyResolverRequestClient, public mojo::ErrorHandler { @@ -114,11 +217,13 @@ interfaces::ProxyResolverPtr resolver_ptr, scoped_ptr<interfaces::HostResolver> host_resolver, scoped_ptr<mojo::Binding<interfaces::HostResolver>> host_resolver_binding, - scoped_ptr<base::ScopedClosureRunner> on_delete_callback_runner) + scoped_ptr<base::ScopedClosureRunner> on_delete_callback_runner, + scoped_ptr<ErrorObserverHolder> error_observer) : ProxyResolver(true), mojo_proxy_resolver_ptr_(resolver_ptr.Pass()), mojo_host_resolver_(host_resolver.Pass()), mojo_host_resolver_binding_(host_resolver_binding.Pass()), + error_observer_(error_observer.Pass()), on_delete_callback_runner_(on_delete_callback_runner.Pass()) { mojo_proxy_resolver_ptr_.set_error_handler(this); } @@ -187,6 +292,8 @@ return job->load_state(); } +} // namespace + class ProxyResolverFactoryMojo::Job : public interfaces::ProxyResolverFactoryRequestClient, public mojo::ErrorHandler, @@ -205,11 +312,20 @@ new mojo::Binding<interfaces::HostResolver>(host_resolver_.get())) { interfaces::HostResolverPtr host_resolver_ptr; interfaces::ProxyResolverFactoryRequestClientPtr client_ptr; + interfaces::ProxyResolverErrorObserverPtr error_observer_ptr; binding_.Bind(mojo::GetProxy(&client_ptr)); + if (!factory_->error_observer_factory_.is_null()) { + scoped_ptr<ProxyResolverErrorObserver> error_observer = + factory_->error_observer_factory_.Run(); + if (error_observer) { + error_observer_.reset(new ErrorObserverHolder( + error_observer.Pass(), mojo::GetProxy(&error_observer_ptr))); + } + } host_resolver_binding_->Bind(mojo::GetProxy(&host_resolver_ptr)); on_delete_callback_runner_ = factory_->mojo_proxy_factory_->CreateResolver( mojo::String::From(pac_script->utf16()), mojo::GetProxy(&resolver_ptr_), - host_resolver_ptr.Pass(), client_ptr.Pass()); + host_resolver_ptr.Pass(), error_observer_ptr.Pass(), client_ptr.Pass()); resolver_ptr_.set_error_handler(this); binding_.set_error_handler(this); } @@ -226,7 +342,8 @@ if (error == OK) { resolver_->reset(new ProxyResolverMojo( resolver_ptr_.Pass(), host_resolver_.Pass(), - host_resolver_binding_.Pass(), on_delete_callback_runner_.Pass())); + host_resolver_binding_.Pass(), on_delete_callback_runner_.Pass(), + error_observer_.Pass())); } on_delete_callback_runner_.reset(); callback_.Run(error); @@ -240,14 +357,18 @@ scoped_ptr<interfaces::HostResolver> host_resolver_; scoped_ptr<mojo::Binding<interfaces::HostResolver>> host_resolver_binding_; scoped_ptr<base::ScopedClosureRunner> on_delete_callback_runner_; + scoped_ptr<ErrorObserverHolder> error_observer_; }; ProxyResolverFactoryMojo::ProxyResolverFactoryMojo( MojoProxyResolverFactory* mojo_proxy_factory, - HostResolver* host_resolver) + HostResolver* host_resolver, + const base::Callback<scoped_ptr<ProxyResolverErrorObserver>()>& + error_observer_factory) : ProxyResolverFactory(true), mojo_proxy_factory_(mojo_proxy_factory), - host_resolver_(host_resolver) { + host_resolver_(host_resolver), + error_observer_factory_(error_observer_factory) { } ProxyResolverFactoryMojo::~ProxyResolverFactoryMojo() = default;
diff --git a/net/proxy/proxy_resolver_mojo.h b/net/proxy/proxy_resolver_mojo.h index ada4352..7c827462 100644 --- a/net/proxy/proxy_resolver_mojo.h +++ b/net/proxy/proxy_resolver_mojo.h
@@ -5,95 +5,27 @@ #ifndef NET_PROXY_PROXY_RESOLVER_MOJO_H_ #define NET_PROXY_PROXY_RESOLVER_MOJO_H_ -#include <set> - -#include "base/callback_helpers.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" -#include "base/threading/thread_checker.h" #include "net/base/completion_callback.h" -#include "net/base/load_states.h" -#include "net/interfaces/host_resolver_service.mojom.h" -#include "net/interfaces/proxy_resolver_service.mojom.h" -#include "net/proxy/proxy_resolver.h" #include "net/proxy/proxy_resolver_factory.h" -#include "net/proxy/proxy_resolver_script_data.h" #include "third_party/mojo/src/mojo/public/cpp/bindings/binding.h" -class GURL; - namespace net { - -class BoundNetLog; class HostResolver; -class ProxyInfo; +class ProxyResolverErrorObserver; +class ProxyResolverScriptData; class MojoProxyResolverFactory; -// Implementation of ProxyResolver that connects to a Mojo service to evaluate -// PAC scripts. This implementation only knows about Mojo services, and -// therefore that service may live in or out of process. -// -// This implementation reports disconnections from the Mojo service (i.e. if the -// service is out-of-process and that process crashes) using the error code -// ERR_PAC_SCRIPT_TERMINATED. -class ProxyResolverMojo : public ProxyResolver, public mojo::ErrorHandler { - public: - // Constructs a ProxyResolverMojo that connects to a mojo proxy resolver - // implementation using |resolver_ptr|. The implementation uses - // |host_resolver| as the DNS resolver, using |host_resolver_binding| to - // communicate with it. When deleted, the closure contained within - // |on_delete_callback_runner| will be run. - // TODO(amistry): Add ProxyResolverErrorObserver and NetLog. - ProxyResolverMojo( - interfaces::ProxyResolverPtr resolver_ptr, - scoped_ptr<interfaces::HostResolver> host_resolver, - scoped_ptr<mojo::Binding<interfaces::HostResolver>> host_resolver_binding, - scoped_ptr<base::ScopedClosureRunner> on_delete_callback_runner); - ~ProxyResolverMojo() override; - - // ProxyResolver implementation: - int GetProxyForURL(const GURL& url, - ProxyInfo* results, - const net::CompletionCallback& callback, - RequestHandle* request, - const BoundNetLog& net_log) override; - void CancelRequest(RequestHandle request) override; - LoadState GetLoadState(RequestHandle request) const override; - void CancelSetPacScript() override; - int SetPacScript(const scoped_refptr<ProxyResolverScriptData>& pac_script, - const net::CompletionCallback& callback) override; - - private: - class Job; - - // Overridden from mojo::ErrorHandler: - void OnConnectionError() override; - - void RemoveJob(Job* job); - - // Connection to the Mojo proxy resolver. - interfaces::ProxyResolverPtr mojo_proxy_resolver_ptr_; - - // Mojo host resolver service and binding. - scoped_ptr<interfaces::HostResolver> mojo_host_resolver_; - scoped_ptr<mojo::Binding<interfaces::HostResolver>> - mojo_host_resolver_binding_; - - std::set<Job*> pending_jobs_; - - base::ThreadChecker thread_checker_; - - scoped_ptr<base::ScopedClosureRunner> on_delete_callback_runner_; - - DISALLOW_COPY_AND_ASSIGN(ProxyResolverMojo); -}; - // Implementation of ProxyResolverFactory that connects to a Mojo service to // create implementations of a Mojo proxy resolver to back a ProxyResolverMojo. class ProxyResolverFactoryMojo : public ProxyResolverFactory { public: - ProxyResolverFactoryMojo(MojoProxyResolverFactory* mojo_proxy_factory, - HostResolver* host_resolver); + ProxyResolverFactoryMojo( + MojoProxyResolverFactory* mojo_proxy_factory, + HostResolver* host_resolver, + const base::Callback<scoped_ptr<ProxyResolverErrorObserver>()>& + error_observer_factory); ~ProxyResolverFactoryMojo() override; // ProxyResolverFactory override. @@ -108,6 +40,8 @@ MojoProxyResolverFactory* const mojo_proxy_factory_; HostResolver* const host_resolver_; + const base::Callback<scoped_ptr<ProxyResolverErrorObserver>()> + error_observer_factory_; DISALLOW_COPY_AND_ASSIGN(ProxyResolverFactoryMojo); };
diff --git a/net/proxy/proxy_resolver_mojo_unittest.cc b/net/proxy/proxy_resolver_mojo_unittest.cc index 83bdf004..a99e755 100644 --- a/net/proxy/proxy_resolver_mojo_unittest.cc +++ b/net/proxy/proxy_resolver_mojo_unittest.cc
@@ -15,12 +15,15 @@ #include "base/run_loop.h" #include "base/stl_util.h" #include "mojo/common/common_type_converters.h" +#include "net/base/load_states.h" #include "net/base/net_errors.h" #include "net/base/test_completion_callback.h" #include "net/log/net_log.h" #include "net/proxy/mojo_proxy_resolver_factory.h" #include "net/proxy/mojo_proxy_type_converters.h" #include "net/proxy/proxy_info.h" +#include "net/proxy/proxy_resolver.h" +#include "net/proxy/proxy_resolver_error_observer.h" #include "net/proxy/proxy_resolver_script_data.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/mojo/src/mojo/public/cpp/bindings/binding.h" @@ -316,6 +319,7 @@ const mojo::String& pac_url, mojo::InterfaceRequest<interfaces::ProxyResolver> request, interfaces::HostResolverPtr host_resolver, + interfaces::ProxyResolverErrorObserverPtr error_observer, interfaces::ProxyResolverFactoryRequestClientPtr client) override; void WakeWaiter(); @@ -368,6 +372,7 @@ const mojo::String& pac_script, mojo::InterfaceRequest<interfaces::ProxyResolver> request, interfaces::HostResolverPtr host_resolver, + interfaces::ProxyResolverErrorObserverPtr error_observer, interfaces::ProxyResolverFactoryRequestClientPtr client) { ASSERT_FALSE(create_resolver_actions_.empty()); CreateProxyResolverAction action = create_resolver_actions_.front(); @@ -409,8 +414,9 @@ void SetUp() override { mock_proxy_resolver_factory_.reset(new MockMojoProxyResolverFactory( &mock_proxy_resolver_, mojo::GetProxy(&factory_ptr_))); - proxy_resolver_factory_mojo_.reset( - new ProxyResolverFactoryMojo(this, nullptr)); + proxy_resolver_factory_mojo_.reset(new ProxyResolverFactoryMojo( + this, nullptr, + base::Callback<scoped_ptr<ProxyResolverErrorObserver>()>())); } scoped_ptr<Request> MakeRequest(const GURL& url) { @@ -421,9 +427,10 @@ const mojo::String& pac_script, mojo::InterfaceRequest<interfaces::ProxyResolver> req, interfaces::HostResolverPtr host_resolver, + interfaces::ProxyResolverErrorObserverPtr error_observer, interfaces::ProxyResolverFactoryRequestClientPtr client) override { factory_ptr_->CreateResolver(pac_script, req.Pass(), host_resolver.Pass(), - client.Pass()); + error_observer.Pass(), client.Pass()); return make_scoped_ptr( new base::ScopedClosureRunner(on_delete_callback_.closure())); }
diff --git a/net/proxy/proxy_resolver_v8_tracing.cc b/net/proxy/proxy_resolver_v8_tracing.cc index 921cd55..448a512 100644 --- a/net/proxy/proxy_resolver_v8_tracing.cc +++ b/net/proxy/proxy_resolver_v8_tracing.cc
@@ -4,6 +4,10 @@ #include "net/proxy/proxy_resolver_v8_tracing.h" +#include <map> +#include <string> +#include <vector> + #include "base/bind.h" #include "base/single_thread_task_runner.h" #include "base/strings/stringprintf.h" @@ -64,10 +68,9 @@ return dict; } -} // namespace - // The Job class is responsible for executing GetProxyForURL() and -// SetPacScript(), since both of these operations share similar code. +// creating ProxyResolverV8 instances, since both of these operations share +// similar code. // // The DNS for these operations can operate in either blocking or // non-blocking mode. Blocking mode is used as a fallback when the PAC script @@ -80,17 +83,41 @@ // The lifetime of Jobs does not exceed that of the ProxyResolverV8Tracing that // spawned it. Destruction might happen on either the origin thread or the // worker thread. -class ProxyResolverV8Tracing::Job - : public base::RefCountedThreadSafe<ProxyResolverV8Tracing::Job>, - public ProxyResolverV8::JSBindings { +class Job : public base::RefCountedThreadSafe<Job>, + public ProxyResolverV8::JSBindings { public: - // |parent| is non-owned. It is the ProxyResolverV8Tracing that spawned this - // Job, and must oulive it. - explicit Job(ProxyResolverV8Tracing* parent); + struct Params { + Params( + const scoped_refptr<base::SingleThreadTaskRunner>& worker_task_runner, + HostResolver* host_resolver, + ProxyResolverErrorObserver* error_observer, + NetLog* net_log, + ProxyResolver::LoadStateChangedCallback on_load_state_changed, + int* num_outstanding_callbacks) + : v8_resolver(nullptr), + worker_task_runner(worker_task_runner), + host_resolver(host_resolver), + error_observer(error_observer), + net_log(net_log), + on_load_state_changed(on_load_state_changed), + num_outstanding_callbacks(num_outstanding_callbacks) {} + + ProxyResolverV8* v8_resolver; + scoped_refptr<base::SingleThreadTaskRunner> worker_task_runner; + HostResolver* host_resolver; + ProxyResolverErrorObserver* error_observer; + NetLog* net_log; + ProxyResolver::LoadStateChangedCallback on_load_state_changed; + int* num_outstanding_callbacks; + }; + // |params| is non-owned. It contains the parameters for this Job, and must + // outlive it. + explicit Job(const Params* params); // Called from origin thread. - void StartSetPacScript( + void StartCreateV8Resolver( const scoped_refptr<ProxyResolverScriptData>& script_data, + scoped_ptr<ProxyResolverV8>* resolver, const CompletionCallback& callback); // Called from origin thread. @@ -107,10 +134,10 @@ private: typedef std::map<std::string, std::string> DnsCache; - friend class base::RefCountedThreadSafe<ProxyResolverV8Tracing::Job>; + friend class base::RefCountedThreadSafe<Job>; enum Operation { - SET_PAC_SCRIPT, + CREATE_V8_RESOLVER, GET_PROXY_FOR_URL, }; @@ -129,7 +156,7 @@ void ReleaseCallback(); ProxyResolverV8* v8_resolver(); - base::MessageLoop* worker_loop(); + const scoped_refptr<base::SingleThreadTaskRunner>& worker_task_runner(); HostResolver* host_resolver(); ProxyResolverErrorObserver* error_observer(); NetLog* net_log(); @@ -203,9 +230,9 @@ // completion callback is expected to run. scoped_refptr<base::SingleThreadTaskRunner> origin_runner_; - // The ProxyResolverV8Tracing which spawned this Job. + // The Parameters for this Job. // Initialized on origin thread and then accessed from both threads. - ProxyResolverV8Tracing* parent_; + const Params* const params_; // The callback to run (on the origin thread) when the Job finishes. // Should only be accessed from origin thread. @@ -236,10 +263,11 @@ scoped_refptr<Job> owned_self_reference_; // ------------------------------------------------------- - // State specific to SET_PAC_SCRIPT. + // State specific to CREATE_V8_RESOLVER. // ------------------------------------------------------- scoped_refptr<ProxyResolverScriptData> script_data_; + scoped_ptr<ProxyResolverV8>* resolver_out_; // ------------------------------------------------------- // State specific to GET_PROXY_FOR_URL. @@ -295,34 +323,82 @@ AddressList pending_dns_addresses_; }; -ProxyResolverV8Tracing::Job::Job(ProxyResolverV8Tracing* parent) +class ProxyResolverV8Tracing : public ProxyResolver, + public base::NonThreadSafe { + public: + // Constructs a ProxyResolver that will issue DNS requests through + // |job_params->host_resolver|, forward Javascript errors through + // |error_observer|, and log Javascript errors and alerts to + // |job_params->net_log|. When the LoadState for a request changes, + // |job_params->on_load_state_changed| will be invoked with the RequestHandle + // for that request with the new LoadState. + // + // Note that the constructor takes ownership of |error_observer|, whereas + // |job_params->host_resolver| and |job_params->net_log| are expected to + // outlive |this|. + ProxyResolverV8Tracing(scoped_ptr<ProxyResolverErrorObserver> error_observer, + scoped_ptr<base::Thread> thread, + scoped_ptr<ProxyResolverV8> resolver, + scoped_ptr<Job::Params> job_params); + + ~ProxyResolverV8Tracing() override; + + // ProxyResolver implementation: + int GetProxyForURL(const GURL& url, + ProxyInfo* results, + const CompletionCallback& callback, + RequestHandle* request, + const BoundNetLog& net_log) override; + void CancelRequest(RequestHandle request) override; + LoadState GetLoadState(RequestHandle request) const override; + void CancelSetPacScript() override; + int SetPacScript(const scoped_refptr<ProxyResolverScriptData>& script_data, + const CompletionCallback& callback) override; + + private: + // The worker thread on which the ProxyResolverV8 will be run. + scoped_ptr<base::Thread> thread_; + scoped_ptr<ProxyResolverV8> v8_resolver_; + + scoped_ptr<ProxyResolverErrorObserver> error_observer_; + + scoped_ptr<Job::Params> job_params_; + + // The number of outstanding (non-cancelled) jobs. + int num_outstanding_callbacks_; + + DISALLOW_COPY_AND_ASSIGN(ProxyResolverV8Tracing); +}; + +Job::Job(const Job::Params* params) : origin_runner_(base::ThreadTaskRunnerHandle::Get()), - parent_(parent), + params_(params), event_(true, false), last_num_dns_(0), pending_dns_(NULL) { CheckIsOnOriginThread(); } -void ProxyResolverV8Tracing::Job::StartSetPacScript( +void Job::StartCreateV8Resolver( const scoped_refptr<ProxyResolverScriptData>& script_data, + scoped_ptr<ProxyResolverV8>* resolver, const CompletionCallback& callback) { CheckIsOnOriginThread(); + resolver_out_ = resolver; script_data_ = script_data; // Script initialization uses blocking DNS since there isn't any // advantage to using non-blocking mode here. That is because the // parent ProxyService can't submit any ProxyResolve requests until // initialization has completed successfully! - Start(SET_PAC_SCRIPT, true /*blocking*/, callback); + Start(CREATE_V8_RESOLVER, true /*blocking*/, callback); } -void ProxyResolverV8Tracing::Job::StartGetProxyForURL( - const GURL& url, - ProxyInfo* results, - const BoundNetLog& net_log, - const CompletionCallback& callback) { +void Job::StartGetProxyForURL(const GURL& url, + ProxyInfo* results, + const BoundNetLog& net_log, + const CompletionCallback& callback) { CheckIsOnOriginThread(); url_ = url; @@ -332,7 +408,7 @@ Start(GET_PROXY_FOR_URL, false /*non-blocking*/, callback); } -void ProxyResolverV8Tracing::Job::Cancel() { +void Job::Cancel() { CheckIsOnOriginThread(); // There are several possibilities to consider for cancellation: @@ -367,7 +443,7 @@ owned_self_reference_ = NULL; } -LoadState ProxyResolverV8Tracing::Job::GetLoadState() const { +LoadState Job::GetLoadState() const { CheckIsOnOriginThread(); if (pending_dns_) @@ -376,66 +452,65 @@ return LOAD_STATE_RESOLVING_PROXY_FOR_URL; } -ProxyResolverV8Tracing::Job::~Job() { +Job::~Job() { DCHECK(!pending_dns_); DCHECK(callback_.is_null()); } -void ProxyResolverV8Tracing::Job::CheckIsOnWorkerThread() const { - DCHECK_EQ(base::MessageLoop::current(), parent_->thread_->message_loop()); +void Job::CheckIsOnWorkerThread() const { + DCHECK(params_->worker_task_runner->BelongsToCurrentThread()); } -void ProxyResolverV8Tracing::Job::CheckIsOnOriginThread() const { +void Job::CheckIsOnOriginThread() const { DCHECK(origin_runner_->BelongsToCurrentThread()); } -void ProxyResolverV8Tracing::Job::SetCallback( - const CompletionCallback& callback) { +void Job::SetCallback(const CompletionCallback& callback) { CheckIsOnOriginThread(); DCHECK(callback_.is_null()); - parent_->num_outstanding_callbacks_++; + (*params_->num_outstanding_callbacks)++; callback_ = callback; } -void ProxyResolverV8Tracing::Job::ReleaseCallback() { +void Job::ReleaseCallback() { CheckIsOnOriginThread(); DCHECK(!callback_.is_null()); - CHECK_GT(parent_->num_outstanding_callbacks_, 0); - parent_->num_outstanding_callbacks_--; + CHECK_GT(*params_->num_outstanding_callbacks, 0); + (*params_->num_outstanding_callbacks)--; callback_.Reset(); // For good measure, clear this other user-owned pointer. user_results_ = NULL; } -ProxyResolverV8* ProxyResolverV8Tracing::Job::v8_resolver() { - return parent_->v8_resolver_.get(); +ProxyResolverV8* Job::v8_resolver() { + return params_->v8_resolver; } -base::MessageLoop* ProxyResolverV8Tracing::Job::worker_loop() { - return parent_->thread_->message_loop(); +const scoped_refptr<base::SingleThreadTaskRunner>& Job::worker_task_runner() { + return params_->worker_task_runner; } -HostResolver* ProxyResolverV8Tracing::Job::host_resolver() { - return parent_->host_resolver_; +HostResolver* Job::host_resolver() { + return params_->host_resolver; } -ProxyResolverErrorObserver* ProxyResolverV8Tracing::Job::error_observer() { - return parent_->error_observer_.get(); +ProxyResolverErrorObserver* Job::error_observer() { + return params_->error_observer; } -NetLog* ProxyResolverV8Tracing::Job::net_log() { - return parent_->net_log_; +NetLog* Job::net_log() { + return params_->net_log; } -void ProxyResolverV8Tracing::Job::NotifyCaller(int result) { +void Job::NotifyCaller(int result) { CheckIsOnWorkerThread(); origin_runner_->PostTask( FROM_HERE, base::Bind(&Job::NotifyCallerOnOriginLoop, this, result)); } -void ProxyResolverV8Tracing::Job::NotifyCallerOnOriginLoop(int result) { +void Job::NotifyCallerOnOriginLoop(int result) { CheckIsOnOriginThread(); if (cancelled_.IsSet()) @@ -448,13 +523,6 @@ *user_results_ = results_; } - // There is only ever 1 outstanding SET_PAC_SCRIPT job. It needs to be - // tracked to support cancellation. - if (operation_ == SET_PAC_SCRIPT) { - DCHECK_EQ(parent_->set_pac_script_job_.get(), this); - parent_->set_pac_script_job_ = NULL; - } - CompletionCallback callback = callback_; ReleaseCallback(); callback.Run(result); @@ -462,8 +530,9 @@ owned_self_reference_ = NULL; } -void ProxyResolverV8Tracing::Job::Start(Operation op, bool blocking_dns, - const CompletionCallback& callback) { +void Job::Start(Operation op, + bool blocking_dns, + const CompletionCallback& callback) { CheckIsOnOriginThread(); operation_ = op; @@ -472,12 +541,12 @@ owned_self_reference_ = this; - worker_loop()->PostTask(FROM_HERE, - blocking_dns_ ? base::Bind(&Job::ExecuteBlocking, this) : - base::Bind(&Job::ExecuteNonBlocking, this)); + worker_task_runner()->PostTask( + FROM_HERE, blocking_dns_ ? base::Bind(&Job::ExecuteBlocking, this) + : base::Bind(&Job::ExecuteNonBlocking, this)); } -void ProxyResolverV8Tracing::Job::ExecuteBlocking() { +void Job::ExecuteBlocking() { CheckIsOnWorkerThread(); DCHECK(blocking_dns_); @@ -487,7 +556,7 @@ NotifyCaller(ExecuteProxyResolver()); } -void ProxyResolverV8Tracing::Job::ExecuteNonBlocking() { +void Job::ExecuteNonBlocking() { CheckIsOnWorkerThread(); DCHECK(!blocking_dns_); @@ -518,18 +587,23 @@ NotifyCaller(result); } -int ProxyResolverV8Tracing::Job::ExecuteProxyResolver() { - JSBindings* prev_bindings = v8_resolver()->js_bindings(); - v8_resolver()->set_js_bindings(this); - +int Job::ExecuteProxyResolver() { int result = ERR_UNEXPECTED; // Initialized to silence warnings. switch (operation_) { - case SET_PAC_SCRIPT: - result = v8_resolver()->SetPacScript( - script_data_, CompletionCallback()); + case CREATE_V8_RESOLVER: { + scoped_ptr<ProxyResolverV8> resolver(new ProxyResolverV8); + resolver->set_js_bindings(this); + result = resolver->SetPacScript(script_data_, CompletionCallback()); + resolver->set_js_bindings(nullptr); + if (result == OK) + *resolver_out_ = resolver.Pass(); break; - case GET_PROXY_FOR_URL: + } + case GET_PROXY_FOR_URL: { + JSBindings* prev_bindings = v8_resolver()->js_bindings(); + v8_resolver()->set_js_bindings(this); + result = v8_resolver()->GetProxyForURL( url_, // Important: Do not write directly into |user_results_|, since if the @@ -539,18 +613,18 @@ CompletionCallback(), NULL, bound_net_log_); + v8_resolver()->set_js_bindings(prev_bindings); break; + } } - v8_resolver()->set_js_bindings(prev_bindings); - return result; } -bool ProxyResolverV8Tracing::Job::ResolveDns(const std::string& host, - ResolveDnsOperation op, - std::string* output, - bool* terminate) { +bool Job::ResolveDns(const std::string& host, + ResolveDnsOperation op, + std::string* output, + bool* terminate) { if (cancelled_.IsSet()) { *terminate = true; return false; @@ -566,18 +640,17 @@ ResolveDnsNonBlocking(host, op, output, terminate); } -void ProxyResolverV8Tracing::Job::Alert(const base::string16& message) { +void Job::Alert(const base::string16& message) { HandleAlertOrError(true, -1, message); } -void ProxyResolverV8Tracing::Job::OnError(int line_number, - const base::string16& error) { +void Job::OnError(int line_number, const base::string16& error) { HandleAlertOrError(false, line_number, error); } -bool ProxyResolverV8Tracing::Job::ResolveDnsBlocking(const std::string& host, - ResolveDnsOperation op, - std::string* output) { +bool Job::ResolveDnsBlocking(const std::string& host, + ResolveDnsOperation op, + std::string* output) { CheckIsOnWorkerThread(); // Check if the DNS result for this host has already been cached. @@ -601,10 +674,10 @@ return rv; } -bool ProxyResolverV8Tracing::Job::ResolveDnsNonBlocking(const std::string& host, - ResolveDnsOperation op, - std::string* output, - bool* terminate) { +bool Job::ResolveDnsNonBlocking(const std::string& host, + ResolveDnsOperation op, + std::string* output, + bool* terminate) { CheckIsOnWorkerThread(); if (abandoned_) { @@ -654,10 +727,9 @@ return false; } -bool ProxyResolverV8Tracing::Job::PostDnsOperationAndWait( - const std::string& host, ResolveDnsOperation op, - bool* completed_synchronously) { - +bool Job::PostDnsOperationAndWait(const std::string& host, + ResolveDnsOperation op, + bool* completed_synchronously) { // Post the DNS request to the origin thread. DCHECK(!pending_dns_); pending_dns_host_ = host; @@ -676,7 +748,7 @@ return true; } -void ProxyResolverV8Tracing::Job::DoDnsOperation() { +void Job::DoDnsOperation() { CheckIsOnOriginThread(); DCHECK(!pending_dns_); @@ -708,8 +780,8 @@ } else { DCHECK(dns_request); pending_dns_ = dns_request; - if (!parent_->on_load_state_changed_.is_null()) { - parent_->on_load_state_changed_.Run( + if (!params_->on_load_state_changed.is_null()) { + params_->on_load_state_changed.Run( this, LOAD_STATE_RESOLVING_HOST_IN_PROXY_SCRIPT); } // OnDnsOperationComplete() will be called by host resolver on completion. @@ -722,7 +794,7 @@ } } -void ProxyResolverV8Tracing::Job::OnDnsOperationComplete(int result) { +void Job::OnDnsOperationComplete(int result) { CheckIsOnOriginThread(); DCHECK(!cancelled_.IsSet()); @@ -732,10 +804,10 @@ pending_dns_addresses_); pending_dns_ = NULL; - if (!parent_->on_load_state_changed_.is_null() && + if (!params_->on_load_state_changed.is_null() && !pending_dns_completed_synchronously_ && !cancelled_.IsSet()) { - parent_->on_load_state_changed_.Run(this, - LOAD_STATE_RESOLVING_PROXY_FOR_URL); + params_->on_load_state_changed.Run(this, + LOAD_STATE_RESOLVING_PROXY_FOR_URL); } if (blocking_dns_) { @@ -746,12 +818,12 @@ if (!blocking_dns_ && !pending_dns_completed_synchronously_) { // Restart. This time it should make more progress due to having // cached items. - worker_loop()->PostTask(FROM_HERE, - base::Bind(&Job::ExecuteNonBlocking, this)); + worker_task_runner()->PostTask(FROM_HERE, + base::Bind(&Job::ExecuteNonBlocking, this)); } } -void ProxyResolverV8Tracing::Job::ScheduleRestartWithBlockingDns() { +void Job::ScheduleRestartWithBlockingDns() { CheckIsOnWorkerThread(); DCHECK(!should_restart_with_blocking_dns_); @@ -764,11 +836,10 @@ should_restart_with_blocking_dns_ = true; } -bool ProxyResolverV8Tracing::Job::GetDnsFromLocalCache( - const std::string& host, - ResolveDnsOperation op, - std::string* output, - bool* return_value) { +bool Job::GetDnsFromLocalCache(const std::string& host, + ResolveDnsOperation op, + std::string* output, + bool* return_value) { CheckIsOnWorkerThread(); DnsCache::const_iterator it = dns_cache_.find(MakeDnsCacheKey(host, op)); @@ -780,11 +851,10 @@ return true; } -void ProxyResolverV8Tracing::Job::SaveDnsToLocalCache( - const std::string& host, - ResolveDnsOperation op, - int net_error, - const AddressList& addresses) { +void Job::SaveDnsToLocalCache(const std::string& host, + ResolveDnsOperation op, + int net_error, + const AddressList& addresses) { CheckIsOnOriginThread(); // Serialize the result into a string to save to the cache. @@ -809,8 +879,8 @@ } // static -HostResolver::RequestInfo ProxyResolverV8Tracing::Job::MakeDnsRequestInfo( - const std::string& host, ResolveDnsOperation op) { +HostResolver::RequestInfo Job::MakeDnsRequestInfo(const std::string& host, + ResolveDnsOperation op) { HostPortPair host_port = HostPortPair(host, 80); if (op == MY_IP_ADDRESS || op == MY_IP_ADDRESS_EX) { host_port.set_host(GetHostName()); @@ -831,15 +901,14 @@ return info; } -std::string ProxyResolverV8Tracing::Job::MakeDnsCacheKey( - const std::string& host, ResolveDnsOperation op) { +std::string Job::MakeDnsCacheKey(const std::string& host, + ResolveDnsOperation op) { return base::StringPrintf("%d:%s", op, host.c_str()); } -void ProxyResolverV8Tracing::Job::HandleAlertOrError( - bool is_alert, - int line_number, - const base::string16& message) { +void Job::HandleAlertOrError(bool is_alert, + int line_number, + const base::string16& message) { CheckIsOnWorkerThread(); if (cancelled_.IsSet()) @@ -871,7 +940,7 @@ alerts_and_errors_.push_back(entry); } -void ProxyResolverV8Tracing::Job::DispatchBufferedAlertsAndErrors() { +void Job::DispatchBufferedAlertsAndErrors() { CheckIsOnWorkerThread(); DCHECK(!blocking_dns_); DCHECK(!abandoned_); @@ -882,8 +951,9 @@ } } -void ProxyResolverV8Tracing::Job::DispatchAlertOrError( - bool is_alert, int line_number, const base::string16& message) { +void Job::DispatchAlertOrError(bool is_alert, + int line_number, + const base::string16& message) { CheckIsOnWorkerThread(); // Note that the handling of cancellation is racy with regard to @@ -925,7 +995,7 @@ } } -void ProxyResolverV8Tracing::Job::LogEventToCurrentRequestAndGlobally( +void Job::LogEventToCurrentRequestAndGlobally( NetLog::EventType type, const NetLog::ParametersCallback& parameters_callback) { CheckIsOnWorkerThread(); @@ -937,46 +1007,26 @@ } ProxyResolverV8Tracing::ProxyResolverV8Tracing( - HostResolver* host_resolver, - ProxyResolverErrorObserver* error_observer, - NetLog* net_log) - : ProxyResolverV8Tracing(host_resolver, - error_observer, - net_log, - LoadStateChangedCallback()) { -} - -ProxyResolverV8Tracing::ProxyResolverV8Tracing( - HostResolver* host_resolver, - ProxyResolverErrorObserver* error_observer, - NetLog* net_log, - const LoadStateChangedCallback& on_load_state_changed) + scoped_ptr<ProxyResolverErrorObserver> error_observer, + scoped_ptr<base::Thread> thread, + scoped_ptr<ProxyResolverV8> resolver, + scoped_ptr<Job::Params> job_params) : ProxyResolver(true /*expects_pac_bytes*/), - host_resolver_(host_resolver), - error_observer_(error_observer), - net_log_(net_log), - num_outstanding_callbacks_(0), - on_load_state_changed_(on_load_state_changed) { - DCHECK(host_resolver); - // Start up the thread. - thread_.reset(new base::Thread("Proxy resolver")); - base::Thread::Options options; - options.timer_slack = base::TIMER_SLACK_MAXIMUM; - CHECK(thread_->StartWithOptions(options)); - - v8_resolver_.reset(new ProxyResolverV8); + thread_(thread.Pass()), + v8_resolver_(resolver.Pass()), + error_observer_(error_observer.Pass()), + job_params_(job_params.Pass()), + num_outstanding_callbacks_(0) { + job_params_->num_outstanding_callbacks = &num_outstanding_callbacks_; } ProxyResolverV8Tracing::~ProxyResolverV8Tracing() { // Note, all requests should have been cancelled. - CHECK(!set_pac_script_job_.get()); CHECK_EQ(0, num_outstanding_callbacks_); - // Join the worker thread. See http://crbug.com/69710. Note that we call - // Stop() here instead of simply clearing thread_ since there may be pending - // callbacks on the worker thread which want to dereference thread_. + // Join the worker thread. See http://crbug.com/69710. base::ThreadRestrictions::ScopedAllowIO allow_io; - thread_->Stop(); + thread_.reset(); } int ProxyResolverV8Tracing::GetProxyForURL(const GURL& url, @@ -986,9 +1036,8 @@ const BoundNetLog& net_log) { DCHECK(CalledOnValidThread()); DCHECK(!callback.is_null()); - DCHECK(!set_pac_script_job_.get()); - scoped_refptr<Job> job = new Job(this); + scoped_refptr<Job> job = new Job(job_params_.get()); if (request) *request = job.get(); @@ -1008,27 +1057,144 @@ } void ProxyResolverV8Tracing::CancelSetPacScript() { - DCHECK(set_pac_script_job_.get()); - set_pac_script_job_->Cancel(); - set_pac_script_job_ = NULL; + NOTREACHED(); } int ProxyResolverV8Tracing::SetPacScript( const scoped_refptr<ProxyResolverScriptData>& script_data, const CompletionCallback& callback) { - DCHECK(CalledOnValidThread()); - DCHECK(!callback.is_null()); + NOTREACHED(); + return ERR_NOT_IMPLEMENTED; +} - // Note that there should not be any outstanding (non-cancelled) Jobs when - // setting the PAC script (ProxyService should guarantee this). If there are, - // then they might complete in strange ways after the new script is set. - DCHECK(!set_pac_script_job_.get()); - CHECK_EQ(0, num_outstanding_callbacks_); +} // namespace - set_pac_script_job_ = new Job(this); - set_pac_script_job_->StartSetPacScript(script_data, callback); +class ProxyResolverFactoryV8Tracing::CreateJob + : public ProxyResolverFactory::Request { + public: + CreateJob(ProxyResolverFactoryV8Tracing* factory, + HostResolver* host_resolver, + scoped_ptr<ProxyResolverErrorObserver> error_observer, + NetLog* net_log, + const ProxyResolver::LoadStateChangedCallback& + load_state_changed_callback, + const scoped_refptr<ProxyResolverScriptData>& pac_script, + scoped_ptr<ProxyResolver>* resolver_out, + const CompletionCallback& callback) + : factory_(factory), + thread_(new base::Thread("Proxy Resolver")), + error_observer_(error_observer.Pass()), + resolver_out_(resolver_out), + callback_(callback), + num_outstanding_callbacks_(0) { + // Start up the thread. + base::Thread::Options options; + options.timer_slack = base::TIMER_SLACK_MAXIMUM; + CHECK(thread_->StartWithOptions(options)); + job_params_.reset(new Job::Params( + thread_->task_runner(), host_resolver, error_observer_.get(), net_log, + load_state_changed_callback, &num_outstanding_callbacks_)); + create_resolver_job_ = new Job(job_params_.get()); + create_resolver_job_->StartCreateV8Resolver( + pac_script, &v8_resolver_, + base::Bind( + &ProxyResolverFactoryV8Tracing::CreateJob::OnV8ResolverCreated, + base::Unretained(this))); + } + ~CreateJob() override { + if (factory_) { + factory_->RemoveJob(this); + DCHECK(create_resolver_job_); + create_resolver_job_->Cancel(); + StopWorkerThread(); + } + DCHECK_EQ(0, num_outstanding_callbacks_); + } + + void FactoryDestroyed() { + factory_ = nullptr; + create_resolver_job_->Cancel(); + create_resolver_job_ = nullptr; + StopWorkerThread(); + } + + private: + void OnV8ResolverCreated(int error) { + DCHECK(factory_); + if (error == OK) { + job_params_->v8_resolver = v8_resolver_.get(); + resolver_out_->reset( + new ProxyResolverV8Tracing(error_observer_.Pass(), thread_.Pass(), + v8_resolver_.Pass(), job_params_.Pass())); + } else { + StopWorkerThread(); + } + + factory_->RemoveJob(this); + factory_ = nullptr; + create_resolver_job_ = nullptr; + callback_.Run(error); + } + + void StopWorkerThread() { + // Join the worker thread. See http://crbug.com/69710. + base::ThreadRestrictions::ScopedAllowIO allow_io; + thread_.reset(); + } + + ProxyResolverFactoryV8Tracing* factory_; + scoped_ptr<base::Thread> thread_; + scoped_ptr<ProxyResolverErrorObserver> error_observer_; + scoped_ptr<Job::Params> job_params_; + scoped_refptr<Job> create_resolver_job_; + scoped_ptr<ProxyResolverV8> v8_resolver_; + scoped_ptr<ProxyResolver>* resolver_out_; + const CompletionCallback callback_; + int num_outstanding_callbacks_; + + DISALLOW_COPY_AND_ASSIGN(CreateJob); +}; + +ProxyResolverFactoryV8Tracing::ProxyResolverFactoryV8Tracing( + HostResolver* host_resolver, + NetLog* net_log, + const ProxyResolver::LoadStateChangedCallback& callback, + const base::Callback<scoped_ptr<ProxyResolverErrorObserver>()>& + error_observer_factory) + : ProxyResolverFactory(true), + host_resolver_(host_resolver), + net_log_(net_log), + load_state_changed_callback_(callback), + error_observer_factory_(error_observer_factory) { +} + +ProxyResolverFactoryV8Tracing::~ProxyResolverFactoryV8Tracing() { + for (auto job : jobs_) { + job->FactoryDestroyed(); + } +} + +// ProxyResolverFactory override. +int ProxyResolverFactoryV8Tracing::CreateProxyResolver( + const scoped_refptr<ProxyResolverScriptData>& pac_script, + scoped_ptr<ProxyResolver>* resolver, + const CompletionCallback& callback, + scoped_ptr<Request>* request) { + scoped_ptr<CreateJob> job(new CreateJob( + this, host_resolver_, + error_observer_factory_.is_null() ? nullptr + : error_observer_factory_.Run(), + net_log_, load_state_changed_callback_, pac_script, resolver, callback)); + jobs_.insert(job.get()); + *request = job.Pass(); return ERR_IO_PENDING; } +void ProxyResolverFactoryV8Tracing::RemoveJob( + ProxyResolverFactoryV8Tracing::CreateJob* job) { + size_t erased = jobs_.erase(job); + DCHECK_EQ(1u, erased); +} + } // namespace net
diff --git a/net/proxy/proxy_resolver_v8_tracing.h b/net/proxy/proxy_resolver_v8_tracing.h index 48afd47..c2a9de5 100644 --- a/net/proxy/proxy_resolver_v8_tracing.h +++ b/net/proxy/proxy_resolver_v8_tracing.h
@@ -5,93 +5,62 @@ #ifndef NET_PROXY_PROXY_RESOLVER_V8_TRACING_H_ #define NET_PROXY_PROXY_RESOLVER_V8_TRACING_H_ +#include <set> + #include "base/basictypes.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" -#include "base/threading/non_thread_safe.h" #include "net/base/net_export.h" #include "net/proxy/proxy_resolver.h" - -namespace base { -class Thread; -class SingleThreadTaskRunner; -} // namespace base +#include "net/proxy/proxy_resolver_factory.h" namespace net { class HostResolver; class NetLog; class ProxyResolverErrorObserver; -class ProxyResolverV8; -// ProxyResolverV8Tracing is a non-blocking ProxyResolver. It executes +// ProxyResolverFactoryV8Tracing is a ProxyResolverFactory that returns +// non-blocking ProxyResolver instances. Each ProxyResolver instance executes // ProxyResolverV8 on a single helper thread, and does some magic to avoid // blocking in DNS. For more details see the design document: // https://docs.google.com/a/google.com/document/d/16Ij5OcVnR3s0MH4Z5XkhI9VTPoMJdaBn9rKreAmGOdE/edit?pli=1 -class NET_EXPORT_PRIVATE ProxyResolverV8Tracing - : public ProxyResolver, - NON_EXPORTED_BASE(public base::NonThreadSafe) { +class NET_EXPORT ProxyResolverFactoryV8Tracing : public ProxyResolverFactory { public: - // Constructs a ProxyResolver that will issue DNS requests through - // |host_resolver|, forward Javascript errors through |error_observer|, and - // log Javascript errors and alerts to |net_log|. - // - // Note that the constructor takes ownership of |error_observer|, whereas - // |host_resolver| and |net_log| are expected to outlive |this|. - ProxyResolverV8Tracing(HostResolver* host_resolver, - ProxyResolverErrorObserver* error_observer, - NetLog* net_log); + // Note that |host_resolver| and |net_log| are expected to outlive |this| and + // any ProxyResolver instances created using |this|. |error_observer_factory| + // will be invoked once per CreateProxyResolver() call to create a + // ProxyResolverErrorObserver to be used by the ProxyResolver instance + // returned by that call. + ProxyResolverFactoryV8Tracing( + HostResolver* host_resolver, + NetLog* net_log, + const ProxyResolver::LoadStateChangedCallback& callback, + const base::Callback<scoped_ptr<ProxyResolverErrorObserver>()>& + error_observer_factory); + ~ProxyResolverFactoryV8Tracing() override; - // Constructs a ProxyResolver that will issue DNS requests through - // |host_resolver|, forward Javascript errors through |error_observer|, and - // log Javascript errors and alerts to |net_log|. When the LoadState for a - // request changes, |on_load_state_changed| will be invoked with the - // RequestHandle for that request with the new LoadState. - // - // Note that the constructor takes ownership of |error_observer|, whereas - // |host_resolver| and |net_log| are expected to outlive |this|. - ProxyResolverV8Tracing(HostResolver* host_resolver, - ProxyResolverErrorObserver* error_observer, - NetLog* net_log, - const LoadStateChangedCallback& on_load_state_changed); - - ~ProxyResolverV8Tracing() override; - - // ProxyResolver implementation: - int GetProxyForURL(const GURL& url, - ProxyInfo* results, - const CompletionCallback& callback, - RequestHandle* request, - const BoundNetLog& net_log) override; - void CancelRequest(RequestHandle request) override; - LoadState GetLoadState(RequestHandle request) const override; - void CancelSetPacScript() override; - int SetPacScript(const scoped_refptr<ProxyResolverScriptData>& script_data, - const CompletionCallback& callback) override; + // ProxyResolverFactory override. + int CreateProxyResolver( + const scoped_refptr<ProxyResolverScriptData>& pac_script, + scoped_ptr<ProxyResolver>* resolver, + const CompletionCallback& callback, + scoped_ptr<Request>* request) override; private: - class Job; + class CreateJob; - // The worker thread on which the ProxyResolverV8 will be run. - scoped_ptr<base::Thread> thread_; - scoped_ptr<ProxyResolverV8> v8_resolver_; + void RemoveJob(CreateJob* job); - // Non-owned host resolver, which is to be operated on the origin thread. - HostResolver* host_resolver_; + HostResolver* const host_resolver_; + NetLog* const net_log_; + const ProxyResolver::LoadStateChangedCallback load_state_changed_callback_; + const base::Callback<scoped_ptr<ProxyResolverErrorObserver>()> + error_observer_factory_; - scoped_ptr<ProxyResolverErrorObserver> error_observer_; - NetLog* net_log_; + std::set<CreateJob*> jobs_; - // The outstanding SetPacScript operation, or NULL. - scoped_refptr<Job> set_pac_script_job_; - - // The number of outstanding (non-cancelled) jobs. - int num_outstanding_callbacks_; - - // Invoked when the load state for a request changes. - const LoadStateChangedCallback on_load_state_changed_; - - DISALLOW_COPY_AND_ASSIGN(ProxyResolverV8Tracing); + DISALLOW_COPY_AND_ASSIGN(ProxyResolverFactoryV8Tracing); }; } // namespace net
diff --git a/net/proxy/proxy_resolver_v8_tracing_unittest.cc b/net/proxy/proxy_resolver_v8_tracing_unittest.cc index f52b1d4..296853c 100644 --- a/net/proxy/proxy_resolver_v8_tracing_unittest.cc +++ b/net/proxy/proxy_resolver_v8_tracing_unittest.cc
@@ -4,6 +4,8 @@ #include "net/proxy/proxy_resolver_v8_tracing.h" +#include <string> + #include "base/files/file_util.h" #include "base/message_loop/message_loop.h" #include "base/path_service.h" @@ -60,12 +62,28 @@ return ProxyResolverScriptData::FromUTF8(file_contents); } -void InitResolver(ProxyResolverV8Tracing* resolver, const char* filename) { +scoped_ptr<ProxyResolverErrorObserver> ReturnErrorObserver( + scoped_ptr<ProxyResolverErrorObserver> error_observer) { + return error_observer; +} + +scoped_ptr<ProxyResolver> CreateResolver( + NetLog* net_log, + HostResolver* host_resolver, + scoped_ptr<ProxyResolverErrorObserver> error_observer, + const char* filename) { + scoped_ptr<ProxyResolver> resolver; + ProxyResolverFactoryV8Tracing factory( + host_resolver, net_log, ProxyResolver::LoadStateChangedCallback(), + base::Bind(&ReturnErrorObserver, base::Passed(&error_observer))); TestCompletionCallback callback; - int rv = - resolver->SetPacScript(LoadScriptData(filename), callback.callback()); + scoped_ptr<ProxyResolverFactory::Request> request; + int rv = factory.CreateProxyResolver(LoadScriptData(filename), &resolver, + callback.callback(), &request); EXPECT_EQ(ERR_IO_PENDING, rv); EXPECT_EQ(OK, callback.WaitForResult()); + EXPECT_TRUE(resolver); + return resolver.Pass(); } class MockErrorObserver : public ProxyResolverErrorObserver { @@ -102,16 +120,16 @@ BoundTestNetLog request_log; MockCachingHostResolver host_resolver; MockErrorObserver* error_observer = new MockErrorObserver; - ProxyResolverV8Tracing resolver(&host_resolver, error_observer, &log); - InitResolver(&resolver, "simple.js"); + scoped_ptr<ProxyResolver> resolver = CreateResolver( + &log, &host_resolver, make_scoped_ptr(error_observer), "simple.js"); TestCompletionCallback callback; ProxyInfo proxy_info; - int rv = resolver.GetProxyForURL( - GURL("http://foo/"), &proxy_info, callback.callback(), - NULL, request_log.bound()); + int rv = + resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info, + callback.callback(), NULL, request_log.bound()); EXPECT_EQ(ERR_IO_PENDING, rv); EXPECT_EQ(OK, callback.WaitForResult()); @@ -133,16 +151,16 @@ BoundTestNetLog request_log; MockCachingHostResolver host_resolver; MockErrorObserver* error_observer = new MockErrorObserver; - ProxyResolverV8Tracing resolver(&host_resolver, error_observer, &log); - InitResolver(&resolver, "error.js"); + scoped_ptr<ProxyResolver> resolver = CreateResolver( + &log, &host_resolver, make_scoped_ptr(error_observer), "error.js"); TestCompletionCallback callback; ProxyInfo proxy_info; - int rv = resolver.GetProxyForURL( - GURL("http://throw-an-error/"), &proxy_info, callback.callback(), NULL, - request_log.bound()); + int rv = + resolver->GetProxyForURL(GURL("http://throw-an-error/"), &proxy_info, + callback.callback(), NULL, request_log.bound()); EXPECT_EQ(ERR_IO_PENDING, rv); EXPECT_EQ(ERR_PAC_SCRIPT_FAILED, callback.WaitForResult()); @@ -179,19 +197,17 @@ BoundTestNetLog request_log; MockCachingHostResolver host_resolver; MockErrorObserver* error_observer = new MockErrorObserver; - ProxyResolverV8Tracing resolver(&host_resolver, error_observer, &log); - InitResolver(&resolver, "too_many_alerts.js"); + scoped_ptr<ProxyResolver> resolver = + CreateResolver(&log, &host_resolver, make_scoped_ptr(error_observer), + "too_many_alerts.js"); TestCompletionCallback callback; ProxyInfo proxy_info; - int rv = resolver.GetProxyForURL( - GURL("http://foo/"), - &proxy_info, - callback.callback(), - NULL, - request_log.bound()); + int rv = + resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info, + callback.callback(), NULL, request_log.bound()); EXPECT_EQ(ERR_IO_PENDING, rv); EXPECT_EQ(OK, callback.WaitForResult()); @@ -230,19 +246,17 @@ BoundTestNetLog request_log; MockCachingHostResolver host_resolver; MockErrorObserver* error_observer = new MockErrorObserver; - ProxyResolverV8Tracing resolver(&host_resolver, error_observer, &log); - InitResolver(&resolver, "too_many_empty_alerts.js"); + scoped_ptr<ProxyResolver> resolver = + CreateResolver(&log, &host_resolver, make_scoped_ptr(error_observer), + "too_many_empty_alerts.js"); TestCompletionCallback callback; ProxyInfo proxy_info; - int rv = resolver.GetProxyForURL( - GURL("http://foo/"), - &proxy_info, - callback.callback(), - NULL, - request_log.bound()); + int rv = + resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info, + callback.callback(), NULL, request_log.bound()); EXPECT_EQ(ERR_IO_PENDING, rv); EXPECT_EQ(OK, callback.WaitForResult()); @@ -279,7 +293,6 @@ BoundTestNetLog request_log; MockCachingHostResolver host_resolver; MockErrorObserver* error_observer = new MockErrorObserver; - ProxyResolverV8Tracing resolver(&host_resolver, error_observer, &log); host_resolver.rules()->AddRuleForAddressFamily( "host1", ADDRESS_FAMILY_IPV4, "166.155.144.44"); @@ -293,17 +306,15 @@ "*", ADDRESS_FAMILY_IPV4, "122.133.144.155"); host_resolver.rules()->AddRule("*", "133.122.100.200"); - InitResolver(&resolver, "dns.js"); + scoped_ptr<ProxyResolver> resolver = CreateResolver( + &log, &host_resolver, make_scoped_ptr(error_observer), "dns.js"); TestCompletionCallback callback; ProxyInfo proxy_info; - int rv = resolver.GetProxyForURL( - GURL("http://foo/"), - &proxy_info, - callback.callback(), - NULL, - request_log.bound()); + int rv = + resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info, + callback.callback(), NULL, request_log.bound()); EXPECT_EQ(ERR_IO_PENDING, rv); EXPECT_EQ(OK, callback.WaitForResult()); @@ -356,23 +367,20 @@ BoundTestNetLog request_log; MockCachingHostResolver host_resolver; MockErrorObserver* error_observer = new MockErrorObserver; - ProxyResolverV8Tracing resolver(&host_resolver, error_observer, &log); host_resolver.rules()->AddRule("foopy", "166.155.144.11"); host_resolver.rules()->AddRule("*", "122.133.144.155"); - InitResolver(&resolver, "simple_dns.js"); + scoped_ptr<ProxyResolver> resolver = CreateResolver( + &log, &host_resolver, make_scoped_ptr(error_observer), "simple_dns.js"); TestCompletionCallback callback1; TestCompletionCallback callback2; ProxyInfo proxy_info; - int rv = resolver.GetProxyForURL( - GURL("http://foopy/req1"), - &proxy_info, - callback1.callback(), - NULL, - request_log.bound()); + int rv = + resolver->GetProxyForURL(GURL("http://foopy/req1"), &proxy_info, + callback1.callback(), NULL, request_log.bound()); EXPECT_EQ(ERR_IO_PENDING, rv); EXPECT_EQ(OK, callback1.WaitForResult()); @@ -383,12 +391,9 @@ // The first request took 2 restarts, hence on g_iteration=3. EXPECT_EQ("166.155.144.11:3", proxy_info.proxy_server().ToURI()); - rv = resolver.GetProxyForURL( - GURL("http://foopy/req2"), - &proxy_info, - callback2.callback(), - NULL, - request_log.bound()); + rv = + resolver->GetProxyForURL(GURL("http://foopy/req2"), &proxy_info, + callback2.callback(), NULL, request_log.bound()); EXPECT_EQ(ERR_IO_PENDING, rv); EXPECT_EQ(OK, callback2.WaitForResult()); @@ -413,20 +418,21 @@ BoundTestNetLog request_log; MockCachingHostResolver host_resolver; MockErrorObserver* error_observer = new MockErrorObserver; - ProxyResolverV8Tracing resolver(&host_resolver, error_observer, &log); host_resolver.rules()->AddRule("host1", "166.155.144.11"); host_resolver.rules()->AddRule("crazy4", "133.199.111.4"); host_resolver.rules()->AddRule("*", "122.133.144.155"); - InitResolver(&resolver, "global_sideffects1.js"); + scoped_ptr<ProxyResolver> resolver = + CreateResolver(&log, &host_resolver, make_scoped_ptr(error_observer), + "global_sideffects1.js"); TestCompletionCallback callback; ProxyInfo proxy_info; - int rv = resolver.GetProxyForURL( - GURL("http://foo/"), &proxy_info, callback.callback(), NULL, - request_log.bound()); + int rv = + resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info, + callback.callback(), NULL, request_log.bound()); EXPECT_EQ(ERR_IO_PENDING, rv); EXPECT_EQ(OK, callback.WaitForResult()); @@ -465,7 +471,6 @@ BoundTestNetLog request_log; MockCachingHostResolver host_resolver; MockErrorObserver* error_observer = new MockErrorObserver; - ProxyResolverV8Tracing resolver(&host_resolver, error_observer, &log); host_resolver.rules()->AddRule("host1", "166.155.144.11"); host_resolver.rules()->AddRule("host2", "166.155.144.22"); @@ -473,14 +478,16 @@ host_resolver.rules()->AddRule("host4", "166.155.144.44"); host_resolver.rules()->AddRule("*", "122.133.144.155"); - InitResolver(&resolver, "global_sideffects2.js"); + scoped_ptr<ProxyResolver> resolver = + CreateResolver(&log, &host_resolver, make_scoped_ptr(error_observer), + "global_sideffects2.js"); TestCompletionCallback callback; ProxyInfo proxy_info; - int rv = resolver.GetProxyForURL( - GURL("http://foo/"), &proxy_info, callback.callback(), NULL, - request_log.bound()); + int rv = + resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info, + callback.callback(), NULL, request_log.bound()); EXPECT_EQ(ERR_IO_PENDING, rv); EXPECT_EQ(OK, callback.WaitForResult()); @@ -505,19 +512,20 @@ BoundTestNetLog request_log; MockCachingHostResolver host_resolver; MockErrorObserver* error_observer = new MockErrorObserver; - ProxyResolverV8Tracing resolver(&host_resolver, error_observer, &log); host_resolver.rules()->AddRule("host*", "166.155.144.11"); host_resolver.rules()->AddRule("*", "122.133.144.155"); - InitResolver(&resolver, "global_sideffects3.js"); + scoped_ptr<ProxyResolver> resolver = + CreateResolver(&log, &host_resolver, make_scoped_ptr(error_observer), + "global_sideffects3.js"); TestCompletionCallback callback; ProxyInfo proxy_info; - int rv = resolver.GetProxyForURL( - GURL("http://foo/"), &proxy_info, callback.callback(), NULL, - request_log.bound()); + int rv = + resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info, + callback.callback(), NULL, request_log.bound()); EXPECT_EQ(ERR_IO_PENDING, rv); EXPECT_EQ(OK, callback.WaitForResult()); @@ -548,19 +556,20 @@ BoundTestNetLog request_log; MockCachingHostResolver host_resolver; MockErrorObserver* error_observer = new MockErrorObserver; - ProxyResolverV8Tracing resolver(&host_resolver, error_observer, &log); host_resolver.rules()->AddRule("host*", "166.155.144.11"); host_resolver.rules()->AddRule("*", "122.133.144.155"); - InitResolver(&resolver, "global_sideffects4.js"); + scoped_ptr<ProxyResolver> resolver = + CreateResolver(&log, &host_resolver, make_scoped_ptr(error_observer), + "global_sideffects4.js"); TestCompletionCallback callback; ProxyInfo proxy_info; - int rv = resolver.GetProxyForURL( - GURL("http://foo/"), &proxy_info, callback.callback(), NULL, - request_log.bound()); + int rv = + resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info, + callback.callback(), NULL, request_log.bound()); EXPECT_EQ(ERR_IO_PENDING, rv); EXPECT_EQ(OK, callback.WaitForResult()); @@ -582,12 +591,13 @@ MockCachingHostResolver host_resolver; host_resolver.set_synchronous_mode(synchronous_host_resolver); MockErrorObserver* error_observer = new MockErrorObserver; - ProxyResolverV8Tracing resolver(&host_resolver, error_observer, &log); host_resolver.rules()->AddRule("host1", "91.13.12.1"); host_resolver.rules()->AddRule("host2", "91.13.12.2"); - InitResolver(&resolver, "dns_during_init.js"); + scoped_ptr<ProxyResolver> resolver = + CreateResolver(&log, &host_resolver, make_scoped_ptr(error_observer), + "dns_during_init.js"); // Initialization did 2 dnsResolves. EXPECT_EQ(2u, host_resolver.num_resolve()); @@ -601,9 +611,9 @@ TestCompletionCallback callback; ProxyInfo proxy_info; - int rv = resolver.GetProxyForURL( - GURL("http://foo/"), &proxy_info, callback.callback(), NULL, - request_log.bound()); + int rv = + resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info, + callback.callback(), NULL, request_log.bound()); EXPECT_EQ(ERR_IO_PENDING, rv); EXPECT_EQ(OK, callback.WaitForResult()); @@ -651,25 +661,25 @@ TEST_F(ProxyResolverV8TracingTest, CancelAll) { MockCachingHostResolver host_resolver; MockErrorObserver* error_observer = new MockErrorObserver; - ProxyResolverV8Tracing resolver(&host_resolver, error_observer, NULL); host_resolver.rules()->AddSimulatedFailure("*"); - InitResolver(&resolver, "dns.js"); + scoped_ptr<ProxyResolver> resolver = CreateResolver( + nullptr, &host_resolver, make_scoped_ptr(error_observer), "dns.js"); const size_t kNumRequests = 5; ProxyInfo proxy_info[kNumRequests]; ProxyResolver::RequestHandle request[kNumRequests]; for (size_t i = 0; i < kNumRequests; ++i) { - int rv = resolver.GetProxyForURL( - GURL("http://foo/"), &proxy_info[i], - base::Bind(&CrashCallback), &request[i], BoundNetLog()); + int rv = resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info[i], + base::Bind(&CrashCallback), &request[i], + BoundNetLog()); EXPECT_EQ(ERR_IO_PENDING, rv); } for (size_t i = 0; i < kNumRequests; ++i) { - resolver.CancelRequest(request[i]); + resolver->CancelRequest(request[i]); } } @@ -679,11 +689,11 @@ TEST_F(ProxyResolverV8TracingTest, CancelSome) { MockCachingHostResolver host_resolver; MockErrorObserver* error_observer = new MockErrorObserver; - ProxyResolverV8Tracing resolver(&host_resolver, error_observer, NULL); host_resolver.rules()->AddSimulatedFailure("*"); - InitResolver(&resolver, "dns.js"); + scoped_ptr<ProxyResolver> resolver = CreateResolver( + nullptr, &host_resolver, make_scoped_ptr(error_observer), "dns.js"); ProxyInfo proxy_info1; ProxyInfo proxy_info2; @@ -691,17 +701,16 @@ ProxyResolver::RequestHandle request2; TestCompletionCallback callback; - int rv = resolver.GetProxyForURL( - GURL("http://foo/"), &proxy_info1, - base::Bind(&CrashCallback), &request1, BoundNetLog()); + int rv = resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info1, + base::Bind(&CrashCallback), &request1, + BoundNetLog()); EXPECT_EQ(ERR_IO_PENDING, rv); - rv = resolver.GetProxyForURL( - GURL("http://foo/"), &proxy_info2, - callback.callback(), &request2, BoundNetLog()); + rv = resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info2, + callback.callback(), &request2, BoundNetLog()); EXPECT_EQ(ERR_IO_PENDING, rv); - resolver.CancelRequest(request1); + resolver->CancelRequest(request1); EXPECT_EQ(OK, callback.WaitForResult()); } @@ -711,11 +720,11 @@ TEST_F(ProxyResolverV8TracingTest, CancelWhilePendingCompletionTask) { MockCachingHostResolver host_resolver; MockErrorObserver* error_observer = new MockErrorObserver; - ProxyResolverV8Tracing resolver(&host_resolver, error_observer, NULL); host_resolver.rules()->AddSimulatedFailure("*"); - InitResolver(&resolver, "error.js"); + scoped_ptr<ProxyResolver> resolver = CreateResolver( + nullptr, &host_resolver, make_scoped_ptr(error_observer), "error.js"); ProxyInfo proxy_info1; ProxyInfo proxy_info2; @@ -725,14 +734,13 @@ ProxyResolver::RequestHandle request3; TestCompletionCallback callback; - int rv = resolver.GetProxyForURL( - GURL("http://foo/"), &proxy_info1, - base::Bind(&CrashCallback), &request1, BoundNetLog()); + int rv = resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info1, + base::Bind(&CrashCallback), &request1, + BoundNetLog()); EXPECT_EQ(ERR_IO_PENDING, rv); - rv = resolver.GetProxyForURL( - GURL("http://throw-an-error/"), &proxy_info2, - callback.callback(), &request2, BoundNetLog()); + rv = resolver->GetProxyForURL(GURL("http://throw-an-error/"), &proxy_info2, + callback.callback(), &request2, BoundNetLog()); EXPECT_EQ(ERR_IO_PENDING, rv); // Wait until the first request has finished running on the worker thread. @@ -741,14 +749,14 @@ // Cancel the first request, while it has a pending completion task on // the origin thread. - resolver.CancelRequest(request1); + resolver->CancelRequest(request1); EXPECT_EQ(ERR_PAC_SCRIPT_FAILED, callback.WaitForResult()); // Start another request, to make sure it is able to complete. - rv = resolver.GetProxyForURL( - GURL("http://i-have-no-idea-what-im-doing/"), &proxy_info3, - callback.callback(), &request3, BoundNetLog()); + rv = resolver->GetProxyForURL(GURL("http://i-have-no-idea-what-im-doing/"), + &proxy_info3, callback.callback(), &request3, + BoundNetLog()); EXPECT_EQ(ERR_IO_PENDING, rv); EXPECT_EQ(OK, callback.WaitForResult()); @@ -829,33 +837,33 @@ TEST_F(ProxyResolverV8TracingTest, CancelWhileOutstandingNonBlockingDns) { BlockableHostResolver host_resolver; MockErrorObserver* error_observer = new MockErrorObserver; - ProxyResolverV8Tracing resolver(&host_resolver, error_observer, NULL); - InitResolver(&resolver, "dns.js"); + scoped_ptr<ProxyResolver> resolver = CreateResolver( + nullptr, &host_resolver, make_scoped_ptr(error_observer), "dns.js"); ProxyInfo proxy_info1; ProxyInfo proxy_info2; ProxyResolver::RequestHandle request1; ProxyResolver::RequestHandle request2; - int rv = resolver.GetProxyForURL( - GURL("http://foo/req1"), &proxy_info1, - base::Bind(&CrashCallback), &request1, BoundNetLog()); + int rv = resolver->GetProxyForURL(GURL("http://foo/req1"), &proxy_info1, + base::Bind(&CrashCallback), &request1, + BoundNetLog()); EXPECT_EQ(ERR_IO_PENDING, rv); host_resolver.WaitUntilRequestIsReceived(); - rv = resolver.GetProxyForURL( - GURL("http://foo/req2"), &proxy_info2, - base::Bind(&CrashCallback), &request2, BoundNetLog()); + rv = resolver->GetProxyForURL(GURL("http://foo/req2"), &proxy_info2, + base::Bind(&CrashCallback), &request2, + BoundNetLog()); EXPECT_EQ(ERR_IO_PENDING, rv); host_resolver.WaitUntilRequestIsReceived(); - resolver.CancelRequest(request1); - resolver.CancelRequest(request2); + resolver->CancelRequest(request1); + resolver->CancelRequest(request2); EXPECT_EQ(2, host_resolver.num_cancelled_requests()); @@ -864,7 +872,7 @@ // should have been cancelled. } -void CancelRequestAndPause(ProxyResolverV8Tracing* resolver, +void CancelRequestAndPause(ProxyResolver* resolver, ProxyResolver::RequestHandle request) { resolver->CancelRequest(request); @@ -880,21 +888,21 @@ TEST_F(ProxyResolverV8TracingTest, CancelWhileBlockedInNonBlockingDns) { BlockableHostResolver host_resolver; MockErrorObserver* error_observer = new MockErrorObserver; - ProxyResolverV8Tracing resolver(&host_resolver, error_observer, NULL); - InitResolver(&resolver, "dns.js"); + scoped_ptr<ProxyResolver> resolver = CreateResolver( + nullptr, &host_resolver, make_scoped_ptr(error_observer), "dns.js"); ProxyInfo proxy_info; ProxyResolver::RequestHandle request; - int rv = resolver.GetProxyForURL( - GURL("http://foo/"), &proxy_info, - base::Bind(&CrashCallback), &request, BoundNetLog()); + int rv = resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info, + base::Bind(&CrashCallback), &request, + BoundNetLog()); EXPECT_EQ(ERR_IO_PENDING, rv); host_resolver.SetAction( - base::Bind(CancelRequestAndPause, &resolver, request)); + base::Bind(CancelRequestAndPause, resolver.get(), request)); host_resolver.WaitUntilRequestIsReceived(); @@ -909,16 +917,16 @@ TEST_F(ProxyResolverV8TracingTest, CancelWhileBlockedInNonBlockingDns2) { MockCachingHostResolver host_resolver; MockErrorObserver* error_observer = new MockErrorObserver; - ProxyResolverV8Tracing resolver(&host_resolver, error_observer, NULL); - InitResolver(&resolver, "dns.js"); + scoped_ptr<ProxyResolver> resolver = CreateResolver( + nullptr, &host_resolver, make_scoped_ptr(error_observer), "dns.js"); ProxyInfo proxy_info; ProxyResolver::RequestHandle request; - int rv = resolver.GetProxyForURL( - GURL("http://foo/"), &proxy_info, - base::Bind(&CrashCallback), &request, BoundNetLog()); + int rv = resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info, + base::Bind(&CrashCallback), &request, + BoundNetLog()); EXPECT_EQ(ERR_IO_PENDING, rv); @@ -926,28 +934,75 @@ // work whatever the delay is here, but it is most useful if the delay // is large enough to allow a task to be posted back. base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(10)); - resolver.CancelRequest(request); + resolver->CancelRequest(request); EXPECT_EQ(0u, host_resolver.num_resolve()); } -TEST_F(ProxyResolverV8TracingTest, CancelSetPacWhileOutstandingBlockingDns) { +TEST_F(ProxyResolverV8TracingTest, + CancelCreateResolverWhileOutstandingBlockingDns) { BlockableHostResolver host_resolver; MockErrorObserver* error_observer = new MockErrorObserver; - ProxyResolverV8Tracing resolver(&host_resolver, error_observer, NULL); + ProxyResolverFactoryV8Tracing factory( + &host_resolver, nullptr, ProxyResolver::LoadStateChangedCallback(), + base::Bind(&ReturnErrorObserver, + base::Passed(make_scoped_ptr(error_observer)))); - int rv = - resolver.SetPacScript(LoadScriptData("dns_during_init.js"), - base::Bind(&CrashCallback)); + scoped_ptr<ProxyResolver> resolver; + scoped_ptr<ProxyResolverFactory::Request> request; + int rv = factory.CreateProxyResolver(LoadScriptData("dns_during_init.js"), + &resolver, base::Bind(&CrashCallback), + &request); EXPECT_EQ(ERR_IO_PENDING, rv); host_resolver.WaitUntilRequestIsReceived(); - resolver.CancelSetPacScript(); + request.reset(); EXPECT_EQ(1, host_resolver.num_cancelled_requests()); } +TEST_F(ProxyResolverV8TracingTest, DeleteFactoryWhileOutstandingBlockingDns) { + BlockableHostResolver host_resolver; + MockErrorObserver* error_observer = new MockErrorObserver; + + scoped_ptr<ProxyResolver> resolver; + scoped_ptr<ProxyResolverFactory::Request> request; + { + ProxyResolverFactoryV8Tracing factory( + &host_resolver, nullptr, ProxyResolver::LoadStateChangedCallback(), + base::Bind(&ReturnErrorObserver, + base::Passed(make_scoped_ptr(error_observer)))); + + int rv = factory.CreateProxyResolver(LoadScriptData("dns_during_init.js"), + &resolver, base::Bind(&CrashCallback), + &request); + EXPECT_EQ(ERR_IO_PENDING, rv); + host_resolver.WaitUntilRequestIsReceived(); + } + EXPECT_EQ(1, host_resolver.num_cancelled_requests()); +} + +TEST_F(ProxyResolverV8TracingTest, ErrorLoadingScript) { + BlockableHostResolver host_resolver; + MockErrorObserver* error_observer = new MockErrorObserver; + + ProxyResolverFactoryV8Tracing factory( + &host_resolver, nullptr, ProxyResolver::LoadStateChangedCallback(), + base::Bind(&ReturnErrorObserver, + base::Passed(make_scoped_ptr(error_observer)))); + + scoped_ptr<ProxyResolver> resolver; + scoped_ptr<ProxyResolverFactory::Request> request; + TestCompletionCallback callback; + int rv = + factory.CreateProxyResolver(LoadScriptData("error_on_load.js"), &resolver, + callback.callback(), &request); + EXPECT_EQ(ERR_IO_PENDING, rv); + EXPECT_EQ(ERR_PAC_SCRIPT_FAILED, callback.WaitForResult()); + EXPECT_FALSE(resolver); +} + // This tests that the execution of a PAC script is terminated when the DNS // dependencies are missing. If the test fails, then it will hang. TEST_F(ProxyResolverV8TracingTest, Terminate) { @@ -955,22 +1010,19 @@ BoundTestNetLog request_log; MockCachingHostResolver host_resolver; MockErrorObserver* error_observer = new MockErrorObserver; - ProxyResolverV8Tracing resolver(&host_resolver, error_observer, &log); host_resolver.rules()->AddRule("host1", "182.111.0.222"); host_resolver.rules()->AddRule("host2", "111.33.44.55"); - InitResolver(&resolver, "terminate.js"); + scoped_ptr<ProxyResolver> resolver = CreateResolver( + &log, &host_resolver, make_scoped_ptr(error_observer), "terminate.js"); TestCompletionCallback callback; ProxyInfo proxy_info; - int rv = resolver.GetProxyForURL( - GURL("http://foopy/req1"), - &proxy_info, - callback.callback(), - NULL, - request_log.bound()); + int rv = + resolver->GetProxyForURL(GURL("http://foopy/req1"), &proxy_info, + callback.callback(), NULL, request_log.bound()); EXPECT_EQ(ERR_IO_PENDING, rv); EXPECT_EQ(OK, callback.WaitForResult()); @@ -1007,39 +1059,39 @@ host_resolver0.rules()->AddRuleForAddressFamily( "*", ADDRESS_FAMILY_IPV4, "122.133.144.155"); host_resolver0.rules()->AddRule("*", "133.122.100.200"); - ProxyResolverV8Tracing resolver0( - &host_resolver0, new MockErrorObserver, NULL); - InitResolver(&resolver0, "dns.js"); + scoped_ptr<ProxyResolver> resolver0 = + CreateResolver(nullptr, &host_resolver0, + make_scoped_ptr(new MockErrorObserver), "dns.js"); // ------------------------ // Setup resolver1 // ------------------------ - ProxyResolverV8Tracing resolver1( - &host_resolver0, new MockErrorObserver, NULL); - InitResolver(&resolver1, "dns.js"); + scoped_ptr<ProxyResolver> resolver1 = + CreateResolver(nullptr, &host_resolver0, + make_scoped_ptr(new MockErrorObserver), "dns.js"); // ------------------------ // Setup resolver2 // ------------------------ - ProxyResolverV8Tracing resolver2( - &host_resolver0, new MockErrorObserver, NULL); - InitResolver(&resolver2, "simple.js"); + scoped_ptr<ProxyResolver> resolver2 = + CreateResolver(nullptr, &host_resolver0, + make_scoped_ptr(new MockErrorObserver), "simple.js"); // ------------------------ // Setup resolver3 // ------------------------ MockHostResolver host_resolver3; host_resolver3.rules()->AddRule("foo", "166.155.144.33"); - ProxyResolverV8Tracing resolver3( - &host_resolver3, new MockErrorObserver, NULL); - InitResolver(&resolver3, "simple_dns.js"); + scoped_ptr<ProxyResolver> resolver3 = + CreateResolver(nullptr, &host_resolver3, + make_scoped_ptr(new MockErrorObserver), "simple_dns.js"); // ------------------------ // Queue up work for each resolver (which will be running in parallel). // ------------------------ - ProxyResolverV8Tracing* resolver[] = { - &resolver0, &resolver1, &resolver2, &resolver3, + ProxyResolver* resolver[] = { + resolver0.get(), resolver1.get(), resolver2.get(), resolver3.get(), }; const size_t kNumResolvers = arraysize(resolver);
diff --git a/net/proxy/proxy_service_mojo.cc b/net/proxy/proxy_service_mojo.cc index 86da99a..fe818532 100644 --- a/net/proxy/proxy_service_mojo.cc +++ b/net/proxy/proxy_service_mojo.cc
@@ -5,11 +5,13 @@ #include "net/proxy/proxy_service_mojo.h" #include "base/logging.h" +#include "base/message_loop/message_loop_proxy.h" #include "net/dns/mojo_host_resolver_impl.h" #include "net/interfaces/proxy_resolver_service.mojom.h" #include "net/proxy/in_process_mojo_proxy_resolver_factory.h" #include "net/proxy/mojo_proxy_resolver_factory.h" #include "net/proxy/mojo_proxy_resolver_impl.h" +#include "net/proxy/network_delegate_error_observer.h" #include "net/proxy/proxy_resolver_factory.h" #include "net/proxy/proxy_resolver_mojo.h" #include "net/proxy/proxy_resolver_v8_tracing.h" @@ -31,8 +33,11 @@ DCHECK(host_resolver); ProxyService* proxy_service = new ProxyService( - proxy_config_service, make_scoped_ptr(new ProxyResolverFactoryMojo( - mojo_proxy_factory, host_resolver)), + proxy_config_service, + make_scoped_ptr(new ProxyResolverFactoryMojo( + mojo_proxy_factory, host_resolver, + base::Bind(&NetworkDelegateErrorObserver::Create, network_delegate, + base::MessageLoopProxy::current()))), net_log); // Configure fetchers to use for PAC script downloads and auto-detect.
diff --git a/net/proxy/proxy_service_mojo_unittest.cc b/net/proxy/proxy_service_mojo_unittest.cc index 5caf2a5..334bafa 100644 --- a/net/proxy/proxy_service_mojo_unittest.cc +++ b/net/proxy/proxy_service_mojo_unittest.cc
@@ -8,7 +8,9 @@ #include "base/callback_helpers.h" #include "base/memory/scoped_ptr.h" +#include "base/strings/utf_string_conversions.h" #include "net/base/load_flags.h" +#include "net/base/network_delegate_impl.h" #include "net/base/test_completion_callback.h" #include "net/dns/mock_host_resolver.h" #include "net/log/net_log.h" @@ -18,6 +20,7 @@ #include "net/proxy/mojo_proxy_resolver_factory.h" #include "net/proxy/proxy_config_service_fixed.h" #include "net/proxy/proxy_service.h" +#include "net/test/event_waiter.h" #include "testing/gtest/include/gtest/gtest.h" #include "url/gurl.h" @@ -36,6 +39,31 @@ " return 'DIRECT';\n" " return 'QUIC bar:4321';\n" "}"; +const char kErrorPacScript[] = + "function FindProxyForURL(url, host) {\n" + " throw new Error('test error');\n" + "}"; + +class TestNetworkDelegate : public NetworkDelegateImpl { + public: + enum Event { + PAC_SCRIPT_ERROR, + }; + + EventWaiter<Event>& event_waiter() { return event_waiter_; } + + void OnPACScriptError(int line_number, const base::string16& error) override; + + private: + EventWaiter<Event> event_waiter_; +}; + +void TestNetworkDelegate::OnPACScriptError(int line_number, + const base::string16& error) { + event_waiter_.NotifyEvent(PAC_SCRIPT_ERROR); + EXPECT_EQ(2, line_number); + EXPECT_TRUE(base::UTF16ToUTF8(error).find("test error") != std::string::npos); +} } // namespace @@ -50,20 +78,23 @@ this, new ProxyConfigServiceFixed( ProxyConfig::CreateFromCustomPacURL(GURL(kPacUrl))), fetcher_, new DoNothingDhcpProxyScriptFetcher(), &mock_host_resolver_, - nullptr /* NetLog* */, nullptr /* NetworkDelegate* */)); + nullptr /* NetLog* */, &network_delegate_)); } scoped_ptr<base::ScopedClosureRunner> CreateResolver( const mojo::String& pac_script, mojo::InterfaceRequest<interfaces::ProxyResolver> req, interfaces::HostResolverPtr host_resolver, + interfaces::ProxyResolverErrorObserverPtr error_observer, interfaces::ProxyResolverFactoryRequestClientPtr client) override { InProcessMojoProxyResolverFactory::GetInstance()->CreateResolver( - pac_script, req.Pass(), host_resolver.Pass(), client.Pass()); + pac_script, req.Pass(), host_resolver.Pass(), error_observer.Pass(), + client.Pass()); return make_scoped_ptr( new base::ScopedClosureRunner(on_delete_closure_.closure())); } + TestNetworkDelegate network_delegate_; MockHostResolver mock_host_resolver_; MockProxyScriptFetcher* fetcher_; // Owned by |proxy_service_|. scoped_ptr<ProxyService> proxy_service_; @@ -112,4 +143,22 @@ on_delete_closure_.WaitForResult(); } +TEST_F(ProxyServiceMojoTest, Error) { + ProxyInfo info; + TestCompletionCallback callback; + EXPECT_EQ(ERR_IO_PENDING, + proxy_service_->ResolveProxy(GURL("http://foo"), LOAD_NORMAL, &info, + callback.callback(), nullptr, nullptr, + BoundNetLog())); + + // Proxy script fetcher should have a fetch triggered by the first + // |ResolveProxy()| request. + EXPECT_TRUE(fetcher_->has_pending_request()); + EXPECT_EQ(GURL(kPacUrl), fetcher_->pending_request_url()); + fetcher_->NotifyFetchCompletion(OK, kErrorPacScript); + + network_delegate_.event_waiter().WaitForEvent( + TestNetworkDelegate::PAC_SCRIPT_ERROR); +} + } // namespace net
diff --git a/net/proxy/proxy_service_v8.cc b/net/proxy/proxy_service_v8.cc index 60916771..3634613 100644 --- a/net/proxy/proxy_service_v8.cc +++ b/net/proxy/proxy_service_v8.cc
@@ -14,38 +14,6 @@ #include "net/proxy/proxy_service.h" namespace net { -namespace { - -class ProxyResolverFactoryForV8Resolver : public LegacyProxyResolverFactory { - public: - explicit ProxyResolverFactoryForV8Resolver(HostResolver* host_resolver, - NetLog* net_log, - NetworkDelegate* network_delegate) - : LegacyProxyResolverFactory(true), - host_resolver_(host_resolver), - net_log_(net_log), - network_delegate_(network_delegate) {} - - // LegacyProxyResolverFactory override. - scoped_ptr<ProxyResolver> CreateProxyResolver() override { - DCHECK(thread_checker_.CalledOnValidThread()); - ProxyResolverErrorObserver* error_observer = - new NetworkDelegateErrorObserver( - network_delegate_, base::ThreadTaskRunnerHandle::Get().get()); - return make_scoped_ptr( - new ProxyResolverV8Tracing(host_resolver_, error_observer, net_log_)); - } - - private: - HostResolver* const host_resolver_; - NetLog* const net_log_; - NetworkDelegate* const network_delegate_; - - base::ThreadChecker thread_checker_; - - DISALLOW_COPY_AND_ASSIGN(ProxyResolverFactoryForV8Resolver); -}; -} // namespace // static ProxyService* CreateProxyServiceUsingV8ProxyResolver( @@ -60,11 +28,13 @@ DCHECK(dhcp_proxy_script_fetcher); DCHECK(host_resolver); - ProxyService* proxy_service = - new ProxyService(proxy_config_service, - make_scoped_ptr(new ProxyResolverFactoryForV8Resolver( - host_resolver, net_log, network_delegate)), - net_log); + ProxyService* proxy_service = new ProxyService( + proxy_config_service, + make_scoped_ptr(new ProxyResolverFactoryV8Tracing( + host_resolver, net_log, ProxyResolver::LoadStateChangedCallback(), + base::Bind(&NetworkDelegateErrorObserver::Create, network_delegate, + base::ThreadTaskRunnerHandle::Get()))), + net_log); // Configure fetchers to use for PAC script downloads and auto-detect. proxy_service->SetProxyScriptFetchers(proxy_script_fetcher,
diff --git a/net/quic/congestion_control/send_algorithm_interface.cc b/net/quic/congestion_control/send_algorithm_interface.cc index bc3ee8f..77d8900 100644 --- a/net/quic/congestion_control/send_algorithm_interface.cc +++ b/net/quic/congestion_control/send_algorithm_interface.cc
@@ -21,10 +21,8 @@ QuicConnectionStats* stats, QuicPacketCount initial_congestion_window) { const QuicPacketCount max_congestion_window = - FLAGS_quic_limit_max_cwnd_to_receive_buffer - ? (kDefaultSocketReceiveBuffer * kUsableRecieveBufferFraction) / - kDefaultTCPMSS - : kMaxTcpCongestionWindow; + (kDefaultSocketReceiveBuffer * kUsableRecieveBufferFraction) / + kDefaultTCPMSS; switch (congestion_control_type) { case kCubic: return new TcpCubicSender(clock, rtt_stats, false /* don't use Reno */,
diff --git a/net/quic/crypto/crypto_protocol.h b/net/quic/crypto/crypto_protocol.h index 2f1cb37..1f881ea 100644 --- a/net/quic/crypto/crypto_protocol.h +++ b/net/quic/crypto/crypto_protocol.h
@@ -57,7 +57,6 @@ const QuicTag kRENO = TAG('R', 'E', 'N', 'O'); // Reno Congestion Control const QuicTag kBYTE = TAG('B', 'Y', 'T', 'E'); // TCP cubic or reno in bytes const QuicTag kIW10 = TAG('I', 'W', '1', '0'); // Force ICWND to 10 -const QuicTag kPACE = TAG('P', 'A', 'C', 'E'); // Enable pacing const QuicTag k1CON = TAG('1', 'C', 'O', 'N'); // Emulate a single connection const QuicTag kNTLP = TAG('N', 'T', 'L', 'P'); // No tail loss probe const QuicTag kNCON = TAG('N', 'C', 'O', 'N'); // N Connection Congestion Ctrl
diff --git a/net/quic/crypto/quic_crypto_client_config.cc b/net/quic/crypto/quic_crypto_client_config.cc index eef97433..a95c0f0 100644 --- a/net/quic/crypto/quic_crypto_client_config.cc +++ b/net/quic/crypto/quic_crypto_client_config.cc
@@ -727,7 +727,7 @@ return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND; } cached->add_server_designated_connection_id(connection_id); - return QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT; + return QUIC_NO_ERROR; } return QUIC_NO_ERROR;
diff --git a/net/quic/crypto/quic_crypto_client_config.h b/net/quic/crypto/quic_crypto_client_config.h index 1fddafa..a65f007 100644 --- a/net/quic/crypto/quic_crypto_client_config.h +++ b/net/quic/crypto/quic_crypto_client_config.h
@@ -221,9 +221,7 @@ // about a future handshake (i.e. an nonce value from the server), then it // will be saved in |out_params|. |now| is used to judge whether the server // config in the rejection message has expired. |is_https| is used to track - // reject reason for secure vs insecure QUIC. If the rejection message - // indicates that the reject is a stateless-reject, returns error code - // QUIC_CRYPTO_HANDSHAKE_RECEIVED_STATELESS_REJECT. + // reject reason for secure vs insecure QUIC. QuicErrorCode ProcessRejection(const CryptoHandshakeMessage& rej, QuicWallTime now, CachedState* cached,
diff --git a/net/quic/crypto/quic_crypto_client_config_test.cc b/net/quic/crypto/quic_crypto_client_config_test.cc index bf3a343..348f8f9 100644 --- a/net/quic/crypto/quic_crypto_client_config_test.cc +++ b/net/quic/crypto/quic_crypto_client_config_test.cc
@@ -370,11 +370,10 @@ QuicCryptoNegotiatedParameters out_params; string error; QuicCryptoClientConfig config; - EXPECT_EQ( - QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT, - config.ProcessRejection(rej, QuicWallTime::FromUNIXSeconds(0), &cached, - true, // is_https - &out_params, &error)); + EXPECT_EQ(QUIC_NO_ERROR, config.ProcessRejection( + rej, QuicWallTime::FromUNIXSeconds(0), &cached, + true, // is_https + &out_params, &error)); EXPECT_TRUE(cached.has_server_designated_connection_id()); EXPECT_EQ(kConnectionId, cached.GetNextServerDesignatedConnectionId()); }
diff --git a/net/quic/quic_connection.cc b/net/quic/quic_connection.cc index 08fc9026..12f9290 100644 --- a/net/quic/quic_connection.cc +++ b/net/quic/quic_connection.cc
@@ -907,36 +907,59 @@ if (!last_stream_frames_.empty()) { visitor_->OnStreamFrames(last_stream_frames_); + if (!connected_ && !FLAGS_quic_stop_early) { + return; + } } for (size_t i = 0; i < last_stream_frames_.size(); ++i) { stats_.stream_bytes_received += last_stream_frames_[i].data.TotalBufferSize(); } - // Process window updates, blocked, stream resets, acks, then congestion // feedback. if (!last_window_update_frames_.empty()) { visitor_->OnWindowUpdateFrames(last_window_update_frames_); + if (!connected_ && !FLAGS_quic_stop_early) { + return; + } } if (!last_blocked_frames_.empty()) { visitor_->OnBlockedFrames(last_blocked_frames_); + if (!connected_ && !FLAGS_quic_stop_early) { + return; + } } for (size_t i = 0; i < last_goaway_frames_.size(); ++i) { visitor_->OnGoAway(last_goaway_frames_[i]); + if (!connected_ && !FLAGS_quic_stop_early) { + return; + } } for (size_t i = 0; i < last_rst_frames_.size(); ++i) { visitor_->OnRstStream(last_rst_frames_[i]); + if (!connected_ && !FLAGS_quic_stop_early) { + return; + } } for (size_t i = 0; i < last_ack_frames_.size(); ++i) { ProcessAckFrame(last_ack_frames_[i]); + if (!connected_ && !FLAGS_quic_stop_early) { + return; + } } for (size_t i = 0; i < last_stop_waiting_frames_.size(); ++i) { ProcessStopWaitingFrame(last_stop_waiting_frames_[i]); + if (!connected_ && !FLAGS_quic_stop_early) { + return; + } } if (!last_close_frames_.empty()) { CloseConnection(last_close_frames_[0].error_code, true); DCHECK(!connected_); + if (!FLAGS_quic_stop_early) { + return; + } } // If there are new missing packets to report, send an ack immediately. @@ -959,9 +982,8 @@ if (ack_alarm_->IsSet()) { ack_queued_ = true; } else { - // Send an ack much more quickly for crypto handshake packets. - QuicTime::Delta delayed_ack_time = sent_packet_manager_.DelayedAckTime(); - ack_alarm_->Set(clock_->ApproximateNow().Add(delayed_ack_time)); + ack_alarm_->Set( + clock_->ApproximateNow().Add(sent_packet_manager_.DelayedAckTime())); DVLOG(1) << "Ack timer set; next packet or timer will trigger ACK."; } }
diff --git a/net/quic/quic_crypto_client_stream.cc b/net/quic/quic_crypto_client_stream.cc index 28a6db8..f1f0909 100644 --- a/net/quic/quic_crypto_client_stream.cc +++ b/net/quic/quic_crypto_client_stream.cc
@@ -87,7 +87,8 @@ channel_id_source_callback_run_(false), channel_id_source_callback_(nullptr), verify_context_(verify_context), - proof_verify_callback_(nullptr) { + proof_verify_callback_(nullptr), + stateless_reject_received_(false) { DCHECK_EQ(Perspective::IS_CLIENT, session->connection()->perspective()); } @@ -246,6 +247,19 @@ void QuicCryptoClientStream::DoSendCHLO( const CryptoHandshakeMessage* in, QuicCryptoClientConfig::CachedState* cached) { + if (stateless_reject_received_) { + // If we've gotten to this point, we've sent at least one hello + // and received a stateless reject in response. We cannot + // continue to send hellos because the server has abandoned state + // for this connection. Abandon further handshakes. + next_state_ = STATE_NONE; + if (session()->connection()->connected()) { + session()->connection()->CloseConnection( + QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT, false); + } + return; + } + // Send the client hello in plaintext. session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_NONE); if (num_client_hellos_ > kMaxClientHellos) { @@ -255,6 +269,11 @@ num_client_hellos_++; CryptoHandshakeMessage out; + DCHECK(session() != nullptr); + DCHECK(session()->config() != nullptr); + // Send all the options, regardless of whether we're sending an + // inchoate or subsequent hello. + session()->config()->ToHandshakeMessage(&out); if (!cached->IsComplete(session()->connection()->clock()->WallNow())) { crypto_config_->FillInchoateClientHello( server_id_, @@ -282,7 +301,6 @@ return; } - session()->config()->ToHandshakeMessage(&out); string error_details; QuicErrorCode error = crypto_config_->FillClientHello( server_id_, @@ -344,16 +362,18 @@ // perform a handshake, or we sent a full hello that the server // rejected. Here we hope to have a REJ that contains the information // that we need. - if (in->tag() != kREJ) { + if ((in->tag() != kREJ) && (in->tag() != kSREJ)) { next_state_ = STATE_NONE; CloseConnectionWithDetails(QUIC_INVALID_CRYPTO_MESSAGE_TYPE, "Expected REJ"); return; } + stateless_reject_received_ = in->tag() == kSREJ; string error_details; QuicErrorCode error = crypto_config_->ProcessRejection( *in, session()->connection()->clock()->WallNow(), cached, server_id_.is_https(), &crypto_negotiated_params_, &error_details); + if (error != QUIC_NO_ERROR) { next_state_ = STATE_NONE; CloseConnectionWithDetails(error, error_details); @@ -491,9 +511,11 @@ const CryptoHandshakeMessage* in, QuicCryptoClientConfig::CachedState* cached) { next_state_ = STATE_NONE; - // We sent a CHLO that we expected to be accepted and now we're hoping - // for a SHLO from the server to confirm that. - if (in->tag() == kREJ) { + // We sent a CHLO that we expected to be accepted and now we're + // hoping for a SHLO from the server to confirm that. First check + // to see whether the response was a reject, and if so, move on to + // the reject-processing state. + if ((in->tag() == kREJ) || (in->tag() == kSREJ)) { // alternative_decrypter will be nullptr if the original alternative // decrypter latched and became the primary decrypter. That happens // if we received a message encrypted with the INITIAL key.
diff --git a/net/quic/quic_crypto_client_stream.h b/net/quic/quic_crypto_client_stream.h index 230cb94..a60ce780 100644 --- a/net/quic/quic_crypto_client_stream.h +++ b/net/quic/quic_crypto_client_stream.h
@@ -209,6 +209,11 @@ std::string verify_error_details_; scoped_ptr<ProofVerifyDetails> verify_details_; + // True if the server responded to a previous CHLO with a stateless + // reject. Used for book-keeping between the STATE_RECV_REJ, + // STATE_VERIFY_PROOF*, and subsequent STATE_SEND_CHLO state. + bool stateless_reject_received_; + DISALLOW_COPY_AND_ASSIGN(QuicCryptoClientStream); };
diff --git a/net/quic/quic_crypto_client_stream_test.cc b/net/quic/quic_crypto_client_stream_test.cc index 417652d0..de3d68e25 100644 --- a/net/quic/quic_crypto_client_stream_test.cc +++ b/net/quic/quic_crypto_client_stream_test.cc
@@ -200,6 +200,92 @@ stream_->ProcessRawData(data->data(), data->length()); } +class QuicCryptoClientStreamStatelessTest : public ::testing::Test { + public: + QuicCryptoClientStreamStatelessTest() + : server_crypto_config_(QuicCryptoServerConfig::TESTING, + QuicRandom::GetInstance()), + server_id_(kServerHostname, kServerPort, false, PRIVACY_MODE_DISABLED) { + TestClientSession* client_session = nullptr; + QuicCryptoClientStream* client_stream = nullptr; + SetupCryptoClientStreamForTest(server_id_, + /* supports_stateless_rejects= */ true, + QuicTime::Delta::FromSeconds(100000), + &client_crypto_config_, &client_connection_, + &client_session, &client_stream); + CHECK(client_session); + CHECK(client_stream); + client_session_.reset(client_session); + client_stream_.reset(client_stream); + } + + void AdvanceHandshakeWithFakeServer() { + client_stream_->CryptoConnect(); + CryptoTestUtils::AdvanceHandshake(client_connection_, client_stream_.get(), + 0, server_connection_, + server_stream_.get(), 0); + } + + // Initializes the server_stream_ for stateless rejects. + void InitializeFakeStatelessRejectServer() { + TestServerSession* server_session = nullptr; + QuicCryptoServerStream* server_stream = nullptr; + SetupCryptoServerStreamForTest(server_id_, + QuicTime::Delta::FromSeconds(100000), + &server_crypto_config_, &server_connection_, + &server_session, &server_stream); + CHECK(server_session); + CHECK(server_stream); + server_session_.reset(server_session); + server_stream_.reset(server_stream); + CryptoTestUtils::SetupCryptoServerConfigForTest( + server_connection_->clock(), server_connection_->random_generator(), + server_session_->config(), &server_crypto_config_); + server_stream_->set_use_stateless_rejects_if_peer_supported(true); + } + + // Client crypto stream state + PacketSavingConnection* client_connection_; + scoped_ptr<TestClientSession> client_session_; + scoped_ptr<QuicCryptoClientStream> client_stream_; + QuicCryptoClientConfig client_crypto_config_; + + // Server crypto stream state + PacketSavingConnection* server_connection_; + scoped_ptr<TestServerSession> server_session_; + QuicCryptoServerConfig server_crypto_config_; + scoped_ptr<QuicCryptoServerStream> server_stream_; + QuicServerId server_id_; +}; + +TEST_F(QuicCryptoClientStreamStatelessTest, StatelessReject) { + ValueRestore<bool> old_flag(&FLAGS_enable_quic_stateless_reject_support, + true); + + QuicCryptoClientConfig::CachedState* client_state = + client_crypto_config_.LookupOrCreate(server_id_); + + EXPECT_FALSE(client_state->has_server_designated_connection_id()); + EXPECT_CALL(*client_session_, OnProofValid(testing::_)); + + InitializeFakeStatelessRejectServer(); + AdvanceHandshakeWithFakeServer(); + + EXPECT_FALSE(client_stream_->encryption_established()); + EXPECT_FALSE(client_stream_->handshake_confirmed()); + // Even though the handshake was not complete, the cached client_state is + // complete, and can be used for a subsequent successful handshake. + EXPECT_TRUE(client_state->IsComplete(QuicWallTime::FromUNIXSeconds(0))); + + ASSERT_TRUE(client_state->has_server_designated_connection_id()); + QuicConnectionId server_designated_id = + client_state->GetNextServerDesignatedConnectionId(); + QuicConnectionId expected_id = + server_session_->connection()->random_generator()->RandUint64(); + EXPECT_EQ(expected_id, server_designated_id); + EXPECT_FALSE(client_state->has_server_designated_connection_id()); +} + } // namespace } // namespace test } // namespace net
diff --git a/net/quic/quic_crypto_server_stream.cc b/net/quic/quic_crypto_server_stream.cc index 173001d..ec243c6f 100644 --- a/net/quic/quic_crypto_server_stream.cc +++ b/net/quic/quic_crypto_server_stream.cc
@@ -9,8 +9,10 @@ #include "net/quic/crypto/crypto_protocol.h" #include "net/quic/crypto/crypto_utils.h" #include "net/quic/crypto/quic_crypto_server_config.h" +#include "net/quic/crypto/quic_random.h" #include "net/quic/proto/cached_network_parameters.pb.h" #include "net/quic/quic_config.h" +#include "net/quic/quic_flags.h" #include "net/quic/quic_protocol.h" #include "net/quic/quic_session.h" @@ -32,7 +34,9 @@ crypto_config_(crypto_config), validate_client_hello_cb_(nullptr), num_handshake_messages_(0), - num_server_config_update_messages_sent_(0) { + num_server_config_update_messages_sent_(0), + use_stateless_rejects_if_peer_supported_(false), + peer_supports_stateless_rejects_(false) { DCHECK_EQ(Perspective::IS_SERVER, session->connection()->perspective()); } @@ -84,10 +88,14 @@ DCHECK(validate_client_hello_cb_ != nullptr); validate_client_hello_cb_ = nullptr; - string error_details; + if (FLAGS_enable_quic_stateless_reject_support) { + peer_supports_stateless_rejects_ = DoesPeerSupportStatelessRejects(message); + } + CryptoHandshakeMessage reply; - QuicErrorCode error = ProcessClientHello( - message, result, &reply, &error_details); + string error_details; + QuicErrorCode error = + ProcessClientHello(message, result, &reply, &error_details); if (error != QUIC_NO_ERROR) { CloseConnectionWithDetails(error, error_details); @@ -99,7 +107,9 @@ return; } - // If we are returning a SHLO then we accepted the handshake. + // If we are returning a SHLO then we accepted the handshake. Now + // process the negotiated configuration options as part of the + // session config. QuicConfig* config = session()->config(); OverrideQuicConfigDefaults(config); error = config->ProcessPeerHello(message, CLIENT, &error_details); @@ -107,6 +117,7 @@ CloseConnectionWithDetails(error, error_details); return; } + session()->OnConfigNegotiated(); config->ToHandshakeMessage(&reply); @@ -223,14 +234,21 @@ } previous_source_address_tokens_ = result.info.source_address_tokens; + const bool use_stateless_rejects_in_crypto_config = + FLAGS_enable_quic_stateless_reject_support && + use_stateless_rejects_if_peer_supported_ && + peer_supports_stateless_rejects_; QuicConnection* connection = session()->connection(); + const QuicConnectionId server_designated_connection_id = + use_stateless_rejects_in_crypto_config + ? GenerateConnectionIdForReject(connection->connection_id()) + : 0; return crypto_config_->ProcessClientHello( result, connection->connection_id(), connection->self_address().address(), connection->peer_address(), version(), connection->supported_versions(), - /* use_stateless_rejects= */ false, - /* server_designated_connection_id= */ 0, connection->clock(), - connection->random_generator(), &crypto_negotiated_params_, reply, - error_details); + use_stateless_rejects_in_crypto_config, server_designated_connection_id, + connection->clock(), connection->random_generator(), + &crypto_negotiated_params_, reply, error_details); } void QuicCryptoServerStream::OverrideQuicConfigDefaults(QuicConfig* config) { @@ -255,4 +273,29 @@ } } +QuicConnectionId QuicCryptoServerStream::GenerateConnectionIdForReject( + QuicConnectionId connection_id) { + return session()->connection()->random_generator()->RandUint64(); +} + +// TODO(jokulik): Once stateless rejects support is inherent in the version +// number, this function will likely go away entirely. +// static +bool QuicCryptoServerStream::DoesPeerSupportStatelessRejects( + const CryptoHandshakeMessage& message) { + const QuicTag* received_tags; + size_t received_tags_length; + QuicErrorCode error = + message.GetTaglist(kCOPT, &received_tags, &received_tags_length); + if (error != QUIC_NO_ERROR) { + return false; + } + for (size_t i = 0; i < received_tags_length; ++i) { + if (received_tags[i] == kSREJ) { + return true; + } + } + return false; +} + } // namespace net
diff --git a/net/quic/quic_crypto_server_stream.h b/net/quic/quic_crypto_server_stream.h index 7b842ae..27f6f95 100644 --- a/net/quic/quic_crypto_server_stream.h +++ b/net/quic/quic_crypto_server_stream.h
@@ -23,6 +23,7 @@ namespace test { class CryptoTestUtils; +class QuicCryptoServerStreamPeer; } // namespace test // Receives a notification when the server hello (SHLO) has been ACKed by the @@ -84,6 +85,28 @@ const CachedNetworkParameters* previous_cached_network_params() const; + bool use_stateless_rejects_if_peer_supported() const { + return use_stateless_rejects_if_peer_supported_; + } + + // Used by the quic dispatcher to indicate that this crypto server + // stream should use stateless rejects, so long as stateless rejects + // are supported by the client. + void set_use_stateless_rejects_if_peer_supported( + bool use_stateless_rejects_if_peer_supported) { + use_stateless_rejects_if_peer_supported_ = + use_stateless_rejects_if_peer_supported; + } + + bool peer_supports_stateless_rejects() const { + return peer_supports_stateless_rejects_; + } + + void set_peer_supports_stateless_rejects( + bool peer_supports_stateless_rejects) { + peer_supports_stateless_rejects_ = peer_supports_stateless_rejects; + } + protected: virtual QuicErrorCode ProcessClientHello( const CryptoHandshakeMessage& message, @@ -95,8 +118,14 @@ // before going through the parameter negotiation step. virtual void OverrideQuicConfigDefaults(QuicConfig* config); + // Given the current connection_id, generates a new ConnectionId to + // be returned with a stateless reject. + virtual QuicConnectionId GenerateConnectionIdForReject( + QuicConnectionId connection_id); + private: friend class test::CryptoTestUtils; + friend class test::QuicCryptoServerStreamPeer; class ValidateCallback : public ValidateClientHelloResultCallback { public: @@ -121,6 +150,11 @@ const CryptoHandshakeMessage& message, const ValidateClientHelloResultCallback::Result& result); + // Checks the options on the handshake-message to see whether the + // peer supports stateless-rejects. + static bool DoesPeerSupportStatelessRejects( + const CryptoHandshakeMessage& message); + // crypto_config_ contains crypto parameters for the handshake. const QuicCryptoServerConfig* crypto_config_; @@ -144,6 +178,17 @@ // Contains any source address tokens which were present in the CHLO. SourceAddressTokens previous_source_address_tokens_; + // If true, the server should use stateless rejects, so long as the + // client supports them, as indicated by + // peer_supports_stateless_rejects_. + bool use_stateless_rejects_if_peer_supported_; + + // Set to true, once the server has received information from the + // client that it supports stateless reject. + // TODO(jokulik): Remove once client stateless reject support + // becomes the default. + bool peer_supports_stateless_rejects_; + DISALLOW_COPY_AND_ASSIGN(QuicCryptoServerStream); };
diff --git a/net/quic/quic_crypto_server_stream_test.cc b/net/quic/quic_crypto_server_stream_test.cc index 2cc8e293..6874612d 100644 --- a/net/quic/quic_crypto_server_stream_test.cc +++ b/net/quic/quic_crypto_server_stream_test.cc
@@ -18,6 +18,7 @@ #include "net/quic/crypto/quic_encrypter.h" #include "net/quic/crypto/quic_random.h" #include "net/quic/quic_crypto_client_stream.h" +#include "net/quic/quic_flags.h" #include "net/quic/quic_protocol.h" #include "net/quic/quic_session.h" #include "net/quic/test_tools/crypto_test_utils.h" @@ -48,6 +49,15 @@ } }; +class QuicCryptoServerStreamPeer { + public: + static bool DoesPeerSupportStatelessRejects( + const CryptoHandshakeMessage& message) { + return net::QuicCryptoServerStream::DoesPeerSupportStatelessRejects( + message); + } +}; + namespace { const char kServerHostname[] = "test.example.com"; @@ -56,39 +66,65 @@ class QuicCryptoServerStreamTest : public ::testing::TestWithParam<bool> { public: QuicCryptoServerStreamTest() - : connection_(new PacketSavingConnection(Perspective::IS_SERVER)), - session_(connection_, DefaultQuicConfig()), - crypto_config_(QuicCryptoServerConfig::TESTING, - QuicRandom::GetInstance()), - stream_(&crypto_config_, &session_), - strike_register_client_(nullptr) { - session_.SetCryptoStream(&stream_); - // We advance the clock initially because the default time is zero and the - // strike register worries that we've just overflowed a uint32 time. - connection_->AdvanceTime(QuicTime::Delta::FromSeconds(100000)); + : server_crypto_config_(QuicCryptoServerConfig::TESTING, + QuicRandom::GetInstance()), + server_id_(kServerHostname, kServerPort, false, PRIVACY_MODE_DISABLED) { // TODO(wtc): replace this with ProofSourceForTesting() when Chromium has // a working ProofSourceForTesting(). - crypto_config_.SetProofSource(CryptoTestUtils::FakeProofSourceForTesting()); - crypto_config_.set_strike_register_no_startup_period(); + server_crypto_config_.SetProofSource( + CryptoTestUtils::FakeProofSourceForTesting()); + server_crypto_config_.set_strike_register_no_startup_period(); - CryptoTestUtils::SetupCryptoServerConfigForTest( - connection_->clock(), connection_->random_generator(), - session_.config(), &crypto_config_); + InitializeServer(); if (AsyncStrikeRegisterVerification()) { string orbit = - QuicCryptoServerConfigPeer::GetPrimaryOrbit(crypto_config_); + QuicCryptoServerConfigPeer::GetPrimaryOrbit(server_crypto_config_); strike_register_client_ = new DelayedVerifyStrikeRegisterClient( 10000, // strike_register_max_entries - static_cast<uint32>(connection_->clock()->WallNow().ToUNIXSeconds()), + static_cast<uint32>( + server_connection_->clock()->WallNow().ToUNIXSeconds()), 60, // strike_register_window_secs - reinterpret_cast<const uint8 *>(orbit.data()), + reinterpret_cast<const uint8*>(orbit.data()), StrikeRegister::NO_STARTUP_PERIOD_NEEDED); strike_register_client_->StartDelayingVerification(); - crypto_config_.SetStrikeRegisterClient(strike_register_client_); + server_crypto_config_.SetStrikeRegisterClient(strike_register_client_); } } + // Initializes the crypto server stream state for testing. May be + // called multiple times. + void InitializeServer() { + TestServerSession* server_session = nullptr; + QuicCryptoServerStream* server_stream = nullptr; + SetupCryptoServerStreamForTest(server_id_, + QuicTime::Delta::FromSeconds(100000), + &server_crypto_config_, &server_connection_, + &server_session, &server_stream); + CHECK(server_session); + CHECK(server_stream); + server_session_.reset(server_session); + server_stream_.reset(server_stream); + CryptoTestUtils::SetupCryptoServerConfigForTest( + server_connection_->clock(), server_connection_->random_generator(), + server_session_->config(), &server_crypto_config_); + } + + // Initializes a fake client, and all its associated state, for + // testing. May be called multiple times. + void InitializeFakeClient(bool supports_stateless_rejects) { + TestClientSession* client_session = nullptr; + QuicCryptoClientStream* client_stream = nullptr; + SetupCryptoClientStreamForTest(server_id_, supports_stateless_rejects, + QuicTime::Delta::FromSeconds(100000), + &client_crypto_config_, &client_connection_, + &client_session, &client_stream); + CHECK(client_session); + CHECK(client_stream); + client_session_.reset(client_session); + client_stream_.reset(client_stream); + } + bool AsyncStrikeRegisterVerification() { return GetParam(); } @@ -99,16 +135,41 @@ } int CompleteCryptoHandshake() { - return CryptoTestUtils::HandshakeWithFakeClient(connection_, &stream_, - client_options_); + CHECK(server_connection_); + CHECK(server_stream_ != nullptr); + return CryptoTestUtils::HandshakeWithFakeClient( + server_connection_, server_stream_.get(), client_options_); + } + + // Performs a single round of handshake message-exchange between the + // client and server. + void AdvanceHandshakeWithFakeClient() { + CHECK(server_connection_); + CHECK(server_stream_ != nullptr); + CHECK(client_session_ != nullptr); + CHECK(client_stream_ != nullptr); + + EXPECT_CALL(*client_session_, OnProofValid(_)).Times(testing::AnyNumber()); + client_stream_->CryptoConnect(); + CryptoTestUtils::AdvanceHandshake(client_connection_, client_stream_.get(), + 0, server_connection_, + server_stream_.get(), 0); } protected: - PacketSavingConnection* connection_; - TestClientSession session_; - QuicConfig config_; - QuicCryptoServerConfig crypto_config_; - QuicCryptoServerStream stream_; + // Server state + PacketSavingConnection* server_connection_; + scoped_ptr<TestServerSession> server_session_; + QuicCryptoServerConfig server_crypto_config_; + scoped_ptr<QuicCryptoServerStream> server_stream_; + QuicServerId server_id_; + + // Client state + PacketSavingConnection* client_connection_; + QuicCryptoClientConfig client_crypto_config_; + scoped_ptr<TestClientSession> client_session_; + scoped_ptr<QuicCryptoClientStream> client_stream_; + CryptoHandshakeMessage message_; scoped_ptr<QuicData> message_data_; CryptoTestUtils::FakeClientOptions client_options_; @@ -118,8 +179,13 @@ INSTANTIATE_TEST_CASE_P(Tests, QuicCryptoServerStreamTest, testing::Bool()); TEST_P(QuicCryptoServerStreamTest, NotInitiallyConected) { - EXPECT_FALSE(stream_.encryption_established()); - EXPECT_FALSE(stream_.handshake_confirmed()); + EXPECT_FALSE(server_stream_->encryption_established()); + EXPECT_FALSE(server_stream_->handshake_confirmed()); +} + +TEST_P(QuicCryptoServerStreamTest, NotInitiallySendingStatelessRejects) { + EXPECT_FALSE(server_stream_->use_stateless_rejects_if_peer_supported()); + EXPECT_FALSE(server_stream_->peer_supports_stateless_rejects()); } TEST_P(QuicCryptoServerStreamTest, ConnectedAfterCHLO) { @@ -128,154 +194,248 @@ // * One to get a source-address token and certificates. // * One to complete the handshake. EXPECT_EQ(2, CompleteCryptoHandshake()); - EXPECT_TRUE(stream_.encryption_established()); - EXPECT_TRUE(stream_.handshake_confirmed()); + EXPECT_TRUE(server_stream_->encryption_established()); + EXPECT_TRUE(server_stream_->handshake_confirmed()); } -TEST_P(QuicCryptoServerStreamTest, ZeroRTT) { - PacketSavingConnection* client_conn = - new PacketSavingConnection(Perspective::IS_CLIENT); - PacketSavingConnection* server_conn = - new PacketSavingConnection(Perspective::IS_SERVER); - client_conn->AdvanceTime(QuicTime::Delta::FromSeconds(100000)); - server_conn->AdvanceTime(QuicTime::Delta::FromSeconds(100000)); +TEST_P(QuicCryptoServerStreamTest, StatelessRejectAfterCHLO) { + ValueRestore<bool> old_flag(&FLAGS_enable_quic_stateless_reject_support, + true); + server_stream_->set_use_stateless_rejects_if_peer_supported(true); - QuicConfig client_config; - scoped_ptr<TestClientSession> client_session( - new TestClientSession(client_conn, client_config)); - QuicCryptoClientConfig client_crypto_config; + InitializeFakeClient(/* supports_stateless_rejects= */ true); + AdvanceHandshakeWithFakeClient(); - QuicServerId server_id(kServerHostname, kServerPort, false, - PRIVACY_MODE_DISABLED); - scoped_ptr<QuicCryptoClientStream> client(new QuicCryptoClientStream( - server_id, client_session.get(), nullptr, &client_crypto_config)); - client_session->SetCryptoStream(client.get()); + // Check the server to make the sure the handshake did not succeed. + EXPECT_FALSE(server_stream_->encryption_established()); + EXPECT_FALSE(server_stream_->handshake_confirmed()); - // Do a first handshake in order to prime the client config with the server's - // information. - client->CryptoConnect(); - CHECK_EQ(1u, client_conn->encrypted_packets_.size()); + // Check the client state to make sure that it received a + // server-designated connection id. + QuicCryptoClientConfig::CachedState* client_state = + client_crypto_config_.LookupOrCreate(server_id_); - scoped_ptr<TestSession> server_session(new TestSession(server_conn, config_)); - scoped_ptr<QuicCryptoServerStream> server( - new QuicCryptoServerStream(&crypto_config_, server_session.get())); - server_session->SetCryptoStream(server.get()); + ASSERT_TRUE(client_state->has_server_designated_connection_id()); + const QuicConnectionId server_designated_connection_id = + client_state->GetNextServerDesignatedConnectionId(); + const QuicConnectionId expected_id = + reinterpret_cast<MockRandom*>(server_connection_->random_generator()) + ->RandUint64(); + EXPECT_EQ(expected_id, server_designated_connection_id); + EXPECT_FALSE(client_state->has_server_designated_connection_id()); + ASSERT_TRUE(client_state->IsComplete(QuicWallTime::FromUNIXSeconds(0))); +} - CryptoTestUtils::CommunicateHandshakeMessages( - client_conn, client.get(), server_conn, server.get()); - EXPECT_EQ(2, client->num_sent_client_hellos()); +TEST_P(QuicCryptoServerStreamTest, ConnectedAfterStatelessHandshake) { + ValueRestore<bool> old_flag(&FLAGS_enable_quic_stateless_reject_support, + true); + server_stream_->set_use_stateless_rejects_if_peer_supported(true); - // Now do another handshake, hopefully in 0-RTT. - LOG(INFO) << "Resetting for 0-RTT handshake attempt"; + InitializeFakeClient(/* supports_stateless_rejects= */ true); + AdvanceHandshakeWithFakeClient(); - client_conn = new PacketSavingConnection(Perspective::IS_CLIENT); - server_conn = new PacketSavingConnection(Perspective::IS_SERVER); - // We need to advance time past the strike-server window so that it's - // authoritative in this time span. - client_conn->AdvanceTime(QuicTime::Delta::FromSeconds(102000)); - server_conn->AdvanceTime(QuicTime::Delta::FromSeconds(102000)); + // On the first round, encryption will not be established. + EXPECT_FALSE(server_stream_->encryption_established()); + EXPECT_FALSE(server_stream_->handshake_confirmed()); - // This causes the client's nonce to be different and thus stops the - // strike-register from rejecting the repeated nonce. - reinterpret_cast<MockRandom*>(client_conn->random_generator())->ChangeValue(); - client_session.reset(new TestClientSession(client_conn, client_config)); - server_session.reset(new TestSession(server_conn, config_)); - client.reset(new QuicCryptoClientStream(server_id, client_session.get(), - nullptr, &client_crypto_config)); - client_session->SetCryptoStream(client.get()); + // Now check the client state. + QuicCryptoClientConfig::CachedState* client_state = + client_crypto_config_.LookupOrCreate(server_id_); - server.reset(new QuicCryptoServerStream(&crypto_config_, - server_session.get())); - server_session->SetCryptoStream(server.get()); + ASSERT_TRUE(client_state->has_server_designated_connection_id()); + const QuicConnectionId server_designated_connection_id = + client_state->GetNextServerDesignatedConnectionId(); + const QuicConnectionId expected_id = + reinterpret_cast<MockRandom*>(server_connection_->random_generator()) + ->RandUint64(); + EXPECT_EQ(expected_id, server_designated_connection_id); + EXPECT_FALSE(client_state->has_server_designated_connection_id()); + ASSERT_TRUE(client_state->IsComplete(QuicWallTime::FromUNIXSeconds(0))); - client->CryptoConnect(); + // Now create new client and server streams with the existing config + // and try the handshake again (0-RTT handshake). + InitializeServer(); + server_stream_->set_use_stateless_rejects_if_peer_supported(true); + InitializeFakeClient(/* supports_stateless_rejects= */ true); + + client_stream_->CryptoConnect(); if (AsyncStrikeRegisterVerification()) { - EXPECT_FALSE(client->handshake_confirmed()); - EXPECT_FALSE(server->handshake_confirmed()); + EXPECT_FALSE(client_stream_->handshake_confirmed()); + EXPECT_FALSE(server_stream_->handshake_confirmed()); // Advance the handshake. Expect that the server will be stuck // waiting for client nonce verification to complete. pair<size_t, size_t> messages_moved = CryptoTestUtils::AdvanceHandshake( - client_conn, client.get(), 0, server_conn, server.get(), 0); + client_connection_, client_stream_.get(), 0, server_connection_, + server_stream_.get(), 0); EXPECT_EQ(1u, messages_moved.first); EXPECT_EQ(0u, messages_moved.second); EXPECT_EQ(1, strike_register_client_->PendingVerifications()); - EXPECT_FALSE(client->handshake_confirmed()); - EXPECT_FALSE(server->handshake_confirmed()); + EXPECT_FALSE(client_stream_->handshake_confirmed()); + EXPECT_FALSE(server_stream_->handshake_confirmed()); // The server handshake completes once the nonce verification completes. strike_register_client_->RunPendingVerifications(); - EXPECT_FALSE(client->handshake_confirmed()); - EXPECT_TRUE(server->handshake_confirmed()); + EXPECT_FALSE(client_stream_->handshake_confirmed()); + EXPECT_TRUE(server_stream_->handshake_confirmed()); messages_moved = CryptoTestUtils::AdvanceHandshake( - client_conn, client.get(), messages_moved.first, - server_conn, server.get(), messages_moved.second); + client_connection_, client_stream_.get(), messages_moved.first, + server_connection_, server_stream_.get(), messages_moved.second); EXPECT_EQ(1u, messages_moved.first); EXPECT_EQ(1u, messages_moved.second); - EXPECT_TRUE(client->handshake_confirmed()); - EXPECT_TRUE(server->handshake_confirmed()); } else { - CryptoTestUtils::CommunicateHandshakeMessages( - client_conn, client.get(), server_conn, server.get()); + AdvanceHandshakeWithFakeClient(); } - EXPECT_EQ(1, client->num_sent_client_hellos()); + // On the second round, encryption will be established. + EXPECT_TRUE(server_stream_->encryption_established()); + EXPECT_TRUE(server_stream_->handshake_confirmed()); +} + +TEST_P(QuicCryptoServerStreamTest, NoStatelessRejectIfNoClientSupport) { + ValueRestore<bool> old_flag(&FLAGS_enable_quic_stateless_reject_support, + true); + server_stream_->set_use_stateless_rejects_if_peer_supported(true); + + // The server is configured to use stateless rejects, but the client + // does not support it. + InitializeFakeClient(/* supports_stateless_rejects= */ false); + AdvanceHandshakeWithFakeClient(); + + // Check the server to make the sure the handshake did not succeed. + EXPECT_FALSE(server_stream_->encryption_established()); + EXPECT_FALSE(server_stream_->handshake_confirmed()); + + // Check the client state to make sure that it did not receive a + // server-designated connection id. + QuicCryptoClientConfig::CachedState* client_state = + client_crypto_config_.LookupOrCreate(server_id_); + + ASSERT_FALSE(client_state->has_server_designated_connection_id()); + ASSERT_TRUE(client_state->IsComplete(QuicWallTime::FromUNIXSeconds(0))); +} + +TEST_P(QuicCryptoServerStreamTest, ZeroRTT) { + InitializeFakeClient(/* supports_stateless_rejects= */ false); + + // Do a first handshake in order to prime the client config with the server's + // information. + AdvanceHandshakeWithFakeClient(); + + // Now do another handshake, hopefully in 0-RTT. + DVLOG(1) << "Resetting for 0-RTT handshake attempt"; + InitializeFakeClient(/* supports_stateless_rejects= */ false); + InitializeServer(); + + client_stream_->CryptoConnect(); + + if (AsyncStrikeRegisterVerification()) { + EXPECT_FALSE(client_stream_->handshake_confirmed()); + EXPECT_FALSE(server_stream_->handshake_confirmed()); + + // Advance the handshake. Expect that the server will be stuck + // waiting for client nonce verification to complete. + pair<size_t, size_t> messages_moved = CryptoTestUtils::AdvanceHandshake( + client_connection_, client_stream_.get(), 0, server_connection_, + server_stream_.get(), 0); + EXPECT_EQ(1u, messages_moved.first); + EXPECT_EQ(0u, messages_moved.second); + EXPECT_EQ(1, strike_register_client_->PendingVerifications()); + EXPECT_FALSE(client_stream_->handshake_confirmed()); + EXPECT_FALSE(server_stream_->handshake_confirmed()); + + // The server handshake completes once the nonce verification completes. + strike_register_client_->RunPendingVerifications(); + EXPECT_FALSE(client_stream_->handshake_confirmed()); + EXPECT_TRUE(server_stream_->handshake_confirmed()); + + messages_moved = CryptoTestUtils::AdvanceHandshake( + client_connection_, client_stream_.get(), messages_moved.first, + server_connection_, server_stream_.get(), messages_moved.second); + EXPECT_EQ(1u, messages_moved.first); + EXPECT_EQ(1u, messages_moved.second); + EXPECT_TRUE(client_stream_->handshake_confirmed()); + EXPECT_TRUE(server_stream_->handshake_confirmed()); + } else { + CryptoTestUtils::CommunicateHandshakeMessages( + client_connection_, client_stream_.get(), server_connection_, + server_stream_.get()); + } + + EXPECT_EQ(1, client_stream_->num_sent_client_hellos()); } TEST_P(QuicCryptoServerStreamTest, MessageAfterHandshake) { CompleteCryptoHandshake(); - EXPECT_CALL(*connection_, SendConnectionClose( - QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE)); + EXPECT_CALL( + *server_connection_, + SendConnectionClose(QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE)); message_.set_tag(kCHLO); ConstructHandshakeMessage(); - stream_.ProcessRawData(message_data_->data(), message_data_->length()); + server_stream_->ProcessRawData(message_data_->data(), + message_data_->length()); } TEST_P(QuicCryptoServerStreamTest, BadMessageType) { message_.set_tag(kSHLO); ConstructHandshakeMessage(); - EXPECT_CALL(*connection_, SendConnectionClose( - QUIC_INVALID_CRYPTO_MESSAGE_TYPE)); - stream_.ProcessRawData(message_data_->data(), message_data_->length()); + EXPECT_CALL(*server_connection_, + SendConnectionClose(QUIC_INVALID_CRYPTO_MESSAGE_TYPE)); + server_stream_->ProcessRawData(message_data_->data(), + message_data_->length()); } TEST_P(QuicCryptoServerStreamTest, WithoutCertificates) { - crypto_config_.SetProofSource(nullptr); + server_crypto_config_.SetProofSource(nullptr); client_options_.dont_verify_certs = true; // Only 2 client hellos need to be sent in the no-certs case: one to get the // source-address token and the second to finish. EXPECT_EQ(2, CompleteCryptoHandshake()); - EXPECT_TRUE(stream_.encryption_established()); - EXPECT_TRUE(stream_.handshake_confirmed()); + EXPECT_TRUE(server_stream_->encryption_established()); + EXPECT_TRUE(server_stream_->handshake_confirmed()); } TEST_P(QuicCryptoServerStreamTest, ChannelID) { client_options_.channel_id_enabled = true; client_options_.channel_id_source_async = false; // CompleteCryptoHandshake verifies - // stream_.crypto_negotiated_params().channel_id is correct. + // server_stream_->crypto_negotiated_params().channel_id is correct. EXPECT_EQ(2, CompleteCryptoHandshake()); - EXPECT_TRUE(stream_.encryption_established()); - EXPECT_TRUE(stream_.handshake_confirmed()); + EXPECT_TRUE(server_stream_->encryption_established()); + EXPECT_TRUE(server_stream_->handshake_confirmed()); } TEST_P(QuicCryptoServerStreamTest, ChannelIDAsync) { client_options_.channel_id_enabled = true; client_options_.channel_id_source_async = true; // CompleteCryptoHandshake verifies - // stream_.crypto_negotiated_params().channel_id is correct. + // server_stream_->crypto_negotiated_params().channel_id is correct. EXPECT_EQ(2, CompleteCryptoHandshake()); - EXPECT_TRUE(stream_.encryption_established()); - EXPECT_TRUE(stream_.handshake_confirmed()); + EXPECT_TRUE(server_stream_->encryption_established()); + EXPECT_TRUE(server_stream_->handshake_confirmed()); } TEST_P(QuicCryptoServerStreamTest, OnlySendSCUPAfterHandshakeComplete) { // An attempt to send a SCUP before completing handshake should fail. - stream_.SendServerConfigUpdate(nullptr); - EXPECT_EQ(0, stream_.num_server_config_update_messages_sent()); + server_stream_->SendServerConfigUpdate(nullptr); + EXPECT_EQ(0, server_stream_->num_server_config_update_messages_sent()); +} + +TEST_P(QuicCryptoServerStreamTest, DoesPeerSupportStatelessRejects) { + ConstructHandshakeMessage(); + QuicConfig stateless_reject_config = DefaultQuicConfigStatelessRejects(); + stateless_reject_config.ToHandshakeMessage(&message_); + EXPECT_TRUE( + QuicCryptoServerStreamPeer::DoesPeerSupportStatelessRejects(message_)); + + message_.Clear(); + QuicConfig stateful_reject_config = DefaultQuicConfig(); + stateful_reject_config.ToHandshakeMessage(&message_); + EXPECT_FALSE( + QuicCryptoServerStreamPeer::DoesPeerSupportStatelessRejects(message_)); } } // namespace
diff --git a/net/quic/quic_flags.cc b/net/quic/quic_flags.cc index b1c53b9..cf3b262 100644 --- a/net/quic/quic_flags.cc +++ b/net/quic/quic_flags.cc
@@ -39,9 +39,9 @@ // no configured limit. int64 FLAGS_quic_time_wait_list_max_connections = 50000; -// If true, use the peer's receive buffer size to set the max CWND used by the -// send algorithms. -bool FLAGS_quic_limit_max_cwnd_to_receive_buffer = true; - // Enables server-side support for QUIC stateless rejects. bool FLAGS_enable_quic_stateless_reject_support = false; + +// If true, stop processing quic data as soon as the connection is closed rather +// than processing a full packet. +bool FLAGS_quic_stop_early = true;
diff --git a/net/quic/quic_flags.h b/net/quic/quic_flags.h index 2ad52e6..30bf0ae8 100644 --- a/net/quic/quic_flags.h +++ b/net/quic/quic_flags.h
@@ -17,7 +17,7 @@ NET_EXPORT_PRIVATE extern bool FLAGS_quic_too_many_outstanding_packets; NET_EXPORT_PRIVATE extern int64 FLAGS_quic_time_wait_list_seconds; NET_EXPORT_PRIVATE extern int64 FLAGS_quic_time_wait_list_max_connections; -NET_EXPORT_PRIVATE extern bool FLAGS_quic_limit_max_cwnd_to_receive_buffer; NET_EXPORT_PRIVATE extern bool FLAGS_enable_quic_stateless_reject_support; +NET_EXPORT_PRIVATE extern bool FLAGS_quic_stop_early; #endif // NET_QUIC_QUIC_FLAGS_H_
diff --git a/net/quic/quic_flow_controller.cc b/net/quic/quic_flow_controller.cc index d95541e..af79b956 100644 --- a/net/quic/quic_flow_controller.cc +++ b/net/quic/quic_flow_controller.cc
@@ -92,16 +92,16 @@ // (receive window offset - consumed bytes) < (max window / 2). // This is behaviour copied from SPDY. DCHECK_LT(bytes_consumed_, receive_window_offset_); - QuicStreamOffset consumed_window = receive_window_offset_ - bytes_consumed_; + QuicStreamOffset available_window = receive_window_offset_ - bytes_consumed_; QuicByteCount threshold = (max_receive_window_ / 2); - if (consumed_window < threshold) { + if (available_window < threshold) { // Update our receive window. - receive_window_offset_ += (max_receive_window_ - consumed_window); + receive_window_offset_ += (max_receive_window_ - available_window); DVLOG(1) << ENDPOINT << "Sending WindowUpdate frame for stream " << id_ << ", consumed bytes: " << bytes_consumed_ - << ", consumed window: " << consumed_window + << ", available window: " << available_window << ", and threshold: " << threshold << ", and max recvw: " << max_receive_window_ << ". New receive window offset is: " << receive_window_offset_;
diff --git a/net/quic/quic_network_transaction_unittest.cc b/net/quic/quic_network_transaction_unittest.cc index ed0d740..b78bde6 100644 --- a/net/quic/quic_network_transaction_unittest.cc +++ b/net/quic/quic_network_transaction_unittest.cc
@@ -242,7 +242,7 @@ params_.proxy_service = proxy_service_.get(); params_.ssl_config_service = ssl_config_service_.get(); params_.http_auth_handler_factory = auth_handler_factory_.get(); - params_.http_server_properties = http_server_properties.GetWeakPtr(); + params_.http_server_properties = http_server_properties_.GetWeakPtr(); params_.quic_supported_versions = SupportedVersions(GetParam()); if (use_next_protos) { @@ -325,22 +325,22 @@ crypto_client_stream_factory_.set_handshake_mode(handshake_mode); HostPortPair host_port_pair = HostPortPair::FromURL(request_.url); AlternativeService alternative_service(QUIC, host_port_pair.host(), 80); - session_->http_server_properties()->SetAlternativeService( - host_port_pair, alternative_service, 1.0); + http_server_properties_.SetAlternativeService(host_port_pair, + alternative_service, 1.0); } void ExpectBrokenAlternateProtocolMapping() { const HostPortPair origin = HostPortPair::FromURL(request_.url); const AlternativeService alternative_service = - session_->http_server_properties()->GetAlternativeService(origin); + http_server_properties_.GetAlternativeService(origin); EXPECT_NE(UNINITIALIZED_ALTERNATE_PROTOCOL, alternative_service.protocol); - EXPECT_TRUE(session_->http_server_properties()->IsAlternativeServiceBroken( + EXPECT_TRUE(http_server_properties_.IsAlternativeServiceBroken( alternative_service)); } void ExpectQuicAlternateProtocolMapping() { const AlternativeService alternative_service = - session_->http_server_properties()->GetAlternativeService( + http_server_properties_.GetAlternativeService( HostPortPair::FromURL(request_.url)); EXPECT_EQ(QUIC, alternative_service.protocol); } @@ -363,7 +363,7 @@ scoped_ptr<ProxyService> proxy_service_; scoped_ptr<HttpAuthHandlerFactory> auth_handler_factory_; MockRandom random_generator_; - HttpServerPropertiesImpl http_server_properties; + HttpServerPropertiesImpl http_server_properties_; HttpNetworkSession::Params params_; HttpRequestInfo request_; BoundTestNetLog net_log_; @@ -623,18 +623,16 @@ AlternativeService alternative_service(QUIC, HostPortPair::FromURL(request_.url)); - session_->http_server_properties()->MarkAlternativeServiceRecentlyBroken( + http_server_properties_.MarkAlternativeServiceRecentlyBroken( alternative_service); - EXPECT_TRUE( - session_->http_server_properties()->WasAlternativeServiceRecentlyBroken( - alternative_service)); + EXPECT_TRUE(http_server_properties_.WasAlternativeServiceRecentlyBroken( + alternative_service)); SendRequestAndExpectHttpResponse("hello world"); SendRequestAndExpectQuicResponse("hello!"); - EXPECT_FALSE( - session_->http_server_properties()->WasAlternativeServiceRecentlyBroken( - alternative_service)); + EXPECT_FALSE(http_server_properties_.WasAlternativeServiceRecentlyBroken( + alternative_service)); } TEST_P(QuicNetworkTransactionTest, UseAlternateProtocolProbabilityForQuic) { @@ -1256,7 +1254,7 @@ cert->VerifyNameMatch("www.example.org", &common_name_fallback_used)); ProofVerifyDetailsChromium verify_details; verify_details.cert_verify_result.verified_cert = cert; - crypto_client_stream_factory_.set_proof_verify_details(&verify_details); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); request_.url = GURL("https://www.example.org:443"); AddHangingNonAlternateProtocolSocketData();
diff --git a/net/quic/quic_sent_packet_manager.cc b/net/quic/quic_sent_packet_manager.cc index 2beef66b..c81c93df 100644 --- a/net/quic/quic_sent_packet_manager.cc +++ b/net/quic/quic_sent_packet_manager.cc
@@ -166,10 +166,8 @@ receive_buffer_bytes_ = max(kMinSocketReceiveBuffer, static_cast<QuicByteCount>(config.ReceivedSocketReceiveBuffer())); - if (FLAGS_quic_limit_max_cwnd_to_receive_buffer) { - send_algorithm_->SetMaxCongestionWindow(receive_buffer_bytes_ * - kUsableRecieveBufferFraction); - } + send_algorithm_->SetMaxCongestionWindow(receive_buffer_bytes_ * + kUsableRecieveBufferFraction); } send_algorithm_->SetFromConfig(config, perspective_); @@ -783,11 +781,6 @@ if (pending_timer_transmission_count_ > 0) { return QuicTime::Delta::Zero(); } - if (!FLAGS_quic_limit_max_cwnd_to_receive_buffer && - unacked_packets_.bytes_in_flight() >= - kUsableRecieveBufferFraction * receive_buffer_bytes_) { - return QuicTime::Delta::Infinite(); - } return send_algorithm_->TimeUntilSend( now, unacked_packets_.bytes_in_flight(), retransmittable); }
diff --git a/net/quic/quic_sent_packet_manager_test.cc b/net/quic/quic_sent_packet_manager_test.cc index 7887c67..2b55382 100644 --- a/net/quic/quic_sent_packet_manager_test.cc +++ b/net/quic/quic_sent_packet_manager_test.cc
@@ -1584,10 +1584,8 @@ QuicConfig client_config; QuicConfigPeer::SetReceivedSocketReceiveBuffer(&client_config, 1024); EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); - if (FLAGS_quic_limit_max_cwnd_to_receive_buffer) { - EXPECT_CALL(*send_algorithm_, - SetMaxCongestionWindow(kMinSocketReceiveBuffer * 0.95)); - } + EXPECT_CALL(*send_algorithm_, + SetMaxCongestionWindow(kMinSocketReceiveBuffer * 0.95)); EXPECT_CALL(*send_algorithm_, PacingRate()) .WillRepeatedly(Return(QuicBandwidth::Zero())); EXPECT_CALL(*network_change_visitor_, OnCongestionWindowChange()); @@ -1610,10 +1608,8 @@ manager_.OnPacketSent(&packet, 0, clock_.Now(), 1024, NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA); } - if (FLAGS_quic_limit_max_cwnd_to_receive_buffer) { - EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, _, _)) - .WillOnce(Return(QuicTime::Delta::Infinite())); - } + EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, _, _)) + .WillOnce(Return(QuicTime::Delta::Infinite())); EXPECT_EQ(QuicTime::Delta::Infinite(), manager_.TimeUntilSend(clock_.Now(), HAS_RETRANSMITTABLE_DATA)); } @@ -1635,10 +1631,8 @@ manager_.OnPacketSent(&packet, 0, clock_.Now(), 1024, NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA); } - if (FLAGS_quic_limit_max_cwnd_to_receive_buffer) { - EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, _, _)) - .WillOnce(Return(QuicTime::Delta::Infinite())); - } + EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, _, _)) + .WillOnce(Return(QuicTime::Delta::Infinite())); EXPECT_EQ(QuicTime::Delta::Infinite(), manager_.TimeUntilSend(clock_.Now(), HAS_RETRANSMITTABLE_DATA)); }
diff --git a/net/quic/quic_session.cc b/net/quic/quic_session.cc index 0be72eba..570eab7 100644 --- a/net/quic/quic_session.cc +++ b/net/quic/quic_session.cc
@@ -103,7 +103,6 @@ config_(config), max_open_streams_(config_.MaxStreamsPerConnection()), next_stream_id_(perspective() == Perspective::IS_SERVER ? 2 : 5), - write_blocked_streams_(true), largest_peer_created_stream_id_(0), error_(QUIC_NO_ERROR), flow_controller_(connection_.get(), @@ -134,7 +133,7 @@ } void QuicSession::OnStreamFrames(const vector<QuicStreamFrame>& frames) { - for (size_t i = 0; i < frames.size(); ++i) { + for (size_t i = 0; i < frames.size() && connection_->connected(); ++i) { // TODO(rch) deal with the error case of stream id 0. const QuicStreamFrame& frame = frames[i]; QuicStreamId stream_id = frame.stream_id; @@ -153,6 +152,9 @@ continue; } stream->OnStreamFrame(frames[i]); + if (!connection_->connected()) { + return; + } } }
diff --git a/net/quic/quic_stream_factory_test.cc b/net/quic/quic_stream_factory_test.cc index b5a1b5b1..fc07174 100644 --- a/net/quic/quic_stream_factory_test.cc +++ b/net/quic/quic_stream_factory_test.cc
@@ -682,7 +682,7 @@ ProofVerifyDetailsChromium verify_details; verify_details.cert_verify_result.verified_cert = test_cert; verify_details.cert_verify_result.is_issued_by_known_root = true; - crypto_client_stream_factory_.set_proof_verify_details(&verify_details); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); host_resolver_.set_synchronous_mode(true); host_resolver_.rules()->AddIPLiteralRule(server1.host(), "192.168.0.1", ""); @@ -746,7 +746,7 @@ ProofVerifyDetailsChromium verify_details; verify_details.cert_verify_result.verified_cert = test_cert; verify_details.cert_verify_result.is_issued_by_known_root = true; - crypto_client_stream_factory_.set_proof_verify_details(&verify_details); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); host_resolver_.set_synchronous_mode(true); host_resolver_.rules()->AddIPLiteralRule(server1.host(), "192.168.0.1", ""); @@ -815,8 +815,7 @@ ASSERT_NE(static_cast<X509Certificate*>(nullptr), test_cert.get()); ProofVerifyDetailsChromium verify_details; verify_details.cert_verify_result.verified_cert = test_cert; - crypto_client_stream_factory_.set_proof_verify_details(&verify_details); - + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); host_resolver_.set_synchronous_mode(true); host_resolver_.rules()->AddIPLiteralRule(server1.host(), "192.168.0.1", ""); @@ -884,8 +883,7 @@ verify_details.cert_verify_result.is_issued_by_known_root = true; verify_details.cert_verify_result.public_key_hashes.push_back( test::GetTestHashValue(primary_pin)); - crypto_client_stream_factory_.set_proof_verify_details(&verify_details); - + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); host_resolver_.set_synchronous_mode(true); host_resolver_.rules()->AddIPLiteralRule(server1.host(), "192.168.0.1", ""); @@ -954,8 +952,7 @@ verify_details.cert_verify_result.is_issued_by_known_root = true; verify_details.cert_verify_result.public_key_hashes.push_back( test::GetTestHashValue(primary_pin)); - crypto_client_stream_factory_.set_proof_verify_details(&verify_details); - + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); host_resolver_.set_synchronous_mode(true); host_resolver_.rules()->AddIPLiteralRule(server1.host(), "192.168.0.1", ""); @@ -1025,13 +1022,20 @@ scoped_refptr<X509Certificate> test_cert( ImportCertFromFile(certs_dir, "spdy_pooling.pem")); ASSERT_NE(static_cast<X509Certificate*>(nullptr), test_cert.get()); - ProofVerifyDetailsChromium verify_details; - verify_details.cert_verify_result.verified_cert = test_cert; - verify_details.cert_verify_result.is_issued_by_known_root = true; - verify_details.cert_verify_result.public_key_hashes.push_back( - test::GetTestHashValue(bad_pin)); - crypto_client_stream_factory_.set_proof_verify_details(&verify_details); + ProofVerifyDetailsChromium verify_details1; + verify_details1.cert_verify_result.verified_cert = test_cert; + verify_details1.cert_verify_result.is_issued_by_known_root = true; + verify_details1.cert_verify_result.public_key_hashes.push_back( + test::GetTestHashValue(bad_pin)); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details1); + + ProofVerifyDetailsChromium verify_details2; + verify_details2.cert_verify_result.verified_cert = test_cert; + verify_details2.cert_verify_result.is_issued_by_known_root = true; + verify_details2.cert_verify_result.public_key_hashes.push_back( + test::GetTestHashValue(primary_pin)); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details2); host_resolver_.set_synchronous_mode(true); host_resolver_.rules()->AddIPLiteralRule(server1.host(), "192.168.0.1", "");
diff --git a/net/quic/quic_utils_test.cc b/net/quic/quic_utils_test.cc index d741abb..1a3a1e5 100644 --- a/net/quic/quic_utils_test.cc +++ b/net/quic/quic_utils_test.cc
@@ -88,10 +88,9 @@ QuicTagVector empty_options = QuicUtils::ParseQuicConnectionOptions(""); EXPECT_EQ(0ul, empty_options.size()); - QuicTagVector parsed_options = QuicUtils::ParseQuicConnectionOptions( - "PACE,TIMER,TBBR,REJ"); + QuicTagVector parsed_options = + QuicUtils::ParseQuicConnectionOptions("TIMER,TBBR,REJ"); QuicTagVector expected_options; - expected_options.push_back(kPACE); expected_options.push_back(kTIME); expected_options.push_back(kTBBR); expected_options.push_back(kREJ);
diff --git a/net/quic/quic_write_blocked_list.cc b/net/quic/quic_write_blocked_list.cc index 36854e5..e763d17 100644 --- a/net/quic/quic_write_blocked_list.cc +++ b/net/quic/quic_write_blocked_list.cc
@@ -11,10 +11,8 @@ const QuicPriority QuicWriteBlockedList::kLowestPriority = static_cast<QuicPriority>(net::kLowestPriority); -QuicWriteBlockedList::QuicWriteBlockedList(bool avoid_duplicate_streams) - : base_write_blocked_list_(avoid_duplicate_streams), - crypto_stream_blocked_(false), - headers_stream_blocked_(false) { +QuicWriteBlockedList::QuicWriteBlockedList() + : crypto_stream_blocked_(false), headers_stream_blocked_(false) { } QuicWriteBlockedList::~QuicWriteBlockedList() {}
diff --git a/net/quic/quic_write_blocked_list.h b/net/quic/quic_write_blocked_list.h index cb6a89a..3c08badd 100644 --- a/net/quic/quic_write_blocked_list.h +++ b/net/quic/quic_write_blocked_list.h
@@ -24,7 +24,7 @@ static const QuicPriority kHighestPriority; static const QuicPriority kLowestPriority; - explicit QuicWriteBlockedList(bool avoid_duplicate_streams); + QuicWriteBlockedList(); ~QuicWriteBlockedList(); bool HasWriteBlockedDataStreams() const { @@ -61,7 +61,6 @@ SpdyPriority priority = base_write_blocked_list_.GetHighestPriorityWriteBlockedList(); QuicStreamId id = base_write_blocked_list_.PopFront(priority); - blocked_streams_.erase(id); return id; } @@ -80,15 +79,8 @@ return; } - if (!base_write_blocked_list_.avoids_inserting_duplicates() && - blocked_streams_.find(stream_id) != blocked_streams_.end()) { - DVLOG(1) << "Stream " << stream_id << " already in write blocked list."; - return; - } - base_write_blocked_list_.PushBack( stream_id, static_cast<SpdyPriority>(priority)); - blocked_streams_.insert(stream_id); return; } @@ -100,11 +92,6 @@ bool crypto_stream_blocked_; bool headers_stream_blocked_; - // Keep track of write blocked streams in a set for faster membership checking - // than iterating over the base_write_blocked_list_. The contents of this set - // should mirror the contents of base_write_blocked_list_. - std::set<QuicStreamId> blocked_streams_; - DISALLOW_COPY_AND_ASSIGN(QuicWriteBlockedList); };
diff --git a/net/quic/quic_write_blocked_list_test.cc b/net/quic/quic_write_blocked_list_test.cc index ec59268..0633f63 100644 --- a/net/quic/quic_write_blocked_list_test.cc +++ b/net/quic/quic_write_blocked_list_test.cc
@@ -12,7 +12,7 @@ namespace { TEST(QuicWriteBlockedListTest, PriorityOrder) { - QuicWriteBlockedList write_blocked_list(true); + QuicWriteBlockedList write_blocked_list; // Mark streams blocked in roughly reverse priority order, and // verify that streams are sorted. @@ -46,7 +46,7 @@ } TEST(QuicWriteBlockedListTest, CryptoStream) { - QuicWriteBlockedList write_blocked_list(true); + QuicWriteBlockedList write_blocked_list; write_blocked_list.PushBack(kCryptoStreamId, QuicWriteBlockedList::kHighestPriority); @@ -58,7 +58,7 @@ } TEST(QuicWriteBlockedListTest, HeadersStream) { - QuicWriteBlockedList write_blocked_list(true); + QuicWriteBlockedList write_blocked_list; write_blocked_list.PushBack(kHeadersStreamId, QuicWriteBlockedList::kHighestPriority); @@ -70,7 +70,7 @@ } TEST(QuicWriteBlockedListTest, VerifyHeadersStream) { - QuicWriteBlockedList write_blocked_list(true); + QuicWriteBlockedList write_blocked_list; write_blocked_list.PushBack(5, QuicWriteBlockedList::kHighestPriority); write_blocked_list.PushBack(kHeadersStreamId, @@ -90,7 +90,7 @@ TEST(QuicWriteBlockedListTest, NoDuplicateEntries) { // Test that QuicWriteBlockedList doesn't allow duplicate entries. - QuicWriteBlockedList write_blocked_list(true); + QuicWriteBlockedList write_blocked_list; // Try to add a stream to the write blocked list multiple times at the same // priority.
diff --git a/net/quic/test_tools/mock_crypto_client_stream_factory.cc b/net/quic/test_tools/mock_crypto_client_stream_factory.cc index 5088c43..ebb5611 100644 --- a/net/quic/test_tools/mock_crypto_client_stream_factory.cc +++ b/net/quic/test_tools/mock_crypto_client_stream_factory.cc
@@ -13,10 +13,12 @@ namespace net { +MockCryptoClientStreamFactory::~MockCryptoClientStreamFactory() { +} + MockCryptoClientStreamFactory::MockCryptoClientStreamFactory() : handshake_mode_(MockCryptoClientStream::CONFIRM_HANDSHAKE), - last_stream_(nullptr), - proof_verify_details_(nullptr) { + last_stream_(nullptr) { } QuicCryptoClientStream* @@ -24,9 +26,14 @@ const QuicServerId& server_id, QuicClientSession* session, QuicCryptoClientConfig* crypto_config) { - last_stream_ = new MockCryptoClientStream( - server_id, session, nullptr, crypto_config, handshake_mode_, - proof_verify_details_); + const ProofVerifyDetails* proof_verify_details = nullptr; + if (!proof_verify_details_queue_.empty()) { + proof_verify_details = proof_verify_details_queue_.front(); + proof_verify_details_queue_.pop(); + } + last_stream_ = + new MockCryptoClientStream(server_id, session, nullptr, crypto_config, + handshake_mode_, proof_verify_details); return last_stream_; }
diff --git a/net/quic/test_tools/mock_crypto_client_stream_factory.h b/net/quic/test_tools/mock_crypto_client_stream_factory.h index b138c70e..c96db26a 100644 --- a/net/quic/test_tools/mock_crypto_client_stream_factory.h +++ b/net/quic/test_tools/mock_crypto_client_stream_factory.h
@@ -5,6 +5,7 @@ #ifndef NET_QUIC_TEST_TOOLS_MOCK_CRYPTO_CLIENT_STREAM_FACTORY_H_ #define NET_QUIC_TEST_TOOLS_MOCK_CRYPTO_CLIENT_STREAM_FACTORY_H_ +#include <queue> #include <string> #include "net/quic/quic_crypto_client_stream.h" @@ -18,7 +19,7 @@ class MockCryptoClientStreamFactory : public QuicCryptoClientStreamFactory { public: MockCryptoClientStreamFactory(); - ~MockCryptoClientStreamFactory() override {} + ~MockCryptoClientStreamFactory() override; QuicCryptoClientStream* CreateQuicCryptoClientStream( const QuicServerId& server_id, @@ -30,9 +31,9 @@ handshake_mode_ = handshake_mode; } - void set_proof_verify_details( - const ProofVerifyDetails* proof_verify_details) { - proof_verify_details_ = proof_verify_details; + // The caller keeps ownership of |proof_verify_details|. + void AddProofVerifyDetails(const ProofVerifyDetails* proof_verify_details) { + proof_verify_details_queue_.push(proof_verify_details); } MockCryptoClientStream* last_stream() const { @@ -42,7 +43,7 @@ private: MockCryptoClientStream::HandshakeMode handshake_mode_; MockCryptoClientStream* last_stream_; - const ProofVerifyDetails* proof_verify_details_; + std::queue<const ProofVerifyDetails*> proof_verify_details_queue_; DISALLOW_COPY_AND_ASSIGN(MockCryptoClientStreamFactory); };
diff --git a/net/quic/test_tools/quic_test_utils.cc b/net/quic/test_tools/quic_test_utils.cc index 2b426e8b..676a37d 100644 --- a/net/quic/test_tools/quic_test_utils.cc +++ b/net/quic/test_tools/quic_test_utils.cc
@@ -381,6 +381,14 @@ return crypto_stream_; } +TestServerSession::TestServerSession(const QuicConfig& config, + QuicConnection* connection) + : QuicServerSession(config, connection, nullptr) { +} + +TestServerSession::~TestServerSession() { +} + MockPacketWriter::MockPacketWriter() { } @@ -711,6 +719,14 @@ return config; } +QuicConfig DefaultQuicConfigStatelessRejects() { + QuicConfig config = DefaultQuicConfig(); + QuicTagVector copt; + copt.push_back(kSREJ); + config.SetConnectionOptionsToSend(copt); + return config; +} + QuicVersionVector SupportedVersions(QuicVersion version) { QuicVersionVector versions; versions.push_back(version); @@ -760,10 +776,8 @@ // in a different way, so TestWriterFactory::OnPacketSent might never be // called. factory_->current_writer_ = this; - return tools::QuicPerConnectionPacketWriter::WritePacket(buffer, - buf_len, - self_address, - peer_address); + return tools::QuicPerConnectionPacketWriter::WritePacket( + buffer, buf_len, self_address, peer_address); } MockQuicConnectionDebugVisitor::MockQuicConnectionDebugVisitor() { @@ -772,5 +786,60 @@ MockQuicConnectionDebugVisitor::~MockQuicConnectionDebugVisitor() { } +void SetupCryptoClientStreamForTest( + QuicServerId server_id, + bool supports_stateless_rejects, + QuicTime::Delta connection_start_time, + QuicCryptoClientConfig* crypto_client_config, + PacketSavingConnection** client_connection, + TestClientSession** client_session, + QuicCryptoClientStream** client_stream) { + CHECK(crypto_client_config); + CHECK(client_connection); + CHECK(client_session); + CHECK(client_stream); + CHECK(!connection_start_time.IsZero()) + << "Connections must start at non-zero times, otherwise the " + << "strike-register will be unhappy."; + + QuicConfig config = supports_stateless_rejects + ? DefaultQuicConfigStatelessRejects() + : DefaultQuicConfig(); + *client_connection = new PacketSavingConnection(Perspective::IS_CLIENT); + *client_session = new TestClientSession(*client_connection, config); + *client_stream = new QuicCryptoClientStream(server_id, *client_session, + nullptr, crypto_client_config); + (*client_session)->SetCryptoStream(*client_stream); + (*client_connection)->AdvanceTime(connection_start_time); +} + +// Setup or create? +void SetupCryptoServerStreamForTest( + QuicServerId server_id, + QuicTime::Delta connection_start_time, + QuicCryptoServerConfig* server_crypto_config, + PacketSavingConnection** server_connection, + TestServerSession** server_session, + QuicCryptoServerStream** server_stream) { + CHECK(server_crypto_config); + CHECK(server_connection); + CHECK(server_session); + CHECK(server_stream); + CHECK(!connection_start_time.IsZero()) + << "Connections must start at non-zero times, otherwise the " + << "strike-register will be unhappy."; + + *server_connection = new PacketSavingConnection(Perspective::IS_SERVER); + *server_session = + new TestServerSession(DefaultQuicConfig(), *server_connection); + *server_stream = + new QuicCryptoServerStream(server_crypto_config, *server_session); + (*server_session)->InitializeSession(server_crypto_config); + + // We advance the clock initially because the default time is zero and the + // strike register worries that we've just overflowed a uint32 time. + (*server_connection)->AdvanceTime(connection_start_time); +} + } // namespace test } // namespace net
diff --git a/net/quic/test_tools/quic_test_utils.h b/net/quic/test_tools/quic_test_utils.h index 9755778..facdcbf6 100644 --- a/net/quic/test_tools/quic_test_utils.h +++ b/net/quic/test_tools/quic_test_utils.h
@@ -26,6 +26,7 @@ #include "net/spdy/spdy_framer.h" #include "net/tools/quic/quic_dispatcher.h" #include "net/tools/quic/quic_per_connection_packet_writer.h" +#include "net/tools/quic/quic_server_session.h" #include "testing/gmock/include/gmock/gmock.h" namespace net { @@ -129,6 +130,9 @@ // Returns QuicConfig set to default values. QuicConfig DefaultQuicConfig(); +// Returns a QuicConfig set to default values that supports stateless rejects. +QuicConfig DefaultQuicConfigStatelessRejects(); + // Returns a version vector consisting of |version|. QuicVersionVector SupportedVersions(QuicVersion version); @@ -706,6 +710,65 @@ void(const QuicPacketHeader&, StringPiece payload)); }; +class TestServerSession : public tools::QuicServerSession { + public: + TestServerSession(const QuicConfig& config, QuicConnection* connection); + ~TestServerSession() override; + + private: + DISALLOW_COPY_AND_ASSIGN(TestServerSession); +}; + +// Creates and sets up a QuicCryptoClientStream for testing, and all +// its associated state. +// +// server_id: The server id associated with this stream. +// supports_stateless_rejects: Does this client support stateless rejects. +// connection_start_time: The time to set for the connection clock. +// Needed for strike-register nonce verification. The client +// connection_start_time should be synchronized witht the server +// start time, otherwise nonce verification will fail. +// crypto_client_config: Pointer to the crypto client config. +// client_connection: Pointer reference for newly created +// connection. This object will be owned by the +// client_session. +// client_session: Pointer reference for the newly created client +// session. The new object will be owned by the caller. +// client_stream: Pointer reference for the newly created crypto +// client stream. The new object will be owned by the caller. +void SetupCryptoClientStreamForTest( + QuicServerId server_id, + bool supports_stateless_rejects, + QuicTime::Delta connection_start_time, + QuicCryptoClientConfig* crypto_client_config, + PacketSavingConnection** client_connection, + TestClientSession** client_session, + QuicCryptoClientStream** client_stream); + +// Creates and sets up a QuicCryptoServerStream for testing, and all +// its associated state. +// +// server_id: The server id associated with this stream. +// connection_start_time: The time to set for the connection clock. +// Needed for strike-register nonce verification. The server +// connection_start_time should be synchronized witht the client +// start time, otherwise nonce verification will fail. +// crypto_server_config: Pointer to the crypto server config. +// server_connection: Pointer reference for newly created +// connection. This object will be owned by the +// server_session. +// server_session: Pointer reference for the newly created server +// session. The new object will be owned by the caller. +// server_stream: Pointer reference for the newly created crypto +// server stream. The new object will be owned by the caller. +void SetupCryptoServerStreamForTest( + QuicServerId server_id, + QuicTime::Delta connection_start_time, + QuicCryptoServerConfig* crypto_server_config, + PacketSavingConnection** server_connection, + TestServerSession** server_session, + QuicCryptoServerStream** server_stream); + } // namespace test } // namespace net
diff --git a/net/socket/client_socket_handle.cc b/net/socket/client_socket_handle.cc index 734e58a..d5c17005 100644 --- a/net/socket/client_socket_handle.cc +++ b/net/socket/client_socket_handle.cc
@@ -21,7 +21,9 @@ reuse_type_(ClientSocketHandle::UNUSED), callback_(base::Bind(&ClientSocketHandle::OnIOComplete, base::Unretained(this))), - is_ssl_error_(false) {} + is_ssl_error_(false), + ssl_failure_state_(SSL_FAILURE_NONE) { +} ClientSocketHandle::~ClientSocketHandle() { Reset(); @@ -72,6 +74,7 @@ void ClientSocketHandle::ResetErrorState() { is_ssl_error_ = false; ssl_error_response_info_ = HttpResponseInfo(); + ssl_failure_state_ = SSL_FAILURE_NONE; pending_http_proxy_connection_.reset(); }
diff --git a/net/socket/client_socket_handle.h b/net/socket/client_socket_handle.h index 2f8bed2..a4f7befb 100644 --- a/net/socket/client_socket_handle.h +++ b/net/socket/client_socket_handle.h
@@ -23,6 +23,7 @@ #include "net/socket/client_socket_pool.h" #include "net/socket/connection_attempts.h" #include "net/socket/stream_socket.h" +#include "net/ssl/ssl_failure_state.h" namespace net { @@ -135,6 +136,9 @@ void set_ssl_error_response_info(const HttpResponseInfo& ssl_error_state) { ssl_error_response_info_ = ssl_error_state; } + void set_ssl_failure_state(SSLFailureState ssl_failure_state) { + ssl_failure_state_ = ssl_failure_state; + } void set_pending_http_proxy_connection(ClientSocketHandle* connection) { pending_http_proxy_connection_.reset(connection); } @@ -153,6 +157,7 @@ const HttpResponseInfo& ssl_error_response_info() const { return ssl_error_response_info_; } + SSLFailureState ssl_failure_state() const { return ssl_failure_state_; } ClientSocketHandle* release_pending_http_proxy_connection() { return pending_http_proxy_connection_.release(); } @@ -210,6 +215,7 @@ int pool_id_; // See ClientSocketPool::ReleaseSocket() for an explanation. bool is_ssl_error_; HttpResponseInfo ssl_error_response_info_; + SSLFailureState ssl_failure_state_; scoped_ptr<ClientSocketHandle> pending_http_proxy_connection_; std::vector<ConnectionAttempt> connection_attempts_; base::TimeTicks init_time_;
diff --git a/net/socket/sequenced_socket_data_unittest.cc b/net/socket/sequenced_socket_data_unittest.cc index e0ed320..920666e7 100644 --- a/net/socket/sequenced_socket_data_unittest.cc +++ b/net/socket/sequenced_socket_data_unittest.cc
@@ -194,6 +194,7 @@ void AssertSyncWriteEquals(const char* data, int len); void AssertAsyncWriteEquals(const char* data, int len); void AssertWriteReturns(const char* data, int len, int rv); + void CompleteRead(); // When a given test completes, data_.at_eof() is expected to // match the value specified here. Most test should consume all @@ -313,6 +314,10 @@ ASSERT_EQ(len, write_callback_.WaitForResult()); } +void SequencedSocketDataTest::CompleteRead() { + data_->CompleteRead(); +} + void SequencedSocketDataTest::AssertWriteReturns(const char* data, int len, int rv) { @@ -603,6 +608,28 @@ ASSERT_FALSE(read_callback_.have_result()); } +TEST_F(SequencedSocketDataTest, CompleteRead) { + MockRead reads[] = { + MockRead(ASYNC, ERR_IO_PENDING, 0), MockRead(ASYNC, kMsg1, kLen1, 1), + }; + + Initialize(reads, arraysize(reads), nullptr, 0); + + AssertReadReturns(kLen1, ERR_IO_PENDING); + ASSERT_FALSE(read_callback_.have_result()); + + // Even though the read is scheduled to complete at sequence number 0, + // verify that the read callback in not called, until CompleteRead() is. + base::MessageLoop::current()->RunUntilIdle(); + ASSERT_FALSE(read_callback_.have_result()); + + CompleteRead(); + + ASSERT_TRUE(read_callback_.have_result()); + ASSERT_EQ(kLen1, read_callback_.WaitForResult()); + AssertReadBufferEquals(kMsg1, kLen1); +} + // ----------- Write TEST_F(SequencedSocketDataTest, SingleSyncWriteTooEarly) {
diff --git a/net/socket/socket_test_util.cc b/net/socket/socket_test_util.cc index c5861faa..8d4b2039 100644 --- a/net/socket/socket_test_util.cc +++ b/net/socket/socket_test_util.cc
@@ -26,6 +26,7 @@ #include "net/socket/websocket_endpoint_lock_manager.h" #include "net/ssl/ssl_cert_request_info.h" #include "net/ssl/ssl_connection_status_flags.h" +#include "net/ssl/ssl_failure_state.h" #include "net/ssl/ssl_info.h" #include "testing/gtest/include/gtest/gtest.h" @@ -248,6 +249,14 @@ helper_.Reset(); } +bool StaticSocketDataProvider::AllReadDataConsumed() const { + return helper_.at_read_eof(); +} + +bool StaticSocketDataProvider::AllWriteDataConsumed() const { + return helper_.at_write_eof(); +} + DynamicSocketDataProvider::DynamicSocketDataProvider() : short_read_limit_(0), allow_unconsumed_reads_(false) { @@ -364,103 +373,6 @@ socket()->OnReadComplete(OnRead()); } -OrderedSocketData::OrderedSocketData( - MockRead* reads, size_t reads_count, MockWrite* writes, size_t writes_count) - : StaticSocketDataProvider(reads, reads_count, writes, writes_count), - sequence_number_(0), loop_stop_stage_(0), - blocked_(false), weak_factory_(this) { -} - -OrderedSocketData::OrderedSocketData( - const MockConnect& connect, - MockRead* reads, size_t reads_count, - MockWrite* writes, size_t writes_count) - : StaticSocketDataProvider(reads, reads_count, writes, writes_count), - sequence_number_(0), loop_stop_stage_(0), - blocked_(false), weak_factory_(this) { - set_connect_data(connect); -} - -void OrderedSocketData::EndLoop() { - // If we've already stopped the loop, don't do it again until we've advanced - // to the next sequence_number. - NET_TRACE(1, " *** ") << "Stage " << sequence_number_ << ": EndLoop()"; - if (loop_stop_stage_ > 0) { - const MockRead& next_read = helper()->PeekRead(); - if ((next_read.sequence_number & ~MockRead::STOPLOOP) > - loop_stop_stage_) { - NET_TRACE(1, " *** ") << "Stage " << sequence_number_ - << ": Clearing stop index"; - loop_stop_stage_ = 0; - } else { - return; - } - } - // Record the sequence_number at which we stopped the loop. - NET_TRACE(1, " *** ") << "Stage " << sequence_number_ - << ": Posting Quit at read " << read_index(); - loop_stop_stage_ = sequence_number_; -} - -MockRead OrderedSocketData::OnRead() { - weak_factory_.InvalidateWeakPtrs(); - blocked_ = false; - const MockRead& next_read = helper()->PeekRead(); - if (next_read.sequence_number & MockRead::STOPLOOP) - EndLoop(); - if ((next_read.sequence_number & ~MockRead::STOPLOOP) <= - sequence_number_++) { - NET_TRACE(1, " *** ") << "Stage " << sequence_number_ - 1 << ": Read " - << read_index(); - DumpMockReadWrite(next_read); - blocked_ = (next_read.result == ERR_IO_PENDING); - return StaticSocketDataProvider::OnRead(); - } - NET_TRACE(1, " *** ") << "Stage " << sequence_number_ - 1 << ": I/O Pending"; - MockRead result = MockRead(ASYNC, ERR_IO_PENDING); - DumpMockReadWrite(result); - blocked_ = true; - return result; -} - -MockWriteResult OrderedSocketData::OnWrite(const std::string& data) { - NET_TRACE(1, " *** ") << "Stage " << sequence_number_ << ": Write " - << write_index(); - DumpMockReadWrite(helper()->PeekWrite()); - ++sequence_number_; - if (blocked_) { - // TODO(willchan): This 100ms delay seems to work around some weirdness. We - // should probably fix the weirdness. One example is in SpdyStream, - // DoSendRequest() will return ERR_IO_PENDING, and there's a race. If the - // SYN_REPLY causes OnResponseReceived() to get called before - // SpdyStream::ReadResponseHeaders() is called, we hit a NOTREACHED(). - base::MessageLoop::current()->PostDelayedTask( - FROM_HERE, - base::Bind(&OrderedSocketData::CompleteRead, - weak_factory_.GetWeakPtr()), - base::TimeDelta::FromMilliseconds(100)); - } - return StaticSocketDataProvider::OnWrite(data); -} - -void OrderedSocketData::Reset() { - NET_TRACE(1, " *** ") << "Stage " << sequence_number_ << ": Reset()"; - sequence_number_ = 0; - loop_stop_stage_ = 0; - set_socket(NULL); - weak_factory_.InvalidateWeakPtrs(); - StaticSocketDataProvider::Reset(); -} - -void OrderedSocketData::CompleteRead() { - if (socket() && blocked_) { - NET_TRACE(1, " *** ") << "Stage " << sequence_number_; - socket()->OnReadComplete(OnRead()); - } -} - -OrderedSocketData::~OrderedSocketData() {} - SequencedSocketData::SequencedSocketData(MockRead* reads, size_t reads_count, MockWrite* writes, @@ -515,15 +427,6 @@ NET_TRACE(1, " *** ") << "next_read: " << next_read.sequence_number; CHECK_GE(next_read.sequence_number, sequence_number_); - // Special case handling for hanging reads. - if (next_read.mode == ASYNC && next_read.result == ERR_IO_PENDING) { - NET_TRACE(1, " *** ") << "Hanging read"; - helper_.AdvanceRead(); - ++sequence_number_; - CHECK(helper_.at_read_eof()); - return MockRead(SYNCHRONOUS, ERR_IO_PENDING); - } - if (next_read.sequence_number <= sequence_number_) { if (next_read.mode == SYNCHRONOUS) { NET_TRACE(1, " *** ") << "Returning synchronously"; @@ -534,6 +437,15 @@ return next_read; } + // If the result is ERR_IO_PENDING, then advance to the next state + // and pause reads. + if (next_read.result == ERR_IO_PENDING) { + NET_TRACE(1, " *** ") << "Pausing at: " << sequence_number_; + ++sequence_number_; + helper_.AdvanceRead(); + read_state_ = PAUSED; + return MockRead(SYNCHRONOUS, ERR_IO_PENDING); + } base::MessageLoop::current()->PostTask( FROM_HERE, base::Bind(&SequencedSocketData::OnReadComplete, weak_factory_.GetWeakPtr())); @@ -600,6 +512,14 @@ weak_factory_.InvalidateWeakPtrs(); } +bool SequencedSocketData::AllReadDataConsumed() const { + return helper_.at_read_eof(); +} + +bool SequencedSocketData::AllWriteDataConsumed() const { + return helper_.at_write_eof(); +} + bool SequencedSocketData::at_read_eof() const { return helper_.at_read_eof(); } @@ -608,6 +528,19 @@ return helper_.at_read_eof(); } +bool SequencedSocketData::IsReadPaused() { + return read_state_ == PAUSED; +} + +void SequencedSocketData::CompleteRead() { + if (read_state_ != PAUSED) { + ADD_FAILURE() << "Unable to CompleteRead when not paused."; + return; + } + read_state_ = COMPLETING; + OnReadComplete(); +} + void SequencedSocketData::MaybePostReadCompleteTask() { NET_TRACE(1, " ****** ") << " current: " << sequence_number_; // Only trigger the next read to complete if there is already a read pending @@ -617,6 +550,16 @@ return; } + // If the result is ERR_IO_PENDING, then advance to the next state + // and pause reads. + if (helper_.PeekRead().result == ERR_IO_PENDING) { + NET_TRACE(1, " *** ") << "Pausing read at: " << sequence_number_; + ++sequence_number_; + helper_.AdvanceRead(); + read_state_ = PAUSED; + return; + } + NET_TRACE(1, " ****** ") << "Posting task to complete read: " << sequence_number_; base::MessageLoop::current()->PostTask( @@ -647,10 +590,6 @@ void SequencedSocketData::OnReadComplete() { CHECK_EQ(COMPLETING, read_state_); NET_TRACE(1, " *** ") << "Completing read for: " << sequence_number_; - if (!socket()) { - NET_TRACE(1, " *** ") << "No socket available to complete read"; - return; - } MockRead data = helper_.AdvanceRead(); DCHECK_EQ(sequence_number_, data.sequence_number); @@ -664,7 +603,13 @@ // before calling that. MaybePostWriteCompleteTask(); - NET_TRACE(1, " *** ") << "Completing socket read for: " << sequence_number_; + if (!socket()) { + NET_TRACE(1, " *** ") << "No socket available to complete read"; + return; + } + + NET_TRACE(1, " *** ") << "Completing socket read for: " + << data.sequence_number; DumpMockReadWrite(data); socket()->OnReadComplete(data); NET_TRACE(1, " *** ") << "Done"; @@ -673,10 +618,6 @@ void SequencedSocketData::OnWriteComplete() { CHECK_EQ(COMPLETING, write_state_); NET_TRACE(1, " *** ") << " Completing write for: " << sequence_number_; - if (!socket()) { - NET_TRACE(1, " *** ") << "No socket available to complete write."; - return; - } const MockWrite& data = helper_.AdvanceWrite(); DCHECK_EQ(sequence_number_, data.sequence_number); @@ -691,7 +632,13 @@ // before calling that. MaybePostReadCompleteTask(); - NET_TRACE(1, " *** ") << " Completing socket write for: " << sequence_number_; + if (!socket()) { + NET_TRACE(1, " *** ") << "No socket available to complete write"; + return; + } + + NET_TRACE(1, " *** ") << " Completing socket write for: " + << data.sequence_number; socket()->OnWriteComplete(rv); NET_TRACE(1, " *** ") << "Done"; } @@ -1033,6 +980,10 @@ return NULL; } +SSLFailureState MockClientSocket::GetSSLFailureState() const { + return IsConnected() ? SSL_FAILURE_NONE : SSL_FAILURE_UNKNOWN; +} + SSLClientSocket::NextProtoStatus MockClientSocket::GetNextProto( std::string* proto) const { proto->clear();
diff --git a/net/socket/socket_test_util.h b/net/socket/socket_test_util.h index b7d090e..7d9a53b 100644 --- a/net/socket/socket_test_util.h +++ b/net/socket/socket_test_util.h
@@ -166,7 +166,7 @@ const char* data; int data_len; - // For OrderedSocketData, which only allows reads to occur in a particular + // For data providers that only allows reads to occur in a particular // sequence. If a read occurs before the given |sequence_number| is reached, // an ERR_IO_PENDING is returned. int sequence_number; // The sequence number at which a read is allowed @@ -198,6 +198,8 @@ virtual MockRead OnRead() = 0; virtual MockWriteResult OnWrite(const std::string& data) = 0; virtual void Reset() = 0; + virtual bool AllReadDataConsumed() const = 0; + virtual bool AllWriteDataConsumed() const = 0; // Accessor for the socket which is using the SocketDataProvider. AsyncSocket* socket() { return socket_; } @@ -294,6 +296,8 @@ MockRead OnRead() override; MockWriteResult OnWrite(const std::string& data) override; void Reset() override; + bool AllReadDataConsumed() const override; + bool AllWriteDataConsumed() const override; size_t read_index() const { return helper_.read_index(); } size_t write_index() const { return helper_.write_index(); } @@ -418,61 +422,6 @@ DISALLOW_COPY_AND_ASSIGN(DelayedSocketData); }; -// A DataProvider where the reads are ordered. -// If a read is requested before its sequence number is reached, we return an -// ERR_IO_PENDING (that way we don't have to explicitly add a MockRead just to -// wait). -// The sequence number is incremented on every read and write operation. -// The message loop may be interrupted by setting the high bit of the sequence -// number in the MockRead's sequence number. When that MockRead is reached, -// we post a Quit message to the loop. This allows us to interrupt the reading -// of data before a complete message has arrived, and provides support for -// testing server push when the request is issued while the response is in the -// middle of being received. -class OrderedSocketData : public StaticSocketDataProvider { - public: - // |reads| the list of MockRead completions. - // |writes| the list of MockWrite completions. - // Note: All MockReads and MockWrites must be async. - // Note: For stream sockets, the MockRead list must end with a EOF, e.g., a - // MockRead(true, 0, 0); - OrderedSocketData(MockRead* reads, - size_t reads_count, - MockWrite* writes, - size_t writes_count); - ~OrderedSocketData() override; - - // |connect| the result for the connect phase. - // |reads| the list of MockRead completions. - // |writes| the list of MockWrite completions. - // Note: All MockReads and MockWrites must be async. - // Note: For stream sockets, the MockRead list must end with a EOF, e.g., a - // MockRead(true, 0, 0); - OrderedSocketData(const MockConnect& connect, - MockRead* reads, - size_t reads_count, - MockWrite* writes, - size_t writes_count); - - // Posts a quit message to the current message loop, if one is running. - void EndLoop(); - - // StaticSocketDataProvider: - MockRead OnRead() override; - MockWriteResult OnWrite(const std::string& data) override; - void Reset() override; - void CompleteRead() override; - - private: - int sequence_number_; - int loop_stop_stage_; - bool blocked_; - - base::WeakPtrFactory<OrderedSocketData> weak_factory_; - - DISALLOW_COPY_AND_ASSIGN(OrderedSocketData); -}; - // Uses the sequence_number field in the mock reads and writes to // complete the operations in a specified order. class SequencedSocketData : public SocketDataProvider { @@ -499,6 +448,8 @@ MockRead OnRead() override; MockWriteResult OnWrite(const std::string& data) override; void Reset() override; + bool AllReadDataConsumed() const override; + bool AllWriteDataConsumed() const override; // Returns true if all data has been read. bool at_read_eof() const; @@ -506,6 +457,9 @@ // Returns true if all data has been written. bool at_write_eof() const; + bool IsReadPaused(); + void CompleteRead(); + private: // Defines the state for the read or write path. enum IoState { @@ -513,7 +467,9 @@ PENDING, // An async operation in waiting for another opteration to // complete. COMPLETING, // A task has been posted to complet an async operation. + PAUSED, // IO is paused until CompleteRead() is called. }; + void OnReadComplete(); void OnWriteComplete(); @@ -793,6 +749,7 @@ int GetTLSUniqueChannelBinding(std::string* out) override; NextProtoStatus GetNextProto(std::string* proto) const override; ChannelIDService* GetChannelIDService() const override; + SSLFailureState GetSSLFailureState() const override; protected: ~MockClientSocket() override;
diff --git a/net/socket/ssl_client_socket.h b/net/socket/ssl_client_socket.h index cb5e5fbe..6774f15 100644 --- a/net/socket/ssl_client_socket.h +++ b/net/socket/ssl_client_socket.h
@@ -13,6 +13,7 @@ #include "net/base/net_errors.h" #include "net/socket/ssl_socket.h" #include "net/socket/stream_socket.h" +#include "net/ssl/ssl_failure_state.h" namespace net { @@ -129,6 +130,11 @@ // channel ids are not supported. virtual ChannelIDService* GetChannelIDService() const = 0; + // Returns the state of the handshake when it failed, or |SSL_FAILURE_NONE| if + // the handshake succeeded. This is used to classify causes of the TLS version + // fallback. + virtual SSLFailureState GetSSLFailureState() const = 0; + protected: void set_negotiation_extension( SSLNegotiationExtension negotiation_extension) {
diff --git a/net/socket/ssl_client_socket_nss.cc b/net/socket/ssl_client_socket_nss.cc index 229735b..7c5264db 100644 --- a/net/socket/ssl_client_socket_nss.cc +++ b/net/socket/ssl_client_socket_nss.cc
@@ -106,6 +106,7 @@ #include "net/ssl/ssl_cert_request_info.h" #include "net/ssl/ssl_cipher_suite_names.h" #include "net/ssl/ssl_connection_status_flags.h" +#include "net/ssl/ssl_failure_state.h" #include "net/ssl/ssl_info.h" #if defined(USE_NSS_CERTS) @@ -3208,4 +3209,10 @@ return channel_id_service_; } +SSLFailureState SSLClientSocketNSS::GetSSLFailureState() const { + if (completed_handshake_) + return SSL_FAILURE_NONE; + return SSL_FAILURE_UNKNOWN; +} + } // namespace net
diff --git a/net/socket/ssl_client_socket_nss.h b/net/socket/ssl_client_socket_nss.h index 72fa9d2..75b47af 100644 --- a/net/socket/ssl_client_socket_nss.h +++ b/net/socket/ssl_client_socket_nss.h
@@ -105,7 +105,10 @@ const CompletionCallback& callback) override; int SetReceiveBufferSize(int32 size) override; int SetSendBufferSize(int32 size) override; + + // SSLClientSocket implementation. ChannelIDService* GetChannelIDService() const override; + SSLFailureState GetSSLFailureState() const override; protected: // SSLClientSocket implementation.
diff --git a/net/socket/ssl_client_socket_openssl.cc b/net/socket/ssl_client_socket_openssl.cc index 9b1ce38..89d29528 100644 --- a/net/socket/ssl_client_socket_openssl.cc +++ b/net/socket/ssl_client_socket_openssl.cc
@@ -38,6 +38,7 @@ #include "net/ssl/ssl_cert_request_info.h" #include "net/ssl/ssl_client_session_cache_openssl.h" #include "net/ssl/ssl_connection_status_flags.h" +#include "net/ssl/ssl_failure_state.h" #include "net/ssl/ssl_info.h" #if defined(OS_WIN) @@ -368,6 +369,7 @@ channel_id_sent_(false), handshake_completed_(false), certificate_verified_(false), + ssl_failure_state_(SSL_FAILURE_NONE), transport_security_state_(context.transport_security_state), policy_enforcer_(context.cert_policy_enforcer), net_log_(transport_->socket()->NetLog()), @@ -397,6 +399,10 @@ return channel_id_service_; } +SSLFailureState SSLClientSocketOpenSSL::GetSSLFailureState() const { + return ssl_failure_state_; +} + int SSLClientSocketOpenSSL::ExportKeyingMaterial( const base::StringPiece& label, bool has_context, const base::StringPiece& context, @@ -504,7 +510,10 @@ npn_proto_.clear(); channel_id_sent_ = false; + handshake_completed_ = false; + certificate_verified_ = false; channel_id_request_handle_.Cancel(); + ssl_failure_state_ = SSL_FAILURE_NONE; } bool SSLClientSocketOpenSSL::IsConnected() const { @@ -932,6 +941,31 @@ net_log_.AddEvent( NetLog::TYPE_SSL_HANDSHAKE_ERROR, CreateNetLogOpenSSLErrorCallback(net_error, ssl_error, error_info)); + + // Classify the handshake failure. This is used to determine causes of the + // TLS version fallback. + + // |cipher| is the current outgoing cipher suite, so it is non-null iff + // ChangeCipherSpec was sent. + const SSL_CIPHER* cipher = SSL_get_current_cipher(ssl_); + if (SSL_get_state(ssl_) == SSL3_ST_CR_SRVR_HELLO_A) { + ssl_failure_state_ = SSL_FAILURE_CLIENT_HELLO; + } else if (cipher && (SSL_CIPHER_get_id(cipher) == + TLS1_CK_DHE_RSA_WITH_AES_128_GCM_SHA256 || + SSL_CIPHER_get_id(cipher) == + TLS1_CK_RSA_WITH_AES_128_GCM_SHA256)) { + ssl_failure_state_ = SSL_FAILURE_BUGGY_GCM; + } else if (cipher && ssl_config_.send_client_cert) { + ssl_failure_state_ = SSL_FAILURE_CLIENT_AUTH; + } else if (ERR_GET_LIB(error_info.error_code) == ERR_LIB_SSL && + ERR_GET_REASON(error_info.error_code) == + SSL_R_OLD_SESSION_VERSION_NOT_RETURNED) { + ssl_failure_state_ = SSL_FAILURE_SESSION_MISMATCH; + } else if (cipher && npn_status_ != kNextProtoUnsupported) { + ssl_failure_state_ = SSL_FAILURE_NEXT_PROTO; + } else { + ssl_failure_state_ = SSL_FAILURE_UNKNOWN; + } } GotoState(STATE_HANDSHAKE_COMPLETE);
diff --git a/net/socket/ssl_client_socket_openssl.h b/net/socket/ssl_client_socket_openssl.h index c78a815..452936a 100644 --- a/net/socket/ssl_client_socket_openssl.h +++ b/net/socket/ssl_client_socket_openssl.h
@@ -21,6 +21,7 @@ #include "net/ssl/openssl_ssl_util.h" #include "net/ssl/ssl_client_cert_type.h" #include "net/ssl/ssl_config_service.h" +#include "net/ssl/ssl_failure_state.h" // Avoid including misc OpenSSL headers, i.e.: // <openssl/bio.h> @@ -63,6 +64,7 @@ void GetSSLCertRequestInfo(SSLCertRequestInfo* cert_request_info) override; NextProtoStatus GetNextProto(std::string* proto) const override; ChannelIDService* GetChannelIDService() const override; + SSLFailureState GetSSLFailureState() const override; // SSLSocket implementation. int ExportKeyingMaterial(const base::StringPiece& label, @@ -303,6 +305,7 @@ bool certificate_verified_; // The request handle for |channel_id_service_|. ChannelIDService::RequestHandle channel_id_request_handle_; + SSLFailureState ssl_failure_state_; TransportSecurityState* transport_security_state_;
diff --git a/net/socket/ssl_client_socket_pool.cc b/net/socket/ssl_client_socket_pool.cc index 11de9193..f8db1d0 100644 --- a/net/socket/ssl_client_socket_pool.cc +++ b/net/socket/ssl_client_socket_pool.cc
@@ -163,6 +163,8 @@ handle->set_ssl_error_response_info(error_response_info_); if (!connect_timing_.ssl_start.is_null()) handle->set_is_ssl_error(true); + if (ssl_socket_) + handle->set_ssl_failure_state(ssl_socket_->GetSSLFailureState()); handle->set_connection_attempts(connection_attempts_); }
diff --git a/net/spdy/spdy_framer.cc b/net/spdy/spdy_framer.cc index ea5eaa5..eebddf6 100644 --- a/net/spdy/spdy_framer.cc +++ b/net/spdy/spdy_framer.cc
@@ -161,7 +161,8 @@ enable_compression_(true), syn_frame_processed_(false), probable_http_response_(false), - end_stream_when_done_(false) { + end_stream_when_done_(false), + header_table_size_bound_(4096) { DCHECK_GE(protocol_version_, SPDY_MIN_VERSION); DCHECK_LE(protocol_version_, SPDY_MAX_VERSION); DCHECK_LE(kMaxControlFrameSize, @@ -2056,8 +2057,9 @@ reader.ReadUInt8(&altsvc_scratch_.pid_len); DCHECK(successful_read); // Sanity check length value. - if (GetAltSvcMinimumSize() + altsvc_scratch_.pid_len >= - current_frame_length_) { + if (altsvc_scratch_.pid_len == 0 || + GetAltSvcMinimumSize() + altsvc_scratch_.pid_len >= + current_frame_length_) { set_error(SPDY_INVALID_CONTROL_FRAME); return 0; } @@ -3201,6 +3203,17 @@ return read_successfully; } +void SpdyFramer::UpdateHeaderTableSizeSetting(uint32 value) { + header_table_size_bound_ = value; + GetHpackEncoder()->ApplyHeaderTableSizeSetting(value); + GetHpackDecoder()->ApplyHeaderTableSizeSetting(value); +} + +// Return size bound of the header compression table. +size_t SpdyFramer::header_table_size_bound() const { + return header_table_size_bound_; +} + void SpdyFramer::SerializeNameValueBlockWithoutCompression( SpdyFrameBuilder* builder, const SpdyNameValueBlock& name_value_block) const {
diff --git a/net/spdy/spdy_framer.h b/net/spdy/spdy_framer.h index 55c3fa7..f1f4908 100644 --- a/net/spdy/spdy_framer.h +++ b/net/spdy/spdy_framer.h
@@ -590,6 +590,12 @@ const char* data, size_t len); + // Updates the maximum size of header compression table. + void UpdateHeaderTableSizeSetting(uint32 value); + + // Returns bound of header compression table size. + size_t header_table_size_bound() const; + protected: // TODO(jgraettinger): Switch to test peer pattern. FRIEND_TEST_ALL_PREFIXES(SpdyFramerTest, BasicCompression); @@ -805,6 +811,9 @@ // we know to terminate the stream when the entire header block has been // processed. bool end_stream_when_done_; + + // Last acknowledged value for SETTINGS_HEADER_TABLE_SIZE. + size_t header_table_size_bound_; }; } // namespace net
diff --git a/net/spdy/spdy_framer_test.cc b/net/spdy/spdy_framer_test.cc index fe7d4b8..4e69b207 100644 --- a/net/spdy/spdy_framer_test.cc +++ b/net/spdy/spdy_framer_test.cc
@@ -5755,6 +5755,32 @@ << SpdyFramer::ErrorCodeToString(framer.error_code()); } +TEST_P(SpdyFramerTest, OnAltSvcEmptyProtocolId) { + if (spdy_version_ <= SPDY3) { + return; + } + + testing::StrictMock<test::MockSpdyFramerVisitor> visitor; + SpdyFramer framer(spdy_version_); + framer.set_visitor(&visitor); + + EXPECT_CALL(visitor, OnError(testing::Eq(&framer))); + + SpdyAltSvcIR altsvc_ir(1); + altsvc_ir.set_max_age(10); + altsvc_ir.set_port(443); + altsvc_ir.set_host("h1"); + altsvc_ir.set_origin("o1"); + scoped_ptr<SpdySerializedFrame> frame(framer.SerializeFrame(altsvc_ir)); + framer.ProcessInput(frame->data(), framer.GetAltSvcMinimumSize() + + altsvc_ir.protocol_id().length() + + altsvc_ir.host().length()); + + EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state()); + EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME, framer.error_code()) + << SpdyFramer::ErrorCodeToString(framer.error_code()); +} + TEST_P(SpdyFramerTest, OnAltSvcBadLengths) { if (spdy_version_ <= SPDY3) { return;
diff --git a/net/spdy/spdy_network_transaction_unittest.cc b/net/spdy/spdy_network_transaction_unittest.cc index b75405b..78242df 100644 --- a/net/spdy/spdy_network_transaction_unittest.cc +++ b/net/spdy/spdy_network_transaction_unittest.cc
@@ -268,16 +268,9 @@ // should end with an empty read, and that read needs to be processed to // ensure proper deletion of the spdy_session_pool. void VerifyDataConsumed() { - for (DataVector::iterator it = data_vector_.begin(); - it != data_vector_.end(); ++it) { - EXPECT_TRUE((*it)->at_read_eof()) << "Read count: " - << (*it)->read_count() - << " Read index: " - << (*it)->read_index(); - EXPECT_TRUE((*it)->at_write_eof()) << "Write count: " - << (*it)->write_count() - << " Write index: " - << (*it)->write_index(); + for (const SocketDataProvider* provider : data_vector_) { + EXPECT_TRUE(provider->AllReadDataConsumed()); + EXPECT_TRUE(provider->AllWriteDataConsumed()); } } @@ -285,20 +278,13 @@ // processed. In that case we want to explicitly ensure that the reads were // not processed. void VerifyDataNotConsumed() { - for (DataVector::iterator it = data_vector_.begin(); - it != data_vector_.end(); ++it) { - EXPECT_TRUE(!(*it)->at_read_eof()) << "Read count: " - << (*it)->read_count() - << " Read index: " - << (*it)->read_index(); - EXPECT_TRUE(!(*it)->at_write_eof()) << "Write count: " - << (*it)->write_count() - << " Write index: " - << (*it)->write_index(); + for (const SocketDataProvider* provider : data_vector_) { + EXPECT_FALSE(provider->AllReadDataConsumed()); + EXPECT_FALSE(provider->AllWriteDataConsumed()); } } - void RunToCompletion(StaticSocketDataProvider* data) { + void RunToCompletion(SocketDataProvider* data) { RunPreTestSetup(); AddData(data); RunDefaultTest(); @@ -306,7 +292,7 @@ } void RunToCompletionWithSSLData( - StaticSocketDataProvider* data, + SocketDataProvider* data, scoped_ptr<SSLSocketDataProvider> ssl_provider) { RunPreTestSetup(); AddDataWithSSLSocketDataProvider(data, ssl_provider.Pass()); @@ -314,7 +300,7 @@ VerifyDataConsumed(); } - void AddData(StaticSocketDataProvider* data) { + void AddData(SocketDataProvider* data) { scoped_ptr<SSLSocketDataProvider> ssl_provider( new SSLSocketDataProvider(ASYNC, OK)); ssl_provider->cert = @@ -323,7 +309,7 @@ } void AddDataWithSSLSocketDataProvider( - StaticSocketDataProvider* data, + SocketDataProvider* data, scoped_ptr<SSLSocketDataProvider> ssl_provider) { DCHECK(!deterministic_); data_vector_.push_back(data); @@ -391,16 +377,16 @@ } private: - typedef std::vector<StaticSocketDataProvider*> DataVector; + typedef std::vector<SocketDataProvider*> DataVector; typedef ScopedVector<SSLSocketDataProvider> SSLVector; - typedef ScopedVector<StaticSocketDataProvider> AlternateVector; + typedef ScopedVector<SocketDataProvider> AlternateVector; typedef ScopedVector<DeterministicSocketData> AlternateDeterministicVector; HttpRequestInfo request_; RequestPriority priority_; scoped_ptr<SpdySessionDependencies> session_deps_; scoped_refptr<HttpNetworkSession> session_; TransactionHelperResult output_; - scoped_ptr<StaticSocketDataProvider> first_transaction_; + scoped_ptr<SocketDataProvider> first_transaction_; SSLVector ssl_vector_; TestCompletionCallback callback_; scoped_ptr<HttpNetworkTransaction> trans_; @@ -567,7 +553,7 @@ // to skip over data destined for other transactions while we consume // the data for |trans|. int ReadResult(HttpNetworkTransaction* trans, - StaticSocketDataProvider* data, + SocketDataProvider* data, std::string* result) { const int kSize = 3000; @@ -577,12 +563,6 @@ while (true) { int rv = trans->Read(buf.get(), kSize, callback.callback()); if (rv == ERR_IO_PENDING) { - // Multiple transactions may be in the data set. Keep pulling off - // reads until we complete our callback. - while (!callback.have_result()) { - data->CompleteRead(); - base::RunLoop().RunUntilIdle(); - } rv = callback.WaitForResult(); } else if (rv <= 0) { break; @@ -610,7 +590,7 @@ EXPECT_EQ(0u, spdy_session->num_unclaimed_pushed_streams()); } - void RunServerPushTest(OrderedSocketData* data, + void RunServerPushTest(SequencedSocketData* data, HttpResponseInfo* response, HttpResponseInfo* push_response, const std::string& expected) { @@ -751,18 +731,17 @@ // Construct the request. scoped_ptr<SpdyFrame> req( spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); - MockWrite writes[] = { CreateMockWrite(*req) }; + MockWrite writes[] = {CreateMockWrite(*req, 0)}; scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true)); MockRead reads[] = { - CreateMockRead(*resp), - CreateMockRead(*body), - MockRead(ASYNC, 0, 0) // EOF + CreateMockRead(*resp, 1), + CreateMockRead(*body, 2), + MockRead(ASYNC, 0, 3) // EOF }; - DelayedSocketData data(1, reads, arraysize(reads), - writes, arraysize(writes)); + SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL); helper.RunToCompletion(&data); @@ -778,7 +757,7 @@ // Construct the request. scoped_ptr<SpdyFrame> req( spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, p, true)); - MockWrite writes[] = { CreateMockWrite(*req) }; + MockWrite writes[] = {CreateMockWrite(*req, 0)}; SpdyPriority spdy_prio = 0; EXPECT_TRUE(GetSpdyPriority(spdy_util_.spdy_version(), *req, &spdy_prio)); @@ -828,13 +807,13 @@ scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true)); MockRead reads[] = { - CreateMockRead(*resp), - CreateMockRead(*body), - MockRead(ASYNC, 0, 0) // EOF + CreateMockRead(*resp, 1), + CreateMockRead(*body, 2), + MockRead(ASYNC, 0, 3) // EOF }; - DelayedSocketData data(1, reads, arraysize(reads), - writes, arraysize(writes)); + SequencedSocketData data(reads, arraysize(reads), writes, + arraysize(writes)); HttpRequestInfo http_req = CreateGetRequest(); NormalSpdyTransactionHelper helper(http_req, p, BoundNetLog(), @@ -877,27 +856,26 @@ scoped_ptr<SpdyFrame> fbody3(spdy_util_.ConstructSpdyBodyFrame(5, true)); MockWrite writes[] = { - CreateMockWrite(*req), - CreateMockWrite(*req2), - CreateMockWrite(*req3), + CreateMockWrite(*req, 0), + CreateMockWrite(*req2, 3), + CreateMockWrite(*req3, 6), }; MockRead reads[] = { - CreateMockRead(*resp, 1), - CreateMockRead(*body), - CreateMockRead(*resp2, 4), - CreateMockRead(*body2), - CreateMockRead(*resp3, 7), - CreateMockRead(*body3), + CreateMockRead(*resp, 1), + CreateMockRead(*body, 2), + CreateMockRead(*resp2, 4), + CreateMockRead(*body2, 5), + CreateMockRead(*resp3, 7), + CreateMockRead(*body3, 8), - CreateMockRead(*fbody), - CreateMockRead(*fbody2), - CreateMockRead(*fbody3), + CreateMockRead(*fbody, 9), + CreateMockRead(*fbody2, 10), + CreateMockRead(*fbody3, 11), - MockRead(ASYNC, 0, 0), // EOF + MockRead(ASYNC, 0, 12), // EOF }; - OrderedSocketData data(reads, arraysize(reads), - writes, arraysize(writes)); - OrderedSocketData data_placeholder(NULL, 0, NULL, 0); + SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); + SequencedSocketData data_placeholder(NULL, 0, NULL, 0); BoundNetLog log; TransactionHelperResult out; @@ -968,23 +946,21 @@ scoped_ptr<SpdyFrame> fbody2(spdy_util_.ConstructSpdyBodyFrame(3, true)); MockWrite writes[] = { - CreateMockWrite(*req), - CreateMockWrite(*req2), + CreateMockWrite(*req, 0), CreateMockWrite(*req2, 3), }; MockRead reads[] = { - CreateMockRead(*resp, 1), - CreateMockRead(*body), - CreateMockRead(*resp2, 4), - CreateMockRead(*body2), - CreateMockRead(*fbody), - CreateMockRead(*fbody2), - MockRead(ASYNC, 0, 0), // EOF + CreateMockRead(*resp, 1), + CreateMockRead(*body, 2), + CreateMockRead(*resp2, 4), + CreateMockRead(*body2, 5), + CreateMockRead(*fbody, 6), + CreateMockRead(*fbody2, 7), + MockRead(ASYNC, 0, 8), // EOF }; - OrderedSocketData data(reads, arraysize(reads), - writes, arraysize(writes)); + SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); MockConnect never_finishing_connect(SYNCHRONOUS, ERR_IO_PENDING); - OrderedSocketData data_placeholder(NULL, 0, NULL, 0); + SequencedSocketData data_placeholder(NULL, 0, NULL, 0); data_placeholder.set_connect_data(never_finishing_connect); BoundNetLog log; @@ -1055,24 +1031,23 @@ scoped_ptr<SpdyFrame> fbody2(spdy_util_.ConstructSpdyBodyFrame(3, true)); MockWrite writes[] = { - CreateMockWrite(*req), - CreateMockWrite(*req2), + CreateMockWrite(*req, 0), CreateMockWrite(*req2, 3), }; MockRead reads[] = { - CreateMockRead(*resp, 1), - CreateMockRead(*body), - CreateMockRead(*resp2, 4), - CreateMockRead(*body2), - CreateMockRead(*fbody), - CreateMockRead(*fbody2), - MockRead(ASYNC, 0, 0), // EOF + CreateMockRead(*resp, 1), + CreateMockRead(*body, 2), + CreateMockRead(*resp2, 4), + CreateMockRead(*body2, 5), + CreateMockRead(*fbody, 6), + CreateMockRead(*fbody2, 7), + MockRead(ASYNC, 0, 8), // EOF }; - OrderedSocketData preconnect_data(reads, arraysize(reads), - writes, arraysize(writes)); + SequencedSocketData preconnect_data(reads, arraysize(reads), writes, + arraysize(writes)); MockConnect never_finishing_connect(ASYNC, ERR_IO_PENDING); - OrderedSocketData data_placeholder(NULL, 0, NULL, 0); + SequencedSocketData data_placeholder(NULL, 0, NULL, 0); data_placeholder.set_connect_data(never_finishing_connect); BoundNetLog log; @@ -1174,29 +1149,28 @@ scoped_ptr<SpdyFrame> settings_ack(spdy_util_.ConstructSpdySettingsAck()); MockWrite writes[] = { - CreateMockWrite(*req), - CreateMockWrite(*settings_ack, 2), - CreateMockWrite(*req2), - CreateMockWrite(*req3), + CreateMockWrite(*req, 0), + CreateMockWrite(*settings_ack, 5), + CreateMockWrite(*req2, 6), + CreateMockWrite(*req3, 10), }; MockRead reads[] = { - CreateMockRead(*settings_frame, 1), - CreateMockRead(*resp), - CreateMockRead(*body), - CreateMockRead(*fbody), - CreateMockRead(*resp2, 8), - CreateMockRead(*body2), - CreateMockRead(*fbody2), - CreateMockRead(*resp3, 13), - CreateMockRead(*body3), - CreateMockRead(*fbody3), + CreateMockRead(*settings_frame, 1), + CreateMockRead(*resp, 2), + CreateMockRead(*body, 3), + CreateMockRead(*fbody, 4), + CreateMockRead(*resp2, 7), + CreateMockRead(*body2, 8), + CreateMockRead(*fbody2, 9), + CreateMockRead(*resp3, 11), + CreateMockRead(*body3, 12), + CreateMockRead(*fbody3, 13), - MockRead(ASYNC, 0, 0), // EOF + MockRead(ASYNC, 0, 14), // EOF }; - OrderedSocketData data(reads, arraysize(reads), - writes, arraysize(writes)); + SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); BoundNetLog log; TransactionHelperResult out; @@ -1233,7 +1207,6 @@ ASSERT_EQ(out.rv, ERR_IO_PENDING); out.rv = callback2.WaitForResult(); ASSERT_EQ(OK, out.rv); - EXPECT_EQ(7U, data.read_index()); // i.e. the third trans was queued out.rv = callback3.WaitForResult(); ASSERT_EQ(OK, out.rv); @@ -1307,39 +1280,40 @@ scoped_ptr<SpdyFrame> settings_frame( spdy_util_.ConstructSpdySettings(settings)); scoped_ptr<SpdyFrame> settings_ack(spdy_util_.ConstructSpdySettingsAck()); - - MockWrite writes[] = { CreateMockWrite(*req), - CreateMockWrite(*settings_ack, 2), - CreateMockWrite(*req2), - CreateMockWrite(*req4), - CreateMockWrite(*req3), + MockWrite writes[] = { + CreateMockWrite(*req, 0), + CreateMockWrite(*settings_ack, 5), + // By making these synchronous, it guarantees that they are not *started* + // before their sequence number, which in turn verifies that only a single + // request is in-flight at a time. + CreateMockWrite(*req2, 6, SYNCHRONOUS), + CreateMockWrite(*req4, 10, SYNCHRONOUS), + CreateMockWrite(*req3, 13, SYNCHRONOUS), }; MockRead reads[] = { - CreateMockRead(*settings_frame, 1), - CreateMockRead(*resp), - CreateMockRead(*body), - CreateMockRead(*fbody), - CreateMockRead(*resp2, 8), - CreateMockRead(*body2), - CreateMockRead(*fbody2), - CreateMockRead(*resp4, 14), - CreateMockRead(*fbody4), - CreateMockRead(*resp3, 17), - CreateMockRead(*body3), - CreateMockRead(*fbody3), + CreateMockRead(*settings_frame, 1), + CreateMockRead(*resp, 2), + CreateMockRead(*body, 3), + CreateMockRead(*fbody, 4), + CreateMockRead(*resp2, 7), + CreateMockRead(*body2, 8), + CreateMockRead(*fbody2, 9), + CreateMockRead(*resp4, 11), + CreateMockRead(*fbody4, 12), + CreateMockRead(*resp3, 14), + CreateMockRead(*body3, 15), + CreateMockRead(*fbody3, 16), - MockRead(ASYNC, 0, 0), // EOF + MockRead(ASYNC, 0, 17), // EOF }; - - OrderedSocketData data(reads, arraysize(reads), - writes, arraysize(writes)); - + SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); BoundNetLog log; TransactionHelperResult out; NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL); helper.RunPreTestSetup(); helper.AddData(&data); + scoped_ptr<HttpNetworkTransaction> trans1( new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get())); scoped_ptr<HttpNetworkTransaction> trans2( @@ -1374,7 +1348,6 @@ out.rv = callback2.WaitForResult(); ASSERT_EQ(OK, out.rv); - EXPECT_EQ(data.read_index(), 7U); // i.e. the third & fourth trans queued out.rv = callback3.WaitForResult(); ASSERT_EQ(OK, out.rv); @@ -1421,7 +1394,7 @@ } // Similar to ThreeGetsMaxConcurrrent above, however, this test -// deletes a session in the middle of the transaction to insure +// deletes a session in the middle of the transaction to ensure // that we properly remove pendingcreatestream objects from // the spdy_session TEST_P(SpdyNetworkTransactionTest, ThreeGetsWithMaxConcurrentDelete) { @@ -1447,23 +1420,22 @@ scoped_ptr<SpdyFrame> settings_ack(spdy_util_.ConstructSpdySettingsAck()); MockWrite writes[] = { - CreateMockWrite(*req), - CreateMockWrite(*settings_ack, 2), - CreateMockWrite(*req2), + CreateMockWrite(*req, 0), + CreateMockWrite(*settings_ack, 5), + CreateMockWrite(*req2, 6), }; MockRead reads[] = { - CreateMockRead(*settings_frame, 1), - CreateMockRead(*resp), - CreateMockRead(*body), - CreateMockRead(*fbody), - CreateMockRead(*resp2, 8), - CreateMockRead(*body2), - CreateMockRead(*fbody2), - MockRead(ASYNC, 0, 0), // EOF + CreateMockRead(*settings_frame, 1), + CreateMockRead(*resp, 2), + CreateMockRead(*body, 3), + CreateMockRead(*fbody, 4), + CreateMockRead(*resp2, 7), + CreateMockRead(*body2, 8), + CreateMockRead(*fbody2, 9), + MockRead(ASYNC, 0, 10), // EOF }; - OrderedSocketData data(reads, arraysize(reads), - writes, arraysize(writes)); + SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); BoundNetLog log; TransactionHelperResult out; @@ -1500,8 +1472,6 @@ out.rv = callback2.WaitForResult(); ASSERT_EQ(OK, out.rv); - EXPECT_EQ(8U, data.read_index()); - const HttpResponseInfo* response1 = trans1->GetResponseInfo(); ASSERT_TRUE(response1 != NULL); EXPECT_TRUE(response1->headers.get() != NULL); @@ -1579,22 +1549,21 @@ scoped_ptr<SpdyFrame> settings_ack(spdy_util_.ConstructSpdySettingsAck()); MockWrite writes[] = { - CreateMockWrite(*req), - CreateMockWrite(*settings_ack, 2), - CreateMockWrite(*req2), + CreateMockWrite(*req, 0), + CreateMockWrite(*settings_ack, 5), + CreateMockWrite(*req2, 6), }; MockRead reads[] = { - CreateMockRead(*settings_frame, 1), - CreateMockRead(*resp), - CreateMockRead(*body), - CreateMockRead(*fin_body), - CreateMockRead(*resp2, 8), - MockRead(ASYNC, ERR_CONNECTION_RESET, 0), // Abort! + CreateMockRead(*settings_frame, 1), + CreateMockRead(*resp, 2), + CreateMockRead(*body, 3), + CreateMockRead(*fin_body, 4), + CreateMockRead(*resp2, 7), + MockRead(ASYNC, ERR_CONNECTION_RESET, 8), // Abort! }; - OrderedSocketData data(reads, arraysize(reads), - writes, arraysize(writes)); - OrderedSocketData data_placeholder(NULL, 0, NULL, 0); + SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); + SequencedSocketData data_placeholder(NULL, 0, NULL, 0); BoundNetLog log; TransactionHelperResult out; @@ -1632,8 +1601,6 @@ out.rv = callback3.WaitForResult(); ASSERT_EQ(ERR_ABORTED, out.rv); - EXPECT_EQ(6U, data.read_index()); - const HttpResponseInfo* response1 = trans1.GetResponseInfo(); ASSERT_TRUE(response1 != NULL); EXPECT_TRUE(response1->headers.get() != NULL); @@ -1665,19 +1632,18 @@ scoped_ptr<SpdyFrame> req( spdy_util_.ConstructSpdySyn(1, *put_headers, LOWEST, false, true)); MockWrite writes[] = { - CreateMockWrite(*req), + CreateMockWrite(*req, 0), }; scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true)); MockRead reads[] = { - CreateMockRead(*resp), - CreateMockRead(*body), - MockRead(ASYNC, 0, 0) // EOF + CreateMockRead(*resp, 1), + CreateMockRead(*body, 2), + MockRead(ASYNC, 0, 3) // EOF }; - DelayedSocketData data(1, reads, arraysize(reads), - writes, arraysize(writes)); + SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL); helper.RunToCompletion(&data); @@ -1699,19 +1665,18 @@ scoped_ptr<SpdyFrame> req( spdy_util_.ConstructSpdySyn(1, *head_headers, LOWEST, false, true)); MockWrite writes[] = { - CreateMockWrite(*req), + CreateMockWrite(*req, 0), }; scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true)); MockRead reads[] = { - CreateMockRead(*resp), - CreateMockRead(*body), - MockRead(ASYNC, 0, 0) // EOF + CreateMockRead(*resp, 1), + CreateMockRead(*body, 2), + MockRead(ASYNC, 0, 3) // EOF }; - DelayedSocketData data(1, reads, arraysize(reads), - writes, arraysize(writes)); + SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL); helper.RunToCompletion(&data); @@ -1727,19 +1692,17 @@ GetDefaultUrl(), 1, kUploadDataSize, LOWEST, NULL, 0)); scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true)); MockWrite writes[] = { - CreateMockWrite(*req), - CreateMockWrite(*body), // POST upload frame + CreateMockWrite(*req, 0), CreateMockWrite(*body, 1), // POST upload frame }; scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0)); MockRead reads[] = { - CreateMockRead(*resp), - CreateMockRead(*body), - MockRead(ASYNC, 0, 0) // EOF + CreateMockRead(*resp, 2), + CreateMockRead(*body, 3), + MockRead(ASYNC, 0, 4) // EOF }; - DelayedSocketData data(2, reads, arraysize(reads), - writes, arraysize(writes)); + SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); NormalSpdyTransactionHelper helper(CreatePostRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL); helper.RunToCompletion(&data); @@ -1755,19 +1718,17 @@ GetDefaultUrl(), 1, kUploadDataSize, LOWEST, NULL, 0)); scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true)); MockWrite writes[] = { - CreateMockWrite(*req), - CreateMockWrite(*body), // POST upload frame + CreateMockWrite(*req, 0), CreateMockWrite(*body, 1), // POST upload frame }; scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0)); MockRead reads[] = { - CreateMockRead(*resp), - CreateMockRead(*body), - MockRead(ASYNC, 0, 0) // EOF + CreateMockRead(*resp, 2), + CreateMockRead(*body, 3), + MockRead(ASYNC, 0, 4) // EOF }; - DelayedSocketData data(2, reads, arraysize(reads), - writes, arraysize(writes)); + SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); NormalSpdyTransactionHelper helper(CreateFilePostRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL); helper.RunToCompletion(&data); @@ -1780,13 +1741,13 @@ // Test that a POST with a unreadable file fails. TEST_P(SpdyNetworkTransactionTest, UnreadableFilePost) { MockWrite writes[] = { - MockWrite(ASYNC, 0, 0) // EOF + MockWrite(ASYNC, 0, 0) // EOF }; MockRead reads[] = { - MockRead(ASYNC, 0, 0) // EOF + MockRead(ASYNC, 0, 1) // EOF }; - DelayedSocketData data(1, reads, arraysize(reads), writes, arraysize(writes)); + SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); NormalSpdyTransactionHelper helper(CreateUnreadableFilePostRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL); @@ -1805,19 +1766,17 @@ GetDefaultUrl(), 1, kUploadDataSize, LOWEST, NULL, 0)); scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true)); MockWrite writes[] = { - CreateMockWrite(*req), - CreateMockWrite(*body), // POST upload frame + CreateMockWrite(*req, 0), CreateMockWrite(*body, 1), // POST upload frame }; scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0)); MockRead reads[] = { - CreateMockRead(*resp), - CreateMockRead(*body), - MockRead(ASYNC, 0, 0) // EOF + CreateMockRead(*resp, 2), + CreateMockRead(*body, 3), + MockRead(ASYNC, 0, 4) // EOF }; - DelayedSocketData data(2, reads, arraysize(reads), - writes, arraysize(writes)); + SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); NormalSpdyTransactionHelper helper(CreateComplexPostRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL); @@ -1833,19 +1792,17 @@ scoped_ptr<SpdyFrame> req(spdy_util_.ConstructChunkedSpdyPost(NULL, 0)); scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true)); MockWrite writes[] = { - CreateMockWrite(*req), - CreateMockWrite(*body), + CreateMockWrite(*req, 0), CreateMockWrite(*body, 1), }; scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0)); MockRead reads[] = { - CreateMockRead(*resp), - CreateMockRead(*body), - MockRead(ASYNC, 0, 0) // EOF + CreateMockRead(*resp, 2), + CreateMockRead(*body, 3), + MockRead(ASYNC, 0, 4) // EOF }; - DelayedSocketData data(2, reads, arraysize(reads), - writes, arraysize(writes)); + SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); NormalSpdyTransactionHelper helper(CreateChunkedPostRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL); @@ -1870,23 +1827,22 @@ scoped_ptr<SpdyFrame> chunk2(spdy_util_.ConstructSpdyBodyFrame(1, false)); scoped_ptr<SpdyFrame> chunk3(spdy_util_.ConstructSpdyBodyFrame(1, true)); MockWrite writes[] = { - CreateMockWrite(*req), - CreateMockWrite(*chunk1), - CreateMockWrite(*chunk2), - CreateMockWrite(*chunk3), + CreateMockWrite(*req, 0), + CreateMockWrite(*chunk1, 1), + CreateMockWrite(*chunk2, 2), + CreateMockWrite(*chunk3, 3), }; scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0)); MockRead reads[] = { - CreateMockRead(*resp), - CreateMockRead(*chunk1), - CreateMockRead(*chunk2), - CreateMockRead(*chunk3), - MockRead(ASYNC, 0, 0) // EOF + CreateMockRead(*resp, 4), + CreateMockRead(*chunk1, 5), + CreateMockRead(*chunk2, 6), + CreateMockRead(*chunk3, 7), + MockRead(ASYNC, 0, 8) // EOF }; - DelayedSocketData data(4, reads, arraysize(reads), - writes, arraysize(writes)); + SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); NormalSpdyTransactionHelper helper(CreateChunkedPostRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL); @@ -1934,19 +1890,18 @@ spdy_util_.ConstructSpdySyn(1, *req_block, LOWEST, false, true)); MockWrite writes[] = { - CreateMockWrite(*req), + CreateMockWrite(*req, 0), }; scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0)); scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true)); MockRead reads[] = { - CreateMockRead(*resp), - CreateMockRead(*body), - MockRead(ASYNC, 0, 0) // EOF + CreateMockRead(*resp, 1), + CreateMockRead(*body, 2), + MockRead(ASYNC, 0, 3) // EOF }; - DelayedSocketData data(1, reads, arraysize(reads), - writes, arraysize(writes)); + SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL); @@ -1978,18 +1933,18 @@ spdy_util_.ConstructSpdySyn(1, *req_block, LOWEST, false, true)); MockWrite writes[] = { - CreateMockWrite(*req), + CreateMockWrite(*req, 0), }; scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0)); scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true)); MockRead reads[] = { - CreateMockRead(*resp), - CreateMockRead(*body), - MockRead(ASYNC, 0, 0) // EOF + CreateMockRead(*resp, 1), + CreateMockRead(*body, 2), + MockRead(ASYNC, 0, 3) // EOF }; - DelayedSocketData data(1, reads, arraysize(reads), writes, arraysize(writes)); + SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL); @@ -2092,11 +2047,17 @@ TEST_P(SpdyNetworkTransactionTest, ResponseWithoutSynReply) { scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true)); MockRead reads[] = { - CreateMockRead(*body), - MockRead(ASYNC, 0, 0) // EOF + CreateMockRead(*body, 1), MockRead(ASYNC, 0, 3) // EOF }; - DelayedSocketData data(1, reads, arraysize(reads), NULL, 0); + scoped_ptr<SpdyFrame> req( + spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); + scoped_ptr<SpdyFrame> rst( + spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR)); + MockWrite writes[] = { + CreateMockWrite(*req, 0), CreateMockWrite(*rst, 2), + }; + SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL); helper.RunToCompletion(&data); @@ -2112,21 +2073,19 @@ scoped_ptr<SpdyFrame> rst( spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR)); MockWrite writes[] = { - CreateMockWrite(*req), - CreateMockWrite(*rst), + CreateMockWrite(*req, 0), CreateMockWrite(*rst, 4), }; scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true)); MockRead reads[] = { - CreateMockRead(*resp), - CreateMockRead(*resp), - CreateMockRead(*body), - MockRead(ASYNC, 0, 0) // EOF + CreateMockRead(*resp, 1), + CreateMockRead(*resp, 2), + CreateMockRead(*body, 3), + MockRead(ASYNC, 0, 5) // EOF }; - DelayedSocketData data(1, reads, arraysize(reads), - writes, arraysize(writes)); + SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL); @@ -2159,8 +2118,7 @@ scoped_ptr<SpdyFrame> rst( spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR)); MockWrite writes[] = { - CreateMockWrite(*req), - CreateMockWrite(*rst), + CreateMockWrite(*req, 0), CreateMockWrite(*rst, 2), }; const char* const headers[] = { @@ -2171,13 +2129,12 @@ scoped_ptr<SpdyFrame> body( spdy_util_.ConstructSpdyBodyFrame(1, true)); MockRead reads[] = { - CreateMockRead(*resp), - CreateMockRead(*body), - MockRead(ASYNC, 0, 0) // EOF + CreateMockRead(*resp, 1), + CreateMockRead(*body, 3), + MockRead(ASYNC, 0, 4) // EOF }; - DelayedSocketData data(1, reads, arraysize(reads), - writes, arraysize(writes)); + SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL); helper.RunToCompletion(&data); @@ -2195,8 +2152,7 @@ scoped_ptr<SpdyFrame> rst( spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR)); MockWrite writes[] = { - CreateMockWrite(*req), - CreateMockWrite(*rst), + CreateMockWrite(*req, 0), CreateMockWrite(*rst, 4), }; scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); @@ -2208,14 +2164,13 @@ GetDefaultUrlWithPath("/1").c_str())); scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true)); MockRead reads[] = { - CreateMockRead(*resp), - CreateMockRead(*push), - CreateMockRead(*body), - MockRead(ASYNC, 0, 0) // EOF + CreateMockRead(*resp, 1), + CreateMockRead(*push, 2), + CreateMockRead(*body, 3), + MockRead(ASYNC, 0, 5) // EOF }; - DelayedSocketData data(1, reads, arraysize(reads), - writes, arraysize(writes)); + SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL); helper.RunToCompletion(&data); @@ -2316,8 +2271,8 @@ TEST_P(SpdyNetworkTransactionTest, StartTransactionOnReadCallback) { scoped_ptr<SpdyFrame> req( spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); - MockWrite writes[] = { CreateMockWrite(*req) }; - MockWrite writes2[] = { CreateMockWrite(*req) }; + MockWrite writes[] = {CreateMockWrite(*req)}; + MockWrite writes2[] = {CreateMockWrite(*req, 0)}; // The indicated length of this frame is longer than its actual length. When // the session receives an empty frame after this one, it shuts down the @@ -2330,22 +2285,20 @@ scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); MockRead reads[] = { - CreateMockRead(*resp, 2), - MockRead(ASYNC, ERR_IO_PENDING, 3), // Force a pause - MockRead(ASYNC, reinterpret_cast<const char*>(kGetBodyFrame2), - arraysize(kGetBodyFrame2), 4), - MockRead(ASYNC, ERR_IO_PENDING, 5), // Force a pause - MockRead(ASYNC, 0, 0, 6), // EOF + CreateMockRead(*resp, 1), + MockRead(ASYNC, ERR_IO_PENDING, 2), // Force a pause + MockRead(ASYNC, reinterpret_cast<const char*>(kGetBodyFrame2), + arraysize(kGetBodyFrame2), 3), + MockRead(ASYNC, ERR_IO_PENDING, 4), // Force a pause + MockRead(ASYNC, 0, 0, 5), // EOF }; MockRead reads2[] = { - CreateMockRead(*resp, 2), - MockRead(ASYNC, 0, 0, 3), // EOF + CreateMockRead(*resp, 1), MockRead(ASYNC, 0, 0, 2), // EOF }; - OrderedSocketData data(reads, arraysize(reads), - writes, arraysize(writes)); - DelayedSocketData data2(1, reads2, arraysize(reads2), - writes2, arraysize(writes2)); + SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); + SequencedSocketData data2(reads2, arraysize(reads2), writes2, + arraysize(writes2)); NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL); @@ -2366,6 +2319,7 @@ buf.get(), kSize, base::Bind(&SpdyNetworkTransactionTest::StartTransactionCallback, helper.session(), GURL(GetDefaultUrl()))); + ASSERT_EQ(ERR_IO_PENDING, rv); // This forces an err_IO_pending, which sets the callback. data.CompleteRead(); // This finishes the read. @@ -2379,19 +2333,18 @@ TEST_P(SpdyNetworkTransactionTest, DeleteSessionOnReadCallback) { scoped_ptr<SpdyFrame> req( spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); - MockWrite writes[] = { CreateMockWrite(*req) }; + MockWrite writes[] = {CreateMockWrite(*req, 0)}; scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true)); MockRead reads[] = { - CreateMockRead(*resp.get(), 2), - MockRead(ASYNC, ERR_IO_PENDING, 3), // Force a pause - CreateMockRead(*body.get(), 4), - MockRead(ASYNC, 0, 0, 5), // EOF + CreateMockRead(*resp.get(), 1), + MockRead(ASYNC, ERR_IO_PENDING, 2), // Force a pause + CreateMockRead(*body.get(), 3), + MockRead(ASYNC, 0, 0, 4), // EOF }; - OrderedSocketData data(reads, arraysize(reads), - writes, arraysize(writes)); + SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL); @@ -2458,10 +2411,9 @@ CreateMockRead(*body2, 3), MockRead(ASYNC, 0, 0, 4) // EOF }; - OrderedSocketData data(reads, arraysize(reads), - writes, arraysize(writes)); - OrderedSocketData data2(reads2, arraysize(reads2), - writes2, arraysize(writes2)); + SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); + SequencedSocketData data2(reads2, arraysize(reads2), writes2, + arraysize(writes2)); // TODO(erikchen): Make test support SPDYSSL, SPDYNPN TestDelegate d; @@ -2541,10 +2493,9 @@ CreateMockRead(*body2, 3), MockRead(ASYNC, 0, 0, 5) // EOF }; - OrderedSocketData data(reads, arraysize(reads), - writes, arraysize(writes)); - OrderedSocketData data2(reads2, arraysize(reads2), - writes2, arraysize(writes2)); + SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); + SequencedSocketData data2(reads2, arraysize(reads2), writes2, + arraysize(writes2)); // TODO(erikchen): Make test support SPDYSSL, SPDYNPN TestDelegate d; @@ -2581,12 +2532,10 @@ std::string contents2("hello!"); EXPECT_EQ(contents2, d2.data_received()); } - data.CompleteRead(); - data2.CompleteRead(); - EXPECT_TRUE(data.at_read_eof()); - EXPECT_TRUE(data.at_write_eof()); - EXPECT_TRUE(data2.at_read_eof()); - EXPECT_TRUE(data2.at_write_eof()); + EXPECT_TRUE(data.AllReadDataConsumed()); + EXPECT_TRUE(data.AllWriteDataConsumed()); + EXPECT_TRUE(data2.AllReadDataConsumed()); + EXPECT_TRUE(data2.AllWriteDataConsumed()); } TEST_P(SpdyNetworkTransactionTest, ServerPushSingleDataFrame) { @@ -2595,7 +2544,7 @@ scoped_ptr<SpdyFrame> stream1_body( spdy_util_.ConstructSpdyBodyFrame(1, true)); MockWrite writes[] = { - CreateMockWrite(*stream1_syn, 1), + CreateMockWrite(*stream1_syn, 0), }; scoped_ptr<SpdyFrame> @@ -2607,18 +2556,17 @@ spdy_util_.ConstructSpdyBodyFrame( 2, kPushedData, strlen(kPushedData), true)); MockRead reads[] = { - CreateMockRead(*stream1_reply, 2), - CreateMockRead(*stream2_syn, 3), - CreateMockRead(*stream1_body, 4, SYNCHRONOUS), - CreateMockRead(*stream2_body, 5), - MockRead(ASYNC, ERR_IO_PENDING, 6), // Force a pause + CreateMockRead(*stream1_reply, 1), + CreateMockRead(*stream2_syn, 2), + CreateMockRead(*stream1_body, 3, SYNCHRONOUS), + CreateMockRead(*stream2_body, 4), + MockRead(SYNCHRONOUS, ERR_IO_PENDING, 5), // Force a pause }; HttpResponseInfo response; HttpResponseInfo response2; std::string expected_push_result("pushed"); - OrderedSocketData data(reads, arraysize(reads), - writes, arraysize(writes)); + SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); RunServerPushTest(&data, &response, &response2, @@ -2639,7 +2587,7 @@ scoped_ptr<SpdyFrame> stream1_body( spdy_util_.ConstructSpdyBodyFrame(1, true)); MockWrite writes[] = { - CreateMockWrite(*stream1_syn, 1), + CreateMockWrite(*stream1_syn, 0), }; scoped_ptr<SpdyFrame> @@ -2651,18 +2599,17 @@ spdy_util_.ConstructSpdyBodyFrame( 2, kPushedData, strlen(kPushedData), true)); MockRead reads[] = { - CreateMockRead(*stream2_syn, 2), - CreateMockRead(*stream1_reply, 3), - CreateMockRead(*stream1_body, 4, SYNCHRONOUS), - CreateMockRead(*stream2_body, 5), - MockRead(ASYNC, ERR_IO_PENDING, 6), // Force a pause + CreateMockRead(*stream2_syn, 1), + CreateMockRead(*stream1_reply, 2), + CreateMockRead(*stream1_body, 3, SYNCHRONOUS), + CreateMockRead(*stream2_body, 4), + MockRead(SYNCHRONOUS, ERR_IO_PENDING, 5), // Force a pause }; HttpResponseInfo response; HttpResponseInfo response2; std::string expected_push_result("pushed"); - OrderedSocketData data(reads, arraysize(reads), - writes, arraysize(writes)); + SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); RunServerPushTest(&data, &response, &response2, @@ -2680,7 +2627,9 @@ TEST_P(SpdyNetworkTransactionTest, ServerPushSingleDataFrame2) { scoped_ptr<SpdyFrame> stream1_syn( spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); - MockWrite writes[] = { CreateMockWrite(*stream1_syn, 1), }; + MockWrite writes[] = { + CreateMockWrite(*stream1_syn, 0), + }; scoped_ptr<SpdyFrame> stream1_reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); @@ -2693,18 +2642,17 @@ scoped_ptr<SpdyFrame> stream1_body(spdy_util_.ConstructSpdyBodyFrame(1, true)); MockRead reads[] = { - CreateMockRead(*stream1_reply, 2), - CreateMockRead(*stream2_syn, 3), - CreateMockRead(*stream2_body, 4), - CreateMockRead(*stream1_body, 5, SYNCHRONOUS), - MockRead(ASYNC, ERR_IO_PENDING, 6), // Force a pause + CreateMockRead(*stream1_reply, 1), + CreateMockRead(*stream2_syn, 2), + CreateMockRead(*stream2_body, 3), + CreateMockRead(*stream1_body, 4, SYNCHRONOUS), + MockRead(SYNCHRONOUS, ERR_IO_PENDING, 5), // Force a pause }; HttpResponseInfo response; HttpResponseInfo response2; std::string expected_push_result("pushed"); - OrderedSocketData data(reads, arraysize(reads), - writes, arraysize(writes)); + SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); RunServerPushTest(&data, &response, &response2, @@ -2725,7 +2673,7 @@ scoped_ptr<SpdyFrame> stream1_body( spdy_util_.ConstructSpdyBodyFrame(1, true)); MockWrite writes[] = { - CreateMockWrite(*stream1_syn, 1), + CreateMockWrite(*stream1_syn, 0), }; scoped_ptr<SpdyFrame> @@ -2735,15 +2683,14 @@ scoped_ptr<SpdyFrame> stream2_rst( spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR)); MockRead reads[] = { - CreateMockRead(*stream1_reply, 2), - CreateMockRead(*stream2_syn, 3), - CreateMockRead(*stream2_rst, 4), - CreateMockRead(*stream1_body, 5, SYNCHRONOUS), - MockRead(ASYNC, ERR_IO_PENDING, 6), // Force a pause + CreateMockRead(*stream1_reply, 1), + CreateMockRead(*stream2_syn, 2), + CreateMockRead(*stream2_rst, 3), + CreateMockRead(*stream1_body, 4, SYNCHRONOUS), + MockRead(SYNCHRONOUS, ERR_IO_PENDING, 5), // Force a pause }; - OrderedSocketData data(reads, arraysize(reads), - writes, arraysize(writes)); + SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL); @@ -2761,14 +2708,8 @@ EXPECT_EQ(OK, rv); // Verify that we consumed all test data. - EXPECT_TRUE(data.at_read_eof()) << "Read count: " - << data.read_count() - << " Read index: " - << data.read_index(); - EXPECT_TRUE(data.at_write_eof()) << "Write count: " - << data.write_count() - << " Write index: " - << data.write_index(); + EXPECT_TRUE(data.AllReadDataConsumed()); + EXPECT_TRUE(data.AllWriteDataConsumed()); // Verify the SYN_REPLY. HttpResponseInfo response = *trans->GetResponseInfo(); @@ -2786,8 +2727,7 @@ scoped_ptr<SpdyFrame> stream3_rst( spdy_util_.ConstructSpdyRstStream(4, RST_STREAM_PROTOCOL_ERROR)); MockWrite writes[] = { - CreateMockWrite(*stream1_syn, 1), - CreateMockWrite(*stream3_rst, 5), + CreateMockWrite(*stream1_syn, 0), CreateMockWrite(*stream3_rst, 4), }; scoped_ptr<SpdyFrame> @@ -2801,19 +2741,18 @@ scoped_ptr<SpdyFrame> stream3_syn(spdy_util_.ConstructSpdyPush( NULL, 0, 4, 1, GetDefaultUrlWithPath("/foo.dat").c_str())); MockRead reads[] = { - CreateMockRead(*stream1_reply, 2), - CreateMockRead(*stream2_syn, 3), - CreateMockRead(*stream3_syn, 4), - CreateMockRead(*stream1_body, 6, SYNCHRONOUS), - CreateMockRead(*stream2_body, 7), - MockRead(ASYNC, ERR_IO_PENDING, 8), // Force a pause + CreateMockRead(*stream1_reply, 1), + CreateMockRead(*stream2_syn, 2), + CreateMockRead(*stream3_syn, 3), + CreateMockRead(*stream1_body, 5), + CreateMockRead(*stream2_body, 6), + MockRead(SYNCHRONOUS, ERR_IO_PENDING, 7), // Force a pause }; HttpResponseInfo response; HttpResponseInfo response2; std::string expected_push_result("pushed"); - OrderedSocketData data(reads, arraysize(reads), - writes, arraysize(writes)); + SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); RunServerPushTest(&data, &response, &response2, @@ -2834,7 +2773,7 @@ scoped_ptr<SpdyFrame> stream1_body( spdy_util_.ConstructSpdyBodyFrame(1, true)); MockWrite writes[] = { - CreateMockWrite(*stream1_syn, 1), + CreateMockWrite(*stream1_syn, 0), }; scoped_ptr<SpdyFrame> @@ -2857,21 +2796,20 @@ new SpdyFrame(stream2_body_base->data() + 3 * kChunkSize, stream2_body_base->size() - 3 * kChunkSize, false)); MockRead reads[] = { - CreateMockRead(*stream1_reply, 2), - CreateMockRead(*stream2_syn, 3), - CreateMockRead(*stream2_body1, 4), - CreateMockRead(*stream2_body2, 5), - CreateMockRead(*stream2_body3, 6), - CreateMockRead(*stream2_body4, 7), - CreateMockRead(*stream1_body, 8, SYNCHRONOUS), - MockRead(ASYNC, ERR_IO_PENDING, 9), // Force a pause + CreateMockRead(*stream1_reply, 1), + CreateMockRead(*stream2_syn, 2), + CreateMockRead(*stream2_body1, 3), + CreateMockRead(*stream2_body2, 4), + CreateMockRead(*stream2_body3, 5), + CreateMockRead(*stream2_body4, 6), + CreateMockRead(*stream1_body, 7, SYNCHRONOUS), + MockRead(SYNCHRONOUS, ERR_IO_PENDING, 8), // Force a pause }; HttpResponseInfo response; HttpResponseInfo response2; std::string expected_push_result("pushed my darling hello my baby"); - OrderedSocketData data(reads, arraysize(reads), - writes, arraysize(writes)); + SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); RunServerPushTest(&data, &response, &response2, kPushedData); // Verify the SYN_REPLY. @@ -2889,7 +2827,7 @@ scoped_ptr<SpdyFrame> stream1_body( spdy_util_.ConstructSpdyBodyFrame(1, true)); MockWrite writes[] = { - CreateMockWrite(*stream1_syn, 1), + CreateMockWrite(*stream1_syn, 0), }; scoped_ptr<SpdyFrame> @@ -2912,21 +2850,19 @@ new SpdyFrame(stream2_body_base->data() + 3 * kChunkSize, stream2_body_base->size() - 3 * kChunkSize, false)); MockRead reads[] = { - CreateMockRead(*stream1_reply, 2), - CreateMockRead(*stream2_syn, 3), - CreateMockRead(*stream2_body1, 4), - CreateMockRead(*stream2_body2, 5), - MockRead(ASYNC, ERR_IO_PENDING, 6), // Force a pause - CreateMockRead(*stream2_body3, 7), - CreateMockRead(*stream2_body4, 8), - CreateMockRead(*stream1_body.get(), 9, SYNCHRONOUS), - MockRead(ASYNC, ERR_IO_PENDING, 10) // Force a pause. + CreateMockRead(*stream1_reply, 1), + CreateMockRead(*stream2_syn, 2), + CreateMockRead(*stream2_body1, 3), + CreateMockRead(*stream2_body2, 4), + CreateMockRead(*stream2_body3, 5), + CreateMockRead(*stream2_body4, 6), + CreateMockRead(*stream1_body.get(), 7, SYNCHRONOUS), + MockRead(SYNCHRONOUS, ERR_IO_PENDING, 8) // Force a pause. }; HttpResponseInfo response; HttpResponseInfo response2; - OrderedSocketData data(reads, arraysize(reads), - writes, arraysize(writes)); + SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); RunServerPushTest(&data, &response, &response2, kPushedData); // Verify the SYN_REPLY. @@ -2952,8 +2888,7 @@ scoped_ptr<SpdyFrame> stream2_rst( spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_REFUSED_STREAM)); MockWrite writes[] = { - CreateMockWrite(*stream1_syn, 1), - CreateMockWrite(*stream2_rst, 4), + CreateMockWrite(*stream1_syn, 0), CreateMockWrite(*stream2_rst, 3), }; scoped_ptr<SpdyFrame> @@ -2961,14 +2896,13 @@ scoped_ptr<SpdyFrame> stream2_syn(spdy_util_.ConstructSpdyPush( NULL, 0, 2, 0, GetDefaultUrlWithPath("/foo.dat").c_str())); MockRead reads[] = { - CreateMockRead(*stream1_reply, 2), - CreateMockRead(*stream2_syn, 3), - CreateMockRead(*stream1_body, 4), - MockRead(ASYNC, ERR_IO_PENDING, 5) // Force a pause + CreateMockRead(*stream1_reply, 1), + CreateMockRead(*stream2_syn, 2), + CreateMockRead(*stream1_body, 4), + MockRead(SYNCHRONOUS, ERR_IO_PENDING, 5) // Force a pause }; - OrderedSocketData data(reads, arraysize(reads), - writes, arraysize(writes)); + SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL); @@ -2986,14 +2920,8 @@ EXPECT_EQ(OK, rv); // Verify that we consumed all test data. - EXPECT_TRUE(data.at_read_eof()) << "Read count: " - << data.read_count() - << " Read index: " - << data.read_index(); - EXPECT_TRUE(data.at_write_eof()) << "Write count: " - << data.write_count() - << " Write index: " - << data.write_index(); + EXPECT_TRUE(data.AllReadDataConsumed()); + EXPECT_TRUE(data.AllWriteDataConsumed()); // Verify the SYN_REPLY. HttpResponseInfo response = *trans->GetResponseInfo(); @@ -3009,8 +2937,7 @@ scoped_ptr<SpdyFrame> stream2_rst( spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_INVALID_STREAM)); MockWrite writes[] = { - CreateMockWrite(*stream1_syn, 1), - CreateMockWrite(*stream2_rst, 4), + CreateMockWrite(*stream1_syn, 0), CreateMockWrite(*stream2_rst, 3), }; scoped_ptr<SpdyFrame> @@ -3018,14 +2945,13 @@ scoped_ptr<SpdyFrame> stream2_syn(spdy_util_.ConstructSpdyPush( NULL, 0, 2, 9, GetDefaultUrlWithPath("/foo.dat").c_str())); MockRead reads[] = { - CreateMockRead(*stream1_reply, 2), - CreateMockRead(*stream2_syn, 3), - CreateMockRead(*stream1_body, 4), - MockRead(ASYNC, ERR_IO_PENDING, 5), // Force a pause + CreateMockRead(*stream1_reply, 1), + CreateMockRead(*stream2_syn, 2), + CreateMockRead(*stream1_body, 4), + MockRead(SYNCHRONOUS, ERR_IO_PENDING, 5), // Force a pause }; - OrderedSocketData data(reads, arraysize(reads), - writes, arraysize(writes)); + SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL); @@ -3043,14 +2969,8 @@ EXPECT_EQ(OK, rv); // Verify that we consumed all test data. - EXPECT_TRUE(data.at_read_eof()) << "Read count: " - << data.read_count() - << " Read index: " - << data.read_index(); - EXPECT_TRUE(data.at_write_eof()) << "Write count: " - << data.write_count() - << " Write index: " - << data.write_index(); + EXPECT_TRUE(data.AllReadDataConsumed()); + EXPECT_TRUE(data.AllWriteDataConsumed()); // Verify the SYN_REPLY. HttpResponseInfo response = *trans->GetResponseInfo(); @@ -3066,8 +2986,7 @@ scoped_ptr<SpdyFrame> stream2_rst( spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR)); MockWrite writes[] = { - CreateMockWrite(*stream1_syn, 1), - CreateMockWrite(*stream2_rst, 4), + CreateMockWrite(*stream1_syn, 0), CreateMockWrite(*stream2_rst, 3), }; scoped_ptr<SpdyFrame> @@ -3079,14 +2998,13 @@ scoped_ptr<SpdyFrame> stream2_syn(spdy_util_.ConstructInitialSpdyPushFrame( incomplete_headers.Pass(), 2, 1)); MockRead reads[] = { - CreateMockRead(*stream1_reply, 2), - CreateMockRead(*stream2_syn, 3), - CreateMockRead(*stream1_body, 4), - MockRead(ASYNC, ERR_IO_PENDING, 5) // Force a pause + CreateMockRead(*stream1_reply, 1), + CreateMockRead(*stream2_syn, 2), + CreateMockRead(*stream1_body, 4), + MockRead(SYNCHRONOUS, ERR_IO_PENDING, 5) // Force a pause }; - OrderedSocketData data(reads, arraysize(reads), - writes, arraysize(writes)); + SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL); @@ -3102,15 +3020,10 @@ EXPECT_EQ(ERR_IO_PENDING, rv); rv = callback.WaitForResult(); EXPECT_EQ(OK, rv); + // Verify that we consumed all test data. - EXPECT_TRUE(data.at_read_eof()) << "Read count: " - << data.read_count() - << " Read index: " - << data.read_index(); - EXPECT_TRUE(data.at_write_eof()) << "Write count: " - << data.write_count() - << " Write index: " - << data.write_index(); + EXPECT_TRUE(data.AllReadDataConsumed()); + EXPECT_TRUE(data.AllWriteDataConsumed()); // Verify the SYN_REPLY. HttpResponseInfo response = *trans->GetResponseInfo(); @@ -3168,7 +3081,7 @@ for (size_t i = 0; i < arraysize(test_cases); ++i) { scoped_ptr<SpdyFrame> req( spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); - MockWrite writes[] = { CreateMockWrite(*req) }; + MockWrite writes[] = {CreateMockWrite(*req, 0)}; scoped_ptr<SpdyFrame> resp( spdy_util_.ConstructSpdyGetSynReply(test_cases[i].extra_headers, @@ -3176,13 +3089,13 @@ 1)); scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true)); MockRead reads[] = { - CreateMockRead(*resp), - CreateMockRead(*body), - MockRead(ASYNC, 0, 0) // EOF + CreateMockRead(*resp, 1), + CreateMockRead(*body, 2), + MockRead(ASYNC, 0, 3) // EOF }; - DelayedSocketData data(1, reads, arraysize(reads), - writes, arraysize(writes)); + SequencedSocketData data(reads, arraysize(reads), writes, + arraysize(writes)); NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL); helper.RunToCompletion(&data); @@ -3286,7 +3199,7 @@ false, 1, LOWEST, true)); MockWrite writes[] = { - CreateMockWrite(*frame_req), + CreateMockWrite(*frame_req, 0), }; // Construct the reply. @@ -3299,9 +3212,9 @@ scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true)); MockRead reads[] = { - CreateMockRead(*frame_reply), - CreateMockRead(*body), - MockRead(ASYNC, 0, 0) // EOF + CreateMockRead(*frame_reply, 1), + CreateMockRead(*body, 2), + MockRead(ASYNC, 0, 3) // EOF }; // Attach the headers to the request. @@ -3314,8 +3227,8 @@ request.extra_headers.SetHeader(header_key, header_value); } - DelayedSocketData data(1, reads, arraysize(reads), - writes, arraysize(writes)); + SequencedSocketData data(reads, arraysize(reads), writes, + arraysize(writes)); NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL); helper.RunToCompletion(&data); @@ -3380,8 +3293,7 @@ scoped_ptr<SpdyFrame> rst( spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR)); MockWrite writes[] = { - CreateMockWrite(*req), - CreateMockWrite(*rst), + CreateMockWrite(*req, 0), CreateMockWrite(*rst, 2), }; // Construct the reply. @@ -3390,12 +3302,11 @@ test_cases[i].headers, test_cases[i].num_headers, &reply_headers); scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyReply(1, reply_headers)); MockRead reads[] = { - CreateMockRead(*resp), - MockRead(ASYNC, 0, 0) // EOF + CreateMockRead(*resp, 1), MockRead(ASYNC, 0, 3) // EOF }; - DelayedSocketData data(1, reads, arraysize(reads), - writes, arraysize(writes)); + SequencedSocketData data(reads, arraysize(reads), writes, + arraysize(writes)); NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL); helper.RunToCompletion(&data); @@ -3436,19 +3347,18 @@ scoped_ptr<SpdyFrame> rst( spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR)); MockWrite writes[] = { - CreateMockWrite(*req), - CreateMockWrite(*rst), + CreateMockWrite(*req, 0), CreateMockWrite(*rst, 3), }; scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true)); MockRead reads[] = { - MockRead(ASYNC, test_cases[i].syn_reply->data(), wrong_size), - CreateMockRead(*body), - MockRead(ASYNC, 0, 0) // EOF + MockRead(ASYNC, test_cases[i].syn_reply->data(), wrong_size, 1), + CreateMockRead(*body, 2), + MockRead(ASYNC, 0, 4) // EOF }; - DelayedSocketData data(1, reads, arraysize(reads), - writes, arraysize(writes)); + SequencedSocketData data(reads, arraysize(reads), writes, + arraysize(writes)); NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL); helper.RunToCompletion(&data); @@ -3477,16 +3387,15 @@ spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); scoped_ptr<SpdyFrame> goaway(spdy_util_.ConstructSpdyGoAway( 0, GOAWAY_COMPRESSION_ERROR, "Framer error: 5 (DECOMPRESS_FAILURE).")); - MockWrite writes[] = {CreateMockWrite(*req), CreateMockWrite(*goaway)}; + MockWrite writes[] = {CreateMockWrite(*req, 0), CreateMockWrite(*goaway, 2)}; scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true)); MockRead reads[] = { - MockRead(ASYNC, syn_reply_wrong_length->data(), - syn_reply_wrong_length->size() - 4), + MockRead(ASYNC, syn_reply_wrong_length->data(), + syn_reply_wrong_length->size() - 4, 1), }; - DelayedSocketData data(1, reads, arraysize(reads), - writes, arraysize(writes)); + SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL); helper.RunToCompletion(&data); @@ -3503,14 +3412,14 @@ spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); scoped_ptr<SpdyFrame> goaway(spdy_util_.ConstructSpdyGoAway( 0, GOAWAY_COMPRESSION_ERROR, "Framer error: 5 (DECOMPRESS_FAILURE).")); - MockWrite writes[] = {CreateMockWrite(*req), CreateMockWrite(*goaway)}; + MockWrite writes[] = {CreateMockWrite(*req, 0), CreateMockWrite(*goaway, 2)}; // Read HEADERS with corrupted payload. scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); memset(resp->data() + 12, 0xff, resp->size() - 12); - MockRead reads[] = {CreateMockRead(*resp)}; + MockRead reads[] = {CreateMockRead(*resp, 1)}; - DelayedSocketData data(1, reads, arraysize(reads), writes, arraysize(writes)); + SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); NormalSpdyTransactionHelper helper( CreateGetRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL); helper.RunToCompletion(&data); @@ -3523,7 +3432,7 @@ spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); scoped_ptr<SpdyFrame> goaway(spdy_util_.ConstructSpdyGoAway( 0, GOAWAY_PROTOCOL_ERROR, "Framer error: 1 (INVALID_CONTROL_FRAME).")); - MockWrite writes[] = {CreateMockWrite(*req), CreateMockWrite(*goaway)}; + MockWrite writes[] = {CreateMockWrite(*req, 0), CreateMockWrite(*goaway, 2)}; // Read WINDOW_UPDATE with incorrectly-sized payload. // TODO(jgraettinger): SpdyFramer signals this as an INVALID_CONTROL_FRAME, @@ -3533,9 +3442,9 @@ test::SetFrameLength(bad_window_update.get(), bad_window_update->size() - 1, spdy_util_.spdy_version()); - MockRead reads[] = {CreateMockRead(*bad_window_update)}; + MockRead reads[] = {CreateMockRead(*bad_window_update, 1)}; - DelayedSocketData data(1, reads, arraysize(reads), writes, arraysize(writes)); + SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); NormalSpdyTransactionHelper helper( CreateGetRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL); helper.RunToCompletion(&data); @@ -3584,17 +3493,19 @@ spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); const int kChunks = 5; scoped_ptr<MockWrite[]> writes(ChopWriteFrame(*req.get(), kChunks)); + for (int i = 0; i < kChunks; ++i) { + writes[i].sequence_number = i; + } scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true)); MockRead reads[] = { - CreateMockRead(*resp), - CreateMockRead(*body), - MockRead(ASYNC, 0, 0) // EOF + CreateMockRead(*resp, kChunks), + CreateMockRead(*body, kChunks + 1), + MockRead(ASYNC, 0, kChunks + 2) // EOF }; - DelayedSocketData data(kChunks, reads, arraysize(reads), - writes.get(), kChunks); + SequencedSocketData data(reads, arraysize(reads), writes.get(), kChunks); NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL); helper.RunToCompletion(&data); @@ -3615,16 +3526,16 @@ spdy_util_.ConstructSpdyGet(NULL, 0, true, 1, LOWEST, true)); scoped_ptr<SpdyFrame> goaway(spdy_util_.ConstructSpdyGoAway( 0, GOAWAY_COMPRESSION_ERROR, "Framer error: 5 (DECOMPRESS_FAILURE).")); - MockWrite writes[] = {CreateMockWrite(*compressed), CreateMockWrite(*goaway)}; + MockWrite writes[] = {CreateMockWrite(*compressed, 0), + CreateMockWrite(*goaway, 2)}; scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true)); MockRead reads[] = { - CreateMockRead(*resp), + CreateMockRead(*resp, 1), }; - DelayedSocketData data(1, reads, arraysize(reads), - writes, arraysize(writes)); + SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); SpdySessionDependencies* session_deps = CreateSpdySessionDependencies(GetParam()); session_deps->enable_compression = true; @@ -3643,20 +3554,19 @@ }; scoped_ptr<SpdyFrame> req( spdy_util_.ConstructSpdyGet(kExtraHeaders, 1, false, 1, LOWEST, true)); - MockWrite writes[] = { CreateMockWrite(*req) }; + MockWrite writes[] = {CreateMockWrite(*req, 0)}; scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true)); MockRead reads[] = { - CreateMockRead(*resp), - CreateMockRead(*body), - MockRead(ASYNC, 0, 0) // EOF + CreateMockRead(*resp, 1), + CreateMockRead(*body, 2), + MockRead(ASYNC, 0, 3) // EOF }; BoundTestNetLog log; - DelayedSocketData data(1, reads, arraysize(reads), - writes, arraysize(writes)); + SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); NormalSpdyTransactionHelper helper(CreateGetRequestWithUserAgent(), DEFAULT_PRIORITY, log.bound(), GetParam(), NULL); @@ -3735,7 +3645,7 @@ scoped_ptr<SpdyFrame> req( spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); - MockWrite writes[] = { CreateMockWrite(*req) }; + MockWrite writes[] = {CreateMockWrite(*req, 0)}; // 2 data frames in a single read. scoped_ptr<SpdyFrame> data_frame_1( @@ -3755,16 +3665,15 @@ scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); MockRead reads[] = { - CreateMockRead(*resp), - MockRead(ASYNC, ERR_IO_PENDING), // Force a pause - MockRead(ASYNC, combined_data_frames, combined_data_frames_len), - MockRead(ASYNC, ERR_IO_PENDING), // Force a pause - CreateMockRead(*last_frame), - MockRead(ASYNC, 0, 0) // EOF + CreateMockRead(*resp, 1), + MockRead(ASYNC, ERR_IO_PENDING, 2), // Force a pause + MockRead(ASYNC, combined_data_frames, combined_data_frames_len, 3), + MockRead(ASYNC, ERR_IO_PENDING, 4), // Force a pause + CreateMockRead(*last_frame, 5), + MockRead(ASYNC, 0, 6) // EOF }; - DelayedSocketData data(1, reads, arraysize(reads), - writes, arraysize(writes)); + SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); TestCompletionCallback callback; @@ -3829,7 +3738,7 @@ scoped_ptr<SpdyFrame> req( spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); - MockWrite writes[] = { CreateMockWrite(*req) }; + MockWrite writes[] = {CreateMockWrite(*req, 0)}; // 4 data frames in a single read. scoped_ptr<SpdyFrame> data_frame( @@ -3849,14 +3758,13 @@ scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); MockRead reads[] = { - CreateMockRead(*resp), - MockRead(ASYNC, ERR_IO_PENDING), // Force a pause - MockRead(ASYNC, combined_data_frames, combined_data_frames_len), - MockRead(ASYNC, 0, 0) // EOF + CreateMockRead(*resp, 1), + MockRead(ASYNC, ERR_IO_PENDING, 2), // Force a pause + MockRead(ASYNC, combined_data_frames, combined_data_frames_len, 3), + MockRead(ASYNC, 0, 4) // EOF }; - DelayedSocketData data(1, reads, arraysize(reads), - writes, arraysize(writes)); + SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL); @@ -3924,7 +3832,7 @@ scoped_ptr<SpdyFrame> req( spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); - MockWrite writes[] = { CreateMockWrite(*req) }; + MockWrite writes[] = {CreateMockWrite(*req, 0)}; // 5 data frames in a single read. scoped_ptr<SpdyFrame> reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); @@ -3940,12 +3848,11 @@ combined_frames, arraysize(combined_frames)); MockRead reads[] = { - MockRead(ASYNC, combined_frames, combined_frames_len), - MockRead(ASYNC, 0, 0) // EOF + MockRead(ASYNC, combined_frames, combined_frames_len, 1), + MockRead(ASYNC, 0, 2) // EOF }; - DelayedSocketData data(1, reads, arraysize(reads), - writes, arraysize(writes)); + SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL); @@ -4009,7 +3916,7 @@ scoped_ptr<SpdyFrame> req( spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); - MockWrite writes[] = { CreateMockWrite(*req) }; + MockWrite writes[] = {CreateMockWrite(*req, 0)}; // All data frames in a single read. // NOTE: We don't FIN the stream. @@ -4027,14 +3934,13 @@ combined_data_frames, arraysize(combined_data_frames)); scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); MockRead reads[] = { - CreateMockRead(*resp), - MockRead(ASYNC, ERR_IO_PENDING), // Force a wait - MockRead(ASYNC, combined_data_frames, combined_data_frames_len), - MockRead(ASYNC, 0, 0) // EOF + CreateMockRead(*resp, 1), + MockRead(ASYNC, ERR_IO_PENDING, 2), // Force a wait + MockRead(ASYNC, combined_data_frames, combined_data_frames_len, 3), + MockRead(ASYNC, 0, 4) // EOF }; - DelayedSocketData data(1, reads, arraysize(reads), - writes, arraysize(writes)); + SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL); @@ -4102,7 +4008,7 @@ spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); scoped_ptr<SpdyFrame> rst( spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL)); - MockWrite writes[] = {CreateMockWrite(*req), CreateMockWrite(*rst)}; + MockWrite writes[] = {CreateMockWrite(*req, 0), CreateMockWrite(*rst, 4)}; // NOTE: We don't FIN the stream. scoped_ptr<SpdyFrame> data_frame( @@ -4110,14 +4016,13 @@ scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); MockRead reads[] = { - CreateMockRead(*resp), - MockRead(ASYNC, ERR_IO_PENDING), // Force a wait - CreateMockRead(*data_frame), - MockRead(ASYNC, 0, 0) // EOF + CreateMockRead(*resp, 1), + MockRead(ASYNC, ERR_IO_PENDING, 2), // Force a wait + CreateMockRead(*data_frame, 3), + MockRead(ASYNC, 0, 5) // EOF }; - DelayedSocketData data(1, reads, arraysize(reads), - writes, arraysize(writes)); + SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL); @@ -4198,7 +4103,7 @@ // Construct the request. scoped_ptr<SpdyFrame> req( spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); - MockWrite writes[] = { CreateMockWrite(*req) }; + MockWrite writes[] = {CreateMockWrite(*req, 0)}; // Construct the reply. scoped_ptr<SpdyHeaderBlock> reply_headers(new SpdyHeaderBlock()); @@ -4231,14 +4136,13 @@ scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true)); MockRead reads[] = { - CreateMockRead(*reply), - CreateMockRead(*body), - CreateMockRead(*settings_frame), - MockRead(ASYNC, 0, 0) // EOF + CreateMockRead(*reply, 1), + CreateMockRead(*body, 2), + CreateMockRead(*settings_frame, 3), + MockRead(ASYNC, 0, 4) // EOF }; - DelayedSocketData data(1, reads, arraysize(reads), - writes, arraysize(writes)); + SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); helper.AddData(&data); helper.RunDefaultTest(); helper.VerifyDataConsumed(); @@ -4347,17 +4251,11 @@ scoped_ptr<SpdyFrame> req( spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); - std::vector<MockWrite> writes; - if ((GetParam().protocol >= kProtoSPDY4MinimumVersion) && - (GetParam().protocol <= kProtoSPDY4MaximumVersion)) { - writes.push_back( - MockWrite(ASYNC, - kHttp2ConnectionHeaderPrefix, - kHttp2ConnectionHeaderPrefixSize)); - } - writes.push_back(CreateMockWrite(*initial_settings_frame)); - writes.push_back(CreateMockWrite(*settings_frame)); - writes.push_back(CreateMockWrite(*req)); + MockWrite writes[] = { + CreateMockWrite(*initial_settings_frame, 0), + CreateMockWrite(*settings_frame, 1), + CreateMockWrite(*req, 2), + }; // Construct the reply. scoped_ptr<SpdyHeaderBlock> reply_headers(new SpdyHeaderBlock()); @@ -4368,13 +4266,12 @@ scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true)); MockRead reads[] = { - CreateMockRead(*reply), - CreateMockRead(*body), - MockRead(ASYNC, 0, 0) // EOF + CreateMockRead(*reply, 3), + CreateMockRead(*body, 4), + MockRead(ASYNC, 0, 5) // EOF }; - DelayedSocketData data(2, reads, arraysize(reads), - vector_as_array(&writes), writes.size()); + SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); helper.AddData(&data); helper.RunDefaultTest(); helper.VerifyDataConsumed(); @@ -4409,15 +4306,14 @@ TEST_P(SpdyNetworkTransactionTest, GoAwayWithActiveStream) { scoped_ptr<SpdyFrame> req( spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); - MockWrite writes[] = { CreateMockWrite(*req) }; + MockWrite writes[] = {CreateMockWrite(*req, 0)}; scoped_ptr<SpdyFrame> go_away(spdy_util_.ConstructSpdyGoAway()); MockRead reads[] = { - CreateMockRead(*go_away), + CreateMockRead(*go_away, 1), }; - DelayedSocketData data(1, reads, arraysize(reads), - writes, arraysize(writes)); + SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL); helper.AddData(&data); @@ -4429,16 +4325,14 @@ TEST_P(SpdyNetworkTransactionTest, CloseWithActiveStream) { scoped_ptr<SpdyFrame> req( spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); - MockWrite writes[] = { CreateMockWrite(*req) }; + MockWrite writes[] = {CreateMockWrite(*req, 0)}; scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); MockRead reads[] = { - CreateMockRead(*resp), - MockRead(SYNCHRONOUS, 0, 0) // EOF + CreateMockRead(*resp, 1), MockRead(SYNCHRONOUS, 0, 2) // EOF }; - DelayedSocketData data(1, reads, arraysize(reads), - writes, arraysize(writes)); + SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); BoundNetLog log; NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, log, GetParam(), NULL); @@ -4476,9 +4370,9 @@ scoped_ptr<SpdyFrame> go_away(spdy_util_.ConstructSpdyGoAway( 0, GOAWAY_HTTP_1_1_REQUIRED, "Try again using HTTP/1.1 please.")); MockRead reads[] = { - CreateMockRead(*go_away), + CreateMockRead(*go_away, 0), }; - DelayedSocketData data(0, reads, arraysize(reads), nullptr, 0); + SequencedSocketData data(reads, arraysize(reads), nullptr, 0); helper.RunToCompletion(&data); TransactionHelperResult out = helper.output(); @@ -4512,12 +4406,12 @@ scoped_ptr<SpdyHeaderBlock> headers(spdy_util_.ConstructGetHeaderBlock(url)); scoped_ptr<SpdyFrame> req( spdy_util_.ConstructSpdySyn(1, *headers, LOWEST, false, true)); - MockWrite writes0[] = {CreateMockWrite(*req)}; + MockWrite writes0[] = {CreateMockWrite(*req, 0)}; scoped_ptr<SpdyFrame> go_away(spdy_util_.ConstructSpdyGoAway( 0, GOAWAY_HTTP_1_1_REQUIRED, "Try again using HTTP/1.1 please.")); - MockRead reads0[] = {CreateMockRead(*go_away)}; - DelayedSocketData data0(1, reads0, arraysize(reads0), writes0, - arraysize(writes0)); + MockRead reads0[] = {CreateMockRead(*go_away, 1)}; + SequencedSocketData data0(reads0, arraysize(reads0), writes0, + arraysize(writes0)); scoped_ptr<SSLSocketDataProvider> ssl_provider0( new SSLSocketDataProvider(ASYNC, OK)); @@ -4531,16 +4425,16 @@ helper.AddDataWithSSLSocketDataProvider(&data0, ssl_provider0.Pass()); // Second socket: falling back to HTTP/1.1. - MockWrite writes1[] = {MockWrite( - "GET / HTTP/1.1\r\n" - "Host: www.example.org\r\n" - "Connection: keep-alive\r\n\r\n")}; - MockRead reads1[] = {MockRead( - "HTTP/1.1 200 OK\r\n" - "Content-Length: 5\r\n\r\n" - "hello")}; - DelayedSocketData data1(1, reads1, arraysize(reads1), writes1, - arraysize(writes1)); + MockWrite writes1[] = {MockWrite(ASYNC, 0, + "GET / HTTP/1.1\r\n" + "Host: www.example.org\r\n" + "Connection: keep-alive\r\n\r\n")}; + MockRead reads1[] = {MockRead(ASYNC, 1, + "HTTP/1.1 200 OK\r\n" + "Content-Length: 5\r\n\r\n" + "hello")}; + SequencedSocketData data1(reads1, arraysize(reads1), writes1, + arraysize(writes1)); scoped_ptr<SSLSocketDataProvider> ssl_provider1( new SSLSocketDataProvider(ASYNC, OK)); @@ -4603,12 +4497,12 @@ // First socket: HTTP/2 CONNECT rejected with HTTP_1_1_REQUIRED. scoped_ptr<SpdyFrame> req(spdy_util_.ConstructSpdyConnect( nullptr, 0, 1, LOWEST, HostPortPair("www.example.org", 443))); - MockWrite writes0[] = {CreateMockWrite(*req)}; + MockWrite writes0[] = {CreateMockWrite(*req, 0)}; scoped_ptr<SpdyFrame> go_away(spdy_util_.ConstructSpdyGoAway( 0, GOAWAY_HTTP_1_1_REQUIRED, "Try again using HTTP/1.1 please.")); - MockRead reads0[] = {CreateMockRead(*go_away)}; - DelayedSocketData data0(1, reads0, arraysize(reads0), writes0, - arraysize(writes0)); + MockRead reads0[] = {CreateMockRead(*go_away, 1)}; + SequencedSocketData data0(reads0, arraysize(reads0), writes0, + arraysize(writes0)); scoped_ptr<SSLSocketDataProvider> ssl_provider0( new SSLSocketDataProvider(ASYNC, OK)); @@ -4623,25 +4517,25 @@ // Second socket: retry using HTTP/1.1. MockWrite writes1[] = { - MockWrite(ASYNC, 1, + MockWrite(ASYNC, 0, "CONNECT www.example.org:443 HTTP/1.1\r\n" "Host: www.example.org\r\n" "Proxy-Connection: keep-alive\r\n\r\n"), - MockWrite(ASYNC, 3, + MockWrite(ASYNC, 2, "GET / HTTP/1.1\r\n" "Host: www.example.org\r\n" "Connection: keep-alive\r\n\r\n"), }; MockRead reads1[] = { - MockRead(ASYNC, 2, "HTTP/1.1 200 OK\r\n\r\n"), - MockRead(ASYNC, 4, + MockRead(ASYNC, 1, "HTTP/1.1 200 OK\r\n\r\n"), + MockRead(ASYNC, 3, "HTTP/1.1 200 OK\r\n" "Content-Length: 5\r\n\r\n" "hello"), }; - DelayedSocketData data1(1, reads1, arraysize(reads1), writes1, - arraysize(writes1)); + SequencedSocketData data1(reads1, arraysize(reads1), writes1, + arraysize(writes1)); scoped_ptr<SSLSocketDataProvider> ssl_provider1( new SSLSocketDataProvider(ASYNC, OK)); @@ -4715,7 +4609,7 @@ CreateMockRead(*body.get(), 4), MockRead(ASYNC, 0, 0, 5), }; - scoped_ptr<OrderedSocketData> data(new OrderedSocketData( + scoped_ptr<SequencedSocketData> data(new SequencedSocketData( reads, arraysize(reads), writes, arraysize(writes))); helper.AddData(data.get()); @@ -4765,19 +4659,17 @@ scoped_ptr<SpdyFrame> req( spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); MockWrite writes[] = { - CreateMockWrite(*req, 1), + CreateMockWrite(*req, 0), }; scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true)); MockRead reads[] = { - CreateMockRead(*resp, 2), - CreateMockRead(*body, 3), - MockRead(ASYNC, ERR_IO_PENDING, 4), // Force a pause - MockRead(ASYNC, 0, 5) // EOF + CreateMockRead(*resp, 1), + CreateMockRead(*body, 2), + MockRead(SYNCHRONOUS, ERR_IO_PENDING, 3), // Force a pause }; - OrderedSocketData data(reads, arraysize(reads), - writes, arraysize(writes)); + SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); helper.AddData(&data); HttpNetworkTransaction* trans = helper.trans(); @@ -4832,7 +4724,7 @@ MockRead(ASYNC, 0, 5) // EOF }; - scoped_ptr<OrderedSocketData> data_proxy(new OrderedSocketData( + scoped_ptr<SequencedSocketData> data_proxy(new SequencedSocketData( reads2, arraysize(reads2), writes2, arraysize(writes2))); // Create another request to www.example.org, but this time through a proxy. @@ -4872,7 +4764,6 @@ ASSERT_EQ(OK, ReadTransaction(trans_proxy, &response_data)); EXPECT_EQ("hello!", response_data); - data.CompleteRead(); helper_proxy.VerifyDataConsumed(); } @@ -4884,33 +4775,41 @@ scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true)); MockRead reads[] = { - CreateMockRead(*resp), - CreateMockRead(*body), - MockRead(ASYNC, ERR_IO_PENDING), - MockRead(ASYNC, ERR_CONNECTION_RESET), + CreateMockRead(*resp, 1), + CreateMockRead(*body, 2), + MockRead(ASYNC, ERR_IO_PENDING, 3), + MockRead(ASYNC, ERR_CONNECTION_RESET, 4), }; MockRead reads2[] = { - CreateMockRead(*resp), - CreateMockRead(*body), - MockRead(ASYNC, 0, 0) // EOF + CreateMockRead(*resp, 1), + CreateMockRead(*body, 2), + MockRead(ASYNC, 0, 3) // EOF }; + scoped_ptr<SpdyFrame> req( + spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); + scoped_ptr<SpdyFrame> req3( + spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, LOWEST, true)); + MockWrite writes1[] = {CreateMockWrite(*req, 0), CreateMockWrite(*req3, 5)}; + MockWrite writes2[] = {CreateMockWrite(*req, 0)}; + // This test has a couple of variants. enum { // Induce the RST while waiting for our transaction to send. - VARIANT_RST_DURING_SEND_COMPLETION, + VARIANT_RST_DURING_SEND_COMPLETION = 0, // Induce the RST while waiting for our transaction to read. // In this case, the send completed - everything copied into the SNDBUF. - VARIANT_RST_DURING_READ_COMPLETION + VARIANT_RST_DURING_READ_COMPLETION = 1 }; for (int variant = VARIANT_RST_DURING_SEND_COMPLETION; variant <= VARIANT_RST_DURING_READ_COMPLETION; ++variant) { - DelayedSocketData data1(1, reads, arraysize(reads), NULL, 0); + SequencedSocketData data1(reads, arraysize(reads), writes1, 1 + variant); - DelayedSocketData data2(1, reads2, arraysize(reads2), NULL, 0); + SequencedSocketData data2(reads2, arraysize(reads2), writes2, + arraysize(writes2)); NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL); @@ -4935,9 +4834,7 @@ } // Now schedule the ERR_CONNECTION_RESET. - EXPECT_EQ(3u, data1.read_index()); data1.CompleteRead(); - EXPECT_EQ(4u, data1.read_index()); } rv = callback.WaitForResult(); EXPECT_EQ(OK, rv); @@ -4951,9 +4848,11 @@ EXPECT_EQ(OK, rv); EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); EXPECT_EQ("hello!", response_data); + base::RunLoop().RunUntilIdle(); } helper.VerifyDataConsumed(); + base::RunLoop().RunUntilIdle(); } } @@ -4962,18 +4861,18 @@ HttpStreamFactory::set_spdy_enabled(true); scoped_ptr<SpdyFrame> req( spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); - MockWrite spdy_writes[] = { CreateMockWrite(*req) }; + MockWrite spdy_writes[] = {CreateMockWrite(*req, 0)}; scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true)); MockRead spdy_reads[] = { - CreateMockRead(*resp), - CreateMockRead(*body), - MockRead(ASYNC, 0, 0) // EOF + CreateMockRead(*resp, 1), + CreateMockRead(*body, 2), + MockRead(ASYNC, 0, 3) // EOF }; - DelayedSocketData data(1, spdy_reads, arraysize(spdy_reads), - spdy_writes, arraysize(spdy_writes)); + SequencedSocketData data(spdy_reads, arraysize(spdy_reads), spdy_writes, + arraysize(spdy_writes)); NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL); helper.RunToCompletion(&data); @@ -4983,12 +4882,20 @@ EXPECT_EQ("hello!", out.response_data); HttpStreamFactory::set_spdy_enabled(false); - MockRead http_reads[] = { - MockRead("HTTP/1.1 200 OK\r\n\r\n"), - MockRead("hello from http"), - MockRead(SYNCHRONOUS, OK), + MockWrite http_writes[] = { + MockWrite(SYNCHRONOUS, 0, + "GET / HTTP/1.1\r\n" + "Host: www.example.org\r\n" + "Connection: keep-alive\r\n\r\n"), }; - DelayedSocketData data2(1, http_reads, arraysize(http_reads), NULL, 0); + + MockRead http_reads[] = { + MockRead(SYNCHRONOUS, 1, "HTTP/1.1 200 OK\r\n\r\n"), + MockRead(SYNCHRONOUS, 2, "hello from http"), + MockRead(SYNCHRONOUS, OK, 3), + }; + SequencedSocketData data2(http_reads, arraysize(http_reads), http_writes, + arraysize(http_writes)); NormalSpdyTransactionHelper helper2(CreateGetRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL); helper2.SetSpdyDisabled(); @@ -5017,8 +4924,7 @@ arraysize(kExtraAuthorizationHeaders) / 2, false, 3, LOWEST, true)); MockWrite spdy_writes[] = { - CreateMockWrite(*req_get, 1), - CreateMockWrite(*req_get_authorization, 4), + CreateMockWrite(*req_get, 0), CreateMockWrite(*req_get_authorization, 3), }; // The first response is a 401 authentication challenge, and the second @@ -5040,15 +4946,15 @@ spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3)); scoped_ptr<SpdyFrame> body_data(spdy_util_.ConstructSpdyBodyFrame(3, true)); MockRead spdy_reads[] = { - CreateMockRead(*resp_authentication, 2), - CreateMockRead(*body_authentication, 3), - CreateMockRead(*resp_data, 5), - CreateMockRead(*body_data, 6), - MockRead(ASYNC, 0, 7), + CreateMockRead(*resp_authentication, 1), + CreateMockRead(*body_authentication, 2), + CreateMockRead(*resp_data, 4), + CreateMockRead(*body_data, 5), + MockRead(ASYNC, 0, 6), }; - OrderedSocketData data(spdy_reads, arraysize(spdy_reads), - spdy_writes, arraysize(spdy_writes)); + SequencedSocketData data(spdy_reads, arraysize(spdy_reads), spdy_writes, + arraysize(spdy_writes)); HttpRequestInfo request(CreateGetRequest()); BoundNetLog net_log; NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY, @@ -5099,7 +5005,7 @@ scoped_ptr<SpdyFrame> stream1_body( spdy_util_.ConstructSpdyBodyFrame(1, true)); MockWrite writes[] = { - CreateMockWrite(*stream1_syn, 1), + CreateMockWrite(*stream1_syn, 0), }; scoped_ptr<SpdyHeaderBlock> initial_headers(new SpdyHeaderBlock()); @@ -5128,19 +5034,18 @@ spdy_util_.ConstructSpdyBodyFrame( 2, kPushedData, strlen(kPushedData), true)); MockRead reads[] = { - CreateMockRead(*stream1_reply, 2), - CreateMockRead(*stream2_syn, 3), - CreateMockRead(*stream2_headers, 4), - CreateMockRead(*stream1_body, 5, SYNCHRONOUS), - CreateMockRead(*stream2_body, 5), - MockRead(ASYNC, ERR_IO_PENDING, 7), // Force a pause + CreateMockRead(*stream1_reply, 1), + CreateMockRead(*stream2_syn, 2), + CreateMockRead(*stream2_headers, 3), + CreateMockRead(*stream1_body, 4, SYNCHRONOUS), + CreateMockRead(*stream2_body, 5), + MockRead(SYNCHRONOUS, ERR_IO_PENDING, 6), // Force a pause }; HttpResponseInfo response; HttpResponseInfo response2; std::string expected_push_result("pushed"); - OrderedSocketData data(reads, arraysize(reads), - writes, arraysize(writes)); + SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); RunServerPushTest(&data, &response, &response2, @@ -5526,7 +5431,7 @@ scoped_ptr<SpdyFrame> rst( spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR)); MockWrite writes[] = { - CreateMockWrite(*req), CreateMockWrite(*rst), + CreateMockWrite(*req, 0), CreateMockWrite(*rst, 4), }; scoped_ptr<SpdyFrame> stream1_reply( @@ -5545,14 +5450,13 @@ scoped_ptr<SpdyFrame> stream1_body( spdy_util_.ConstructSpdyBodyFrame(1, true)); MockRead reads[] = { - CreateMockRead(*stream1_reply), - CreateMockRead(*stream1_headers), - CreateMockRead(*stream1_body), - MockRead(ASYNC, 0, 0) // EOF + CreateMockRead(*stream1_reply, 1), + CreateMockRead(*stream1_headers, 2), + CreateMockRead(*stream1_body, 3), + MockRead(ASYNC, 0, 5) // EOF }; - DelayedSocketData data(1, reads, arraysize(reads), - writes, arraysize(writes)); + SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL); helper.RunToCompletion(&data); @@ -5566,8 +5470,7 @@ scoped_ptr<SpdyFrame> rst( spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR)); MockWrite writes[] = { - CreateMockWrite(*req), - CreateMockWrite(*rst), + CreateMockWrite(*req, 0), CreateMockWrite(*rst, 4), }; scoped_ptr<SpdyFrame> stream1_reply( @@ -5588,15 +5491,14 @@ scoped_ptr<SpdyFrame> stream1_body2( spdy_util_.ConstructSpdyBodyFrame(1, true)); MockRead reads[] = { - CreateMockRead(*stream1_reply), - CreateMockRead(*stream1_body), - CreateMockRead(*stream1_headers), - CreateMockRead(*stream1_body2), - MockRead(ASYNC, 0, 0) // EOF + CreateMockRead(*stream1_reply, 1), + CreateMockRead(*stream1_body, 2), + CreateMockRead(*stream1_headers, 3), + CreateMockRead(*stream1_body2, 5), + MockRead(ASYNC, 0, 6) // EOF }; - DelayedSocketData data(1, reads, arraysize(reads), - writes, arraysize(writes)); + SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL); helper.RunToCompletion(&data); @@ -5644,8 +5546,7 @@ scoped_ptr<SpdyFrame> push_rst( spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_REFUSED_STREAM)); MockWrite writes[] = { - CreateMockWrite(*stream1_syn, 1), - CreateMockWrite(*push_rst, 4), + CreateMockWrite(*stream1_syn, 0), CreateMockWrite(*push_rst, 3), }; scoped_ptr<SpdyFrame> @@ -5664,16 +5565,16 @@ spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_CANCEL)); MockRead reads[] = { - CreateMockRead(*stream1_reply, 2), - CreateMockRead(*stream2_syn, 3), - CreateMockRead(*stream1_body, 5, SYNCHRONOUS), - CreateMockRead(*stream2_body, 6), - MockRead(ASYNC, ERR_IO_PENDING, 7), // Force a pause + CreateMockRead(*stream1_reply, 1), + CreateMockRead(*stream2_syn, 2), + CreateMockRead(*stream1_body, 4), + CreateMockRead(*stream2_body, 5), + MockRead(SYNCHRONOUS, ERR_IO_PENDING, 6), // Force a pause }; HttpResponseInfo response; - OrderedSocketData data(reads, arraysize(reads), - writes, arraysize(writes)); + SequencedSocketData data(reads, arraysize(reads), writes, + arraysize(writes)); HttpRequestInfo request; request.method = "GET"; @@ -5727,8 +5628,7 @@ scoped_ptr<SpdyFrame> req2( spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, LOWEST, true)); MockWrite writes[] = { - CreateMockWrite(*req, 1), - CreateMockWrite(*req2, 3), + CreateMockWrite(*req, 0), CreateMockWrite(*req2, 2), }; scoped_ptr<SpdyFrame> refused( @@ -5736,14 +5636,13 @@ scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3)); scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(3, true)); MockRead reads[] = { - CreateMockRead(*refused, 2), - CreateMockRead(*resp, 4), - CreateMockRead(*body, 5), - MockRead(ASYNC, 0, 6) // EOF + CreateMockRead(*refused, 1), + CreateMockRead(*resp, 3), + CreateMockRead(*body, 4), + MockRead(ASYNC, 0, 5) // EOF }; - OrderedSocketData data(reads, arraysize(reads), - writes, arraysize(writes)); + SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL); @@ -5761,14 +5660,8 @@ EXPECT_EQ(OK, rv); // Verify that we consumed all test data. - EXPECT_TRUE(data.at_read_eof()) << "Read count: " - << data.read_count() - << " Read index: " - << data.read_index(); - EXPECT_TRUE(data.at_write_eof()) << "Write count: " - << data.write_count() - << " Write index: " - << data.write_index(); + EXPECT_TRUE(data.AllReadDataConsumed()); + EXPECT_TRUE(data.AllWriteDataConsumed()); // Verify the SYN_REPLY. HttpResponseInfo response = *trans->GetResponseInfo(); @@ -6029,16 +5922,14 @@ writes.push_back(MockWrite(ASYNC, kHttp2ConnectionHeaderPrefix, kHttp2ConnectionHeaderPrefixSize, 0)); } - writes.push_back(CreateMockWrite(*initial_settings_frame)); - writes.push_back(CreateMockWrite(*initial_window_update)); - writes.push_back(CreateMockWrite(*req)); - writes.push_back(CreateMockWrite(*session_window_update)); - writes.push_back(CreateMockWrite(*stream_window_update)); + writes.push_back(CreateMockWrite(*initial_settings_frame, writes.size())); + writes.push_back(CreateMockWrite(*initial_window_update, writes.size())); + writes.push_back(CreateMockWrite(*req, writes.size())); std::vector<MockRead> reads; scoped_ptr<SpdyFrame> resp( spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); - reads.push_back(CreateMockRead(*resp)); + reads.push_back(CreateMockRead(*resp, writes.size() + reads.size())); ScopedVector<SpdyFrame> body_frames; const std::string body_data(kChunkSize, 'x'); @@ -6046,13 +5937,20 @@ size_t frame_size = std::min(remaining, body_data.size()); body_frames.push_back(spdy_util_.ConstructSpdyBodyFrame( 1, body_data.data(), frame_size, false)); - reads.push_back(CreateMockRead(*body_frames.back())); + reads.push_back( + CreateMockRead(*body_frames.back(), writes.size() + reads.size())); remaining -= frame_size; } - reads.push_back(MockRead(ASYNC, ERR_IO_PENDING, 0)); // Yield. + reads.push_back( + MockRead(ASYNC, ERR_IO_PENDING, writes.size() + reads.size())); // Yield. - DelayedSocketData data(2, vector_as_array(&reads), reads.size(), - vector_as_array(&writes), writes.size()); + writes.push_back( + CreateMockWrite(*session_window_update, writes.size() + reads.size())); + writes.push_back( + CreateMockWrite(*stream_window_update, writes.size() + reads.size())); + + SequencedSocketData data(vector_as_array(&reads), reads.size(), + vector_as_array(&writes), writes.size()); NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL); @@ -6174,9 +6072,9 @@ // This test constructs a POST request followed by enough data frames // containing 'a' that would make the window size 0, followed by another // data frame containing default content (which is "hello!") and this frame -// also contains a FIN flag. DelayedSocketData is used to enforce all -// writes go through before a read could happen. However, the last frame -// ("hello!") is not supposed to go through since by the time its turn +// also contains a FIN flag. SequencedSocketData is used to enforce all +// writes, save the last, go through before a read could happen. The last frame +// ("hello!") is not permitted to go through since by the time its turn // arrives, window size is 0. At this point MessageLoop::Run() called via // callback would block. Therefore we call MessageLoop::RunUntilIdle() // which returns after performing all possible writes. We use DCHECKS to @@ -6218,11 +6116,13 @@ // Fill in mock writes. scoped_ptr<MockWrite[]> writes(new MockWrite[num_writes]); size_t i = 0; - writes[i] = CreateMockWrite(*req); + writes[i] = CreateMockWrite(*req, i); for (i = 1; i < num_writes - 2; i++) - writes[i] = CreateMockWrite(*body1); - writes[i++] = CreateMockWrite(*body2); - writes[i] = CreateMockWrite(*body3); + writes[i] = CreateMockWrite(*body1, i); + writes[i] = CreateMockWrite(*body2, i); + // The last write must not be attempted until after the WINDOW_UPDATES + // have been received. + writes[i + 1] = CreateMockWrite(*body3, i + 4, SYNCHRONOUS); // Construct read frame, give enough space to upload the rest of the // data. @@ -6232,25 +6132,17 @@ spdy_util_.ConstructSpdyWindowUpdate(1, kUploadDataSize)); scoped_ptr<SpdyFrame> reply(spdy_util_.ConstructSpdyPostSynReply(NULL, 0)); MockRead reads[] = { - CreateMockRead(*session_window_update), - CreateMockRead(*session_window_update), - CreateMockRead(*window_update), - CreateMockRead(*window_update), - CreateMockRead(*reply), - CreateMockRead(*body2), - CreateMockRead(*body3), - MockRead(ASYNC, 0, 0) // EOF + MockRead(ASYNC, ERR_IO_PENDING, i + 1), // Force a pause + CreateMockRead(*session_window_update, i + 2), + CreateMockRead(*window_update, i + 3), + // Now the last write will occur. + CreateMockRead(*reply, i + 5), + CreateMockRead(*body2, i + 6), + CreateMockRead(*body3, i + 7), + MockRead(ASYNC, 0, i + 8) // EOF }; - // Skip the session window updates unless we're using SPDY/3.1 and - // above. - size_t read_offset = (GetParam().protocol >= kProtoSPDY31) ? 0 : 2; - size_t num_reads = arraysize(reads) - read_offset; - - // Force all writes to happen before any read, last write will not - // actually queue a frame, due to window size being 0. - DelayedSocketData data(num_writes, reads + read_offset, num_reads, - writes.get(), num_writes); + SequencedSocketData data(reads, arraysize(reads), writes.get(), num_writes); ScopedVector<UploadElementReader> element_readers; std::string upload_data_string(initial_window_size, 'a'); @@ -6288,7 +6180,7 @@ // since we're send-stalled. EXPECT_TRUE(stream->stream()->send_stalled_by_flow_control()); - data.ForceNextRead(); // Read in WINDOW_UPDATE frame. + data.CompleteRead(); // Read in WINDOW_UPDATE frame. rv = callback.WaitForResult(); helper.VerifyDataConsumed(); } @@ -6551,7 +6443,7 @@ CreateMockWrite(*req, 0), CreateMockWrite(*goaway, 2), }; - DelayedSocketData data(1, reads, arraysize(reads), writes, arraysize(writes)); + SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); NormalSpdyTransactionHelper helper( CreateGetRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL); helper.RunToCompletion(&data); @@ -6585,7 +6477,7 @@ CreateMockWrite(*req, 0), CreateMockWrite(*goaway, 3), }; - DelayedSocketData data(1, reads, arraysize(reads), writes, arraysize(writes)); + SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); NormalSpdyTransactionHelper helper( CreateGetRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL); helper.RunToCompletion(&data); @@ -6600,17 +6492,18 @@ // Construct the request. scoped_ptr<SpdyFrame> req( spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); - MockWrite writes[] = {CreateMockWrite(*req)}; + MockWrite writes[] = {CreateMockWrite(*req, 0)}; scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true)); MockRead reads[] = { - CreateMockRead(*resp), CreateMockRead(*body), - MockRead(ASYNC, 0, 0) // EOF + CreateMockRead(*resp, 1), + CreateMockRead(*body, 2), + MockRead(ASYNC, 0, 3) // EOF }; - DelayedSocketData data( - 1, reads, arraysize(reads), writes, arraysize(writes)); + SequencedSocketData data(reads, arraysize(reads), writes, + arraysize(writes)); HttpRequestInfo request; request.method = "GET"; request.url = GURL("https://www.example.org/"); @@ -6662,7 +6555,7 @@ spdy_util_.ConstructSpdyGoAway(0, GOAWAY_INADEQUATE_SECURITY, "")); MockWrite writes[] = {CreateMockWrite(*goaway)}; - DelayedSocketData data(1, NULL, 0, writes, arraysize(writes)); + StaticSocketDataProvider data(NULL, 0, writes, arraysize(writes)); HttpRequestInfo request; request.method = "GET"; request.url = GURL("https://www.example.org/");
diff --git a/net/spdy/spdy_protocol.h b/net/spdy/spdy_protocol.h index 1837feb2..f4d2222 100644 --- a/net/spdy/spdy_protocol.h +++ b/net/spdy/spdy_protocol.h
@@ -999,10 +999,10 @@ parent_stream_id_(0), weight_(1), exclusive_(false) {} - explicit SpdyPriorityIR(SpdyStreamId stream_id, - SpdyStreamId parent_stream_id, - uint8 weight, - bool exclusive) + SpdyPriorityIR(SpdyStreamId stream_id, + SpdyStreamId parent_stream_id, + uint8 weight, + bool exclusive) : SpdyFrameWithStreamIdIR(stream_id), parent_stream_id_(parent_stream_id), weight_(weight),
diff --git a/net/spdy/write_blocked_list.h b/net/spdy/write_blocked_list.h index c6d60b3..bb3bcfff 100644 --- a/net/spdy/write_blocked_list.h +++ b/net/spdy/write_blocked_list.h
@@ -28,8 +28,7 @@ typedef std::deque<IdType> BlockedList; typedef typename BlockedList::iterator iterator; - explicit WriteBlockedList(bool use_stream_to_priority_map) - : use_stream_to_priority_(use_stream_to_priority_map) {} + WriteBlockedList() {} static SpdyPriority ClampPriority(SpdyPriority priority) { if (priority < kHighestPriority) { @@ -58,9 +57,7 @@ DCHECK(!write_blocked_lists_[priority].empty()); IdType stream_id = write_blocked_lists_[priority].front(); write_blocked_lists_[priority].pop_front(); - if (use_stream_to_priority_) { - stream_to_priority_.erase(stream_id); - } + stream_to_priority_.erase(stream_id); return stream_id; } @@ -88,44 +85,38 @@ DVLOG(2) << "Adding stream " << stream_id << " at priority " << static_cast<int>(priority); bool should_insert_stream = true; - if (use_stream_to_priority_) { - typename StreamToPriorityMap::iterator iter = - stream_to_priority_.find(stream_id); - if (iter != stream_to_priority_.end()) { - DVLOG(1) << "Stream " << stream_id << " already in write blocked list."; - if (iter->second == priority) { - // The stream is already in the write blocked list for the priority. - should_insert_stream = false; - } else { - // The stream is in a write blocked list for a different priority. - bool removed = - RemoveStreamFromWriteBlockedList(stream_id, iter->second); - DCHECK(removed); - } + typename StreamToPriorityMap::iterator iter = + stream_to_priority_.find(stream_id); + if (iter != stream_to_priority_.end()) { + DVLOG(1) << "Stream " << stream_id << " already in write blocked list."; + if (iter->second == priority) { + // The stream is already in the write blocked list for the priority. + should_insert_stream = false; + } else { + // The stream is in a write blocked list for a different priority. + bool removed = + RemoveStreamFromWriteBlockedList(stream_id, iter->second); + DCHECK(removed); } - if (should_insert_stream) { - stream_to_priority_[stream_id] = priority; - write_blocked_lists_[priority].push_back(stream_id); - } - } else { + } + if (should_insert_stream) { + stream_to_priority_[stream_id] = priority; write_blocked_lists_[priority].push_back(stream_id); } } bool RemoveStreamFromWriteBlockedList(IdType stream_id, SpdyPriority priority) { - if (use_stream_to_priority_) { - typename StreamToPriorityMap::iterator iter = - stream_to_priority_.find(stream_id); - if (iter == stream_to_priority_.end()) { - // The stream is not present in the write blocked list. - return false; - } else if (iter->second == priority) { - stream_to_priority_.erase(iter); - } else { - // The stream is not present at the specified priority level. - return false; - } + typename StreamToPriorityMap::iterator iter = + stream_to_priority_.find(stream_id); + if (iter == stream_to_priority_.end()) { + // The stream is not present in the write blocked list. + return false; + } else if (iter->second == priority) { + stream_to_priority_.erase(iter); + } else { + // The stream is not present at the specified priority level. + return false; } // We shouldn't really add a stream_id to a list multiple times, // but under some conditions it does happen. Doing a check in PushBack @@ -161,8 +152,6 @@ return num_blocked_streams; } - bool avoids_inserting_duplicates() const { return use_stream_to_priority_; } - private: friend class net::test::WriteBlockedListPeer; @@ -170,7 +159,6 @@ BlockedList write_blocked_lists_[kLowestPriority + 1]; StreamToPriorityMap stream_to_priority_; - bool use_stream_to_priority_; }; } // namespace net
diff --git a/net/spdy/write_blocked_list_test.cc b/net/spdy/write_blocked_list_test.cc index 50c3f35..20a1b7e4 100644 --- a/net/spdy/write_blocked_list_test.cc +++ b/net/spdy/write_blocked_list_test.cc
@@ -23,14 +23,12 @@ typedef WriteBlockedList<int> IntWriteBlockedList; -class WriteBlockedListTest : public ::testing::TestWithParam<bool> { +class WriteBlockedListTest : public ::testing::Test { public: - WriteBlockedListTest() : list(GetParam()) {} - IntWriteBlockedList list; }; -TEST_P(WriteBlockedListTest, GetHighestPriority) { +TEST_F(WriteBlockedListTest, GetHighestPriority) { EXPECT_FALSE(list.HasWriteBlockedStreams()); list.PushBack(1, 1); EXPECT_TRUE(list.HasWriteBlockedStreams()); @@ -40,7 +38,7 @@ EXPECT_EQ(0, list.GetHighestPriorityWriteBlockedList()); } -TEST_P(WriteBlockedListTest, HasWriteBlockedStreamsOfGreaterThanPriority) { +TEST_F(WriteBlockedListTest, HasWriteBlockedStreamsOfGreaterThanPriority) { list.PushBack(1, 4); EXPECT_TRUE(list.HasWriteBlockedStreamsGreaterThanPriority(5)); EXPECT_FALSE(list.HasWriteBlockedStreamsGreaterThanPriority(4)); @@ -49,7 +47,7 @@ EXPECT_FALSE(list.HasWriteBlockedStreamsGreaterThanPriority(2)); } -TEST_P(WriteBlockedListTest, RemoveStreamFromWriteBlockedList) { +TEST_F(WriteBlockedListTest, RemoveStreamFromWriteBlockedList) { list.PushBack(1, 4); EXPECT_TRUE(list.HasWriteBlockedStreams()); @@ -66,100 +64,52 @@ EXPECT_TRUE(list.HasWriteBlockedStreams()); } -TEST_P(WriteBlockedListTest, PopFront) { +TEST_F(WriteBlockedListTest, PopFront) { list.PushBack(1, 4); EXPECT_EQ(1u, list.NumBlockedStreams()); list.PushBack(2, 4); list.PushBack(1, 4); list.PushBack(3, 4); - if (GetParam()) { - EXPECT_EQ(3u, list.NumBlockedStreams()); - } else { - EXPECT_EQ(4u, list.NumBlockedStreams()); - } + EXPECT_EQ(3u, list.NumBlockedStreams()); EXPECT_EQ(1, list.PopFront(4)); EXPECT_EQ(2, list.PopFront(4)); - EXPECT_EQ(1, list.PopFront(4)); - if (!GetParam()) { - EXPECT_EQ(1, list.PopFront(4)); - } EXPECT_EQ(1u, list.NumBlockedStreams()); EXPECT_EQ(3, list.PopFront(4)); } -TEST_P(WriteBlockedListTest, UpdateStreamPriorityInWriteBlockedList) { - if (GetParam()) { - list.PushBack(1, 1); - list.PushBack(2, 2); - list.PushBack(3, 3); - list.PushBack(1, 3); // Re-prioritizes stream 1 at priority 3. - list.PushBack(1, 3); // No effect. - EXPECT_EQ(3u, list.NumBlockedStreams()); - EXPECT_EQ(0u, WriteBlockedListPeer::GetWriteBlockedList(1, &list)->size()); - EXPECT_EQ(1u, WriteBlockedListPeer::GetWriteBlockedList(2, &list)->size()); - EXPECT_EQ(2u, WriteBlockedListPeer::GetWriteBlockedList(3, &list)->size()); +TEST_F(WriteBlockedListTest, UpdateStreamPriorityInWriteBlockedList) { + list.PushBack(1, 1); + list.PushBack(2, 2); + list.PushBack(3, 3); + list.PushBack(1, 3); // Re-prioritizes stream 1 at priority 3. + list.PushBack(1, 3); // No effect. + EXPECT_EQ(3u, list.NumBlockedStreams()); + EXPECT_EQ(0u, WriteBlockedListPeer::GetWriteBlockedList(1, &list)->size()); + EXPECT_EQ(1u, WriteBlockedListPeer::GetWriteBlockedList(2, &list)->size()); + EXPECT_EQ(2u, WriteBlockedListPeer::GetWriteBlockedList(3, &list)->size()); - list.UpdateStreamPriorityInWriteBlockedList(1, 3, 2); - EXPECT_EQ(0u, WriteBlockedListPeer::GetWriteBlockedList(1, &list)->size()); - EXPECT_EQ(2u, WriteBlockedListPeer::GetWriteBlockedList(2, &list)->size()); - list.UpdateStreamPriorityInWriteBlockedList(3, 3, 1); - EXPECT_EQ(1u, WriteBlockedListPeer::GetWriteBlockedList(1, &list)->size()); - EXPECT_EQ(0u, WriteBlockedListPeer::GetWriteBlockedList(3, &list)->size()); + list.UpdateStreamPriorityInWriteBlockedList(1, 3, 2); + EXPECT_EQ(0u, WriteBlockedListPeer::GetWriteBlockedList(1, &list)->size()); + EXPECT_EQ(2u, WriteBlockedListPeer::GetWriteBlockedList(2, &list)->size()); + list.UpdateStreamPriorityInWriteBlockedList(3, 3, 1); + EXPECT_EQ(1u, WriteBlockedListPeer::GetWriteBlockedList(1, &list)->size()); + EXPECT_EQ(0u, WriteBlockedListPeer::GetWriteBlockedList(3, &list)->size()); - // Redundant update. - list.UpdateStreamPriorityInWriteBlockedList(1, 2, 2); - EXPECT_EQ(2u, WriteBlockedListPeer::GetWriteBlockedList(2, &list)->size()); + // Redundant update. + list.UpdateStreamPriorityInWriteBlockedList(1, 2, 2); + EXPECT_EQ(2u, WriteBlockedListPeer::GetWriteBlockedList(2, &list)->size()); - // No entries for given stream_id / old_priority pair. - list.UpdateStreamPriorityInWriteBlockedList(4, 4, 1); - EXPECT_EQ(1u, WriteBlockedListPeer::GetWriteBlockedList(1, &list)->size()); - EXPECT_EQ(2u, WriteBlockedListPeer::GetWriteBlockedList(2, &list)->size()); - EXPECT_EQ(0u, WriteBlockedListPeer::GetWriteBlockedList(4, &list)->size()); + // No entries for given stream_id / old_priority pair. + list.UpdateStreamPriorityInWriteBlockedList(4, 4, 1); + EXPECT_EQ(1u, WriteBlockedListPeer::GetWriteBlockedList(1, &list)->size()); + EXPECT_EQ(2u, WriteBlockedListPeer::GetWriteBlockedList(2, &list)->size()); + EXPECT_EQ(0u, WriteBlockedListPeer::GetWriteBlockedList(4, &list)->size()); - EXPECT_EQ(3, list.PopFront(1)); - EXPECT_EQ(2, list.PopFront(2)); - EXPECT_EQ(1, list.PopFront(2)); - EXPECT_EQ(0u, list.NumBlockedStreams()); - } else { - list.PushBack(1, 1); - list.PushBack(2, 2); - list.PushBack(3, 3); - list.PushBack(1, 3); - list.PushBack(1, 3); - EXPECT_EQ(5u, list.NumBlockedStreams()); - EXPECT_EQ(1u, WriteBlockedListPeer::GetWriteBlockedList(1, &list)->size()); - EXPECT_EQ(1u, WriteBlockedListPeer::GetWriteBlockedList(2, &list)->size()); - EXPECT_EQ(3u, WriteBlockedListPeer::GetWriteBlockedList(3, &list)->size()); - - list.UpdateStreamPriorityInWriteBlockedList(1, 1, 2); - EXPECT_EQ(0u, WriteBlockedListPeer::GetWriteBlockedList(1, &list)->size()); - EXPECT_EQ(2u, WriteBlockedListPeer::GetWriteBlockedList(2, &list)->size()); - list.UpdateStreamPriorityInWriteBlockedList(3, 3, 1); - EXPECT_EQ(1u, WriteBlockedListPeer::GetWriteBlockedList(1, &list)->size()); - EXPECT_EQ(2u, WriteBlockedListPeer::GetWriteBlockedList(3, &list)->size()); - - // Redundant update. - list.UpdateStreamPriorityInWriteBlockedList(1, 3, 3); - EXPECT_EQ(2u, WriteBlockedListPeer::GetWriteBlockedList(3, &list)->size()); - - // No entries for given stream_id / old_priority pair. - list.UpdateStreamPriorityInWriteBlockedList(4, 4, 1); - EXPECT_EQ(1u, WriteBlockedListPeer::GetWriteBlockedList(1, &list)->size()); - EXPECT_EQ(2u, WriteBlockedListPeer::GetWriteBlockedList(2, &list)->size()); - EXPECT_EQ(0u, WriteBlockedListPeer::GetWriteBlockedList(4, &list)->size()); - - // Update multiple entries. - list.UpdateStreamPriorityInWriteBlockedList(1, 3, 4); - EXPECT_EQ(0u, WriteBlockedListPeer::GetWriteBlockedList(3, &list)->size()); - EXPECT_EQ(1u, WriteBlockedListPeer::GetWriteBlockedList(4, &list)->size()); - - EXPECT_EQ(3, list.PopFront(1)); - EXPECT_EQ(2, list.PopFront(2)); - EXPECT_EQ(1, list.PopFront(2)); - EXPECT_EQ(1, list.PopFront(4)); - EXPECT_EQ(0u, list.NumBlockedStreams()); - } + EXPECT_EQ(3, list.PopFront(1)); + EXPECT_EQ(2, list.PopFront(2)); + EXPECT_EQ(1, list.PopFront(2)); + EXPECT_EQ(0u, list.NumBlockedStreams()); } } // namespace
diff --git a/net/ssl/ssl_failure_state.h b/net/ssl/ssl_failure_state.h new file mode 100644 index 0000000..5f43e0a --- /dev/null +++ b/net/ssl/ssl_failure_state.h
@@ -0,0 +1,49 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef NET_SSL_SSL_FAILURE_STATE_H_ +#define NET_SSL_SSL_FAILURE_STATE_H_ + +namespace net { + +// Describes the most likely cause for the TLS handshake failure. This is an +// approximation used to classify the causes of TLS version fallback. These +// values are used in histograms, so new values must be appended. +enum SSLFailureState { + // The connection was successful. + SSL_FAILURE_NONE = 0, + + // The connection failed for unknown reasons. + SSL_FAILURE_UNKNOWN = 1, + + // The connection failed after sending ClientHello and before receiving + // ServerHello. + SSL_FAILURE_CLIENT_HELLO = 2, + + // The connection failed after negotiating TLS_RSA_WITH_AES_128_GCM_SHA256 or + // TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 and completing the client's second + // leg. Some Microsoft IIS servers fail at this point. See + // https://crbug.com/433406. + SSL_FAILURE_BUGGY_GCM = 3, + + // The connection failed after CertificateVerify was sent. Some servers are + // known to incorrectly implement TLS 1.2 client auth. + SSL_FAILURE_CLIENT_AUTH = 4, + + // The connection failed because the server attempted to resume a session at + // the wrong version. Some versions of OpenSSL may do this in rare + // circumstances. See https://crbug.com/441456 + SSL_FAILURE_SESSION_MISMATCH = 5, + + // The connection failed after sending the NextProto message. Some F5 servers + // fail to parse such messages in TLS 1.1 and TLS 1.2, but not 1.0. See + // https://crbug.com/466977. + SSL_FAILURE_NEXT_PROTO = 6, + + SSL_FAILURE_MAX, +}; + +} // namespace net + +#endif // NET_SSL_SSL_FAILURE_STATE_H_
diff --git a/net/test/spawned_test_server/remote_test_server.cc b/net/test/spawned_test_server/remote_test_server.cc index 1d1481b..bf2c025 100644 --- a/net/test/spawned_test_server/remote_test_server.cc +++ b/net/test/spawned_test_server/remote_test_server.cc
@@ -103,7 +103,7 @@ // Generate JSON-formatted argument string. std::string arguments_string; - base::JSONWriter::Write(&arguments_dict, &arguments_string); + base::JSONWriter::Write(arguments_dict, &arguments_string); if (arguments_string.empty()) return false; @@ -123,7 +123,7 @@ // the remote server. server_data_dict.SetInteger("port", test_server_port); std::string server_data; - base::JSONWriter::Write(&server_data_dict, &server_data); + base::JSONWriter::Write(server_data_dict, &server_data); if (server_data.empty() || !ParseServerData(server_data)) { LOG(ERROR) << "Could not parse server_data: " << server_data; return false;
diff --git a/net/tools/get_server_time/get_server_time.cc b/net/tools/get_server_time/get_server_time.cc index 9915e8e..fe1c124 100644 --- a/net/tools/get_server_time/get_server_time.cc +++ b/net/tools/get_server_time/get_server_time.cc
@@ -122,7 +122,7 @@ scoped_ptr<base::Value> params(entry.ParametersToValue()); std::string params_str; if (params.get()) { - base::JSONWriter::Write(params.get(), ¶ms_str); + base::JSONWriter::Write(*params, ¶ms_str); params_str.insert(0, ": "); }
diff --git a/net/tools/net_watcher/net_watcher.cc b/net/tools/net_watcher/net_watcher.cc index 8d1d056..02c373a 100644 --- a/net/tools/net_watcher/net_watcher.cc +++ b/net/tools/net_watcher/net_watcher.cc
@@ -71,7 +71,7 @@ std::string ProxyConfigToString(const net::ProxyConfig& config) { scoped_ptr<base::Value> config_value(config.ToValue()); std::string str; - base::JSONWriter::Write(config_value.get(), &str); + base::JSONWriter::Write(*config_value, &str); return str; }
diff --git a/net/tools/quic/quic_dispatcher.cc b/net/tools/quic/quic_dispatcher.cc index 1b252ef..04c7c10 100644 --- a/net/tools/quic/quic_dispatcher.cc +++ b/net/tools/quic/quic_dispatcher.cc
@@ -9,6 +9,7 @@ #include "base/debug/stack_trace.h" #include "base/logging.h" #include "base/stl_util.h" +#include "net/quic/quic_flags.h" #include "net/quic/quic_utils.h" #include "net/tools/quic/quic_per_connection_packet_writer.h" #include "net/tools/quic/quic_time_wait_list_manager.h" @@ -20,6 +21,12 @@ using std::make_pair; using base::StringPiece; +// The threshold size for the session map, over which the dispatcher will start +// sending stateless rejects (SREJ), rather than stateful rejects (REJ) to +// clients who support them. If -1, stateless rejects will not be sent. If 0, +// the server will only send stateless rejects to clients who support them. +int32 FLAGS_quic_session_map_threshold_for_stateless_rejects = -1; + namespace { // An alarm that informs the QuicDispatcher to delete old sessions. @@ -290,6 +297,17 @@ session_map_.insert(make_pair(connection_id, session)); session->connection()->ProcessUdpPacket( current_server_address_, current_client_address_, *current_packet_); + + if (FLAGS_enable_quic_stateless_reject_support && + session->UsingStatelessRejectsIfPeerSupported() && + session->PeerSupportsStatelessRejects() && + !session->IsCryptoHandshakeConfirmed()) { + DVLOG(1) << "Removing new session for " << connection_id + << " because the session is in stateless reject mode and" + << " encryption has not been established."; + session->connection()->CloseConnection( + QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT, /* from_peer */ false); + } break; } case kFateTimeWait: @@ -298,7 +316,8 @@ DVLOG(1) << "Adding connection ID " << connection_id << "to time-wait list."; time_wait_list_manager_->AddConnectionIdToTimeWait( - connection_id, framer_.version(), nullptr); + connection_id, framer_.version(), + /*connection_rejected_statelessly=*/false, nullptr); DCHECK(time_wait_list_manager_->IsConnectionIdInTimeWait( header.public_header.connection_id)); time_wait_list_manager_->ProcessPacket( @@ -343,14 +362,16 @@ return kFateProcess; } -void QuicDispatcher::CleanUpSession(SessionMap::iterator it) { +void QuicDispatcher::CleanUpSession(SessionMap::iterator it, + bool should_close_statelessly) { QuicConnection* connection = it->second->connection(); QuicEncryptedPacket* connection_close_packet = connection->ReleaseConnectionClosePacket(); write_blocked_list_.erase(connection); - time_wait_list_manager_->AddConnectionIdToTimeWait(it->first, - connection->version(), - connection_close_packet); + DCHECK(!should_close_statelessly || !connection_close_packet); + time_wait_list_manager_->AddConnectionIdToTimeWait( + it->first, connection->version(), should_close_statelessly, + connection_close_packet); session_map_.erase(it); } @@ -407,7 +428,9 @@ delete_sessions_alarm_->Set(helper()->GetClock()->ApproximateNow()); } closed_session_list_.push_back(it->second); - CleanUpSession(it); + const bool should_close_statelessly = + (error == QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT); + CleanUpSession(it, should_close_statelessly); } void QuicDispatcher::OnWriteBlocked( @@ -444,6 +467,12 @@ QuicServerSession* session = new QuicServerSession(config_, connection, this); session->InitializeSession(crypto_config_); + if (FLAGS_quic_session_map_threshold_for_stateless_rejects != -1 && + session_map_.size() >= + static_cast<size_t>( + FLAGS_quic_session_map_threshold_for_stateless_rejects)) { + session->set_use_stateless_rejects_if_peer_supported(true); + } return session; }
diff --git a/net/tools/quic/quic_dispatcher.h b/net/tools/quic/quic_dispatcher.h index 9fcc03b..8381969 100644 --- a/net/tools/quic/quic_dispatcher.h +++ b/net/tools/quic/quic_dispatcher.h
@@ -226,9 +226,10 @@ // of a data packet that is destined for the time wait manager. void OnUnauthenticatedHeader(const QuicPacketHeader& header); - // Removes the session from the session map and write blocked list, and - // adds the ConnectionId to the time-wait list. - void CleanUpSession(SessionMap::iterator it); + // Removes the session from the session map and write blocked list, and adds + // the ConnectionId to the time-wait list. If |session_closed_statelessly| is + // true, any future packets for the ConnectionId will be black-holed. + void CleanUpSession(SessionMap::iterator it, bool session_closed_statelessly); bool HandlePacketForTimeWait(const QuicPacketPublicHeader& header);
diff --git a/net/tools/quic/quic_dispatcher_test.cc b/net/tools/quic/quic_dispatcher_test.cc index 0e3fdff..95b0030f 100644 --- a/net/tools/quic/quic_dispatcher_test.cc +++ b/net/tools/quic/quic_dispatcher_test.cc
@@ -4,6 +4,7 @@ #include "net/tools/quic/quic_dispatcher.h" +#include <ostream> #include <string> #include "base/strings/string_piece.h" @@ -31,6 +32,7 @@ using net::test::MockSession; using net::test::ValueRestore; using std::string; +using std::vector; using testing::DoAll; using testing::InSequence; using testing::Invoke; @@ -52,21 +54,28 @@ MOCK_METHOD1(CreateIncomingDataStream, QuicDataStream*(QuicStreamId id)); MOCK_METHOD0(CreateOutgoingDataStream, QuicDataStream*()); + void SetCryptoStream(QuicCryptoServerStream* crypto_stream) { + crypto_stream_ = crypto_stream; + } + + QuicCryptoServerStream* GetCryptoStream() override { return crypto_stream_; } + private: + QuicCryptoServerStream* crypto_stream_; + DISALLOW_COPY_AND_ASSIGN(TestServerSession); }; class TestDispatcher : public QuicDispatcher { public: - explicit TestDispatcher(const QuicConfig& config, - const QuicCryptoServerConfig* crypto_config, - EpollServer* eps) + TestDispatcher(const QuicConfig& config, + const QuicCryptoServerConfig* crypto_config, + EpollServer* eps) : QuicDispatcher(config, crypto_config, QuicSupportedVersions(), new QuicDispatcher::DefaultPacketWriterFactory(), - new QuicEpollConnectionHelper(eps)) { - } + new QuicEpollConnectionHelper(eps)) {} MOCK_METHOD3(CreateQuicSession, QuicServerSession*(QuicConnectionId connection_id, @@ -77,8 +86,8 @@ using QuicDispatcher::current_client_address; }; -// A Connection class which unregisters the session from the dispatcher -// when sending connection close. +// A Connection class which unregisters the session from the dispatcher when +// sending connection close. // It'd be slightly more realistic to do this from the Session but it would // involve a lot more mocking. class MockServerConnection : public MockConnection { @@ -269,7 +278,7 @@ // wait list manager. EXPECT_CALL(*time_wait_list_manager_, ProcessPacket(_, _, connection_id, _, _)).Times(1); - EXPECT_CALL(*time_wait_list_manager_, AddConnectionIdToTimeWait(_, _, _)) + EXPECT_CALL(*time_wait_list_manager_, AddConnectionIdToTimeWait(_, _, _, _)) .Times(0); ProcessPacket(client_address, connection_id, true, "foo"); } @@ -284,11 +293,130 @@ EXPECT_CALL(dispatcher_, CreateQuicSession(_, _, _)).Times(0); EXPECT_CALL(*time_wait_list_manager_, ProcessPacket(_, _, connection_id, _, _)).Times(1); - EXPECT_CALL(*time_wait_list_manager_, AddConnectionIdToTimeWait(_, _, _)) + EXPECT_CALL(*time_wait_list_manager_, AddConnectionIdToTimeWait(_, _, _, _)) .Times(1); ProcessPacket(client_address, connection_id, false, "data"); } +// Enables mocking of the handshake-confirmation for stateless rejects. +class MockQuicCryptoServerStream : public QuicCryptoServerStream { + public: + MockQuicCryptoServerStream(const QuicCryptoServerConfig& crypto_config, + QuicSession* session) + : QuicCryptoServerStream(&crypto_config, session) {} + void set_handshake_confirmed_for_testing(bool handshake_confirmed) { + handshake_confirmed_ = handshake_confirmed; + } + + private: + DISALLOW_COPY_AND_ASSIGN(MockQuicCryptoServerStream); +}; + +struct StatelessRejectTestParams { + StatelessRejectTestParams(bool enable_stateless_rejects_via_flag, + bool use_stateless_rejects_if_peer_supported, + bool client_supports_statelesss_rejects, + bool crypto_handshake_successful) + : enable_stateless_rejects_via_flag(enable_stateless_rejects_via_flag), + use_stateless_rejects_if_peer_supported( + use_stateless_rejects_if_peer_supported), + client_supports_statelesss_rejects(client_supports_statelesss_rejects), + crypto_handshake_successful(crypto_handshake_successful) {} + + friend std::ostream& operator<<(std::ostream& os, + const StatelessRejectTestParams& p) { + os << " enable_stateless_rejects_via_flag: " + << p.enable_stateless_rejects_via_flag << std::endl; + os << "{ use_stateless_rejects_if_peer_supported: " + << p.use_stateless_rejects_if_peer_supported << std::endl; + os << "{ client_supports_statelesss_rejects: " + << p.client_supports_statelesss_rejects << std::endl; + os << " crypto_handshake_successful: " << p.crypto_handshake_successful + << " }"; + return os; + } + + // This only enables the stateless reject feature via the feature-flag. + // It does not force the crypto server to emit stateless rejects. + bool enable_stateless_rejects_via_flag; + // If true, this forces the server to send a stateless reject when rejecting + // messages. This should be a no-op if enable_stateless_rejects_via_flag is + // false or the peer does not support them. + bool use_stateless_rejects_if_peer_supported; + // Whether or not the client supports stateless rejects. + bool client_supports_statelesss_rejects; + // Should the initial crypto handshake succeed or not. + bool crypto_handshake_successful; +}; + +// Constructs various test permutations for stateless rejects. +vector<StatelessRejectTestParams> GetStatelessRejectTestParams() { + vector<StatelessRejectTestParams> params; + for (bool enable_stateless_rejects_via_flag : {true, false}) { + for (bool use_stateless_rejects_if_peer_supported : {true, false}) { + for (bool client_supports_statelesss_rejects : {true, false}) { + for (bool crypto_handshake_successful : {true, false}) { + params.push_back(StatelessRejectTestParams( + enable_stateless_rejects_via_flag, + use_stateless_rejects_if_peer_supported, + client_supports_statelesss_rejects, crypto_handshake_successful)); + } + } + } + } + return params; +} + +class QuicDispatcherStatelessRejectTest + : public QuicDispatcherTest, + public ::testing::WithParamInterface<StatelessRejectTestParams> { + public: + QuicDispatcherStatelessRejectTest() : crypto_stream1_(nullptr) {} + + ~QuicDispatcherStatelessRejectTest() override { + if (crypto_stream1_) { + delete crypto_stream1_; + } + } + + // This test setup assumes that all testing will be done using + // crypto_stream1_. + void SetUp() override { + FLAGS_enable_quic_stateless_reject_support = + GetParam().enable_stateless_rejects_via_flag; + } + + // Returns true or false, depending on whether the server will emit + // a stateless reject, depending upon the parameters of the test. + bool ExpectStatelessReject() { + return GetParam().enable_stateless_rejects_via_flag && + GetParam().use_stateless_rejects_if_peer_supported && + !GetParam().crypto_handshake_successful && + GetParam().client_supports_statelesss_rejects; + } + + // Sets up dispatcher_, sesession1_, and crypto_stream1_ based on + // the test parameters. + QuicServerSession* CreateSessionBasedOnTestParams( + QuicConnectionId connection_id, + const IPEndPoint& client_address) { + CreateSession(&dispatcher_, config_, connection_id, client_address, + &session1_); + + crypto_stream1_ = new MockQuicCryptoServerStream(crypto_config_, session1_); + session1_->SetCryptoStream(crypto_stream1_); + crypto_stream1_->set_use_stateless_rejects_if_peer_supported( + GetParam().use_stateless_rejects_if_peer_supported); + crypto_stream1_->set_handshake_confirmed_for_testing( + GetParam().crypto_handshake_successful); + crypto_stream1_->set_peer_supports_stateless_rejects( + GetParam().client_supports_statelesss_rejects); + return session1_; + } + + MockQuicCryptoServerStream* crypto_stream1_; +}; + TEST_F(QuicDispatcherTest, ProcessPacketWithZeroPort) { CreateTimeWaitListManager(); @@ -298,7 +426,7 @@ // dispatcher_ should drop this packet. EXPECT_CALL(dispatcher_, CreateQuicSession(1, _, client_address)).Times(0); EXPECT_CALL(*time_wait_list_manager_, ProcessPacket(_, _, _, _, _)).Times(0); - EXPECT_CALL(*time_wait_list_manager_, AddConnectionIdToTimeWait(_, _, _)) + EXPECT_CALL(*time_wait_list_manager_, AddConnectionIdToTimeWait(_, _, _, _)) .Times(0); ProcessPacket(client_address, 1, true, "foo"); } @@ -330,7 +458,7 @@ EXPECT_CALL(dispatcher_, CreateQuicSession(_, _, _)).Times(0); EXPECT_CALL(*time_wait_list_manager_, ProcessPacket(_, _, connection_id, _, _)).Times(1); - EXPECT_CALL(*time_wait_list_manager_, AddConnectionIdToTimeWait(_, _, _)) + EXPECT_CALL(*time_wait_list_manager_, AddConnectionIdToTimeWait(_, _, _, _)) .Times(1); // A packet whose sequence number is one to large to be allowed to start a // connection. @@ -339,6 +467,52 @@ QuicDispatcher::kMaxReasonableInitialSequenceNumber + 1); } +INSTANTIATE_TEST_CASE_P(QuicDispatcherStatelessRejectTests, + QuicDispatcherStatelessRejectTest, + ::testing::ValuesIn(GetStatelessRejectTestParams())); + +// Parameterized test for stateless rejects. Should test all +// combinations of enabling/disabling, reject/no-reject for stateless +// rejects. +TEST_P(QuicDispatcherStatelessRejectTest, ParameterizedBasicTest) { + CreateTimeWaitListManager(); + + IPEndPoint client_address(net::test::Loopback4(), 1); + QuicConnectionId connection_id = 1; + EXPECT_CALL(dispatcher_, CreateQuicSession(connection_id, _, client_address)) + .WillOnce(testing::Return( + CreateSessionBasedOnTestParams(connection_id, client_address))); + + // Process the first packet for the connection. + if (ExpectStatelessReject()) { + // If this is a stateless reject, we expect the connection to close. + EXPECT_CALL(*session1_, OnConnectionClosed(_, _)) + .Times(1) + .WillOnce(WithoutArgs(Invoke( + reinterpret_cast<MockServerConnection*>(session1_->connection()), + &MockServerConnection::UnregisterOnConnectionClosed))); + } + ProcessPacket(client_address, connection_id, true, "foo"); + + // Send a second packet and check the results. If this is a stateless reject, + // the existing connection_id will go on the time-wait list. + EXPECT_EQ(ExpectStatelessReject(), + time_wait_list_manager_->IsConnectionIdInTimeWait(connection_id)); + if (ExpectStatelessReject()) { + // The second packet will be processed on the time-wait list. + EXPECT_CALL(*time_wait_list_manager_, + ProcessPacket(_, _, connection_id, _, _)).Times(1); + } else { + // The second packet will trigger a packet-validation + EXPECT_CALL(*reinterpret_cast<MockConnection*>(session1_->connection()), + ProcessUdpPacket(_, _, _)) + .Times(1) + .WillOnce(testing::WithArgs<2>( + Invoke(this, &QuicDispatcherTest::ValidatePacket))); + } + ProcessPacket(client_address, connection_id, true, "foo"); +} + // Verify the stopgap test: Packets with truncated connection IDs should be // dropped. class QuicDispatcherTestStrayPacketConnectionId @@ -358,7 +532,7 @@ EXPECT_CALL(dispatcher_, CreateQuicSession(_, _, _)).Times(0); EXPECT_CALL(*time_wait_list_manager_, ProcessPacket(_, _, connection_id, _, _)).Times(0); - EXPECT_CALL(*time_wait_list_manager_, AddConnectionIdToTimeWait(_, _, _)) + EXPECT_CALL(*time_wait_list_manager_, AddConnectionIdToTimeWait(_, _, _, _)) .Times(0); ProcessPacket(client_address, connection_id, true, "data", connection_id_length, PACKET_6BYTE_SEQUENCE_NUMBER);
diff --git a/net/tools/quic/quic_server.cc b/net/tools/quic/quic_server.cc index b285b33..5d551e68 100644 --- a/net/tools/quic/quic_server.cc +++ b/net/tools/quic/quic_server.cc
@@ -27,10 +27,6 @@ // TODO(rtenneti): Add support for MMSG_MORE. #define MMSG_MORE 0 -// If true, QuicListener uses the QuicPacketReader to read packets instead of -// QuicServer. -// TODO(rtenneti): Enable this flag after MMSG_MORE is set to 1. -#define FLAGS_quic_use_optimized_packet_reader false #ifndef SO_RXQ_OVFL #define SO_RXQ_OVFL 40 @@ -221,32 +217,13 @@ bool read = true; while (read) { if (use_recvmmsg_) { - if (FLAGS_quic_use_optimized_packet_reader) { - read = packet_reader_->ReadAndDispatchPackets( - fd_, port_, dispatcher_.get(), - overflow_supported_ ? &packets_dropped_ : nullptr); - } else { -// TODO(rtenneti): Add support for ReadAndDispatchPackets. -#if 0 - read = ReadAndDispatchPackets( - fd_, port_, dispatcher_.get(), - overflow_supported_ ? &packets_dropped_ : nullptr); -#else - read = ReadAndDispatchSinglePacket( - fd_, port_, dispatcher_.get(), - overflow_supported_ ? &packets_dropped_ : nullptr); -#endif - } + read = packet_reader_->ReadAndDispatchPackets( + fd_, port_, dispatcher_.get(), + overflow_supported_ ? &packets_dropped_ : nullptr); } else { - if (FLAGS_quic_use_optimized_packet_reader) { - read = QuicPacketReader::ReadAndDispatchSinglePacket( - fd_, port_, dispatcher_.get(), - overflow_supported_ ? &packets_dropped_ : nullptr); - } else { - read = ReadAndDispatchSinglePacket( - fd_, port_, dispatcher_.get(), - overflow_supported_ ? &packets_dropped_ : nullptr); - } + read = QuicPacketReader::ReadAndDispatchSinglePacket( + fd_, port_, dispatcher_.get(), + overflow_supported_ ? &packets_dropped_ : nullptr); } } } @@ -260,35 +237,5 @@ } } -/* static */ -bool QuicServer::ReadAndDispatchSinglePacket(int fd, - int port, - ProcessPacketInterface* processor, - QuicPacketCount* packets_dropped) { - // Allocate some extra space so we can send an error if the client goes over - // the limit. - char buf[2 * kMaxPacketSize]; - - IPEndPoint client_address; - IPAddressNumber server_ip; - int bytes_read = - QuicSocketUtils::ReadPacket(fd, buf, arraysize(buf), - packets_dropped, - &server_ip, &client_address); - - if (bytes_read < 0) { - return false; // We failed to read. - } - - QuicEncryptedPacket packet(buf, bytes_read, false); - - IPEndPoint server_address(server_ip, port); - processor->ProcessPacket(server_address, client_address, packet); - - // The socket read was successful, so return true even if packet dispatch - // failed. - return true; -} - } // namespace tools } // namespace net
diff --git a/net/tools/quic/quic_server.h b/net/tools/quic/quic_server.h index 865de95..56b9e4d 100644 --- a/net/tools/quic/quic_server.h +++ b/net/tools/quic/quic_server.h
@@ -55,20 +55,6 @@ void OnEvent(int fd, EpollEvent* event) override; void OnUnregistration(int fd, bool replaced) override {} - // Reads a number of packets from the given fd, and then passes them off to - // the QuicDispatcher. Returns true if some packets are read, false - // otherwise. - // If packets_dropped is non-null, the socket is configured to track - // dropped packets, and some packets are read, it will be set to the number of - // dropped packets. - static bool ReadAndDispatchPackets(int fd, int port, - ProcessPacketInterface* processor, - QuicPacketCount* packets_dropped); - // Same as ReadAndDispatchPackets, only does one packet at a time. - static bool ReadAndDispatchSinglePacket(int fd, int port, - ProcessPacketInterface* processor, - QuicPacketCount* packets_dropped); - void OnShutdown(EpollServer* eps, int fd) override {} void SetStrikeRegisterNoStartupPeriod() {
diff --git a/net/tools/quic/quic_server_session.cc b/net/tools/quic/quic_server_session.cc index 2d80451..8999397 100644 --- a/net/tools/quic/quic_server_session.cc +++ b/net/tools/quic/quic_server_session.cc
@@ -175,6 +175,11 @@ } bool QuicServerSession::ShouldCreateIncomingDataStream(QuicStreamId id) { + if (!connection()->connected()) { + LOG(DFATAL) << "ShouldCreateIncomingDataStream called when disconnected"; + return false; + } + if (id % 2 == 0) { DVLOG(1) << "Invalid incoming even stream_id:" << id; connection()->SendConnectionClose(QUIC_INVALID_STREAM_ID);
diff --git a/net/tools/quic/quic_server_session.h b/net/tools/quic/quic_server_session.h index 5cd6dfd..dc63341 100644 --- a/net/tools/quic/quic_server_session.h +++ b/net/tools/quic/quic_server_session.h
@@ -76,10 +76,31 @@ // Override base class to process FEC config received from client. void OnConfigNegotiated() override; + bool UsingStatelessRejectsIfPeerSupported() { + if (GetCryptoStream() == nullptr) { + return false; + } + return GetCryptoStream()->use_stateless_rejects_if_peer_supported(); + } + + bool PeerSupportsStatelessRejects() { + if (GetCryptoStream() == nullptr) { + return false; + } + return GetCryptoStream()->peer_supports_stateless_rejects(); + } + void set_serving_region(std::string serving_region) { serving_region_ = serving_region; } + void set_use_stateless_rejects_if_peer_supported( + bool use_stateless_rejects_if_peer_supported) { + DCHECK(GetCryptoStream() != nullptr); + GetCryptoStream()->set_use_stateless_rejects_if_peer_supported( + use_stateless_rejects_if_peer_supported); + } + protected: // QuicSession methods: QuicDataStream* CreateIncomingDataStream(QuicStreamId id) override;
diff --git a/net/tools/quic/quic_server_session_test.cc b/net/tools/quic/quic_server_session_test.cc index 665ca6b..b48021b 100644 --- a/net/tools/quic/quic_server_session_test.cc +++ b/net/tools/quic/quic_server_session_test.cc
@@ -18,6 +18,7 @@ #include "net/quic/test_tools/quic_session_peer.h" #include "net/quic/test_tools/quic_sustained_bandwidth_recorder_peer.h" #include "net/quic/test_tools/quic_test_utils.h" +#include "net/test/gtest_util.h" #include "net/tools/quic/quic_spdy_server_stream.h" #include "net/tools/quic/test_tools/quic_test_utils.h" #include "testing/gmock/include/gmock/gmock.h" @@ -262,6 +263,13 @@ QuicServerSessionPeer::GetIncomingDataStream(session_.get(), 4)); } +TEST_P(QuicServerSessionTest, GetStreamDisconnected) { + // Don't create new streams if the connection is disconnected. + QuicConnectionPeer::CloseConnection(connection_); + EXPECT_DFATAL(QuicServerSessionPeer::GetIncomingDataStream(session_.get(), 4), + "ShouldCreateIncomingDataStream called when disconnected"); +} + TEST_P(QuicServerSessionTest, SetFecProtectionFromConfig) { ValueRestore<bool> old_flag(&FLAGS_enable_quic_fec, true);
diff --git a/net/tools/quic/quic_time_wait_list_manager.cc b/net/tools/quic/quic_time_wait_list_manager.cc index baba81e0..c9405e55 100644 --- a/net/tools/quic/quic_time_wait_list_manager.cc +++ b/net/tools/quic/quic_time_wait_list_manager.cc
@@ -106,7 +106,11 @@ void QuicTimeWaitListManager::AddConnectionIdToTimeWait( QuicConnectionId connection_id, QuicVersion version, + bool connection_rejected_statelessly, QuicEncryptedPacket* close_packet) { + DCHECK(!connection_rejected_statelessly || !close_packet) + << "Connections that were rejected statelessly should not " + << "have a close packet. connection_id = " << connection_id; int num_packets = 0; ConnectionIdMap::iterator it = connection_id_map_.find(connection_id); const bool new_connection_id = it == connection_id_map_.end(); @@ -118,10 +122,8 @@ TrimTimeWaitListIfNeeded(); DCHECK_LT(num_connections(), static_cast<size_t>(FLAGS_quic_time_wait_list_max_connections)); - ConnectionIdData data(num_packets, - version, - clock_->ApproximateNow(), - close_packet); + ConnectionIdData data(num_packets, version, clock_->ApproximateNow(), + close_packet, connection_rejected_statelessly); connection_id_map_.insert(std::make_pair(connection_id, data)); if (new_connection_id) { visitor_->OnConnectionAddedToTimeWaitList(connection_id); @@ -164,22 +166,24 @@ ConnectionIdMap::iterator it = connection_id_map_.find(connection_id); DCHECK(it != connection_id_map_.end()); // Increment the received packet count. - ++((it->second).num_packets); - if (!ShouldSendResponse((it->second).num_packets)) { + ConnectionIdData* connection_data = &it->second; + ++(connection_data->num_packets); + if (!ShouldSendResponse(connection_data->num_packets)) { return; } - if (it->second.close_packet) { - QueuedPacket* queued_packet = - new QueuedPacket(server_address, - client_address, - it->second.close_packet->Clone()); + if (connection_data->close_packet) { + QueuedPacket* queued_packet = new QueuedPacket( + server_address, client_address, connection_data->close_packet->Clone()); // Takes ownership of the packet. SendOrQueuePacket(queued_packet); - } else { + } else if (!connection_data->connection_rejected_statelessly) { SendPublicReset(server_address, client_address, connection_id, sequence_number); + } else { + DVLOG(3) << "Time wait list not sending response for connection " + << connection_id << " due to previous stateless reject."; } }
diff --git a/net/tools/quic/quic_time_wait_list_manager.h b/net/tools/quic/quic_time_wait_list_manager.h index 8c12869..bbaf6f0 100644 --- a/net/tools/quic/quic_time_wait_list_manager.h +++ b/net/tools/quic/quic_time_wait_list_manager.h
@@ -55,9 +55,16 @@ // and sends it again when packets are received for added connection_ids. If // nullptr, a public reset packet is sent with the specified |version|. // DCHECKs that connection_id is not already on the list. "virtual" to - // override in tests. + // override in tests. If "connection_rejected_statelessly" is true, it means + // that the connection was closed due to a stateless reject, and no close + // packet is expected. Any packets that are received for connection_id will + // be black-holed. + // TODO(jokulik): In the future, we plan send (redundant) SREJ packets back to + // the client in response to stray data-packets that arrive after the first + // SREJ. This requires some new plumbing, so we black-hole for now. virtual void AddConnectionIdToTimeWait(QuicConnectionId connection_id, QuicVersion version, + bool connection_rejected_statelessly, QuicEncryptedPacket* close_packet); // Returns true if the connection_id is in time wait state, false otherwise. @@ -145,15 +152,18 @@ ConnectionIdData(int num_packets_, QuicVersion version_, QuicTime time_added_, - QuicEncryptedPacket* close_packet) + QuicEncryptedPacket* close_packet, + bool connection_rejected_statelessly) : num_packets(num_packets_), version(version_), time_added(time_added_), - close_packet(close_packet) {} + close_packet(close_packet), + connection_rejected_statelessly(connection_rejected_statelessly) {} int num_packets; QuicVersion version; QuicTime time_added; QuicEncryptedPacket* close_packet; + bool connection_rejected_statelessly; }; // linked_hash_map allows lookup by ConnectionId and traversal in add order.
diff --git a/net/tools/quic/quic_time_wait_list_manager_test.cc b/net/tools/quic/quic_time_wait_list_manager_test.cc index 42073146..8f12c7e 100644 --- a/net/tools/quic/quic_time_wait_list_manager_test.cc +++ b/net/tools/quic/quic_time_wait_list_manager_test.cc
@@ -114,14 +114,22 @@ } void AddConnectionId(QuicConnectionId connection_id) { - AddConnectionId(connection_id, QuicVersionMax(), nullptr); + AddConnectionId(connection_id, QuicVersionMax(), + /*connection_rejected_statelessly=*/false, nullptr); + } + + void AddStatelessConnectionId(QuicConnectionId connection_id) { + time_wait_list_manager_.AddConnectionIdToTimeWait( + connection_id, QuicVersionMax(), + /*connection_rejected_statelessly=*/true, nullptr); } void AddConnectionId(QuicConnectionId connection_id, QuicVersion version, + bool connection_rejected_statelessly, QuicEncryptedPacket* packet) { time_wait_list_manager_.AddConnectionIdToTimeWait( - connection_id, version, packet); + connection_id, version, connection_rejected_statelessly, packet); } bool IsConnectionIdInTimeWait(QuicConnectionId connection_id) { @@ -231,14 +239,21 @@ EXPECT_TRUE(IsConnectionIdInTimeWait(connection_id_)); } +TEST_F(QuicTimeWaitListManagerTest, CheckStatelessConnectionIdInTimeWait) { + EXPECT_FALSE(IsConnectionIdInTimeWait(connection_id_)); + EXPECT_CALL(visitor_, OnConnectionAddedToTimeWaitList(connection_id_)); + AddStatelessConnectionId(connection_id_); + EXPECT_EQ(1u, time_wait_list_manager_.num_connections()); + EXPECT_TRUE(IsConnectionIdInTimeWait(connection_id_)); +} + TEST_F(QuicTimeWaitListManagerTest, SendConnectionClose) { const size_t kConnectionCloseLength = 100; EXPECT_CALL(visitor_, OnConnectionAddedToTimeWaitList(connection_id_)); - AddConnectionId( - connection_id_, - QuicVersionMax(), - new QuicEncryptedPacket( - new char[kConnectionCloseLength], kConnectionCloseLength, true)); + AddConnectionId(connection_id_, QuicVersionMax(), + /*connection_rejected_statelessly=*/false, + new QuicEncryptedPacket(new char[kConnectionCloseLength], + kConnectionCloseLength, true)); const int kRandomSequenceNumber = 1; EXPECT_CALL(writer_, WritePacket(_, kConnectionCloseLength, server_address_.address(), @@ -283,6 +298,13 @@ } } +TEST_F(QuicTimeWaitListManagerTest, NoPublicResetForStatelessConnections) { + EXPECT_CALL(visitor_, OnConnectionAddedToTimeWaitList(connection_id_)); + AddStatelessConnectionId(connection_id_); + const int kRandomSequenceNumber = 1; + ProcessPacket(connection_id_, kRandomSequenceNumber); +} + TEST_F(QuicTimeWaitListManagerTest, CleanUpOldConnectionIds) { const size_t kConnectionIdCount = 100; const size_t kOldConnectionIdCount = 31; @@ -406,9 +428,12 @@ EXPECT_CALL(visitor_, OnConnectionAddedToTimeWaitList(kConnectionId1)); EXPECT_CALL(visitor_, OnConnectionAddedToTimeWaitList(kConnectionId2)); EXPECT_CALL(visitor_, OnConnectionAddedToTimeWaitList(kConnectionId3)); - AddConnectionId(kConnectionId1, QuicVersionMin(), nullptr); - AddConnectionId(kConnectionId2, QuicVersionMax(), nullptr); - AddConnectionId(kConnectionId3, QuicVersionMax(), nullptr); + AddConnectionId(kConnectionId1, QuicVersionMin(), + /*connection_rejected_statelessly=*/false, nullptr); + AddConnectionId(kConnectionId2, QuicVersionMax(), + /*connection_rejected_statelessly=*/false, nullptr); + AddConnectionId(kConnectionId3, QuicVersionMax(), + /*connection_rejected_statelessly=*/false, nullptr); EXPECT_EQ(QuicVersionMin(), QuicTimeWaitListManagerPeer::GetQuicVersionFromConnectionId( @@ -428,11 +453,10 @@ AddConnectionId(connection_id_); EXPECT_TRUE(IsConnectionIdInTimeWait(connection_id_)); const size_t kConnectionCloseLength = 100; - AddConnectionId( - connection_id_, - QuicVersionMax(), - new QuicEncryptedPacket( - new char[kConnectionCloseLength], kConnectionCloseLength, true)); + AddConnectionId(connection_id_, QuicVersionMax(), + /*connection_rejected_statelessly=*/false, + new QuicEncryptedPacket(new char[kConnectionCloseLength], + kConnectionCloseLength, true)); EXPECT_TRUE(IsConnectionIdInTimeWait(connection_id_)); EXPECT_EQ(1u, time_wait_list_manager_.num_connections());
diff --git a/net/tools/quic/test_tools/packet_dropping_test_writer.cc b/net/tools/quic/test_tools/packet_dropping_test_writer.cc index e31a728..7957380 100644 --- a/net/tools/quic/test_tools/packet_dropping_test_writer.cc +++ b/net/tools/quic/test_tools/packet_dropping_test_writer.cc
@@ -46,8 +46,10 @@ PacketDroppingTestWriter::PacketDroppingTestWriter() : clock_(nullptr), cur_buffer_size_(0), + num_calls_to_write_(0), config_mutex_(), fake_packet_loss_percentage_(0), + fake_drop_first_n_packets_(0), fake_blocked_socket_percentage_(0), fake_packet_reorder_percentage_(0), fake_packet_delay_(QuicTime::Delta::Zero()), @@ -76,9 +78,16 @@ size_t buf_len, const net::IPAddressNumber& self_address, const net::IPEndPoint& peer_address) { + ++num_calls_to_write_; ReleaseOldPackets(); base::AutoLock locked(config_mutex_); + if (fake_drop_first_n_packets_ > 0 && + num_calls_to_write_ <= static_cast<uint64>(fake_drop_first_n_packets_)) { + DVLOG(1) << "Dropping first " << fake_drop_first_n_packets_ + << " packets (packet number " << num_calls_to_write_ << ")"; + return WriteResult(WRITE_STATUS_OK, buf_len); + } if (fake_packet_loss_percentage_ > 0 && simple_random_.RandUint64() % 100 < static_cast<uint64>(fake_packet_loss_percentage_)) {
diff --git a/net/tools/quic/test_tools/packet_dropping_test_writer.h b/net/tools/quic/test_tools/packet_dropping_test_writer.h index e181fdbf..ae1aac0 100644 --- a/net/tools/quic/test_tools/packet_dropping_test_writer.h +++ b/net/tools/quic/test_tools/packet_dropping_test_writer.h
@@ -69,6 +69,13 @@ fake_packet_loss_percentage_ = fake_packet_loss_percentage; } + // Simulate dropping the first n packets unconditionally. + // Subsequent packets will be lost at fake_packet_loss_percentage_ if set. + void set_fake_drop_first_n_packets(int32 fake_drop_first_n_packets) { + base::AutoLock locked(config_mutex_); + fake_drop_first_n_packets_ = fake_drop_first_n_packets; + } + // The percent of time WritePacket will block and set WriteResult's status // to WRITE_STATUS_BLOCKED. void set_fake_blocked_socket_percentage( @@ -141,9 +148,11 @@ // Stored packets delayed by fake packet delay or bandwidth restrictions. DelayedPacketList delayed_packets_; QuicByteCount cur_buffer_size_; + uint64 num_calls_to_write_; base::Lock config_mutex_; int32 fake_packet_loss_percentage_; + int32 fake_drop_first_n_packets_; int32 fake_blocked_socket_percentage_; int32 fake_packet_reorder_percentage_; QuicTime::Delta fake_packet_delay_;
diff --git a/net/tools/quic/test_tools/quic_test_utils.cc b/net/tools/quic/test_tools/quic_test_utils.cc index 5e954dd..11ff985 100644 --- a/net/tools/quic/test_tools/quic_test_utils.cc +++ b/net/tools/quic/test_tools/quic_test_utils.cc
@@ -123,8 +123,8 @@ QuicSupportedVersions()) { // Though AddConnectionIdToTimeWait is mocked, we want to retain its // functionality. - EXPECT_CALL(*this, AddConnectionIdToTimeWait(_, _, _)).Times(AnyNumber()); - ON_CALL(*this, AddConnectionIdToTimeWait(_, _, _)) + EXPECT_CALL(*this, AddConnectionIdToTimeWait(_, _, _, _)).Times(AnyNumber()); + ON_CALL(*this, AddConnectionIdToTimeWait(_, _, _, _)) .WillByDefault( Invoke(this, &MockTimeWaitListManager:: QuicTimeWaitListManager_AddConnectionIdToTimeWait));
diff --git a/net/tools/quic/test_tools/quic_test_utils.h b/net/tools/quic/test_tools/quic_test_utils.h index e7884680..dac5f5c 100644 --- a/net/tools/quic/test_tools/quic_test_utils.h +++ b/net/tools/quic/test_tools/quic_test_utils.h
@@ -154,20 +154,21 @@ MockTimeWaitListManager(QuicPacketWriter* writer, QuicServerSessionVisitor* visitor, QuicConnectionHelperInterface* helper); - ~MockTimeWaitListManager() override; - MOCK_METHOD3(AddConnectionIdToTimeWait, + MOCK_METHOD4(AddConnectionIdToTimeWait, void(QuicConnectionId connection_id, QuicVersion version, + bool connection_rejected_statelessly, QuicEncryptedPacket* close_packet)); void QuicTimeWaitListManager_AddConnectionIdToTimeWait( QuicConnectionId connection_id, QuicVersion version, + bool connection_rejected_statelessly, QuicEncryptedPacket* close_packet) { - QuicTimeWaitListManager::AddConnectionIdToTimeWait(connection_id, version, - close_packet); + QuicTimeWaitListManager::AddConnectionIdToTimeWait( + connection_id, version, connection_rejected_statelessly, close_packet); } MOCK_METHOD5(ProcessPacket,
diff --git a/pdf/out_of_process_instance.cc b/pdf/out_of_process_instance.cc index 8c240a60..d8188ad4 100644 --- a/pdf/out_of_process_instance.cc +++ b/pdf/out_of_process_instance.cc
@@ -469,7 +469,7 @@ engine_->HasPermission(PDFEngine::PERMISSION_COPY_ACCESSIBLE); node.SetBoolean(kAccessibleCopyable, has_permissions); std::string json; - base::JSONWriter::Write(&node, &json); + base::JSONWriter::Write(node, &json); reply.Set(pp::Var(kJSAccessibilityJSON), pp::Var(json)); } PostMessage(reply);
diff --git a/pdf/pdfium/pdfium_engine.cc b/pdf/pdfium/pdfium_engine.cc index 8012dd26..f4df4a99 100644 --- a/pdf/pdfium/pdfium_engine.cc +++ b/pdf/pdfium/pdfium_engine.cc
@@ -661,17 +661,11 @@ pages_[i]->Unload(); if (doc_) { - if (form_) { - FORM_DoDocumentAAction(form_, FPDFDOC_AACTION_WC); - } + FORM_DoDocumentAAction(form_, FPDFDOC_AACTION_WC); FPDF_CloseDocument(doc_); - if (form_) { - FPDFDOC_ExitFormFillEnvironment(form_); - } + FPDFDOC_ExitFormFillEnvironment(form_); } - - if (fpdf_availability_) - FPDFAvail_Destroy(fpdf_availability_); + FPDFAvail_Destroy(fpdf_availability_); STLDeleteElements(&pages_); } @@ -2440,7 +2434,7 @@ scoped_ptr<base::Value> node( pages_[index]->GetAccessibleContentAsValue(current_rotation_)); std::string page_json; - base::JSONWriter::Write(node.get(), &page_json); + base::JSONWriter::Write(*node, &page_json); return page_json; }
diff --git a/printing/printed_document.cc b/printing/printed_document.cc index 62fbef8..3b17eff 100644 --- a/printing/printed_document.cc +++ b/printing/printed_document.cc
@@ -78,7 +78,7 @@ PrintSettingsToJobSettingsDebug(settings, &job_settings); std::string settings_str; base::JSONWriter::WriteWithOptions( - &job_settings, base::JSONWriter::OPTIONS_PRETTY_PRINT, &settings_str); + job_settings, base::JSONWriter::OPTIONS_PRETTY_PRINT, &settings_str); scoped_refptr<base::RefCountedMemory> data = base::RefCountedString::TakeString(&settings_str); blocking_runner->PostTask(
diff --git a/remoting/app_remoting_webapp.gyp b/remoting/app_remoting_webapp.gyp index 9c8add8a..7373778d 100644 --- a/remoting/app_remoting_webapp.gyp +++ b/remoting/app_remoting_webapp.gyp
@@ -92,6 +92,7 @@ 'targets': [ { + # GN version: //remoting/webapp:ar_sample_app # Sample AppRemoting app. 'target_name': 'ar_sample_app', 'app_key': 'Sample_App',
diff --git a/remoting/app_remoting_webapp_build.gypi b/remoting/app_remoting_webapp_build.gypi index 9f7572cb..bc6ffa6 100644 --- a/remoting/app_remoting_webapp_build.gypi +++ b/remoting/app_remoting_webapp_build.gypi
@@ -11,6 +11,7 @@ 'app_remoting_webapp_files.gypi', ], + # GN version: See remoting/webapp/build_template.gni 'target_defaults': { 'type': 'none', @@ -119,7 +120,6 @@ '<(ar_app_manifest_app)', # Manifest template 'app_remoting', # Web app type '<@(ar_webapp_files)', - '<@(ar_generated_html_files)', '--locales_listfile', '<(ar_webapp_locales_listfile)', '--jinja_paths',
diff --git a/remoting/base/buffered_socket_writer_unittest.cc b/remoting/base/buffered_socket_writer_unittest.cc index 0c740447..07bb2ec 100644 --- a/remoting/base/buffered_socket_writer_unittest.cc +++ b/remoting/base/buffered_socket_writer_unittest.cc
@@ -45,6 +45,14 @@ size); } + bool AllReadDataConsumed() const override { + return true; + } + + bool AllWriteDataConsumed() const override { + return true; + } + void Reset() override {} std::string written_data() { return written_data_; }
diff --git a/remoting/base/vlog_net_log.cc b/remoting/base/vlog_net_log.cc index 39a388a7..bfcea02 100644 --- a/remoting/base/vlog_net_log.cc +++ b/remoting/base/vlog_net_log.cc
@@ -35,7 +35,7 @@ if (VLOG_IS_ON(4)) { scoped_ptr<base::Value> value(entry.ToValue()); std::string json; - base::JSONWriter::Write(value.get(), &json); + base::JSONWriter::Write(*value, &json); VLOG(4) << json; } }
diff --git a/remoting/client/plugin/chromoting_instance.cc b/remoting/client/plugin/chromoting_instance.cc index 3faab96..a3544aa9 100644 --- a/remoting/client/plugin/chromoting_instance.cc +++ b/remoting/client/plugin/chromoting_instance.cc
@@ -1016,12 +1016,12 @@ void ChromotingInstance::PostLegacyJsonMessage( const std::string& method, scoped_ptr<base::DictionaryValue> data) { - scoped_ptr<base::DictionaryValue> message(new base::DictionaryValue()); - message->SetString("method", method); - message->Set("data", data.release()); + base::DictionaryValue message; + message.SetString("method", method); + message.Set("data", data.release()); std::string message_json; - base::JSONWriter::Write(message.get(), &message_json); + base::JSONWriter::Write(message, &message_json); PostMessage(pp::Var(message_json)); }
diff --git a/remoting/codec/video_encoder_vpx.cc b/remoting/codec/video_encoder_vpx.cc index 724fbecd..c74f0d8 100644 --- a/remoting/codec/video_encoder_vpx.cc +++ b/remoting/codec/video_encoder_vpx.cc
@@ -39,6 +39,10 @@ const int kVp9I420ProfileNumber = 0; const int kVp9I444ProfileNumber = 1; +// Magic encoder constants for adaptive quantization strategy. +const int kVp9AqModeNone = 0; +const int kVp9AqModeCyclicRefresh = 3; + void SetCommonCodecParameters(vpx_codec_enc_cfg_t* config, const webrtc::DesktopSize& size) { // Use millisecond granularity time base. @@ -137,6 +141,11 @@ ret = vpx_codec_control( codec, VP9E_SET_TUNE_CONTENT, VP9E_CONTENT_SCREEN); DCHECK_EQ(VPX_CODEC_OK, ret) << "Failed to set screen content mode"; + + // Set cyclic refresh (aka "top-off") only for lossy encoding. + int aq_mode = lossless_encode ? kVp9AqModeNone : kVp9AqModeCyclicRefresh; + ret = vpx_codec_control(codec, VP9E_SET_AQ_MODE, aq_mode); + DCHECK_EQ(VPX_CODEC_OK, ret) << "Failed to set aq mode"; } void FreeImageIfMismatched(bool use_i444, @@ -273,7 +282,7 @@ PrepareImage(frame, &updated_region); // Update active map based on updated region. - PrepareActiveMap(updated_region); + SetActiveMapFromRegion(updated_region); // Apply active map to the encoder. vpx_active_map_t act_map; @@ -293,6 +302,14 @@ << "Details: " << vpx_codec_error(codec_.get()) << "\n" << vpx_codec_error_detail(codec_.get()); + if (use_vp9_ && !lossless_encode_) { + ret = vpx_codec_control(codec_.get(), VP9E_GET_ACTIVEMAP, &act_map); + DCHECK_EQ(ret, VPX_CODEC_OK) + << "Failed to fetch active map: " + << vpx_codec_err_to_string(ret) << "\n"; + UpdateRegionFromActiveMap(&updated_region); + } + // Read the encoded data. vpx_codec_iter_t iter = NULL; bool got_data = false; @@ -485,7 +502,7 @@ } } -void VideoEncoderVpx::PrepareActiveMap( +void VideoEncoderVpx::SetActiveMapFromRegion( const webrtc::DesktopRegion& updated_region) { // Clear active map first. memset(active_map_.get(), 0, active_map_width_ * active_map_height_); @@ -510,4 +527,26 @@ } } +void VideoEncoderVpx::UpdateRegionFromActiveMap( + webrtc::DesktopRegion* updated_region) { + const uint8* map = active_map_.get(); + for (int y = 0; y < active_map_height_; ++y) { + for (int x0 = 0; x0 < active_map_width_;) { + int x1 = x0; + for (; x1 < active_map_width_; ++x1) { + if (map[y * active_map_width_ + x1] == 0) + break; + } + if (x1 > x0) { + updated_region->AddRect(webrtc::DesktopRect::MakeLTRB( + kMacroBlockSize * x0, kMacroBlockSize * y, kMacroBlockSize * x1, + kMacroBlockSize * (y + 1))); + } + x0 = x1 + 1; + } + } + updated_region->IntersectWith( + webrtc::DesktopRect::MakeWH(image_->w, image_->h)); +} + } // namespace remoting
diff --git a/remoting/codec/video_encoder_vpx.h b/remoting/codec/video_encoder_vpx.h index a7433a1..d8d39eb 100644 --- a/remoting/codec/video_encoder_vpx.h +++ b/remoting/codec/video_encoder_vpx.h
@@ -47,7 +47,11 @@ // Updates the active map according to |updated_region|. Active map is then // given to the encoder to speed up encoding. - void PrepareActiveMap(const webrtc::DesktopRegion& updated_region); + void SetActiveMapFromRegion(const webrtc::DesktopRegion& updated_region); + + // Adds areas changed in the most recent frame to |updated_region|. This + // includes both content changes and areas enhanced by cyclic refresh. + void UpdateRegionFromActiveMap(webrtc::DesktopRegion* updated_region); // True if the encoder is for VP9, false for VP8. const bool use_vp9_;
diff --git a/remoting/host/cast_extension_session.cc b/remoting/host/cast_extension_session.cc index 9bceaa6..843a79d 100644 --- a/remoting/host/cast_extension_session.cc +++ b/remoting/host/cast_extension_session.cc
@@ -202,15 +202,15 @@ peer_connection_->SetLocalDescription( CastSetSessionDescriptionObserver::Create(), desc); - scoped_ptr<base::DictionaryValue> json(new base::DictionaryValue()); - json->SetString(kWebRtcSessionDescType, desc->type()); + base::DictionaryValue json; + json.SetString(kWebRtcSessionDescType, desc->type()); std::string subject = (desc->type() == "offer") ? kSubjectOffer : kSubjectAnswer; std::string desc_str; desc->ToString(&desc_str); - json->SetString(kWebRtcSessionDescSDP, desc_str); + json.SetString(kWebRtcSessionDescSDP, desc_str); std::string json_str; - if (!base::JSONWriter::Write(json.get(), &json_str)) { + if (!base::JSONWriter::Write(json, &json_str)) { LOG(ERROR) << "Failed to serialize sdp message."; return; } @@ -420,7 +420,7 @@ message_dict.SetString(kTopLevelData, data); std::string message_json; - if (!base::JSONWriter::Write(&message_dict, &message_json)) { + if (!base::JSONWriter::Write(message_dict, &message_json)) { LOG(ERROR) << "Failed to serialize JSON message."; return false; } @@ -647,12 +647,12 @@ LOG(ERROR) << "PeerConnectionObserver: failed to serialize candidate."; return; } - scoped_ptr<base::DictionaryValue> json(new base::DictionaryValue()); - json->SetString(kWebRtcSDPMid, candidate->sdp_mid()); - json->SetInteger(kWebRtcSDPMLineIndex, candidate->sdp_mline_index()); - json->SetString(kWebRtcCandidate, candidate_str); + base::DictionaryValue json; + json.SetString(kWebRtcSDPMid, candidate->sdp_mid()); + json.SetInteger(kWebRtcSDPMLineIndex, candidate->sdp_mline_index()); + json.SetString(kWebRtcCandidate, candidate_str); std::string json_str; - if (!base::JSONWriter::Write(json.get(), &json_str)) { + if (!base::JSONWriter::Write(json, &json_str)) { LOG(ERROR) << "Failed to serialize candidate message."; return; }
diff --git a/remoting/host/gnubby_auth_handler_posix.cc b/remoting/host/gnubby_auth_handler_posix.cc index 13c8f41..4639f01 100644 --- a/remoting/host/gnubby_auth_handler_posix.cc +++ b/remoting/host/gnubby_auth_handler_posix.cc
@@ -174,7 +174,7 @@ request.Set(kDataPayload, bytes); std::string request_json; - if (!base::JSONWriter::Write(&request, &request_json)) { + if (!base::JSONWriter::Write(request, &request_json)) { LOG(ERROR) << "Failed to create request json"; return; }
diff --git a/remoting/host/host_config.cc b/remoting/host/host_config.cc index 40ae940b..2250d6fc4 100644 --- a/remoting/host/host_config.cc +++ b/remoting/host/host_config.cc
@@ -28,7 +28,7 @@ std::string HostConfigToJson(const base::DictionaryValue& host_config) { std::string data; - base::JSONWriter::Write(&host_config, &data); + base::JSONWriter::Write(host_config, &data); return data; }
diff --git a/remoting/host/it2me/it2me_native_messaging_host.cc b/remoting/host/it2me/it2me_native_messaging_host.cc index 7af2db74..441224e 100644 --- a/remoting/host/it2me/it2me_native_messaging_host.cc +++ b/remoting/host/it2me/it2me_native_messaging_host.cc
@@ -121,7 +121,7 @@ scoped_ptr<base::DictionaryValue> message) const { DCHECK(task_runner()->BelongsToCurrentThread()); std::string message_json; - base::JSONWriter::Write(message.get(), &message_json); + base::JSONWriter::Write(*message, &message_json); client_->PostMessageFromNativeHost(message_json); }
diff --git a/remoting/host/it2me/it2me_native_messaging_host_unittest.cc b/remoting/host/it2me/it2me_native_messaging_host_unittest.cc index a6c6724..cfe66bb 100644 --- a/remoting/host/it2me/it2me_native_messaging_host_unittest.cc +++ b/remoting/host/it2me/it2me_native_messaging_host_unittest.cc
@@ -291,7 +291,7 @@ void It2MeNativeMessagingHostTest::WriteMessageToInputPipe( const base::Value& message) { std::string message_json; - base::JSONWriter::Write(&message, &message_json); + base::JSONWriter::Write(message, &message_json); uint32 length = message_json.length(); input_write_file_.WriteAtCurrentPos(reinterpret_cast<char*>(&length),
diff --git a/remoting/host/native_messaging/native_messaging_pipe.cc b/remoting/host/native_messaging/native_messaging_pipe.cc index 8521472d..da204d1 100644 --- a/remoting/host/native_messaging/native_messaging_pipe.cc +++ b/remoting/host/native_messaging/native_messaging_pipe.cc
@@ -27,7 +27,7 @@ void NativeMessagingPipe::OnMessage(scoped_ptr<base::Value> message) { std::string message_json; - base::JSONWriter::Write(message.get(), &message_json); + base::JSONWriter::Write(*message, &message_json); host_->OnMessage(message_json); }
diff --git a/remoting/host/native_messaging/native_messaging_writer.cc b/remoting/host/native_messaging/native_messaging_writer.cc index 3266fdb7..030cfd3 100644 --- a/remoting/host/native_messaging/native_messaging_writer.cc +++ b/remoting/host/native_messaging/native_messaging_writer.cc
@@ -44,7 +44,7 @@ } std::string message_json; - base::JSONWriter::Write(&message, &message_json); + base::JSONWriter::Write(message, &message_json); CHECK_LE(message_json.length(), kMaximumMessageSize);
diff --git a/remoting/host/policy_watcher_unittest.cc b/remoting/host/policy_watcher_unittest.cc index 1d683cbc..b9cbefd 100644 --- a/remoting/host/policy_watcher_unittest.cc +++ b/remoting/host/policy_watcher_unittest.cc
@@ -27,11 +27,11 @@ if (!equal) { std::string actual_value; base::JSONWriter::WriteWithOptions( - arg, base::JSONWriter::OPTIONS_PRETTY_PRINT, &actual_value); + *arg, base::JSONWriter::OPTIONS_PRETTY_PRINT, &actual_value); std::string expected_value; base::JSONWriter::WriteWithOptions( - dict, base::JSONWriter::OPTIONS_PRETTY_PRINT, &expected_value); + *dict, base::JSONWriter::OPTIONS_PRETTY_PRINT, &expected_value); *result_listener << "Policies are not equal. "; *result_listener << "Expected policy: " << expected_value << ". ";
diff --git a/remoting/host/setup/daemon_controller_delegate_win.cc b/remoting/host/setup/daemon_controller_delegate_win.cc index 0dcae692..1795110f 100644 --- a/remoting/host/setup/daemon_controller_delegate_win.cc +++ b/remoting/host/setup/daemon_controller_delegate_win.cc
@@ -186,7 +186,7 @@ } } std::string unprivileged_config_str; - base::JSONWriter::Write(&unprivileged_config_dict, &unprivileged_config_str); + base::JSONWriter::Write(unprivileged_config_dict, &unprivileged_config_str); // Write the full configuration file to a temporary location. base::FilePath full_config_file_path = @@ -413,7 +413,7 @@ // Write the updated config. std::string config_updated_str; - base::JSONWriter::Write(config_old.get(), &config_updated_str); + base::JSONWriter::Write(*config_old, &config_updated_str); bool result = WriteConfig(config_updated_str); InvokeCompletionCallback(done, result); @@ -458,7 +458,7 @@ // Set the configuration. std::string config_str; - base::JSONWriter::Write(config.release(), &config_str); + base::JSONWriter::Write(*config, &config_str); // Determine the config directory path and create it if necessary. base::FilePath config_dir = remoting::GetConfigDir();
diff --git a/remoting/host/setup/me2me_native_messaging_host_unittest.cc b/remoting/host/setup/me2me_native_messaging_host_unittest.cc index bdd6daf9..b44c2bda 100644 --- a/remoting/host/setup/me2me_native_messaging_host_unittest.cc +++ b/remoting/host/setup/me2me_native_messaging_host_unittest.cc
@@ -409,7 +409,7 @@ void Me2MeNativeMessagingHostTest::WriteMessageToInputPipe( const base::Value& message) { std::string message_json; - base::JSONWriter::Write(&message, &message_json); + base::JSONWriter::Write(message, &message_json); uint32 length = message_json.length(); input_write_file_.WriteAtCurrentPos(reinterpret_cast<char*>(&length),
diff --git a/remoting/host/setup/service_client.cc b/remoting/host/setup/service_client.cc index 260f7621..f99f6a6c 100644 --- a/remoting/host/setup/service_client.cc +++ b/remoting/host/setup/service_client.cc
@@ -83,7 +83,7 @@ if (!host_client_id.empty()) url_suffix = "?hostClientId=" + host_client_id; std::string post_body_str; - base::JSONWriter::Write(&post_body, &post_body_str); + base::JSONWriter::Write(post_body, &post_body_str); MakeChromotingRequest(net::URLFetcher::POST, url_suffix, post_body_str,
diff --git a/remoting/host/token_validator_factory_impl_unittest.cc b/remoting/host/token_validator_factory_impl_unittest.cc index bfbed9f..aa5a024 100644 --- a/remoting/host/token_validator_factory_impl_unittest.cc +++ b/remoting/host/token_validator_factory_impl_unittest.cc
@@ -108,7 +108,7 @@ response_dict.SetString("token_type", "shared_secret"); response_dict.SetString("scope", scope); std::string response; - base::JSONWriter::Write(&response_dict, &response); + base::JSONWriter::Write(response_dict, &response); return response; } @@ -116,7 +116,7 @@ base::DictionaryValue response_dict; response_dict.SetString("error", error); std::string response; - base::JSONWriter::Write(&response_dict, &response); + base::JSONWriter::Write(response_dict, &response); return response; }
diff --git a/remoting/host/video_frame_recorder_host_extension.cc b/remoting/host/video_frame_recorder_host_extension.cc index 61bd7460..efa110e 100644 --- a/remoting/host/video_frame_recorder_host_extension.cc +++ b/remoting/host/video_frame_recorder_host_extension.cc
@@ -159,7 +159,7 @@ // Note that JSONWriter::Write() can only fail due to invalid inputs, and will // DCHECK in Debug builds in that case. std::string reply_json; - if (!base::JSONWriter::Write(&reply_message, &reply_json)) { + if (!base::JSONWriter::Write(reply_message, &reply_json)) { return; }
diff --git a/remoting/remoting_client.gypi b/remoting/remoting_client.gypi index e82139c..bef823d3 100644 --- a/remoting/remoting_client.gypi +++ b/remoting/remoting_client.gypi
@@ -49,12 +49,11 @@ }, # end of target 'remoting_client' { - # GN version: //remoting/webapp:html + # GN version: See remoting/webapp/build_template.gni 'target_name': 'remoting_webapp_html', 'type': 'none', 'actions': [ { - # GN version: //remoting/webapp:main_html 'action_name': 'Build Remoting Webapp main.html', 'inputs': [ 'webapp/build-html.py', @@ -75,7 +74,6 @@ ], }, { - # GN version: //remoting/webapp:wcs_sandbox_html 'action_name': 'Build Remoting Webapp wcs_sandbox.html', 'inputs': [ 'webapp/build-html.py', @@ -92,7 +90,6 @@ ], }, { - # GN version: //remoting/webapp:background_html 'action_name': 'Build Remoting Webapp background.html', 'inputs': [ 'webapp/build-html.py', @@ -128,6 +125,7 @@ }, # end of target 'remoting_webapp_html' { + # GN version: //remoting/webapp:webapp 'target_name': 'remoting_webapp', 'type': 'none', 'dependencies': [ @@ -143,6 +141,7 @@ }, # end of target 'remoting_webapp' { + # GN version: //remoting/webapp:webapp_v1 'target_name': 'remoting_webapp_v1', 'type': 'none', 'variables': { @@ -158,6 +157,7 @@ ['disable_nacl==0 and disable_nacl_untrusted==0', { 'targets': [ { + # GN version: //remoting/webapp:webapp_v1 'target_name': 'remoting_webapp_v2', 'type': 'none', 'variables': {
diff --git a/remoting/remoting_version.gni b/remoting/remoting_version.gni index cb8fb659..db117bd1 100644 --- a/remoting/remoting_version.gni +++ b/remoting/remoting_version.gni
@@ -15,7 +15,7 @@ # Set these files as being input dependencies to the scripts, so the build will # be re-run if the files change. -_script_deps = [ +remoting_version_files = [ _remoting_version_abspath, _chrome_version_abspath, _remoting_branding_abspath, @@ -35,7 +35,7 @@ "-t \"@MAJOR@\"", ], "value", - _script_deps) + remoting_version_files) version_minor = exec_script(_version_py_abspath, [ @@ -44,7 +44,7 @@ "-t \"@REMOTING_PATCH@\"", ], "value", - _script_deps) + remoting_version_files) version_short = "${version_major}.${version_minor}." + exec_script(_version_py_abspath, @@ -56,7 +56,7 @@ "-t \"@BUILD@\"", ], "value", - _script_deps) + remoting_version_files) version_full = "${version_short}." + exec_script(_version_py_abspath, [ @@ -67,7 +67,7 @@ "-t \"@PATCH@\"", ], "value", - _script_deps) + remoting_version_files) prefpane_bundle_name = exec_script(_version_py_abspath, [ @@ -76,7 +76,7 @@ "-t \"@MAC_PREFPANE_BUNDLE_NAME@\"", ], "string", - _script_deps) + remoting_version_files) host_bundle_name = exec_script(_version_py_abspath, [ @@ -85,4 +85,4 @@ "-t \"@MAC_HOST_BUNDLE_NAME@\"", ], "string", - _script_deps) + remoting_version_files)
diff --git a/remoting/signaling/xmpp_signal_strategy_unittest.cc b/remoting/signaling/xmpp_signal_strategy_unittest.cc index b4c4a53..2193982 100644 --- a/remoting/signaling/xmpp_signal_strategy_unittest.cc +++ b/remoting/signaling/xmpp_signal_strategy_unittest.cc
@@ -29,6 +29,14 @@ void Reset() override {} + bool AllReadDataConsumed() const override { + return true; + } + + bool AllWriteDataConsumed() const override { + return true; + } + void ReceiveData(const std::string& text) { socket()->OnReadComplete( net::MockRead(net::ASYNC, text.data(), text.size()));
diff --git a/remoting/webapp/BUILD.gn b/remoting/webapp/BUILD.gn index 02b66677..e3e79664 100644 --- a/remoting/webapp/BUILD.gn +++ b/remoting/webapp/BUILD.gn
@@ -10,6 +10,7 @@ group("webapp") { deps = [ ":webapp_v1", + ":ar_sample_app", ] if (enable_nacl) { @@ -17,17 +18,17 @@ } } -remoting_webapp("webapp_v1") { +desktop_remoting_webapp("webapp_v1") { webapp_type = "v1" - output_dir = "remoting.webapp" - zip_path = "remoting-webapp.zip" + output_dir = "remoting/remoting-webapp" + zip_path = "remoting/remoting-webapp.zip" extra_files = [] } -remoting_webapp("webapp_v2") { +desktop_remoting_webapp("webapp_v2") { webapp_type = "v2_pnacl" - output_dir = "remoting.webapp.v2" - zip_path = "remoting-webapp.v2.zip" + output_dir = "remoting/remoting-webapp.v2" + zip_path = "remoting/remoting-webapp.v2.zip" extra_files = [ "crd/remoting_client_pnacl.nmf.jinja2", # TODO(garykac): Get correct path to this. @@ -35,91 +36,12 @@ ] } -group("html") { - deps = [ - ":background_html", - ":main_html", - ":message_window_html", - ":wcs_sandbox_html", - ] -} - -action("main_html") { - script = "build-html.py" - - inputs = [ remoting_webapp_template_main ] + remoting_webapp_template_files + - remoting_webapp_crd_main_html_all_js_files - - outputs = [ - "$target_gen_dir/main.html", - ] - - args = [ - rebase_path("$target_gen_dir/main.html", root_build_dir), - rebase_path(remoting_webapp_template_main, root_build_dir), - ] - args += [ - "--template-dir", - rebase_path(remoting_dir, root_build_dir), - ] - args += [ "--templates" ] + - rebase_path(remoting_webapp_template_files, remoting_dir) - args += [ "--js" ] + - rebase_path(remoting_webapp_crd_main_html_all_js_files, remoting_dir) -} - -action("wcs_sandbox_html") { - script = "build-html.py" - - inputs = [ remoting_webapp_template_wcs_sandbox ] + - remoting_webapp_wcs_sandbox_html_all_js_files - - outputs = [ - "$target_gen_dir/wcs_sandbox.html", - ] - - args = [ - rebase_path("$target_gen_dir/wcs_sandbox.html", root_build_dir), - rebase_path(remoting_webapp_template_wcs_sandbox, root_build_dir), - ] - args += - [ "--js" ] + - rebase_path(remoting_webapp_wcs_sandbox_html_all_js_files, remoting_dir) -} - -action("background_html") { - script = "build-html.py" - - inputs = [ remoting_webapp_template_background ] + - remoting_webapp_background_html_all_js_files - - outputs = [ - "$target_gen_dir/background.html", - ] - - args = [ - rebase_path("$target_gen_dir/background.html", root_build_dir), - rebase_path(remoting_webapp_template_background, root_build_dir), - ] - args += [ "--js" ] + rebase_path(remoting_webapp_background_html_all_js_files, - remoting_dir) -} - -action("message_window_html") { - script = "build-html.py" - - inputs = [ remoting_webapp_template_message_window ] + - remoting_webapp_message_window_html_all_js_files - - outputs = [ - "$target_gen_dir/message_window.html", - ] - - args = [ - rebase_path("$target_gen_dir/message_window.html", root_build_dir), - rebase_path(remoting_webapp_template_message_window, root_build_dir), - ] - args += - [ "--js" ] + rebase_path(remoting_webapp_message_window_html_all_js_files, - remoting_dir) +app_remoting_webapp("ar_sample_app") { + app_key = "Sample_App" + app_id = "ljacajndfccfgnfohlgkdphmbnpkjflk" + app_client_id = "sample_client_id" + app_name = "App Remoting Client" + app_description = "App Remoting client" + app_capabilities = [ "GOOGLE_DRIVE" ] + manifest_key = "remotingdevbuild" }
diff --git a/remoting/webapp/build-webapp.py b/remoting/webapp/build-webapp.py index e2a0abe5c..8f61ca1 100755 --- a/remoting/webapp/build-webapp.py +++ b/remoting/webapp/build-webapp.py
@@ -169,7 +169,7 @@ raise else: pass - os.mkdir(destination, 0775) + os.makedirs(destination, 0775) if buildtype != 'Official' and buildtype != 'Release' and buildtype != 'Dev': raise Exception('Unknown buildtype: ' + buildtype)
diff --git a/remoting/webapp/build_template.gni b/remoting/webapp/build_template.gni index 5d4233c..8930b04 100644 --- a/remoting/webapp/build_template.gni +++ b/remoting/webapp/build_template.gni
@@ -15,17 +15,24 @@ # to this directory. remoting_dir = "//remoting" -template("remoting_webapp") { - locales_listfile = target_name + "_locales" - listfile = "$target_gen_dir/${target_name}_locales.txt" - listfile_rel = rebase_path(listfile, root_build_dir) +buildtype = "Dev" +if (!is_debug) { + if (is_official_build) { + buildtype = "Official" + } else { + buildtype = "Release" + } +} - action(locales_listfile) { +template("build_locales_listfile") { + action(target_name) { + locales_listfile_output = invoker.locales_listfile_output + script = "../tools/build/remoting_localize.py" inputs = [] outputs = [ - listfile, + locales_listfile_output, ] args = [ @@ -33,10 +40,88 @@ rebase_path(webapp_locale_dir, root_build_dir) + "/@{json_suffix}/messages.json", "--locales_listfile", - listfile_rel, + rebase_path(locales_listfile_output, root_build_dir), ] args += remoting_locales } +} + +template("build_webapp_html") { + action(target_name) { + html_template_file = invoker.html_template_file + html_template_files = invoker.html_template_files + js_files = invoker.js_files + html_output = invoker.html_output + + script = "build-html.py" + + inputs = [ html_template_file ] + html_template_files + js_files + + outputs = [ + html_output, + ] + + args = [ + rebase_path(html_output, root_build_dir), + rebase_path(html_template_file, root_build_dir), + ] + args += [ + "--template-dir", + rebase_path(remoting_dir, root_build_dir), + ] + args += [ "--templates" ] + html_template_files + args += [ "--js" ] + rebase_path(js_files, remoting_dir) + } +} + +template("desktop_remoting_webapp") { + locales_listfile = target_name + "_locales" + locales_listfile_output = "$target_gen_dir/${target_name}_locales.txt" + + build_locales_listfile(locales_listfile) { + # Template uses locales_listfile_output from outer scope. + } + + background_html = target_name + "_background_html" + background_html_output = "$target_gen_dir/html/$target_name/background.html" + + build_webapp_html(background_html) { + html_template_file = remoting_webapp_template_background + html_template_files = [] + js_files = remoting_webapp_background_html_all_js_files + html_output = background_html_output + } + + message_window_html = target_name + "_message_window_html" + message_window_html_output = + "$target_gen_dir/html/$target_name/message_window.html" + + build_webapp_html(message_window_html) { + html_template_file = remoting_webapp_template_message_window + html_template_files = [] + js_files = remoting_webapp_message_window_html_all_js_files + html_output = message_window_html_output + } + + wcs_sandbox_html = target_name + "_wcs_sandbox_html" + wcs_sandbox_html_output = "$target_gen_dir/html/$target_name/wcs_sandbox.html" + + build_webapp_html(wcs_sandbox_html) { + html_template_file = remoting_webapp_template_wcs_sandbox + html_template_files = [] + js_files = remoting_webapp_wcs_sandbox_html_all_js_files + html_output = wcs_sandbox_html_output + } + + main_html = target_name + "_main_html" + main_html_output = "$target_gen_dir/html/$target_name/main.html" + + build_webapp_html(main_html) { + html_template_file = remoting_webapp_template_main + html_template_files = remoting_webapp_template_files + js_files = remoting_webapp_crd_main_html_all_js_files + html_output = main_html_output + } action(target_name) { script = "build-webapp.py" @@ -46,39 +131,37 @@ zip_path = invoker.zip_path extra_files = invoker.extra_files - inputs = [] + inputs = + [ rebase_path("crd/manifest.json.jinja2", root_build_dir) ] + + remoting_version_files + + rebase_path(remoting_webapp_crd_files, root_build_dir) + extra_files + outputs = [ "$target_gen_dir/$zip_path", ] deps = [ - ":html", ":$locales_listfile", + ":$background_html", + ":$message_window_html", + ":$wcs_sandbox_html", + ":$main_html", "//remoting/resources", ] - buildtype = "Dev" - if (!is_debug) { - if (is_official_build) { - buildtype = "Official" - } else { - buildtype = "Release" - } - } - - generated_html_files = [ - "$target_gen_dir/background.html", - "$target_gen_dir/main.html", - "$target_gen_dir/message_window.html", - "$target_gen_dir/wcs_sandbox.html", + dr_generated_html_files = [ + background_html_output, + message_window_html_output, + wcs_sandbox_html_output, + main_html_output, ] # Create a file that contains a list of all the resource files needed # to build the webapp. This is needed to avoid problems on platforms that # limit the size of a command line. - file_list = "$target_gen_dir/${target_name}_file_list.txt" + file_list = "$target_gen_dir/${target_name}_files.txt" files = [] - files += rebase_path(generated_html_files, root_build_dir) + files += rebase_path(dr_generated_html_files, root_build_dir) files += rebase_path(remoting_webapp_crd_files, root_build_dir) files += rebase_path(extra_files, root_build_dir) write_file(file_list, files) @@ -97,7 +180,7 @@ ] args += [ "--locales_listfile", - listfile_rel, + rebase_path(locales_listfile_output, root_build_dir), ] args += [ "--use_gcd", @@ -105,3 +188,198 @@ ] } } + +template("app_remoting_webapp") { + locales_listfile = target_name + "_locales" + locales_listfile_output = "$target_gen_dir/${target_name}_locales.txt" + + build_locales_listfile(locales_listfile) { + # Template uses locales_listfile_output from outer scope. + } + + feedback_consent_html = target_name + "_feedback_consent_html" + feedback_consent_html_output = + "$target_gen_dir/html/$target_name/feedback_consent.html" + + build_webapp_html(feedback_consent_html) { + html_template_file = ar_feedback_consent_template + html_template_files = [] + js_files = ar_feedback_consent_html_all_js_files + html_output = feedback_consent_html_output + } + + loading_window_html = target_name + "_loading_window_html" + loading_window_html_output = + "$target_gen_dir/html/$target_name/loading_window.html" + + build_webapp_html(loading_window_html) { + html_template_file = ar_loading_window_template + html_template_files = [] + + # The loading window is just a reskin of the message window -- all JS code + # is shared. + js_files = remoting_webapp_message_window_html_all_js_files + html_output = loading_window_html_output + } + + message_window_html = target_name + "_message_window_html" + message_window_html_output = + "$target_gen_dir/html/$target_name/message_window.html" + + build_webapp_html(message_window_html) { + html_template_file = remoting_webapp_template_message_window + html_template_files = [] + js_files = remoting_webapp_message_window_html_all_js_files + html_output = message_window_html_output + } + + wcs_sandbox_html = target_name + "_wcs_sandbox_html" + wcs_sandbox_html_output = "$target_gen_dir/html/$target_name/wcs_sandbox.html" + + build_webapp_html(wcs_sandbox_html) { + html_template_file = remoting_webapp_template_wcs_sandbox + html_template_files = [] + js_files = remoting_webapp_wcs_sandbox_html_all_js_files + html_output = wcs_sandbox_html_output + } + + main_html = target_name + "_main_html" + main_html_output = "$target_gen_dir/html/$target_name/main.html" + + build_webapp_html(main_html) { + html_template_file = ar_main_template + html_template_files = ar_main_template_files + js_files = ar_main_js_files + html_output = main_html_output + } + + action(target_name) { + script = "build-webapp.py" + + app_key = invoker.app_key + app_id = invoker.app_id + app_client_id = invoker.app_client_id + app_name = invoker.app_name + app_description = invoker.app_description + app_capabilities = invoker.app_capabilities + manifest_key = invoker.manifest_key + + # These asserts are so that these variables get marked as being used so + # that GN doesn't complain about them. + assert(app_key != "" || app_key == "") + assert(app_id != "" || app_id == "") + + # TODO(garykac) For internal targets, we need to extract the vendor and app + # name from the target. + ar_app_name = "sample_app" #target_name + ar_app_path = "app_remoting/apps/$ar_app_name" + ar_app_manifest = "$ar_app_path/manifest.json.jinja2" + ar_app_manifest_common = "app_remoting/manifest_common.json.jinja2" + + output_dir = "remoting/app_remoting/$ar_service_environment/$target_name" + zip_path = "remoting/app_remoting/$ar_service_environment/$target_name.zip" + + ar_app_specific_files = [ + "$ar_app_path/icon16.png", + "$ar_app_path/icon48.png", + "$ar_app_path/icon128.png", + "$ar_app_path/loading_splash.png", + ] + + ar_generated_html_files = [ + feedback_consent_html_output, + loading_window_html_output, + message_window_html_output, + wcs_sandbox_html_output, + main_html_output, + ] + + ar_webapp_files = + ar_app_specific_files + ar_shared_resource_files + ar_all_js_files + + inputs = [ + rebase_path(ar_app_manifest, root_build_dir), + rebase_path(ar_app_manifest_common, root_build_dir), + ] + remoting_version_files + ar_webapp_files + + outputs = [ + "$target_gen_dir/$zip_path", + ] + + deps = [ + ":$locales_listfile", + ":$feedback_consent_html", + ":$loading_window_html", + ":$message_window_html", + ":$wcs_sandbox_html", + ":$main_html", + "//remoting/resources", + ] + + # Create a file that contains a list of all the resource files needed + # to build the webapp. This is needed to avoid problems on platforms that + # limit the size of a command line. + file_list = "$target_gen_dir/${target_name}_files.txt" + files = [] + files += rebase_path(ar_generated_html_files, root_build_dir) + files += rebase_path(ar_webapp_files, root_build_dir) + write_file(file_list, files) + + args = [ + buildtype, + version_full, + output_dir, + zip_path, + rebase_path(ar_app_manifest, root_build_dir), + "app_remoting", # Web app type + ] + args += [ + "--files_listfile", + rebase_path(file_list, root_build_dir), + ] + args += [ + "--locales_listfile", + rebase_path(locales_listfile_output, root_build_dir), + ] + args += [ + "--jinja_paths", + rebase_path("app_remoting", root_build_dir), + ] + + if (is_debug) { + # Normally, the app-id for the orchestrator is automatically extracted + # from the webapp's extension id, but that approach doesn't work for + # dev webapp builds (since they all share the same dev extension id). + # The --appid arg will create a webapp that registers the given app-id + # rather than using the extension id. + # This is only done for Dev apps because the app-id for Release apps + # *must* match the extension id. + args += [ + "--appid", + app_id, + ] + } + + args += [ + "--app_name", + app_name, + ] + args += [ + "--app_description", + app_description, + ] + args += [ "--app_capabilities" ] + app_capabilities + args += [ + "--service_environment", + ar_service_environment, + ] + args += [ + "--manifest_key", + manifest_key, + ] + args += [ + "--app_client_id", + app_client_id, + ] + } +}
diff --git a/remoting/webapp/files.gni b/remoting/webapp/files.gni index 08e34271..4bc2b83 100644 --- a/remoting/webapp/files.gni +++ b/remoting/webapp/files.gni
@@ -10,7 +10,8 @@ # MM `Mb.YM. , 8M MM `Mb MM MM MM MM YM. , # .JMML. .JMM.`Mbmmd' `Moo9^Yo.`Wbmd"MML..JMML JMML JMML.`Mbmmd' # -# Please keep this file in sync with remoting/remoting_webapp_files.gypi. +# Please keep this file in sync with remoting/remoting_webapp_files.gypi +# and remoting/app_remoting_webapp_files.gypi. # Jscompile proto files. # These provide type information for jscompile. @@ -235,13 +236,11 @@ remoting_webapp_js_cast_extension_files = [ "crd/js/cast_extension_handler.js" ] # Client JavaScript files. -remoting_webapp_js_client_files = [ "crd/js/video_frame_recorder.js" ] - -# Remoting core JavaScript files. -remoting_webapp_js_core_files = [ +remoting_webapp_js_client_files = [ "crd/js/apps_v2_migration.js", "crd/js/event_handlers.js", "crd/js/gcd_client.js", + "crd/js/video_frame_recorder.js", ] # Gnubby authentication JavaScript files. @@ -278,7 +277,6 @@ "crd/js/crd_auth_dialog.js", "crd/js/crd_event_handlers.js", "crd/js/crd_experimental.js", - "crd/js/crd_main.js", "crd/js/desktop_connected_view.js", "crd/js/desktop_remoting.js", "crd/js/desktop_remoting_activity.js", @@ -324,7 +322,8 @@ # The CRD-specific JavaScript files required by main.html. remoting_webapp_crd_main_html_all_js_files = - remoting_webapp_shared_main_html_js_files + remoting_webapp_crd_js_ui_files + remoting_webapp_shared_main_html_js_files + + remoting_webapp_crd_js_ui_files + [ "crd/js/crd_main.js" ] # These template files are used to construct main.html. remoting_webapp_template_files = [ @@ -353,7 +352,7 @@ ] # -# Webapp background.html generation files. +# DesktopRemoting background.html generation files. # remoting_webapp_template_background = "crd/html/template_background.html" @@ -390,7 +389,7 @@ ] # -# Webapp wcs_sandbox.html generation files. +# DesktopRemoting wcs_sandbox.html generation files. # remoting_webapp_template_wcs_sandbox = "base/html/template_wcs_sandbox.html" @@ -413,7 +412,7 @@ ] # -# Webapp message_window.html generation files. +# DesktopRemoting message_window.html generation files. # remoting_webapp_template_message_window = @@ -428,7 +427,7 @@ remoting_webapp_message_window_html_js_files + [ "base/js/base.js" ] # -# Complete webapp JS and resource files. +# DesktopRemoting webapp JS and resource files. # # All the JavaScript files that are shared by webapps. @@ -498,3 +497,114 @@ "<@(remoting_webapp_template_files)", "<@(remoting_webapp_crd_js_files)", ] + +# +# AppRemoting Files +# + +ar_shared_resource_files = [ + "app_remoting/html/ar_dialog.css", + "app_remoting/html/ar_main.css", + "app_remoting/html/feedback_consent.css", + "app_remoting/html/loading_window.css", + "app_remoting/html/context_menu.css", + "../resources/drag.webp", + ] + remoting_webapp_resource_files + +# +# AppRemoting main.html generation files. +# + +# These template files are used to construct the webapp html files. +ar_main_template = "app_remoting/html/template_lg.html" + +ar_main_template_files = [ + "base/html/client_plugin.html", + "app_remoting/html/context_menu.html", + "app_remoting/html/idle_dialog.html", +] + +ar_main_js_files = [ + "app_remoting/js/application_context_menu.js", + "app_remoting/js/app_connected_view.js", + "app_remoting/js/app_remoting.js", + "app_remoting/js/app_remoting_activity.js", + "app_remoting/js/ar_auth_dialog.js", + "app_remoting/js/ar_main.js", + "app_remoting/js/context_menu_adapter.js", + "app_remoting/js/context_menu_chrome.js", + "app_remoting/js/context_menu_dom.js", + "app_remoting/js/drag_and_drop.js", + "app_remoting/js/idle_detector.js", + "app_remoting/js/keyboard_layouts_menu.js", + "app_remoting/js/loading_window.js", + "app_remoting/js/submenu_manager.js", + "app_remoting/js/window_activation_menu.js", + "base/js/application.js", + "base/js/base.js", + "base/js/message_window_helper.js", + "base/js/message_window_manager.js", + ] + remoting_webapp_shared_js_auth_google_files + + remoting_webapp_shared_js_client_files + + remoting_webapp_shared_js_core_files + + remoting_webapp_shared_js_host_files + + remoting_webapp_shared_js_logging_files + + remoting_webapp_shared_js_signaling_files + + remoting_webapp_shared_js_ui_files + +# +# AppRemoting feedback_consent.html generation files. +# + +ar_feedback_consent_template = + "app_remoting/html/template_feedback_consent.html" + +# These JS files are specific to the feedback consent page and are not part +# of the main JS files. +ar_feedback_consent_html_js_files = [ "app_remoting/js/feedback_consent.js" ] + +# All the JavaScript files required by feedback_consent.html. +ar_feedback_consent_html_all_js_files = [ + "app_remoting/js/feedback_consent.js", + "base/js/base.js", + "base/js/error.js", + "base/js/identity.js", + "base/js/oauth2_api.js", + "base/js/oauth2_api_impl.js", + "base/js/plugin_settings.js", + "base/js/l10n.js", + "base/js/xhr.js", +] + +# +# AppRemoting loading_window.html generation files. +# + +# Variables for loading_window.html. Note that the JS files are the same as +# for message_window.html, and are not duplicated here. +ar_loading_window_template = "app_remoting/html/template_loading_window.html" + +# +# AppRemoting background JS files. +# These files are referenced from the manifest +# + +ar_background_js_files = [ + "app_remoting/js/ar_background.js", + "base/js/platform.js", +] + +ar_all_js_files = + ar_main_js_files + ar_feedback_consent_html_js_files + + remoting_webapp_message_window_html_js_files + + remoting_webapp_wcs_sandbox_html_js_files + ar_background_js_files + +# Files that contain localizable strings. +app_remoting_webapp_localizable_files = + [ + ar_main_template, + ar_feedback_consent_template, + ar_loading_window_template, + remoting_webapp_template_message_window, + remoting_webapp_template_wcs_sandbox, + ] + ar_main_template_files + ar_all_js_files
diff --git a/skia/config/SkUserConfig.h b/skia/config/SkUserConfig.h index ba9bde3f..06c49e7 100644 --- a/skia/config/SkUserConfig.h +++ b/skia/config/SkUserConfig.h
@@ -265,6 +265,10 @@ # define SK_IGNORE_ETC1_SUPPORT #endif +#ifndef SK_SUPPORT_LEGACY_IMAGEFILTER_TRANSFORM_SCRATCH_LAYTER +# define SK_SUPPORT_LEGACY_IMAGEFILTER_TRANSFORM_SCRATCH_LAYTER +#endif + #ifndef SK_IGNORE_GPU_DITHER # define SK_IGNORE_GPU_DITHER #endif
diff --git a/skia/skia_test_expectations.txt b/skia/skia_test_expectations.txt index 0f3de22b..4327f6e 100644 --- a/skia/skia_test_expectations.txt +++ b/skia/skia_test_expectations.txt
@@ -48,9 +48,4 @@ # # START OVERRIDES HERE -# The Skia CL https://codereview.chromium.org/1138893002 -# (Plus xfermode using Sk4px) fixed two images: -crbug.com/487587 fast/canvas/canvas-composite-transformclip.html [ ImageOnlyFailure ] -crbug.com/487587 virtual/display_list_2d_canvas/fast/canvas/canvas-composite-transformclip.html [ ImageOnlyFailure ] - # END OVERRIDES HERE (this line ensures that the file is newline-terminated)
diff --git a/sync/BUILD.gn b/sync/BUILD.gn index bb30475..515f8309 100644 --- a/sync/BUILD.gn +++ b/sync/BUILD.gn
@@ -743,37 +743,6 @@ ] } -# GYP version: sync/sync_tests.gypi:test_support_accounts_client -static_library("test_support_accounts_client") { - testonly = true - sources = [ - "test/accounts_client/test_accounts_client.cc", - "test/accounts_client/test_accounts_client.h", - "test/accounts_client/url_request_context_getter.cc", - "test/accounts_client/url_request_context_getter.h", - ] - deps = [ - "//base", - "//net", - "//url", - ] -} - -# GYP version: sync/sync_tests.gypi:sync_endtoend_tests -test("sync_endtoend_tests") { - sources = [ - "test/accounts_client/test_accounts_client_unittest.cc", - ] - deps = [ - "//base", - "//base/test:run_all_unittests", - "//testing/gmock", - "//testing/gtest", - "//url", - ":test_support_accounts_client", - ] -} - if (!is_ios) { # GYP version: sync/sync_tests.gypi:run_sync_testserver executable("run_sync_testserver") {
diff --git a/sync/api/sync_data.cc b/sync/api/sync_data.cc index 0dd567d6..d6c9152 100644 --- a/sync/api/sync_data.cc +++ b/sync/api/sync_data.cc
@@ -155,10 +155,9 @@ std::string type = ModelTypeToString(GetDataType()); std::string specifics; - scoped_ptr<base::DictionaryValue> value( - EntitySpecificsToValue(GetSpecifics())); - base::JSONWriter::WriteWithOptions( - value.get(), base::JSONWriter::OPTIONS_PRETTY_PRINT, &specifics); + base::JSONWriter::WriteWithOptions(*EntitySpecificsToValue(GetSpecifics()), + base::JSONWriter::OPTIONS_PRETTY_PRINT, + &specifics); if (IsLocal()) { SyncDataLocal sync_data_local(*this);
diff --git a/sync/engine/traffic_logger.cc b/sync/engine/traffic_logger.cc index bc285bd..1e9a6bc 100644 --- a/sync/engine/traffic_logger.cc +++ b/sync/engine/traffic_logger.cc
@@ -25,9 +25,8 @@ scoped_ptr<base::DictionaryValue> value = (*to_dictionary_value)(data, true /* include_specifics */); std::string message; - base::JSONWriter::WriteWithOptions(value.get(), - base::JSONWriter::OPTIONS_PRETTY_PRINT, - &message); + base::JSONWriter::WriteWithOptions( + *value, base::JSONWriter::OPTIONS_PRETTY_PRINT, &message); DVLOG(1) << "\n" << description << "\n" << message << "\n"; } }
diff --git a/sync/internal_api/public/engine/model_safe_worker.cc b/sync/internal_api/public/engine/model_safe_worker.cc index 9692a78e..f054e503 100644 --- a/sync/internal_api/public/engine/model_safe_worker.cc +++ b/sync/internal_api/public/engine/model_safe_worker.cc
@@ -24,10 +24,8 @@ std::string ModelSafeRoutingInfoToString( const ModelSafeRoutingInfo& routing_info) { - scoped_ptr<base::DictionaryValue> dict = - ModelSafeRoutingInfoToValue(routing_info); std::string json; - base::JSONWriter::Write(dict.get(), &json); + base::JSONWriter::Write(*ModelSafeRoutingInfoToValue(routing_info), &json); return json; }
diff --git a/sync/internal_api/public/sessions/sync_session_snapshot.cc b/sync/internal_api/public/sessions/sync_session_snapshot.cc index dcb3f73..9614330 100644 --- a/sync/internal_api/public/sessions/sync_session_snapshot.cc +++ b/sync/internal_api/public/sessions/sync_session_snapshot.cc
@@ -105,7 +105,7 @@ std::string SyncSessionSnapshot::ToString() const { std::string json; base::JSONWriter::WriteWithOptions( - ToValue().get(), base::JSONWriter::OPTIONS_PRETTY_PRINT, &json); + *ToValue(), base::JSONWriter::OPTIONS_PRETTY_PRINT, &json); return json; }
diff --git a/sync/js/js_event_details.cc b/sync/js/js_event_details.cc index 0517b39..d430632 100644 --- a/sync/js/js_event_details.cc +++ b/sync/js/js_event_details.cc
@@ -21,7 +21,7 @@ std::string JsEventDetails::ToString() const { std::string str; - base::JSONWriter::Write(&Get(), &str); + base::JSONWriter::Write(Get(), &str); return str; }
diff --git a/sync/sync_tests.gypi b/sync/sync_tests.gypi index 198f659..eba5872 100644 --- a/sync/sync_tests.gypi +++ b/sync/sync_tests.gypi
@@ -373,46 +373,6 @@ }], ], }, - - # Test support files for using the Test Accounts service. - # GN version: //sync:test_support_accounts_client - { - 'target_name': 'test_support_accounts_client', - 'type': 'static_library', - 'direct_dependent_settings': { - 'include_dirs': [ - '..', - ], - }, - 'dependencies': [ - '../base/base.gyp:base', - '../net/net.gyp:net', - ], - 'sources': [ - 'test/accounts_client/test_accounts_client.cc', - 'test/accounts_client/test_accounts_client.h', - 'test/accounts_client/url_request_context_getter.cc', - 'test/accounts_client/url_request_context_getter.h', - ], - }, - - # The Sync end-to-end (and associated infrastructure) tests. - # GN version: //sync:sync_endtoend_tests - { - 'target_name': 'sync_endtoend_tests', - 'type': '<(gtest_target_type)', - 'dependencies': [ - '../base/base.gyp:run_all_unittests', - '../testing/gmock.gyp:gmock', - '../testing/gtest.gyp:gtest', - '../url/url.gyp:url_lib', - 'test_support_accounts_client', - ], - 'sources': [ - 'test/accounts_client/test_accounts_client_unittest.cc', - ], - }, - ], 'conditions': [ ['OS != "ios"', {
diff --git a/sync/syncable/nigori_util.cc b/sync/syncable/nigori_util.cc index 1eb92277..1ad5095 100644 --- a/sync/syncable/nigori_util.cc +++ b/sync/syncable/nigori_util.cc
@@ -175,9 +175,8 @@ if (VLOG_IS_ON(2)) { scoped_ptr<base::DictionaryValue> value(entry->ToValue(NULL)); std::string info; - base::JSONWriter::WriteWithOptions(value.get(), - base::JSONWriter::OPTIONS_PRETTY_PRINT, - &info); + base::JSONWriter::WriteWithOptions( + *value, base::JSONWriter::OPTIONS_PRETTY_PRINT, &info); DVLOG(2) << "Encrypting specifics of type " << ModelTypeToString(type) << " with content: "
diff --git a/sync/test/accounts_client/DEPS b/sync/test/accounts_client/DEPS deleted file mode 100644 index db6d6e2..0000000 --- a/sync/test/accounts_client/DEPS +++ /dev/null
@@ -1,5 +0,0 @@ -include_rules = [ - # Allow this directory to depend on net since it's test infrastructure and - # not test cases. - "+net", -]
diff --git a/sync/test/accounts_client/test_accounts_client.cc b/sync/test/accounts_client/test_accounts_client.cc deleted file mode 100644 index 2856ed2..0000000 --- a/sync/test/accounts_client/test_accounts_client.cc +++ /dev/null
@@ -1,161 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "sync/test/accounts_client/test_accounts_client.h" - -#include <algorithm> -#include <string> -#include <vector> - -#include "base/json/json_reader.h" -#include "base/json/json_writer.h" -#include "base/message_loop/message_loop.h" -#include "base/run_loop.h" -#include "base/strings/stringprintf.h" -#include "base/time/time.h" -#include "base/values.h" -#include "net/base/url_util.h" -#include "net/http/http_status_code.h" -#include "net/url_request/url_fetcher.h" -#include "net/url_request/url_fetcher_delegate.h" -#include "net/url_request/url_request.h" -#include "net/url_request/url_request_context_getter.h" -#include "sync/test/accounts_client/url_request_context_getter.h" - -using std::string; -using std::vector; - -static const int kMaxSessionLifetimeSeconds = 30 * 60; -static const string kClaimPath = "claim"; -static const string kReleasePath = "release"; -static const base::TimeDelta kRequestTimeout = base::TimeDelta::FromSeconds(10); - -AccountSession::AccountSession() {} -AccountSession::~AccountSession() {} - -class AccountsRequestDelegate : public net::URLFetcherDelegate { - public: - AccountsRequestDelegate(base::RunLoop* run_loop) : response_(""), - success_(false), run_loop_(run_loop) {} - - void OnURLFetchComplete(const net::URLFetcher* source) override { - string url = source->GetURL().spec(); - source->GetResponseAsString(&response_); - - if (!source->GetStatus().is_success()) { - int error = source->GetStatus().error(); - DVLOG(0) << "The request failed with error code " << error << "." - << "\nRequested URL: " << url << "."; - } else if (source->GetResponseCode() != net::HTTP_OK) { - DVLOG(0) << "The request failed with response code " - << source->GetResponseCode() << "." - << "\nRequested URL: " << url - << "\nResponse body: \"" << response_ << "\""; - } else { - success_ = true; - } - - run_loop_->Quit(); - } - - string response() const { return response_; } - bool success() const { return success_; } - - private: - string response_; - bool success_; - base::RunLoop* run_loop_; -}; - -TestAccountsClient::TestAccountsClient(const string& server, - const string& account_space, - const vector<string>& usernames) - : server_(server), account_space_(account_space), usernames_(usernames) { -} - -TestAccountsClient::~TestAccountsClient() {} - -bool TestAccountsClient::ClaimAccount(AccountSession* session) { - GURL url = CreateGURLWithPath(kClaimPath); - url = net::AppendQueryParameter(url, "account_space", account_space_); - string max_lifetime_seconds = base::StringPrintf("%d", - kMaxSessionLifetimeSeconds); - url = net::AppendQueryParameter(url, "max_lifetime_seconds", - max_lifetime_seconds); - - // TODO(pvalenzuela): Select N random usernames instead of all usernames. - for (vector<string>::iterator it = usernames_.begin(); - it != usernames_.end(); ++it) { - url = net::AppendQueryParameter(url, "username", *it); - } - - string response; - if (!SendRequest(url, &response)) { - return false; - } - - scoped_ptr<base::Value> value(base::JSONReader::Read(response)); - base::DictionaryValue* dict_value; - if (value != NULL && value->GetAsDictionary(&dict_value) && - dict_value != NULL) { - dict_value->GetString("username", &session->username); - dict_value->GetString("account_space", &session->account_space); - dict_value->GetString("session_id", &session->session_id); - dict_value->GetString("expiration_time", &session->expiration_time); - } else { - return false; - } - - return true; -} - -void TestAccountsClient::ReleaseAccount(const AccountSession& session) { - // The expiration_time field is ignored since it isn't passed as part of the - // release request. - if (session.username.empty() || session.account_space.empty() || - account_space_.compare(session.account_space) != 0 || - session.session_id.empty()) { - return; - } - - GURL url = CreateGURLWithPath(kReleasePath); - url = net::AppendQueryParameter(url, "account_space", session.account_space); - url = net::AppendQueryParameter(url, "username", session.username); - url = net::AppendQueryParameter(url, "session_id", session.session_id); - - // This operation is best effort, so don't send any errors back to the caller. - string response; - SendRequest(url, &response); -} - -GURL TestAccountsClient::CreateGURLWithPath(const string& path) { - return GURL(base::StringPrintf("%s/%s", server_.c_str(), path.c_str())); -} - - -bool TestAccountsClient::SendRequest(const GURL& url, string* response) { - base::MessageLoop* loop = base::MessageLoop::current(); - scoped_refptr<URLRequestContextGetter> context_getter( - new URLRequestContextGetter(loop->message_loop_proxy())); - - base::RunLoop run_loop; - - AccountsRequestDelegate delegate(&run_loop); - scoped_ptr<net::URLFetcher> fetcher = - net::URLFetcher::Create(url, net::URLFetcher::POST, &delegate); - fetcher->SetRequestContext(context_getter.get()); - fetcher->SetUploadData("application/json", ""); - fetcher->Start(); - - base::MessageLoop::current()->PostDelayedTask(FROM_HERE, - run_loop.QuitClosure(), - kRequestTimeout); - run_loop.Run(); - - if (delegate.success()) { - *response = delegate.response(); - } - - return delegate.success(); -}
diff --git a/sync/test/accounts_client/test_accounts_client.h b/sync/test/accounts_client/test_accounts_client.h deleted file mode 100644 index 15a582e..0000000 --- a/sync/test/accounts_client/test_accounts_client.h +++ /dev/null
@@ -1,63 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef SYNC_TEST_ACCOUNTS_CLIENT_TEST_ACCOUNTS_CLIENT_H_ -#define SYNC_TEST_ACCOUNTS_CLIENT_TEST_ACCOUNTS_CLIENT_H_ - -#include <string> -#include <vector> - -#include "base/message_loop/message_loop.h" -#include "url/gurl.h" - -using std::string; -using std::vector; - -// The data associated with an account session. -struct AccountSession { - AccountSession(); - ~AccountSession(); - - string username; - string account_space; - string session_id; - string expiration_time; -}; - -// A test-side client for the Test Accounts service. This service provides -// short-term, exclusive access to test accounts for the purpose of testing -// against real Chrome Sync servers. -class TestAccountsClient { - public: - // Creates a client associated with the given |server| URL (e.g., - // http://service-runs-here.com), |account_space| (for account segregation), - // and |usernames| (the collection of accounts to be chosen from). - TestAccountsClient(const string& server, - const string& account_space, - const vector<string>& usernames); - - virtual ~TestAccountsClient(); - - // Attempts to claim an account via the Test Accounts service. If - // successful, true is returned and the given |session| has its data set. - // If an error occurred, then false is returned. - bool ClaimAccount(AccountSession* session); - - // Attempts to release an account via the Test Accounts service. The value - // of |session| should be one returned from ClaimAccount(). This function - // is best-effort and fails silently. - void ReleaseAccount(const AccountSession& session); - - // Sends an HTTP POST request to the Test Accounts service. - virtual bool SendRequest(const GURL& url, string* response); - - private: - GURL CreateGURLWithPath(const string& path); - base::MessageLoopForIO io_loop_; - const string server_; - const string account_space_; - vector<string> usernames_; -}; - -#endif // SYNC_TEST_ACCOUNTS_CLIENT_TEST_ACCOUNTS_CLIENT_H_
diff --git a/sync/test/accounts_client/test_accounts_client_unittest.cc b/sync/test/accounts_client/test_accounts_client_unittest.cc deleted file mode 100644 index f73a43b..0000000 --- a/sync/test/accounts_client/test_accounts_client_unittest.cc +++ /dev/null
@@ -1,98 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include <vector> - -#include "base/json/json_writer.h" -#include "base/values.h" -#include "sync/test/accounts_client/test_accounts_client.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "url/gurl.h" - -using std::string; -using std::vector; -using testing::_; -using testing::DoAll; -using testing::Return; -using testing::SetArgPointee; - -namespace { -static const string kServer = "https://test-account-service"; -static const string kUsername = "foobar@baz.com"; -static const string kAccountSpace = "test_account_space"; -static const string kSessionId = "1234-ABCD"; -static const string kExpirationTime = "12:00"; -} // namespace - -static AccountSession CreateValidAccountSession() { - AccountSession session; - session.username = kUsername; - session.account_space = kAccountSpace; - session.session_id = kSessionId; - session.expiration_time = kExpirationTime; - return session; -} - -class NoNetworkTestAccountsClient : public TestAccountsClient { - public: - NoNetworkTestAccountsClient(const string& server, - const string& account_space, - vector<string> usernames) - : TestAccountsClient(server, account_space, usernames) {} - MOCK_METHOD2(SendRequest, bool(const GURL&, string*)); -}; - -TEST(TestAccountsClientTest, ClaimAccountError) { - vector<string> usernames; - NoNetworkTestAccountsClient client(kServer, kAccountSpace, usernames); - EXPECT_CALL(client, SendRequest(_, _)) - .WillOnce(Return(false)); - AccountSession session; - EXPECT_FALSE(client.ClaimAccount(&session)); -} - -TEST(TestAccountsClientTest, ClaimAccountSuccess) { - vector<string> usernames; - usernames.push_back("foo0@gmail.com"); - usernames.push_back("foo1@gmail.com"); - usernames.push_back("foo2@gmail.com"); - NoNetworkTestAccountsClient client(kServer, kAccountSpace, usernames); - - base::DictionaryValue success_dict; - success_dict.Set("username", new base::StringValue(kUsername)); - success_dict.Set("account_space", new base::StringValue(kAccountSpace)); - success_dict.Set("session_id", new base::StringValue(kSessionId)); - success_dict.Set("expiration_time", new base::StringValue(kExpirationTime)); - - string success_response; - base::JSONWriter::Write(&success_dict, &success_response); - EXPECT_CALL(client, SendRequest(_, _)) - .WillOnce(DoAll(SetArgPointee<1>(success_response), Return(true))); - - AccountSession session; - EXPECT_TRUE(client.ClaimAccount(&session)); - EXPECT_EQ(kUsername, session.username); - EXPECT_EQ(kAccountSpace, session.account_space); - EXPECT_EQ(kSessionId, session.session_id); - EXPECT_EQ(kExpirationTime, session.expiration_time); -} - -TEST(TestAccountsClientTest, ReleaseAccountEmptySession) { - vector<string> usernames; - NoNetworkTestAccountsClient client(kServer, kAccountSpace, usernames); - AccountSession session; - // No expectation for SendRequest is made because no network call should be - // performed in this scenario. - client.ReleaseAccount(session); -} - -TEST(TestAccountsClientTest, ReleaseAccountSuccess) { - vector<string> usernames; - NoNetworkTestAccountsClient client(kServer, kAccountSpace, usernames); - EXPECT_CALL(client, SendRequest(_, _)) - .WillOnce(Return(true)); - AccountSession session = CreateValidAccountSession(); - client.ReleaseAccount(session); -}
diff --git a/sync/test/accounts_client/url_request_context_getter.cc b/sync/test/accounts_client/url_request_context_getter.cc deleted file mode 100644 index 11e1cc2..0000000 --- a/sync/test/accounts_client/url_request_context_getter.cc +++ /dev/null
@@ -1,39 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "sync/test/accounts_client/url_request_context_getter.h" - -#include <string> - -#include "net/proxy/proxy_config_service_fixed.h" -#include "net/url_request/url_request_context.h" -#include "net/url_request/url_request_context_builder.h" - -URLRequestContextGetter::URLRequestContextGetter( - scoped_refptr<base::SingleThreadTaskRunner> network_task_runner) - : network_task_runner_(network_task_runner) { -} - -net::URLRequestContext* URLRequestContextGetter::GetURLRequestContext() { - CHECK(network_task_runner_->BelongsToCurrentThread()); - if (!url_request_context_) { - net::URLRequestContextBuilder builder; - // net::HttpServer fails to parse headers if user-agent header is blank. - builder.set_user_agent("sync-test-accounts-client"); - builder.DisableHttpCache(); -#if defined(OS_LINUX) || defined(OS_ANDROID) - builder.set_proxy_config_service( - new net::ProxyConfigServiceFixed(net::ProxyConfig::CreateDirect())); -#endif - url_request_context_.reset(builder.Build()); - } - return url_request_context_.get(); -} - -scoped_refptr<base::SingleThreadTaskRunner> - URLRequestContextGetter::GetNetworkTaskRunner() const { - return network_task_runner_; -} - -URLRequestContextGetter::~URLRequestContextGetter() {}
diff --git a/sync/test/accounts_client/url_request_context_getter.h b/sync/test/accounts_client/url_request_context_getter.h deleted file mode 100644 index 20a3931..0000000 --- a/sync/test/accounts_client/url_request_context_getter.h +++ /dev/null
@@ -1,43 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef SYNC_TEST_ACCOUNTS_CLIENT_URL_REQUEST_CONTEXT_GETTER_H_ -#define SYNC_TEST_ACCOUNTS_CLIENT_URL_REQUEST_CONTEXT_GETTER_H_ - -#include "base/basictypes.h" -#include "base/compiler_specific.h" -#include "base/memory/ref_counted.h" -#include "base/memory/scoped_ptr.h" -#include "net/url_request/url_request_context_getter.h" - -namespace base { -class SingleThreadTaskRunner; -} - -namespace net { -class URLRequestContext; -} - -class URLRequestContextGetter : public net::URLRequestContextGetter { - public: - explicit URLRequestContextGetter( - scoped_refptr<base::SingleThreadTaskRunner> network_task_runner); - - // Overridden from net::URLRequestContextGetter: - net::URLRequestContext* GetURLRequestContext() override; - scoped_refptr<base::SingleThreadTaskRunner> GetNetworkTaskRunner() - const override; - - private: - ~URLRequestContextGetter() override; - - scoped_refptr<base::SingleThreadTaskRunner> network_task_runner_; - - // Only accessed on the IO thread. - scoped_ptr<net::URLRequestContext> url_request_context_; - - DISALLOW_COPY_AND_ASSIGN(URLRequestContextGetter); -}; - -#endif // SYNC_TEST_ACCOUNTS_CLIENT_URL_REQUEST_CONTEXT_GETTER_H_
diff --git a/sync/test/fake_server/fake_server_verifier.cc b/sync/test/fake_server/fake_server_verifier.cc index bc64550..b968d0f 100644 --- a/sync/test/fake_server/fake_server_verifier.cc +++ b/sync/test/fake_server/fake_server_verifier.cc
@@ -53,8 +53,7 @@ string ConvertFakeServerContentsToString( const base::DictionaryValue& entities) { string entities_str; - if (!JSONWriter::WriteWithOptions(&entities, - JSONWriter::OPTIONS_PRETTY_PRINT, + if (!JSONWriter::WriteWithOptions(entities, JSONWriter::OPTIONS_PRETTY_PRINT, &entities_str)) { entities_str = "Could not convert FakeServer contents to string."; }
diff --git a/sync/tools/sync_client.cc b/sync/tools/sync_client.cc index 8422d2e..1106460 100644 --- a/sync/tools/sync_client.cc +++ b/sync/tools/sync_client.cc
@@ -122,7 +122,7 @@ std::string ValueToString(const base::Value& value) { std::string str; - base::JSONWriter::Write(&value, &str); + base::JSONWriter::Write(value, &str); return str; }
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json index 670524f70..5596e6b 100644 --- a/testing/buildbot/chromium.fyi.json +++ b/testing/buildbot/chromium.fyi.json
@@ -17,64 +17,6 @@ } ] }, - "Cast Linux": { - "gtest_tests": [ - { - "test": "base_unittests" - }, - { - "test": "cacheinvalidation_unittests" - }, - { - "test": "cast_base_unittests" - }, - { - "test": "cast_media_unittests" - }, - { - "test": "cast_shell_browser_test" - }, - { - "test": "content_unittests" - }, - { - "test": "crypto_unittests" - }, - { - "test": "gpu_unittests" - }, - { - "test": "ipc_tests" - }, - { - "test": "jingle_unittests" - }, - { - "test": "media_unittests" - }, - { - "test": "midi_unittests" - }, - { - "test": "net_unittests" - }, - { - "test": "sandbox_linux_unittests" - }, - { - "test": "sql_unittests" - }, - { - "test": "sync_unit_tests" - }, - { - "test": "ui_base_unittests" - }, - { - "test": "url_unittests" - } - ] - }, "Chromium Mac 10.10": { "gtest_tests": [ {
diff --git a/testing/buildbot/chromium.linux.json b/testing/buildbot/chromium.linux.json index c18aece..f0cfa3b 100644 --- a/testing/buildbot/chromium.linux.json +++ b/testing/buildbot/chromium.linux.json
@@ -35,6 +35,64 @@ } ] }, + "Cast Linux": { + "gtest_tests": [ + { + "test": "base_unittests" + }, + { + "test": "cacheinvalidation_unittests" + }, + { + "test": "cast_base_unittests" + }, + { + "test": "cast_media_unittests" + }, + { + "test": "cast_shell_browser_test" + }, + { + "test": "content_unittests" + }, + { + "test": "crypto_unittests" + }, + { + "test": "gpu_unittests" + }, + { + "test": "ipc_tests" + }, + { + "test": "jingle_unittests" + }, + { + "test": "media_unittests" + }, + { + "test": "midi_unittests" + }, + { + "test": "net_unittests" + }, + { + "test": "sandbox_linux_unittests" + }, + { + "test": "sql_unittests" + }, + { + "test": "sync_unit_tests" + }, + { + "test": "ui_base_unittests" + }, + { + "test": "url_unittests" + } + ] + }, "Linux Clang (dbg)": { "gtest_tests": [ {
diff --git a/third_party/boringssl/BUILD.gn b/third_party/boringssl/BUILD.gn index cd398de..8ce890d 100644 --- a/third_party/boringssl/BUILD.gn +++ b/third_party/boringssl/BUILD.gn
@@ -25,7 +25,7 @@ # Windows' assembly is built with Yasm. The other platforms use the platform # assembler. -if (is_win) { +if (is_win && !is_msan) { import("//third_party/yasm/yasm_assemble.gni") yasm_assemble("boringssl_asm") { if (current_cpu == "x64") { @@ -70,7 +70,9 @@ "src/crypto", ] - if (current_cpu == "x64") { + if (is_msan) { + defines += [ "OPENSSL_NO_ASM" ] + } else if (current_cpu == "x64") { if (is_mac || is_ios) { sources += gypi_values.boringssl_mac_x86_64_sources } else if (is_linux || is_android) {
diff --git a/third_party/boringssl/boringssl.gyp b/third_party/boringssl/boringssl.gyp index f3a169d5..3079d0b6 100644 --- a/third_party/boringssl/boringssl.gyp +++ b/third_party/boringssl/boringssl.gyp
@@ -26,7 +26,7 @@ 'BORINGSSL_SHARED_LIBRARY', ], }], - ['target_arch == "arm"', { + ['target_arch == "arm" and msan == 0', { 'conditions': [ ['OS == "linux" or OS == "android"', { 'sources': [ '<@(boringssl_linux_arm_sources)' ], @@ -35,7 +35,7 @@ }], ], }], - ['target_arch == "arm64"', { + ['target_arch == "arm64" and msan == 0', { 'conditions': [ ['OS == "linux" or OS == "android"', { 'sources': [ '<@(boringssl_linux_aarch64_sources)' ], @@ -44,7 +44,7 @@ }], ], }], - ['target_arch == "ia32"', { + ['target_arch == "ia32" and msan == 0', { 'conditions': [ ['OS == "mac" or OS == "ios"', { 'sources': [ '<@(boringssl_mac_x86_sources)' ], @@ -68,7 +68,7 @@ }], ] }], - ['target_arch == "x64"', { + ['target_arch == "x64" and msan == 0', { 'conditions': [ ['OS == "mac" or OS == "ios"', { 'sources': [ '<@(boringssl_mac_x86_64_sources)' ], @@ -92,7 +92,7 @@ }], ] }], - ['target_arch != "arm" and target_arch != "ia32" and target_arch != "x64" and target_arch != "arm64"', { + ['msan == 1 or (target_arch != "arm" and target_arch != "ia32" and target_arch != "x64" and target_arch != "arm64")', { 'defines': [ 'OPENSSL_NO_ASM' ], }], ],
diff --git a/third_party/boringssl/boringssl_tests.gypi b/third_party/boringssl/boringssl_tests.gypi index cec67805..58dc9ad 100644 --- a/third_party/boringssl/boringssl_tests.gypi +++ b/third_party/boringssl/boringssl_tests.gypi
@@ -83,7 +83,7 @@ 'boringssl.gyp:boringssl', ], 'sources': [ - 'src/crypto/cipher/cipher_test.c', + 'src/crypto/cipher/cipher_test.cc', '<@(boringssl_test_support_sources)', ], # TODO(davidben): Fix size_t truncations in BoringSSL.
diff --git a/third_party/boringssl/err_data.c b/third_party/boringssl/err_data.c index 68397e4bb..f09b1c2 100644 --- a/third_party/boringssl/err_data.c +++ b/third_party/boringssl/err_data.c
@@ -79,202 +79,202 @@ 0xc3d0679, 0xc3d8681, 0xc3e068c, - 0x103218ee, - 0x10329905, - 0x1033191e, - 0x10339934, - 0x10341944, - 0x10349957, - 0x10351965, - 0x10359974, - 0x10361994, - 0x103699b3, - 0x103719d0, - 0x103799ed, - 0x10381a02, - 0x10389a24, - 0x10391a43, - 0x10399a62, - 0x103a1a79, - 0x103a9a90, - 0x103b1a99, - 0x103b9aa4, - 0x103c1abe, - 0x103c9ac6, - 0x103d1ace, - 0x103d9ad5, - 0x103e1ae8, - 0x103e9afa, - 0x103f1b0d, - 0x103f9b16, + 0x1032191e, + 0x10329935, + 0x1033194e, + 0x10339964, + 0x10341974, + 0x10349987, + 0x10351995, + 0x103599a4, + 0x103619c4, + 0x103699e3, + 0x10371a00, + 0x10379a1d, + 0x10381a32, + 0x10389a54, + 0x10391a73, + 0x10399a92, + 0x103a1aa9, + 0x103a9ac0, + 0x103b1ac9, + 0x103b9ad4, + 0x103c1aee, + 0x103c9af6, + 0x103d1afe, + 0x103d9b05, + 0x103e1b18, + 0x103e9b2a, + 0x103f1b3d, + 0x103f9b46, 0x14320a2f, 0x14328a3d, 0x14330a49, 0x14338a56, - 0x183611d5, - 0x18371203, - 0x18379214, - 0x1838122a, - 0x1839124d, - 0x18399262, - 0x183a1274, - 0x183c12b8, - 0x183c92c6, - 0x183d12d9, - 0x183d92e9, - 0x183e930f, - 0x183f1322, - 0x183f9331, - 0x1840935b, - 0x184113c7, - 0x184193d8, - 0x184213eb, - 0x184293fd, - 0x1843140f, - 0x18439420, - 0x18441431, - 0x18449442, - 0x18451453, - 0x18459460, - 0x18461482, - 0x18469495, - 0x184714a9, - 0x184794b6, - 0x184814c5, - 0x184894d4, - 0x184914e5, - 0x18499501, - 0x184a150f, - 0x184a9520, - 0x184b1531, - 0x184b953f, - 0x184c154f, - 0x184c9575, - 0x184d1584, - 0x184d9594, - 0x184e15a4, - 0x184e95b3, - 0x184f14f2, - 0x184f9164, - 0x18501107, - 0x1850911f, - 0x18511141, - 0x18519153, - 0x18521185, - 0x1852919e, - 0x185311af, - 0x185391c5, - 0x185411ea, - 0x1854923b, - 0x18551284, - 0x18559299, - 0x185612a6, - 0x185692fe, - 0x18571341, - 0x1857934e, - 0x1858136a, - 0x1858937b, - 0x1859138b, - 0x1859939b, - 0x185a13aa, - 0x185a93b9, - 0x185b146e, + 0x18361205, + 0x18371233, + 0x18379244, + 0x1838125a, + 0x1839127d, + 0x18399292, + 0x183a12a4, + 0x183c12e8, + 0x183c92f6, + 0x183d1309, + 0x183d9319, + 0x183e933f, + 0x183f1352, + 0x183f9361, + 0x1840938b, + 0x184113f7, + 0x18419408, + 0x1842141b, + 0x1842942d, + 0x1843143f, + 0x18439450, + 0x18441461, + 0x18449472, + 0x18451483, + 0x18459490, + 0x184614b2, + 0x184694c5, + 0x184714d9, + 0x184794e6, + 0x184814f5, + 0x18489504, + 0x18491515, + 0x18499531, + 0x184a153f, + 0x184a9550, + 0x184b1561, + 0x184b956f, + 0x184c157f, + 0x184c95a5, + 0x184d15b4, + 0x184d95c4, + 0x184e15d4, + 0x184e95e3, + 0x184f1522, + 0x184f9194, + 0x18501137, + 0x1850914f, + 0x18511171, + 0x18519183, + 0x185211b5, + 0x185291ce, + 0x185311df, + 0x185391f5, + 0x1854121a, + 0x1854926b, + 0x185512b4, + 0x185592c9, + 0x185612d6, + 0x1856932e, + 0x18571371, + 0x1857937e, + 0x1858139a, + 0x185893ab, + 0x185913bb, + 0x185993cb, + 0x185a13da, + 0x185a93e9, + 0x185b149e, 0x1c320699, 0x1c3286a5, 0x1c3306b0, 0x1c3386bc, - 0x203215c7, - 0x203295d2, - 0x203315da, - 0x203395e6, - 0x243215f2, - 0x24329600, - 0x24331612, - 0x24339621, - 0x24341634, - 0x24349647, - 0x2435165e, - 0x24359676, - 0x24361684, - 0x2436969c, - 0x243716a5, - 0x243796b7, - 0x243816cb, - 0x243896d8, - 0x243916ee, - 0x24399706, - 0x243a171e, - 0x243a9728, - 0x243b173d, - 0x243b974b, - 0x243c1763, - 0x243c977a, - 0x243d1785, - 0x243d9793, + 0x203215f7, + 0x20329602, + 0x2033160a, + 0x20339616, + 0x24321622, + 0x24329630, + 0x24331642, + 0x24339651, + 0x24341664, + 0x24349677, + 0x2435168e, + 0x243596a6, + 0x243616b4, + 0x243696cc, + 0x243716d5, + 0x243796e7, + 0x243816fb, + 0x24389708, + 0x2439171e, + 0x24399736, + 0x243a174e, + 0x243a9758, + 0x243b176d, + 0x243b977b, + 0x243c1793, + 0x243c97aa, + 0x243d17b5, + 0x243d97c3, 0x28320a8f, 0x28328a9e, 0x28330aa9, 0x28338aae, 0x28340ab9, - 0x2c322a70, - 0x2c32aa7c, - 0x2c332a8f, - 0x2c33aaa0, - 0x2c342ab9, - 0x2c34aae1, - 0x2c352af8, - 0x2c35ab15, - 0x2c362b32, - 0x2c36ab4f, - 0x2c372b68, - 0x2c37ab81, - 0x2c382b97, - 0x2c38aba5, - 0x2c392bb7, - 0x2c39abd4, - 0x2c3a2bf1, - 0x2c3aabff, - 0x2c3b2c1d, - 0x2c3bac3b, - 0x2c3c2c56, - 0x2c3cac6a, - 0x2c3d2c7c, - 0x2c3dac8c, - 0x2c3e2c9a, - 0x2c3eacaa, - 0x2c3f2cba, - 0x2c3facd5, - 0x2c402ce6, - 0x2c40ad01, - 0x2c412d15, - 0x2c41ad28, - 0x2c422d47, - 0x2c42ad5b, - 0x2c432d6e, - 0x2c43ad7d, - 0x2c442d8c, - 0x2c44ada3, - 0x2c452dbe, - 0x2c45add6, - 0x2c462dea, - 0x2c46adfd, - 0x2c472e0e, - 0x2c47ae1f, - 0x2c482e30, - 0x2c48ae41, - 0x2c492e50, - 0x2c49ae5d, - 0x2c4a2e6a, - 0x2c4aae77, - 0x2c4b2e80, - 0x2c4bae94, - 0x2c4c2ea3, - 0x2c4caeb1, - 0x2c4d2ed3, - 0x2c4daee4, - 0x2c4e2ef5, - 0x2c4eaec0, - 0x2c4f2ad2, + 0x2c322aa0, + 0x2c32aaac, + 0x2c332abf, + 0x2c33aad0, + 0x2c342ae9, + 0x2c34ab11, + 0x2c352b28, + 0x2c35ab45, + 0x2c362b62, + 0x2c36ab7f, + 0x2c372b98, + 0x2c37abb1, + 0x2c382bc7, + 0x2c38abd5, + 0x2c392be7, + 0x2c39ac04, + 0x2c3a2c21, + 0x2c3aac2f, + 0x2c3b2c4d, + 0x2c3bac6b, + 0x2c3c2c86, + 0x2c3cac9a, + 0x2c3d2cac, + 0x2c3dacbc, + 0x2c3e2cca, + 0x2c3eacda, + 0x2c3f2cea, + 0x2c3fad05, + 0x2c402d16, + 0x2c40ad31, + 0x2c412d45, + 0x2c41ad58, + 0x2c422d77, + 0x2c42ad8b, + 0x2c432d9e, + 0x2c43adad, + 0x2c442dbc, + 0x2c44add3, + 0x2c452dee, + 0x2c45ae06, + 0x2c462e1a, + 0x2c46ae2d, + 0x2c472e3e, + 0x2c47ae4f, + 0x2c482e60, + 0x2c48ae71, + 0x2c492e80, + 0x2c49ae8d, + 0x2c4a2e9a, + 0x2c4aaea7, + 0x2c4b2eb0, + 0x2c4baec4, + 0x2c4c2ed3, + 0x2c4caee1, + 0x2c4d2f03, + 0x2c4daf14, + 0x2c4e2f25, + 0x2c4eaef0, + 0x2c4f2b02, 0x30320000, 0x30328018, 0x3033002c, @@ -351,239 +351,241 @@ 0x3c328ada, 0x3c330af1, 0x3c338b05, - 0x3c340b20, - 0x3c348b31, - 0x3c350b3d, - 0x3c358b51, - 0x3c360b63, - 0x3c368b8c, - 0x3c370b99, - 0x3c378ba6, - 0x3c380bb4, - 0x3c388bc1, - 0x3c390bce, - 0x3c398bf2, - 0x3c3a0c02, - 0x3c3a8c1a, - 0x3c3b0c2f, - 0x3c3b8c44, - 0x3c3c0c51, - 0x3c3c8c64, - 0x3c3d0c77, - 0x3c3d8c9b, - 0x3c3e0cc3, - 0x3c3e8cdc, - 0x3c3f0cf2, - 0x3c3f8cff, - 0x3c400d12, - 0x3c408d23, - 0x3c410d34, - 0x3c418d4d, - 0x3c420d66, - 0x3c428d7c, - 0x3c430d99, - 0x3c438daf, - 0x3c440e33, - 0x3c448e5a, - 0x3c450e78, - 0x3c458e92, - 0x3c460eaa, - 0x3c468ec2, - 0x3c470eed, - 0x3c478f18, - 0x3c480f39, - 0x3c488f62, - 0x3c490f7d, - 0x3c498fa6, - 0x3c4a0fb3, - 0x3c4a8fca, - 0x3c4b0fe1, - 0x3c4b900a, - 0x3c4c101a, - 0x3c4c9026, - 0x3c4d103e, - 0x3c4d9051, - 0x3c4e1062, - 0x3c4e9073, - 0x3c4f1099, + 0x3c340b37, + 0x3c348b48, + 0x3c350b54, + 0x3c358b81, + 0x3c360b93, + 0x3c368bbc, + 0x3c370bc9, + 0x3c378bd6, + 0x3c380be4, + 0x3c388bf1, + 0x3c390bfe, + 0x3c398c22, + 0x3c3a0c32, + 0x3c3a8c4a, + 0x3c3b0c5f, + 0x3c3b8c74, + 0x3c3c0c81, + 0x3c3c8c94, + 0x3c3d0ca7, + 0x3c3d8ccb, + 0x3c3e0cf3, + 0x3c3e8d0c, + 0x3c3f0d22, + 0x3c3f8d2f, + 0x3c400d42, + 0x3c408d53, + 0x3c410d64, + 0x3c418d7d, + 0x3c420d96, + 0x3c428dac, + 0x3c430dc9, + 0x3c438ddf, + 0x3c440e63, + 0x3c448e8a, + 0x3c450ea8, + 0x3c458ec2, + 0x3c460eda, + 0x3c468ef2, + 0x3c470f1d, + 0x3c478f48, + 0x3c480f69, + 0x3c488f92, + 0x3c490fad, + 0x3c498fd6, + 0x3c4a0fe3, + 0x3c4a8ffa, + 0x3c4b1011, + 0x3c4b903a, + 0x3c4c104a, + 0x3c4c9056, + 0x3c4d106e, + 0x3c4d9081, + 0x3c4e1092, + 0x3c4e90a3, + 0x3c4f10c9, 0x3c4f8ac0, - 0x3c500dcb, - 0x3c508deb, - 0x3c510e18, - 0x3c518f98, - 0x3c521083, - 0x40321b21, - 0x40329b3b, - 0x40331b63, - 0x40339b7b, - 0x40341b99, - 0x40349be0, - 0x40351bf7, - 0x40359c13, - 0x40361c2f, - 0x40369c49, - 0x40371c68, - 0x40379c87, - 0x40381c9f, - 0x40389cbc, - 0x40391cdf, - 0x40399cfc, - 0x403a1d1a, - 0x403a9d2a, - 0x403b1d3f, - 0x403b9d5b, - 0x403c1d75, - 0x403c9d80, - 0x403d1da3, - 0x403d9dc7, - 0x403e1ddd, - 0x403e9de7, - 0x403f1df3, - 0x403f9e04, - 0x40401e1c, - 0x40409e24, - 0x40411e2d, - 0x40419e36, - 0x40421e5e, - 0x40429e72, - 0x40431e7d, - 0x40439e89, - 0x40441edd, - 0x40449ee9, - 0x40451ef6, - 0x40459f09, - 0x40461f21, - 0x40469f39, - 0x40471f4f, - 0x40479f6a, - 0x40481f85, - 0x40489f99, - 0x40491fb2, - 0x40499fcb, - 0x404a1fe5, - 0x404a9fef, - 0x404b1fff, - 0x404ba020, - 0x404c203b, - 0x404ca049, - 0x404d2056, - 0x404da06a, - 0x404e2082, - 0x404ea090, - 0x404f20ba, - 0x404fa0d1, - 0x405020e3, - 0x4050a114, - 0x40512145, - 0x4051a15a, - 0x4052216b, - 0x4052a18b, - 0x405321a6, - 0x4053a1b6, - 0x4054a1c2, - 0x405521d8, - 0x4055a1f6, - 0x40562203, - 0x4056a20d, - 0x4057221b, - 0x4057a236, - 0x40582251, - 0x4058a270, - 0x40592285, - 0x4059a29a, - 0x405a22b7, - 0x405aa2cb, - 0x405b22e7, - 0x405ba2fd, - 0x405c231a, - 0x405ca32c, - 0x405d2343, - 0x405da354, - 0x405e2370, - 0x405ea384, - 0x405f2394, - 0x405fa3b0, - 0x406023c5, - 0x4060a3db, - 0x406123f8, - 0x4061a411, - 0x4062243b, - 0x4062a444, - 0x40632454, - 0x4063a48d, - 0x406424a3, - 0x4064a4c1, - 0x406524d6, - 0x4065a4f3, - 0x4066250a, - 0x4066a528, - 0x40672545, - 0x4067a55c, - 0x4068257a, - 0x4068a591, - 0x406925a9, - 0x4069a5ba, - 0x406a25cd, - 0x406aa5e0, - 0x406b25f4, - 0x406ba618, - 0x406c2633, - 0x406ca654, - 0x406d2678, - 0x406da693, - 0x406e26b4, - 0x406ea6c9, - 0x406f26e2, - 0x406fa6ef, - 0x407026fd, - 0x4070a70a, - 0x40712727, - 0x4071a747, - 0x40722762, - 0x4072a77b, - 0x40732792, - 0x4073a7ac, - 0x407427d0, - 0x4074a7e6, - 0x407527fa, - 0x4075a80f, - 0x40762829, - 0x4076a83b, - 0x40772850, - 0x4077a876, - 0x40782893, - 0x4078a8b6, - 0x407928dc, - 0x4079a8f9, - 0x407a291c, - 0x407aa938, - 0x407b2954, - 0x407ba966, - 0x407c2973, - 0x407e2980, - 0x407ea996, - 0x407f29ae, - 0x407fa9c1, - 0x408029d6, - 0x4080a9ef, - 0x40812a0d, - 0x4081aa2d, - 0x40822a36, - 0x4082aa52, - 0x40832a5b, - 0x4083a09f, - 0x4084212e, - 0x4084a0fe, - 0x4085247c, - 0x4085a460, - 0x40861bb8, - 0x40869bcb, - 0x40871ebd, - 0x40879ecc, - 0x40881b47, - 0x40889e46, - 0x40891ea4, - 0x4089a424, + 0x3c500dfb, + 0x3c508e1b, + 0x3c510e48, + 0x3c518fc8, + 0x3c5210b3, + 0x3c528b68, + 0x3c530b20, + 0x40321b51, + 0x40329b6b, + 0x40331b93, + 0x40339bab, + 0x40341bc9, + 0x40349c10, + 0x40351c27, + 0x40359c43, + 0x40361c5f, + 0x40369c79, + 0x40371c98, + 0x40379cb7, + 0x40381ccf, + 0x40389cec, + 0x40391d0f, + 0x40399d2c, + 0x403a1d4a, + 0x403a9d5a, + 0x403b1d6f, + 0x403b9d8b, + 0x403c1da5, + 0x403c9db0, + 0x403d1dd3, + 0x403d9df7, + 0x403e1e0d, + 0x403e9e17, + 0x403f1e23, + 0x403f9e34, + 0x40401e4c, + 0x40409e54, + 0x40411e5d, + 0x40419e66, + 0x40421e8e, + 0x40429ea2, + 0x40431ead, + 0x40439eb9, + 0x40441f0d, + 0x40449f19, + 0x40451f26, + 0x40459f39, + 0x40461f51, + 0x40469f69, + 0x40471f7f, + 0x40479f9a, + 0x40481fb5, + 0x40489fc9, + 0x40491fe2, + 0x40499ffb, + 0x404a2015, + 0x404aa01f, + 0x404b202f, + 0x404ba050, + 0x404c206b, + 0x404ca079, + 0x404d2086, + 0x404da09a, + 0x404e20b2, + 0x404ea0c0, + 0x404f20ea, + 0x404fa101, + 0x40502113, + 0x4050a144, + 0x40512175, + 0x4051a18a, + 0x4052219b, + 0x4052a1bb, + 0x405321d6, + 0x4053a1e6, + 0x4054a1f2, + 0x40552208, + 0x4055a226, + 0x40562233, + 0x4056a23d, + 0x4057224b, + 0x4057a266, + 0x40582281, + 0x4058a2a0, + 0x405922b5, + 0x4059a2ca, + 0x405a22e7, + 0x405aa2fb, + 0x405b2317, + 0x405ba32d, + 0x405c234a, + 0x405ca35c, + 0x405d2373, + 0x405da384, + 0x405e23a0, + 0x405ea3b4, + 0x405f23c4, + 0x405fa3e0, + 0x406023f5, + 0x4060a40b, + 0x40612428, + 0x4061a441, + 0x4062246b, + 0x4062a474, + 0x40632484, + 0x4063a4bd, + 0x406424d3, + 0x4064a4f1, + 0x40652506, + 0x4065a523, + 0x4066253a, + 0x4066a558, + 0x40672575, + 0x4067a58c, + 0x406825aa, + 0x4068a5c1, + 0x406925d9, + 0x4069a5ea, + 0x406a25fd, + 0x406aa610, + 0x406b2624, + 0x406ba648, + 0x406c2663, + 0x406ca684, + 0x406d26a8, + 0x406da6c3, + 0x406e26e4, + 0x406ea6f9, + 0x406f2712, + 0x406fa71f, + 0x4070272d, + 0x4070a73a, + 0x40712757, + 0x4071a777, + 0x40722792, + 0x4072a7ab, + 0x407327c2, + 0x4073a7dc, + 0x40742800, + 0x4074a816, + 0x4075282a, + 0x4075a83f, + 0x40762859, + 0x4076a86b, + 0x40772880, + 0x4077a8a6, + 0x407828c3, + 0x4078a8e6, + 0x4079290c, + 0x4079a929, + 0x407a294c, + 0x407aa968, + 0x407b2984, + 0x407ba996, + 0x407c29a3, + 0x407e29b0, + 0x407ea9c6, + 0x407f29de, + 0x407fa9f1, + 0x40802a06, + 0x4080aa1f, + 0x40812a3d, + 0x4081aa5d, + 0x40822a66, + 0x4082aa82, + 0x40832a8b, + 0x4083a0cf, + 0x4084215e, + 0x4084a12e, + 0x408524ac, + 0x4085a490, + 0x40861be8, + 0x40869bfb, + 0x40871eed, + 0x40879efc, + 0x40881b77, + 0x40889e76, + 0x40891ed4, + 0x4089a454, 0x4432042a, 0x4432843c, 0x44330445, @@ -602,87 +604,87 @@ 0x44398522, 0x443a052c, 0x443a8536, - 0x4c32179b, - 0x4c3297aa, - 0x4c3317b9, - 0x4c3397d2, - 0x4c3417ed, - 0x4c349809, - 0x4c35181b, - 0x4c359829, - 0x4c36183e, - 0x4c36984f, - 0x4c37185d, - 0x4c37986b, - 0x4c38187d, - 0x4c38988d, - 0x4c391897, - 0x4c3998af, - 0x4c3a18c7, - 0x4c3a98da, - 0x50322f06, - 0x5032af1b, - 0x50332f2c, - 0x5033af3f, - 0x50342f50, - 0x5034af63, - 0x50352f72, - 0x5035af87, - 0x50362f97, - 0x5036afa6, - 0x50372fb7, - 0x5037afc7, - 0x50382fd8, - 0x5038afeb, - 0x50392ffd, - 0x5039b013, - 0x503a3025, - 0x503ab036, - 0x503b3047, - 0x503bb058, - 0x503c3063, - 0x503cb06f, - 0x503d307a, - 0x503db085, - 0x503e3092, - 0x503eb0a7, - 0x503f30b5, - 0x503fb0c9, - 0x504030dc, - 0x5040b0ed, - 0x50413107, - 0x5041b116, - 0x5042311f, - 0x5042b12e, - 0x50433140, - 0x5043b14c, - 0x50443154, - 0x5044b167, - 0x50453178, - 0x5045b18e, - 0x5046319a, - 0x5046b1ae, - 0x504731bc, - 0x5047b1d0, - 0x504831ea, - 0x5048b1fe, - 0x50493214, - 0x5049b22b, - 0x504a323d, - 0x504ab251, - 0x504b3266, - 0x504bb27d, - 0x504c3291, - 0x504cb29a, - 0x504d32a2, - 0x504db2b1, - 0x504e32c1, - 0x683210ba, - 0x683290cb, - 0x683310db, - 0x683390e9, - 0x683410f6, - 0x6c3210a9, + 0x4c3217cb, + 0x4c3297da, + 0x4c3317e9, + 0x4c339802, + 0x4c34181d, + 0x4c349839, + 0x4c35184b, + 0x4c359859, + 0x4c36186e, + 0x4c36987f, + 0x4c37188d, + 0x4c37989b, + 0x4c3818ad, + 0x4c3898bd, + 0x4c3918c7, + 0x4c3998df, + 0x4c3a18f7, + 0x4c3a990a, + 0x50322f36, + 0x5032af4b, + 0x50332f5c, + 0x5033af6f, + 0x50342f80, + 0x5034af93, + 0x50352fa2, + 0x5035afb7, + 0x50362fc7, + 0x5036afd6, + 0x50372fe7, + 0x5037aff7, + 0x50383008, + 0x5038b01b, + 0x5039302d, + 0x5039b043, + 0x503a3055, + 0x503ab066, + 0x503b3077, + 0x503bb088, + 0x503c3093, + 0x503cb09f, + 0x503d30aa, + 0x503db0b5, + 0x503e30c2, + 0x503eb0d7, + 0x503f30e5, + 0x503fb0f9, + 0x5040310c, + 0x5040b11d, + 0x50413137, + 0x5041b146, + 0x5042314f, + 0x5042b15e, + 0x50433170, + 0x5043b17c, + 0x50443184, + 0x5044b197, + 0x504531a8, + 0x5045b1be, + 0x504631ca, + 0x5046b1de, + 0x504731ec, + 0x5047b200, + 0x5048321a, + 0x5048b22e, + 0x50493244, + 0x5049b25b, + 0x504a326d, + 0x504ab281, + 0x504b3296, + 0x504bb2ad, + 0x504c32c1, + 0x504cb2ca, + 0x504d32d2, + 0x504db2e1, + 0x504e32f1, + 0x683210ea, + 0x683290fb, + 0x6833110b, + 0x68339119, + 0x68341126, + 0x6c3210d9, 0x74320a6a, 0x74328a7c, 0x783206c9, @@ -720,7 +722,7 @@ 0x784207a0, 0x784287be, 0x784307dc, - 0x803215c2, + 0x803215f2, }; const size_t kOpenSSLFunctionValuesLen = sizeof(kOpenSSLFunctionValues) / sizeof(kOpenSSLFunctionValues[0]); @@ -896,9 +898,11 @@ "EC_GROUP_get_curve_GFp\0" "EC_GROUP_get_degree\0" "EC_GROUP_new_by_curve_name\0" + "EC_GROUP_new_curve_GFp\0" "EC_KEY_check_key\0" "EC_KEY_copy\0" "EC_KEY_generate_key\0" + "EC_KEY_new_by_curve_name\0" "EC_KEY_new_method\0" "EC_KEY_set_public_key_affine_coordinates\0" "EC_POINT_add\0"
diff --git a/third_party/closure_compiler/externs/file_manager_private.js b/third_party/closure_compiler/externs/file_manager_private.js index 49d892d1..09affc9 100644 --- a/third_party/closure_compiler/externs/file_manager_private.js +++ b/third_party/closure_compiler/externs/file_manager_private.js
@@ -60,6 +60,7 @@ * volumeId: string, * fileSystemId: (string|undefined), * extensionId: (string|undefined), + * source: string, * volumeLabel: (string|undefined), * profile: ProfileInfo, * sourcePath: (string|undefined), @@ -69,6 +70,7 @@ * isParentDevice: (boolean|undefined), * isReadOnly: boolean, * hasMedia: boolean, + * configurable: boolean, * mountCondition: (string|undefined), * mountContext: (string|undefined) * }} @@ -613,8 +615,7 @@ * @param {string} volumeId * @param {function()} callback */ -chrome.fileManagerPrivate.configureProvidedFileSystem = - function(volumeId, callback) {}; +chrome.fileManagerPrivate.configureVolume = function(volumeId, callback) {}; /** @type {!ChromeEvent} */ chrome.fileManagerPrivate.onMountCompleted;
diff --git a/tools/clang/blink_gc_plugin/BlinkGCPlugin.cpp b/tools/clang/blink_gc_plugin/BlinkGCPlugin.cpp index 2d221d7..2d6eff256 100644 --- a/tools/clang/blink_gc_plugin/BlinkGCPlugin.cpp +++ b/tools/clang/blink_gc_plugin/BlinkGCPlugin.cpp
@@ -17,6 +17,7 @@ #include "clang/AST/RecursiveASTVisitor.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendPluginRegistry.h" +#include "clang/Sema/Sema.h" using namespace clang; using std::string; @@ -144,6 +145,23 @@ "[blink-gc] Class %0 which inherits from GarbageCollectedMixin must" " locally declare and override trace(Visitor*)"; +// Use a local RAV implementation to simply collect all FunctionDecls marked for +// late template parsing. This happens with the flag -fdelayed-template-parsing, +// which is on by default in MSVC-compatible mode. +std::set<FunctionDecl*> GetLateParsedFunctionDecls(TranslationUnitDecl* decl) { + struct Visitor : public RecursiveASTVisitor<Visitor> { + bool VisitFunctionDecl(FunctionDecl* function_decl) { + if (function_decl->isLateTemplateParsed()) + late_parsed_decls.insert(function_decl); + return true; + } + + std::set<FunctionDecl*> late_parsed_decls; + } v; + v.TraverseDecl(decl); + return v.late_parsed_decls; +} + struct BlinkGCPluginOptions { BlinkGCPluginOptions() : enable_oilpan(false) @@ -1017,6 +1035,8 @@ if (diagnostic_.hasErrorOccurred()) return; + ParseFunctionTemplates(context.getTranslationUnitDecl()); + CollectVisitor visitor; visitor.TraverseDecl(context.getTranslationUnitDecl()); @@ -1063,6 +1083,31 @@ } } + void ParseFunctionTemplates(TranslationUnitDecl* decl) { + if (!instance_.getLangOpts().DelayedTemplateParsing) + return; // Nothing to do. + + std::set<FunctionDecl*> late_parsed_decls = + GetLateParsedFunctionDecls(decl); + clang::Sema& sema = instance_.getSema(); + + for (const FunctionDecl* fd : late_parsed_decls) { + assert(fd->isLateTemplateParsed()); + + if (!Config::IsTraceMethod(fd)) + continue; + + if (instance_.getSourceManager().isInSystemHeader( + instance_.getSourceManager().getSpellingLoc(fd->getLocation()))) + continue; + + // Force parsing and AST building of the yet-uninstantiated function + // template trace method bodies. + clang::LateParsedTemplate* lpt = sema.LateParsedTemplateMap[fd]; + sema.LateTemplateParser(sema.OpaqueParser, *lpt); + } + } + // Main entry for checking a record declaration. void CheckRecord(RecordInfo* info) { if (IsIgnored(info))
diff --git a/tools/clang/blink_gc_plugin/Config.h b/tools/clang/blink_gc_plugin/Config.h index 02cbee9a..445952a 100644 --- a/tools/clang/blink_gc_plugin/Config.h +++ b/tools/clang/blink_gc_plugin/Config.h
@@ -214,7 +214,7 @@ TRACE_AFTER_DISPATCH_IMPL_METHOD }; - static TraceMethodType GetTraceMethodType(clang::FunctionDecl* method) { + static TraceMethodType GetTraceMethodType(const clang::FunctionDecl* method) { if (method->getNumParams() != 1) return NOT_TRACE_METHOD; @@ -244,7 +244,7 @@ return NOT_TRACE_METHOD; } - static bool IsTraceMethod(clang::FunctionDecl* method) { + static bool IsTraceMethod(const clang::FunctionDecl* method) { return GetTraceMethodType(method) != NOT_TRACE_METHOD; }
diff --git a/tools/clang/blink_gc_plugin/tests/cycle_ptrs.txt b/tools/clang/blink_gc_plugin/tests/cycle_ptrs.txt index 4d242a6..7ad6c48c 100644 --- a/tools/clang/blink_gc_plugin/tests/cycle_ptrs.txt +++ b/tools/clang/blink_gc_plugin/tests/cycle_ptrs.txt
@@ -5,4 +5,3 @@ ./cycle_ptrs.h:34:5: blink::B (m_c) => blink::C ./cycle_ptrs.h:39:5: blink::C (m_d) => blink::D ./cycle_ptrs.h:44:5: blink::D (m_es) => blink::E -
diff --git a/tools/clang/blink_gc_plugin/tests/cycle_sub.txt b/tools/clang/blink_gc_plugin/tests/cycle_sub.txt index b37907d..9c015c8 100644 --- a/tools/clang/blink_gc_plugin/tests/cycle_sub.txt +++ b/tools/clang/blink_gc_plugin/tests/cycle_sub.txt
@@ -3,4 +3,3 @@ ./cycle_sub.h:31:5: blink::C (m_a) => blink::A ./cycle_sub.h:22:11: blink::A (<subclass>) => blink::B ./cycle_sub.h:26:5: blink::B (m_c) => blink::C -
diff --git a/tools/clang/blink_gc_plugin/tests/cycle_super.txt b/tools/clang/blink_gc_plugin/tests/cycle_super.txt index 89b3675..374074b 100644 --- a/tools/clang/blink_gc_plugin/tests/cycle_super.txt +++ b/tools/clang/blink_gc_plugin/tests/cycle_super.txt
@@ -2,4 +2,3 @@ Found a potentially leaking cycle starting from a GC root: ./cycle_super.h:36:5: blink::D (m_c) => blink::C ./cycle_super.h:21:5: blink::C (blink::B <: blink::A <: m_d) => blink::D -
diff --git a/tools/clang/blink_gc_plugin/tests/cycle_super_neg.txt b/tools/clang/blink_gc_plugin/tests/cycle_super_neg.txt new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/tools/clang/blink_gc_plugin/tests/cycle_super_neg.txt
@@ -0,0 +1 @@ +
diff --git a/tools/clang/blink_gc_plugin/tests/delayed_parsing.cpp b/tools/clang/blink_gc_plugin/tests/delayed_parsing.cpp new file mode 100644 index 0000000..149d95e --- /dev/null +++ b/tools/clang/blink_gc_plugin/tests/delayed_parsing.cpp
@@ -0,0 +1,25 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "heap/stubs.h" + +namespace blink { + +struct HeapObject : public GarbageCollected<HeapObject> { + void trace(Visitor*) { } +}; + +template<typename T> +class TemplateBase + : public GarbageCollected<TemplateBase<T> > { +public: + void trace(Visitor* visitor) { visitor->trace(m_obj); } +private: + Member<HeapObject> m_obj; +}; + +class Subclass : public TemplateBase<Subclass> { +}; + +}
diff --git a/tools/clang/blink_gc_plugin/tests/delayed_parsing.flags b/tools/clang/blink_gc_plugin/tests/delayed_parsing.flags new file mode 100644 index 0000000..94af50f --- /dev/null +++ b/tools/clang/blink_gc_plugin/tests/delayed_parsing.flags
@@ -0,0 +1 @@ +-fdelayed-template-parsing
diff --git a/tools/clang/blink_gc_plugin/tests/delayed_parsing.txt b/tools/clang/blink_gc_plugin/tests/delayed_parsing.txt new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tools/clang/blink_gc_plugin/tests/delayed_parsing.txt
diff --git a/tools/clang/blink_gc_plugin/tests/register_weak_members_template.txt b/tools/clang/blink_gc_plugin/tests/register_weak_members_template.txt new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/tools/clang/blink_gc_plugin/tests/register_weak_members_template.txt
@@ -0,0 +1 @@ +
diff --git a/tools/clang/blink_gc_plugin/tests/test.py b/tools/clang/blink_gc_plugin/tests/test.py index 5ade0323..acb7e74 100755 --- a/tools/clang/blink_gc_plugin/tests/test.py +++ b/tools/clang/blink_gc_plugin/tests/test.py
@@ -4,20 +4,18 @@ # found in the LICENSE file. -import argparse import glob import os import subprocess import sys -def run_test(test_base_name, cmd, reset_results): +def run_test(test_base_name, cmd): """Run a test case. Args: test_base_name: The name for the test C++ source file without the extension. cmd: The actual command to run for the test. - reset_results: True if the results should be overwritten in place. Returns: None on pass, or a str with the description of the failure. @@ -49,31 +47,31 @@ # from a previous run. os.remove('%s.graph.json' % test_base_name) + # TODO(dcheng): Remove the rstrip() and just rebaseline the tests to match. + actual = actual.rstrip() + # On Windows, clang emits CRLF as the end of line marker. Normalize it to LF # to match posix systems. actual = actual.replace('\r\n', '\n') - result_file = '%s.txt%s' % ( - test_base_name, '' if reset_results else '.actual') try: - expected = open('%s.txt' % test_base_name).read() + expected = open('%s.txt' % test_base_name).read().rstrip() except IOError: - open(result_file, 'w').write(actual) + open('%s.txt.actual' % test_base_name, 'w').write(actual) return 'no expected file found' if expected != actual: - open(result_file, 'w').write(actual) + open('%s.txt.actual' % test_base_name, 'w').write(actual) return 'expected and actual differed' -def run_tests(clang_path, plugin_path, reset_results): +def run_tests(clang_path, plugin_path): """Runs the tests. Args: clang_path: The path to the clang binary to be tested. plugin_path: An optional path to the plugin to test. This may be None, if plugin is built directly into clang, like on Windows. - reset_results: True if the results should be overwritten in place. Returns: (passing, failing): Two lists containing the base names of the passing and @@ -103,7 +101,7 @@ pass cmd.append(test) - failure_message = run_test(test_base_name, cmd, reset_results) + failure_message = run_test(test_base_name, cmd) if failure_message: print 'failed: %s' % failure_message failing.append(test_base_name) @@ -115,23 +113,18 @@ def main(): - parser = argparse.ArgumentParser() - parser.add_argument( - '--reset-results', action='store_true', - help='If specified, overwrites the expected results in place.') - parser.add_argument('clang_path', help='The path to the clang binary.') - parser.add_argument('plugin_path', nargs='?', - help='The path to the plugin library, if any.') - args = parser.parse_args() + if len(sys.argv) < 2: + print 'Usage: <path to clang>[ <path to plugin>]' + return -1 os.chdir(os.path.dirname(os.path.realpath(__file__))) - print 'Using clang %s...' % args.clang_path - print 'Using plugin %s...' % args.plugin_path + clang_path = sys.argv[1] + plugin_path = sys.argv[2] if len(sys.argv) > 2 else None + print 'Using clang %s...' % clang_path + print 'Using plugin %s...' % plugin_path - passing, failing = run_tests(args.clang_path, - args.plugin_path, - args.reset_results) + passing, failing = run_tests(clang_path, plugin_path) print 'Ran %d tests: %d succeeded, %d failed' % ( len(passing) + len(failing), len(passing), len(failing)) for test in failing:
diff --git a/tools/clang/blink_gc_plugin/tests/trace_after_dispatch_impl.txt b/tools/clang/blink_gc_plugin/tests/trace_after_dispatch_impl.txt new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/tools/clang/blink_gc_plugin/tests/trace_after_dispatch_impl.txt
@@ -0,0 +1 @@ +
diff --git a/tools/clang/blink_gc_plugin/tests/traceimpl.txt b/tools/clang/blink_gc_plugin/tests/traceimpl.txt new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/tools/clang/blink_gc_plugin/tests/traceimpl.txt
@@ -0,0 +1 @@ +
diff --git a/tools/clang/blink_gc_plugin/tests/traceimpl_derived_from_templated_base.txt b/tools/clang/blink_gc_plugin/tests/traceimpl_derived_from_templated_base.txt new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/tools/clang/blink_gc_plugin/tests/traceimpl_derived_from_templated_base.txt
@@ -0,0 +1 @@ +
diff --git a/tools/clang/blink_gc_plugin/tests/traceimpl_omitted_trace.txt b/tools/clang/blink_gc_plugin/tests/traceimpl_omitted_trace.txt new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/tools/clang/blink_gc_plugin/tests/traceimpl_omitted_trace.txt
@@ -0,0 +1 @@ +
diff --git a/tools/clang/blink_gc_plugin/tests/traceimpl_overloaded.txt b/tools/clang/blink_gc_plugin/tests/traceimpl_overloaded.txt new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/tools/clang/blink_gc_plugin/tests/traceimpl_overloaded.txt
@@ -0,0 +1 @@ +
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index edb97af..27b3b10 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -605,6 +605,16 @@ </summary> </histogram> +<histogram name="Ash.AppList.TimeBetweenTaskSwitches" units="seconds"> + <owner>bruthig@chromium.org</owner> + <owner>tdanderson@chromium.org</owner> + <summary> + The amount of time between selecting an item from the Ash app list. Not + recorded on the first time an item is selected from the app list after + startup. + </summary> +</histogram> + <histogram name="Ash.Dock.Action" enum="DockedAction"> <owner>kuscher@google.com</owner> <owner>varkha@chromium.org</owner> @@ -785,6 +795,16 @@ <summary>The duration of mostly stationary long-duration touches.</summary> </histogram> +<histogram name="Ash.Tab.TimeBetweenSwitchToExistingTabUserActions" + units="seconds"> + <owner>bruthig@chromium.org</owner> + <owner>tdanderson@chromium.org</owner> + <summary> + The number of seconds between tab switches triggered by a user gesture (e.g. + Ctrl+T, Ctrl+1, tapping or clicking the tab strip, etc). + </summary> +</histogram> + <histogram name="Ash.TouchDuration" units="milliseconds"> <obsolete> Deprecated 12/2013 in r239809, and replaced by Ash.TouchDuration2. @@ -916,6 +936,16 @@ </summary> </histogram> +<histogram name="Ash.WindowCycleController.TimeBetweenTaskSwitches" + units="seconds"> + <owner>tdanderson@google.com</owner> + <owner>bruthig@google.com</owner> + <summary> + The number of seconds between task switches triggered by the next window and + previous window accelerator keys (ie Alt+Tab, Alt+Shift+Tab). + </summary> +</histogram> + <histogram name="Ash.WindowSelector.ArrowKeyPresses"> <owner>flackr@chromium.org</owner> <owner>tdanderson@chromium.org</owner> @@ -996,11 +1026,25 @@ </summary> </histogram> +<histogram name="Ash.WindowSelector.TimeBetweenActiveWindowChanges" + units="seconds"> + <owner>bruthig@chromium.org</owner> + <owner>tdanderson@chromium.org</owner> + <summary> + The amount of time between endings of overview mode sessions which were + caused by the user selecting a window which was not previously active. Only + recorded on the second and later times after startup that the user selected + a window which was not previously active. + </summary> +</histogram> + <histogram name="Ash.WindowSelector.TimeBetweenUse" units="milliseconds"> <owner>flackr@chromium.org</owner> <owner>kuscher@google.com</owner> <summary> - The amount of time between uses of overview mode to switch between windows. + The amount of time between uses of overview mode, recorded when overview + mode is entered. Only recorded on the second and later times after startup + that the user entered overview mode. </summary> </histogram> @@ -4098,14 +4142,14 @@ </histogram> <histogram name="CrosFirstRun.DialogShown"> - <owner>Please list the metric's owners. Add more owner tags as needed.</owner> + <owner>dzhioev@chromium.org</owner> <summary> Records the number of times when first-run dialog was shown. </summary> </histogram> <histogram name="CrosFirstRun.FurthestStep"> - <owner>Please list the metric's owners. Add more owner tags as needed.</owner> + <owner>dzhioev@chromium.org</owner> <summary> Index of furthest step that was reached during tutorial. Since order of steps could change eventially and new steps could apear we use index here @@ -4114,23 +4158,23 @@ </histogram> <histogram name="CrosFirstRun.TimeSpent" units="ms"> - <owner>Please list the metric's owners. Add more owner tags as needed.</owner> + <owner>dzhioev@chromium.org</owner> <summary>The total time that user spent on first-run tutorial.</summary> </histogram> <histogram name="CrosFirstRun.TimeSpentOnStep" units="ms"> - <owner>Please list the metric's owners. Add more owner tags as needed.</owner> + <owner>dzhioev@chromium.org</owner> <summary>The time that user spent on some step of tutorial.</summary> </histogram> <histogram name="CrosFirstRun.TutorialCompletion" enum="CrosFirstRunTutorialCompletionType"> - <owner>Please list the metric's owners. Add more owner tags as needed.</owner> + <owner>dzhioev@chromium.org</owner> <summary>Tracks the way how user left tutorial.</summary> </histogram> <histogram name="CrosFirstRun.TutorialLaunched"> - <owner>Please list the metric's owners. Add more owner tags as needed.</owner> + <owner>dzhioev@chromium.org</owner> <summary> Records the number of times when first-run tutorial has been launched. </summary> @@ -4298,6 +4342,41 @@ </summary> </histogram> +<histogram name="DataReductionProxy.ConfigFetchLostBytesCL"> + <owner>jeremyim@chromium.org</owner> + <owner>bengr@chromium.org</owner> + <summary> + Size of the response body. This is the actual number of bytes received, + which usually agrees with but is not necessarily the same as the size + specified by the Content-Length header. Only recorded if the request is sent + while a simulated Data Reduction Proxy configuration fetch is taking place. + </summary> +</histogram> + +<histogram name="DataReductionProxy.ConfigFetchLostBytesDiff"> + <owner>jeremyim@chromium.org</owner> + <owner>bengr@chromium.org</owner> + <summary> + The difference between the size specified in the X-Original-Content-Length + header and the size of the response body. Only recorded if the request is + sent while a simulated Data Reduction Proxy configuration fetch is taking + place. Only positive values are logged, so if X-Original-Content-Length is + not specified or if it equals or exceeds the content length, it is not + logged. + </summary> +</histogram> + +<histogram name="DataReductionProxy.ConfigFetchLostBytesOCL"> + <owner>jeremyim@chromium.org</owner> + <owner>bengr@chromium.org</owner> + <summary> + Size specified in the X-Original-Content-Length header. If this header is + not present in the response, the size of the response body is used. Only + recorded if the request is sent while a simulated Data Reduction Proxy + configuration fetch is taking place. + </summary> +</histogram> + <histogram name="DataReductionProxy.ConfigService.FetchFailedAttemptsBeforeSuccess"> <owner>jeremyim@chromium.org</owner> @@ -13638,7 +13717,10 @@ <histogram name="interstitial.decision" enum="SecurityInterstitialDecision"> <owner>felt@chromium.org</owner> - <summary>User decision when presented with a security interstitial.</summary> + <summary> + User decision when presented with a security interstitial. As of M44, + subresource interstitials were split into their own entries. + </summary> </histogram> <histogram name="interstitial.decision.repeat_visit" @@ -13646,14 +13728,18 @@ <owner>felt@chromium.org</owner> <summary> User decision when presented with a security interstitial, on a site that - the user had previously visited. + the user had previously visited. As of M44, subresource interstitials were + split into their own entries. </summary> </histogram> <histogram name="interstitial.interaction" enum="SecurityInterstitialInteraction"> <owner>felt@chromium.org</owner> - <summary>User interactions with a security interstitial.</summary> + <summary> + User interactions with a security interstitial. As of M44, subresource + interstitials were split into their own entries. + </summary> </histogram> <histogram name="interstitial.ssl" enum="SSLResponseTypesV2"> @@ -14362,6 +14448,20 @@ </summary> </histogram> +<histogram name="Login.NewUserPriorityPrefsSyncResult" + enum="NewUserPriorityPrefsSyncResult"> + <owner>dzhioev@chromeos.org</owner> + <summary>Records whether a new user's priority prefs sync timed out.</summary> +</histogram> + +<histogram name="Login.NewUserPriorityPrefsSyncTime" units="milliseconds"> + <owner>dzhioev@chromeos.org</owner> + <summary> + Time spent waiting for priority preferences to sync after new user sign in. + The operation will time out after 10s. + </summary> +</histogram> + <histogram name="Login.PolicyFilesStatePerBoot" enum="LoginPolicyFilesState"> <owner>cmasone@chromium.org</owner> <summary>The state of Chrome OS owner key and device policy files.</summary> @@ -20206,6 +20306,14 @@ </summary> </histogram> +<histogram name="Net.PrefProxyConfig.GooglezipProxyRemovalCount"> + <owner>sclittle@chromium.org</owner> + <summary> + Records how many *.googlezip.net Data Reduction Proxies were removed from + the effective proxy configuration when a proxy reconfiguration occurs. + </summary> +</histogram> + <histogram name="Net.Priority_High_Latency" units="milliseconds"> <obsolete> Replaced by Net.Priority_High_Latency_b. @@ -22120,6 +22228,22 @@ <summary>Time to complete a certificate verification (error case).</summary> </histogram> +<histogram name="Net.SSLFallbackErrorCode" enum="NetErrorCodes"> + <owner>davidben@chromium.org</owner> + <summary> + For each successful HTTPS request which used the TLS version fallback, the + error code of the last failed attempt. + </summary> +</histogram> + +<histogram name="Net.SSLFallbackFailureState" enum="SSLFailureState"> + <owner>davidben@chromium.org</owner> + <summary> + For each successful HTTPS request which used the TLS version fallback, the + type of handshake failure of the last failed attempt. + </summary> +</histogram> + <histogram name="Net.SSLHostInfoDNSLookup" units="milliseconds"> <owner>Please list the metric's owners. Add more owner tags as needed.</owner> <summary>Time to complete a DNS lookup for a DNS CAA record.</summary> @@ -26417,6 +26541,17 @@ </summary> </histogram> +<histogram name="PasswordManager.EmptyUsernames.TextAndPasswordFieldCount"> + <owner>msramek@chromium.org</owner> + <owner>vasilii@chromium.org</owner> + <summary> + The total number of text and password fields for password forms that do not + have a username field. This is recorded every time such a password form is + successfully parsed. Note that the parsing is attempted when the form is + encountered (i.e when the document is loaded) and also when it is submitted. + </summary> +</histogram> + <histogram name="PasswordManager.EmptyUsernames.WithoutCorrespondingNonempty"> <owner>msramek@chromium.org</owner> <owner>vasilii@chromium.org</owner> @@ -36107,6 +36242,14 @@ </summary> </histogram> +<histogram name="ServiceWorker.UnhandledEventRatio" units="percent"> + <owner>kinuko@chromium.org</owner> + <summary> + Records the ratio of unhandled events to all events that are dispatched to + each ServiceWorker. Recorded when each ServiceWorkerVersion is destructed. + </summary> +</histogram> + <histogram name="ServiceWorkerCache.Cache" units="milliseconds"> <owner>dmurph@chromium.org</owner> <summary> @@ -41677,6 +41820,36 @@ </summary> </histogram> +<histogram name="Sync.MemoryPressureWarningBeforeCleanShutdown" units="count"> + <owner>gangwu@chromium.org</owner> + <summary> + Counts the number of times a user's sync service received a + MEMORY_PRESSURE_LEVEL_CRITICAL warning before the sync service shut down + cleanly. The sync service emits this number the next time the user's sync + service is started, which will likely happen the next time the user's + profile is opened after a Chrome restart. This count is emitted once per + user/profile. Things like browser crashes that implicitly bring down all + users' sync services will cause unclean shutdown tags to appear on all open + profiles, meaning that there will be multiple emissions to this histogram as + those profiles are re-opened. + </summary> +</histogram> + +<histogram name="Sync.MemoryPressureWarningBeforeUncleanShutdown" units="count"> + <owner>gangwu@chromium.org</owner> + <summary> + Counts the number of times a user's sync service received a + MEMORY_PRESSURE_LEVEL_CRITICAL warning before the sync service shut down + uncleanly. The sync service emits this number the next time the user's sync + service is started, which will likely happen the next time the user's + profile is opened after a Chrome restart. This count is emitted once per + user/profile. Things like browser crashes that implicitly bring down all + users' sync services will cause unclean shutdown tags to appear on all open + profiles, meaning that there will be multiple emissions to this histogram as + those profiles are re-opened. + </summary> +</histogram> + <histogram name="Sync.NigoriMigrationState" enum="SyncNigoriMigrationState"> <owner>zea@chromium.org</owner> <summary>Breakdown of sync's nigori node keystore migration state.</summary> @@ -52314,7 +52487,7 @@ <int value="1007" label="DEVELOPERPRIVATE_SHOWOPTIONS"/> <int value="1008" label="DEVELOPERPRIVATE_SHOWPATH"/> <int value="1009" label="FILEMANAGERPRIVATE_ADDPROVIDEDFILESYSTEM"/> - <int value="1010" label="FILEMANAGERPRIVATE_CONFIGUREPROVIDEDFILESYSTEM"/> + <int value="1010" label="FILEMANAGERPRIVATE_CONFIGUREVOLUME"/> <int value="1011" label="SEARCHENGINESPRIVATE_GETSEARCHENGINES"/> <int value="1012" label="SEARCHENGINESPRIVATE_SETSELECTEDSEARCHENGINE"/> <int value="1013" label="AUTOFILLPRIVATE_SAVEADDRESS"/> @@ -52345,6 +52518,7 @@ <int value="1037" label="PASSWORDSPRIVATE_REMOVESAVEDPASSWORD"/> <int value="1038" label="PASSWORDSPRIVATE_REMOVEPASSWORDEXCEPTION"/> <int value="1039" label="PASSWORDSPRIVATE_GETPLAINTEXTPASSWORD"/> + <int value="1040" label="LAUNCHERPAGE_HIDE"/> </enum> <enum name="ExtensionInstallCause" type="int"> @@ -56484,6 +56658,7 @@ <int value="-1835975804" label="disable-offline-auto-reload"/> <int value="-1833149810" label="enable-accessibility-tab-switcher"/> <int value="-1832575380" label="show-saved-copy"/> + <int value="-1832221649" label="disable-out-of-process-pac"/> <int value="-1821058653" label="enable-delay-agnostic-aec"/> <int value="-1767470652" label="out-of-process-pdf"/> <int value="-1751928267" label="disable-icon-ntp"/> @@ -56600,6 +56775,7 @@ <int value="-649956990" label="enable-harfbuzz-rendertext"/> <int value="-641719457" label="disable-compositor-touch-hit-testing"/> <int value="-622685174" label="enable-pdf-material-ui"/> + <int value="-610411643" label="enable-printer-app-search"/> <int value="-604814313" label="enable-pinch"/> <int value="-601384286" label="disable-contextual-search"/> <int value="-579192400" label="disable-input-view"/> @@ -58826,6 +59002,11 @@ <int value="6" label="URL blocked for supervised user"/> </enum> +<enum name="NewUserPriorityPrefsSyncResult" type="int"> + <int value="0" label="Succeeded"/> + <int value="1" label="Timed out"/> +</enum> + <enum name="NotificationActionType" type="int"> <int value="0" label="Unknown"/> <int value="1" label="Notification added"/> @@ -62034,6 +62215,7 @@ <int value="63" label="IDC_WRITING_DIRECTION_DEFAULT"/> <int value="64" label="IDC_WRITING_DIRECTION_LTR"/> <int value="65" label="IDC_WRITING_DIRECTION_RTL"/> + <int value="66" label="IDC_CONTENT_CONTEXT_SHOW_ORIGINAL_IMAGE"/> </enum> <enum name="ReportProcessingResult" type="int"> @@ -64084,6 +64266,16 @@ <int value="9" label="UNKNOWN"/> </enum> +<enum name="SSLFailureState" type="int"> + <int value="0" label="No failure"/> + <int value="1" label="Unknown failure"/> + <int value="2" label="Failed to process ClientHello"/> + <int value="3" label="Buggy AES-GCM"/> + <int value="4" label="Failed with client authentication"/> + <int value="5" label="Session version mismatch"/> + <int value="6" label="Failed with Next Proto Negotiation"/> +</enum> + <enum name="SSLGoodCertSeenEvent" type="int"> <int value="0" label="NO_PREVIOUS_EXCEPTION"/> <int value="1" label="HAD_PREVIOUS_EXCEPTION"/> @@ -66644,6 +66836,22 @@ <affected-histogram name="DataReductionProxy.BypassedBytes"/> </histogram_suffixes> +<histogram_suffixes name="DataReductionProxyConfigFetchLostBytes" separator="_"> + <suffix name="0" label="Bucket 0 for gathering multiple data points."/> + <suffix name="1" label="Bucket 1 for gathering multiple data points."/> + <suffix name="2" label="Bucket 2 for gathering multiple data points."/> + <suffix name="3" label="Bucket 3 for gathering multiple data points."/> + <suffix name="4" label="Bucket 4 for gathering multiple data points."/> + <suffix name="5" label="Bucket 5 for gathering multiple data points."/> + <suffix name="6" label="Bucket 6 for gathering multiple data points."/> + <suffix name="7" label="Bucket 7 for gathering multiple data points."/> + <suffix name="8" label="Bucket 8 for gathering multiple data points."/> + <suffix name="9" label="Bucket 9 for gathering multiple data points."/> + <affected-histogram name="DataReductionProxy.ConfigFetchLostBytesCL"/> + <affected-histogram name="DataReductionProxy.ConfigFetchLostBytesDiff"/> + <affected-histogram name="DataReductionProxy.ConfigFetchLostBytesOCL"/> +</histogram_suffixes> + <histogram_suffixes name="DataReductionProxyMissingViaHeaderBytes" separator="."> <suffix name="4xx" label="Response with 4xx response code"/> @@ -69945,8 +70153,11 @@ ordering="prefix"> <suffix name="bad_clock"/> <suffix name="harmful"/> + <suffix name="harmful_subresource"/> <suffix name="malware"/> + <suffix name="malware_subresource"/> <suffix name="phishing"/> + <suffix name="phishing_subresource"/> <suffix name="ssl_nonoverridable"/> <suffix name="ssl_overridable"/> <affected-histogram name="interstitial.decision"/>
diff --git a/tools/perf/benchmarks/blink_perf.py b/tools/perf/benchmarks/blink_perf.py index 8720aa7..3c31e9b 100644 --- a/tools/perf/benchmarks/blink_perf.py +++ b/tools/perf/benchmarks/blink_perf.py
@@ -167,7 +167,8 @@ return CreatePageSetFromPath(path, SKIPPED_FILE) -@benchmark.Disabled('win') # crbug.com/455796 +@benchmark.Disabled('win', # http://crbug.com/488493 + 'linux') # http://crbug.com/488059 class BlinkPerfCanvas(benchmark.Benchmark): tag = 'canvas' test = _BlinkPerfMeasurement
diff --git a/tools/perf/benchmarks/thread_times.py b/tools/perf/benchmarks/thread_times.py index 1cdbe931..812cbca70 100644 --- a/tools/perf/benchmarks/thread_times.py +++ b/tools/perf/benchmarks/thread_times.py
@@ -94,3 +94,17 @@ def Name(cls): return 'thread_times.polymer' +@benchmark.Enabled('android') +class ThreadTimesKeyIdlePowerCases(_ThreadTimes): + """Measures timeline metrics for sites that should be idle in foreground + and background scenarios. The metrics are per-second rather than per-frame.""" + page_set = page_sets.KeyIdlePowerCasesPageSet + + @classmethod + def Name(cls): + return 'thread_times.key_idle_power_cases' + + @classmethod + def ValueCanBeAddedPredicate(cls, value, _): + # Only report per-second metrics. + return 'per_frame' not in value.name and 'mean_frame' not in value.name
diff --git a/tools/perf/page_sets/android_screen_restoration_shared_state.py b/tools/perf/page_sets/android_screen_restoration_shared_state.py new file mode 100644 index 0000000..3de3c2e --- /dev/null +++ b/tools/perf/page_sets/android_screen_restoration_shared_state.py
@@ -0,0 +1,29 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +import logging + +from telemetry.page import shared_page_state + + +class AndroidScreenRestorationSharedState(shared_page_state.SharedPageState): + """ Ensures the screen is on before and after each user story is run. """ + + def WillRunUserStory(self, page): + super(AndroidScreenRestorationSharedState, self).WillRunUserStory(page) + self._EnsureScreenOn() + + def DidRunUserStory(self, results): + try: + super(AndroidScreenRestorationSharedState, self).DidRunUserStory(results) + finally: + self._EnsureScreenOn() + + def CanRunOnBrowser(self, browser_info): + if not browser_info.browser_type.startswith('android'): + logging.warning('Browser is non-Android, skipping test') + return False + return True + + def _EnsureScreenOn(self): + self.platform.android_action_runner.EnsureScreenOn()
diff --git a/tools/perf/page_sets/key_idle_power_cases.py b/tools/perf/page_sets/key_idle_power_cases.py new file mode 100644 index 0000000..207a1e3 --- /dev/null +++ b/tools/perf/page_sets/key_idle_power_cases.py
@@ -0,0 +1,66 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +from page_sets import android_screen_restoration_shared_state + +from telemetry.page import page as page_module +from telemetry.page import page_set as page_set_module + + +class KeyIdlePowerPage(page_module.Page): + + def __init__(self, url, page_set, turn_screen_off): + super(KeyIdlePowerPage, self).__init__( + url=url, + page_set=page_set, + shared_page_state_class=(android_screen_restoration_shared_state + .AndroidScreenRestorationSharedState)) + self.user_agent_type = 'mobile' + self._turn_screen_off = turn_screen_off + + def RunNavigateSteps(self, action_runner): + super(KeyIdlePowerPage, self).RunNavigateSteps(action_runner) + action_runner.Wait(2) + if self._turn_screen_off: + # TODO(jdduke): Remove this API violation after the shared page state is + # exposed here, crbug.com/470147. + # pylint: disable=protected-access + action_runner._tab.browser.platform.android_action_runner.TurnScreenOff() + # We're not interested in tracking activity that occurs immediately after + # the screen is turned off. Several seconds should be enough time for the + # browser to "settle down" into an idle state. + action_runner.Wait(2) + + def RunPageInteractions(self, action_runner): + # The page interaction is simply waiting in an idle state. + action_runner.Wait(20) + + +class KeyIdlePowerCasesPageSet(page_set_module.PageSet): + + """ Key idle power cases """ + + def __init__(self): + super(KeyIdlePowerCasesPageSet, self).__init__(user_agent_type='mobile') + + foreground_urls_list = [ + # Why: Ensure minimal activity for static, empty pages in the foreground. + 'file://key_idle_power_cases/blank.html', + ] + + for url in foreground_urls_list: + self.AddUserStory(KeyIdlePowerPage(url, self, False)) + + background_urls_list = [ + # Why: Ensure animated GIFs aren't processed when Chrome is backgrounded. + 'file://key_idle_power_cases/animated-gif.html', + # Why: Ensure CSS animations aren't processed when Chrome is backgrounded. + 'file://key_idle_power_cases/css-animation.html', + # Why: Ensure rAF is suppressed when Chrome is backgrounded. + 'file://key_idle_power_cases/request-animation-frame.html', + # Why: Ensure setTimeout is throttled when Chrome is backgrounded. + 'file://key_idle_power_cases/set-timeout.html', + ] + + for url in background_urls_list: + self.AddUserStory(KeyIdlePowerPage(url, self, True))
diff --git a/tools/perf/page_sets/key_idle_power_cases/animated-gif.html b/tools/perf/page_sets/key_idle_power_cases/animated-gif.html new file mode 100644 index 0000000..b37f244 --- /dev/null +++ b/tools/perf/page_sets/key_idle_power_cases/animated-gif.html
@@ -0,0 +1,10 @@ +<!DOCTYPE html> +<html> +<head> + <meta charset="utf-8"> + <title>Animated GIF Test</title> +</head> +<body> +<img src="animated-10color.gif"> +</body> +</html>
diff --git a/tools/perf/page_sets/key_idle_power_cases/blank.html b/tools/perf/page_sets/key_idle_power_cases/blank.html new file mode 100644 index 0000000..3ac80b70 --- /dev/null +++ b/tools/perf/page_sets/key_idle_power_cases/blank.html
@@ -0,0 +1,8 @@ +<!DOCTYPE html> +<html> +<head> + <title>Blank Test</title> +</head> +<body> +</body> +</html>
diff --git a/tools/perf/page_sets/key_idle_power_cases/css-animation.html b/tools/perf/page_sets/key_idle_power_cases/css-animation.html new file mode 100644 index 0000000..d8457ac --- /dev/null +++ b/tools/perf/page_sets/key_idle_power_cases/css-animation.html
@@ -0,0 +1,171 @@ +<!DOCTYPE html> +<html> + <head> + <title>CSS Animation Test</title> + <meta name="viewport" content="initial-scale=0.60, minimum-scale=0.60, maximum-scale=0.60"> + <style type="text/css"> + + #stage { + margin: 150px auto; + width: 600px; + height: 400px; + /* + + Setting the perspective of the contents of the stage + but not the stage itself + + */ + -webkit-perspective: 800; + } + + #rotate { + margin: 0 auto; + width: 600px; + height: 400px; + /* Ensure that we're in 3D space */ + -webkit-transform-style: preserve-3d; + /* + Make the whole set of rows use the x-axis spin animation + for a duration of 7 seconds, running infinitely and linearly + */ + -webkit-animation-name: x-spin; + -webkit-animation-duration: 7s; + -webkit-animation-iteration-count: infinite; + -webkit-animation-timing-function: linear; + } + + .ring { + margin: 0 auto; + height: 110px; + width: 600px; + -webkit-transform-style: preserve-3d; + -webkit-animation-iteration-count: infinite; + -webkit-animation-timing-function: linear; + } + + .ring > :nth-child(odd) { + background-color: #995C7F; + } + + .ring > :nth-child(even) { + background-color: #835A99; + } + + .poster { + position: absolute; + left: 250px; + width: 100px; + height: 100px; + opacity: 0.7; + color: rgba(0,0,0,0.9); + -webkit-border-radius: 10px; + } + + .poster > p { + font-family: 'Georgia', serif; + font-size: 36px; + font-weight: bold; + text-align: center; + margin-top: 28px; + } + + /* + Set up each row to have a different animation duration + and alternating y-axis rotation directions. + */ + #ring-1 { + -webkit-animation-name: y-spin; + -webkit-animation-duration: 5s; + } + + #ring-2 { + -webkit-animation-name: back-y-spin; + -webkit-animation-duration: 4s; + } + + #ring-3 { + -webkit-animation-name: y-spin; + -webkit-animation-duration: 3s; + } + + /* + + Here we define each of the three individual animations that + we will be using to have our 3D rotation effect. The first + animation will perform a full rotation on the x-axis, we'll + use that on the whole set of objects. The second and third + animations will perform a full rotation on the y-axis in + opposite directions, alternating directions between rows. + + Note that you currently have to specify an intermediate step + for rotations even when you are using individual transformation + constructs. + + */ + @-webkit-keyframes x-spin { + 0% { -webkit-transform: rotateX(0deg); } + 50% { -webkit-transform: rotateX(180deg); } + 100% { -webkit-transform: rotateX(360deg); } + } + + @-webkit-keyframes y-spin { + 0% { -webkit-transform: rotateY(0deg); } + 50% { -webkit-transform: rotateY(180deg); } + 100% { -webkit-transform: rotateY(360deg); } + } + + @-webkit-keyframes back-y-spin { + 0% { -webkit-transform: rotateY(360deg); } + 50% { -webkit-transform: rotateY(180deg); } + 100% { -webkit-transform: rotateY(0deg); } + } + </style> + + <script type="text/javascript"> + + const POSTERS_PER_ROW = 12; + const RING_RADIUS = 200; + + function setup_posters (row) + { + var posterAngle = 360 / POSTERS_PER_ROW; + for (var i = 0; i < POSTERS_PER_ROW; i ++) { + var poster = document.createElement('div'); + poster.className = 'poster'; + // compute and assign the transform for this poster + var transform = 'rotateY(' + (posterAngle * i) + 'deg) translateZ(' + RING_RADIUS + 'px)'; + poster.style.webkitTransform = transform; + // setup the number to show inside the poster + var content = poster.appendChild(document.createElement('p')); + content.textContent = i; + // add the poster to the row + row.appendChild(poster); + } + + } + + function init () + { + setup_posters(document.getElementById('ring-1')); + setup_posters(document.getElementById('ring-2')); + setup_posters(document.getElementById('ring-3')); + } + + // call init once the document is fully loaded + window.addEventListener('load', init, false); + + </script> + </head> + + <body> + <div id="stage"> + <div id="rotate"> + <div id="ring-1" class="ring"></div> + <div id="ring-2" class="ring"></div> + <div id="ring-3" class="ring"></div> + </div> + </div> + + </body> + +</html>
diff --git a/tools/perf/page_sets/key_idle_power_cases/request-animation-frame.html b/tools/perf/page_sets/key_idle_power_cases/request-animation-frame.html new file mode 100644 index 0000000..05b01c6 --- /dev/null +++ b/tools/perf/page_sets/key_idle_power_cases/request-animation-frame.html
@@ -0,0 +1,33 @@ +<!DOCTYPE html> +<html> +<head> + <meta name="viewport" content="width=device-width, minimum-scale=1.0, maximum-scale=1.0"> + <title>requestAnimationFrame Test</title> + <style type="text/css"> + html, body { + height: 100%; + padding: 0px; + margin: 0px; + } + #container { + width: 100%; + height: 100%; + background: rgb(128, 128, 128); + } + </style> +</head> +<body> + <div id="container"></div> + <script type="text/javascript"> + var container = document.getElementById('container'); + var c = 128; + tick(); + function tick() { + ++c; + c %= 256; + container.style.backgroundColor = "rgb("+c+","+c+","+c+")"; + requestAnimationFrame(tick); + }; + </script> +</body> +</html>
diff --git a/tools/perf/page_sets/key_idle_power_cases/set-timeout.html b/tools/perf/page_sets/key_idle_power_cases/set-timeout.html new file mode 100644 index 0000000..df04bbfa --- /dev/null +++ b/tools/perf/page_sets/key_idle_power_cases/set-timeout.html
@@ -0,0 +1,33 @@ +<!DOCTYPE html> +<html> +<head> + <meta name="viewport" content="width=device-width, minimum-scale=1.0, maximum-scale=1.0"> + <title>setTimeout Test</title> + <style type="text/css"> + html, body { + height: 100%; + padding: 0px; + margin: 0px; + } + #container { + width: 100%; + height: 100%; + background: rgb(128, 128, 128); + } + </style> +</head> +<body> + <div id="container"></div> + <script type="text/javascript"> + var container = document.getElementById('container'); + var c = 128; + tick(); + function tick() { + ++c; + c %= 256; + container.style.backgroundColor = "rgb("+c+","+c+","+c+")"; + setTimeout(tick, 16.66666); + }; + </script> +</body> +</html>
diff --git a/tools/perf/record_wpr b/tools/perf/record_wpr index e12055f..c579adf 100755 --- a/tools/perf/record_wpr +++ b/tools/perf/record_wpr
@@ -11,7 +11,7 @@ _telemetry_path = os.path.join(_perf_dir, os.pardir, 'telemetry') sys.path.append(_telemetry_path) -from telemetry.page import record_wpr +from telemetry import record_wpr if __name__ == '__main__': sys.exit(record_wpr.Main(_perf_dir))
diff --git a/tools/telemetry/telemetry/TELEMETRY_DEPS b/tools/telemetry/telemetry/TELEMETRY_DEPS index 1cfc34c..1bf6493 100644 --- a/tools/telemetry/telemetry/TELEMETRY_DEPS +++ b/tools/telemetry/telemetry/TELEMETRY_DEPS
@@ -46,6 +46,7 @@ "build/android/android_no_jni_exports.lst", "build/android/ant/apk-package.xml", "build/android/ant/chromium-debug.keystore", + "build/android/apkbuilder_action.gypi", "build/android/asan_symbolize.py", "build/android/avd.py", "build/android/bb_run_sharded_steps.py", @@ -134,6 +135,7 @@ "build/android/native_app_dependencies.gypi", "build/android/ndk.gyp", "build/android/pack_arm_relocations.gypi", + "build/android/package_resources_action.gypi", "build/android/provision_devices.py", "build/android/push_libraries.gypi", "build/android/rezip.gyp",
diff --git a/tools/telemetry/telemetry/core/backends/chrome_inspector/inspector_websocket_unittest.py b/tools/telemetry/telemetry/core/backends/chrome_inspector/inspector_websocket_unittest.py index 397f7ee..0db7face 100644 --- a/tools/telemetry/telemetry/core/backends/chrome_inspector/inspector_websocket_unittest.py +++ b/tools/telemetry/telemetry/core/backends/chrome_inspector/inspector_websocket_unittest.py
@@ -112,6 +112,7 @@ self.assertEqual(1, len(results)) self.assertEqual('Test2.foo', results[0]['method']) + @decorators.Disabled('chromeos') # crbug.com/483212 def testUnregisterDomainWithUnregisteredDomain(self): inspector = inspector_websocket.InspectorWebsocket() with self.assertRaises(AssertionError):
diff --git a/tools/telemetry/telemetry/core/browser_info.py b/tools/telemetry/telemetry/core/browser_info.py index df85029..94cb1543 100644 --- a/tools/telemetry/telemetry/core/browser_info.py +++ b/tools/telemetry/telemetry/core/browser_info.py
@@ -53,3 +53,7 @@ branch_num = ( self._browser._browser_backend.devtools_client.GetChromeBranchNumber()) return branch_num >= 2332 + + @property + def browser_type(self): + return self._browser.browser_type
diff --git a/tools/telemetry/telemetry/core/platform/android_action_runner.py b/tools/telemetry/telemetry/core/platform/android_action_runner.py index 8728c9f..c2f79b4 100644 --- a/tools/telemetry/telemetry/core/platform/android_action_runner.py +++ b/tools/telemetry/telemetry/core/platform/android_action_runner.py
@@ -116,15 +116,28 @@ """ self._platform_backend.adb.RunShellCommand('input roll %s %s' % (dx, dy)) + def EnsureScreenOn(self): + """If device screen is off, turn screen on. + If the screen is already on, return immediately. + + Raises: + Timeout: If the screen is off and device fails to turn screen on. + """ + if self._platform_backend.IsScreenOn(): + return + + self._ToggleScreenOn() + util.WaitFor(self._platform_backend.IsScreenOn, 5) + def TurnScreenOn(self): """If device screen is off, turn screen on. - If the screen is already on, this method returns immediately. + If the screen is already on, log a warning and return immediately. Raises: Timeout: If the screen is off and device fails to turn screen on. """ if not self._platform_backend.IsScreenOn(): - self._platform_backend.adb.RunShellCommand('input keyevent 26') + self._ToggleScreenOn() else: logging.warning('Screen on when expected off.') return @@ -133,7 +146,7 @@ def TurnScreenOff(self): """If device screen is on, turn screen off. - If the screen is already off, this method returns immediately. + If the screen is already off, log a warning and return immediately. Raises: Timeout: If the screen is on and device fails to turn screen off. @@ -142,8 +155,7 @@ return not self._platform_backend.IsScreenOn() if self._platform_backend.IsScreenOn(): - self._platform_backend.adb.RunShellCommand( - 'input keyevent 26') + self._ToggleScreenOn() else: logging.warning('Screen off when expected on.') return @@ -152,7 +164,7 @@ def UnlockScreen(self): """If device screen is locked, unlocks it. - If the device is not locked, this method returns immediately. + If the device is not locked, log a warning and return immediately. Raises: Timeout: If device fails to unlock screen. @@ -167,3 +179,6 @@ return util.WaitFor(is_screen_unlocked, 5) + + def _ToggleScreenOn(self): + self._platform_backend.adb.RunShellCommand('input keyevent 26')
diff --git a/tools/telemetry/telemetry/core/user_agent_unittest.py b/tools/telemetry/telemetry/core/user_agent_unittest.py index b5160b0..d0539fa1 100644 --- a/tools/telemetry/telemetry/core/user_agent_unittest.py +++ b/tools/telemetry/telemetry/core/user_agent_unittest.py
@@ -2,6 +2,7 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +from telemetry import decorators from telemetry.core import user_agent from telemetry.unittest_util import tab_test_case @@ -11,6 +12,7 @@ def CustomizeBrowserOptions(cls, options): options.browser_user_agent_type = 'mobile' + @decorators.Disabled('chromeos') # crbug.com/483212 def testUserAgent(self): ua = self._tab.EvaluateJavaScript('window.navigator.userAgent') self.assertEquals(ua, user_agent.UA_TYPE_MAPPING['mobile']) @@ -20,6 +22,7 @@ def CustomizeBrowserOptions(cls, options): options.browser_user_agent_type = 'tablet' + @decorators.Disabled('chromeos') # crbug.com/483212 def testUserAgent(self): ua = self._tab.EvaluateJavaScript('window.navigator.userAgent') self.assertEquals(ua, user_agent.UA_TYPE_MAPPING['tablet']) @@ -29,6 +32,7 @@ def CustomizeBrowserOptions(cls, options): options.browser_user_agent_type = 'desktop' + @decorators.Disabled('chromeos') # crbug.com/483212 def testUserAgent(self): ua = self._tab.EvaluateJavaScript('window.navigator.userAgent') self.assertEquals(ua, user_agent.UA_TYPE_MAPPING['desktop'])
diff --git a/tools/telemetry/telemetry/page/record_wpr.py b/tools/telemetry/telemetry/record_wpr.py similarity index 67% rename from tools/telemetry/telemetry/page/record_wpr.py rename to tools/telemetry/telemetry/record_wpr.py index 6d0ecbf..8ce1974 100644 --- a/tools/telemetry/telemetry/page/record_wpr.py +++ b/tools/telemetry/telemetry/record_wpr.py
@@ -2,6 +2,7 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import argparse import logging import sys @@ -16,7 +17,8 @@ from telemetry.page import test_expectations from telemetry.results import results_options -class RecorderPageTest(page_test.PageTest): # pylint: disable=W0223 + +class RecorderPageTest(page_test.PageTest): def __init__(self): super(RecorderPageTest, self).__init__() self.page_test = None @@ -68,14 +70,43 @@ super(RecorderPageTest, self).RunNavigateSteps(page, tab) +def _GetSubclasses(base_dir, cls): + """ Return all subclasses of |cls| in |base_dir|. + Args: + cls: a class + Returns: + + """ + return discover.DiscoverClasses(base_dir, base_dir, cls, + index_by_class_name=True) + + def _MaybeGetInstanceOfClass(target, base_dir, cls): if isinstance(target, cls): return target - classes = discover.DiscoverClasses(base_dir, base_dir, cls, - index_by_class_name=True) + classes = _GetSubclasses(base_dir, cls) return classes[target]() if target in classes else None +def _PrintAllBenchmarks(base_dir, output_stream): + # TODO: reuse the logic of finding supported benchmarks in benchmark_runner.py + # so this only prints out benchmarks that are supported by the recording + # platform. + classes = _GetSubclasses(base_dir, benchmark.Benchmark) + output_stream.write('Available benchmarks\' names:\n\n') + for k in classes: + output_stream.write('%s\n' % k) + + +def _PrintAllUserStories(base_dir, output_stream): + output_stream.write('Available page sets\' names:\n\n') + # TODO: actually print all user stories once record_wpr support general + # user stories recording. + classes = _GetSubclasses(base_dir, page_set.PageSet) + for k in classes: + output_stream.write('%s\n' % k) + + class WprRecorder(object): def __init__(self, base_dir, target, args=None): @@ -84,7 +115,7 @@ self._benchmark = _MaybeGetInstanceOfClass(target, base_dir, benchmark.Benchmark) - self._parser = self._options.CreateParser(usage='%prog <PageSet|Benchmark>') + self._parser = self._options.CreateParser(usage='See %prog --help') self._AddCommandLineArgs() self._ParseArgs(args) self._ProcessCommandLineArgs() @@ -166,22 +197,43 @@ upload_to_cloud_storage) +# TODO(nednguyen): use benchmark.Environment instead of base_dir for discovering +# benchmark & user story classes. def Main(base_dir): - quick_args = [] - upload_to_cloud_storage = False - for a in sys.argv[1:]: - if not a.startswith('-'): - quick_args.append(a) - elif a == '--upload': - upload_to_cloud_storage = True + parser = argparse.ArgumentParser( + usage='Record a benchmark or a user story (page set).') + parser.add_argument( + 'benchmark', type=str, + help=('benchmark name. This argument is optional. If both benchmark name ' + 'and user story name are specified, this takes precedence as the ' + 'target of the recording.'), + nargs='?') + parser.add_argument('--story', dest='story', type=str, + help='user story (page set) name') + parser.add_argument('--list-stories', dest='list_stories', + action='store_true', help='list all user story names.') + parser.add_argument('--list-benchmarks', dest='list_benchmarks', + action='store_true', help='list all benchmark names.') + parser.add_argument('--upload', action='store_true', + help='upload to cloud storage.') + args, extra_args = parser.parse_known_args() - if len(quick_args) != 1: - print >> sys.stderr, 'Usage: record_wpr <PageSet|Benchmark> [--upload]\n' - sys.exit(1) - target = quick_args.pop() - wpr_recorder = WprRecorder(base_dir, target) + if args.list_benchmarks: + _PrintAllBenchmarks(base_dir, sys.stderr) + elif args.list_stories: + _PrintAllUserStories(base_dir, sys.stderr) + + target = args.benchmark or args.story + + if not target: + return 0 + + # TODO(nednguyen): update WprRecorder so that it handles the difference + # between recording a benchmark vs recording a user story better based on + # the distinction between args.benchmark & args.story + wpr_recorder = WprRecorder(base_dir, target, extra_args) results = wpr_recorder.CreateResults() wpr_recorder.Record(results) - wpr_recorder.HandleResults(results, upload_to_cloud_storage) + wpr_recorder.HandleResults(results, args.upload) return min(255, len(results.failures))
diff --git a/tools/telemetry/telemetry/page/record_wpr_unittest.py b/tools/telemetry/telemetry/record_wpr_unittest.py similarity index 99% rename from tools/telemetry/telemetry/page/record_wpr_unittest.py rename to tools/telemetry/telemetry/record_wpr_unittest.py index 367461c..c0ba943 100644 --- a/tools/telemetry/telemetry/page/record_wpr_unittest.py +++ b/tools/telemetry/telemetry/record_wpr_unittest.py
@@ -6,13 +6,13 @@ import sys from telemetry import benchmark +from telemetry import record_wpr from telemetry.core import util from telemetry.core import wpr_modes from telemetry import decorators from telemetry.page import page as page_module from telemetry.page import page_set as page_set_module from telemetry.page import page_test -from telemetry.page import record_wpr from telemetry.unittest_util import tab_test_case
diff --git a/tools/valgrind/gtest_exclude/browser_tests.gtest-drmemory.txt b/tools/valgrind/gtest_exclude/browser_tests.gtest-drmemory.txt index 9e10b47..6823027 100644 --- a/tools/valgrind/gtest_exclude/browser_tests.gtest-drmemory.txt +++ b/tools/valgrind/gtest_exclude/browser_tests.gtest-drmemory.txt
@@ -35,8 +35,3 @@ # https://crbug.com/480721 OutOfProcessProxyResolverBrowserTest.Verify - -# https://crbug.com/484910 -PasswordAutofillAgentTest.ClearPreviewWithInlineAutocompletedUsername -PasswordAutofillAgentTest.InlineAutocomplete -PasswordAutofillAgentTest.RememberLastNonEmptyUsernameAndPasswordOnSubmit_UserCleared
diff --git a/tools/valgrind/gtest_exclude/net_unittests.gtest-drmemory_win-xp.txt b/tools/valgrind/gtest_exclude/net_unittests.gtest-drmemory_win-xp.txt deleted file mode 100644 index 9d77b20..0000000 --- a/tools/valgrind/gtest_exclude/net_unittests.gtest-drmemory_win-xp.txt +++ /dev/null
@@ -1,3 +0,0 @@ -# https://github.com/DynamoRIO/drmemory/issues/842 -# Failing and then crashing. -HttpNetworkTransationSpdy21Test.HttpsProxySpdy*
diff --git a/ui/android/java/src/org/chromium/ui/picker/DateTimePickerDialog.java b/ui/android/java/src/org/chromium/ui/picker/DateTimePickerDialog.java index c9dde077..8a0ff359 100644 --- a/ui/android/java/src/org/chromium/ui/picker/DateTimePickerDialog.java +++ b/ui/android/java/src/org/chromium/ui/picker/DateTimePickerDialog.java
@@ -99,6 +99,7 @@ private void tryNotifyDateTimeSet() { if (mCallBack != null) { mDatePicker.clearFocus(); + mTimePicker.clearFocus(); mCallBack.onDateTimeSet(mDatePicker, mTimePicker, mDatePicker.getYear(), mDatePicker.getMonth(), mDatePicker.getDayOfMonth(), mTimePicker.getCurrentHour(), mTimePicker.getCurrentMinute());
diff --git a/ui/android/java/src/org/chromium/ui/picker/MultiFieldTimePickerDialog.java b/ui/android/java/src/org/chromium/ui/picker/MultiFieldTimePickerDialog.java index f8647ec..43cee0e8 100644 --- a/ui/android/java/src/org/chromium/ui/picker/MultiFieldTimePickerDialog.java +++ b/ui/android/java/src/org/chromium/ui/picker/MultiFieldTimePickerDialog.java
@@ -247,12 +247,12 @@ } private void notifyDateSet() { - int hour = mHourSpinner.getValue(); - int minute = mMinuteSpinner.getValue(); - int sec = mSecSpinner.getValue(); - int milli = mMilliSpinner.getValue() * mStep + mBaseMilli; + int hour = getPickerValue(mHourSpinner); + int minute = getPickerValue(mMinuteSpinner); + int sec = getPickerValue(mSecSpinner); + int milli = getPickerValue(mMilliSpinner) * mStep + mBaseMilli; if (!mIs24hourFormat) { - int ampm = mAmPmSpinner.getValue(); + int ampm = getPickerValue(mAmPmSpinner); if (hour == 12) { hour = 0; } @@ -261,6 +261,15 @@ mListener.onTimeSet(hour, minute, sec, milli); } + /** + * Clear focus before retrieving so that values inserted with + * keyboard are taken into account. + */ + private int getPickerValue(NumberPicker picker) { + picker.clearFocus(); + return picker.getValue(); + } + private static class NumberFormatter implements NumberPicker.Formatter { private final String mFormat;
diff --git a/ui/base/cocoa/nsview_additions.h b/ui/base/cocoa/nsview_additions.h index 467c04fa..62043b2a 100644 --- a/ui/base/cocoa/nsview_additions.h +++ b/ui/base/cocoa/nsview_additions.h
@@ -37,7 +37,12 @@ // Draw using ancestorView's drawRect function into this view's rect. Do any // required translating or flipping to transform between the two coordinate -// systems. +// systems, and optionally clip to the ancestor view's bounds. +- (void)cr_drawUsingAncestor:(NSView*)ancestorView inRect:(NSRect)dirtyRect + clippedToAncestorBounds:(BOOL)clipToAncestorBounds; + +// Same as cr_drawUsingAncestor:inRect:clippedToAncestorBounds: except always +// clips to the ancestor view's bounds. - (void)cr_drawUsingAncestor:(NSView*)ancestorView inRect:(NSRect)dirtyRect; // Used by ancestorView in the above draw call, to look up the child view that
diff --git a/ui/base/cocoa/nsview_additions.mm b/ui/base/cocoa/nsview_additions.mm index 49f18b0..1bfd3a5 100644 --- a/ui/base/cocoa/nsview_additions.mm +++ b/ui/base/cocoa/nsview_additions.mm
@@ -75,7 +75,8 @@ static NSView* g_ancestorBeingDrawnFrom = nil; static NSView* g_childBeingDrawnTo = nil; -- (void)cr_drawUsingAncestor:(NSView*)ancestorView inRect:(NSRect)dirtyRect { +- (void)cr_drawUsingAncestor:(NSView*)ancestorView inRect:(NSRect)dirtyRect + clippedToAncestorBounds:(BOOL)clipToAncestorBounds { gfx::ScopedNSGraphicsContextSaveGState scopedGSState; NSRect frame = [self convertRect:[self bounds] toView:ancestorView]; NSAffineTransform* transform = [NSAffineTransform transform]; @@ -91,13 +92,21 @@ DCHECK(!g_ancestorBeingDrawnFrom && !g_childBeingDrawnTo); g_ancestorBeingDrawnFrom = ancestorView; g_childBeingDrawnTo = self; - [ancestorView drawRect:NSIntersectionRect( - [ancestorView bounds], - [self convertRect:dirtyRect toView:ancestorView])]; + NSRect drawRect = [self convertRect:dirtyRect toView:ancestorView]; + if (clipToAncestorBounds) { + drawRect = NSIntersectionRect([ancestorView bounds], drawRect); + } + [ancestorView drawRect:drawRect]; g_childBeingDrawnTo = nil; g_ancestorBeingDrawnFrom = nil; } +- (void)cr_drawUsingAncestor:(NSView*)ancestorView inRect:(NSRect)dirtyRect { + [self cr_drawUsingAncestor:ancestorView + inRect:dirtyRect + clippedToAncestorBounds:YES]; +} + - (NSView*)cr_viewBeingDrawnTo { if (!g_ancestorBeingDrawnFrom) return self;
diff --git a/ui/compositor/layer.cc b/ui/compositor/layer.cc index c1347c4e..a46c6b9 100644 --- a/ui/compositor/layer.cc +++ b/ui/compositor/layer.cc
@@ -796,7 +796,7 @@ void AppendAsTraceFormat(std::string* out) const override { base::DictionaryValue dictionary; dictionary.SetString("layer_name", name_); - base::JSONWriter::Write(&dictionary, out); + base::JSONWriter::Write(dictionary, out); } private:
diff --git a/ui/events/event_unittest.cc b/ui/events/event_unittest.cc index 0ac9335..38ad283 100644 --- a/ui/events/event_unittest.cc +++ b/ui/events/event_unittest.cc
@@ -351,7 +351,7 @@ ASSERT_EQ(kDomCodeForSpace, ui::KeycodeConverter::CodeStringToDomCode(kCodeForSpace)); const uint16 kNativeCodeSpace = - ui::KeycodeConverter::CodeToNativeKeycode(kCodeForSpace); + ui::KeycodeConverter::DomCodeToNativeKeycode(kDomCodeForSpace); ASSERT_NE(ui::KeycodeConverter::InvalidNativeKeycode(), kNativeCodeSpace); ASSERT_EQ(kNativeCodeSpace, ui::KeycodeConverter::DomCodeToNativeKeycode(kDomCodeForSpace)); @@ -433,8 +433,10 @@ #if defined(USE_X11) || defined(OS_WIN) TEST(EventTest, AutoRepeat) { - const uint16 kNativeCodeA = ui::KeycodeConverter::CodeToNativeKeycode("KeyA"); - const uint16 kNativeCodeB = ui::KeycodeConverter::CodeToNativeKeycode("KeyB"); + const uint16 kNativeCodeA = + ui::KeycodeConverter::DomCodeToNativeKeycode(DomCode::KEY_A); + const uint16 kNativeCodeB = + ui::KeycodeConverter::DomCodeToNativeKeycode(DomCode::KEY_B); #if defined(USE_X11) ScopedXI2Event native_event_a_pressed; native_event_a_pressed.InitKeyEvent(ET_KEY_PRESSED, VKEY_A, kNativeCodeA);
diff --git a/ui/events/keycodes/dom/keycode_converter.cc b/ui/events/keycodes/dom/keycode_converter.cc index c77b8aba..c438a66 100644 --- a/ui/events/keycodes/dom/keycode_converter.cc +++ b/ui/events/keycodes/dom/keycode_converter.cc
@@ -69,18 +69,6 @@ } // static -const char* KeycodeConverter::NativeKeycodeToCode(int native_keycode) { - for (size_t i = 0; i < kKeycodeMapEntries; ++i) { - if (usb_keycode_map[i].native_keycode == native_keycode) { - if (usb_keycode_map[i].code != NULL) - return usb_keycode_map[i].code; - break; - } - } - return ""; -} - -// static DomCode KeycodeConverter::NativeKeycodeToDomCode(int native_keycode) { for (size_t i = 0; i < kKeycodeMapEntries; ++i) { if (usb_keycode_map[i].native_keycode == native_keycode) { @@ -93,20 +81,6 @@ } // static -int KeycodeConverter::CodeToNativeKeycode(const char* code) { - if (!code || !*code) - return InvalidNativeKeycode(); - - for (size_t i = 0; i < kKeycodeMapEntries; ++i) { - if (usb_keycode_map[i].code && - strcmp(usb_keycode_map[i].code, code) == 0) { - return usb_keycode_map[i].native_keycode; - } - } - return InvalidNativeKeycode(); -} - -// static int KeycodeConverter::DomCodeToNativeKeycode(DomCode code) { return UsbKeycodeToNativeKeycode(static_cast<uint32_t>(code)); } @@ -129,7 +103,14 @@ // static const char* KeycodeConverter::DomCodeToCodeString(DomCode dom_code) { - return UsbKeycodeToCode(static_cast<uint32_t>(dom_code)); + for (size_t i = 0; i < kKeycodeMapEntries; ++i) { + if (usb_keycode_map[i].usb_keycode == static_cast<uint32_t>(dom_code)) { + if (usb_keycode_map[i].code) + return usb_keycode_map[i].code; + break; + } + } + return ""; } // static @@ -239,18 +220,6 @@ } // static -const char* KeycodeConverter::UsbKeycodeToCode(uint32_t usb_keycode) { - for (size_t i = 0; i < kKeycodeMapEntries; ++i) { - if (usb_keycode_map[i].usb_keycode == usb_keycode) { - if (usb_keycode_map[i].code) - return usb_keycode_map[i].code; - break; - } - } - return ""; -} - -// static DomCode KeycodeConverter::UsbKeycodeToDomCode(uint32_t usb_keycode) { for (size_t i = 0; i < kKeycodeMapEntries; ++i) { if (usb_keycode_map[i].usb_keycode == usb_keycode) @@ -260,6 +229,15 @@ } // static +uint32_t KeycodeConverter::DomCodeToUsbKeycode(DomCode dom_code) { + for (size_t i = 0; i < kKeycodeMapEntries; ++i) { + if (usb_keycode_map[i].usb_keycode == static_cast<uint32_t>(dom_code)) + return usb_keycode_map[i].usb_keycode; + } + return InvalidUsbKeycode(); +} + +// static uint32_t KeycodeConverter::CodeToUsbKeycode(const char* code) { if (!code || !*code) return InvalidUsbKeycode();
diff --git a/ui/events/keycodes/dom/keycode_converter.h b/ui/events/keycodes/dom/keycode_converter.h index 1f1fed0d..fb1ac041 100644 --- a/ui/events/keycodes/dom/keycode_converter.h +++ b/ui/events/keycodes/dom/keycode_converter.h
@@ -45,16 +45,9 @@ // Return the value that identifies an invalid native keycode. static int InvalidNativeKeycode(); - // Convert a native (Mac/Win/Linux) keycode into the |code| string. - // The returned pointer references a static global string. - static const char* NativeKeycodeToCode(int native_keycode); - // Convert a native (Mac/Win/Linux) keycode into a DomCode. static DomCode NativeKeycodeToDomCode(int native_keycode); - // Convert a UI Events |code| string value into a native keycode. - static int CodeToNativeKeycode(const char* code); - // Convert a DomCode into a native keycode. static int DomCodeToNativeKeycode(DomCode code); @@ -88,13 +81,12 @@ // Convert a platform native keycode into an equivalent USB keycode. static uint32_t NativeKeycodeToUsbKeycode(int native_keycode); - // Convert a USB keycode into the string with the DOM3 |code| value. - // The returned pointer references a static global string. - static const char* UsbKeycodeToCode(uint32_t usb_keycode); - // Convert a USB keycode into a DomCode. static DomCode UsbKeycodeToDomCode(uint32_t usb_keycode); + // Convert a DomCode into a USB keycode. + static uint32_t DomCodeToUsbKeycode(DomCode dom_code); + // Convert a DOM3 Event |code| string into a USB keycode value. static uint32_t CodeToUsbKeycode(const char* code);
diff --git a/ui/events/keycodes/dom/keycode_converter_unittest.cc b/ui/events/keycodes/dom/keycode_converter_unittest.cc index c3149ce..f5da9a092 100644 --- a/ui/events/keycodes/dom/keycode_converter_unittest.cc +++ b/ui/events/keycodes/dom/keycode_converter_unittest.cc
@@ -38,7 +38,7 @@ EXPECT_EQ(ui::KeycodeConverter::InvalidNativeKeycode(), keycode_map[0].native_keycode); EXPECT_EQ(ui::KeycodeConverter::InvalidNativeKeycode(), - ui::KeycodeConverter::CodeToNativeKeycode("Unidentified")); + ui::KeycodeConverter::DomCodeToNativeKeycode(ui::DomCode::NONE)); // Verify that there are no duplicate entries in the mapping. std::map<uint32_t, uint16_t> usb_to_native; @@ -55,17 +55,14 @@ entry->native_keycode, ui::KeycodeConverter::UsbKeycodeToNativeKeycode(entry->usb_keycode)); - // Verify CodeToNativeKeycode and NativeKeycodeToCode work correctly. + // Verify DomCodeToNativeKeycode works correctly. + ui::DomCode dom_code = + ui::KeycodeConverter::CodeStringToDomCode(entry->code); if (entry->code) { EXPECT_EQ(entry->native_keycode, - ui::KeycodeConverter::CodeToNativeKeycode(entry->code)); - EXPECT_STREQ( - entry->code, - ui::KeycodeConverter::NativeKeycodeToCode(entry->native_keycode)); - } - else { - EXPECT_EQ(ui::KeycodeConverter::InvalidNativeKeycode(), - ui::KeycodeConverter::CodeToNativeKeycode(entry->code)); + ui::KeycodeConverter::DomCodeToNativeKeycode(dom_code)); + } else { + EXPECT_EQ(ui::DomCode::NONE, dom_code); } // Verify that the USB or native codes aren't duplicated.
diff --git a/ui/events/latency_info.cc b/ui/events/latency_info.cc index 96fe74c1..d815790 100644 --- a/ui/events/latency_info.cc +++ b/ui/events/latency_info.cc
@@ -108,7 +108,7 @@ void LatencyInfoTracedValue::AppendAsTraceFormat(std::string* out) const { std::string tmp; - base::JSONWriter::Write(value_.get(), &tmp); + base::JSONWriter::Write(*value_, &tmp); *out += tmp; } @@ -296,7 +296,7 @@ } TRACE_EVENT_COPY_ASYNC_BEGIN_WITH_TIMESTAMP0( - "benchmark", + "benchmark,latencyInfo", trace_name.c_str(), TRACE_ID_DONT_MANGLE(trace_id), ts); @@ -332,7 +332,7 @@ terminated = true; if (*benchmark_enabled) { - TRACE_EVENT_COPY_ASYNC_END1("benchmark", + TRACE_EVENT_COPY_ASYNC_END1("benchmark,latencyInfo", trace_name.c_str(), TRACE_ID_DONT_MANGLE(trace_id), "data", AsTraceableData(*this));
diff --git a/ui/file_manager/file_manager/background/js/volume_manager.js b/ui/file_manager/file_manager/background/js/volume_manager.js index ac7a4505..0c0e6c8 100644 --- a/ui/file_manager/file_manager/background/js/volume_manager.js +++ b/ui/file_manager/file_manager/background/js/volume_manager.js
@@ -27,6 +27,7 @@ * @param {boolean} hasMedia When true the volume has been identified * as containing media such as photos or videos. * @param {boolean} configurable When true, then the volume can be configured. + * @param {VolumeManagerCommon.Source} source Source of the volume's data. */ function VolumeInfo( volumeType, @@ -40,7 +41,8 @@ label, extensionId, hasMedia, - configurable) { + configurable, + source) { this.volumeType_ = volumeType; this.volumeId_ = volumeId; this.fileSystem_ = fileSystem; @@ -83,6 +85,7 @@ this.extensionId_ = extensionId; this.hasMedia_ = hasMedia; this.configurable_ = configurable; + this.source_ = source; } VolumeInfo.prototype = /** @struct */ { @@ -170,6 +173,12 @@ */ get configurable() { return this.configurable_; + }, + /** + * @return {VolumeManagerCommon.Source} Source of the volume's data. + */ + get source() { + return this.source_; } }; @@ -254,124 +263,104 @@ } console.debug('Requesting file system.'); - var configurable = false; - return new Promise( function(resolve, reject) { - if (volumeMetadata.volumeType !== - VolumeManagerCommon.VolumeType.PROVIDED) { - resolve(); - } - - chrome.fileManagerPrivate.getProvidingExtensions( - function(extensions) { - if (chrome.runtime.lastError) { + chrome.fileSystem.requestFileSystem( + { + volumeId: volumeMetadata.volumeId, + writable: !volumeMetadata.isReadOnly + }, + function(isolatedFileSystem) { + if (chrome.runtime.lastError) reject(chrome.runtime.lastError.message); - return; - } - configurable = extensions.some(function(extension) { - return extension.extensionId === volumeMetadata.extensionId && - extension.configurable; - }); - resolve(); + else + resolve(isolatedFileSystem); }); }) - .then( - function() { - return new Promise(function(resolve, reject) { - chrome.fileSystem.requestFileSystem( - { - volumeId: volumeMetadata.volumeId, - writable: !volumeMetadata.isReadOnly - }, - function(isolatedFileSystem) { - if (chrome.runtime.lastError) - reject(chrome.runtime.lastError.message); - else - resolve(isolatedFileSystem); - }); - }); - }) - .then( - /** - * @param {!FileSystem} isolatedFileSystem - */ - function(isolatedFileSystem) { - // Since File System API works on isolated entries only, we need to - // convert it back to external one. - // TODO(mtomasz): Make Files app work on isolated entries. - return new Promise(function(resolve, reject) { - chrome.fileManagerPrivate.resolveIsolatedEntries( - [isolatedFileSystem.root], - function(entries) { - if (chrome.runtime.lastError) - reject(chrome.runtime.lastError.message); - else if (!entries[0]) - reject('Resolving for external context failed.'); - else - resolve(entries[0].filesystem); - }); + .then( + /** + * @param {!FileSystem} isolatedFileSystem + */ + function(isolatedFileSystem) { + // Since File System API works on isolated entries only, we need to + // convert it back to external one. + // TODO(mtomasz): Make Files app work on isolated entries. + return new Promise(function(resolve, reject) { + chrome.fileManagerPrivate.resolveIsolatedEntries( + [isolatedFileSystem.root], + function(entries) { + if (chrome.runtime.lastError) + reject(chrome.runtime.lastError.message); + else if (!entries[0]) + reject('Resolving for external context failed.'); + else + resolve(entries[0].filesystem); }); - }) - .then( - /** - * @param {!FileSystem} fileSystem - */ - function(fileSystem) { - console.debug('File system obtained: ' + volumeMetadata.volumeId); - if (volumeMetadata.volumeType === - VolumeManagerCommon.VolumeType.DRIVE) { - // After file system is mounted, we "read" drive grand root - // entry at first. This triggers full feed fetch on background. - // Note: we don't need to handle errors here, because even if - // it fails, accessing to some path later will just become - // a fast-fetch and it re-triggers full-feed fetch. - fileSystem.root.createReader().readEntries( - function() { /* do nothing */ }, - function(error) { - console.error( - 'Triggering full feed fetch is failed: ' + - error.name); - }); - } - return new VolumeInfo( - /** @type {VolumeManagerCommon.VolumeType} */ - (volumeMetadata.volumeType), - volumeMetadata.volumeId, - fileSystem, - volumeMetadata.mountCondition, - volumeMetadata.deviceType, - volumeMetadata.devicePath, - volumeMetadata.isReadOnly, - volumeMetadata.profile, - localizedLabel, - volumeMetadata.extensionId, - volumeMetadata.hasMedia, - configurable); - }) - .catch( - /** - * @param {*} error - */ - function(error) { - console.error('Failed to mount a file system: ' + - volumeMetadata.volumeId + ' because of: ' + - (error.stack || error)); - return new VolumeInfo( - /** @type {VolumeManagerCommon.VolumeType} */ - (volumeMetadata.volumeType), - volumeMetadata.volumeId, - null, // File system is not found. - volumeMetadata.mountCondition, - volumeMetadata.deviceType, - volumeMetadata.devicePath, - volumeMetadata.isReadOnly, - volumeMetadata.profile, - localizedLabel, - volumeMetadata.extensionId, - volumeMetadata.hasMedia, - configurable); }); + }) + .then( + /** + * @param {!FileSystem} fileSystem + */ + function(fileSystem) { + console.debug('File system obtained: ' + volumeMetadata.volumeId); + if (volumeMetadata.volumeType === + VolumeManagerCommon.VolumeType.DRIVE) { + // After file system is mounted, we "read" drive grand root + // entry at first. This triggers full feed fetch on background. + // Note: we don't need to handle errors here, because even if + // it fails, accessing to some path later will just become + // a fast-fetch and it re-triggers full-feed fetch. + fileSystem.root.createReader().readEntries( + function() { /* do nothing */ }, + function(error) { + console.error( + 'Triggering full feed fetch is failed: ' + + error.name); + }); + } + return new VolumeInfo( + /** @type {VolumeManagerCommon.VolumeType} */ + (volumeMetadata.volumeType), + volumeMetadata.volumeId, + fileSystem, + volumeMetadata.mountCondition, + volumeMetadata.deviceType, + volumeMetadata.devicePath, + volumeMetadata.isReadOnly, + volumeMetadata.profile, + localizedLabel, + volumeMetadata.extensionId, + volumeMetadata.hasMedia, + volumeMetadata.configurable, + /** @type {VolumeManagerCommon.Source} */ + (volumeMetadata.source)); + }) + .catch( + /** + * @param {*} error + */ + function(error) { + console.error('Failed to mount a file system: ' + + volumeMetadata.volumeId + ' because of: ' + + (error.stack || error)); + return new VolumeInfo( + /** @type {VolumeManagerCommon.VolumeType} */ + (volumeMetadata.volumeType), + volumeMetadata.volumeId, + null, // File system is not found. + volumeMetadata.mountCondition, + volumeMetadata.deviceType, + volumeMetadata.devicePath, + volumeMetadata.isReadOnly, + volumeMetadata.profile, + localizedLabel, + volumeMetadata.extensionId, + volumeMetadata.hasMedia, + volumeMetadata.configurable, + /** @type {VolumeManagerCommon.Source} */ + (volumeMetadata.source)); + }); }; /** @@ -863,7 +852,7 @@ }; /** - * Unmounts volume. + * Unmounts a volume. * @param {!VolumeInfo} volumeInfo Volume to be unmounted. * @param {function()} successCallback Success callback. * @param {function(VolumeManagerCommon.VolumeError)} errorCallback Error @@ -877,6 +866,25 @@ this.startRequest_(requestKey, successCallback, errorCallback); }; +/** + * Configures a volume. + * @param {!VolumeInfo} volumeInfo Volume to be configured. + * @return {!Promise} Fulfilled on success, otherwise rejected with an error + * message. + */ +VolumeManager.prototype.configure = function(volumeInfo) { + return new Promise(function(fulfill, reject) { + chrome.fileManagerPrivate.configureVolume( + volumeInfo.volumeId, + function() { + if (chrome.runtime.lastError) + reject(chrome.runtime.lastError.message); + else + fulfill(); + }); + }); +}; + /** @override */ VolumeManager.prototype.getVolumeInfo = function(entry) { return this.volumeInfoList.findByEntry(entry);
diff --git a/ui/file_manager/file_manager/background/js/volume_manager_unittest.js b/ui/file_manager/file_manager/background/js/volume_manager_unittest.js index d2d4c4f..30cb335 100644 --- a/ui/file_manager/file_manager/background/js/volume_manager_unittest.js +++ b/ui/file_manager/file_manager/background/js/volume_manager_unittest.js
@@ -91,14 +91,18 @@ volumeLabel: '', volumeType: VolumeManagerCommon.VolumeType.DOWNLOADS, isReadOnly: false, - profile: getMockProfile() + profile: getMockProfile(), + configurable: false, + source: VolumeManagerCommon.Source.SYSTEM }, { volumeId: 'drive:drive-foobar%40chromium.org-hash', volumeLabel: '', volumeType: VolumeManagerCommon.VolumeType.DRIVE, isReadOnly: false, - profile: getMockProfile() + profile: getMockProfile(), + configurable: false, + source: VolumeManagerCommon.Source.NETWORK } ]; chrome.fileManagerPrivate.fileSystemMap_ = { @@ -185,7 +189,9 @@ volumeType: VolumeManagerCommon.VolumeType.ARCHIVE, isReadOnly: true, sourcePath: mountSourcePath, - profile: getMockProfile() + profile: getMockProfile(), + configurable: false, + source: VolumeManagerCommon.Source.FILE } }); }).then(function(result) { @@ -255,7 +261,8 @@ /* label */ null, /* extensionid */ null, /* hasMedia */ false, - /* configurable */ false); + /* configurable */ false, + /* source */ VolumeManagerCommon.Source.FILE); list.add(volumeInfo); var promiseAfterAdd = list.whenVolumeInfoReady('volumeId'); reportPromise(Promise.all([promiseBeforeAdd, promiseAfterAdd]).then(
diff --git a/ui/file_manager/file_manager/common/js/volume_manager_common.js b/ui/file_manager/file_manager/common/js/volume_manager_common.js index 7dfc38c..46a1a07 100644 --- a/ui/file_manager/file_manager/common/js/volume_manager_common.js +++ b/ui/file_manager/file_manager/common/js/volume_manager_common.js
@@ -125,6 +125,18 @@ }; /** + * Source of each volume's data. + * @enum {string} + * @const + */ +VolumeManagerCommon.Source = { + FILE: 'file', + DEVICE: 'device', + NETWORK: 'network', + SYSTEM: 'system' +}; + +/** * Returns if the volume is linux native file system or not. Non-native file * system does not support few operations (e.g. load unpacked extension). * @param {VolumeManagerCommon.VolumeType} type
diff --git a/ui/file_manager/file_manager/foreground/js/file_manager_commands.js b/ui/file_manager/file_manager/foreground/js/file_manager_commands.js index 674d53c..a57a79b 100644 --- a/ui/file_manager/file_manager/foreground/js/file_manager_commands.js +++ b/ui/file_manager/file_manager/foreground/js/file_manager_commands.js
@@ -1375,10 +1375,8 @@ */ execute: function(event, fileManager) { var volumeInfo = this.getCommandVolumeInfo_(event, fileManager); - if (volumeInfo && volumeInfo.configurable) { - fileManager.providersModel.requestConfigure( - assert(volumeInfo.extensionId)); - } + if (volumeInfo && volumeInfo.configurable) + fileManager.volumeManager.configure(volumeInfo); }, /**
diff --git a/ui/file_manager/file_manager/foreground/js/providers_model.js b/ui/file_manager/file_manager/foreground/js/providers_model.js index 49f3fe4..9b4a937c 100644 --- a/ui/file_manager/file_manager/foreground/js/providers_model.js +++ b/ui/file_manager/file_manager/foreground/js/providers_model.js
@@ -145,15 +145,3 @@ console.error(chrome.runtime.lastError.message); }); }; - -/** - * @param {string} extensionId - */ -ProvidersModel.prototype.requestConfigure = function(extensionId) { - chrome.fileManagerPrivate.configureProvidedFileSystem( - assert(extensionId), - function() { - if (chrome.runtime.lastError) - console.error(chrome.runtime.lastError.message); - }); -};
diff --git a/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js b/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js index 109d481b..455a8410 100644 --- a/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js +++ b/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js
@@ -369,11 +369,11 @@ // Sets up context menu of the item. if (tree.contextMenuForSubitems) - item.setContextMenu(tree.contextMenuForSubitems); + item.setContextMenu_(tree.contextMenuForSubitems); // Adds handler for future change. tree.addEventListener( 'contextMenuForSubitemsChange', - function(e) { item.setContextMenu(e.newValue); }); + function(e) { item.setContextMenu_(e.newValue); }); // Populates children now if needed. if (parentDirItem.expanded) @@ -393,8 +393,9 @@ /** * Sets the context menu for directory tree. * @param {!cr.ui.Menu} menu Menu to be set. + * @private */ -SubDirectoryItem.prototype.setContextMenu = function(menu) { +SubDirectoryItem.prototype.setContextMenu_ = function(menu) { var tree = this.parentTree_ || this; // If no parent, 'this' itself is tree. var locationInfo = tree.volumeManager_.getLocationInfo(this.entry); if (locationInfo && locationInfo.isEligibleForFolderShortcut) @@ -433,14 +434,17 @@ item.modelItem_ = modelItem; item.volumeInfo_ = modelItem.volumeInfo; - - // Sets up icons of the item. item.setupIcon_(item.querySelector('.icon'), item.volumeInfo_); - item.setupEjectButton_(item.rowElement); + + // Attach the "eject" icon if the volume is ejectable. + if (modelItem.volumeInfo_.source === VolumeManagerCommon.Source.DEVICE || + modelItem.volumeInfo_.source === VolumeManagerCommon.Source.FILE) { + item.setupEjectButton_(item.rowElement); + } // Sets up context menu of the item. if (tree.contextMenuForRootItems) - item.setContextMenu(tree.contextMenuForRootItems); + item.setContextMenu_(tree.contextMenuForRootItems); // Populate children of this volume using resolved display root. item.volumeInfo_.resolveDisplayRoot(function(displayRoot) { @@ -477,10 +481,10 @@ /** * Sets the context menu for volume items. * @param {!cr.ui.Menu} menu Menu to be set. + * @private */ -VolumeItem.prototype.setContextMenu = function(menu) { - if (this.isRemovable_()) - cr.ui.contextMenuHandler.setContextMenu(this, menu); +VolumeItem.prototype.setContextMenu_ = function(menu) { + cr.ui.contextMenuHandler.setContextMenu(this, menu); }; /** @@ -509,17 +513,6 @@ }; /** - * @return {boolean} True if this volume can be removed by user operation. - * @private - */ -VolumeItem.prototype.isRemovable_ = function() { - var volumeType = this.volumeInfo_.volumeType; - return volumeType === VolumeManagerCommon.VolumeType.ARCHIVE || - volumeType === VolumeManagerCommon.VolumeType.REMOVABLE || - volumeType === VolumeManagerCommon.VolumeType.PROVIDED; -}; - -/** * Set up icon of this volume item. * @param {Element} icon Icon element to be setup. * @param {VolumeInfo} volumeInfo VolumeInfo determines the icon type. @@ -548,31 +541,29 @@ * @private */ VolumeItem.prototype.setupEjectButton_ = function(rowElement) { - if (this.isRemovable_()) { - var ejectButton = cr.doc.createElement('div'); - // Block other mouse handlers. - ejectButton.addEventListener( - 'mouseup', function(event) { event.stopPropagation() }); - ejectButton.addEventListener( - 'mousedown', function(event) { event.stopPropagation() }); - ejectButton.className = 'root-eject'; - ejectButton.setAttribute('aria-label', str('UNMOUNT_DEVICE_BUTTON_LABEL')); - ejectButton.addEventListener('click', function(event) { - event.stopPropagation(); - var unmountCommand = cr.doc.querySelector('command#unmount'); - // Let's make sure 'canExecute' state of the command is properly set for - // the root before executing it. - unmountCommand.canExecuteChange(this); - unmountCommand.execute(this); - }.bind(this)); - rowElement.appendChild(ejectButton); + var ejectButton = cr.doc.createElement('div'); + // Block other mouse handlers. + ejectButton.addEventListener( + 'mouseup', function(event) { event.stopPropagation() }); + ejectButton.addEventListener( + 'mousedown', function(event) { event.stopPropagation() }); + ejectButton.className = 'root-eject'; + ejectButton.setAttribute('aria-label', str('UNMOUNT_DEVICE_BUTTON_LABEL')); + ejectButton.addEventListener('click', function(event) { + event.stopPropagation(); + var unmountCommand = cr.doc.querySelector('command#unmount'); + // Let's make sure 'canExecute' state of the command is properly set for + // the root before executing it. + unmountCommand.canExecuteChange(this); + unmountCommand.execute(this); + }.bind(this)); + rowElement.appendChild(ejectButton); - // Add paper-ripple effect on the eject button. - var ripple = cr.doc.createElement('paper-ripple'); - ripple.setAttribute('fit', ''); - ripple.className = 'circle recenteringTouch'; - ejectButton.appendChild(ripple); - } + // Add paper-ripple effect on the eject button. + var ripple = cr.doc.createElement('paper-ripple'); + ripple.setAttribute('fit', ''); + ripple.className = 'circle recenteringTouch'; + ejectButton.appendChild(ripple); }; @@ -716,7 +707,7 @@ icon.setAttribute('volume-type-icon', VolumeManagerCommon.VolumeType.DRIVE); if (tree.contextMenuForRootItems) - item.setContextMenu(tree.contextMenuForRootItems); + item.setContextMenu_(tree.contextMenuForRootItems); item.label = modelItem.entry.name; return item; @@ -773,8 +764,9 @@ /** * Sets the context menu for shortcut items. * @param {!cr.ui.Menu} menu Menu to be set. + * @private */ -ShortcutItem.prototype.setContextMenu = function(menu) { +ShortcutItem.prototype.setContextMenu_ = function(menu) { cr.ui.contextMenuHandler.setContextMenu(this, menu); };
diff --git a/ui/file_manager/file_manager/foreground/js/volume_manager_wrapper.js b/ui/file_manager/file_manager/foreground/js/volume_manager_wrapper.js index 38e3e44..7b4f53a3 100644 --- a/ui/file_manager/file_manager/foreground/js/volume_manager_wrapper.js +++ b/ui/file_manager/file_manager/foreground/js/volume_manager_wrapper.js
@@ -323,6 +323,24 @@ }; /** + * Requests configuring of the specified volume. + * @param {!VolumeInfo} volumeInfo Volume to be configured. + * @return {!Promise} Fulfilled on success, otherwise rejected with an error + * message. + */ +VolumeManagerWrapper.prototype.configure = function(volumeInfo) { + if (this.pendingTasks_) { + return new Promise(function(fulfill, reject) { + this.pendingTasks_.push(function() { + return this.volumeManager_.configure(volumeInfo).then(fulfill, reject); + }.bind(this)); + }.bind(this)); + } + + return this.volumeManager_.configure(volumeInfo); +}; + +/** * Filters volume info by referring nonNativeEnabled. * * @param {VolumeInfo} volumeInfo Volume info.
diff --git a/ui/keyboard/keyboard_controller.cc b/ui/keyboard/keyboard_controller.cc index a085c53..351cf57 100644 --- a/ui/keyboard/keyboard_controller.cc +++ b/ui/keyboard/keyboard_controller.cc
@@ -211,6 +211,7 @@ input_method_ = proxy_->GetInputMethod(); input_method_->AddObserver(this); window_bounds_observer_.reset(new WindowBoundsChangeObserver()); + proxy_->SetController(this); } KeyboardController::~KeyboardController() { @@ -222,6 +223,7 @@ if (input_method_) input_method_->RemoveObserver(this); ResetWindowInsets(); + proxy_->SetController(nullptr); } // static
diff --git a/ui/keyboard/keyboard_controller_proxy.h b/ui/keyboard/keyboard_controller_proxy.h index 2c91446..f927849e 100644 --- a/ui/keyboard/keyboard_controller_proxy.h +++ b/ui/keyboard/keyboard_controller_proxy.h
@@ -31,6 +31,8 @@ namespace keyboard { +class KeyboardController; + // A proxy used by the KeyboardController to get access to the virtual // keyboard window. class KEYBOARD_EXPORT KeyboardControllerProxy : public aura::WindowObserver { @@ -101,6 +103,11 @@ // provide one. virtual void ReloadKeyboardIfNeeded(); + // KeyboardController owns KeyboardControllerProxy so KeyboardControllerProxy + // or its subclasses should not take ownership of the |controller|. + // |controller| can be null when KeyboardController is destroying. + virtual void SetController(KeyboardController* controller) {} + protected: // The implementation can choose to setup the WebContents before the virtual // keyboard page is loaded (e.g. install a WebContentsObserver).
diff --git a/ui/ozone/platform/caca/caca_window_manager.cc b/ui/ozone/platform/caca/caca_window_manager.cc index 3e11ad2..2b5a5d22 100644 --- a/ui/ozone/platform/caca/caca_window_manager.cc +++ b/ui/ozone/platform/caca/caca_window_manager.cc
@@ -118,16 +118,19 @@ } CacaWindowManager::~CacaWindowManager() { + DCHECK(thread_checker_.CalledOnValidThread()); } bool CacaWindowManager::LoadEGLGLES2Bindings( AddGLLibraryCallback add_gl_library, SetGLGetProcAddressProcCallback set_gl_get_proc_address) { + DCHECK(thread_checker_.CalledOnValidThread()); return false; } scoped_ptr<ui::SurfaceOzoneCanvas> CacaWindowManager::CreateCanvasForWidget( gfx::AcceleratedWidget widget) { + DCHECK(thread_checker_.CalledOnValidThread()); CacaWindow* window = windows_.Lookup(widget); DCHECK(window);
diff --git a/ui/ozone/platform/caca/caca_window_manager.h b/ui/ozone/platform/caca/caca_window_manager.h index 4f51a7f..31134965 100644 --- a/ui/ozone/platform/caca/caca_window_manager.h +++ b/ui/ozone/platform/caca/caca_window_manager.h
@@ -7,6 +7,7 @@ #include "base/id_map.h" #include "base/memory/scoped_ptr.h" +#include "base/threading/thread_checker.h" #include "ui/ozone/public/surface_factory_ozone.h" namespace gfx { @@ -37,6 +38,7 @@ private: IDMap<CacaWindow> windows_; + base::ThreadChecker thread_checker_; DISALLOW_COPY_AND_ASSIGN(CacaWindowManager); };
diff --git a/ui/ozone/platform/drm/BUILD.gn b/ui/ozone/platform/drm/BUILD.gn index d124da2..20cf79a 100644 --- a/ui/ozone/platform/drm/BUILD.gn +++ b/ui/ozone/platform/drm/BUILD.gn
@@ -47,8 +47,6 @@ "gpu/drm_vsync_provider.h", "gpu/drm_window.cc", "gpu/drm_window.h", - "gpu/gpu_lock.cc", - "gpu/gpu_lock.h", "gpu/hardware_display_controller.cc", "gpu/hardware_display_controller.h", "gpu/hardware_display_plane.cc",
diff --git a/ui/ozone/platform/drm/drm.gypi b/ui/ozone/platform/drm/drm.gypi index 532f62e..bc1c86c7 100644 --- a/ui/ozone/platform/drm/drm.gypi +++ b/ui/ozone/platform/drm/drm.gypi
@@ -69,8 +69,6 @@ 'gpu/drm_vsync_provider.h', 'gpu/drm_window.cc', 'gpu/drm_window.h', - 'gpu/gpu_lock.cc', - 'gpu/gpu_lock.h', 'gpu/hardware_display_controller.cc', 'gpu/hardware_display_controller.h', 'gpu/hardware_display_plane.cc',
diff --git a/ui/ozone/platform/drm/drm_surface_factory.cc b/ui/ozone/platform/drm/drm_surface_factory.cc index 6fbf260..ccbbf2b 100644 --- a/ui/ozone/platform/drm/drm_surface_factory.cc +++ b/ui/ozone/platform/drm/drm_surface_factory.cc
@@ -25,12 +25,14 @@ scoped_ptr<ui::SurfaceOzoneCanvas> DrmSurfaceFactory::CreateCanvasForWidget( gfx::AcceleratedWidget widget) { + DCHECK(thread_checker_.CalledOnValidThread()); return make_scoped_ptr(new DrmSurface(screen_manager_->GetWindow(widget))); } bool DrmSurfaceFactory::LoadEGLGLES2Bindings( AddGLLibraryCallback add_gl_library, SetGLGetProcAddressProcCallback set_gl_get_proc_address) { + DCHECK(thread_checker_.CalledOnValidThread()); return false; }
diff --git a/ui/ozone/platform/drm/drm_surface_factory.h b/ui/ozone/platform/drm/drm_surface_factory.h index 1dfdf1a..3baa1754 100644 --- a/ui/ozone/platform/drm/drm_surface_factory.h +++ b/ui/ozone/platform/drm/drm_surface_factory.h
@@ -6,6 +6,7 @@ #define UI_OZONE_PLATFORM_DRM_DRM_SURFACE_FACTORY_H_ #include "base/memory/scoped_ptr.h" +#include "base/threading/thread_checker.h" #include "ui/ozone/public/surface_factory_ozone.h" namespace ui { @@ -30,6 +31,7 @@ protected: ScreenManager* screen_manager_; // Not owned. + base::ThreadChecker thread_checker_; DISALLOW_COPY_AND_ASSIGN(DrmSurfaceFactory); };
diff --git a/ui/ozone/platform/drm/gbm_surface_factory.cc b/ui/ozone/platform/drm/gbm_surface_factory.cc index afe8d2c..f81d746 100644 --- a/ui/ozone/platform/drm/gbm_surface_factory.cc +++ b/ui/ozone/platform/drm/gbm_surface_factory.cc
@@ -78,6 +78,7 @@ } GbmSurfaceFactory::~GbmSurfaceFactory() { + DCHECK(thread_checker_.CalledOnValidThread()); } void GbmSurfaceFactory::InitializeGpu(DrmDeviceManager* drm_device_manager, @@ -87,11 +88,13 @@ } intptr_t GbmSurfaceFactory::GetNativeDisplay() { + DCHECK(thread_checker_.CalledOnValidThread()); return EGL_DEFAULT_DISPLAY; } const int32* GbmSurfaceFactory::GetEGLSurfaceProperties( const int32* desired_list) { + DCHECK(thread_checker_.CalledOnValidThread()); static const int32 kConfigAttribs[] = {EGL_BUFFER_SIZE, 32, EGL_ALPHA_SIZE, @@ -114,17 +117,20 @@ bool GbmSurfaceFactory::LoadEGLGLES2Bindings( AddGLLibraryCallback add_gl_library, SetGLGetProcAddressProcCallback set_gl_get_proc_address) { + DCHECK(thread_checker_.CalledOnValidThread()); return LoadDefaultEGLGLES2Bindings(add_gl_library, set_gl_get_proc_address); } scoped_ptr<SurfaceOzoneCanvas> GbmSurfaceFactory::CreateCanvasForWidget( gfx::AcceleratedWidget widget) { + DCHECK(thread_checker_.CalledOnValidThread()); LOG(FATAL) << "Software rendering mode is not supported with GBM platform"; return nullptr; } scoped_ptr<SurfaceOzoneEGL> GbmSurfaceFactory::CreateEGLSurfaceForWidget( gfx::AcceleratedWidget widget) { + DCHECK(thread_checker_.CalledOnValidThread()); scoped_refptr<GbmDevice> gbm = GetGbmDevice(widget); DCHECK(gbm); @@ -139,6 +145,7 @@ scoped_ptr<SurfaceOzoneEGL> GbmSurfaceFactory::CreateSurfacelessEGLSurfaceForWidget( gfx::AcceleratedWidget widget) { + DCHECK(thread_checker_.CalledOnValidThread()); if (!allow_surfaceless_) return nullptr; @@ -171,6 +178,7 @@ OverlayCandidatesOzone* GbmSurfaceFactory::GetOverlayCandidates( gfx::AcceleratedWidget w) { + DCHECK(thread_checker_.CalledOnValidThread()); if (base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kOzoneTestSingleOverlaySupport)) return new SingleOverlay(); @@ -184,6 +192,7 @@ scoped_refptr<NativePixmap> buffer, const gfx::Rect& display_bounds, const gfx::RectF& crop_rect) { + DCHECK(thread_checker_.CalledOnValidThread()); scoped_refptr<GbmPixmap> pixmap = static_cast<GbmPixmap*>(buffer.get()); if (!pixmap.get()) { LOG(ERROR) << "ScheduleOverlayPlane passed NULL buffer."; @@ -196,10 +205,12 @@ } bool GbmSurfaceFactory::CanShowPrimaryPlaneAsOverlay() { + DCHECK(thread_checker_.CalledOnValidThread()); return allow_surfaceless_; } bool GbmSurfaceFactory::CanCreateNativePixmap(BufferUsage usage) { + DCHECK(thread_checker_.CalledOnValidThread()); switch (usage) { case MAP: return false;
diff --git a/ui/ozone/platform/drm/gpu/gpu_lock.cc b/ui/ozone/platform/drm/gpu/gpu_lock.cc deleted file mode 100644 index bcb287d..0000000 --- a/ui/ozone/platform/drm/gpu/gpu_lock.cc +++ /dev/null
@@ -1,42 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ui/ozone/platform/drm/gpu/gpu_lock.h" - -#include <sys/file.h> -#include <unistd.h> - -#include "base/logging.h" -#include "base/posix/eintr_wrapper.h" - -namespace ui { - -namespace { -const char kGpuLockFile[] = "/run/frecon"; -} - -GpuLock::GpuLock() { - fd_ = open(kGpuLockFile, O_RDWR); - if (fd_ < 0) { - PLOG(ERROR) << "Failed to open lock file '" << kGpuLockFile << "'"; - return; - } - - VLOG(1) << "Taking write lock on '" << kGpuLockFile << "'"; - if (HANDLE_EINTR(flock(fd_, LOCK_EX))) - PLOG(ERROR) << "Error while trying to get lock on '" << kGpuLockFile << "'"; - - VLOG(1) << "Done trying to take write lock on '" << kGpuLockFile << "'"; -} - -GpuLock::~GpuLock() { - // Failed to open the lock file, so nothing to do here. - if (fd_ < 0) - return; - - VLOG(1) << "Releasing write lock on '" << kGpuLockFile << "'"; - close(fd_); -} - -} // namespace ui
diff --git a/ui/ozone/platform/drm/gpu/gpu_lock.h b/ui/ozone/platform/drm/gpu/gpu_lock.h deleted file mode 100644 index 72a093e..0000000 --- a/ui/ozone/platform/drm/gpu/gpu_lock.h +++ /dev/null
@@ -1,27 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef UI_OZONE_PLATFORM_DRM_GPU_GPU_LOCK_H_ -#define UI_OZONE_PLATFORM_DRM_GPU_GPU_LOCK_H_ - -#include "base/macros.h" - -namespace ui { - -// Used to synchronize with Frecon and make sure the GPU process isn't trying to -// access the DRM resources before Frecon finishes drawing. -class GpuLock { - public: - GpuLock(); - ~GpuLock(); - - private: - int fd_; - - DISALLOW_COPY_AND_ASSIGN(GpuLock); -}; - -} // namespace ui - -#endif // UI_OZONE_PLATFORM_DRM_GPU_GPU_LOCK_H_
diff --git a/ui/ozone/platform/drm/gpu/screen_manager.cc b/ui/ozone/platform/drm/gpu/screen_manager.cc index 3dc6c4f..120de8c3 100644 --- a/ui/ozone/platform/drm/gpu/screen_manager.cc +++ b/ui/ozone/platform/drm/gpu/screen_manager.cc
@@ -182,13 +182,6 @@ controllers_.push_back(controller); } - if (!controller->IsDisabled()) { - // Workaround for driver bug that does not release the buffer on null - // modeset. - ModesetDisplayController(controller, controller->origin(), - controller->get_mode(), false); - } - controller->Disable(); UpdateControllerToWindowMapping(); return true;
diff --git a/ui/ozone/platform/drm/host/drm_device_handle.cc b/ui/ozone/platform/drm/host/drm_device_handle.cc index 36d5a837..8d9fc0c 100644 --- a/ui/ozone/platform/drm/host/drm_device_handle.cc +++ b/ui/ozone/platform/drm/host/drm_device_handle.cc
@@ -30,7 +30,8 @@ } DrmDeviceHandle::~DrmDeviceHandle() { - base::ThreadRestrictions::AssertIOAllowed(); + if (file_.is_valid()) + base::ThreadRestrictions::AssertIOAllowed(); } bool DrmDeviceHandle::Initialize(const base::FilePath& path) { @@ -63,15 +64,8 @@ return file_.is_valid(); } -base::ScopedFD DrmDeviceHandle::Duplicate() { - DCHECK(file_.is_valid()); - int fd = dup(file_.get()); - if (fd < 0) { - PLOG(ERROR) << "Failed to dup"; - return base::ScopedFD(); - } - - return base::ScopedFD(fd); +base::ScopedFD DrmDeviceHandle::PassFD() { + return file_.Pass(); } } // namespace ui
diff --git a/ui/ozone/platform/drm/host/drm_device_handle.h b/ui/ozone/platform/drm/host/drm_device_handle.h index 7b65d97b..b360837 100644 --- a/ui/ozone/platform/drm/host/drm_device_handle.h +++ b/ui/ozone/platform/drm/host/drm_device_handle.h
@@ -23,7 +23,7 @@ bool Initialize(const base::FilePath& path); bool IsValid() const; - base::ScopedFD Duplicate(); + base::ScopedFD PassFD(); private: base::ScopedFD file_;
diff --git a/ui/ozone/platform/drm/host/drm_display_host_manager.cc b/ui/ozone/platform/drm/host/drm_display_host_manager.cc index 2feb1f4ba..d2275271 100644 --- a/ui/ozone/platform/drm/host/drm_display_host_manager.cc +++ b/ui/ozone/platform/drm/host/drm_display_host_manager.cc
@@ -48,14 +48,6 @@ FROM_HERE, base::Bind(callback, path, base::Passed(handle.Pass()))); } -void CloseDeviceOnWorkerThread( - scoped_ptr<DrmDeviceHandle> handle, - const scoped_refptr<base::TaskRunner>& reply_runner, - const base::Closure& callback) { - handle.reset(); - reply_runner->PostTask(FROM_HERE, callback); -} - base::FilePath GetPrimaryDisplayCardPath() { struct drm_mode_card_res res; for (int i = 0; /* end on first card# that does not exist */; i++) { @@ -111,39 +103,29 @@ // synchronously since the GPU process will need it to initialize the // graphics state. base::ThreadRestrictions::ScopedAllowIO allow_io; - scoped_ptr<DrmDeviceHandle> handle(new DrmDeviceHandle()); - if (!handle->Initialize(primary_graphics_card_path_)) { + primary_drm_device_handle_.reset(new DrmDeviceHandle()); + if (!primary_drm_device_handle_->Initialize(primary_graphics_card_path_)) { LOG(FATAL) << "Failed to open primary graphics card"; return; } - drm_devices_.add(primary_graphics_card_path_, handle.Pass()); + drm_devices_.insert(primary_graphics_card_path_); } device_manager_->AddObserver(this); proxy_->RegisterHandler(this); - DrmDeviceHandle* handle = drm_devices_.get(primary_graphics_card_path_); ScopedVector<HardwareDisplayControllerInfo> display_infos = - GetAvailableDisplayControllerInfos(handle->fd()); + GetAvailableDisplayControllerInfos(primary_drm_device_handle_->fd()); has_dummy_display_ = !display_infos.empty(); for (size_t i = 0; i < display_infos.size(); ++i) { displays_.push_back(new DisplaySnapshotProxy(CreateDisplaySnapshotParams( - display_infos[i], handle->fd(), i, gfx::Point()))); + display_infos[i], primary_drm_device_handle_->fd(), i, gfx::Point()))); } } DrmDisplayHostManager::~DrmDisplayHostManager() { device_manager_->RemoveObserver(this); proxy_->UnregisterHandler(this); - - for (auto it = drm_devices_.begin(); it != drm_devices_.end(); ++it) { - base::WorkerPool::PostTask(FROM_HERE, - base::Bind(&CloseDeviceOnWorkerThread, - base::Passed(drm_devices_.take(it)), - base::ThreadTaskRunnerHandle::Get(), - base::Bind(&base::DoNothing)), - false /* task_is_slow */); - } } DisplaySnapshot* DrmDisplayHostManager::GetDisplay(int64_t display_id) { @@ -268,16 +250,11 @@ << "Removing primary graphics card"; auto it = drm_devices_.find(event.path); if (it != drm_devices_.end()) { - task_pending_ = base::WorkerPool::PostTask( + task_pending_ = base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, - base::Bind( - &CloseDeviceOnWorkerThread, - base::Passed(drm_devices_.take_and_erase(it)), - base::ThreadTaskRunnerHandle::Get(), - base::Bind(&DrmDisplayHostManager::OnRemoveGraphicsDevice, - weak_ptr_factory_.GetWeakPtr(), event.path)), - false /* task_is_slow */); - return; + base::Bind(&DrmDisplayHostManager::OnRemoveGraphicsDevice, + weak_ptr_factory_.GetWeakPtr(), event.path)); + drm_devices_.erase(it); } break; } @@ -288,10 +265,9 @@ const base::FilePath& path, scoped_ptr<DrmDeviceHandle> handle) { if (handle->IsValid()) { - base::ScopedFD file = handle->Duplicate(); - drm_devices_.add(path, handle.Pass()); + drm_devices_.insert(path); proxy_->Send(new OzoneGpuMsg_AddGraphicsDevice( - path, base::FileDescriptor(file.Pass()))); + path, base::FileDescriptor(handle->PassFD()))); NotifyDisplayDelegate(); } @@ -316,19 +292,20 @@ int host_id, scoped_refptr<base::SingleThreadTaskRunner> send_runner, const base::Callback<void(IPC::Message*)>& send_callback) { - auto it = drm_devices_.find(primary_graphics_card_path_); - DCHECK(it != drm_devices_.end()); + drm_devices_.clear(); + drm_devices_.insert(primary_graphics_card_path_); + scoped_ptr<DrmDeviceHandle> handle = primary_drm_device_handle_.Pass(); + if (!handle) { + base::ThreadRestrictions::ScopedAllowIO allow_io; + handle.reset(new DrmDeviceHandle()); + if (!handle->Initialize(primary_graphics_card_path_)) + LOG(FATAL) << "Failed to open primary graphics card"; + } + // Send the primary device first since this is used to initialize graphics // state. proxy_->Send(new OzoneGpuMsg_AddGraphicsDevice( - it->first, base::FileDescriptor(it->second->Duplicate()))); - - for (auto pair : drm_devices_) { - if (pair.second->IsValid() && pair.first != primary_graphics_card_path_) { - proxy_->Send(new OzoneGpuMsg_AddGraphicsDevice( - pair.first, base::FileDescriptor(pair.second->Duplicate()))); - } - } + primary_graphics_card_path_, base::FileDescriptor(handle->PassFD()))); device_manager_->ScanDevices(this); NotifyDisplayDelegate();
diff --git a/ui/ozone/platform/drm/host/drm_display_host_manager.h b/ui/ozone/platform/drm/host/drm_display_host_manager.h index fbebd17..f5ae2b8 100644 --- a/ui/ozone/platform/drm/host/drm_display_host_manager.h +++ b/ui/ozone/platform/drm/host/drm_display_host_manager.h
@@ -7,8 +7,8 @@ #include <map> #include <queue> +#include <set> -#include "base/containers/scoped_ptr_hash_map.h" #include "base/files/file.h" #include "base/files/file_path.h" #include "base/macros.h" @@ -132,8 +132,11 @@ bool task_pending_; // Keeps track of all the active DRM devices. - base::ScopedPtrHashMap<base::FilePath, scoped_ptr<DrmDeviceHandle>> - drm_devices_; + std::set<base::FilePath> drm_devices_; + + // This is used to cache the primary DRM device until the channel is + // established. + scoped_ptr<DrmDeviceHandle> primary_drm_device_handle_; base::WeakPtrFactory<DrmDisplayHostManager> weak_ptr_factory_;
diff --git a/ui/ozone/platform/drm/ozone_platform_drm.cc b/ui/ozone/platform/drm/ozone_platform_drm.cc index 6cc4fed..fb22bdcb 100644 --- a/ui/ozone/platform/drm/ozone_platform_drm.cc +++ b/ui/ozone/platform/drm/ozone_platform_drm.cc
@@ -20,7 +20,6 @@ #include "ui/ozone/platform/drm/gpu/drm_gpu_display_manager.h" #include "ui/ozone/platform/drm/gpu/drm_gpu_platform_support.h" #include "ui/ozone/platform/drm/gpu/drm_window.h" -#include "ui/ozone/platform/drm/gpu/gpu_lock.h" #include "ui/ozone/platform/drm/gpu/screen_manager.h" #include "ui/ozone/platform/drm/host/drm_cursor.h" #include "ui/ozone/platform/drm/host/drm_display_host_manager.h" @@ -88,9 +87,6 @@ new DrmNativeDisplayDelegate(display_manager_.get())); } void InitializeUI() override { -#if defined(OS_CHROMEOS) - gpu_lock_.reset(new GpuLock()); -#endif drm_device_manager_.reset(new DrmDeviceManager( scoped_ptr<DrmDeviceGenerator>(new DrmDeviceGenerator()))); window_manager_.reset(new DrmWindowHostManager()); @@ -125,7 +121,6 @@ private: // Objects in the "GPU" process. - scoped_ptr<GpuLock> gpu_lock_; scoped_ptr<DrmDeviceManager> drm_device_manager_; scoped_ptr<DrmBufferGenerator> buffer_generator_; scoped_ptr<ScreenManager> screen_manager_;
diff --git a/ui/ozone/platform/drm/ozone_platform_gbm.cc b/ui/ozone/platform/drm/ozone_platform_gbm.cc index 75f93c586..3f5bd7b 100644 --- a/ui/ozone/platform/drm/ozone_platform_gbm.cc +++ b/ui/ozone/platform/drm/ozone_platform_gbm.cc
@@ -24,7 +24,6 @@ #include "ui/ozone/platform/drm/gpu/gbm_buffer.h" #include "ui/ozone/platform/drm/gpu/gbm_device.h" #include "ui/ozone/platform/drm/gpu/gbm_surface.h" -#include "ui/ozone/platform/drm/gpu/gpu_lock.h" #include "ui/ozone/platform/drm/gpu/scanout_buffer.h" #include "ui/ozone/platform/drm/gpu/screen_manager.h" #include "ui/ozone/platform/drm/host/drm_cursor.h" @@ -170,9 +169,6 @@ } void InitializeGPU() override { -#if defined(OS_CHROMEOS) - gpu_lock_.reset(new GpuLock()); -#endif gl_api_loader_.reset(new GlApiLoader()); drm_device_manager_.reset(new DrmDeviceManager( scoped_ptr<DrmDeviceGenerator>(new GbmDeviceGenerator()))); @@ -195,7 +191,6 @@ scoped_ptr<GbmSurfaceFactory> surface_factory_ozone_; // Objects in the GPU process. - scoped_ptr<GpuLock> gpu_lock_; scoped_ptr<GlApiLoader> gl_api_loader_; scoped_ptr<DrmDeviceManager> drm_device_manager_; scoped_ptr<GbmBufferGenerator> buffer_generator_;
diff --git a/ui/ozone/platform/egltest/ozone_platform_egltest.cc b/ui/ozone/platform/egltest/ozone_platform_egltest.cc index 42ce0a8..adfadf99 100644 --- a/ui/ozone/platform/egltest/ozone_platform_egltest.cc +++ b/ui/ozone/platform/egltest/ozone_platform_egltest.cc
@@ -9,6 +9,7 @@ #include "base/environment.h" #include "base/files/file_path.h" #include "base/path_service.h" +#include "base/threading/thread_checker.h" #include "library_loaders/libeglplatform_shim.h" #include "third_party/khronos/EGL/egl.h" #include "ui/events/devices/device_data_manager.h" @@ -240,7 +241,9 @@ public: SurfaceFactoryEgltest(LibeglplatformShimLoader* eglplatform_shim) : eglplatform_shim_(eglplatform_shim) {} - ~SurfaceFactoryEgltest() override {} + ~SurfaceFactoryEgltest() override { + DCHECK(thread_checker_.CalledOnValidThread()); + } // SurfaceFactoryOzone: intptr_t GetNativeDisplay() override; @@ -253,14 +256,17 @@ private: LibeglplatformShimLoader* eglplatform_shim_; + base::ThreadChecker thread_checker_; }; intptr_t SurfaceFactoryEgltest::GetNativeDisplay() { + DCHECK(thread_checker_.CalledOnValidThread()); return eglplatform_shim_->ShimGetNativeDisplay(); } scoped_ptr<SurfaceOzoneEGL> SurfaceFactoryEgltest::CreateEGLSurfaceForWidget( gfx::AcceleratedWidget widget) { + DCHECK(thread_checker_.CalledOnValidThread()); return make_scoped_ptr<SurfaceOzoneEGL>( new SurfaceOzoneEgltest(widget, eglplatform_shim_)); } @@ -268,6 +274,7 @@ bool SurfaceFactoryEgltest::LoadEGLGLES2Bindings( AddGLLibraryCallback add_gl_library, SetGLGetProcAddressProcCallback set_gl_get_proc_address) { + DCHECK(thread_checker_.CalledOnValidThread()); const char* egl_soname = eglplatform_shim_->ShimQueryString(SHIM_EGL_LIBRARY); const char* gles_soname = eglplatform_shim_->ShimQueryString(SHIM_GLES_LIBRARY); @@ -282,6 +289,7 @@ const int32* SurfaceFactoryEgltest::GetEGLSurfaceProperties( const int32* desired_list) { + DCHECK(thread_checker_.CalledOnValidThread()); static const int32 broken_props[] = { EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
diff --git a/ui/ozone/platform/test/test_window_manager.cc b/ui/ozone/platform/test/test_window_manager.cc index 3ff3a47..cd48bf3 100644 --- a/ui/ozone/platform/test/test_window_manager.cc +++ b/ui/ozone/platform/test/test_window_manager.cc
@@ -69,6 +69,7 @@ } TestWindowManager::~TestWindowManager() { + DCHECK(thread_checker_.CalledOnValidThread()); } void TestWindowManager::Initialize() { @@ -96,6 +97,7 @@ scoped_ptr<SurfaceOzoneCanvas> TestWindowManager::CreateCanvasForWidget( gfx::AcceleratedWidget widget) { + DCHECK(thread_checker_.CalledOnValidThread()); TestWindow* window = windows_.Lookup(widget); DCHECK(window); return make_scoped_ptr<SurfaceOzoneCanvas>(new FileSurface(window->path())); @@ -104,6 +106,7 @@ bool TestWindowManager::LoadEGLGLES2Bindings( AddGLLibraryCallback add_gl_library, SetGLGetProcAddressProcCallback set_gl_get_proc_address) { + DCHECK(thread_checker_.CalledOnValidThread()); return false; }
diff --git a/ui/ozone/platform/test/test_window_manager.h b/ui/ozone/platform/test/test_window_manager.h index 69be81d9..b651207e 100644 --- a/ui/ozone/platform/test/test_window_manager.h +++ b/ui/ozone/platform/test/test_window_manager.h
@@ -8,6 +8,7 @@ #include "base/files/file_path.h" #include "base/id_map.h" #include "base/memory/scoped_ptr.h" +#include "base/threading/thread_checker.h" #include "ui/gfx/native_widget_types.h" #include "ui/ozone/platform/test/test_window.h" #include "ui/ozone/public/surface_factory_ozone.h" @@ -42,6 +43,7 @@ base::FilePath location_; IDMap<TestWindow> windows_; + base::ThreadChecker thread_checker_; DISALLOW_COPY_AND_ASSIGN(TestWindowManager); };
diff --git a/ui/ozone/public/surface_factory_ozone.h b/ui/ozone/public/surface_factory_ozone.h index e73813d..0fbf9e89 100644 --- a/ui/ozone/public/surface_factory_ozone.h +++ b/ui/ozone/public/surface_factory_ozone.h
@@ -129,6 +129,7 @@ // Create a single native buffer to be used for overlay planes or zero copy // for |widget| representing a particular display controller or default // display controller for kNullAcceleratedWidget. + // It can be called on any thread. virtual scoped_refptr<NativePixmap> CreateNativePixmap( gfx::AcceleratedWidget widget, gfx::Size size,
diff --git a/ui/touch_selection/touch_selection_controller.cc b/ui/touch_selection/touch_selection_controller.cc index ad010c38..34cc30a 100644 --- a/ui/touch_selection/touch_selection_controller.cc +++ b/ui/touch_selection/touch_selection_controller.cc
@@ -491,8 +491,14 @@ } void TouchSelectionController::ForceNextUpdateIfInactive() { - if (active_status_ == INACTIVE) + // Only force the update if the reported selection is non-empty but still + // considered "inactive", i.e., it wasn't preceded by a user gesture or + // the handles have since been explicitly hidden. + if (active_status_ == INACTIVE && + start_.type() != SelectionBound::EMPTY && + end_.type() != SelectionBound::EMPTY) { force_next_update_ = true; + } } gfx::Vector2dF TouchSelectionController::GetStartLineOffset() const {
diff --git a/ui/touch_selection/touch_selection_controller_unittest.cc b/ui/touch_selection/touch_selection_controller_unittest.cc index c78a5d5..8125c50 100644 --- a/ui/touch_selection/touch_selection_controller_unittest.cc +++ b/ui/touch_selection/touch_selection_controller_unittest.cc
@@ -575,6 +575,27 @@ EXPECT_EQ(gfx::PointF(), GetLastEventStart()); } +TEST_F(TouchSelectionControllerTest, SelectionAllowsEmptyUpdateAfterLongPress) { + gfx::RectF start_rect(5, 5, 0, 10); + gfx::RectF end_rect(50, 5, 0, 10); + bool visible = true; + + OnLongPressEvent(); + EXPECT_THAT(GetAndResetEvents(), IsEmpty()); + + // There may be several empty updates after a longpress due to the + // asynchronous response. These empty updates should not prevent the selection + // handles from (eventually) activating. + ClearSelection(); + EXPECT_THAT(GetAndResetEvents(), IsEmpty()); + + ClearSelection(); + EXPECT_THAT(GetAndResetEvents(), IsEmpty()); + + ChangeSelection(start_rect, visible, end_rect, visible); + EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_SHOWN)); +} + TEST_F(TouchSelectionControllerTest, SelectionRepeatedLongPress) { gfx::RectF start_rect(5, 5, 0, 10); gfx::RectF end_rect(50, 5, 0, 10);
diff --git a/ui/webui/resources/cr_elements/v0_8/demo_element.html b/ui/webui/resources/cr_elements/v0_8/demo_element.html new file mode 100644 index 0000000..5a3810b --- /dev/null +++ b/ui/webui/resources/cr_elements/v0_8/demo_element.html
@@ -0,0 +1,49 @@ +<link rel="import" href="chrome://resources/polymer/v0_8/polymer/polymer.html"> +<link rel="import" href="chrome://resources/cr_elements/v0_8/cr_button/cr_button.html"> +<link rel="import" href="chrome://resources/cr_elements/v0_8/cr_checkbox/cr_checkbox.html"> +<link rel="import" href="chrome://resources/cr_elements/v0_8/cr_collapse/cr_collapse.html"> +<link rel="import" href="chrome://resources/cr_elements/v0_8/cr_input/cr_input.html"> +<link rel="import" href="chrome://resources/cr_elements/v0_8/cr_network_icon/cr_network_icon.html"> +<link rel="import" href="chrome://resources/cr_elements/v0_8/cr_toggle_button/cr_toggle_button.html"> + +<dom-module id="cr-demo-element"> + <template> + <div> + <h3>cr-button</h3> + <cr-button>Button</cr-button> + <cr-button raised>Raised Button</cr-button> + </div> + <div> + <h3>cr-checkbox</h3> + <cr-checkbox checked="{{checkboxChecked}}">Checkbox</cr-checkbox> + </div> + <div> + <h3>cr-collapse</h3> + <paper-toggle-button checked="{{collapseOpened}}"> + Toggle Collapse + </paper-toggle-button> + <cr-collapse opened="{{collapseOpened}}"> + <div> + <span>Collapsable section</span> + </div> + </cr-collapse> + </div> + <div> + <h3>cr-input</h3> + <cr-input label="Input" value="{{inputValue}}"></cr-input> + <span>Input.value=</span><span>{{inputValue}}</span> + </div> + <div> + <h3>cr-network-icon</h3> + <cr-network-icon></cr-network-icon> + </div> + <div> + <h3>cr-toggle-button</h3> + <div horizontal layout> + <span>Toggle Button</span> + <cr-toggle-button></cr-toggle-button> + </div> + </div> + </template> + <script src="demo_element.js"></script> +</dom-module>
diff --git a/ui/webui/resources/cr_elements/v0_8/demo_element.js b/ui/webui/resources/cr_elements/v0_8/demo_element.js new file mode 100644 index 0000000..0b3e9ce --- /dev/null +++ b/ui/webui/resources/cr_elements/v0_8/demo_element.js
@@ -0,0 +1,42 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * @fileoverview Polymer element for UI wrapping a list of cr- elements. + */ +Polymer({ + is: 'cr-demo-element', + + properties: { + checkboxChecked: { + type: Boolean, + value: true, + observer: 'checkboxCheckedChanged_' + }, + + collapseOpened: { + type: Boolean, + value: true, + observer: 'collapseOpenedChanged_' + }, + + inputValue: { + type: String, + value: '', + observer: 'inputValueChanged_' + }, + }, + + checkboxCheckedChanged_: function() { + console.log('checkboxCheckedChanged=' + this.checkboxChecked); + }, + + collapseOpenedChanged_: function() { + console.log('collapseOpened=' + this.collapseOpened); + }, + + inputValueChanged_: function() { + console.log('inputValue=' + this.inputValue); + } +});
diff --git a/ui/webui/resources/cr_elements/v0_8/demo_page.html b/ui/webui/resources/cr_elements/v0_8/demo_page.html new file mode 100644 index 0000000..f918666 --- /dev/null +++ b/ui/webui/resources/cr_elements/v0_8/demo_page.html
@@ -0,0 +1,19 @@ +<!doctype html> + +<!-- Demo page for cr-elements. Add new elements to demo_elements.html to --> +<!-- view them and test their interactions with other elements. --> +<!-- To view this page, navigate to: --> +<!-- chrome://resources/cr_elements/v0_8/demo_page.html --> + +<html> + +<head> + <link href="demo_element.html" rel="import" > +</head> + +<body> + <h1>cr-elements</h1> + <cr-demo-element></cr-demo-element> +</body> + +</html>
diff --git a/ui/webui/resources/cr_elements_resources.grdp b/ui/webui/resources/cr_elements_resources.grdp index 6bbe17c9..bc5ac369 100644 --- a/ui/webui/resources/cr_elements_resources.grdp +++ b/ui/webui/resources/cr_elements_resources.grdp
@@ -105,6 +105,15 @@ <!-- Polymer 0.8 Elements --> <if expr="enable_polymer_v08"> + <structure name="IDR_CR_ELEMENTS_08_CR_DEMO_ELEMENT_HTML" + file="../../webui/resources/cr_elements/v0_8/demo_element.html" + type="chrome_html" /> + <structure name="IDR_CR_ELEMENTS_08_CR_DEMO_ELEMENT_JS" + file="../../webui/resources/cr_elements/v0_8/demo_element.js" + type="chrome_html" /> + <structure name="IDR_CR_ELEMENTS_08_CR_DEMO_PAGE_HTML" + file="../../webui/resources/cr_elements/v0_8/demo_page.html" + type="chrome_html" /> <structure name="IDR_CR_ELEMENTS_08_CR_BUTTON_CSS" file="../../webui/resources/cr_elements/v0_8/cr_button/cr_button.css" type="chrome_html" />